2018-10-15 12:40 AM
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!
2018-10-18 04:16 PM
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.