11、STM32H7 MPU Cache

news2024/11/15 23:45:08

篇前小问题

在使用stm32H750的FMC时,出现一些奇怪的问题,写A时序时时,总是写1次的代码了出现了写四次的时序,所以找了很久,才找到问题出在了MPU上,使用FMC时,必须开启MPU,不然会出现此现象。
在这里插入图片描述
while一直执行该函数,会出现此时序图:
在这里插入图片描述
读时序是两字节,但是写出现的时序明显异常
经过解决,才出现正常的时序,如下所示
在这里插入图片描述
解决方法:
开启FMC的区域保护:

void MPU_Config(void)
{
  MPU_Region_InitTypeDef MPU_InitStruct = {0};

  /* Disables the MPU */
  HAL_MPU_Disable();
  /** Initializes and configures the Region and the memory to be protected
  */
  MPU_InitStruct.Enable = MPU_REGION_ENABLE;
  MPU_InitStruct.Number = MPU_REGION_NUMBER0;
  MPU_InitStruct.BaseAddress = 0x60000000;
  MPU_InitStruct.Size = MPU_REGION_SIZE_256MB;
  MPU_InitStruct.SubRegionDisable = 0x0;
  MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
  MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
  MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;
  MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
  MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;
  MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE;

  HAL_MPU_ConfigRegion(&MPU_InitStruct);
  /* Enables the MPU */
  HAL_MPU_Enable(MPU_HFNMI_PRIVDEF);

}

同样问题经验贴参考:https://www.stmcu.org.cn/module/forum/forum.php?mod=viewthread&tid=623865&page=1#pid2491693
至于为什么非要开启MPU呢,因为
在这里插入图片描述
参考出处:https://www.armbbs.cn/forum.php?mod=viewthread&tid=89929
说了这么多,先发下代码吧:
在这里插入图片描述
在这里插入图片描述
fmc.c

/**
  ******************************************************************************
  * File Name          : FMC.c
  * Description        : This file provides code for the configuration
  *                      of the FMC peripheral.
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright (c) 2023 STMicroelectronics.
  * All rights reserved.</center></h2>
  *
  * This software component is licensed by ST under Ultimate Liberty license
  * SLA0044, the "License"; You may not use this file except in compliance with
  * the License. You may obtain a copy of the License at:
  *                             www.st.com/SLA0044
  *
  ******************************************************************************
  */

/* Includes ------------------------------------------------------------------*/
#include "fmc.h"

/* USER CODE BEGIN 0 */
/* USER CODE END 0 */

SRAM_HandleTypeDef hsram1;

/* FMC initialization function */
void MX_FMC_Init(void)
{
  /* USER CODE BEGIN FMC_Init 0 */
  /* USER CODE END FMC_Init 0 */

  FMC_NORSRAM_TimingTypeDef Timing = {0};
  FMC_NORSRAM_TimingTypeDef ExtTiming = {0};

  /* USER CODE BEGIN FMC_Init 1 */
  /* USER CODE END FMC_Init 1 */

  /** Perform the SRAM1 memory initialization sequence
  */
  hsram1.Instance = FMC_NORSRAM_DEVICE;
  hsram1.Extended = FMC_NORSRAM_EXTENDED_DEVICE;
  /* hsram1.Init */
  hsram1.Init.NSBank = FMC_NORSRAM_BANK1;
  hsram1.Init.DataAddressMux = FMC_DATA_ADDRESS_MUX_DISABLE;
  hsram1.Init.MemoryType = FMC_MEMORY_TYPE_SRAM;
  hsram1.Init.MemoryDataWidth = FMC_NORSRAM_MEM_BUS_WIDTH_16;
  hsram1.Init.BurstAccessMode = FMC_BURST_ACCESS_MODE_DISABLE;
  hsram1.Init.WaitSignalPolarity = FMC_WAIT_SIGNAL_POLARITY_LOW;
  hsram1.Init.WaitSignalActive = FMC_WAIT_TIMING_BEFORE_WS;
  hsram1.Init.WriteOperation = FMC_WRITE_OPERATION_ENABLE;
  hsram1.Init.WaitSignal = FMC_WAIT_SIGNAL_DISABLE;
  hsram1.Init.ExtendedMode = FMC_EXTENDED_MODE_ENABLE;
  hsram1.Init.AsynchronousWait = FMC_ASYNCHRONOUS_WAIT_DISABLE;
  hsram1.Init.WriteBurst = FMC_WRITE_BURST_DISABLE;
  hsram1.Init.ContinuousClock = FMC_CONTINUOUS_CLOCK_SYNC_ONLY;
  hsram1.Init.WriteFifo = FMC_WRITE_FIFO_DISABLE;
  hsram1.Init.PageSize = FMC_PAGE_SIZE_NONE;
  /* Timing */
  Timing.AddressSetupTime = 15;
  Timing.AddressHoldTime = 15;
  Timing.DataSetupTime = 255;
  Timing.BusTurnAroundDuration = 15;
  Timing.CLKDivision = 16;
  Timing.DataLatency = 17;
  Timing.AccessMode = FMC_ACCESS_MODE_A;
  /* ExtTiming */
  ExtTiming.AddressSetupTime = 15;
  ExtTiming.AddressHoldTime = 15;
  ExtTiming.DataSetupTime = 255;
  ExtTiming.BusTurnAroundDuration = 15;
  ExtTiming.CLKDivision = 16;
  ExtTiming.DataLatency = 17;
  ExtTiming.AccessMode = FMC_ACCESS_MODE_A;

  if (HAL_SRAM_Init(&hsram1, &Timing, &ExtTiming) != HAL_OK)
  {
    Error_Handler( );
  }

  /* USER CODE BEGIN FMC_Init 2 */
  /* USER CODE END FMC_Init 2 */
}

static uint32_t FMC_Initialized = 0;

static void HAL_FMC_MspInit(void){
  /* USER CODE BEGIN FMC_MspInit 0 */
  /* USER CODE END FMC_MspInit 0 */
  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if (FMC_Initialized) {
    return;
  }
  FMC_Initialized = 1;
  RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};

  /** Initializes the peripherals clock
  */
    PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_FMC;
    PeriphClkInitStruct.PLL2.PLL2M = 8;
    PeriphClkInitStruct.PLL2.PLL2N = 20;
    PeriphClkInitStruct.PLL2.PLL2P = 2;
    PeriphClkInitStruct.PLL2.PLL2Q = 2;
    PeriphClkInitStruct.PLL2.PLL2R = 2;
    PeriphClkInitStruct.PLL2.PLL2RGE = RCC_PLL2VCIRANGE_3;
    PeriphClkInitStruct.PLL2.PLL2VCOSEL = RCC_PLL2VCOMEDIUM;
    PeriphClkInitStruct.FmcClockSelection = RCC_FMCCLKSOURCE_PLL2;
    if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
    {
      Error_Handler();
    }

  /* Peripheral clock enable */
  __HAL_RCC_FMC_CLK_ENABLE();

  /** FMC GPIO Configuration
  PE7   ------> FMC_D4
  PE8   ------> FMC_D5
  PE9   ------> FMC_D6
  PE10   ------> FMC_D7
  PE11   ------> FMC_D8
  PE12   ------> FMC_D9
  PE13   ------> FMC_D10
  PE14   ------> FMC_D11
  PE15   ------> FMC_D12
  PD8   ------> FMC_D13
  PD9   ------> FMC_D14
  PD10   ------> FMC_D15
  PD13   ------> FMC_A18
  PD14   ------> FMC_D0
  PD15   ------> FMC_D1
  PC7   ------> FMC_NE1
  PD0   ------> FMC_D2
  PD1   ------> FMC_D3
  PD4   ------> FMC_NOE
  PD5   ------> FMC_NWE
  */
  /* GPIO_InitStruct */
  GPIO_InitStruct.Pin = GPIO_PIN_7|GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10
                          |GPIO_PIN_11|GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14
                          |GPIO_PIN_15;
  GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
  GPIO_InitStruct.Alternate = GPIO_AF12_FMC;

  HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);

  /* GPIO_InitStruct */
  GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_13
                          |GPIO_PIN_14|GPIO_PIN_15|GPIO_PIN_0|GPIO_PIN_1
                          |GPIO_PIN_4|GPIO_PIN_5;
  GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
  GPIO_InitStruct.Alternate = GPIO_AF12_FMC;

  HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);

  /* GPIO_InitStruct */
  GPIO_InitStruct.Pin = GPIO_PIN_7;
  GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
  GPIO_InitStruct.Alternate = GPIO_AF9_FMC;

  HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

  /* USER CODE BEGIN FMC_MspInit 1 */
  /* USER CODE END FMC_MspInit 1 */
}

void HAL_SRAM_MspInit(SRAM_HandleTypeDef* sramHandle){
  /* USER CODE BEGIN SRAM_MspInit 0 */
  /* USER CODE END SRAM_MspInit 0 */
  HAL_FMC_MspInit();
  /* USER CODE BEGIN SRAM_MspInit 1 */
  /* USER CODE END SRAM_MspInit 1 */
}

static uint32_t FMC_DeInitialized = 0;

static void HAL_FMC_MspDeInit(void){
  /* USER CODE BEGIN FMC_MspDeInit 0 */
  /* USER CODE END FMC_MspDeInit 0 */
  if (FMC_DeInitialized) {
    return;
  }
  FMC_DeInitialized = 1;
  /* Peripheral clock enable */
  __HAL_RCC_FMC_CLK_DISABLE();

  /** FMC GPIO Configuration
  PE7   ------> FMC_D4
  PE8   ------> FMC_D5
  PE9   ------> FMC_D6
  PE10   ------> FMC_D7
  PE11   ------> FMC_D8
  PE12   ------> FMC_D9
  PE13   ------> FMC_D10
  PE14   ------> FMC_D11
  PE15   ------> FMC_D12
  PD8   ------> FMC_D13
  PD9   ------> FMC_D14
  PD10   ------> FMC_D15
  PD13   ------> FMC_A18
  PD14   ------> FMC_D0
  PD15   ------> FMC_D1
  PC7   ------> FMC_NE1
  PD0   ------> FMC_D2
  PD1   ------> FMC_D3
  PD4   ------> FMC_NOE
  PD5   ------> FMC_NWE
  */

  HAL_GPIO_DeInit(GPIOE, GPIO_PIN_7|GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10
                          |GPIO_PIN_11|GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14
                          |GPIO_PIN_15);

  HAL_GPIO_DeInit(GPIOD, GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_13
                          |GPIO_PIN_14|GPIO_PIN_15|GPIO_PIN_0|GPIO_PIN_1
                          |GPIO_PIN_4|GPIO_PIN_5);

  HAL_GPIO_DeInit(GPIOC, GPIO_PIN_7);

  /* USER CODE BEGIN FMC_MspDeInit 1 */
  /* USER CODE END FMC_MspDeInit 1 */
}

void HAL_SRAM_MspDeInit(SRAM_HandleTypeDef* sramHandle){
  /* USER CODE BEGIN SRAM_MspDeInit 0 */
  /* USER CODE END SRAM_MspDeInit 0 */
  HAL_FMC_MspDeInit();
  /* USER CODE BEGIN SRAM_MspDeInit 1 */
  /* USER CODE END SRAM_MspDeInit 1 */
}
/**
  * @}
  */

/**
  * @}
  */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

main.c

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright (c) 2023 STMicroelectronics.
  * All rights reserved.</center></h2>
  *
  * This software component is licensed by ST under Ultimate Liberty license
  * SLA0044, the "License"; You may not use this file except in compliance with
  * the License. You may obtain a copy of the License at:
  *                             www.st.com/SLA0044
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "fatfs.h"
#include "sdmmc.h"
#include "tim.h"
#include "usart.h"
#include "gpio.h"
#include "fmc.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "Common_Driver.h"
#include "sdCheck.h"
#include "Key_Driver.h"
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MPU_Config(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
typedef struct
{
  volatile uint16_t LCD_REG;
  volatile uint16_t LCD_RAM;
} LCD_TypeDef;

#define LCD_BASE        ((uint32_t)(0x60000000 | 0x0007FFFE))
#define LCD ((LCD_TypeDef *) LCD_BASE)

void TestSRAM(void)
{
  volatile uint16_t x = 0;

  x = LCD->LCD_REG;
  x = LCD->LCD_RAM;
  LCD->LCD_REG = 0x00;
  LCD->LCD_RAM = 0x00;
}

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */
  extern uint8_t KeyFlag[2];
  /* USER CODE END 1 */

  /* MPU Configuration--------------------------------------------------------*/
  MPU_Config();

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */
  //MPU_Configx();
  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_USART1_UART_Init();
  MX_SDMMC1_SD_Init();
  MX_FATFS_Init();
  MX_TIM17_Init();
  MX_FMC_Init();
  /* USER CODE BEGIN 2 */
  sdCheck_Init();
  Key_Init();
  //HAL_TIM_Base_Start_IT(&htim17);//1ms任务,需在服务器之前启动
  HAL_Delay(1);
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
    TestSRAM();
  }
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Supply configuration update enable
  */
  HAL_PWREx_ConfigSupply(PWR_LDO_SUPPLY);
  /** Configure the main internal regulator output voltage
  */
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE0);

  while(!__HAL_PWR_GET_FLAG(PWR_FLAG_VOSRDY)) {}
  /** Macro to configure the PLL clock source
  */
  __HAL_RCC_PLL_PLLSOURCE_CONFIG(RCC_PLLSOURCE_HSI);
  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_DIV1;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
  RCC_OscInitStruct.PLL.PLLM = 4;
  RCC_OscInitStruct.PLL.PLLN = 60;
  RCC_OscInitStruct.PLL.PLLP = 2;
  RCC_OscInitStruct.PLL.PLLQ = 20;
  RCC_OscInitStruct.PLL.PLLR = 2;
  RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1VCIRANGE_3;
  RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1VCOWIDE;
  RCC_OscInitStruct.PLL.PLLFRACN = 0;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2
                              |RCC_CLOCKTYPE_D3PCLK1|RCC_CLOCKTYPE_D1PCLK1;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV2;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV2;
  RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV2;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK)
  {
    Error_Handler();
  }
}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

/* MPU Configuration */

void MPU_Config(void)
{
  MPU_Region_InitTypeDef MPU_InitStruct = {0};

  /* Disables the MPU */
  HAL_MPU_Disable();
  /** Initializes and configures the Region and the memory to be protected
  */
  MPU_InitStruct.Enable = MPU_REGION_ENABLE;
  MPU_InitStruct.Number = MPU_REGION_NUMBER0;
  MPU_InitStruct.BaseAddress = 0x60000000;
  MPU_InitStruct.Size = MPU_REGION_SIZE_256MB;
  MPU_InitStruct.SubRegionDisable = 0x0;
  MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
  MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
  MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;
  MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
  MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;
  MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE;

  HAL_MPU_ConfigRegion(&MPU_InitStruct);
  /* Enables the MPU */
  HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);

}

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  __disable_irq();
  printf("Error:Error_Handler()\n");
  while (1)
  {
  }
  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

正篇

MPU(内存保护单元):简单的说就是内存保护、外设保护和代码访问保护
MPU可以保护16个内存区域(独立配置),每个区域最小256字节,每个区域还可以配置为 8 个子区域。由于子区域一般都相同大小,这样每个子区域的大小就是 32 字节,正好跟 Cache 的 Cache Line 大小一样。MPU 可以配置的 16 个内存区的序号范围是 0 到 15,还有默认区 default region,也叫作背景区,序号-1。

MPU的三种内存类型:

在这里插入图片描述

MPU寄存器

寄存器MPU_RASR
在这里插入图片描述
控制寄存器CTRL
在这里插入图片描述
HAL库使用MPU时常用的3个函数:

void HAL_MPU_Disable(void)
void HAL_MPU_Enable(uint32_t MPU_Control)
void HAL_MPU_ConfigRegion(MPU_Region_InitTypeDef *MPU_Init)

1、void HAL_MPU_Enable(uint32_t MPU_Control)

此函数用于使能 MPU,一般情况使用参数 MPU_PRIVILEGED_DEFAULT。
在这里插入图片描述

2、void HAL_MPU_ConfigRegion(MPU_Region_InitTypeDef *MPU_Init)

/** @defgroup CORTEX_MPU_Region_Initialization_Structure_definition MPU Region Initialization Structure Definition
  * @brief  MPU Region initialization structure
  * @{
  */
typedef struct
{
  uint8_t                Enable;                /*!< Specifies the status of the region.
                                                     This parameter can be a value of @ref CORTEX_MPU_Region_Enable                 */
  uint8_t                Number;                /*!< Specifies the number of the region to protect.
                                                     This parameter can be a value of @ref CORTEX_MPU_Region_Number                 */
  uint32_t               BaseAddress;           /*!< Specifies the base address of the region to protect.                           */
  uint8_t                Size;                  /*!< Specifies the size of the region to protect.
                                                     This parameter can be a value of @ref CORTEX_MPU_Region_Size                   */
  uint8_t                SubRegionDisable;      /*!< Specifies the number of the subregion protection to disable.
                                                     This parameter must be a number between Min_Data = 0x00 and Max_Data = 0xFF    */
  uint8_t                TypeExtField;          /*!< Specifies the TEX field level.
                                                     This parameter can be a value of @ref CORTEX_MPU_TEX_Levels                    */
  uint8_t                AccessPermission;      /*!< Specifies the region access permission type.
                                                     This parameter can be a value of @ref CORTEX_MPU_Region_Permission_Attributes  */
  uint8_t                DisableExec;           /*!< Specifies the instruction access status.
                                                     This parameter can be a value of @ref CORTEX_MPU_Instruction_Access            */
  uint8_t                IsShareable;           /*!< Specifies the shareability status of the protected region.
                                                     This parameter can be a value of @ref CORTEX_MPU_Access_Shareable              */
  uint8_t                IsCacheable;           /*!< Specifies the cacheable status of the region protected.
                                                     This parameter can be a value of @ref CORTEX_MPU_Access_Cacheable              */
  uint8_t                IsBufferable;          /*!< Specifies the bufferable status of the protected region.
                                                     This parameter can be a value of @ref CORTEX_MPU_Access_Bufferable             */
}MPU_Region_InitTypeDef;

示例配置:

MPU_Region_InitTypeDef MPU_InitStruct;

/* 禁止 MPU */
HAL_MPU_Disable();

/* 配置AXI SRAM的MPU属性为Write back, Read allocate,Write allocate */
MPU_InitStruct.Number           = MPU_REGION_NUMBER0;
MPU_InitStruct.Enable           = MPU_REGION_ENABLE;
MPU_InitStruct.BaseAddress      = 0x24000000;
MPU_InitStruct.Size             = MPU_REGION_SIZE_512KB;
MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
MPU_InitSruct.IsBufferable      = MPU_ACCESS_BUFFERABLE;
MPU_InitStruct.IsCacheable      = MPU_ACCESS_CACHEABLE;
MPU_InitStruct.IsShareable      = MPU_ACCESS_NOT_SHAREABLE;
MPU_InitStruct.TypeExtField     = MPU_TEX_LEVEL1;
MPU_InitStruct.SubRegionDisable = 0x00;
MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_ENABLE;

HAL_MPU_ConfigRegion(&MPU_InitStruct);

/*使能 MPU */
HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);

Number参数:设定当前配置的保护区域编号。此处配置的是0号区域。一共16个区域,0-15
MPU总共有16个可以独立配置的内存保护区域(在CM4内核的MCU中是8个),范围从015。对应的参数就是MPU_REGION_NUMBER0到MPU_REGION_NUMBER15。注意,这些区域编号顺序和其保护的内存区域的顺序无关。也就是说,完全可以配置1号区域为0x240000000x24080000,而2号区域用来保护0x00000000~0x00010000。
MPU保护的区域可以重叠。在发生重叠的时候,优先应用高序号的MPU配置。也就是,序号更大的MPU区域优先级更高。
除了0~15这16个保护区域外,还有一个编号为-1的内存保护区域,其称之为默认区域(default region)或背景区域(background region)。其优先级为最低。默认区域的访问策略由启用MPU的函数HAL_MPU_Enable的参数指定。

Enable参数:此参数用来决定此区域的MPU配置是否启用。

/** @defgroup CORTEX_MPU_Region_Enable CORTEX MPU Region Enable
  * @{
  */
#define  MPU_REGION_ENABLE     ((uint8_t)0x01)
#define  MPU_REGION_DISABLE    ((uint8_t)0x00)

BaseAddress参数、Size参数:此参数用来确定内存保护区域的具体范围
这两个参数在一起确定了内存区域的范围。其中BaseAddress是保护区域的起始地址。Size则是区域的大小。内存区域的起始地址必须对齐到设定的大小。比如将Size设定为1M,那么BaseAddress就必去对齐到1M。即 BaseAddress % Size == 0 。此外,Size是不能随意设置的,只能从 MPU_REGION_SIZE_xxx的宏中进行选取
AccessPermission参数:配置此区域的内存访问(读写)权限
在这里插入图片描述
SubRegionDisable参数
这个位用于控制内存区的子区域,使用的是 bit[15:8],共计 8 个 bit,一个 bit 控制一个子区域,0表示使能此子区域,1 表示禁止此子区域。一般情况,基本不使用子区域的禁止功能,所以配置 HAL 库的 SubRegionDisable 参数时,直接取值 0x00 即可,表示 8 个子区域均使能。
DisableExec参数:这个参数用来控制当前区域中的指令(代码)是否可以执行
XN=0 表示使能指令提取,即这块内存区可以执行程序代码,XN=1 表示禁止指令提取,即这块内存区禁止执行程序代码。

/** @defgroup CORTEX_MPU_Instruction_Access CORTEX MPU Instruction Access
  * @{
  */
#define  MPU_INSTRUCTION_ACCESS_ENABLE      ((uint8_t)0x00)
#define  MPU_INSTRUCTION_ACCESS_DISABLE     ((uint8_t)0x01)

IsBufferable、IsCacheable、IsShareable、TypeExtField参数:这几个参数组合起来共同决定了所配置的内存区域的缓存和共享策略

 MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE;
 MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE;
 MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
 MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL1;

在这里插入图片描述
S位用于解决多总线或者多核访问的共享问题,一般不要开启;
TEX = 000表示读开辟,RA; TEX= 001表示读写开辟RWA;
C表示缓存使能标志–cacheable,1表示使能;
B表示bufferable,1表示回写,0表示透写。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

四种Cache( MPU) 配置的读写操作流

注意,M7 内核只要开启了 Cache,read allocate 就是开启的。

1、配置 Non-cacheable

就是正常的读写操作,无 Cache。
在这里插入图片描述
在这里插入图片描述在这里插入图片描述
在这里插入图片描述
此处可以看看另一篇文章的解释https://blog.csdn.net/qq_28242041/article/details/129582995,方便理解上面为什么说读写错误
在这里插入图片描述
在这里插入图片描述

透写和回写缓存(Write Through and Write Back in Cache)

透写和回写缓存
高速缓存(Cache)是一种将数据副本临时存储在可快速访问的存储内存中的技术。缓存将最近使用的数据存储在小内存中,以提高访问数据的速度。它充当 RAM 和 CPU 之间的缓冲区,从而提高处理器可用数据的速度。每当处理器想要写入一个字时,它都会检查它想要写入数据的地址是否存在于缓存中。如果地址存在于缓存中,即写入命中(Write Hit)。我们可以更新缓存中的值并避免昂贵的主内存访问。但这会导致数据不一致(Inconsistent Data)问题。由于高速缓存和主存都有不同的数据,如在多处理器系统中,这将导致两个或多个共享主存的设备出现问题。这就是透写(Write Through)和回写(Write Back)出现的地方。

透写(Write Through)
在透写(Write Through)场景中,数据同时更新到缓存和内存(simultaneously updated to cache and memory)。这个过程更简单、更可靠。这用于没有频繁写入缓存的情况(写入操作的次数较少)。

它有助于数据恢复(在断电或系统故障的情况下)。因为我们必须写入两个位置(内存和缓存),数据写入将经历延迟。虽然它解决了不一致的问题,但它的问题是在写操作中使用缓存的优势,因为使用缓存的全部目的是避免对主内存的多次访问。
在这里插入图片描述

回写(Write Back)
回写(Write Back)也被称为延迟写入(Write Behind / Write Deferred)。也就是说,最初数据只在缓存中更新,稍后再更新到内存中。对内存的写入动作会被推迟,直到修改的内容在缓存中即将被另一个缓存块替换。
在这里插入图片描述
变脏标志位(Dirty Bit):缓存中的每个块都需要一个位来指示缓存中存在的数据是被修改(变脏的)还是未被修改(干净的)。如果它是干净的,则无需将其写入内存。它旨在减少对内存的写操作。如果缓存发生故障(Cache fails)或系统发生故障(System fails)或断电(Power outages),修改后的数据将丢失。因为如果数据丢失了,几乎不可能从缓存中恢复数据。
支持回写的缓存实现起来比较复杂,因为它需要跟踪哪些位置已被覆盖,并将它们标记为变脏,以便稍后写入后备内存中。只有当这些位置的数据从缓存中被逐出时,它们才会被写回后备内存中,这种效果称为延迟写入。出于这个原因,回写缓存中的读取未命中(需要一个块被另一个块替换)通常需要两次内存访问来服务:一次将替换的数据从缓存写回存储,然后一次检索所需的数据。
其他策略也可能触发数据回写。如客户端可能对缓存中的数据进行了多次更改,然后显式通知缓存写回数据。

回写(Write Back)通常与写分配(Write Allocation)一起使用。因为这样不需要将数据从内存中带入缓存,然后再把数据更新缓存和主内存中。同时希望后续写入(甚至读取)到现在已缓存的同一位置。
透写(Write Through)通常与无写分配(No Write Allocate)一起使用。因为它们仍然需要直接写入后备内存,所以在这里后续写入没有优势。

STM32H7内存默认映射和属性

在这里插入图片描述
WT 表示 Write-through(透写)
WB 表示 Write-back(回写)
WA 表示 Write-allocate(写分配)
没有明确标注 WA 的就是 RA(读分配)
XN 的意思是 Execute-Never, 其含义为如果相应的地址空间是 XN,是绝不允许执行代码的。
存储器类型为 Normal 的才能使用 cache,并且 TCM 接口是 not cacheable 的。

MPU不配行不行?
在大多数的情况下,如果不访问外部存储空间(如LCD,Flash等),不开启cache的情况下,不配MPU不会有什么问题。但是:
1、H7关闭cache后,性能会有大幅度的下降。
2、由于H7的定位,我们也基本不可能不使用外部存储器。而访问外部存储的内存空间时,如果不配置MPU,则会出现很多奇怪的BUG。比如笔者遇到的FMC

文档参考:

透写和回写缓存(Write Through and Write Back in Cache):https://zhuanlan.zhihu.com/p/571429282
STM32H7/M7中的MPU(内存保护单元)配置详解:https://oshwhub.com/article/STM32H7-M7zhong-de-MPU-nei-cun-bao-hu-dan-yuan-pei-zhi-yang-xie
https://blog.csdn.net/qq_28242041/article/details/129582995
使用STM32H7的FMC注意MPU配置:https://www.armbbs.cn/forum.php?mod=viewthread&tid=89929
STM32H750使用FMC控制LCD数据异常:https://www.stmcu.org.cn/module/forum/forum.php?mod=viewthread&tid=623865&page=1#pid2491693

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/447587.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

QML图形动画基础之

图形动画基础 颜色&#xff08;color&#xff09;渐变&#xff08;Gradient&#xff09;系统调色面板(SystemPalette) 图片边界动画&#xff08;BorderImage&#xff09;动态图片&#xff08;AnimatedImage&#xff09;缩放&#xff0c;旋转和平移变换Transform实现高级变换 颜…

CLion开发工具 | 01 - 认识外观界面

专栏介绍 一、创建/打开项目 二、外观和界面 1. 文件编辑区 CLion的自动提示功能如下&#xff1a; CLion的参数提示功能如下&#xff1a; CLion的形参名称显示功能&#xff1a; 2. 项目文件浏览区 3. 工具栏 3.1. 一键编译运行 CLion内置了MinGW&#xff0c;点击运行可以…

卷积神经网络推理特征图可视化查看,附录imagenet类别和编号对应查询表。通过观察法进行深度学习可解释研究

CNN模型虽然在图像处理上表现出非常良好的性能和准确性&#xff0c;但一直以来都被认为是一个黑盒模型&#xff0c;人们无法了解里面的工作机制。 针对这个问题&#xff0c;研究人员除了从理论层面去寻找解释外&#xff0c;也提出了一些可视化的方法直观地理解CNN的内部机理&am…

atl创建avtive

activex无窗口问题 控件在编码过程中要检查m_hWnd是否存在&#xff0c;不然vs可能会出现绘制错乱和崩溃 atl窗体通过CComControlBase的内部变量控制&#xff0c;窗体属性&#xff0c;包括onsize事件对应的m_bRecomposeOnResize变量控制窗体变化事件响应。 可插入的控件 授权…

Hbase基本操作

目录 HBASE 基本操作 hbase shell&#xff1a;进入hbase shell环境 status命令&#xff1a;查看集群状态 version&#xff1a;查看版本信息 create&#xff1a;创建表 drop 删除表 list&#xff1a;查看所有表 desc &#xff1a;查看表结构 exists &#xff1a;查看表…

分布式数据一致性解决方案推理过程

redis是一个极轻量级的进程&#xff0c;单机单线程单进程。 使用redis很容易实现分布式锁&#xff1a;setnx&#xff0c;同一个key&#xff0c;谁设置成功了&#xff0c;谁就抢到了锁&#xff0c;所以就产生了多锁问题。 假设客户端1抢到了锁&#xff0c;redis挂了&#xff0c…

Docker下载、安装

安装docker前&#xff0c;需要安装WSL Linux 内核、Hyper-V Hyper-V 首先确认系统是否安装&#xff1a;Hyper-V 如果没有则安装&#xff1a; pushd "%~dp0" dir /b %SystemRoot%\servicing\Packages\*Hyper-V*.mum >hyper-v.txt for /f %%i in (findstr /i . h…

java中的泛型

1.2 泛型的引入 在Java中&#xff0c;我们在声明方法时&#xff0c;当在完成方法功能时如果有未知的数据需要参与&#xff0c;这些未知的数据需要在调用方法时才能确定&#xff0c;那么我们把这样的数据通过形参表示。在方法体中&#xff0c;用这个形参名来代表那个未知的数据…

如何在四维轻云地理空间数据管理云平台中搭建场景?

《四维轻云》是一款轻量化的地理空间数据管理云平台&#xff0c;支持地理空间数据的在线管理、编辑以及分享。平台有项目管理、数据上传、场景搭建、发布分享、素材库等功能模块&#xff0c;支持多用户在线协作管理&#xff0c;实现了轻量化、便捷化的空间数据应用。 目前&…

< 前端性能优化: 资源加载优化 >

文章目录 &#x1f449; 前言&#x1f449; 一、路由懒加载> 实现代码> 处理前后各文件大小情况 &#x1f449; 二、组件懒加载> 实现代码> 适用场景 &#x1f449; 三、骨架屏优化白屏时长&#x1f449; 四、JavaScript 的6种加载方式1. 正常模式2. async 模式3. …

云端上的结题报告——凌恩智能交付系统

做组学分析的小伙伴不难发现&#xff0c;在拿到测序分析结果后&#xff0c;经常会需要进行调整&#xff0c;比如&#xff1a;配色不符合自己审美、分组需要重新设置、重复性差需要剔除样本等&#xff0c;面对重新分析或改图的情况&#xff0c;自学生信费时费力&#xff0c;找公…

ClickHouse数据一致性

目录 1 准备测试表和数据2 手动OPTIMIZE(不推荐)3 通过 Group by 去重4 通过 FINAL 查询4.1 老版本测试4.2 新版本测试 1 准备测试表和数据 查询 CK 手册发现&#xff0c;即便对数据一致性支持最好的 Mergetree&#xff0c;也只是保证最终一致性&#xff1a; 我们在使用 Repl…

条码控件Aspose.BarCode入门教程(7):如何在Java 中的 GS1-128 条码生成器

Aspose.BarCode for .NET 是一个功能强大的API&#xff0c;可以从任意角度生成和识别多种图像类型的一维和二维条形码。开发人员可以轻松添加条形码生成和识别功能&#xff0c;以及在.NET应用程序中将生成的条形码导出为高质量的图像格式。 Aspose API支持流行文件格式处理&am…

C语言—深度剖析数据在内存中的存储

深度剖析数据在内存中的存储 数据类型介绍类型的基本归类整形在内存中的存储大小端介绍整形在内存中的存储的相关练习浮点型在内存中的存储浮点型在内存中的存储相关介绍 数据类型介绍 内置类型&#xff08;C语言本身就具有的类型&#xff09;&#xff1a; char //字符…

linux_时序竞态-pause函数-sigsuspend函数-异步I/O-可重入函数-不可重入函数

接上一篇&#xff1a;linux_信号捕捉-signal函数-sigaction函数-sigaction结构体 今天来分享时序竞态的知识&#xff0c;关于时序竞态的问题&#xff0c;肯定会和cpu有关&#xff0c;也会学习两个函数&#xff0c;pause函数&#xff0c;sigsuspend函数&#xff0c; 也会分享什么…

教你轻松申请Azure OpenAI

Azure OpenAI 和 OpenAI 官方提供的服务基本是一致的&#xff0c;但是目前前者还是处于预览版的状态&#xff0c;一些功能还没有完全开放。 优点&#xff1a; 不受地域限制&#xff0c;国内可以直接调用。可以自己上传训练数据进行训练&#xff08;据说很贵&#xff09;。Azu…

【原理图专题】Cadence如何导出智能PDF

原理图导出PDF只会使用打印?打印后没有书签还需要手动建立多页面的书签? 其实Cadence支持导出智能pdf,不仅能够在pdf上直接看到料件的各种参数,还可以直接点击连页符跳转到对应的页面和网络上,并且还能根据页面自动建立完整的书签,方便查找。 最终能生成如下所示的页面…

建筑负荷需求响应的介绍

可再生能源发展及电网用电平衡现状 近些年,我国城市建筑的电网供给和需求存在严重的不平衡问题,特别是当受建筑空调季节性负荷的影响时。一方面夏季及冬季电力负荷短缺,而另外一方面全年仍然存在着发电设备过剩、运行小时数不足等问题。以加州为例,夏季高峰用电中 50%左右…

一个对付小孩便秘的指南,让麻麻不再当催屎员

便秘在儿童中很常见。多达30%的儿童患有便秘。据估计&#xff0c;它占所有儿科医生的3%-5%。便秘通常包括排便困难或排便频率降低。正常排便的频率和特征在不同的儿童时期是不同的&#xff0c;因此没有单一的正常定义。●在足月新生儿中&#xff0c;第一次排便通常发生在出生后…

Linux 下 安装多个mysql8.0

1:下载mysql wget https://dev.mysql.com/get/Downloads/MySQL-8.0/mysql-8.0.33-linux-glibc2.17-x86_64-minimal.tar 2&#xff1a;解压下载的mysql压缩包 解压mysql-8.0.33-linux-glibc2.17-x86_64-minimal.tar tar -xf mysql-8.0.33-linux-glibc2.17-x86_64-minimal.ta…