TL;DR:文档声明,我必须在微控制器中启用特定的内存区域,然后才能使用它。但是,在启用它之前,甚至在禁用它之后,我都可以使用它。这怎麽可能?
我目前正在为STM32H743微控制器开发一个应用程序。当时钟被禁用时,我不明白RAM是如何正确工作的。
这个MCU有多个存储器,分散在多个电源域上:
我想使用SRAM1。参考手册(RM0433 Rev.7)第366页指出:
如果CPU想使用位于D2域中的内存(SRAM1、SRAM2和SRAM3),就必须启用它们。
在第452页的寄存器设置中,将介绍如何做到这一点:
RCC AHB2时钟寄存器(RCC_AHB2ENR): SRAM1EN: SRAM1块启用 通过软件设置和重置。设置时,此位指示SRAM1由CPU分配。它使D2域也考虑到D2的工作模式,即当CPU处于CRun状态时,将DRun域保持在DRun中。 0: SRAM1接口时钟被禁用。(重置后默认) 1:启用SRAM1接口时钟。
因此,默认值(重置后)为0,这意味着禁用了SRAM1接口。
在STM社区论坛上的这条线中,问题是为什么D2内存不能正常工作,解决方案是启用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 */
(...)
}因此,要使用D2内存,应该定义宏DATA_IN_D2_SRAM (或者您必须使用__HAL_RCC_D2SRAM1_CLK_ENABLE()手动启用时钟)。
然而,,,我没有定义这个宏,甚至当我手动禁用时钟时,内存似乎运行得很好。
我的主要任务(我正在运行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内存中,然后在其上计算CRC。儿童权利委员会是正确的。我已经验证了缓冲区确实放置在D2内存中(内存地址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'))
}发布于 2020-12-07 10:28:41
经过大量的测试和调查,我发现在一个最小的应用程序中禁用了D2 SRAM (如文档和预期的那样),使用了SysTick和几个LED来使测试结果可见。然而,当使用计时器(TIM1)而不是SysTick,或者启用USART时,D2 SRAM也被启用了,即使我在代码中没有启用它。实际上,添加以下任何一行代码都将隐式地启用D2内存:
__HAL_RCC_TIM1_CLK_ENABLE();
__HAL_RCC_USART3_CLK_ENABLE();STM支持已经证实了这种行为:
一旦激活D2中的任何外设,D2内存就会被激活。这意味着,如果您为位于D2域中的任何外围设备(AHB1、AHB2、APB1和APB2)启用时钟,则即使
RCC->AHB2ENR为0,D2 SRAM也是活动的。
我仍然在寻找一个可靠的来源(参考手册)来记录这种行为,但这似乎是一个合理的解释。
在实践中,我认为这意味着D2内存几乎总是自动启用的,因此您不必关心它,至少对于最常见的用例(例如,当使用任何外围设备或DMA控制器时)。只有当您想要使用D2内存,而不使用任何D2外围设备时,您才需要手动启用SRAM时钟。这也是启动代码的情况,在启动代码中(如果您选择实现此操作),将在启用任何外围设备之前初始化D2 SRAM。
https://stackoverflow.com/questions/64908765
复制相似问题