Dma STM32
Dma STM32
DMA Channels
The DMA controllers have access to a special bus (“AHB peripheral port”) which
gives them rapid-access to selected peripherals. This is useful as it allows the
standard bus matrix to be bypassed and latency to be significantly reduced.
Each stream has 8 “channels”, which can be thought of as a multiplexer for the
peripheral bus.
The channel selects a DMA trigger (“request”), which can be used to start the DMA
transfer process based on a peripheral’s state and configuration. In example, a
request may be initiated upon arrival of new data to a serial port peripheral.
The channels are OR’d with a software trigger that can manually invoke the DMA
transfer process.
DMA Addressing
The stream can access data as either a char, half-word, or word (int_8, int_16, or
int_32). The source data size and destination data size are independently
configurable.
- Each stream has a source and a destination address pointer.
- In M2P mode, the source address could be an SRAM address, flash address, or
any other address the DMA port may be connected to in the MCU’s bus matrix.
The destination address must be a peripheral address on the AHB bus, though, the
documentation is not clear on whether this address must be the specific peripheral
of the selected channel, or any valid address in the AHB bus. Sean suspects that
only the request triggers are channel dependent, and that any valid address on the
bus may be chosen as the destination address.
- In P2M mode, the inverse of the above is true.
- In M2M mode, both source and destination addresses can be any address on the
bus matrix which the DMA engine has access to. This can include peripheral
addresses, which are handled by the memory manager of the bus matrix.
Both the source and destination pointer have an increment function which can be
enabled or disabled. Upon every successful write, the address pointer will
increment one data unit. Data units remember, are independently configurable for
source and destination, so it is possible to read 16 bit units, yet increment the
destination 32 bits at a time.
The maximum transfer size of the source buffer is programmable.
Circular mode is also supported, where, the address pointer is automatically
reloaded after the source buffer has been emptied, and the DMA transfer process
begins again. This can be useful for continuous data streaming.
Circular mode also has a double buffer mode, where, instead of reloading the initial
pointer address, a second pointer address is reloaded, so that the buffer can be
written to by a secondary program without any conflict.
Transfer Sizes
Peripheral to Memory
So if you want to move data from a peripheral to the DMA controller, to memory,
and use the peripheral’s DMA request trigger as the event which starts the transfer,
- Choose a Stream (1 of 8)
- Use the “DMA Request Mapping” table (specific to the MCU) to find out what is a
valid channel for that stream and chosen peripheral.
This is an example table for the STM32F4 series MCU:
Alternatively, you can software trigger the DMA transfer by writing to a specific
register.
After triggering the transfer, the DMA controller will read from the source address
and either,
- Put that data into a 4 word FIFO
- Write that data directly to the destination address
Depending on your configuration.
Each DMA controller has a FIFO, which can be used as a buffer to store data. The
FIFO will not empty unless either, 1/4 Full, 1/2 Full, 3/4 Full or 100% Full depending
on your configuration. The FIFO can be used to reduce memory access reads or
writes, which is helpful when data does not need to be used in exactly real time.
Memory to Peripheral
So if you want to move data from memory to the DMA controller, and use the
peripheral’s DMA request trigger as the event which starts the transfer. It’s pretty
much the same deal as before.
1. Choose a Stream (1 of 8)
2. Use the “DMA Request Mapping” table (specific to the MCU) to find out what is
a valid channel for that stream and chosen peripheral.
3. Depending on whether or not you enabled the FIFO, the data is either shuttled
directly into the peripheral, or, is buffered for a bit until the peripheral is ready for it.
This is possible because the DMA controller will actually preemptively fill the FIFO
from memory for you.
Memory to Memory
Interrupts
The DMA controller’s streams are capable of interrupt generation, which may be
used to for example, load more data into the source buffer when the transfer is half-
completed. This can be useful for say, reading data from an SD card or other
storage, where the available memory of the MCU is less than that of the mass
storage.
Arbitration
DMA transfers are not instantaneous, as the streams all share the same bus the
speed of the transfer is a function of how much time the arbitrator allocates to the
stream. The allocation is done in a round-robin fashion with bounded maximum
latency, so a higher-priority DMA request can’t jam up the bus entirely for everyone
else.
The high-speed/high-bandwidth peripherals should have the highest Stream
priorities to ensure a high transfer rate. Since the two DMA controllers can work in
parallel, high-speed peripherals’ requests should be balanced between the two.
In case of equal bandwidth requirements, it is recommended to assign a higher
priority to the peripherals working in slave mode (which have no control on the data
transfer speed) compared with the ones working in master mode (which may
control the data flow).
HAL Functions
The DMA HAL driver allows enabling and configuring the peripheral to be
connected to the DMA Channels (except for internal SRAM/FLASH memory which
do not require any initialization).
For a given channel, HAL_DMA_Init() API allows programming the required
configuration through the following parameters:
- Transfer Direction
- Source and Destination data formats
- Normal or Circular mode
- Channel Priority level
- Source and Destination Increment mode
- Hardware request connected to the peripheral
Two operating modes are available:
POLLING MODE I/O OPERATION:
1. Use HAL_DMA_Start() to start DMA transfer when the source and destination
addresses and the Length of data to be transferred have been configured.
2. Use HAL_DMA_PollForTransfer() to poll for the end of current transfer. In this
case a fixed timeout can be configured depending on the user application.
INTERRUPT MODE I/O OPERATION:
1. Configure the DMA interrupt priority using HAL_NVIC_SetPriority()
2. Enable the DMA IRQ handler using HAL_NVIC_EnableIRQ()
3. Use HAL_DMA_Start_IT() to start DMA transfer when the source and destination
addresses and the length of data to be transferred have been confgured. In this
case the DMA interrupt is configured.
4. Use HAL_DMA_IRQHandler() called under DMA_IRQHandler() Interrupt
subroutine
5. When data transfer is complete, HAL_DMA_IRQHandler() function is executed
and a user function can be called by customizing XferCpltCallback and
XferErrorCallback function pointer (i.e. a member of DMA handle structure).
Additional functions and macros are available to ensure efficient DMA
management:
- Use HAL_DMA_GetState() function to return the DMA state
- Use HAL_DMA_GetError() in case of error detection.
- Use HAL_DMA_Abort() function to abort the current transfer
The most used DMA HAL driver macros are the following:
- __HAL_DMA_ENABLE: enables the specified DMA channel.
- __HAL_DMA_DISABLE: disables the specified DMA channel.
- __HAL_DMA_GET_FLAG: gets the DMA channel pending flags.
- __HAL_DMA_CLEAR_FLAG: clears the DMA channel pending flags.
- __HAL_DMA_ENABLE_IT: enables the specified DMA channel interrupts.
- __HAL_DMA_DISABLE_IT: disables the specified DMA channel interrupts.
- __HAL_DMA_GET_IT_SOURCE: checks whether the specified DMA channel
interrupt has been enabled or not.
An additional function, DMA_SetConfig(hdma, SrcAddress, DstAddress,
DataLength); is declared static in the stm32fxxx_hal_dma.h and not exposed. This
is the dumbest thing ever and the function is very useful, since none of the standard
exposed HAL functions are good for configuring the DMA without also immediately
starting a transfer!
Important Notes:
There are several use cases for the DMA units in STM32 microcontrollers. We’ll
implement some of them in the upcoming tutorials’ LABs and projects. However,
here are a handful of possible scenarios: