This is an automated email from the ASF dual-hosted git repository. xiaoxiang pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/nuttx.git
commit c347343e0921791d86c64b3cc9253fd9bcf265d9 Author: raiden00pl <[email protected]> AuthorDate: Tue Nov 7 18:51:57 2023 +0100 Documentation: migrate "STM32 CCM Allocator" from wiki link: https://cwiki.apache.org/confluence/display/NUTTX/STM32+CCM+Allocator Co-authored-by: hartmannathan <[email protected]> --- Documentation/guides/index.rst | 1 + Documentation/guides/stm32ccm.rst | 108 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 109 insertions(+) diff --git a/Documentation/guides/index.rst b/Documentation/guides/index.rst index f8deabb285..7df430e44c 100644 --- a/Documentation/guides/index.rst +++ b/Documentation/guides/index.rst @@ -27,3 +27,4 @@ Guides testingtcpip.rst automounter.rst stm32nullpointer.rst + stm32ccm.rst diff --git a/Documentation/guides/stm32ccm.rst b/Documentation/guides/stm32ccm.rst new file mode 100644 index 0000000000..16ce123f96 --- /dev/null +++ b/Documentation/guides/stm32ccm.rst @@ -0,0 +1,108 @@ +=================== +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()`` somwhere 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.
