首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么即使当时钟被禁用时,D2内存也能正常工作?

为什么即使当时钟被禁用时,D2内存也能正常工作?
EN

Stack Overflow用户
提问于 2020-11-19 09:25:04
回答 1查看 1.3K关注 0票数 6

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域也考虑到D2的工作模式,即当CPU处于CRun状态时,将DRun域保持在DRun中。 0: SRAM1接口时钟被禁用。(重置后默认) 1:启用SRAM1接口时钟。

因此,默认值(重置后)为0,这意味着禁用了SRAM1接口。

在STM社区论坛上的这条线中,问题是为什么D2内存不能正常工作,解决方案是启用D2 RAM时钟。这样做的“正确”方法是在SystemInit() ( STM32H7 HAL的一部分)中。在system_stm32h7xx.c中,我们可以找到以下代码部分:

代码语言:javascript
复制
/************************* 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,这是目前唯一的任务)如下所示:

代码语言:javascript
复制
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,如数据表中所述。

数据缓存被禁用。

我在这里错过了什么?当时钟被禁用时,为什么这个内存是可读的和可写的?

更新:应请求,以下是我的内存测试代码,从中我得出结论,可以成功地编写和读取内存:

代码语言:javascript
复制
// 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'))
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-12-07 10:28:41

经过大量的测试和调查,我发现在一个最小的应用程序中禁用了D2 SRAM (如文档和预期的那样),使用了SysTick和几个LED来使测试结果可见。然而,当使用计时器(TIM1)而不是SysTick,或者启用USART时,D2 SRAM也被启用了,即使我在代码中没有启用它。实际上,添加以下任何一行代码都将隐式地启用D2内存:

代码语言:javascript
复制
__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。

票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/64908765

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档