2020-10-11 01:25 AM
Hi
I am trying to do a simple USART communication via DMA (LL Drivers). I want to send two chars to my STM32F103 from my PC which are received by DMA.
In the DMA RX transfer complete callback I want to send some text string, also via DMA back to the sender.
For that I wrote extra functions to send the text and to clear the text buffer once the DMA TX has completed the transfer.
Receiving the two chars works without problems.
Sending text back to the sender also works, but then the DMA1_Channel7_IRQHandler doesn't get called and subsequently all actions that rely on TX Transfer Complete signal don't work anymore, like clearing my TX-text buffer.
The buffer for the two receiving chars:
char rxBuf[2];
configuration of my reception DMA:
LL_DMA_SetMemoryAddress(DMA1, LL_DMA_CHANNEL_6, (uint32_t)rxBuf);
LL_DMA_SetPeriphAddress(DMA1, LL_DMA_CHANNEL_6, (uint32_t)&USART2->DR);
LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_6, 2);
LL_DMA_EnableIT_TC(DMA1, LL_DMA_CHANNEL_6);
LL_DMA_EnableIT_TE(DMA1, LL_DMA_CHANNEL_6);
LL_USART_EnableDMAReq_RX(USART2);
LL_USART_ClearFlag_TC(USART2);
LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_6);
the global DMA RX IRQ
void DMA1_Channel6_IRQHandler(void)
{
if(LL_DMA_IsActiveFlag_TC6(DMA1)){
LL_DMA_ClearFlag_TC6(DMA1);
DMA_RX_TC_Callback();
}
if(LL_DMA_IsActiveFlag_TE6(DMA1)){
LL_DMA_ClearFlag_TE6(DMA1);
DMA_RX_TE_Callback();
}
}
The RX TC Callback:
void DMA_RX_TC_Callback(void){
LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_6);
// send some text back via DMA
sprintf(usartBuf,"RX_TC event");
sendText(usartBuf);
clearUsartTxBuffer(usartBuf);
DMA1_Channel6->CNDTR = 2; // reset DMA RX counter for next chars receive
LL_USART_ClearFlag_TC(USART2);
LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_6);
}
implementation of the send text function:
char usartBuf[128];
uint8_t issending = 0;
...
void clearUsartTxBuffer(char *buf){
while(issending != 0);
for(int i=0;i<128;i++){
buf[i] = '\0';
}
}
void sendText(char *text){
while(issending != 0);
LL_DMA_SetMemoryAddress(DMA1, LL_DMA_CHANNEL_7, (uint32_t)text);
LL_DMA_SetPeriphAddress(DMA1, LL_DMA_CHANNEL_7, (uint32_t)&USART2->DR);
LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_7, strlen(text));
LL_DMA_EnableIT_TC(DMA1, LL_DMA_CHANNEL_7);
LL_DMA_EnableIT_TE(DMA1, LL_DMA_CHANNEL_7);
LL_USART_EnableDMAReq_TX(USART2); // USART_CR3_DMAT
LL_USART_ClearFlag_TC(USART2); // USART_SR_TC
issending = 1;
LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_7); // DMA_SxCR_EN
}
the DMA TX IRQ:
void DMA1_Channel7_IRQHandler(void)
{
LL_GPIO_SetOutputPin(LED_GPIO_Port, LED_Pin);
if(LL_DMA_IsActiveFlag_TC7(DMA1)){
LL_DMA_ClearFlag_TC7(DMA1);
DMA_TX_TC_Callback();
}
if(LL_DMA_IsActiveFlag_TE7(DMA1)){
DMA1_TX_TE_Callback();
}
}
and the DMA TX transfer complete callback:
void DMA_TX_TC_Callback(void){
LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_7);
issending = 0;
}
Both DMA Channels, TX and RX are in non circular, low priority.
If I use my sendText() function in main everything works as expected, even sending two or more subsequently texts and also its DMA1_Channel7_IRQHandler gets called. But as soon as I try to sendText() inside the DMA_RX_TC Callback it then refuses to call DMA1_Channel7_IRQHandler.
I ran the code in debug and it gets stuck in clearUsartTxBuffer() function while(issending) because issending never gets reset because it needs DMA1_Channel7_IRQHandler fired to reset it...
In CubeIDE I also checked the DMA1 ISR register at that point of hang and all DMA1 Channel 7 registers GIF7, TCIF7 and HTIF7 are set to 1.
So the registers are showing the interrupt is fired but code in DMA1_Channel7_IRQHandler
did not get executed?
Any ideas?
Solved! Go to Solution.
2020-10-11 02:29 AM
I possibly made some progress by playing with NVIC priorities...
After setting
NVIC_SetPriority(DMA1_Channel6_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),0, 0));
to
NVIC_SetPriority(DMA1_Channel6_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),1, 0));
the code works now as desired, the interrupt gets called and the buffer gets cleared.
2020-10-11 02:29 AM
I possibly made some progress by playing with NVIC priorities...
After setting
NVIC_SetPriority(DMA1_Channel6_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),0, 0));
to
NVIC_SetPriority(DMA1_Channel6_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),1, 0));
the code works now as desired, the interrupt gets called and the buffer gets cleared.