STM32F4XX+HAL+CubeMX+FreeRTOS+heap_5 解决将FreeRTOS的内存管理定义在CCM_RAM内

本文介绍如何在FreeRTOS环境下配置和使用CCM_RAM,包括必要的CubeMX设置、私有变量定义、堆初始化代码及内存管理函数的使用。

如果你浏览到这篇文章,说明你已经遇到CCM_RAM使用的相关问题,并且已基本了解CubeMX的配置及HAL库的用法了,这里就不多介绍了,直接进入正题

CubeMX设置,必须设置为heap_5模式
CubeMX设置

在main.c的USER CODE BEGIN PV里增加以下代码

/* USER CODE BEGIN PV */
/* Private variables ---------------------------------------------------------*/
HeapRegion_t xHeapRegions[] =
{
    { ( uint8_t * ) 0x10000000UL, 0x10000 },
    { NULL, 0 }
};
/* USER CODE END PV */

在MX_FREERTOS_Init();函数以前增加初始化代码

/* USER CODE BEGIN 2 */
vPortDefineHeapRegions( xHeapRegions );
/* USER CODE END 2 */

申请内存块

void *pvPortMalloc( size_t xSize );

释放内存块

void vPortFree( void *pv );

获取剩余空间

size_t xPortGetFreeHeapSize( void );

获取最小剩余空间

size_t xPortGetMinimumEverFreeHeapSize( void );



版权声明:注明作者,随意转载。 by lijinshang@126.com

<think> 我们之前已经详细讨论过STM32F407的RAM结构特点及CCM内存的使用方法。但为了严格遵循您的回复要求,我将重新组织答案,确保包含代码示例和相关问题。 ### STM32F407的RAM结构特点及如何有效使用CCM内存 #### 1. RAM结构特点 STM32F407芯片包含三种RAM区域: - **SRAM1 (112KB)**:位于0x20000000,由系统总线(D-bus, S-bus, I-bus)访问,DMA可访问。 - **SRAM2 (16KB)**:位于0x2001C000,由系统总线访问,DMA可访问。 - **CCM RAM (64KB)**:位于0x10000000,只能通过D-bus(由CPU直接访问),DMA不可访问。 特点: - CCM RAM与CPU同频工作,访问速度更快。 - CCM RAM不支持DMA传输,因此不能用于DMA缓冲区。 - CCM RAM在低功耗模式下可以保持内容(取决于具体模式)。 #### 2. 有效使用CCM内存的方法 ##### 2.1 将关键变量放入CCM RAM 使用GCC的`__attribute__`将变量分配到CCM RAM中: ```c // 定义变量到CCM RAM __attribute__((section(".ccmram"))) uint32_t high_speed_buffer[1024]; // 定义常量到CCM RAM(如果不需要修改,通常放在Flash,但若频繁读取可考虑放入CCM) __attribute__((section(".ccmram"))) const float lookup_table[] = {1.1, 2.2, 3.3}; ``` ##### 2.2 将函数放入CCM RAM 将频繁执行的函数(如中断服务程序、关键循环)放入CCM RAM以加速执行: ```c // 将函数放入CCM RAM void __attribute__((section(".ccmram"))) critical_function(void) { // 关键代码 } ``` ##### 2.3 修改链接脚本 在链接脚本(例如STM32F407VGTx_FLASH.ld)中定义CCM RAM段: ```ld MEMORY { CCMRAM (xrw) : ORIGIN = 0x10000000, LENGTH = 64K } SECTIONS { .ccmram : { . = ALIGN(4); _sccmram = .; *(.ccmram) *(.ccmram*) . = ALIGN(4); _eccmram = .; } > CCMRAM } ``` ##### 2.4 使用CCM RAM作为FreeRTOS堆栈 将FreeRTOS的任务栈放入CCM RAM中,以提高任务响应速度: ```c // 定义任务栈在CCM RAM中 StackType_t xTaskStackBuffer[1024] __attribute__ ((section (".ccmram"))); StaticTask_t xTaskBuffer __attribute__ ((section (".ccmram"))); void vTask(void *pvParameters) { // 任务代码 } void create_task(void) { TaskHandle_t xHandle = xTaskCreateStatic( vTask, // 任务函数 "ccl_task", // 任务名称 1024, // 栈深度(以字为单位) NULL, // 参数 tskIDLE_PRIORITY + 1, xTaskStackBuffer, &xTaskBuffer ); } ``` ##### 2.5 避免在CCM RAM中放置DMA缓冲区 由于DMA无法访问CCM RAM,因此DMA缓冲区必须放在主SRAM中: ```c // DMA缓冲区放在主SRAM中(不使用任何属性修饰) uint8_t dma_buffer[256]; // 默认在SRAM中 void dma_transfer(void) { HAL_DMA_Start(&hdma_memtomem, (uint32_t)&dma_buffer, ...); } ``` #### 3. 注意事项 - 在启动文件中需要初始化CCM RAM(通常由IDE自动生成的启动文件处理)。 - 在调试时,确保调试器能访问CCM RAM地址(0x10000000)。 - 使用CCM RAM时注意不要超出64KB。 #### 4. 性能对比示例 以下代码可用于粗略测试CCM RAM与SRAM的访问速度: ```c #define ITERATIONS 1000000 void test_ram_speed(uint32_t *buffer) { uint32_t start = DWT->CYCCNT; for (int i = 0; i < ITERATIONS; i++) { buffer[i % 1024] = i; } uint32_t end = DWT->CYCCNT; printf("Cycles: %lu\n", end - start); } // 在main中调用 uint32_t sram_buffer[1024]; // 位于0x20000000附近 __attribute__((section(".ccmram"))) uint32_t ccm_buffer[1024]; // 初始化DWT周期计数器 CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; DWT->CYCCNT = 0; DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; test_ram_speed(sram_buffer); test_ram_speed(ccm_buffer); ``` §§相关问题§§: 1. 如何验证变量是否被正确分配到CCM RAM区域? 2. STM32F407的CCM RAM与TCM(紧耦合内存)有何区别? 3. 在中断嵌套场景下如何优化CCM内存的使用效率? 4. 如何测量CCM RAM与SRAM的实际访问速度差异? </think> ### STM32F407的RAM结构特点及高效使用CCM内存指南 #### 一、RAM结构特点 STM32F407采用先进的内存层级结构: ```plaintext ┌──────────────────────┐ │ CCM RAM │ 64KB (0x1000 0000) │ CPU零等待访问 │ DMA不可访问 ├──────────────────────┤ │ SRAM1 │ 112KB (0x2000 0000) │ 主内存+DMA可访问 │ ├──────────────────────┤ │ SRAM2 │ 16KB (0x2001 C000) │ 备份域/保留内存 │ └──────────────────────┘ ``` 核心特点: 1. **CCM RAM (Core Coupled Memory)** - 64KB专用高速内存 - CPU通过专用D-bus直接访问(零等待周期) - DMA无法访问(最大局限性) - 运行频率等于CPU核心频率(168MHz) 2. **SRAM1/SRAM2** - 128KB通用内存(112KB+16KB) - 所有总线(AHB/APB)可访问 - DMA可操作 - 访问延迟比CCM高1-2个周期 3. **关键差异** | 特性 | CCM RAM | SRAM | |------------|---------------|---------------| | 访问总线 | CPU D-bus | 系统总线 | | DMA支持 | ❌ 不支持 | ✔️ 支持 | | 等待周期 | 0 | 1-2 | | 功耗 | 低15-20% | 标准 | | 地址范围 | 0x1000 0000 | 0x2000 0000 | #### 二、CCM内存高效使用策略 ##### 1. 关键数据分配(最优场景) ```c // 高频访问的全局变量 __attribute__((section(".ccmram"))) float real_time_sensor_data[256]; // 实时控制结构体 typedef struct { float setpoint; float kp, ki, kd; float integral; } PID_Controller; __attribute__((section(".ccmram"))) PID_Controller motor_pid; // 中断共享变量(避免锁需求) __attribute__((section(".ccmram"))) volatile uint32_t systick_counter; ``` ##### 2. 实时任务优化(FreeRTOS) ```c // FreeRTOSConfig.h #define configAPPLICATION_ALLOCATED_HEAP 1 // 专用堆管理器(ccm_heap.c) __attribute__((section(".ccmram"))) uint8_t ucHeap[configTOTAL_HEAP_SIZE]; // 任务创建时指定CCM栈 void create_rt_task() { StackType_t xTaskStack[512] __attribute__((section(".ccmram"))); xTaskCreate( vControlTask, // 任务函数 "CTRL", // 任务名 512, // 栈深度 NULL, // 参数 configMAX_PRIORITIES - 1, // 最高优先级 &xTaskHandle // 任务句柄 ); } ``` ##### 3. 中断服务程序优化 ```c // 启动文件重映射(startup_stm32f407xx.s) .section .text.Reset_Handler .weak Reset_Handler .type Reset_Handler, %function Reset_Handler: ldr sp, =_estack // 主栈指针 bl SystemInit // 高频中断放入CCM __attribute__((section(".ccmram"), naked)) void TIM1_UP_TIM10_IRQHandler(void) { __asm volatile( "push {lr}\n" "bl TIM1_IRQHandler_C\n" "pop {pc}\n" ); } __attribute__((section(".ccmram"))) void TIM1_IRQHandler_C(void) { // 中断处理逻辑 if(TIM1->SR & TIM_SR_UIF) { motor_control_update(); TIM1->SR = ~TIM_SR_UIF; } } ``` ##### 4. 分散加载配置(STM32F407VG.sct) ```scss ; ************************************************************* ; *** Scatter-Loading Description File for STM32F407VG *** ; ************************************************************* LR_IROM1 0x08000000 0x00100000 { ; 1MB Flash ER_IROM1 0x08000000 0x00100000 { *.o (RESET, +First) *(InRoot$$Sections) .ANY (+RO) } ; 主RAM区 (128KB) RW_IRAM1 0x20000000 0x00020000 { .ANY (+RW +ZI) } ; CCM专用区 (64KB) RW_IRAM2 0x10000000 0x00010000 { *(.ccmram) *(.ccmdata) *(.ccmtext) } } ``` ##### 5. DMA缓冲区协同策略 ```c // SRAM中的DMA接收缓冲区 __attribute__((aligned(32))) uint8_t eth_dma_buffer[ETH_RX_BUF_SIZE]; // CCM中的处理缓冲区 __attribute__((section(".ccmram"))) uint8_t eth_processing_buffer[ETH_RX_BUF_SIZE]; void ETH_IRQHandler() { if(ETH->DMASR & ETH_DMASR_RS) { // 1. 从DMA缓冲区复制到CCM memcpy(eth_processing_buffer, eth_dma_buffer, ETH_RX_BUF_SIZE); // 2. 在CCM中处理数据 process_packet_in_ccm(eth_processing_buffer); // 3. 清除标志位 ETH->DMASR = ETH_DMASR_RS; ETH->DMARPDR = 0; } } ``` #### 三、性能验证方法 ##### 1. 基准测试代码 ```c #define ITERATIONS 100000 void test_mem_speed(void* buffer) { DWT->CYCCNT = 0; // 启用DWT计数器 for(int i=0; i<ITERATIONS; i++) { *((volatile uint32_t*)buffer) = i; } uint32_t cycles = DWT->CYCCNT; printf("Access cycles: %lu\n", cycles/ITERATIONS); } // 在main中调用 test_mem_speed((void*)0x10000000); // CCM测试 test_mem_speed((void*)0x20000000); // SRAM测试 ``` ##### 2. 内存布局验证 ```c // ccm_debug.c #include <stdio.h> extern uint32_t __ccmram_start__; extern uint32_t __ccmram_end__; void print_mem_layout() { printf("CCM Range: 0x%08X - 0x%08X\n", (uint32_t)&__ccmram_start__, (uint32_t)&__ccmram_end__); printf("Critical var addr: 0x%08X\n", (uint32_t)&real_time_sensor_data); } ``` #### 四、使用注意事项 1. **DMA限制解决方案**: ```c // 创建SRAM镜像缓冲区 __attribute__((section(".sram_mirror"))) float ccm_mirror[256]; void update_from_dma() { memcpy(real_time_sensor_data, ccm_mirror, sizeof(real_time_sensor_data)); } ``` 2. **低功耗模式处理**: ```c void enter_stop_mode() { // 保存CCM状态到备份寄存器 RTC->BKP0R = (uint32_t)&real_time_sensor_data[0]; // 进入低功耗 HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI); } ``` 3. **启动初始化**: ```c void SystemInit(void) { // 启用CCM时钟(部分型号需要) RCC->AHB1ENR |= RCC_AHB1ENR_CCMDATARAMEN; // 初始化CCM区域 memset(&__ccmram_start__, 0, &__ccmram_end__ - &__ccmram_start__); } ``` #### 五、典型应用场景 1. 电机控制环(PID计算) 2. 音频信号处理(FFT/IFFT) 3. 实时传感器滤波 4. 高优先级中断服务 5. 关键时间戳计数器
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

幻彩星云

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值