cancel
Showing results for 
Search instead for 
Did you mean: 

using HAL_UART_Transmit with safety

MMath.10
Associate II

Hi,

I'm using the USART function HAL_UART_Transmit for debugging.

Most of the time everything works well.

But sometimes the HAL_UART_ErrorCallback is called... And all my program freeze.

Could you help me with these 2 options (first is best for me) :

how can i get back to a functionnal state after a HAL_UART_ErrorCallback call ?

how can i check if UART is ready to send data before using HAL_UART_Transmit ?

Regards

1 ACCEPTED SOLUTION

Accepted Solutions
Bob S
Principal

I'm not sure what you mean be "the visible code" - you have the source for the entire HAL_UART code (i.e. the file in which you found the source for HAL_UART_Transmit_DMA() above). Search that file for all mentions of "HAL_UART_ErrorCallBack()". Functions that start with underscores, like __HAL_DMA_Enable_IT() are actually macros that are defined in the associated .h file (i.e. stm32l0xx_hal_uart.h or something like that).

As an aside - if your editor does not have a "search all files in this project" function, or a "go to the definitiion of this function", or a "show me all the references to this function" - get a new editor or IDE. Or learn how to use these features in the editor that you are using. They will save you SOOOOOO much time.

Not having debugger access on your board makes things more difficult. Time to go back to old school debugging. A first step would be to add code to your HAL_UART_ErrorCallBack() to dump all of the UART and DMA control and status registers to a debug serial port (which I hope you have). Then look and see what kind of error is indicated. If that doesn't help, you will have to (temporarily) change the code in HAL UART source whereever the error callback is called to somehow tell your program what error happened.

View solution in original post

17 REPLIES 17
Bob S
Principal

HAL_UART_Transmit() should never call HAL_UART_ErrorCallback(), so something is fishy here. The error callback is only used with interrupt and/or DMA transmit and receive.

Are you using any other UART? Are you ever calling HAL_UART_Transmit_IT() or HAL_UART_Transmit_DMA() or the equivalent "receive" functions?

The error callback function is passed a pointer to a UART handle. Set a breakpoint in HAL_UART_ErrorCallback() and look at which structure is passed. Look at the "instance" pointer and see which UART it points to. You can also use the HAL_UART_GetError() function/macro to get the error code.

MMath.10
Associate II

Hi,

yes i use HAL_UART_Transmit_DMA for a second USART.

But i use the printf with this code and i think is safe :

int32_t TraceSendBle( const char *strFormat, ...)
{
  char buf[TEMPBUFSIZE];
  va_list vaArgs;
  uint8_t* buffer;
  va_start( vaArgs, strFormat);
  uint16_t bufSize=vsnprintf(buf,TEMPBUFSIZE,strFormat, vaArgs);
  va_end(vaArgs);
  int status=0;
 
  status =circular_queue_add(&MsgTraceQueue,(uint8_t*)buf, bufSize);
 
  if ((status==0 ) && (TracePeripheralReady==SET))
  {
    circular_queue_get(&MsgTraceQueue,&buffer,&bufSize);
    vcom_Trace(buffer, bufSize);
  }
 
  return status;
}
void vcom_Trace(  uint8_t *p_data, uint16_t size )
{
  HAL_UART_Transmit_DMA(&huart2,p_data, size);
}

 EDIT:

maybe is due to my change to desactivate low power mode :

static void Trace_TxCpltCallback(void)
{
  int status;
  uint8_t* buffer;
  uint16_t bufSize;
 
  //BACKUP_PRIMASK();
 
  //DISABLE_IRQ(); /**< Disable all interrupts by setting PRIMASK bit on Cortex*/
  /* Remove element just sent to UART */
  circular_queue_remove(&MsgTraceQueue);
  //DBG_GPIO_SET(GPIOB, GPIO_PIN_13);
  //DBG_GPIO_RST(GPIOB, GPIO_PIN_13);
  /* Sense if new data to be sent */
  status=circular_queue_sense(&MsgTraceQueue);
 
  if ( status == 0)
  {
    circular_queue_get(&MsgTraceQueue,&buffer,&bufSize);
    //RESTORE_PRIMASK();
    //DBG_GPIO_SET(GPIOB, GPIO_PIN_14);
    //DBG_GPIO_RST(GPIOB, GPIO_PIN_14);
    OutputTrace(buffer, bufSize);
  }
  else
  {
    //DBG_GPIO_SET(GPIOB, GPIO_PIN_12);
 
    //LPM_SetStopMode(LPM_UART_TX_Id , LPM_Enable );
    //TracePeripheralReady = SET;
    //RESTORE_PRIMASK();
  }
}

Bob S
Principal

As I mentioned in my first post - Add code to the error callback, set a breakpoint and see what the error is. Look back through the call stack to see exactly which line (in the HAL_UART code) generated the error. Until you do that, everything else is just a guess.

error code is 0, i don't understand...

is use this code to have it :

void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
{
  /* Initialization Error */
  advanten_error_code = huart->ErrorCode;
  Error_Handler();
}

Today i work on my watchdog which permit to restart but i prefer to found the source of the problem.

Hmmmm... I don't know which CPU you are using, but looking at the L4xx HAL code, there are cases where the error callback is called with the error still at zero. So... set a breakpoint in the error callback, look at the call stack and figure out which path led to the error.

Hi thanks for your time.

I have this CPU : STM32L072

I don't have debug mode on my dev board. I need to change to the primary eval board which not have exactly the same hardware. And it don't have the usart which give this error... So i need to found another way.

Where can i see the low level code of the HAL?

It should be in your project directory under Drivers\STM32L0xx_HAL_Driver, or something like that. But if you are debugging the and set a breakpoint in YOUR error callback function, the debugger's call stack should lead you right to it.

Hi Bob,

I know where the function is HAL_UART_Transmit_DMA.

But I was thinking that the error callback is called in another function.

The callback is set in HAL_DMA_Start_IT but i don't think i have access to the HAL code.

  /* Enable the transfer Error interrupt */
  __HAL_DMA_ENABLE_IT(hdma, DMA_IT_TE);

The visible code where we see the error case when function is called.

/**
  * @brief Send an amount of data in DMA mode.
  * @param huart: UART handle.
  * @param pData: pointer to data buffer.
  * @param Size: amount of data to be sent.
  * @note   When UART parity is not enabled (PCE = 0), and Word Length is configured to 9 bits (M1-M0 = 01),
  *         address of user data buffer containing data to be sent, should be aligned on a half word frontier (16 bits)
  *         (as sent data will be handled using u16 pointer cast). Depending on compilation chain,
  *         use of specific alignment compilation directives or pragmas might be required to ensure proper alignment for pData.
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_UART_Transmit_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
{
  /* Check that a Tx process is not already ongoing */
  if(huart->gState == HAL_UART_STATE_READY)
  {
    if((pData == NULL ) || (Size == 0U))
    {
      return HAL_ERROR;
    }
 
    /* In case of 9bits/No Parity transfer, pData buffer provided as input paramter 
       should be aligned on a u16 frontier, as data copy into TDR will be 
       handled by DMA from a u16 frontier. */
    if ((huart->Init.WordLength == UART_WORDLENGTH_9B) && (huart->Init.Parity == UART_PARITY_NONE))
    {
      if((((uint32_t)pData)&1) != 0)
      {
        return  HAL_ERROR;
      }
    }
 
    /* Process Locked */
    __HAL_LOCK(huart);
 
    huart->pTxBuffPtr = pData;
    huart->TxXferSize = Size;
    huart->TxXferCount = Size;
 
    huart->ErrorCode = HAL_UART_ERROR_NONE;
    huart->gState = HAL_UART_STATE_BUSY_TX;
 
    /* Set the UART DMA transfer complete callback */
    huart->hdmatx->XferCpltCallback = UART_DMATransmitCplt;
 
    /* Set the UART DMA Half transfer complete callback */
    huart->hdmatx->XferHalfCpltCallback = UART_DMATxHalfCplt;
 
    /* Set the DMA error callback */
    huart->hdmatx->XferErrorCallback = UART_DMAError;
 
    /* Set the DMA abort callback */
    huart->hdmatx->XferAbortCallback = NULL;
 
    /* Enable the UART transmit DMA channel */
    HAL_DMA_Start_IT(huart->hdmatx, (uint32_t)huart->pTxBuffPtr, (uint32_t)&huart->Instance->TDR, Size);
 
    /* Clear the TC flag in the ICR register */
    __HAL_UART_CLEAR_FLAG(huart, UART_CLEAR_TCF);
 
    /* Process Unlocked */
    __HAL_UNLOCK(huart);
 
    /* Enable the DMA transfer for transmit request by setting the DMAT bit
       in the UART CR3 register */
    SET_BIT(huart->Instance->CR3, USART_CR3_DMAT);
 
    return HAL_OK;
  }
  else
  {
    return HAL_BUSY;
  }
}

Bob S
Principal

I'm not sure what you mean be "the visible code" - you have the source for the entire HAL_UART code (i.e. the file in which you found the source for HAL_UART_Transmit_DMA() above). Search that file for all mentions of "HAL_UART_ErrorCallBack()". Functions that start with underscores, like __HAL_DMA_Enable_IT() are actually macros that are defined in the associated .h file (i.e. stm32l0xx_hal_uart.h or something like that).

As an aside - if your editor does not have a "search all files in this project" function, or a "go to the definitiion of this function", or a "show me all the references to this function" - get a new editor or IDE. Or learn how to use these features in the editor that you are using. They will save you SOOOOOO much time.

Not having debugger access on your board makes things more difficult. Time to go back to old school debugging. A first step would be to add code to your HAL_UART_ErrorCallBack() to dump all of the UART and DMA control and status registers to a debug serial port (which I hope you have). Then look and see what kind of error is indicated. If that doesn't help, you will have to (temporarily) change the code in HAL UART source whereever the error callback is called to somehow tell your program what error happened.