cancel
Showing results for 
Search instead for 
Did you mean: 

The DMA sending function can only be called once

AlfRomeo
Associate III

Gradually debug the DMA send function, HAL-UART Transmit DMA, and find that the function will judge a status bit of the serial port handle, gState. It will only send normally when huart ->gState==HAL UART State READY,

And the reason why the first transmission can be successful is because initially, gState was set to HAL-UARTVNet READY, so it can be successfully sent. However, during the first transmission, the HAL-UART_Transmit_SMA function will change gState to HAL-UARTVNet BUSY1 TX state, and the gState bit will remain in the HAL-UARTVNet BUSY1 state, causing subsequent transmissions to be unable to be executed. To clear gState state, it must enter the UART of the serial port interrupt HAL-UART_iRQHandler, where the gState flag bit is cleared.
My problem is that the serial port interrupt can only be accessed for the first time and cannot be accessed afterwards, so the sending fails. During debugging, occasional normal sending and receiving can be achieved. Can you please provide some suggestions? Here is my code:

void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
{
  if (huart->Instance == USART3)
  {
    if (HAL_UARTEx_ReceiveToIdle_DMA(&huart3, usart3RxBuff, MAX_COM3_RXSIZES) == HAL_BUSY)
    {
      __HAL_UART_CLEAR_OREFLAG(&huart3);
      huart3.RxState = HAL_UART_STATE_READY;
      huart3.Lock = HAL_UNLOCKED;
      HAL_UARTEx_ReceiveToIdle_DMA(&huart3, usart3RxBuff, MAX_COM3_RXSIZES);
    }
    initSqQueue(&uart[_COM3].Rx, usart3RxBuff, sizeof(usart3RxBuff));
    memset(usart3RxBuff, 0, MAX_COM3_RXSIZES);
    return;
  }
}
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
  if (huart->Instance == USART3)
  {
    uart[_COM3].Rx.rear = Size;
#ifdef _UART3_DEBUG
    uartxEcho(&huart3, &uart3);
#endif
    if (uart[_COM3].rxEnd == true)
    {
      uart[_COM3].rxIdle = false;
      initUartTick(&uart[_COM3], CONST_UART_DLY_TIM);
    }
    else
    {
      uart[_COM3].rxIdle = true;
      initUartTick(&uart[_COM3], CONST_UART_DLY_TIM);
      // MAP_Interrupt_disableSleepOnIsrExit();
    }
    return;
  }
  UNUSED(huart);
}
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
  if (huart->Instance == USART3)
  {
    uart[_COM3].sBusy = false;
#ifdef MAX_COM3_TXSIZES
    memset(usart3TxBuff, 0, MAX_COM3_TXSIZES);
#endif
    return;
  }
  UNUSED(huart);
}

The main program starts calling the function HAL-UARTEx-ReceiveToIdle_DMA (&hurt3, usart3RxBuff, MAX_CM3_SXSIZES); The function that sends the call is HAL-UART_Transmit_SMA (huart, (const uint8_t *) buf, num); During debugging, both buf and num are correct, but when sent out, there is no data. If DMA is not used for sending, the receiving process will enter the HAL-UART-ErrorCallback error callback.

2 REPLIES 2
liaifat85
Senior III

The gState of the UART handle (huart->gState) transitions during transmission and is expected to return to HAL_UART_STATE_READY when the transmission is complete. This typically happens in the HAL_UART_TxCpltCallback or the IRQ handler (HAL_UART_IRQHandler). If the state remains stuck in HAL_UART_STATE_BUSY_TX, subsequent calls to HAL_UART_Transmit_DMA will fail.

 

Check if HAL_UART_IRQHandler is properly called by the interrupt mechanism.Confirm that the HAL_UART_TxCpltCallback is invoked after a successful transmission and resets gState.

 

The flag bit huart ->gState will call HAL_UART_IRQHandler() in the serial port interrupt function USART3_IRQHandler(). In this function, UART_EndTransmit_IT() will be called, and the huart ->gState will be cleared in UART_EndTransmit_IT(). Now I will enter USART3_IRQHandler() for the first time, and will not enter later. So huart ->gState has always been HAL_UART_STATE_BUSY_TX