DMA in the IDE, Part II

STM32 DMA UART Receive P2M Demo

This is the second example of DMA usage on the STM32F405 Feather board. Programming is from the Arduino IDE. This example demonstrates the peripheral to memory (P2M) DMA Mode. We send serial data to the board via UART DMA storing the data into SRAM memory.

For this demo to work, the Arduino serial code needs to be disabled. The instructions are included in the code comments.

Make a serial connection to the SDA pin (PB7). Every 5 characters the board receives toggles the onboard LED.

The Code

// USART1 Rx to SRAM DMA transfer.
// Interrupt mode, transfer complete initiates a callback.
//
// Add build_opt.h file to project with -DHAL_UART_MODULE_ENABLED.
// Tools > U(S)ART Support: Disabled.
// Change option in file: stm32f4xx_hal_conf_default.h
// Located here: 
// C:\Users\default.LAPTOP-7V09ROBA\AppData\Local\Arduino15\packages\STM32\hardware\stm32\1.9.0\system\STM32F4xx
// #define USE_HAL_UART_REGISTER_CALLBACKS 1U
//
// Use TeraTerm to connect to board at 9600 baud.
// USART1 RX is on SDA pin, PB7.
// Every 5 chars sent should toggle LED.
//
#define LED_Pin       GPIO_PIN_1
#define LED_GPIO_Port GPIOC

#define DATA_LENGTH 5
uint8_t data[DATA_LENGTH];

UART_HandleTypeDef huart1;
DMA_HandleTypeDef hdma_usart1_rx;

extern "C" void myCallback(UART_HandleTypeDef *huart) {
  UNUSED(huart);
  HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
}

extern "C" void DMA2_Stream2_IRQHandler(void) {
  HAL_DMA_IRQHandler(&hdma_usart1_rx);
}

void uartInit(void) {
  huart1.Instance = USART1;
  huart1.Init.BaudRate = 9600;
  huart1.Init.WordLength = UART_WORDLENGTH_8B;
  huart1.Init.StopBits = UART_STOPBITS_1;
  huart1.Init.Parity = UART_PARITY_NONE;
  huart1.Init.Mode = UART_MODE_TX_RX;
  huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart1.Init.OverSampling = UART_OVERSAMPLING_16;

  __HAL_RCC_USART1_CLK_ENABLE();
  hdma_usart1_rx.Instance = DMA2_Stream2;
  hdma_usart1_rx.Init.Channel = DMA_CHANNEL_4;
  hdma_usart1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
  hdma_usart1_rx.Init.PeriphInc = DMA_PINC_DISABLE;
  hdma_usart1_rx.Init.MemInc = DMA_MINC_ENABLE;
  hdma_usart1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
  hdma_usart1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
  hdma_usart1_rx.Init.Mode = DMA_NORMAL;
  hdma_usart1_rx.Init.Priority = DMA_PRIORITY_LOW;
  hdma_usart1_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
  if (HAL_DMA_Init(&hdma_usart1_rx) != HAL_OK)
    while(1);

  __HAL_LINKDMA(&huart1, hdmarx, hdma_usart1_rx);

  if (HAL_UART_Init(&huart1) != HAL_OK)
  while(1);
}

void dmaInit(void) {
  __HAL_RCC_DMA2_CLK_ENABLE();
  HAL_NVIC_SetPriority(DMA2_Stream2_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(DMA2_Stream2_IRQn);
}

void gpioInit(void) {
  GPIO_InitTypeDef GPIO_InitStruct;

  __HAL_RCC_GPIOB_CLK_ENABLE();

  // USART1 GPIO Configuration.
  // PB6 --> USART1_TX
  // PB7 --> USART1_RX 
  GPIO_InitStruct.Pin = GPIO_PIN_6 | GPIO_PIN_7;
  GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  GPIO_InitStruct.Pull = GPIO_PULLUP;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
  GPIO_InitStruct.Alternate = GPIO_AF7_USART1;
  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}

void setup() { 
  gpioInit();
  dmaInit();
  uartInit();
  pinMode(LED_BUILTIN, OUTPUT);
  HAL_UART_RegisterCallback(&huart1, HAL_UART_RX_COMPLETE_CB_ID, (pUART_CallbackTypeDef)myCallback);
}

void loop() {
  __HAL_UART_FLUSH_DRREGISTER(&huart1);

  while (1)
    HAL_UART_Receive_DMA(&huart1, (uint8_t *)data, DATA_LENGTH);
}

About Jim Eli

µC experimenter
This entry was posted in Uncategorized. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s