使用STM32F407的CCMRAM进行优化
写在前面
今天在搞STM32F4时,用到了一部分特殊内存——CCM。搜了搜网上没多少介绍,索性自己查手册。
某些芯片没有CCM
基本架构
废话少说,先看看这块内存特殊在哪里。官方的基本架构说明如下:
The main system consists of 32-bit multilayer AHB bus matrix that interconnects:
Eight masters:
– Cortex® -M4 with FPU core I-bus, D-bus and S-bus
– DMA1 memory bus
– DMA2 memory bus
– DMA2 peripheral bus
– Ethernet DMA bus
– USB OTG HS DMA bus
Seven slaves:
– Internal Flash memory ICode bus
– Internal Flash memory DCode bus
– Main internal SRAM1 (112 KB)
– Auxiliary internal SRAM2 (16 KB)
– AHB1 peripherals including AHB to APB bridges and APB peripherals
– AHB2 peripherals
– FSMC
The bus matrix provides access from a master to a slave, enabling concurrent access and efficient operation even when several high-speed peripherals work simultaneously. The 64-Kbyte CCM (core coupled memory) data RAM is not part of the bus matrix and can be accessed only through the CPU. This architecture is shown in
其架构和之前的STM32F1x区别还是挺大的。由上可知,CCM共64KB,是直接挂在D-bus上的,除了CPU(即Cortex-M核)之外,谁都无法访问。此外,由于CCM不属于BusMatrix的一部分,所有也就不能被其他组件访问,例如DMA控制器。
还需要注意,SRAM1和SRAM2(CCM)的空间是不连续的。
对于CCM,CPU能以最大的系统时钟和最小的等待时间从CCM中读取数据或者代码。官方文档说明了使用CCM的一些优势:比如将频繁读取的数据放到CCM,将中断函数放到CCM,这都能加快程序的执行速度。
如何使用
使用方式一
- 配置Keil
知道了这块特殊内存,那么我们怎么来使用他呢?常用Keil的人应该知道,在其配置中,有如下选项:
在默认情况下,其中的IRAM2我们不选中,现在我们就可以选中该部分。这样,Keil在生产代码时,就会自动将变量分配到该部分RAM中了。具体的可以打开,Keil生成的.map文件看看。
- 配置Keil新建一个sct文件
; *************************************************************
; *** Scatter-Loading Description File generated by uVision ***
; *************************************************************
LR_IROM1 0x08020000 0x000D0000 { ; load region size_region
ER_IROM1 0x08020000 0x000D0000 { ; load address = execution address
*.o (RESET, +First)
*(InRoot$$Sections)
.ANY (+RO)
.ANY (+XO)
}
RW_IRAM1 0x20000000 0x00030000 { ; RW data
.ANY (+RW +ZI)
}
RW_IRAM2 0x10000000 0x00010000 {
.ANY (ccmram)
}
}
- 配置工程,加载刚才sct
- 宏定义指定区域
#define CCMRAM __attribute__((section("ccmram")))
- 声明变量
/** This is the actual memory used by the pools (all pools in one big block). */
CCMRAM static u8_t memp_memory[MEM_ALIGNMENT - 1
#define LWIP_MEMPOOL(name,num,size,desc) + ( (num) * (MEMP_SIZE + MEMP_ALIGN_SIZE(size) ) )
#include "lwip/memp_std.h"
];
我自己使用的方法:
CCMRAM uint8_t g_szESWaveBuffData[65535] = {0};
- 编译后的Map文件
注意:
如果仅仅定义几个变量,可能Keil不会将其放到该RAM中。
我在用的时候,没有选中RAM2,Keil仍然把部分内存放到了RAM2中,不知为啥!
但是,这样就有一个问题:由于其只能被内核访问,一旦Keil将例如DMA用的内存放到了该部分RAM中,那么DMA将不能工作! 那么怎么使用更合适呢?
关于系统
我这搞这部分的时候,正好用了FreeRTOS。于是就像既然这部分只能给内核访问,为了内存的合理利用,能不能直接将这部分内存给系统,剩下的给不就是想怎么用就怎么用了么?而且分给FreeRTOS 64KB的内存正好符合我的设计需要!
了解了上面的分散加载文件后,要将FreeRTOS放到RMA2中就非常简单了,根据使用的FreeRTOS的文件,只需要如下的分散加载文件即可。
RW_IRAM2 0x10000000 0x00010000 {
port.o (+RW +ZI)
queue.o (+RW +ZI)
tasks.o (+RW +ZI)
heap_4.o (+RW +ZI)
; 其他的用到的FreeRTOS的.o文件
}
这样就又有一个问题,如果使用动态申请的内存,则内存还是在RAM2中,如果传递给DMA时,则会出错!
注意:
1. FreeRTOS中部分文件只有代码,没有数据(RW和ZI),例如:list.c,这样就不能放到上面的分散加载文件中
注意事项
需要了解ARM的分散加载文件。
需要了解个别的编译器指令
参考文档
STM32F407 Reference manual