I am using USART1 on STM32L051 with interrupts for serial communication. I start my program by sending 5 bytes from MCU to PC, which works fine, but then a USART interrupt gets triggered with only TXE set whilst TXEIE is disabled (as in picture). Any ideas why would MCU behave like this?
I am disabling TXEIE and TCIE interrupts in code - could this cause some issues?
Thank you
EDIT:
Also even if I delete the line handling interrupt errors, RXNE flag does not trigger USART interrupt as it should.
EDIT2:
This is the CR1 register correponding to the status of ISR register above.
EDIT5: Code. I realized that the previous code was unnecessarily bulky, so I created a new project, where I only use USART1 to send fixed string out and perhaps receive simple string in. The behaviour has not changed. Could someone try the code provided and see if you get the same behaviour?
uart.h:
#ifndef INC_UART_H_
#define INC_UART_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "stm32l0xx_ll_crs.h"
#include "stm32l0xx_ll_rcc.h"
#include "stm32l0xx_ll_bus.h"
#include "stm32l0xx_ll_system.h"
#include "stm32l0xx_ll_exti.h"
#include "stm32l0xx_ll_cortex.h"
#include "stm32l0xx_ll_utils.h"
#include "stm32l0xx_ll_usart.h"
#include "stm32l0xx_ll_gpio.h"
#include <stdlib.h>
#define __USART__ USART1
#define __USART_IRQ__ USART1_IRQn
#define __USART_IRQHandler__ USART1_IRQHandler
/* Macros for USART control */
#define DI_DRE_INT() LL_USART_DisableIT_TXE(__USART__) // disable transmission data register empty interrupt
#define EN_DRE_INT() LL_USART_EnableIT_TXE(__USART__) // enable transmission data register empty interrupt
#define DI_TRD_INT() LL_USART_DisableIT_TC(__USART__) // disable transmission done interrupt
#define EN_TRD_INT() LL_USART_EnableIT_TC(__USART__) // enable transmission done interrupt
#define WR_DATA(data) LL_USART_TransmitData8(__USART__, data)
#define RD_DATA() LL_USART_ReceiveData8(__USART__)
//void MX_USART_Init(void);
void __USART_IRQHandler__(void);
int8_t uart_putstring(volatile uint8_t *data);
uint8_t uart_getstring(uint8_t * string);
uint8_t uart_get_stat();
#ifdef __cplusplus
}
#endif
#endif /* INC_UART_H_ */
uart.c
#include "uart.h"
volatile uint8_t *tx_data = NULL;
volatile uint8_t rx_data[16];
volatile uint8_t rx_elements = 0;
volatile uint8_t rx_string = 0;
static void USART_CharReception_Callback(void);
static void USART_TXEmpty_Callback(void);
static void USART_CharTransmitComplete_Callback(void);
static void Error_Callback(void);
int8_t uart_putstring(volatile uint8_t *data)
{
tx_data = data;
EN_DRE_INT();
return 0;
}
uint8_t uart_get_stat()
{
if(rx_string){
rx_string = 0;
return 1;
}
return 0;
}
uint8_t uart_getstring(uint8_t * string)
{
uint8_t i = 0;
do{
string[i] = rx_data[i];
i++;
rx_elements--;
}while(rx_data[i] != '\n');
return i;
}
/**
* Brief This function handles USARTx Instance interrupt request.
* Param None
* Retval None
*/
void __USART_IRQHandler__(void)
{
/* Check RXNE flag value in ISR register */
if(LL_USART_IsActiveFlag_RXNE(__USART__) && LL_USART_IsEnabledIT_RXNE(__USART__)){
/* RXNE flag will be cleared by reading of RDR register (done in call) */
/* Call function in charge of handling Character reception */
USART_CharReception_Callback();
/* output buffer register empty */
} else if(LL_USART_IsEnabledIT_TXE(__USART__) && LL_USART_IsActiveFlag_TXE(__USART__)){
/* TXE flag will be automatically cleared when writing new data in TDR register */
/* Call function in charge of handling empty DR => will lead to transmission of next character */
USART_TXEmpty_Callback();
/* last byte transmission finished */
} else if(LL_USART_IsEnabledIT_TC(__USART__) && LL_USART_IsActiveFlag_TC(__USART__)){
/* Clear TC flag */
LL_USART_ClearFlag_TC(__USART__);
/* Call function in charge of handling end of transmission of sent character
and prepare next charcater transmission */
LL_USART_DisableIT_TC(__USART__);
return;
} else {
/* Call Error function */
Error_Callback();
}
}
/**
* @brief Function called in case of error detected in USART IT Handler
* @param None
* @retval None
*/
static void Error_Callback(void)
{
__IO uint32_t isr_reg;
/* Disable USARTx_IRQn */
NVIC_DisableIRQ(__USART_IRQ__);
/* Error handling example :
- Read USART ISR register to identify flag that leads to IT raising
- Perform corresponding error handling treatment according to flag
*/
isr_reg = LL_USART_ReadReg(__USART__, ISR);
}
/**
* @brief Function called for achieving next TX Byte sending
* @param None
* @retval None
*/
static void USART_TXEmpty_Callback(void)
{
DI_TRD_INT();
static volatile uint8_t i = 0;
if(tx_data[i] != '\n'){
WR_DATA(tx_data[i]);
i++;
} else {
DI_DRE_INT();
EN_TRD_INT();
i = 0;
WR_DATA('\n');
}
}
static void USART_CharReception_Callback(void)
{
uint8_t trash = 0;
trash = RD_DATA();
if(rx_elements < 16){
rx_data[rx_elements++] = trash;
}
if(trash == '\n'){
rx_string = 1;
}
}
main.c
/* 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"
#include "uart.h"
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_USART1_UART_Init(void);
int main(void)
{
volatile uint8_t msg_out[16];
volatile uint8_t msg_in[16];
msg_out[0] = 'a';
msg_out[1] = 'h';
msg_out[2] = 'o';
msg_out[3] = 'j';
msg_out[4] = '\n';
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_SYSCFG);
LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_PWR);
/* SysTick_IRQn interrupt configuration */
NVIC_SetPriority(SysTick_IRQn, 3);
/* Configure the system clock */
SystemClock_Config();
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_USART1_UART_Init();
uart_putstring(msg_out);
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
if( RX_STRING && uart_get_stat()){
uart_putstring(msg_out);
}
}
}
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
LL_FLASH_SetLatency(LL_FLASH_LATENCY_0);
while(LL_FLASH_GetLatency()!= LL_FLASH_LATENCY_0)
{
}
LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE1);
LL_RCC_MSI_Enable();
/* Wait till MSI is ready */
while(LL_RCC_MSI_IsReady() != 1)
{
}
LL_RCC_MSI_SetRange(LL_RCC_MSIRANGE_5);
LL_RCC_MSI_SetCalibTrimming(0);
LL_RCC_SetAHBPrescaler(LL_RCC_SYSCLK_DIV_1);
LL_RCC_SetAPB1Prescaler(LL_RCC_APB1_DIV_1);
LL_RCC_SetAPB2Prescaler(LL_RCC_APB2_DIV_1);
LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_MSI);
/* Wait till System clock is ready */
while(LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_MSI)
{
}
LL_Init1msTick(2097000);
LL_SetSystemCoreClock(2097000);
LL_RCC_SetUSARTClockSource(LL_RCC_USART1_CLKSOURCE_PCLK2);
}
/**
* @brief USART1 Initialization Function
* @param None
* @retval None
*/
static void MX_USART1_UART_Init(void)
{
/* USER CODE BEGIN USART1_Init 0 */
/* USER CODE END USART1_Init 0 */
LL_USART_InitTypeDef USART_InitStruct = {0};
LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
/* Peripheral clock enable */
LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_USART1);
LL_IOP_GRP1_EnableClock(LL_IOP_GRP1_PERIPH_GPIOA);
/**USART1 GPIO Configuration
PA9 ------> USART1_TX
PA10 ------> USART1_RX
*/
GPIO_InitStruct.Pin = LL_GPIO_PIN_9;
GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
GPIO_InitStruct.Alternate = LL_GPIO_AF_4;
LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_InitStruct.Pin = LL_GPIO_PIN_10;
GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
GPIO_InitStruct.Alternate = LL_GPIO_AF_4;
LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/* USART1 interrupt Init */
NVIC_SetPriority(USART1_IRQn, 0);
NVIC_EnableIRQ(USART1_IRQn);
/* USER CODE BEGIN USART1_Init 1 */
LL_USART_EnableIT_RXNE(__USART__);
/* USER CODE END USART1_Init 1 */
USART_InitStruct.BaudRate = 115200;
USART_InitStruct.DataWidth = LL_USART_DATAWIDTH_8B;
USART_InitStruct.StopBits = LL_USART_STOPBITS_1;
USART_InitStruct.Parity = LL_USART_PARITY_NONE;
USART_InitStruct.TransferDirection = LL_USART_DIRECTION_TX_RX;
USART_InitStruct.HardwareFlowControl = LL_USART_HWCONTROL_NONE;
USART_InitStruct.OverSampling = LL_USART_OVERSAMPLING_16;
LL_USART_Init(USART1, &USART_InitStruct);
LL_USART_ConfigAsyncMode(USART1);
LL_USART_Enable(USART1);
/* USER CODE BEGIN USART1_Init 2 */
/* USER CODE END USART1_Init 2 */
}
/**
* @brief GPIO Initialization Function
* @param None
* @retval None
*/
static void MX_GPIO_Init(void)
{
/* GPIO Ports Clock Enable */
LL_IOP_GRP1_EnableClock(LL_IOP_GRP1_PERIPH_GPIOA);
}
/* 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.
* @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 */
main.h
#ifndef __MAIN_H
#define __MAIN_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "stm32l0xx_ll_crs.h"
#include "stm32l0xx_ll_rcc.h"
#include "stm32l0xx_ll_bus.h"
#include "stm32l0xx_ll_system.h"
#include "stm32l0xx_ll_exti.h"
#include "stm32l0xx_ll_cortex.h"
#include "stm32l0xx_ll_utils.h"
#include "stm32l0xx_ll_pwr.h"
#include "stm32l0xx_ll_dma.h"
#include "stm32l0xx_ll_usart.h"
#include "stm32l0xx_ll_gpio.h"
#if defined(USE_FULL_ASSERT)
#include "stm32_assert.h"
#endif /* USE_FULL_ASSERT */
void Error_Handler(void);
/* USER CODE BEGIN EFP */
/* USER CODE END EFP */
/* Private defines -----------------------------------------------------------*/
#ifndef NVIC_PRIORITYGROUP_0
#define NVIC_PRIORITYGROUP_0 ((uint32_t)0x00000007) /*!< 0 bit for pre-emption priority,
4 bits for subpriority */
#define NVIC_PRIORITYGROUP_1 ((uint32_t)0x00000006) /*!< 1 bit for pre-emption priority,
3 bits for subpriority */
#define NVIC_PRIORITYGROUP_2 ((uint32_t)0x00000005) /*!< 2 bits for pre-emption priority,
2 bits for subpriority */
#define NVIC_PRIORITYGROUP_3 ((uint32_t)0x00000004) /*!< 3 bits for pre-emption priority,
1 bit for subpriority */
#define NVIC_PRIORITYGROUP_4 ((uint32_t)0x00000003) /*!< 4 bits for pre-emption priority,
0 bit for subpriority */
#endif
/* USER CODE BEGIN Private defines */
/* USER CODE END Private defines */
#ifdef __cplusplus
}
#endif
#endif /* __MAIN_H */