=================== STM32 CCM Allocator =================== CCM Memory ========== The STM32 F2, F3, and F4 families have a special block of SRAM available called CCM (Core Coupled Memory). This memory has the drawback that it cannot be used for STM32 DMA operations. By default, the CCM memory is lumped in with the rest of memory when the NuttX heaps are created. But this can be a problem because it will be a toss of the coin if non-DMA-able CCM memory or other DMA-able memory gets returned when ``malloc()`` is called. That usually does not matter but it certainly does make a difference if you are allocating memory that will be used for DMA! In that case, getting CCM memory for your DMA buffer will cause a failure. CONFIG_STM32_CCMEXCLUDE ======================= There is a configuration option called ``CONFIG_STM32_CCMEXCLUDE`` that can be used to exclude CCM memory from the heap. That solves the problem of getting CCM memory when you want to allocate a DMA buffer. But then what do you do with the CCM memory? Do you let it go unused? CCM Allocator ============= In order to make use of the CCM memory, a CCM memory allocator is available. This memory allocator is automatically enabled when the following options are set: * ``CONFIG_STM32_CCMEXCLUDE`` CCM memory is excluded from the normal heap, and * ``CONFIG_MM_MULTIHEAP`` Support for multiple heaps is enabled. Under those conditions, the CCM memory allocator is enabled and the allocator interfaces prototyped in the ``arch/arm/src/stm32/stm32_ccm.h`` are available. NOTE: These interfaces are, technically, not prototyped since they are really provided via C pre-processor macros. NOTE: In order to use the CCM memory allocator functions, you must first call ``ccm_initialize()`` somewhere in your early boot-up logic. With these interfaces you have a (nearly) standard way to manage memory from a heap that consists of the the CCM SRAM. And, since the CCM memory is no longer a part of the normal heap, all allocated I/O buffers will be DMA-able (unless you have included other non-DMA-able memory regions in the stack). CCM Stacks ========== One particular problem that has been reported by Petteri Aimonen requires some additional work-arounds. The STM32 SPI driver supports DMA and with SPI it is sometimes necessary to do some very small transfers for which there is no real gain from using DMA. In this case, Petteri has devised a clever way to both 1) make use of the CMM memory and 2) to force fallback to non-DMA transfers for these small stack transfers. Here is what Petteri has done: #. First, he has modified ``arch/arm/src/common/up_createstack.c`` and ``up_releasestack.c`` so that stacks are allocated from CCM memory. That allocation is something like the following: .. code-block:: C void *result = ccm_zalloc(size); if (!result) { /* Fall back to main heap */ result = zalloc(size); } With the matching: .. code-block:: C if (((uint32_t)p & 0xF0000000) == 0x10000000) { ccm_free(p); } else { free(p); } #. Then Petteri added special DMA support enabled with ``CONFIG_STM32_DMACAPABLE``. That option enables an option in all of the DMA logic called: .. code-block:: C bool stm32_dmacapable(uint32_t maddr); That will return true if it is possible to do DMA from the address and false if not. #. Finally, Petteri added logic to the STM32 SPI driver that use ``stm32_dmacapable()``: If the address is not DMA capable, then the SPI driver will fall back to non-DMA operation. With Petteri's changes all of the large I/O buffers will be allocated from DMA-able memory. All stacks will be allocated from non-DMA-able CCM memory (provided that there is space). Small SPI DMA buffers on the non-DMA-able stack will be detected by ``stm32_dmacapable()`` and in that case, the STM32 SPI driver will fall back and use non-DMA-transfers. From all reports this works quite well.