cancel
Showing results for 
Search instead for 
Did you mean: 

Unintentional splitting of messages sent via UART using DMA

grados73
Associate II

Hi, I'm having a problem with unintentionally splitting a message I'm trying to send over the UART using DMA . I am using one function to send the message:

const uint32_t max_value_of_counter_loop = 100; /* in case systick jams */
volatile bool was_u1_tx_cplt = true;
HAL_StatusTypeDef OwnTransmitDma(UART_HandleTypeDef *huart, const uint8_t *pData, uint16_t Size)
{
/* Wait on uart to be ready, but no more than 3ms */
uint32_t start_of_try_to_send = HAL_GetTick();
uint32_t counter_while_loop = 0; /* in case systick jams */
while((huart1.gState != HAL_UART_STATE_READY) && (!was_u1_tx_cplt))
{
counter_while_loop++;
uint32_t now_get_tick = HAL_GetTick();
if(now_get_tick > (start_of_try_to_send+2)) break; /* wait no more than 3ms */
if(counter_while_loop > max_value_of_counter_loop) break; /* in case systick jams */
}
was_u1_tx_cplt = false;
return HAL_UART_Transmit_DMA(huart, pData, Size);
}

I call it like this:

uint8_t SendInfoAboutNumberOfStepsMadeByHighPrecisionMotors(uint8_t number_of_axis)
{
int number_of_steps = 0;
uint8_t axis = number_of_axis;

MG_GetNumberOfSteps(axis, &number_of_steps);

Length = sprintf((char*)Message4, "MG%d=%d\n", axis, number_of_steps);
send_status = OwnTransmitDma(&huart1, Message4, Length);

if(send_status != HAL_OK) return RESPONSE_TRY_ERROR;
else return RESPONSE_TRY_OK;
}

 

I set the was_u1_tx_cplt variable in a callback:
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart == &huart1) was_u1_tx_cplt = true;
}


Message4 is a global array located in this file:
uint8_t Message4[16];

Not every message is split, moreover 99% of messages are sent without any problems, but sometimes messages are split into two parts and I don't see the dependency when this happens. I don't use RTOS.
I'm using this DMA only for this UART, but also for TX and RX, at first I thought the RX stream was interrupting the TX stream, but I set the TX stream priority to DMA_PRIORITY_MEDIUM where RX has DMA_PRIORITY_LOW and that didn't help.

UART and DMA configuration:

grados73_0-1695638586953.png

grados73_1-1695638653997.png

Examples of splitting messages:

grados73_2-1695638696291.png

 
 

grados73_5-1695638747552.png

Unfortunately, I have no idea what can cause the fact that the significant majority of messages are sent correctly, but some are sent incorrectly. If you have any ideas, please help me with this issue.
STM32F407VGTx,
STM32CubeIDE Version: 1.13.1

 

 
11 REPLIES 11
grados73
Associate II

Unfortunately, the problem hasn't gone away, but it didn't occur during my tests, so I can't solve it with an oscilloscope or logic analyzer. We think it may be a Windows problem with the handling of messages coming to the computer's COM port. This is now solved using the message joining procedure in the PC application, but this is a temporary solution. Hopefully, during the next tests, we will be able to catch this definitively and make sure that the problem is not on the STM side. By the way, the bug with the wrong place to check if the transmission is finished has been fixed, and I thank you for your help. If something is clarified I will write in the comment thread, maybe it will be useful to someone someday.

The STM32 with DMA to a USART should not have any significant inter-symbol gaps or pauses, the hardware is pretty simple/dumb so it's going to funnel data consistently, the bandwidth of the serial data being such that any contention is not going to be visible as you've got 8-10 bit times of slop.

What's definitely going to be an issue is the synchronization between the sender and the receiver, they are operating in entirely different time domains, so if one is collecting data say every 100ms to process, or busy with other tasks/threads, where a larger transfer might be bisected is anyone's guess. The receiving end will need to reassemble packets, and you'll want a format that's able to self-synchronize, and detect errors and corruption, and be able to recover. Expecting to send/receive a dozen bytes in lock-step, indefinitely is going to break.

DMA has secondary coherency issues that must be considered, caching and scope. The data can't come from local/auto variables as the scope of these generally collapses immediately, and you end up sending whatever's in memory at the time the data bytes are fetched. You can't reuse the buffer whilst it's active. You have to manage that, using TC / HT interrupts, or chain lists of buffers in the interrupt/callback. Don't start new DMA transfers while one is currently active.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..