相较于APM32F1xx,我们APM32F4xx系列MCU的内部有个特殊的SRAM,它叫做CCM内存,在我司《APM32F4xxx用户手册》的第2.3章节有相关介绍,如下图所示,这个内存是挂在D-bus上直接和内核连接,大小为64K,只有内核可以访问这个内存,DMA等外设不能对其访问。
那么这块CCM内存用户如何才能把它用起来呢?下面我就通过基于KEIL5的开发平台,给大家介绍一下如何使用CCM。
使用CCM一般有两种方式,第一种是通过配置MDK,实现自动分配。这种方式我们只需点击MDK的魔法棒,来到配置界面,并在Target菜单栏下,将IRAM2勾上,即使用这一块内存,这也就是CCM内存。
设置完后,重新编译工程,打开.map文件,就可以查看到会有这块SRAM的资源分配,如下图所示。由于IRAM1优先使用,而且一般SRAM1和SRAM2够用,如果定义的变量太少,系统就不会占用CCM内存。
这种自动分配的方式有什么问题呢?由于CCM除了内核任何其它总线都不能访问,这就意味着,一旦编译器将数据分配到CCM中,而同时使用了DMA访问,显然会出问题。不过,我们也可以通过专用语句来分配这段内存,专用语句如下:
__attribute__((at(address)))
那么在程序中比如我们要定义一个数组,并将这个数组分配到CCM内存中,我们可以这么去做:
uint8_t buff[10] __attribute__((at(0x10000000))) = {0};
再次编译工程后,打开在.map文件,就可以查看到刚刚定义的一段数据的确放在了CCM内存中,如下图所示。
那么使用attribute((at(address)))语句的操作来分配内存到CCM中需要我们每次都要计算变量分配内存的地址,确保地址不冲突,这显然是比价麻烦的。那有没有更简单的方法呢?当然是有的,我们通过配置分散加载文件的方式,就可以实现用户自定义分配内存到CCM中,具体操作如下所述。
首先,点击MDK的魔法棒,如下图所示,在Linker菜单栏下面,不勾选USE Memory Layout from Targe Dialog,这时MDK会自动载入一个分散加载文件(.sct),点Edit进入编辑这个文件,就可以手动选择要放到CCM中的数据了。
打开.sct文件后,原本编译器生成的只有RW_IRAM1,这是SRAM1和SRAM2的内存分配定义,这时我们就需要将CCM内存添加进去,假设定义为RW_IRAM2,如下图所示,如果想把程序中的某些变量放到CCM中,需要定义一个SECTION,将这些变量放到这个SECTION中,再由.sct文件分配到CCM中。
在程序中,为了使用方便我们将上面的关键字定义为下面的宏:
#define CCMRAM __attribute__((section("ccmram")))
比如我们将一个数组放到CCM中,将CCMRAM放在定义的数组即可,如下所示:
CCMRAM uint8_t buff[65535] = {0};
同样我们也可以将一个函数放到CCM中,如下所示:
CCMRAM void APM_MINI_LEDInit(Led_TypeDef Led)
{
GPIO_Config_T configStruct;
/** Enable the GPIO_LED Clock */
RCM_EnableAHB1PeriphClock(GPIO_CLK[Led]);
/** Configure the GPIO_LED pin */
GPIO_ConfigStructInit(&configStruct);
configStruct.pin = GPIO_PIN[Led];
configStruct.mode = GPIO_MODE_OUT;
configStruct.speed = GPIO_SPEED_50MHz;
GPIO_Config(GPIO_PORT[Led], &configStruct);
GPIO_PORT[Led]->BSCL = GPIO_PIN[Led];
}
除此之外,如果我们要将某个.c文件下的所有变量都放入CCM中(这些变量都是不能被外设访问的相关变量),我们只需要将对应的.o文件填入定义的RW_IRAM2,即可将该.c文件下的变量定义到CCM中。例如,我们将usart.c文件下定义的所有变量都放入CCM中。
我们再编译代码,打开在.map文件,就可以查看到usart.c文件下的变量都放在CCM中了。
以上就是关于APM32F407如何使用CCM内存的介绍,如有疑问,欢迎大家留言讨论,谢谢!