2022-12-16 01:10 AM
I'm using STM32F105R8T to send serial buffer commands to an HMI display.MAX485 chip was used for communication. There are pre-defined command buffers and updatable data buffers. Those buffers are sent through a RS485 bus at the baud rate of 9600. There are lots of commands that I should send to operate the display. I'm using 50ms time interrupt for data transmission. MCU doesn't output correct buffers when there is large amount of data, and it causes to error in the display.
When I check HAL_UART_Transmit function, It begins busy sometimes, and it doesn't want to transmit data. What are the solutions that I can get to drive this display smoothly.
Thanks
Here's my Code
https://github.com/akilawickramasinghe/Vega_ETX_Display_Firmware_V2
Solved! Go to Solution.
2022-12-17 08:54 AM
https://github.com/akilawickramasinghe/Vega_ETX_Display_Firmware_V2 Here is my Code.
2022-12-17 03:24 PM
Some things I've noticed.
2022-12-17 06:39 PM
Thank you very much for your support. I'll try this way and let you know the result
2022-12-17 10:43 PM
For anyone else wondering about how to create a queue to transmit UART packets I've mentioned above.
PollingRoutine.c
/*
* PollingRoutine.c
*
* Created on: Dec 17, 2022
* Author: codek
*/
#include "main.h"
#include "PollingRoutine.h"
extern UART_HandleTypeDef huart2;
UART_QueueStruct txMsg = {0};
uint32_t someState;
//Drive Mode
uint8_t EcoON[8] = { 0x5A, 0xA5, 0x05, 0x82, 0x10, 0x55, 0x01, 0xBA };
uint8_t NormalON[8] = { 0x5A, 0xA5, 0x05, 0x82, 0x10, 0x55, 0x01, 0xBC };
uint8_t SportON[8] = { 0x5A, 0xA5, 0x05, 0x82, 0x10, 0x55, 0x01, 0xBE };
uint8_t modeClear[8] = { 0x5A, 0xA5, 0x05, 0x82, 0x10, 0x55, 0x00, 0x00 };
// is called before main while loop
void PollingInit(void)
{
someState = 1; // send EconON
}
// main while loop
void PollingRoutine(void)
{
SomeTask();
UART_SendMessage();
}
// basic example of how to save data to txMsgQueue queue buffer
void SomeTask(void)
{
int status = 0;
switch(someState)
{
case 1:
status= SaveToUART_TxBuffer(EcoON, sizeof(EcoON));
break;
case 2:
status = SaveToUART_TxBuffer(NormalON, sizeof(NormalON));
break;
case 3:
status = SaveToUART_TxBuffer(SportON, sizeof(SportON));
break;
case 4:
status = SaveToUART_TxBuffer(modeClear, sizeof(modeClear));
break;
}
if(status != 0)
{
// buffer is full. Use some notification so user is aware and can increase UART_TX_QUEUE_SIZE
}
someState = 0;
}
int SaveToUART_TxBuffer(uint8_t *data, uint32_t dataSize)
{
if(txMsg.RING_BUFF.ptr.iCnt_OverFlow)
{
return 1; // Overflow. Increase UART_TX_QUEUE_SIZE
}
memcpy(&txMsg.QUEUE.msg[txMsg.RING_BUFF.ptr.iIndexIN].data, data, dataSize);
txMsg.QUEUE.msg[txMsg.RING_BUFF.ptr.iIndexIN].dataSize = dataSize;
DRV_RingBuffPtr__Input(&txMsg.RING_BUFF.ptr, UART_TX_QUEUE_SIZE);
return 0; // no error
}
void UART_SendMessage(void)
{
if(txMsg.RING_BUFF.ptr.iCnt_Handle)
{
if(HAL_UART_Transmit_IT(&huart2, txMsg.QUEUE.msg[txMsg.RING_BUFF.ptr.iIndexOUT].data, txMsg.QUEUE.msg[txMsg.RING_BUFF.ptr.iIndexOUT].dataSize) == HAL_OK)
{
// transmit is good, increment queue pointer to next available message
DRV_RingBuffPtr__Output(&txMsg.RING_BUFF.ptr, UART_TX_QUEUE_SIZE);
}
}
}
PollingRoutine.h
/*
* PollingRoutine.h
*
* Created on: Dec 17, 2022
* Author: codek
*/
#ifndef INC_POLLINGROUTINE_H_
#define INC_POLLINGROUTINE_H_
#define UART_TX_DATA_SIZE 8
#define UART_TX_QUEUE_SIZE 4
typedef struct
{
uint8_t uartPort;
uint8_t data[UART_TX_DATA_SIZE];
uint8_t dataSize;
}UART_Data;
typedef struct
{
struct
{
UART_Data msg[UART_TX_QUEUE_SIZE];
}QUEUE;
struct
{
RING_BUFF_INFO ptr;
}RING_BUFF;
}UART_QueueStruct;
void PollingInit(void);
void PollingRoutine(void);
void SomeTask(void);
int SaveToUART_TxBuffer(uint8_t *data, uint32_t dataSize);
void UART_SendMessage(void);
#endif /* INC_POLLINGROUTINE_H_ */
RingBuff.c
/*
* RingBuff.c
*
* Created on: Sep 18, 2019
* Author: Karl
*
*
*/
#include "main.h"
#include "ringBuff.h"
/*
typedef struct {
uint16_t iIndexIN; // change all these if need more than 16bits.
uint16_t iIndexOUT;
uint16_t iCnt_Handle;
uint16_t iCnt_OverFlow;
}RING_BUFF_INFO;
*/
//==========================================================
// Layer : DRIVER
//==========================================================
void DRV_RingBuffPtr__Clean(RING_BUFF_INFO *ptr) {
ptr->iIndexIN = 0;
ptr->iIndexOUT = 0;
ptr->iCnt_Handle = 0;
ptr->iCnt_OverFlow = 0;
}
void DRV_RingBuffPtr__Input(RING_BUFF_INFO *ptr, unsigned int iBufferSize) {
ptr->iIndexIN++;
if (ptr->iIndexIN >= iBufferSize)
ptr->iIndexIN = 0;
ptr->iCnt_Handle++;
if (ptr->iIndexIN == ptr->iIndexOUT) {
ptr->iCnt_OverFlow++;
if (ptr->iCnt_OverFlow > 50000)
ptr->iCnt_OverFlow = 0;
if (ptr->iIndexIN == 0) {
ptr->iIndexOUT = iBufferSize - 1;
} else {
ptr->iIndexOUT = ptr->iIndexIN - 1;
}
ptr->iCnt_Handle = 1;
}
}
void DRV_RingBuffPtr__Output(RING_BUFF_INFO *ptr, unsigned int iBufferSize) {
if (ptr->iCnt_Handle) {
ptr->iIndexOUT++;
if (ptr->iIndexOUT >= iBufferSize)
ptr->iIndexOUT = 0;
ptr->iCnt_Handle--;
}
}
void DRV_RingBuffPtr__Output_JumpToNew(RING_BUFF_INFO *ptr, unsigned int iBufferSize) {
if (ptr->iCnt_Handle > 1) {
while (ptr->iCnt_Handle > 1) {
ptr->iIndexOUT++;
if (ptr->iIndexOUT >= iBufferSize)
ptr->iIndexOUT = 0;
ptr->iCnt_Handle--;
}
} else {
ptr->iIndexOUT++;
if (ptr->iIndexOUT >= iBufferSize)
ptr->iIndexOUT = 0;
ptr->iCnt_Handle--;
}
}
RingBuff.h
#ifndef RINGBUFF_H
#define RINGBUFF_H
#include "main.h"
#include <stdint.h>
typedef struct {
uint16_t iIndexIN; // change all these if need more than 16bits.
uint16_t iIndexOUT;
uint16_t iCnt_Handle;
uint16_t iCnt_OverFlow;
}RING_BUFF_INFO;
//================================================
// FUNCTION
//================================================
void DRV_RingBuffPtr__Clean(RING_BUFF_INFO *ptr);
void DRV_RingBuffPtr__Input(RING_BUFF_INFO *ptr, unsigned int iBufferSize);
void DRV_RingBuffPtr__Output(RING_BUFF_INFO *ptr, unsigned int iBufferSize);
void DRV_RingBuffPtr__Output_JumpToNew(RING_BUFF_INFO *ptr, unsigned int iBufferSize);
#endif // RINGBUFF_H
main.c
// only showing main function to see how I'm calling PollingInit and PollingRoutine function
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_USART2_UART_Init();
/* USER CODE BEGIN 2 */
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
PollingInit();
while (1)
{
PollingRoutine();
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
main.h
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.h
* @brief : Header for main.c file.
* This file contains the common defines of the application.
******************************************************************************
* @attention
*
* Copyright (c) 2022 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __MAIN_H
#define __MAIN_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "stm32l4xx_hal.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "stdlib.h"
#include "stdint.h"
#include "stdbool.h"
#include "stdio.h"
#include "string.h"
#include "RingBuff.h"
#include "PollingRoutine.h"
/* USER CODE END Includes */
/* Exported types ------------------------------------------------------------*/
/* USER CODE BEGIN ET */
/* USER CODE END ET */
/* Exported constants --------------------------------------------------------*/
/* USER CODE BEGIN EC */
/* USER CODE END EC */
/* Exported macro ------------------------------------------------------------*/
/* USER CODE BEGIN EM */
/* USER CODE END EM */
/* Exported functions prototypes ---------------------------------------------*/
void Error_Handler(void);
/* USER CODE BEGIN EFP */
/* USER CODE END EFP */
/* Private defines -----------------------------------------------------------*/
#define MCO_Pin GPIO_PIN_0
#define MCO_GPIO_Port GPIOA
#define VCP_TX_Pin GPIO_PIN_2
#define VCP_TX_GPIO_Port GPIOA
#define SWDIO_Pin GPIO_PIN_13
#define SWDIO_GPIO_Port GPIOA
#define SWCLK_Pin GPIO_PIN_14
#define SWCLK_GPIO_Port GPIOA
#define VCP_RX_Pin GPIO_PIN_15
#define VCP_RX_GPIO_Port GPIOA
#define LD3_Pin GPIO_PIN_3
#define LD3_GPIO_Port GPIOB
/* USER CODE BEGIN Private defines */
/* USER CODE END Private defines */
#ifdef __cplusplus
}
#endif
#endif /* __MAIN_H */
2022-12-18 06:35 AM
Thank you for the reply. This answer is much appreciated. I'll try this one and let know everyone what is the status of the project
2022-12-19 08:37 PM
I tested the code. It works like a charm. Thank you very much for your help. I'm currently using the baud rate of 9600. I'm planning to increase it to 115200. Furthermore, I need HMI display configuration files to do that. The Chinese manufacturer still unable to provide that. Because of that reason, I increased the queue size. I'll let know everyone what going on with it. Thanks Everyone.
2022-12-19 08:38 PM
Thanks Everyone who helped me to solve this issue. I marked the best answer.
2022-12-19 10:26 PM
You're very welcome! I'm glad it worked out and that I was able to help.
If only ST could update their example code so it's not just calling Error_Handler(). In actuality if it doesn't return HAL_OK, then it just returns HAL_BUSY. ST should show how to retransmit the data again and pretty much 99% of these UART issues people post will go away.
Also ST only shows 1 array for transmitting data. The problem with that is if data is still in the process of being transmitted, new data could be copied to the array which messes up the current data. Having a queue for several messages eliminates that issue.