cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F105R8T HAL Busy and missing data buffers.

AkilaAwantha
Associate II

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

1 ACCEPTED SOLUTION

Accepted Solutions
Karl Yamashita
Lead III

For anyone else wondering about how to create a queue to transmit UART packets I've mentioned above.

  • I'm using a Nucleo-L432KC for this.
  • I've copied some of @AkilaAwantha​ Drive Mode arrays for this demonstration
  • The full project can be found on GitHub

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 */

Tips and Tricks with TimerCallback https://www.youtube.com/@eebykarl
If you find my solution useful, please click the Accept as Solution so others see the solution.

View solution in original post

17 REPLIES 17
S.Ma
Principal

The baudrate is too slow that your messages may take too long. It is luke when your pc get sluggish and hang. Use DMA to send your data and every 50ms, check the job is done. If yes, send the next message. Non blocking and no interrupts.

Your description of the communication method does not overwhelm me with confidence.

Use adequate buffering, be conscious of how quickly, or slowly, data actually moves. At a 50 ms pace you can send less than 20 characters at each interval.

Don't use blocking functions in interrupts or callbacks.​

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

Hey, Thanks for the response. Before doing, it is using HAL_UART_Transmit, I tried DMA method. It didn't work, at least to this level, with DMA. After one or two messages it goes to Busy mode and return back. I used Normal Mode to send pre-defined 10 byte buffers.

Hey Tesla thanks for the reply. I'm a newbie. What are the blocking functions that you have mentioned in your reply. I increased the time duration of the timer interrupt, but it didn't help me either

This is an example buffer that I send to the display. I send many buffers like this within the time. Also, there is a CAN bus connected to the MCU. Which also provide interrupts.

uint8_t Normal[10] = { 0x5A, 0xA5, 0x07, 0x82, 0x00, 0x84, 0x5A, 0x01, 0x01,

      0x44 };

Karl Yamashita
Lead III

You need to post your code so we can see how you're loading the buffers and transmitting the data.

Tips and Tricks with TimerCallback https://www.youtube.com/@eebykarl
If you find my solution useful, please click the Accept as Solution so others see the solution.
S.Ma
Principal

https://github.com/akilawickramasinghe/Vega_ETX_Display_Firmware_V2 Here is my Code. Please don't laugh, :| I'm a newbie

Thanks for the resource. I'll take a look at it.