AnsweredAssumed Answered

USART receive with DMA not working on STM32F1xx

Question asked by techie.renovo on Aug 19, 2015
Latest reply on Aug 24, 2015 by techie.renovo
Hi,

I have a small starter project on an STM32F107. One of the things I need in this project is serial data transmission and reception via USART (I am using USART1). The code I have transmits packets fine using DMA. I also have a second controller that at the moment just sends a single byte once per second. I can receive that fine just by repeatedly checking if  something has been received and then reading the RX buffer of the USART. In that case I am flashing an LED so that I can check this visually (one flash per second). From this I know the USART is set up correctly, the pins are configured correctly and the surrounding hardware functions properly.

What I am not able to get to work is receiving data using DMA. I compared my code against what I could find in other posts. Unfortunately there are no relevant posts against the F1. As far as I can make out I am doing everything right, but clearly something is not or it would be working. I'll post my code below, perhaps someone sees the glaring mistake. Note that the process() function gets called repeatedly on a 1ms schedule.

I tried to inspect the receive buffer to see if the DMA perhaps gets triggered but for some reason never sets the flag I expect, but there is no data. So, I am reasonably sure the DMA never actually gets triggered.

---
void initializeLink (){ GPIO_InitTypeDef gpioInit; USART_ClockInitTypeDef clockInit; USART_InitTypeDef usartInit; DMA_InitTypeDef dmaInit; // ---------------------------------------------------- // first enable the clock // ---------------------------------------------------- RCC_APB2PeriphClockCmd (RCC_APB2Periph_USART1, ENABLE); RCC_APB2PeriphClockCmd (RCC_APB2Periph_GPIOA, ENABLE); RCC_AHBPeriphClockCmd (RCC_AHBPeriph_DMA1, ENABLE); // ---------------------------------------------------- // TX pin // ---------------------------------------------------- gpioInit.GPIO_Speed = GPIO_Speed_50MHz; gpioInit.GPIO_Mode = GPIO_Mode_AF_PP; gpioInit.GPIO_Pin = TX_PIN; GPIO_Init (COM_PORT, &gpioInit); // ---------------------------------------------------- // RX pin // ---------------------------------------------------- gpioInit.GPIO_Mode = GPIO_Mode_IN_FLOATING; gpioInit.GPIO_Pin = RX_PIN; GPIO_Init (COM_PORT, &gpioInit); // ---------------------------------------------------- // USART clock // ---------------------------------------------------- USART_SetPrescaler (LINK_USART, CLOCK_SCALER); clockInit.USART_Clock = USART_Clock_Enable; clockInit.USART_CPOL = USART_CPOL_Low; clockInit.USART_CPHA = USART_CPHA_1Edge; clockInit.USART_LastBit = USART_LastBit_Disable; USART_ClockInit (LINK_USART, &clockInit); // ---------------------------------------------------- // USART // ---------------------------------------------------- usartInit.USART_BaudRate = BAUD_RATE; usartInit.USART_WordLength = USART_WordLength_8b; usartInit.USART_StopBits = USART_StopBits_1; usartInit.USART_Parity = USART_Parity_No; usartInit.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; usartInit.USART_HardwareFlowControl = USART_HardwareFlowControl_None; USART_Init (LINK_USART, &usartInit); USART_Cmd (LINK_USART, ENABLE); // ---------------------------------------------------- // DMA RX // ---------------------------------------------------- dmaInit.DMA_PeripheralBaseAddr = (uint32_t)&(LINK_USART->DR); dmaInit.DMA_MemoryBaseAddr = (uint32_t)rxBuffer; dmaInit.DMA_DIR = DMA_DIR_PeripheralSRC; dmaInit.DMA_BufferSize = STARTUP_PACKET_SIZE; dmaInit.DMA_PeripheralInc = DMA_PeripheralInc_Disable; dmaInit.DMA_MemoryInc = DMA_MemoryInc_Enable; dmaInit.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; dmaInit.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; dmaInit.DMA_Mode = DMA_Mode_Normal; dmaInit.DMA_Priority = DMA_PRIORITY_USART_RX; dmaInit.DMA_M2M = DMA_M2M_Disable; DMA_Cmd (DMA_CHANNEL_USART_RX, ENABLE); DMA_Init (DMA_CHANNEL_USART_RX, &dmaInit); USART_DMACmd (LINK_USART, USART_DMAReq_Rx, ENABLE); // ---------------------------------------------------- // DMA TX // ---------------------------------------------------- dmaInit.DMA_PeripheralBaseAddr = (uint32_t)&(LINK_USART->DR); dmaInit.DMA_MemoryBaseAddr = (uint32_t)txBuffer; dmaInit.DMA_DIR = DMA_DIR_PeripheralDST; dmaInit.DMA_BufferSize = STANDARD_PACKET_SIZE; dmaInit.DMA_PeripheralInc = DMA_PeripheralInc_Disable; dmaInit.DMA_MemoryInc = DMA_MemoryInc_Enable; dmaInit.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; dmaInit.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; dmaInit.DMA_Mode = DMA_Mode_Normal; dmaInit.DMA_Priority = DMA_PRIORITY_USART_TX; dmaInit.DMA_M2M = DMA_M2M_Disable; DMA_Init (DMA_CHANNEL_USART_TX, &dmaInit); // ---------------------------------------------------- // clear DMA associated flags // ---------------------------------------------------- DMA_ClearFlag (DMA1_FLAG_GL5); DMA_ClearFlag (DMA1_FLAG_GL4); DMA_ClearITPendingBit (DMA1_IT_GL5); DMA_ClearITPendingBit (DMA1_IT_GL4);}void process (){  // ----------------------------------------------------
  // transmit a packet once per second
  // ----------------------------------------------------
if (TIMED_OUT (linkTimer)) { timer = 1000; // ---------------------------------------------------- // set the memory address and reset the data counter // for the DMA // ---------------------------------------------------- DMA_CHANNEL_USART_TX->CMAR = (uint32_t)data; DMA_CHANNEL_USART_TX->CNDTR = 5; // ---------------------------------------------------- // Enable the DMA, then generate the USART trigger by // enabling the USART DMA command // ---------------------------------------------------- DMA_Cmd (DMA_CHANNEL_USART_TX, ENABLE); USART_DMACmd (LINK_USART, USART_DMAReq_Tx, ENABLE); } // ---------------------------------------------------- // check for transmit complete // ---------------------------------------------------- if (DMA_GetFlagStatus (DMA_COMPLETE_USART_TX) == SET) { DMA_ClearFlag (DMA_CLEAR_USART_TX); // ---------------------------------------------------- // Disable the USART DMA command and the DMA channel. // The USART DMA command must be disabled, so that a // new trigger is generated when it will be enabled // again. The DMA channel must be disabled, so that // it is possible to set the data counter. // ---------------------------------------------------- USART_DMACmd (LINK_USART, USART_DMAReq_Tx, DISABLE); DMA_Cmd (DMA_CHANNEL_USART_TX, DISABLE); } // ---------------------------------------------------- // check for received data // ---------------------------------------------------- if (DMA_GetFlagStatus (DMA_COMPLETE_USART_RX) == SET) { flashIndicator (RED); DMA_ClearFlag (DMA_CLEAR_USART_RX); DMA_ClearITPendingBit (DMA1_IT_GL5); // ---------------------------------------------------- // Disable the USART DMA command and the DMA channel // ---------------------------------------------------- DMA_Cmd (DMA_CHANNEL_USART_RX, DISABLE); // ---------------------------------------------------- // reset the data counter // ---------------------------------------------------- DMA_CHANNEL_USART_RX->CNDTR = 1; // ---------------------------------------------------- // enable the DMA and USART to be ready for the next // reception // ---------------------------------------------------- DMA_Cmd (DMA_CHANNEL_USART_RX, ENABLE); }/* // ---------------------------------------------------- // for testing if the USART receive works at all // ---------------------------------------------------- if (USART_GetFlagStatus (LINK_USART, USART_FLAG_RXNE)) { received = (uint8_t)LINK_USART->DR; flashIndicator (RED); }*/}
---

Outcomes