STM32H7 内部SRAM空间的配置使用
STM32H750xB器件集成了高速嵌入式存储器,配有128 KB的Flash内存,高达1 MB的RAM(包括192 KB的TCM RAM、高达864 KB的用户SRAM和4 KB的备份SRAM),以及大量连接到APB总线、AHB总线、2个32位多AHB总线矩阵的增强型I/O和外设,支持内部及外部存储器访问的多层AXI互连。
📘内部 SRAM
STM32H7x3 器件具有:
- 多达 864 KB 的系统 SRAM
- 128 KB 的数据 TCM RAM
- 64 KB 的指令 TCM RAM
- 4 K 字节的备份 SRAM
嵌入式系统 SRAM 最多可分为五个块: -
- AXI SRAM(D1 域):
– 映射到地址 0x2400 0000 的 AXI SRAM,可供除 BDMA 外的所有系统主设备通过 D1 域 AXI 总线矩阵访问.
- AXI SRAM(D1 域):
- 6 个从接口端 ASIB1 到 ASIB6外接的主控是 LTDC,DMA2D,MDMA,SDMMC1,AXIM 和 D2-to-D1 AHB 总线。
- 7 个主接口端 AMIB1 到 AMIB7外接的从设备是 AHB3 总线,Flash A,Flash B,FMC 总线,QSPI 和 AXI SRAM。另外 AHB3,也是由 AXI 总线分支出来的,然后再由 AHB3 分支出 APB3 总线。
-
- AHB SRAM(D2 域):
– 映射到地址 0x3000 0000 的 AHB SRAM1,可供除 BDMA 外的所有系统主设备通过 D2 域 AHB 矩阵访问
– 映射到地址 0x3002 0000 的 AHB SRAM2,可供除 BDMA 外的所有系统主设备通 过 D2 域 AHB 矩阵访问
– 映射到地址 0x3004 0000 的 AHB SRAM3,可供除 BDMA 外的所有系统主设备通 过 D2 域 AHB 矩阵访问
- AHB SRAM(D2 域):
- 10 个从接口:外接的主控是 D1-to-D2 AHB 总线,AHBP 总线,DMA1,DMA2,Ethernet MAC,SDMMC2,
USB HS1 和 USB HS2。- 9 个主接口:外接的从设备是 SRAM1,SRMA2,SRAM3,AHB1,AHB2,APB1,APB2,D2-to-D1 AHB
总线和 D2-to-D3 AHB 总线
-
- AHB SRAM(D3 域):
– 映射到地址 0x3800 0000 的 AHB SRAM4,可供大多数系统主设备通过 D3 域 AHB 矩阵访问系统 AHB SRAM 可按字节、半字(16 位单元)或全字(32 位单元)访问,而系统 AXI SRAM 可按字节、半字、全字或双字(64 位单位)访问。这些存储器可在最高系统时钟频率下以 0 等待周期寻址。
当 AHB 主设备对 SRAM 中的一部分进行读/写访问的同时,以太网 MAC 或 USB OTG HS 外设可以访问 SRAM 的另一部分。例如,以太网 MAC 访问 SRAM2,同时 CPU 访SRAM1。
TCM SRAM 专用于 Cortex®-M7:
- AHB SRAM(D3 域):
-
- TCM 接口上的 DTCM-RAM 映射到地址 0x2000 0000,可供 Cortex®-M7 访问,并且可供 MDMA 通过 Cortex®-M7 CPU 的 AHBS 从总线访问。
-
- TCM 接口上的 ITCM-RAM 映射到地址 0x0000 0000,可供 Cortex®-M7 访问,并且可供 MDMA 通过 Cortex®-M7 CPU 的 AHBS 从总线访问。
备份 RAM 映射到地址 0x3880 0000,可供大多数系统主设备通过 D3 域的 AHB 矩阵访问。
- TCM 接口上的 ITCM-RAM 映射到地址 0x0000 0000,可供 Cortex®-M7 访问,并且可供 MDMA 通过 Cortex®-M7 CPU 的 AHBS 从总线访问。
- 3 个从接口:外接的主控 D1-to-D3 AHB 总线,D2-to-D3 AHB 总线和 BDMA。
- 2 个主接口:外接的从设备是 AHB4,SRAM4 和 Bckp SRAM。另外 AHB4 也是这个总线矩阵分支出来的,然后再由 AHB4 分支出 APB4 总线.
📗各块 RAM 特性
各块 RAM 的特性对比如下,特别注意他们支持的最大速度和容量大小。
◆ TCM 区
TCM : Tightly-Coupled Memory 紧密耦合内存 。ITCM 用于运行指令,也就是程序代码,DTCM
用于数据存取,特点是跟内核速度一样,而片上 RAM 的速度基本都达不到这个速度,所以有降频处
理。
速度:400MHz。
DTCM 地址:0x2000 0000,大小 128KB。
ITCM 地址:0x0000 0000,大小 64KB。
◆ AXI SRAM 区
位于 D1 域,数据带宽是 64bit,挂在 AXI 总线上。除了 D3 域中的 BDMB 主控不能访问,其它都可
以访问此 RAM 区。
速度:200MHz。
地址:0x2400 0000,大小 512KB。
用途:用途不限,可以用于用户应用数据存储或者 LCD 显存。
◆ SRAM1,SRAM2 和 SRAM3 区
位于 D2 域,数据带宽是 32bit,挂在AHB 总线上。除了 D3域中的 BDMB主控不能访问这三块SRAM,
其它都可以访问这几个 RAM 区。
速度:200MHz。
SRAM1:地址 0x3000 0000,大小 128KB,用途不限,可用于 D2 域中的 DMA 缓冲,也可以当
D1 域断电后用于运行程序代码。
SRAM2:地址 0x3002 0000,大小 128KB,用途不限,可用于 D2 域中的 DMA 缓冲,也可以用于
用户数据存取。
SRAM3:地址 0x3004 0000,大小 32KB,用途不限,主要用于以太网和 USB 的缓冲。
◆ SRAM4 区
位于 D3 域,数据带宽是 32bit,挂在 AHB 总线上,大部分主控都能访这块 SRAM 区。
速度:200MHz。
地址:0x3800 0000,大小 64KB。
用途:用途不限,可以用于 D3 域中的 DMA 缓冲,也可以当 D1 和 D2 域进入 DStandby 待机方式后,继续保存用户数据。
◆ Backup SRAM 区
备份 RAM 区,位于 D3 域,数据带宽是 32bit,挂在 AHB 总线上,大部分主控都能访问这块 SRAM区。
速度:200MHz。
地址:0x3880 0000,大小 4KB。
用途:用途不限,主要用于系统进入低功耗模式后,继续保存数据(Vbat 引脚外接电池)。
- 📄外设内存映射地址,在
stm32h750xx.h
文件中定义:
/** @addtogroup Peripheral_memory_map
* @{
*/
#define D1_ITCMRAM_BASE (0x00000000UL) /*!< Base address of : 64KB RAM reserved for CPU execution/instruction accessible over ITCM */
#define D1_ITCMICP_BASE (0x00100000UL) /*!< Base address of : (up to 128KB) embedded Test FLASH memory accessible over ITCM */
#define D1_DTCMRAM_BASE (0x20000000UL) /*!< Base address of : 128KB system data RAM accessible over DTCM */
#define D1_AXIFLASH_BASE (0x08000000UL) /*!< Base address of : (up to 128 KB) embedded FLASH memory accessible over AXI */
#define D1_AXIICP_BASE (0x1FF00000UL) /*!< Base address of : (up to 128KB) embedded Test FLASH memory accessible over AXI */
#define D1_AXISRAM_BASE (0x24000000UL) /*!< Base address of : (up to 512KB) system data RAM accessible over over AXI */
#define D2_AXISRAM_BASE (0x10000000UL) /*!< Base address of : (up to 288KB) system data RAM accessible over over AXI */
#define D2_AHBSRAM_BASE (0x30000000UL) /*!< Base address of : (up to 288KB) system data RAM accessible over over AXI->AHB Bridge */
#define D3_BKPSRAM_BASE (0x38800000UL) /*!< Base address of : Backup SRAM(4 KB) over AXI->AHB Bridge */
#define D3_SRAM_BASE (0x38000000UL) /*!< Base address of : Backup SRAM(64 KB) over AXI->AHB Bridge */
#define PERIPH_BASE (0x40000000UL) /*!< Base address of : AHB/APB Peripherals */
#define QSPI_BASE (0x90000000UL) /*!< Base address of : QSPI memories accessible over AXI */
#define FLASH_BANK1_BASE (0x08000000UL) /*!< Base address of : (up to 128 KB) Flash Bank1 accessible over AXI */
#define FLASH_BANK2_BASE (0x08100000UL) /*!< For legacy only , Flash bank 2 not available on STM32H750xx value line */
#define FLASH_END (0x0801FFFFUL) /*!< FLASH end address */
/* Legacy define */
#define FLASH_BASE FLASH_BANK1_BASE
/*!< Device electronic signature memory map */
#define UID_BASE (0x1FF1E800UL) /*!< Unique device ID register base address */
#define FLASHSIZE_BASE (0x1FF1E880UL) /*!< FLASH Size register base address */
🌟各块 RAM 的 DMA 问题
- Bus Master 总线主控端和 Bus Slave 设备端的控制互联::
- 加粗字体是 64 位总线(ITCM,DTCM,Flash A,Flash,AXI SRAM,FMC 等),普通字体是 32位总线。
- 访问通路(每个小方块里面的字符);
- 任何有数字的表示有访问通路。
- 短横杠“-”表示不可访问。
- 有灰色阴影的表示有实用价值的访问通路
- 总线访问类型:
普通字体表示 32 位总线。
斜体表示 32 位总线主机端/ 64 位总线从机端。
粗体表示 64 位总线.
- 以上相关内容参考来源
安富莱_STM32-V7开发板_用户手册
。
📒通过这个总线互联图,要了解到下面三个重要知识点:
◆ DTCM 和 ITCM 不支持 DMA1,DMA2 和 BDMA,仅支持 MDMA。
◆ AXI SRAM,SRAM1,SRAM2,SRAM3 不支持 BDMA,支持 MDMA,DMA1 和 DMA2。
◆ SRAM4 支持所有 DMA,即 MDMA,DMA1,DMA2 和 BDMA
🛠配置使用
- 用户变量定义到指定的CCM 或者SRAM中:
//AC5 Compliler
__align(4) uint8_t SendBuff[SEND_BUF_SIZE]__attribute((at(0X24040000)));
//__ARMCC_VERSION >= 6010050
__attribute__((section (".RAM_D3"))) uint8_t g_spiTxBuf[SPI_BUFFER_SIZE];
- 采用4字节对齐方式
#if defined ( __ICCARM__ ) /* IAR Compiler */
#pragma data_alignment=4
#endif /* defined ( __ICCARM__ ) */
/* Internal string descriptor. */
__ALIGN_BEGIN uint8_t USBD_StrDesc[USBD_MAX_STR_DESC_SIZ] __ALIGN_END;
#if defined ( __ICCARM__ ) /*!< IAR Compiler */
#pragma data_alignment=4
#endif
__ALIGN_BEGIN uint8_t USBD_StringSerial[USB_SIZ_STRING_SERIAL] __ALIGN_END = {
USB_SIZ_STRING_SERIAL,
USB_DESC_TYPE_STRING,
};
......
uint8_t USART_RX_BUF[64*2] __attribute__((section(".ARM.__at_0x24000000")));
📘自定义分散加载(.SCT)文件
- 🌿片内启动,片上RAM配置(Start addr:0x08000000)
LR_IROM1 0x08000000 0x00200000 { ; load region size_region
ER_IROM1 0x08000000 0x00200000 { ; load address = execution address
*.o (RESET, +First)
*(InRoot$$Sections)
.ANY (+RO)
}
; RW data - 128KB DTCM
RW_IRAM1 0x20000000 0x00020000 {
.ANY (+RW +ZI)
}
; RW data - 512KB AXI SRAM
RW_IRAM2 0x24000000 0x00080000 {
*(.RAM_D1)
}
; RW data - 128KB SRAM1(0x30000000) + 128KB SRAM2(0x3002 0000) + 32KB SRAM3(0x30040000)
RW_IRAM3 0x30000000 0x00048000 {
*(.RAM_D2)
}
; RW data - 64KB SRAM4(0x38000000)
RW_IRAM4 0x38000000 0x00010000 {
*(.RAM_D3)
}
- 🌿片外启动,片上RAM配置(Start addr:0x90000000)
; *************************************************************
; *** Scatter-Loading Description File generated by uVision ***
; *************************************************************
LR_IROM1 0x90000000 0x20000000 { ; load region size_region
ER_IROM1 0x90000000 0x20000000 { ; load address = execution address
*.o (RESET, +First)
*(InRoot$$Sections)
.ANY (+RO)
.ANY (+XO)
}
RW_IRAM1 0x20000000 0x00020000 { ; RW data - 128KB DTCM
.ANY (+RW +ZI)
}
RW_IRAM2 0x24000000 0x00080000 { ; RW data - 512KB AXI SRAM
.ANY (+RW +ZI)
}
; RW data - 128KB SRAM1(0x30000000) + 128KB SRAM2(0x3002 0000) + 32KB SRAM3(0x30040000)
RW_IRAM3 0x30000000 0x00048000 {
*(.RAM_D2)
}
; RW data - 64KB SRAM4(0x38000000)
RW_IRAM4 0x38000000 0x00010000 {
*(.RAM_D3)
}
}
- 🔖以下内容参考来自:安富莱stm32-V7用户手册
- LR_IROM1 是 Load Region 加载域,ER_IROM1 是 Execution Region 执行域。首地址都是 0x0800 0000,大小都是 0x0020 0000,即 STM32H7 的 Flash 地址和对应大小。
- 加载域就是程序在 Flash 中的实际存储,而运行域是芯片上电后的运行状态,通过下面的框图可以有一个感性的认识:
通过上面的框图可以看出,RW 区也是要存储到 ROM/Flash 里面的,在执行映像之前,必须将已初始化的 RW 数据从 ROM 中复制到 RAM 中的执行地址并创建 ZI Section(初始化为 0 的变量区)。
的*.o (RESET, +First)
:在启动文件 startup_stm32h750xx.s 有个段名为 RESET 的代码段,主要存储了中断向量表。这里是将其存放在 Flash 的首地址。*(InRoot$$Sections)
:将 MDK 的一些库文件全部放在根域,比如__main.o, _scatter*.o, _dc*.o.ANY (+RO)
:将目标文件中所有具有 RO 只读属性的数据放在这里,即 ER_IROM1。RW_IRAM1
是执行域,配置的是 DTCM,首地址 0x2000 0000,大小 128KB。将目标文件中所有具有 RW 和 ZI 数据放在这里。RW_IRAM2
是执行域,配置的是 AXI SRAM,首地址 0x24000000,大小 512KB。给这个域专门配了一个名字 .RAM_D1。这样就可以通过__attribute__((section(“name”)))将其分配到这个 RAM 域。RW_IRAM3
是执行域,配置的是 D2 域的 SRAM1,SRAM2 和 SRAM3,首地址0x30000000,共计大小 288KB。给这个域专门配了一个名字 .RAM_D2。这样就可以通过__attribute__((section(“name”)))将其分配到这个 RAM 域。RW_IRAM3
是执行域,配置的是 D3 域的 SRAM4,首地址 0x38000000,共计大小
64KB。给这个域专门配了一个名字 .RAM_D3。这样就可以通过__attribute__((section(“name”))),将其分配到这个 RAM 域。
- 在外设开启DMA传输模式下同时启用了I缓存和D缓存下,有必要开启这样的设置,不然读取的数据容易出错。
- I缓存和D缓存启用下,串口DMA传输:
SCB_CleanDCache_by_Addr((uint8_t *)USART_RX_BUF, len);
// SCB_CleanInvalidateDCache_by_Addr ((uint8_t *)USART_RX_BUF, len);//或者
HAL_UART_Transmit_DMA(&huart1,(uint8_t *)USART_RX_BUF, len);//配合上面的函数一起使用
- 读取数据操作:
- I缓存和D缓存启用,接收数组变量指定SRAM情况下,读取数据可以不用在读前读后,分别作启用和禁用的操作。不包括上面表中:短横杠“-”表示不可访问的外设。
📑相关函数
- 🌿
void SCB_CleanDCache_by_Addr (uint32_t *addr, int32_t dsize)
:D-Cache Clean by address
- 作用: 用于清除指定地址范围内的数据缓存。它将缓存中的数据写回到主存储器中,以确保缓存中的数据与主存储器中的数据一致。
- 使用场景: 当你需要确保某个特定内存区域的数据已经被更新到主存储器时,可以使用这个函数。例如,在将数据写入外设之前,或者在修改了关键数据之后。
- 🌿
void SCB_CleanInvalidateDCache_by_Addr (uint32_t *addr, int32_t dsize)
:D-Cache Clean and Invalidate by address
- 作用: 这个函数不仅会清除指定地址范围内的数据缓存,还会使这些缓存行无效。这意味着在调用这个函数后,处理器将不会从缓存中读取这些地址的数据,而是直接从主存储器中读取。
- 使用场景: 当你需要确保某个内存区域的数据是最新的,并且不希望处理器从缓存中读取旧的数据时,可以使用这个函数。例如,在加载新的程序代码或数据到内存中之后。
- 🌿
SCB_CleanDCache()
函数:
作用: 这个函数用于将数据缓存中的数据写回到主存储器中,以确保缓存中的数据与主存储器中的数据一致。这通常在以下情况下使用:
在将数据写入外设之前,确保数据已经更新到主存储器。
在修改了关键数据之后,确保这些数据已经被正确地写回到主存储器。
特点: 只执行写回操作,不使缓存行无效。这意味着处理器仍然可以从缓存中读取数据,即使这些数据已经被写回到主存储器。 - 🌿
SCB_CleanInvalidateDCache()
函数:
作用: 这个函数不仅会将数据缓存中的数据写回到主存储器,还会使这些缓存行无效。这意味着在调用这个函数后,处理器将不会从缓存中读取这些地址的数据,而是直接从主存储器中读取。这通常在以下情况下使用:
在加载新的程序代码或数据到内存中之后,确保处理器使用的是最新的数据。
在需要确保数据一致性的关键操作之前,例如系统启动或上下文切换。
特点: 执行写回操作并且使缓存行无效。这确保了处理器在需要时总是从主存储器中获取最新的数据。
📙MPU内存保护单元
- 📌ST32 MPU应用笔记
AN4838
文档推荐:https://www.st.com/resource/zh/application_note/an4838-managing-memory-protection-unit-in-stm32-mcus-stmicroelectronics.pdf
MPU 可以将 memory map 内存映射区分为多个具有一定访问规则的区域,通过这些规则可以实现如下功能:
◆ 防止不受信任的应用程序访问受保护的内存区域。
◆ 防止用户应用程序破坏操作系统使用的数据。
◆ 通过阻止任务访问其它任务的数据区。
◆ 允许将内存区域定义为只读,以便保护重要数据。
◆ 检测意外的内存访问。
简单的说就是内存保护、外设保护和代码访问保护。
STM32H7的MPU提供多达16个可编程保护区域(region),每个区域(region)都有自己的可编程起始地址、大小及设置。MPU功能必须开启才会有效,MPU默认处于关闭的状态,使用MPU,必须先启用MPU才行.
- 配置MPU保护块
/*
*********************************************************************************************************
* 函 数 名: MPU_Config
* 功能说明: 保护整个AXI SRAM,共512K字节,允许指令访问,禁止共用,允许cache,允许缓冲
* 形 参: 无
* 返 回 值: 无
*********************************************************************************************************
*/
static void MPU_Config( void )
{
MPU_Region_InitTypeDef MPU_InitStruct;
/* 禁止 MPU */
HAL_MPU_Disable();
/* 配置 AXI SRAM 的 MPU 属性为 Write back, Read allocate,Write allocate */
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_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE;//允许缓冲
MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE;//允许cache
MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;//禁止共用
MPU_InitStruct.Number = MPU_REGION_NUMBER0;
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);
}
- 🌿片外启动MPU初始化配置:
void MPU_RegionConfig(void)
{
/* Disable MPU */
HAL_MPU_Disable();
/* 设置QSPI FLASH空间的MPU保护 */
SCB->SHCSR &= ~(1 << 16); /* 禁止MemManage */
MPU->CTRL &= ~(1 << 0); /* 禁止MPU */
MPU->RNR = 0; /* 设置保护区域编号为0(1~7可以给其他内存用) */
MPU->RBAR = 0X90000000; /* 基地址为0X9000 000, 即QSPI的起始地址 */
MPU->RASR = 0X0303002D; /* 设置相关保护参数(禁止共用, 允许cache, 允许缓冲), 详见MPU实验的解析 */
MPU->CTRL = (1 << 2) | (1 << 0);/* 使能PRIVDEFENA, 使能MPU */
SCB->SHCSR |= 1 << 16; /* 使能MemManage */
/* Enable MPU */
HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
}