2021-04-19 10:12 AM
I want to use DMA1_Stream5, Channel 4 to receive variable length packets on USART2. the first 3 bytes of each packet contain a protocol ID, a packet type and packet length. I initially set the RXNE interrupt enabled so I can interpret and decode those 3 bytes in the USART2_IRQHandler.
I then initiate a DMA transfer to receive the remaining bytes of the packet according to the length byte just decoded. And since I no longer need a per byte interrupt for the duration of the DMA transfer, I disable the RXNE interrupt (USART2->CR1 &= ~USART_CR1_RXNEIE;).
However, I have found that the DMA transfer doesn't work and it never enters the DMA1_Stream5_IRQHandler to process the Transfer Complete Interrupt. It is only if I leave the RXNE interrupt enabled will the DMA transfer complete and fire the TC interrupt.
Why is that - i.e. is the RXNE interrupt required to make the USART RX DMA connection?
2021-04-19 11:13 AM
Which STM32?
> DMA transfer doesn't work
At all, or just it does not receive the expected number of bytes?
IMO you have some other problem and it's coincidental that leaving the RXNE interrupt enabled makes any difference.
Post code, mainly the ISR.
JW
2021-04-19 11:27 AM
I forgot to mention its an STM32F765VGT6 and I think you're right - Its another problem. Needing the RXNE interrupt on is a red herring.
I have just found out that if I set the USART2 IDLE_LINE detect interrupt and in the USART2_IRQHandler, terminate the DMA transfer by disabling the DMA, then I can get the DMA Transfer Complete interrupt to fire. It looks like the number of bytes requested for the DMA is incorrect, so I'll have o look into that.
It uses FreeRTOS tasks to handle the actual work so the IRQHandlers are minimal i.e.:
void USART2_IRQHandler(void)
{
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
uint32_t taskNotificationValue = 0;
// Is it a character received interrupt?
if ((USART2->ISR & USART_ISR_RXNE) == USART_ISR_RXNE)
{
uint8_t dataByte = USART2->RDR; // This also clears the USART_ISR_RXNE bit.
// Hand off received byte to the Serial Bus Task
taskNotificationValue = dataByte;
if (xSerialBusTaskHandle != 0)
{
// Send the notification value to the Serial Bus Task
xTaskNotifyFromISR(
xSerialBusTaskHandle,
taskNotificationValue,
eSetValueWithOverwrite,
&xHigherPriorityTaskWoken);
// Make sure the ISR exits and the SRXL2 Task is entered immediately
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
} // if ((USART2->ISR & USART_ISR_RXNE) == USART_ISR_RXNE)
// Is it an IDLE-LINE detect interrupt?
if ((USART2->ISR & USART_ISR_IDLE) == USART_ISR_IDLE)
{
// Clear the interrupt flag.
USART2->ICR |= USART_ICR_IDLECF;
// Then terminate the DMA Transfer to trigger the Transfer Complete Interrupt.
DMA1_Stream5->CR &= ~DMA_SxCR_EN;
}
}
void DMA1_Stream5_IRQHandler(void)
{
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
uint32_t taskNotificationValue = 0;
DebugPutStringWithCRLF("*** In DMA1_Stream5_IRQHandler()-0");
// Is it DMA Channel TCIF5 Transfer complete interrupt flag in HISR?
if (DMA1->HISR & DMA_HISR_TCIF5)
{
// Clear the TCIF5 Interrupt flag (bit position 11 in HIFCR)
DMA1->HIFCR |= DMA_HISR_TCIF5;
DebugPutStringWithCRLF("*** In DMA1_Stream5_IRQHandler()-1");
if (xSerialBusTaskHandle != 0)
{
// taskNotificationValue is 0xFFFFFFFF to indicate to the
// Serial Bus task that this notification is from this IRQ,
// not the USART receive byte IRQ.
taskNotificationValue = TASK_NOTIFICATION_DMA_TRANSFER_COMPLETE;
// Send the notification value to the SerialBus Task
xTaskNotifyFromISR(
xSerialBusTaskHandle,
taskNotificationValue,
eSetValueWithOverwrite,
&xHigherPriorityTaskWoken);
// Make sure the ISR exits and the ProcessThrottle1Task is entered immediately
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
}
}