Configuring DMA peripherals

STM32F767 has two DMA controllers. Each controller has 10 channels and 8 streams to map DMA requests from one location in the MCU to another. On the STM32F767 hardware, streams can do the following:

  • Can be thought of as a way to flow data from one address to another
  • Can transfer data from peripherals to RAM or RAM to peripherals
  • Can transfer data from RAM to RAM
  • Can only transfer data between two points at any given moment in time

Each stream has up to 10 channels for mapping a peripheral register into a given stream. In order to configure the DMA controller to handle requests from the USART2 receive, we'll reference table 27 from the STM32F7xx RM0410 reference manual:

In this table, we can see that DMA1 Channel 4, Stream 5 is the appropriate setup to use to handle requests from USART2_RX. If we were also interested in handling requests for the transmit side, Channel 4, Stream 6 would also need to be set up.

Now that we know the channel and stream numbers, we can add some initialization code to set up the DMA1 and USART2 peripherals:

  • DMA1_Stream5 will be used to transfer data from the receive data register of USART2 directly into a buffer in RAM.
  • USART2 will not have interrupts enabled (they are not needed since DMA will perform all transfers from the peripheral register to RAM).
  • DMA1_Stream5 will be set up to trigger an interrupt after the entire buffer has been filled.

The next few snippets are from the setupUSART2DMA function in Chapter_10/src/mainUartDMABuff.c:

  1. First, the clock to the DMA peripheral is enabled, interrupt priorities are set up, and the interrupts are enabled in the NVIC:
void setupUSART2DMA( void )
{
__HAL_RCC_DMA1_CLK_ENABLE();

NVIC_SetPriority(DMA1_Stream5_IRQn, 6);
NVIC_EnableIRQ(DMA1_Stream5_IRQn);
  1. Next, the DMA stream is configured by filling out a DMA_HandleTypeDef struct (usart2DmaRx) and using HAL_DMA_Init():
  HAL_StatusTypeDef retVal;
memset(&usart2DmaRx, 0, sizeof(usart2DmaRx));
usart2DmaRx.Instance = DMA1_Stream5; //stream 5 is for USART2 Rx

//channel 4 is for USART2 Rx/Tx
usart2DmaRx.Init.Channel = DMA_CHANNEL_4;

//transfering out of memory and into the peripheral register
usart2DmaRx.Init.Direction = DMA_PERIPH_TO_MEMORY;
usart2DmaRx.Init.FIFOMode = DMA_FIFOMODE_DISABLE; //no FIFO

//transfer 1 at a time
usart2DmaRx.Init.MemBurst = DMA_MBURST_SINGLE;
usart2DmaRx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;

//increment 1 byte at a time
usart2DmaRx.Init.MemInc = DMA_MINC_ENABLE;

//flow control mode set to normal
usart2DmaRx.Init.Mode = DMA_NORMAL;

//write 1 at a time to the peripheral
usart2DmaRx.Init.PeriphBurst = DMA_PBURST_SINGLE;

//always keep the peripheral address the same (the RX data
//register is always in the same location)
usart2DmaRx.Init.PeriphInc = DMA_PINC_DISABLE;

usart2DmaRx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;

usart2DmaRx.Init.Priority = DMA_PRIORITY_HIGH;
retVal = HAL_DMA_Init(&usart2DmaRx);
assert_param( retVal == HAL_OK );

//enable transfer complete interrupts
DMA1_Stream5->CR |= DMA_SxCR_TCIE;

//set the DMA receive mode flag in the USART
USART2->CR3 |= USART_CR3_DMAR_Msk;

HAL initialization provides some sanity checking on the values passed to it. Here's a highlight of the most immediately relevant portions:

  • DMA1_Stream5 is set as the instance. All calls that use the usart2DmaRx struct will reference stream 5.
  • Channel 4 is attached to stream 5.
  • Memory incrementing is enabled. The DMA hardware will automatically increment the memory address after a transfer, filling the buffer.
  • The peripheral address is not incremented after each transfer—the address of the USART2 receive data register (RDR) doesn't ever change.
  • The transfer complete interrupt is enabled for DMA1_Stream5.
  • USART2 is set up for DMA receive mode. It is necessary to set this bit in the USART peripheral configuration to signal that the peripheral's receive register will be mapped to the DMA controller.
Additional details about how this struct is used can be found by looking at the DMA_HandleTypeDef struct definition in stm32f7xx_hal_dma.h (line 168) and HAL_DMA_Init() in stm32f7xx_hal_dma.c (line 172). Cross-reference the registers used by the HAL code with section 8 (page 245) in the STM32F76xxx RM0410 reference manual. This same technique is often most productive for understanding exactly what the HAL code is doing with individual function parameters and struct members.

Now that the initial DMA configuration is done, we can explore a few different interrupt implementations using DMA instead of interrupts.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.147.66.178