Skip to main content
Explorer
November 22, 2023
Solved

Weird behavior of HAL_UARTEx_RxEventCallback()

  • November 22, 2023
  • 2 replies
  • 5391 views

Hi all,

I setup DMA normal mode, on RS485 port where I receive more or less 1 byte per second.
Also, I have DMA normal mode on a debug serial port.

I want to send back on rs485 the characters I receive on that port.
What I observe is that if I add the following printf(), that redirects output to debug UART, in HAL_UARTEx_RxEventCallback()
printf( "errCode=%i\r\n", retCode );
everyting works fine, with TeraTerm software, I can see the characters I input in RS485 window displayed correctly.
BUT, if I remove the printf(), when I press keys in rs485 window the cursor only moves one space to the right not showing any character.
Also, if I set a breakpoint at the begiining of HAL_UARTEx_RxEventCallback(), it only gets called once on the first character I type in rs485 putty window and the sending back of the character received is ok, but then on subsequent pressing of keys HAL_UARTEx_RxEventCallback() is never called and nothing is shown in TeraTerm window.

I'm using STM32G070RBTx, STM32CubeIDE v. 1.13.2, I can't figure out what is going on, please help.

 

 

 

 

 

/* USER CODE BEGIN Header */
/**
 ******************************************************************************
 * @file : main.c
 * @brief : Main program body
 ******************************************************************************
 * @attention
 *
 * Copyright (c) 2023 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 */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "adc.h"
#include "crc.h"
#include "dma.h"
#include "tim.h"
#include "usart.h"
#include "gpio.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include <stdio.h>
#include <string.h>
#include "Serials.h"
#include "SerialDebug.h"
#include "AGC.h"
#include "RingBuffer.h"


/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */

/**************************************
 * Global variables *
 **************************************/

/* The device number id */
uint8_t deviceNumber = 0;

/* The array of ADC1 channels converted values */
uint16_t ADC1Values[ADC1_NUMBER_OF_CHANNELS];

/* The error code from parse operation */
ParseErrorCode_t parseResult;
/* The command received via debug serial port */
ParsedCommand_t cmd;

/* Serial port inbound ring buffer */
RingBuffer_t debugSerialInboundBuffer;
/* Serial port outbound ring bufer */
RingBuffer_t debugSerialOutboundBuffer;

/* Debug serial port inbound data buffer for inbound RingBuffer */
unsigned char * debugSerialInboundData[debugSerialInboundBufferSize];
/* Debug serial port outbound data buffer for outbound ringbuffer */
unsigned char * debugSerialOutboundData[debugSerialOutboundBufferSize];
/* Debug serial port inbound data buffer entry */
unsigned char debugSerialInboundEntry[debugSerialInboundBufferEntrySize];
/* Debug serial port outbound data buffer entry */
unsigned char debugSerialOutboundEntry[debugSerialOutboundBufferEntrySize];

/* Inbound buffer lost messages count */
int debugSerialInboundLostMessagesCount = 0;
/* Outbound buffer lost messages count */
int debugSerialOutboundLostMessagesCount = 0;

extern uint8_t UART2_charRxBuffer;

/* ADC1 converted values */
uint16_t ADC1Values[ADC1_NUMBER_OF_CHANNELS];

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */


#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)


/**
 * @brief Retargets the C library printf function to the USART.
 * None
 * @retval None
 */
PUTCHAR_PROTOTYPE
{
 /* Place your implementation of fputc here */
 /* e.g. write a character to the USART1 and Loop until the end of transmission */
 HAL_UART_Transmit(&huart2, (uint8_t *)&ch, 1, 0xFFFF);

 return ch;
}



/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
const uint8_t rs485SerialInboundBufferEntrySize = 255;

/* RS485 serial port inbound data buffer entry */
//unsigned char rs485SerialInboundEntry[rs485SerialInboundBufferEntrySize];

extern DMA_HandleTypeDef hdma_usart1_rx;

#define rs485SerialInboundBufferEntrySize 255
unsigned char rs485SerialInboundEntry[rs485SerialInboundBufferEntrySize];

/* USER CODE END 0 */

/**
 * @brief The application entry point.
 * @retval int
 */
int main(void)
{
 /* USER CODE BEGIN 1 */
 int returnCode = 0;
 /* Initialize debug serial inbound buffer */
 ringBufferInit( &debugSerialInboundBuffer, debugSerialInboundData, debugSerialInboundBufferSize );
 /* Initialize debug serial outbound buffer */
 ringBufferInit( &debugSerialOutboundBuffer, debugSerialOutboundData, debugSerialOutboundBufferSize );

 /* 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_DMA_Init();
 MX_USART2_UART_Init();
 MX_TIM6_Init();
 MX_ADC1_Init();
 MX_TIM14_Init();
 MX_USART1_UART_Init();
 MX_CRC_Init();
 MX_TIM3_Init();
 /* USER CODE BEGIN 2 */

 extern DMA_HandleTypeDef hdma_usart2_rx;

 /* Start conversion of ADC1 channels values in DMA mode */
 HAL_ADC_Start_DMA( &hadc1, (uint32_t *)ADC1Values, ADC1_NUMBER_OF_CHANNELS );
 /* Start reception of characters from debug serial port in DMA mode */
 HAL_UART_Receive_DMA( &huart2, &UART2_charRxBuffer, 1 );

 /* Disable the half transfer complete of data in DMA interrupt mode */
 __HAL_DMA_DISABLE_IT(&hdma_usart2_rx, DMA_IT_HT);
 /* Enable the transfer complete of data in DMA interrupt mode */
 __HAL_DMA_ENABLE_IT(&hdma_usart2_rx, DMA_IT_TC);

 HAL_UARTEx_ReceiveToIdle_DMA( &huart1, rs485SerialInboundEntry, rs485SerialInboundBufferEntrySize );
 /* Disable the half transfer complete of data in DMA interrupt mode */
 __HAL_DMA_DISABLE_IT(&hdma_usart1_rx, DMA_IT_HT);
 /* Enable the transfer complete of data in DMA interrupt mode */
 __HAL_DMA_ENABLE_IT(&hdma_usart1_rx, DMA_IT_TC);



 HAL_TIM_Base_Start_IT(&htim6);
 HAL_TIM_Base_Start_IT(&htim3);
 HAL_TIM_IC_Start_IT(&htim3, TIM_CHANNEL_1);
 HAL_TIM_IC_Start_IT(&htim3, TIM_CHANNEL_2);

 HAL_TIM_PWM_Start(&htim14, TIM_CHANNEL_1);
 HAL_TIM_Base_Start(&htim14);

 HAL_UART_MspInit(&huart1);
 HAL_UART_MspInit(&huart2);

 __HAL_RCC_CRC_CLK_ENABLE();

 /* USER CODE END 2 */

 /* Infinite loop */
 /* USER CODE BEGIN WHILE */

 while (1) {

 /* Manage incoming message on the RS485 serial port */


 	/* Manage outcoming message on the RS485 serial port */



 /* Manage incoming message on the debug serial port */
 	if ( !ringBufferRead( &debugSerialInboundBuffer, debugSerialInboundEntry ) )
 	{
 /* Parse the user command */
 parseResult = parseDebugCommand( debugSerialInboundEntry, &cmd ); // check return code

 /* Execute user command */
 executeDebugCommand( &cmd );
 	}

 	/* Manage outcoming message on the debug serial port */

 	if ( !ringBufferRead( &debugSerialOutboundBuffer, debugSerialOutboundEntry ) )
 	{
 /* Wait for previous transmission to complete */
 while ( __HAL_UART_GET_FLAG(&huart2, UART_FLAG_TC) != SET ) {};
 /* Send outbound message */
 HAL_UART_Transmit_DMA( &huart2, debugSerialOutboundEntry, (uint16_t)strlen( (char *)debugSerialOutboundEntry ) );
 	}

 /* USER CODE END WHILE */

 /* USER CODE BEGIN 3 */
	}
 /* USER CODE END 3 */
}

void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
	int retCode = 0;

	if (huart->Instance == USART1)
	{
		while ( __HAL_UART_GET_FLAG(&huart1, UART_FLAG_TC) != SET ) {};

 /* Pull DE high to enable TX operation */
 HAL_GPIO_WritePin (USART1_DE_GPIO_Port, USART1_DE_Pin, GPIO_PIN_SET);

 sprintf( &rs485SerialInboundEntry[Size], "\r\n\0" );

		 retCode = HAL_UART_Transmit_DMA(&huart1, rs485SerialInboundEntry, strlen( rs485SerialInboundEntry ) );
		 printf( "errCode=%i\r\n", retCode );

 /* Pull DE low to enable RX operation */
 HAL_GPIO_WritePin (USART1_DE_GPIO_Port, USART1_DE_Pin, GPIO_PIN_RESET);

 retCode = HAL_UARTEx_ReceiveToIdle_DMA( &huart1, rs485SerialInboundEntry, rs485SerialInboundBufferEntrySize );

		 /* Disable the half transfer complete of data in DMA interrupt mode */
		 __HAL_DMA_DISABLE_IT(&hdma_usart1_rx, DMA_IT_HT);
		 /* Enable the transfer complete of data in DMA interrupt mode */
		 __HAL_DMA_ENABLE_IT(&hdma_usart1_rx, DMA_IT_TC);

	}
}
/**
 * @brief System Clock Configuration
 * @retval None
 */
void SystemClock_Config(void)
{
 RCC_OscInitTypeDef RCC_OscInitStruct = {0};
 RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

 /** Configure the main internal regulator output voltage
 */
 HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1);

 /** Initializes the RCC Oscillators according to the specified parameters
 * in the RCC_OscInitTypeDef structure.
 */
 RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
 RCC_OscInitStruct.HSIState = RCC_HSI_ON;
 RCC_OscInitStruct.HSIDiv = RCC_HSI_DIV1;
 RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
 RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
 RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
 RCC_OscInitStruct.PLL.PLLM = RCC_PLLM_DIV1;
 RCC_OscInitStruct.PLL.PLLN = 8;
 RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
 RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;
 if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
 {
 Error_Handler();
 }

 /** Initializes the CPU, AHB and APB buses clocks
 */
 RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
 |RCC_CLOCKTYPE_PCLK1;
 RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
 RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
 RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;

 if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
 {
 Error_Handler();
 }
}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

/**
 * @brief This function is executed in case of error occurrence.
 * @retval None
 */
void Error_Handler(void)
{
 /* USER CODE BEGIN Error_Handler_Debug */
	/* User can add his own implementation to report the HAL error return state */
	__disable_irq();
	while (1) {
	}
 /* USER CODE END Error_Handler_Debug */
}

#ifdef USE_FULL_ASSERT
/**
 * @brief Reports the name of the source file and the source line number
 * where the assert_param error has occurred.
 * file: pointer to the source file name
 * line: assert_param error line source number
 * @retval None
 */
void assert_failed(uint8_t *file, uint32_t line)
{
 /* USER CODE BEGIN 6 */
	/* User can add his own implementation to report the file name and line number,
 ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
 /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

 

 

 

 

 

    This topic has been closed for replies.
    Best answer by Beppe101

    This is how i solved it:

    - Added in HAL_UARTEx_RxEventCallback()

    while ( __HAL_UART_GET_FLAG(&huart1, UART_FLAG_TC) != SET ) {};

    to wait transmission completion before setting and resetting the DE pin.

    - Enabled DMA recepion with HAL_UARTEx_ReceiveToIdle_DMA() after resetting the DE pin. ( DMA is in normal mode ).

    - Do not use the same data buffer for HAL_UARTEx_ReceiveToIdle_DMA() and HAL_UART_Transmit_DMA().

    And now works great.

    Thanks TDK for encouragement.

    2 replies

    Super User
    November 22, 2023

    Using blocking functions (HAL_UART_Transmit, via printf) inside HAL_UARTEx_RxEventCallback, particular before you restart the reception again, could be causing overflow events which will stop UART from working until you clear those errors.

    Beppe101AuthorAnswer
    Explorer
    November 24, 2023

    This is how i solved it:

    - Added in HAL_UARTEx_RxEventCallback()

    while ( __HAL_UART_GET_FLAG(&huart1, UART_FLAG_TC) != SET ) {};

    to wait transmission completion before setting and resetting the DE pin.

    - Enabled DMA recepion with HAL_UARTEx_ReceiveToIdle_DMA() after resetting the DE pin. ( DMA is in normal mode ).

    - Do not use the same data buffer for HAL_UARTEx_ReceiveToIdle_DMA() and HAL_UART_Transmit_DMA().

    And now works great.

    Thanks TDK for encouragement.