Skip to main content
ChrisFyberLabs
Associate
October 15, 2018
Question

DMA USART receive data is returning DMA USART transmit data.

  • October 15, 2018
  • 1 reply
  • 1309 views

Hi, I am having the weirdest situation. I setup LL DMA transfers for both transmit and receive on USART2. I let stm32cubemx do its partial init, which seems to work:

void radioUART_init(void) {
 //Turn off USART while we finish non-templated options
 LL_USART_Disable(RADIO_USART);
 LL_USART_DisableDMAReq_RX(RADIO_USART); //RX DMA int off
 LL_USART_DisableDMAReq_TX(RADIO_USART); //TX DMA int of
 LL_DMA_DisableStream(DMA1, LL_DMA_STREAM_6); //TX off
 LL_DMA_DisableStream(DMA1, LL_DMA_STREAM_5); //RX off
 
 //TX setup
 LL_DMA_SetPeriphAddress(DMA1, LL_DMA_STREAM_6, (uint32_t)&RADIO_USART->DR);
 LL_DMA_SetMemoryAddress(DMA1, LL_DMA_STREAM_6, (uint32_t)dma_tx_buf);
 LL_DMA_SetDataLength(DMA1, LL_DMA_STREAM_6, strlen(tx_buffer));
 
 LL_DMA_EnableIT_TE(DMA1, LL_DMA_STREAM_6);//TX enable transfer error int
 LL_DMA_EnableIT_TC(DMA1, LL_DMA_STREAM_6);//TX enable transfer complete int
 //LL_DMA_EnableIT_FE(DMA1, LL_DMA_STREAM_6);//TX enable fifo error int
 LL_DMA_EnableIT_DME(DMA1, LL_DMA_STREAM_6);//TX enable direct mode error int
 LL_DMA_DisableIT_HT(DMA1, LL_DMA_STREAM_6);
 LL_DMA_DisableIT_FE(DMA1, LL_DMA_STREAM_6);
 
 LL_DMA_ClearFlag_TC6(DMA1); //TX Transfer complete clear
 LL_DMA_ClearFlag_TE6(DMA1); //TX Transfer error clear
 LL_DMA_ClearFlag_FE6(DMA1); //TX Fifo error clear
 LL_DMA_ClearFlag_HT6(DMA1);
 LL_DMA_ClearFlag_DME6(DMA1);
 
 //RX setup
 //To start a RX USARTx_CR1_RE must be set
 LL_DMA_SetPeriphAddress(DMA1, LL_DMA_STREAM_5, (uint32_t)&RADIO_USART->DR);
 LL_DMA_SetMemoryAddress(DMA1, LL_DMA_STREAM_5, (uint32_t)rx_buffer);
 LL_DMA_SetDataLength(DMA1, LL_DMA_STREAM_5, RX_DMA_BUF_SIZE);
 
 LL_DMA_EnableIT_HT(DMA1, LL_DMA_STREAM_5);//RX enable half transfer int
 LL_DMA_EnableIT_TE(DMA1, LL_DMA_STREAM_5);//RX enable transfer error int
 LL_DMA_EnableIT_TC(DMA1, LL_DMA_STREAM_5);//RX enable transfer complete int
 LL_DMA_EnableIT_FE(DMA1, LL_DMA_STREAM_5);//RX enable fifo error int
 LL_DMA_EnableIT_DME(DMA1, LL_DMA_STREAM_5);//RX enable direct mode error int
 
 LL_DMA_DisableIT_HT(DMA1, LL_DMA_STREAM_5);//RX disable half transfer int
 LL_DMA_DisableIT_FE(DMA1, LL_DMA_STREAM_5);//RX disable fifo error int
 
 LL_DMA_ClearFlag_TC5(DMA1); //RX Transfer complete clear
 LL_DMA_ClearFlag_TE5(DMA1); //RX Transfer error clear
 LL_DMA_ClearFlag_FE5(DMA1); //RX Fifo error clear
 LL_DMA_ClearFlag_HT5(DMA1);
 LL_DMA_ClearFlag_DME5(DMA1);
 
 
 LL_DMA_EnableStream(DMA1, LL_DMA_STREAM_6); //TX DMA channel on
 LL_DMA_EnableStream(DMA1, LL_DMA_STREAM_5); //RX DMA channel on
 LL_USART_Enable(USART2);
 LL_USART_EnableDMAReq_TX(USART2); //TX DMA int on
 LL_USART_EnableDMAReq_RX(USART2); //RX DMA int on
 LL_USART_EnableIT_IDLE(USART2); //Detect TX(and RX?) IDLEs
 radio_receive = true;
 //RX DMA should be up and listening now
}

I then transmit state on start up, but the data returns back on the receiver buffer. Also, the transmit is throwing DMA FIFO errors.

Transmit function, I assume the DMA is disabled as this can't be called again in its wrapper function unless any current transmit has succeeded with a TC.

void radioUART_Transmit(void) {
 LL_DMA_SetPeriphAddress(DMA1, LL_DMA_STREAM_6, (uint32_t)&RADIO_USART->DR);
 LL_DMA_SetMemoryAddress(DMA1, LL_DMA_STREAM_6, (uint32_t)dma_tx_buf);
 LL_DMA_SetDataLength(DMA1, LL_DMA_STREAM_6, strlen(tx_buffer));
 LL_DMA_ClearFlag_TC6(DMA1); //TX Transfer complete clear
 LL_DMA_ClearFlag_TE6(DMA1); //TX Transfer error clear
 LL_DMA_ClearFlag_FE6(DMA1); //TX Fifo error clear
 LL_DMA_ClearFlag_HT6(DMA1);
 LL_DMA_ClearFlag_DME6(DMA1);
 
 LL_DMA_DisableIT_HT(DMA1, LL_DMA_STREAM_6);
 LL_DMA_DisableIT_FE(DMA1, LL_DMA_STREAM_6);
 
 LL_DMA_EnableStream(DMA1, LL_DMA_STREAM_6); //TX DMA channel on
 
 LL_USART_Enable(USART2);
 LL_USART_EnableDMAReq_TX(USART2); //TX DMA int on
}

Receive is a mix of two DMA with IDLE examples online with a systick based timer(dma_uart_rx struct) after IDLE. The interrupt passes data to a message parser/builder. At some point I would like to implement a HT call to pass to the parser, but I figured small things like buffer corruption should be fixed first.

void radioUART_Receive_IRQHandler(void) {
 if(LL_DMA_IsActiveFlag_TE5(DMA1)) //TX Transfer error set)
 {
 LL_DMA_ClearFlag_TE5(DMA1); //TX Transfer error clear
 Log(LOG_ERROR, "RX DMA Transfer Error");
 }
 
 if(LL_DMA_IsActiveFlag_FE5(DMA1)) //TX FIFO error set)
 {
 LL_DMA_ClearFlag_FE5(DMA1); //TX FIFO error clear
 Log(LOG_ERROR, "RX DMA FIFO or init Error");
 }
 
 if(LL_DMA_IsActiveFlag_DME5(DMA1)) //TX DME error set)
 {
 LL_DMA_ClearFlag_DME5(DMA1); //TX DME error clear
 Log(LOG_ERROR, "RX DMA Direct Mode Error");
 }
 
 if(dma_uart_rx.flag) /* Timeout event */
 {
 volatile uint16_t currCNDTR = LL_DMA_GetDataLength(DMA1, LL_DMA_STREAM_5);
 if(currCNDTR == RX_DMA_BUF_SIZE)
 { 
 dma_uart_rx.flag = 0;
 return;
 }
 else {
 radioBufferReceive(rx_buffer, 0, RX_DMA_BUF_SIZE-currCNDTR);
 }
 dma_uart_rx.prevCNDTR = RX_DMA_BUF_SIZE;
 dma_uart_rx.flag = 0;
 
 LL_DMA_SetPeriphAddress(DMA1, LL_DMA_STREAM_5, (uint32_t)&RADIO_USART->DR);
 LL_DMA_SetMemoryAddress(DMA1, LL_DMA_STREAM_5, (uint32_t)rx_buffer);
 LL_DMA_SetDataLength(DMA1, LL_DMA_STREAM_5, RX_DMA_BUF_SIZE);
 LL_DMA_ClearFlag_TC5(DMA1); //TX Transfer complete clear
 LL_DMA_ClearFlag_HT5(DMA1);
 volatile uint32_t tmp; /* Must be volatile to prevent optimizations */
 tmp = RADIO_USART->SR; /* Read status register */
 tmp = RADIO_USART->DR; /* Read data register */
 (void)tmp; /* Prevent compiler warnings */
 radio_receive = true;
 LL_DMA_EnableStream(DMA1, LL_DMA_STREAM_5); //TX DMA channel on;
 } else {
 
 if(LL_DMA_IsActiveFlag_HT5(DMA1)) {
 LL_DMA_ClearFlag_HT5(DMA1);
 }
 
 if (LL_DMA_IsActiveFlag_TC5(DMA1)) {
 LL_DMA_ClearFlag_TC5(DMA1);
 dma_uart_rx.prevCNDTR = RX_DMA_BUF_SIZE;
 radioBufferReceive(rx_buffer, 0, RX_DMA_BUF_SIZE); 
 
 LL_DMA_SetPeriphAddress(DMA1, LL_DMA_STREAM_5, (uint32_t)&RADIO_USART->DR);
 LL_DMA_SetMemoryAddress(DMA1, LL_DMA_STREAM_5, (uint32_t)rx_buffer);
 LL_DMA_SetDataLength(DMA1, LL_DMA_STREAM_5, RX_DMA_BUF_SIZE);
 LL_DMA_ClearFlag_TC5(DMA1); //TX Transfer complete clear
 
 volatile uint32_t tmp; /* Must be volatile to prevent optimizations */
 tmp = RADIO_USART->SR; /* Read status register */
 tmp = RADIO_USART->DR; /* Read data register */
 (void)tmp; /* Prevent compiler warnings */
 LL_DMA_EnableStream(DMA1, LL_DMA_STREAM_5); //RX DMA channel on;
 }
 }
}

Has anyone seen transmit appear on the receive buffer before? I am not sure if it is some weird effect of running it under Atollic's debug or ? As you can see, RX_DMA_BUF_SIZE is the only data length ever set before the receive DMA is enabled. So there is no weird memory violation.

Thanks for any help!

This topic has been closed for replies.

1 reply

ChrisFyberLabs
Associate
October 18, 2018

The problem was with the ****** RPI defaults for uarts. The TX DMA error was from not disabling the DMA request and then enabling it after setting up transmit again.