pin = CYGHWR_HAL_STM32_DMA(ctlr, stream, chan, mode);
hal_stm32_dma_init(hal_stm32_dma_stream *stream, int priority);
hal_stm32_dma_configure(hal_stm32_dma_stream *stream, int tfr_size, cyg_bool no_minc, cyg_bool polled);
hal_stm32_dma_configure_circular(hal_stm32_dma_stream *stream, cyg_bool enable);
hal_stm32_dma_configure_doublebuffer(hal_stm32_dma_stream *stream, cyg_bool enable, void *memory1);
hal_stm32_dma_configure_flow(hal_stm32_dma_stream *stream, cyg_bool enable);
hal_stm32_dma_start(hal_stm32_dma_stream *stream, void *memory, CYG_ADDRESS peripheral, cyg_uint32 size);
The HAL provides support for access to the DMA controllers. This support is not intended to expose the full functionality of these devices and is mainly limited to supporting peripheral DMA, currently ADC, SPI, I²C and MMC/SD.
The user is referred to the ST documentation for a full description of the DMA devices, and to the sources of the ADC, I²C, SPI and MMC/SD drivers for examples of the use of this API. This documentation only gives a brief description of the functions available.
A DMA stream is defined by a controller number (0 or 1), a stream
number (0 to 8), a channel number (0 to 7) and a mode defining
transfer direction. The macro
CYGHWR_HAL_STM32_DMA() combines these into a
32-bit descriptor that may be stored with a device driver and used
to initialize the stream.
NOTE: the DMA terminology has changed between F1 and F2/F4 versions of the STM32 family. In F1 devices each DMA controller has a number of channels, each of which can be driven by a subset of the on-chip devices; there is no way to select which device drives the channel, and care must be taken to allocate channels so that devices don't trigger the wrong channel. In F2/F4 devices each DMA controller has a number of streams; each stream can explicitly select one of a number of driving devices by means of a channel selection field in a control register. F1 channels and F2/F4 streams are essentially the same thing, and the problems of false triggering in F1 devices is solved in F2/F4 by adding the explicit channel selection. To make things more complicated, F1 channels are numbered from one while F2/F4 streams are numbered from zero. HAL support for DMA largely follows the F2/F4 terminology, but the original channel numbering for the F1 is preserved when defining channels.
The following examples show how definitions should be made:
// F1 definition: controller 1, channel 6, memory-to-peripheral #define CYGHWR_HAL_STM32_I2C1_DMA_TX CYGHWR_HAL_STM32_DMA( 1, 6, 0, M2P ) // F2/F4 definition: controller 2, stream 0, channel 3, peripheral-to-memory #define CYGHWR_HAL_STM32_SPI1_DMA_RX CYGHWR_HAL_STM32_DMA( 2, 0, 3, P2M )
The special manifest
can be used when the code does not require DMA support for a
specific stream. For example:
// I2C2 RX should NOT use DMA #define CYGHWR_HAL_STM32_I2C2_DMA_RX CYGHWR_HAL_STM32_DMA_NONE
Note: Not all device drivers support the ability of using
CYGHWR_HAL_STM32_DMA_NONEto disable DMA use for specific stream mappings. For example, the STM32 I²C driver does allow for individual streams to be configured for interrupt-driven or DMA transfers as required.
Before use a DMA stream must be initialized. This is done by
hal_stm32_dma_init(). The first
argument to this is a
hal_stm32_dma_stream structure in which
desc field should have been
initialized to a DMA descriptor; the
callback field set to a callback
function; and the
data field set to any
user defined data. The
defines both the interrupt level assigned to the stream interrupt,
and the DMA channel arbitration priority level (defined by the top
two bits). This function initializes the hardware and the stream
structure and needs only to be called once during driver
By default a stream is initialized to perform 8 bit transfers
under interrupt control and to advance the memory address
pointer. If a different configuration is required, then the driver
will allow these options to be varied. The
tfr_size argument defines the transfer size
and may be 8, 16 or 32 bits. The
argument disables memory increments if true. The
polled argument configures the stream for
polled mode if true, otherwise it will be interrupt driven. This
function may either be called once to set up the stream
permanently, or on a transfer-by-transfer basis, or not at all if
the defaults are what is required.
If the driver needs circular mode DMA processing then it can call
enable set to true. This allows
circular buffers and continuous data flows (e.g. ADC scan mode as
used by the STM32F ADC driver). Calling the function
enable set to false will disable
If a F2/F4 driver wants to use the continuous double-buffer support
then it can call
enable set to true. This configures the
DMA to automatically switch between buffers at the end of a
memory1 is the second buffer to
be used in conjunction with the buffer passed as
memory parameter to
Note: The second buffer must be at least the same
sizeas the (first) buffer subsequently passed to the
Calling the function with
enable set to false
will disable the double buffer mode, with the
memory1 parameter being ignored.
The DMA controller hardware when using double buffer mode will automatically switch buffers on a buffer fill event.
When using double buffer mode the developer should ensure that the buffer size used is large enough to cope with the processing code associated with a completed transaction being able to complete to avoid overrun. The size of the buffers will depend on the DMA transfer rate for the peripheral being used and the application DSR latency, plus the actual callback buffer processing code time.
If a F2/F4 driver needs to use peripheral controlled DMA flow
then it can call the
enable set to true. This configures
the DMA to allow the peripheral to control the flow of DMA
transfers, instead of the DMA controller (e.g. the STM32 SDIO
device signals the end of data transfers). Calling the function
enable set to false will disable
the peripheral flow control mode.
A transfer is defined and started by calling
memory argument defines the memory address
to/from which the transfer will be made. The
peripheral argument is the address of the
data register of the peripheral involved. The
size argument defines the number of data
items to be transferred, or in the case of peripheral flow control
configurations the number of items expected, as defined by
tfr_size. Once this call completes, the
channel is operational and will transfer data once the peripheral
starts triggering transfers.
If the stream is configured for interrupt control then when a transfer completes an interrupt is raised. This will disable the stream and cause the callback in the stream structure to be called from DSR mode. The prototype of the callback is as follows:
typedef void hal_stm32_dma_callback( hal_stm32_dma_stream *stream, cyg_uint32 count, CYG_ADDRWORD data );
stream argument is the stream structure
initialized by the user. The
count argument is
a count of the number of data items that remain to be transferred,
and will be zero for a successful transfer. The
data argument is a copy of the
data field from the stream structure.
If the stream is configured for polled mode, then the driver must
hal_stm32_dma_poll() frequently. When
the transfer has completed the callback function will be called
from within the poll routine. The driver needs to detect this and
terminate the polling loop.
Most drivers will initialize a DMA stream and keep it enabled
throughout the system lifetime. However, if it is necessary to
share a stream, or otherwise disable use of a stream, the driver
hal_stm32_dma_delete() to return a
stream to unused state. It will be necessary to call
hal_stm32_dma_init() before it can be used
Alternatively for circular mode configured streams
hal_stm32_dma_disable() can be used to
disable the stream DMA without clearing the state. The
hal_stm32_dma_start() can then be
used to re-enable the DMA stream with the previous configured
hal_stm32_dma_stop() function allows a stream
to be disabled without clearing the transfer
state. The normal callback handler is subsequently called with a
count indicating a partial transfer.
hal_stm32_dma_stop()function will return immediately, however the stream may remain active until any active “item” transfer has completed (not the full
sizeamount). When appropriate the stream will be disabled by the DMA controller and the relevant callback handler function called asynchronously.