2020-05-10 12:30 PM
Hi
I am a beginner and I am studding STM32F448 with a nucleo board. Program used "System Workbench for STM32". My problem is quite ***** and I hope that someone can help me.
That program allow to the the user to send a string and the cpu, when receive the character "\n", send back the string. so if I send "Home\n", the cpu should send me back the same string.
What is happening is that at the first connection sending "Home\n", I receive "ome\n" where "H" is replaced with a null character (0x00). After this first communication, all is fine: i receive what i send. it seems like that i loose the first byte.
Thanks a lot in advance
2020-05-10 12:32 PM
After UART2_Init(), but before you use the UART, insert a delay of 1 character in length. HAL_Delay(1) will do.
Your TX line is probably low initially and the receiving end doesn't know how to handle the sudden change high then low again.
2023-06-30 05:48 AM
Hello,
For me, something similar to what my colleague says is happening, but a little bit different
I'm describing the project I'm doing to see if I can solve it.
I am using the USART1 configured as LIN mode with the following parameters:
/* USER CODE BEGIN USART1_Init 1 */
/* USER CODE END USART1_Init 1 */
huart1.Instance = USART1;
huart1.Init.BaudRate = 19200;
huart1.Init.WordLength = UART_WORDLENGTH_8B;
huart1.Init.StopBits = UART_STOPBITS_1;
huart1.Init.Parity = UART_PARITY_NONE;
huart1.Init.Mode = UART_MODE_TX_RX;
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart1.Init.OverSampling = UART_OVERSAMPLING_16;
if (HAL_LIN_Init(&huart1, UART_LINBREAKDETECTLENGTH_10B) != HAL_OK)
{
Error_Handler();
}
In the picture "linrequest and linresponse" you can see on channel 3 sending the LIN break+ sync+protectedID signal and on the channel 1 signal you can see the response of the LIN slave DATA(8 bytes)+ CHK.
The code I have implemented asks the slave if it is on the bus and if it is on the bus it sends me back information.
2023-06-30 02:08 PM - edited 2023-06-30 02:13 PM
You have to stay consistent when you call HAL_UART_Receive_IT. The first call uses data_buffer so on the first interrupt you receive the first character at index 0 but you replace it with rx_data. However rx_data is zero . Then you call HAL_UART_Receive_IT again but now point to rx_data. So now receiving works correctly, at least on the first message. You don't reset your "count" so now you're going to be transmitting previous messages as well.
You are using a blocking code when transmitting which you should never use in an interrupt. Set a flag instead and then transmit. You need to learn how to use the HAL status to your advantage so you can make sure your rx interrupt is always working and to make sure you did transmit.
Below is a working example on a Nucleo-G431KB
/*
* PollingRoutine.c
*
* Created on: Jun 30, 2023
* Author: karl.yama**bleep**a
*/
#include "main.h"
#include "PollingRoutine.h"
extern UART_HandleTypeDef huart2;
typedef struct
{
uint8_t rx[1]; // for rx only
uint8_t data_buffer[100];
uint32_t size;
uint32_t ptr;
bool ready;
bool recIntError;
}UartDataStruct;
char *user_data = "The application is running\r";
UartDataStruct rxData = {0};
UartDataStruct txData = {0};
// called before main while loop
void PollingInit(void)
{
uint16_t len_of_data = strlen(user_data);
HAL_UART_Transmit(&huart2,(uint8_t*)user_data, len_of_data, 100);
UART_EnableReceive(); // init enabling of rx interrupt
}
// called from main while loop
void PollingRoutine(void)
{
UART_ErrorStatus();
UART_RxDataReady();
UART_TxDataReady();
}
// check rx error status, try and enable rx interrupt again
void UART_ErrorStatus(void)
{
if(rxData.recIntError)
{
rxData.recIntError = false;
UART_EnableReceive();
}
}
// enable rx interrupt
void UART_EnableReceive(void)
{
if(HAL_UART_Receive_IT(&huart2, rxData.rx, 1) != HAL_OK)
{
rxData.recIntError = true;
}
}
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(rxData.rx[0] == '\r')
{
rxData.data_buffer[rxData.ptr] = '\r';
rxData.size = rxData.ptr + 1; // save the size
rxData.ptr = 0; // reset pointer
rxData.ready = true;
}
else
{
rxData.data_buffer[rxData.ptr] = rxData.rx[0];
rxData.ptr++;
}
UART_EnableReceive();
}
// if rx data available, copy to tx and set tx ready flag
void UART_RxDataReady(void)
{
if(rxData.ready)
{
rxData.ready = false; // reset
memcpy(&txData.data_buffer, rxData.data_buffer, rxData.size); // copy rx to tx buffer
txData.size = rxData.size;
txData.ready = true; // set tx data is ready to send
}
}
// if tx data available, transmit it and clear flag only if HAL_OK. If not then it'll retry to send again until successful.
void UART_TxDataReady(void)
{
if(txData.ready)
{
if(HAL_UART_Transmit_IT(&huart2, txData.data_buffer, txData.size) == HAL_OK)
{
txData.ready = false;
}
}
}
2023-07-10 04:28 AM
I had the similar effect on the STM32L4+. The first byte received via interrupt was always 0. I think this is related to the "double buffering". So on the first IRQ you need to read the buffer "manually" again.
Something like this
if (__HAL_UART_GET_FLAG(&huart1, UART_FLAG_RXNE)) {
if ((bytesRcvd1 == 0) && (serRxBuffer[0] == 0)) { // if this is first byte
HAL_UART_Receive(&huart1, &serRxBuffer[0],1,1); // READ again
}
else {
if (serRxBuffer[bytesRcvd1] == (uint8_t)'\r') { // return received?
// reset the bytes counter
bytesRcvd1 = 0;
// indicate line reception complete here
}
}
bytesRcvd1++; // increase number of bytes received
HAL_UART_Receive_IT(&huart1, &serRxBuffer[bytesRcvd1], 1);
}