Name
DMA Support — Details
Synopsis
#include <cyg/hal/var_dma.h>
pin = CYGHWR_HAL_STM32_DMA(
ctlr
,
stream
,
chan
,
mode
)
;
pin = CYGHWR_HAL_STM32_DMA(
dmareq_id
,
dmamux_channel
,
mode
)
;
hal_stm32_dma_init
(
hal_stm32_dma_stream *stream
,
int priority
)
;
hal_stm32_dma_delete
(
hal_stm32_dma_stream *stream
)
;
hal_stm32_dma_disable
(
hal_stm32_dma_stream *stream
)
;
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
)
;
hal_stm32_dma_stop
(
hal_stm32_dma_stream *stream
)
;
hal_stm32_dma_poll
(
hal_stm32_dma_stream *stream
)
;
Description
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 CYGHWR_HAL_STM32_DMA_NONE
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 |
Some later variants such as the L4+ or H7 implement a DMA multipexor which routes peripheral DMA requests to DMA controller channels. This means that the way in which DMA channels are associated with peripherals is somewhat different and DMA descriptors have a different format. Instead of selecting a DMA controller and channel, a DMAMUX channel is selected which automatically selects the DMA controller and channel. The following examples show how these descriptors are initialized:
// L4+ // I2C1 RX uses DMAMUX channel 0, which maps to DMAC 1, channel 0, peripheral-to-memory #define CYGHWR_HAL_STM32_I2C1_DMA_RX CYGHWR_HAL_STM32_DMA(CYGHWR_HAL_STM32_DMAMUX_I2C1_RX,0,P2M) // H7 // SPI5 TX uses DMAMUX channel 10, which maps to DMAC 2, channel 3, memory-to-peripheral #define CYGHWR_HAL_STM32_SPI5_DMA_TX CYGHWR_HAL_STM32_DMA(SPI5_TX,10,M2P)
Before use a DMA stream must be initialized. This is done by
calling hal_stm32_dma_init()
. The first
argument to this is a
hal_stm32_dma_stream structure in which
the 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 priority
argument
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
initialization.
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
should call hal_stm32_dma_configure()
which
will allow these options to be varied. The
tfr_size
argument defines the transfer size
and may be 8, 16 or 32 bits. The no_minc
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
the
function hal_stm32_dma_configure_circular()
with 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
with enable
set to false will disable
circular mode.
If a F2/F4 driver wants to use the continuous double-buffer support
then it can call
the hal_stm32_dma_configure_doublebuffer()
with enable
set to true. This configures the
DMA to automatically switch between buffers at the end of a
transfer. The memory1
is the second buffer to
be used in conjunction with the buffer passed as
the memory
parameter to
the hal_stm32_dma_start()
function.
Note | |
---|---|
The second buffer must be at least the
same |
Calling the function with enable
set to false
will disable the double buffer mode, with the
passed memory1
parameter being ignored.
Warning | |
---|---|
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
function hal_stm32_dma_configure_flow()
with 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
with enable
set to false will disable
the peripheral flow control mode.
A transfer is defined and started by calling
hal_stm32_dma_start()
. The
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 );
The 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.
The configuration option
CYGIMP_HAL_STM32_DMA_CALLBACK_ISR
can be
used to enable the optional support for an ISR level callback
when the DMA TransferComplete (TC) interrupt is
triggered. This support is not normally required, but some
STM32 family variants may require some collusion between the
DMA system and the peripheral H/W controller to ensure correct
operation. As such it is not expected that the developer
should ever need to manually enable
CYGIMP_HAL_STM32_DMA_CALLBACK_ISR
since it
will be automatically enabled if any of the configured
packages require the functionality. The callback is executed
within the ISR of the DMA TC processing and so should not
block.
typedef void hal_stm32_dma_callback_isr( hal_stm32_dma_stream *stream, CYG_ADDRWORD data );
As with the normal DSR callback the
stream
argument is the stream structure
initialized by the user and 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
call 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
may call 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
again.
Alternatively for circular mode configured streams
the hal_stm32_dma_disable()
can be used to
disable the stream DMA without clearing the state. The
function hal_stm32_dma_start()
can then be
used to re-enable the DMA stream with the previous configured
state.
The 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
non-zero count
indicating a partial transfer.
Note | |
---|---|
The |
2024-03-18 | eCosPro Non-Commercial Public License |