2021-09-21 05:31 AM
Hi,
I am working with F413 and I am using USART3 to receive and trasmit data over UART. As I need to receive unknow size of data I wrote my own interrupt handler for RX. However I would like to transmit data out with a help of DMA.
If I call regular poll UART_Transmit(...) function, device will send out data and response from the target will be picked up by RX IRQ handler to a buffer without a problem. I wan't to get rid of blocking UART_Transmit() function. For that reason I configure and setup DMA so I could use non-blocking UART_Transmit_DMA(...) function.
With logic analyzer I can see properly formed outgoing and incoming traffic. I would say that DMA transmit works fine... but now I have problem with RX IRQ handler...
My receive IRQ handler looks like this:
/* USART3 RX handler */
UART_RX_INTERRUPT_HANDLER_DECLARATION(USART3)
{
/* Check if receive register is not empty status */
if __HAL_UART_GET_FLAG(&UARTS_Instance()->consts[UART_INSTANCE_3].huart, USART_SR_RXNE)
{
/* Disable/ clear flag */
__HAL_UART_CLEAR_FLAG(&UARTS_Instance()->consts[UART_INSTANCE_3].huart, USART_SR_RXNE);
/* Process received data */
UARTS_Instance()->rx_irq_callback(UARTS_Instance()->consts[UART_INSTANCE_3].index ,__HAL_UART_FLUSH_DRREGISTER(&UARTS_Instance()->consts[UART_INSTANCE_3].huart));
/* Flush register*/
__HAL_UART_FLUSH_DRREGISTER(&UARTS_Instance()->consts[UART_INSTANCE_3].huart);
/* Re-enable interrupt */
__HAL_UART_ENABLE_IT(&UARTS_Instance()->consts[UART_INSTANCE_3].huart, UART_IT_RXNE);
}
}
What happens now is that I am stuck in this handler and it gets called repeatedly, therfore my program "freezes". If I put breakpoint inside handler and inspect peripheral registers I see there's TCIE register enable.... although I never enable it manually anywhere in my code ( I've checked it several times)... So now I am thinking if DMA could have any impact on that and how I should properly handle flags and interrupts within that handler (while DMA Stream has it's own handler - HAL_DMA_IRQHandler(&dma) ).
void DMA1_Stream3_IRQHandler(void)
{
HAL_DMA_IRQHandler(&UARTS_Instance()->consts[UART_INSTANCE_3].hdma);
}
Any help would be much appreciated!
Solved! Go to Solution.
2021-09-21 06:18 AM
Hello @Nix Wayne
Here is the sequence that happens when calling HAL_UART_Transmit_DMA() :
So, problem you encounter, is related to use of HAL API for transmit DMA, while call of HAL_UART_IRQHandler is not executed when a UART interrupt is raised. The management of the TC interrupt is missing in your IRQ handler. As for DMA, standard use of HAL services, requires call of HAL_UART_IRQHandler in USART3_IRQHandler().
A workaround for mixing use of HAL services without using HAL IRQ Handler function, could be to just implement the management of the TC interrupt into your IRQ handler. Here is a draft proposal (not tested nor compiled) that might work if TC interrupt is used only for HAL purposes.
Goal is to replicate what HAL IRQ Handler default function would have done on a TC interrupt at the end of a DMA transmission.
/* USART3 RX handler */
UART_RX_INTERRUPT_HANDLER_DECLARATION(USART3)
{
/* Check if receive register is not empty status */
if __HAL_UART_GET_FLAG(&UARTS_Instance()->consts[UART_INSTANCE_3].huart, USART_SR_RXNE)
{
...
}
/* Check if TC flag is set and TCIE is enabled */
if ( ( (&UARTS_Instance()->consts[UART_INSTANCE_3].huart->Instance->CR1 & (USART_CR1_TCIE)) == (USART_CR1_TCIE))
&& (__HAL_UART_GET_FLAG(&UARTS_Instance()->consts[UART_INSTANCE_3].huart, USART_SR_TC)
)
{
/* Disable the UART Transmit Complete Interrupt
(TCIE has been enabled on DMA TX Complete event) */
__HAL_UART_DISABLE_IT(&UARTS_Instance()->consts[UART_INSTANCE_3].huart, UART_IT_TC);
/* Tx process is ended, restore UART Handle state to Ready
(if not done, this might prevent further transmits) */
&UARTS_Instance()->consts[UART_INSTANCE_3].huart->gState = HAL_UART_STATE_READY;
}
}
What is the version of your STM324 HAL Firmware package ?
Hope this helps.
Regards
2021-09-21 05:37 AM
If you want to use HAL, you need to let the HAL framework handle interrupts and clearing of flags. Here, you would call HAL_UART_IRQHandler within the interrupt and implement HAL_UART_RxCpltCallback if you want something ran when the transfer is complete.
If you want to handle each individual RXNE event, you can use HAL_UART_Transmit_IT with a transfer size of 1 each time.
2021-09-21 06:18 AM
Hello @Nix Wayne
Here is the sequence that happens when calling HAL_UART_Transmit_DMA() :
So, problem you encounter, is related to use of HAL API for transmit DMA, while call of HAL_UART_IRQHandler is not executed when a UART interrupt is raised. The management of the TC interrupt is missing in your IRQ handler. As for DMA, standard use of HAL services, requires call of HAL_UART_IRQHandler in USART3_IRQHandler().
A workaround for mixing use of HAL services without using HAL IRQ Handler function, could be to just implement the management of the TC interrupt into your IRQ handler. Here is a draft proposal (not tested nor compiled) that might work if TC interrupt is used only for HAL purposes.
Goal is to replicate what HAL IRQ Handler default function would have done on a TC interrupt at the end of a DMA transmission.
/* USART3 RX handler */
UART_RX_INTERRUPT_HANDLER_DECLARATION(USART3)
{
/* Check if receive register is not empty status */
if __HAL_UART_GET_FLAG(&UARTS_Instance()->consts[UART_INSTANCE_3].huart, USART_SR_RXNE)
{
...
}
/* Check if TC flag is set and TCIE is enabled */
if ( ( (&UARTS_Instance()->consts[UART_INSTANCE_3].huart->Instance->CR1 & (USART_CR1_TCIE)) == (USART_CR1_TCIE))
&& (__HAL_UART_GET_FLAG(&UARTS_Instance()->consts[UART_INSTANCE_3].huart, USART_SR_TC)
)
{
/* Disable the UART Transmit Complete Interrupt
(TCIE has been enabled on DMA TX Complete event) */
__HAL_UART_DISABLE_IT(&UARTS_Instance()->consts[UART_INSTANCE_3].huart, UART_IT_TC);
/* Tx process is ended, restore UART Handle state to Ready
(if not done, this might prevent further transmits) */
&UARTS_Instance()->consts[UART_INSTANCE_3].huart->gState = HAL_UART_STATE_READY;
}
}
What is the version of your STM324 HAL Firmware package ?
Hope this helps.
Regards
2021-09-21 06:41 AM
Hi Guenael,
YES! That solved my problem...
I was missing only one line:
UARTS_Instance()->consts[UART_INSTANCE_3].huart->gState = HAL_UART_STATE_READY;
All information are in your reply!!! I
Thanks again! You rock and I owe you a beer! ;)
Nix