STM32 之五 Core Coupled Memory(CCM)内存

写在前面

  • 今天在搞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
STM32 之五 Core Coupled Memory(CCM)内存_第1张图片
  其架构和之前的STM32F1x区别还是挺大的。由上可知,CCM共64KB,是直接挂在D-bus上的,除了CPU(即Cortex-M核)之外,谁都无法访问。此外,由于CCM不属于BusMatrix的一部分,所有也就不能被其他组件访问,例如DMA控制器。
  对于CCM,CPU能以最大的系统时钟和最小的等待时间从CCM中读取数据或者代码。官方文档说明了使用CCM的一些优势:比如将频繁读取的数据放到CCM,将中断函数放到CCM,这都能加快程序的执行速度。

如何使用

使用方式一

  知道了这块特殊内存,那么我们怎么来使用他呢?常用Keil的人应该知道,在其配置中,有如下选项:
STM32 之五 Core Coupled Memory(CCM)内存_第2张图片
  在默认情况下,其中的IRAM2我们不选中,现在我们就可以选中该部分。这样,Keil在生产代码时,就会自动将变量分配到该部分RAM中了。具体的可以打开,Keil生成的.map文件看看。

    Execution Region RW_IRAM2 (Base: 0x10000000, Size: 0x00005ce4, Max: 0x00010000, ABSOLUTE)

    Base Addr    Size         Type   Attr      Idx    E Section Name        Object

    0x10000000   0x00005ce4   Zero   RW        16003    .bss                ram2.o


    Execution Region RW_IRAM1 (Base: 0x20000000, Size: 0x0001b360, Max: 0x00020000, ABSOLUTE, COMPRESSED[0x000000c8])

    Base Addr    Size         Type   Attr      Idx    E Section Name        Object

    0x20000000   0x00000001   Data   RW          264    .data               pbuf.o
    0x20000001   0x00000001   Data   RW          909    .data               api_msg.o

注意:

  1. 如果仅仅定义几个变量,可能Keil不会将其放到该RAM中。
  2. 我在用的时候,没有选中RAM2,Keil仍然把部分内存放到了RAM2中,不知为啥!

  但是,这样就有一个问题:由于其只能被内核访问,一旦Keil将例如DMA用的内存放到了该部分RAM中,那么DMA将不能工作! 那么怎么使用更合适呢?

使用方式二

  如前所说,直接让编译器自动分配貌似不太合适,所以我们可以自己指定分配的内存。这其中也有两种方式。
  第一种依靠分散加载文件(.sct),更强大,直接定义一个文件(例如,名字为 RAM2.c),将所有要放得变量均放到该文件中,然后如下修改分散加载文件。

LR_IROM1 0x0800C000 0x00100000  {    ; load region size_region
  ER_IROM1 0x0800C000 0x00100000  {  ; load address = execution address
   *.o (RESET, +First)				; 中断向量表
    *(InRoot$$Sections)
   .ANY (+RO) 
  }

  RW_IRAM1 0x20000000 0x00020000  {  ; RW data
   .ANY (+RW +ZI)
  }
  ; 指定使用CCM
  RW_IRAM2 0x10000000 0x00010000  {
   RAM2.O (RAM2,+RW +ZI)
  }
}

  还有一种方式就是直接使用编译器指令:__attribute__+at。在定义变量时,如下即可:

UINT32 EventNum __attribute__((at(0x10000000))) = 0;

  当然,这种方式也可以稍微变化一下,使用__attribute__+section。给变量指定一个节区名字,然后在分散加载文件中指定节区位置。
  如上处理编译后,可查看map文件对应部分内存中变量的分配了。

关于系统

  我这搞这部分的时候,正好用了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

你可能感兴趣的:(STM32)