2022-11-28 03:13 PM
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
* @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 */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include <stdio.h>
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* 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 ---------------------------------------------------------*/
UART_HandleTypeDef huart2;
/* USER CODE BEGIN PV */
//initialize the menu message
char welcome_message[] = "\r\nHELLO AND WELCOME TO STM32 TYPE YOUR COMMAND\r\n1)Togggles LED1\r\n2)Button status\r\n3)Initial menu\n\r";
//initialize flag for checking if there are data to send or receive data via UART
short int volatile tx_flag = 0;
short int volatile rx_flag = 1;
//initialize a variable for the button status
short int volatile is_button_press = 0;
//variable to store received data
uint8_t rx_message[1];
char tx_message[100];
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_USART2_UART_Init(void);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
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 */
HAL_UART_Transmit(&huart2,(uint8_t*)welcome_message,sizeof(welcome_message),10); //tx initial menu
while (1)
{
if(rx_flag == 1){
HAL_UART_Receive_IT(&huart2,rx_message,sizeof(rx_message));
}
if(tx_flag == 1 && rx_flag == 0){
HAL_UART_Transmit_IT(&huart2,(uint8_t*)tx_message,sizeof(tx_message));
}
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
/**
* @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_RCC_PWR_CLK_ENABLE();
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE2);
/** 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.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
RCC_OscInitStruct.PLL.PLLM = 16;
RCC_OscInitStruct.PLL.PLLN = 336;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV4;
RCC_OscInitStruct.PLL.PLLQ = 7;
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_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
{
Error_Handler();
}
}
/**
* @brief USART2 Initialization Function
* @param None
* @retval None
*/
static void MX_USART2_UART_Init(void)
{
/* USER CODE BEGIN USART2_Init 0 */
/* USER CODE END USART2_Init 0 */
/* USER CODE BEGIN USART2_Init 1 */
/* USER CODE END USART2_Init 1 */
huart2.Instance = USART2;
huart2.Init.BaudRate = 115200;
huart2.Init.WordLength = UART_WORDLENGTH_8B;
huart2.Init.StopBits = UART_STOPBITS_1;
huart2.Init.Parity = UART_PARITY_NONE;
huart2.Init.Mode = UART_MODE_TX_RX;
huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart2.Init.OverSampling = UART_OVERSAMPLING_16;
if (HAL_UART_Init(&huart2) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN USART2_Init 2 */
/* USER CODE END USART2_Init 2 */
}
/**
* @brief GPIO Initialization Function
* @param None
* @retval None
*/
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOH_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, GPIO_PIN_RESET);
/*Configure GPIO pin : B1_Pin */
GPIO_InitStruct.Pin = B1_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING_FALLING;
GPIO_InitStruct.Pull = GPIO_PULLDOWN;
HAL_GPIO_Init(B1_GPIO_Port, &GPIO_InitStruct);
/*Configure GPIO pin : LD2_Pin */
GPIO_InitStruct.Pin = LD2_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(LD2_GPIO_Port, &GPIO_InitStruct);
/* EXTI interrupt init*/
HAL_NVIC_SetPriority(EXTI15_10_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(EXTI15_10_IRQn);
}
/* USER CODE BEGIN 4 */
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart){
//if a message has been send set in rx mode
rx_flag = 1;
tx_flag = 0;
}
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart){
uint8_t error_message[] = "\r\nincorrect command\r\n";
//check if command are correct and prepare the message to send
if(rx_message[0] == '1'){
HAL_GPIO_TogglePin(LD2_GPIO_Port,LD2_Pin);
} else if(rx_message[0] == '2'){
//set tx flag on
tx_flag = 1;
//set rx flag off
rx_flag = 0;
//check button status and save it in char to send it
if(is_button_press == 1){
sprintf(tx_message,"\r\nPRESS\r\n");
} else if(is_button_press == 0){
sprintf(tx_message,"\r\nNOT PRESS\r\n");
}
} else if(rx_message[0] == '3'){
//set tx flag on
tx_flag = 1;
//set rx flag off
rx_flag = 0;
//prepare the message to be send
sprintf(tx_message,"%s",welcome_message);
} else {
//incorrect command was receive
HAL_UART_Transmit(&huart2,error_message,sizeof(error_message),10);
}
}
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin){
//set button status
is_button_press = !is_button_press;
}
/* 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.
* @param file: pointer to the source file name
* @param 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 */
The code is working, but I don't understand why sometimes the serial terminal show me twice.
As shown "NOT PRESS" is printed twice.
2022-11-28 03:18 PM
>>I don't understand why sometimes the serial terminal show me twice.
Because you're in a tight loop, and send things based on a flag you don't clear immediately.
2022-11-28 03:25 PM
Sorry I am new in stm32 programming. I think that too but I've add in the Uart callback functions some lines that clear the flags(rx_flag and tx_flag). If I've understand correctly after the transmissions of the data, first the callback function is execute, and then the infinity loop starts again. Is this correct?
2022-11-28 03:32 PM
while(1)
{
if(tx_flag == 1 && rx_flag == 0){
HAL_UART_Transmit_IT(&huart2,(uint8_t*)tx_message,sizeof(tx_message)); // Called repetitively, returns immediately
}
}
while(1)
{
...
if(tx_flag == 1 && rx_flag == 0){
tx_flag = 2; // stop repeatedly transmitting, clear in call back on COMPLETION
HAL_UART_Transmit_IT(&huart2,(uint8_t*)tx_message,sizeof(tx_message)); // Returns immediately
}
}
Stuff in the foreground is running continuously. The callbacks occur after something completes, not immediate before it starts.
RX likely needs some work on the logic too.
2022-11-28 03:36 PM
Also use strlen(), not sizeof() for some string of unpredictable length. Otherwise you'll seen the whole content of the buffer.
2022-11-28 03:46 PM
Sorry I bore you but I am not understanding. HAL_UART_Transmit_IT() is only use to start the trasmission and return immediately? Then when the transmission end the callback function is execute is this correct? This mean that the UART communication is only start in the while loop and then executed in background?
2022-11-28 04:05 PM
HAL_UART_Transmit_IT() starts a process by which each character is transmitted and generates an interrupt, when all the characters have been sent the interrupt routine calls your callback function.
HAL_UART_Transmit() would be a blocking function, it does not return until completion.
2022-11-28 05:12 PM
You should try to minimize doing any processing in the interrupt. You don't have much code so it's not going to take up many cycles, but you should poll you data in main loop instead. I've added/modified your code so you can see how I handle HAL status. It complains the text is too large so I've removed sections after main
Things I've noticed
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
* @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 */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include <stdio.h>
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* 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 ---------------------------------------------------------*/
UART_HandleTypeDef huart2;
/* USER CODE BEGIN PV */
//initialize the menu message
char welcome_message[] = "\r\nHELLO AND WELCOME TO STM32 TYPE YOUR COMMAND\r\n1)Togggles LED1\r\n2)Button status\r\n3)Initial menu\n\r";
//initialize flag for checking if there are data to send or receive data via UART
short int volatile tx_flag = 0;
short int volatile rx_flag = 1;
//initialize a variable for the button status
short int volatile is_button_press = 0;
//variable to store received data
uint8_t rx_message[1];
char tx_message[100];
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_USART2_UART_Init(void);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
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 */
EnableUART_Interrupt();
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
UART_UpdateTx(welcome_message);
while (1)
{
CheckErrorFlag();
UART_CheckData();
UART_SendData();
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
bool UART_DataAvail = false;
bool UART_RxEnErrorFlag = false;
void UART_CheckData(void)
{
uint8_t error_message[] = "\r\nincorrect command\r\n";
if(UART_DataAvail)
{
UART_DataAvail = false;
//check if command are correct and prepare the message to send
if(rx_message[0] == '1'){
HAL_GPIO_TogglePin(LD2_GPIO_Port,LD2_Pin);
} else if(rx_message[0] == '2'){
//check button status and save it in char to send it
if(is_button_press == 1){
UART_UpdateTx("\r\nPRESS\r\n");
} else if(is_button_press == 0){
UART_UpdateTx("\r\nNOT PRESS\r\n");
}
} else if(rx_message[0] == '3'){
//prepare the message to be send
UART_UpdateTx(welcome_message);
//set tx flag on
} else {
//incorrect command was receive
UART_UpdateTx(error_message);
}
}
}
void UART_SendData(void)
{
if(tx_flag == 1){
if(HAL_UART_Transmit_IT(&huart2,(uint8_t*)tx_message,sizeof(tx_message)) == HAL_OK)
{
tx_flag = 0;
}
}
}
void UART_UpdateTx(char *data)
{
strcpy(tx_message, data);
tx_flag = 1;
}
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart){
UART_DataAvail = true;
EnableUART_Interrupt();
}
void EnableUART_Interrupt(void)
{
if(HAL_UART_Receive_IT(&huart2,rx_message,sizeof(rx_message)) != HAL_OK)
{
UART_RxEnErrorFlag = true;
}
}
bool GetUartEnErrorFlag(void)
{
return UART_RxEnErrorFlag;
}
void ClearUartEnErrorFlag(void)
{
UART_RxEnErrorFlag = false;
}
void CheckErrorFlag(void)
{
if(GetUartEnErrorFlag())
{
ClearUartEnErrorFlag();
EnableUART_Interrupt();
}
}
2022-11-28 11:08 PM
Thank you for your code! But it's not clear to me why in my code I am not cleaning the flag. I try to explain. When I enter in the loop for the transmission, first it start the HAL_TRASMIT_IT(), after this instruction then the interrupt start and there the flag are cleared. Why is it not correct?
2022-11-29 12:17 AM
It was already explained by @Community member by his code that i'm quoting below.
You need to clear your tx_flag or change it to something other than 1 once you test for it and before you start HAL_UART_Transmit_IT. However if the HAL status returns HAL_BUSY then whatever you're trying to transmit will fail so that is why you need to act upon the HAL status. What I posted will work but I should have added my ring buffer code because the tx_message can be overwritten by new data if you receive some new data before the transmit finishes.
while(1)
{
...
if(tx_flag == 1 && rx_flag == 0){
tx_flag = 2; // stop repeatedly transmitting, clear in call back on COMPLETION
HAL_UART_Transmit_IT(&huart2,(uint8_t*)tx_message,sizeof(tx_message)); // Returns immediately
}
}