2024-04-11 07:39 PM - edited 2024-04-11 07:51 PM
Hi Community,
I'm using the STM32U5A9-DK development board and trying to get the UART messages to show up on the screen.
Using osMessageQueue to pass messages between the main and the Model.
But I'm experiencing the problem described in this post , and I've found that the breakpoints don't work in the callback function.
I'm not sure if the message is being put into the queue correctly.
Has anyone else experienced a similar problem or know how to solve it?
This is my code:
Default Task:
void StartDefaultTask(void *argument)
{
/* USER CODE BEGIN defaultTask */
extern UART_HandleTypeDef huart1;
extern char RxData[256]; // received data from UART
HAL_UART_Transmit(&huart1, "UART1 ready...\n", 15, 0xffff);
char cmd[42] = "send_string \"Hello\"\n"
"\n";
HAL_UART_Transmit(&huart1, cmd, sizeof(cmd), 0xffff);
HAL_Delay(50);
/* Infinite loop */
for(;;)
{
HAL_UARTEx_ReceiveToIdle_IT(&huart1, RxData, 256);
osDelay(1);
}
/* USER CODE END defaultTask */
}
Callback function:
extern osMessageQueueId_t uartQueueHandle;
char RxData[256]; // received data from UART
char DataBuffer[256]; // store full message
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
memcpy(DataBuffer, RxData, Size+1);
HAL_UART_Transmit(&huart1, (uint8_t *)DataBuffer, Size, 0xffff);
if (osMessageQueueGetSpace(uartQueueHandle)>0)
{
osMessageQueuePut(uartQueueHandle, DataBuffer, 0 ,0);
}
HAL_Delay(100);
}
Model.c
#include <gui/model/Model.hpp>
#include <gui/model/ModelListener.hpp>
#include "cmsis_os2.h"
#include <cstring>
#include <stm32u5xx.h>
extern osMessageQueueId_t uartQueueHandle;
Model::Model() : modelListener(0)
{
}
char string[256];
char RData[256];
extern UART_HandleTypeDef huart1;
void Model::tick()
{
if(osMessageQueueGet(uartQueueHandle, &string, 0, 0xffff) == osOK)
{
strncpy(RData, string, sizeof(string));
modelListener -> uart_Data(RData);
}
}
2024-04-12 12:41 AM - edited 2024-04-12 12:55 AM
You're not using HAL_UARTEx_ReceiveToIdle_IT correctly. You just need to initiate once before the for loop and within the callback
void StartDefaultTask(void *argument)
{
/* USER CODE BEGIN defaultTask */
extern UART_HandleTypeDef huart1;
extern char RxData[256]; // received data from UART
HAL_UARTEx_ReceiveToIdle_IT(&huart1, RxData, 256);
HAL_UART_Transmit_IT(&huart1, "UART1 ready...\n", strlen("UART1 ready...\n"));
char cmd[42] = "send_string \"Hello\"\n" // start and end quote but missing semicolon?
"\n"; // what is this?
HAL_UART_Transmit_IT(&huart1, cmd, strlen(cmd)); // use interrupt and strlen
HAL_Delay(50);
/* Infinite loop */
for(;;)
{
osDelay(1);
}
/* USER CODE END defaultTask */
}
Don't use HAL_UART_Transmit inside of an interrupt because it is blocking. Use HAL_UART_Transmit_IT instead. Also, you should just set a flag when you get a callback. Then check the flag and do your memcpy and osMessageQueuePut in the StartDefaultTask for loop
extern osMessageQueueId_t uartQueueHandle;
char RxData[256]; // received data from UART
char DataBuffer[256]; // store full message
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
memcpy(DataBuffer, RxData, Size+1);
HAL_UART_Transmit_IT(&huart1, (uint8_t *)DataBuffer, Size);
if (osMessageQueueGetSpace(uartQueueHandle)>0)
{
osMessageQueuePut(uartQueueHandle, DataBuffer, 0 ,0);
}
//HAL_Delay(100); // why delay? not needed.
HAL_UARTEx_ReceiveToIdle_IT(&huart1, RxData, 256); // enable interrupt again
}
2024-04-13 03:45 AM
@Karl Yamashita Thank you for such a clear reply!!!
Although the same problem still exists after the modification, I understand that there was a problem with the call sequence in the previous code.
However, I don't understand why I need to set a flag in the call back?
2024-04-13 06:19 AM
For best practice you want to exit the interrupt quickly. Because you're copying data and transmitting, you could potentially miss more incoming data, and any other interrupts won't trigger, unless you adjust those interrupts as higher priority.
Also i just noticed that you have two HAL_UART_Transmit_IT back to back, so your second transmit may not get sent because the first one is still in the process of sending. So you can either go back to using HAL_UART_Transmit or you can learn to use a ring buffer and queue your messages for transmit.
So i just looked at your other thread. You should follow this example https://www.keil.com/pack/doc/CMSIS/RTOS2/html/group__CMSIS__RTOS__Message.html#gaa515fc8b956f721a8f72b2c505813bfc
And for the queue you would set it up like this
Hope that helps.