2021-01-07 08:03 AM
I'm using the HAL_UART_Transmit_IT procedure on a STM32G431 for the LPUART on a 115200 baud communication to a Putty terminal. The MCU is also running ST Motor code.
I have some simple 3 character commands that either set variables in the code or read back variables. The communication is fairly robust when the motor is not running but is very bad when it is running.
The interface code reads a single character at a time in the callback HAL_UART_RxCpltCallback and puts it in a Rxbuffer. If the character is invalid the buffer is cleared. If a CR is received the command is processed and data is transmitted back to Putty using the HAL_UART_Transmit_IT procedure. I can break on the code just prior to transmitting the message and the data is correct but when the HAL_UART_Transmit_IT is executed the data coming back is very corrupted.
This is the callback:
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
uint8_t Rx_Char;
uint8_t tmp;
tmp = LPUART1_rxBuffer[0]; // uart receives 1 byte
rx_buffer[Rx_Byte] = tmp;
Rx_Char = tmp;
Rx_Byte++; // # of accumulated bytes received for current command
if ( (Rx_Char == ESC) || (Rx_Byte > Nbytes)) // clear command state machine immediately
{
Rx_Byte = 0;
}
else if (Rx_Char == CR) // go process command
{
Rx_Byte = 0;
processUserCmnd();
}
else if ( Rx_Char == 0x7F ) // handle backspace
{
Rx_Byte--;
Rx_Byte--;
rx_buffer[Rx_Byte] = 0;
}
HAL_UART_Receive_IT( &hlpuart1, LPUART1_rxBuffer, 1 ); // ready next byte
}
The processUserCommand decodes the command in the rxBuffer and executes the command. As example, after decoding 'SPD' it will send back the motor speed.
case 7: /* SPD, read speed */
/* speed in #SPEED_UNIT's, _001HZ */
speed = MC_GetMecSpeedAverageMotor1();
sendSPEED(speed);
break;
void sendSPEED(int16_t spd)
{
// send speed in units of 0.001Hz mechanical
if( spd > 32767 ) spd = 32767;
// HZ_001 from ST is 0.01Hz
spd = (spd << 3) + (spd << 1); // 10x
char msg[15];
sprintf(msg, "speed %5u \n", spd); // convert int16_t to ascii, legal itoa
char v = CR;
strncat(msg, &v, 1);
HAL_UART_Transmit_IT(&hlpuart1, (uint8_t *) msg, 14);
// --- done
}
What will happen when at break at line 13 above the value of 'msg' is okay but executing HAL_UART_Transmit_IT, the data received by Putty is bad. Again, this is much worse when the code is running the motor and also, I tried 9600 baud and that was bad as well.
I know I must be missing something basic... ? Please offer some advice,
Solved! Go to Solution.
2021-01-07 09:59 AM
{
static char msg[16]; // persistent
HAL_UART_Transmit_IT(&hlpuart1, (uint8_t *)msg, sprintf(msg, "speed %5u \n", spd));
}
2021-01-07 08:10 AM
Note from author, the setSPEED is multiplying the speed by 10x. This is wrong and I removed it. Presently lines 4,5 & 6 are deleted. I may typical see spd equal to 3318 which is 33.18Hz, but Putty prints garbage. I have another command, 'PNG' which send back 'STM32' just to see if the link is alive and that too will print garbage if the motor is running.
2021-01-07 08:39 AM
Could that be noise on the UART lines from the running motor?
For ruling that out, you could setup a larger rx DMA buffer, do a HAL_UART_Receive_DMA, send some commands and inspect the buffer in the debugger.
A potential issue with the code is, that you are not always listening. Do you have the FIFOs enabled? Interrupt priorities? The IMHO best way of receiving is setting up a circular DMA buffer as a giant FIFO and read from that ring buffer in some background loop, see https://stm32f4-discovery.net/2017/07/stm32-tutorial-efficiently-receive-uart-data-using-dma/
2021-01-07 08:54 AM
msg[] doesn't have persistent scope, you should buffer data
You should perhaps also watch that your callback can complete within a single byte time, and that you don't repetitively call HAL_UART_TX/RX_IT() functions without consideration as to whether a prior request is still pending.
The callback occurs under interrupt context, and will block it's own and other interrupts
2021-01-07 09:20 AM
I looked at the Tx/Rx lines with a scope. They are very clean with no noticeable noise at all.
My interrupt priorities are:
Timebase system tick 4 SUB 0
ADC1 and ADC2 2 SUB 0
TIM1 BRK 4 SUB 1
TIM1 update 4 sub 1
TIM4 global 5 SUB 0
LPUART1 4 SUB 1
====================================
I am typing in characters by hand very slowly, as example 'P', 'N', 'G' then waiting .... then '\r'. Instead of receiving back STM32\r, I get STX#*#
2021-01-07 09:30 AM
See my above response. I can type in single characters at say one per second then wait and type \r. With the motor off an input of PNG gets a response STM32. With the motor on it is STX#*# as example. If other interrupts occur during the time HAL_UART_Transmit_IT is sending data will this corrupt the transfer? For the motor control the ADC's and TIM1 have higher priority.
2021-01-07 09:54 AM
msg[] doesn't have persistent scope
2021-01-07 09:59 AM
{
static char msg[16]; // persistent
HAL_UART_Transmit_IT(&hlpuart1, (uint8_t *)msg, sprintf(msg, "speed %5u \n", spd));
}
2021-01-07 10:01 AM
i.e. HAL_UART_Transmit_IT and hence sendSPEED return before the msg buffer is sent. msg is a local variable, allocated on stack, stack is feed on return. In a "quiet" setting, the content of msg may survive. But, in a "busy" setting, the stack space will be re-used, overwriting msg. Try
static char msg[15];
That's what Einstein said.
2021-01-07 10:21 AM
[SOLVED] Thank you both! That was it. I declared msg at the global scope and the code now works fine with or without the motor running. I will change to static at the local level.