Documentation: migrate "STM32 CCM Allocator" from wiki
link: https://cwiki.apache.org/confluence/display/NUTTX/STM32+CCM+Allocator Co-authored-by: hartmannathan <59230071+hartmannathan@users.noreply.github.com>
This commit is contained in:
parent
3e0d1e9b52
commit
c347343e09
@ -27,3 +27,4 @@ Guides
|
||||
testingtcpip.rst
|
||||
automounter.rst
|
||||
stm32nullpointer.rst
|
||||
stm32ccm.rst
|
||||
|
108
Documentation/guides/stm32ccm.rst
Normal file
108
Documentation/guides/stm32ccm.rst
Normal file
@ -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.
|
Loading…
Reference in New Issue
Block a user