TL;DR:文档指出,我必须先在微控制器中启用特定的内存区域,然后才能使用它。但是,我可以在启用它之前使用它,甚至在禁用它之后使用它。这怎么可能?
我目前正在为 STM32H743 微控制器开发一个应用程序。我不明白在时钟被禁用时 RAM 是如何正常工作的。
该 MCU 具有多个存储器,分布在多个电源域中:
- 在 D1 域中,它具有 ITCMRAM + DTCMRAM + AXI SRAM (64 + 128 + 512 kB)
- 在 D2 域中,它具有 SRAM1 + SRAM2 + SRAM3 (128 + 128 + 32 kB)
- 在 D3 域中,它具有 SRAM4 + 备份 SRAM (64 + 4 kB)
我想使用SRAM1。在参考手册(RM0433 Rev. 7)中,第 366 页指出:
如果 CPU 想要使用位于 D2 域中的存储器(SRAM1、SRAM2 和 SRAM3),则必须启用它们。
在第 452 页的寄存器设置中描述了如何执行此操作:
RCC AHB2 时钟寄存器 (RCC_AHB2ENR):
SRAM1EN: SRAM1 模块使能
由软件置位和复位。置位时,该位表示 SRAM1 由 CPU 分配。它使 D2 域也考虑 CPU 操作模式,即当 CPU 处于 CRun 时,将 D2 域保持在 DRun。
0:SRAM1 接口时钟被禁用。(复位后默认)
1:SRAM1 接口时钟使能。
因此,默认值(复位后)为 0,表示 SRAM1 接口被禁用。
在STM 社区论坛上的这个帖子中,问题是为什么 D2 RAM 不能正常工作,解决方案是启用 D2 RAM 时钟。执行此操作的“正确”方法是SystemInit()
(STM32H7 HAL 的一部分)。在 system_stm32h7xx.c 我们可以找到以下代码部分:
/************************* Miscellaneous Configuration ************************/
/*!< Uncomment the following line if you need to use initialized data in D2 domain SRAM (AHB SRAM)
*/
// #define DATA_IN_D2_SRAM
(...)
void SystemInit(void)
{
(...)
#if defined(DATA_IN_D2_SRAM)
/* in case of initialized data in D2 SRAM (AHB SRAM) , enable the D2 SRAM clock (AHB SRAM clock)
*/
# if defined(RCC_AHB2ENR_D2SRAM3EN)
RCC->AHB2ENR |= (RCC_AHB2ENR_D2SRAM1EN | RCC_AHB2ENR_D2SRAM2EN | RCC_AHB2ENR_D2SRAM3EN);
# elif defined(RCC_AHB2ENR_D2SRAM2EN)
RCC->AHB2ENR |= (RCC_AHB2ENR_D2SRAM1EN | RCC_AHB2ENR_D2SRAM2EN);
# else
RCC->AHB2ENR |= (RCC_AHB2ENR_AHBSRAM1EN | RCC_AHB2ENR_AHBSRAM2EN);
# endif /* RCC_AHB2ENR_D2SRAM3EN */
tmpreg = RCC->AHB2ENR;
(void)tmpreg;
#endif /* DATA_IN_D2_SRAM */
(...)
}
DATA_IN_D2_SRAM
因此,要使用 D2 SRAM,应该定义宏(或者您必须使用 手动启用时钟__HAL_RCC_D2SRAM1_CLK_ENABLE()
)。
但是,我没有定义这个宏,即使我手动禁用时钟,RAM 似乎工作得很好。
我的主要任务(我正在运行 FreeRTOS,这是目前唯一的任务)是这样的:
void main_task(void * argument)
{
__HAL_RCC_D2SRAM1_CLK_DISABLE();
__HAL_RCC_D2SRAM2_CLK_DISABLE();
__HAL_RCC_D2SRAM3_CLK_DISABLE();
mem_test(); // expected to fail, but runs successfully
for (;;) {}
}
内存测试用已知数据完全填充 D2 SRAM,然后对其计算 CRC。CRC 是正确的。我已经验证过缓冲区确实放在了 D2 SRAM 中(内存地址 0x30000400 在 SRAM1 的 0x30000000-0x3001FFFF 范围内)。的值RCC->AHB2ENR
被确认为 0(禁用所有时钟)。我还确认了地址RCC->AHB2ENR
是 0x580244DC,如数据表中所述。
数据缓存被禁用。
我在这里想念什么?为什么时钟被禁用时这个内存是可读写的?
更新:根据要求,这是我的内存测试代码,从中我得出的结论是内存可以成功写入和读取:
// NB: The sections are defined in the linker script.
static char test_data_d1[16] __attribute__((section(".RAM_D1_data"))) = "Test data in D1";
static char test_data_d2[16] __attribute__((section(".RAM_D2_data"))) = "Test data in D2";
static char test_data_d3[16] __attribute__((section(".RAM_D3_data"))) = "Test data in D3";
static char buffer_d1[256 * 1024ul] __attribute__((section(".RAM_D1_bss")));
static char buffer_d2[256 * 1024ul] __attribute__((section(".RAM_D2_bss")));
static char buffer_d3[ 32 * 1024ul] __attribute__((section(".RAM_D3_bss")));
static void mem_test(void)
{
// Fill the buffers each with a different test pattern.
fill_buffer_with_test_data(buffer_d1, sizeof(buffer_d1), test_data_d1);
fill_buffer_with_test_data(buffer_d2, sizeof(buffer_d2), test_data_d2);
fill_buffer_with_test_data(buffer_d3, sizeof(buffer_d3), test_data_d3);
uint32_t crc_d1 = crc32b((uint8_t const *)buffer_d1, sizeof(buffer_d1));
uint32_t crc_d2 = crc32b((uint8_t const *)buffer_d2, sizeof(buffer_d2));
uint32_t crc_d3 = crc32b((uint8_t const *)buffer_d3, sizeof(buffer_d3));
printf("CRC buffer_d1 = 0x%08lX\n", crc_d1);
printf("CRC buffer_d2 = 0x%08lX\n", crc_d2);
printf("CRC buffer_d3 = 0x%08lX\n", crc_d3);
assert(0xC29DFAED == crc_d1); // Python: hex(binascii.crc32(16384 * b'Test data in D1\0'))
assert(0x73B70C2A == crc_d2); // Python: hex(binascii.crc32(16384 * b'Test data in D2\0'))
assert(0xC30AE71E == crc_d3); // Python: hex(binascii.crc32(2048 * b'Test data in D3\0'))
}