cancel
Showing results for 
Search instead for 
Did you mean: 

UART DMA Transmit Binary Semaphore Synchronization Issue/Weird-Bug

DSopp.1
Associate

Hello,

I am trying to synchronize the sending of strings using UART via a DMA. The program ``mostly`` works but the DMA does not write fast enough therefore the program overwrites the buffer and it ends up sending garbage data. I am trying to synchronize the DMA using a binary semaphore that is released when the DMA calls the TxCplt callback function. The code for this is below and the callback function is confirmed working. Note that transmit function is called often.

 

/*
*****************************************************************************************
* @brief Transmit a buffer of bytes to the CLI UART. Calls CLIUart_SafeTransmit().
* @param pBuf - Pointer to data buffer
* @param length - Number of bytes to transmit
* @param timeout - msec timeout
* @return HAL Status
*****************************************************************************************
*/
HAL_StatusTypeDef CLIUart_Transmit(uint8_t* pBuf, uint32_t length, uint32_t timeout)

{
    HAL_StatusTypeDef txStatus = HAL_OK;
configASSERT(CLIUart_TxSemaphore != NULL);

    if (length == 0)
    {
    return(HAL_ERROR);
    }

// FIXME: changed from timeout to portMAX_DELAY
    xSemaphoreTake(CLIUart_TxSemaphore, portMAX_DELAY);
txStatus = HAL_UART_Transmit_DMA(&hUart_CLI, pBuf, length);

    return (txStatus);
}

/*
*****************************************************************************************
* @brief Tx Transfer completed callback called from lower level HAL layer after the
* full DMA transmit is complete.
* @param pParam: pointer to higher priority task woken flag
* @return None
*****************************************************************************************
*/
void CLIUartDriver_UartTxCpltCallback(void *pParam)
{
configASSERT(CLIUart_TxSemaphore != NULL);
xSemaphoreGiveFromISR(CLIUart_TxSemaphore, pParam);
}

 
When I step through the debugger and check the semaphore handle it works and the output of the program is normal. However when not debugging the program runs too fast and often the commands being sent out cut each other off. I changed the semaphore from being before the UART transmit function to being after like:

 

/*
*****************************************************************************************
* @brief Transmit a buffer of bytes to the CLI UART. Calls CLIUart_SafeTransmit().
* @param pBuf - Pointer to data buffer
* @param length - Number of bytes to transmit
* @param timeout - msec timeout
* @return HAL Status
*****************************************************************************************
*/
HAL_StatusTypeDef CLIUart_Transmit(uint8_t* pBuf, uint32_t length, uint32_t timeout)
{
    HAL_StatusTypeDef txStatus = HAL_OK;
configASSERT(CLIUart_TxSemaphore != NULL);

    if (length == 0)
    {
    return(HAL_ERROR);
    }

txStatus = HAL_UART_Transmit_DMA(&hUart_CLI, pBuf, length);

// FIXME: changed from timeout to portMAX_DELAY
xSemaphoreTake(CLIUart_TxSemaphore, portMAX_DELAY);

    return (txStatus);
}

After this change the program magically works as intended and the DMA is fully synchronized to the semaphore and the output on the console is perfect.

This does not make sense to me as I see not difference for waiting for the semaphore before hand or after? I would rather it be before for convention but is there any difference in blocking doing it this way?

I am unsure why this would make such a major difference and I am wondering if anyone knows why...

Note: For additional information the Semaphore is created and released before any UART transmits take place.

// Create all the RTOS overhead
CLIUart_TxSemaphore = xSemaphoreCreateBinary();
xSemaphoreGive(CLIUart_TxSemaphore);

Thanks, Danny

1 REPLY 1
Piranha
Chief II

You are correct - such a "workaround" doesn't make sense and there is no point in analyzing it's behavior. Instead one should fix the real issues - replacing the ST's broken bloatware.