1
\$\begingroup\$

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. enter image description here

EDIT2: This is the CR1 register correponding to the status of ISR register above. enter image description here

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 */
\$\endgroup\$
2
  • \$\begingroup\$ It's a warning sign to me that that microcontroller has two USART peripherals but your ISR doesn't seem to know which one it is attached to. \$\endgroup\$
    – Ben Voigt
    May 30, 2022 at 17:11
  • 1
    \$\begingroup\$ It knows. It is defined in uart.h \$\endgroup\$ May 31, 2022 at 9:27

1 Answer 1

0
\$\begingroup\$

That is normal.

If you don't send anything, the transmit buffer is empty.

If you enable transmit buffer empty interrupts, you will get transmit buffer empty interrupts continuously unless you disable them or transmit data, so transmit buffer becomes empty after transmitting data.

\$\endgroup\$
7
  • \$\begingroup\$ That's the thing. Both TCIE and TXEIE are disabled and there is no data in RX register. According to documentation no IRQ should be triggered in such conditions. Also later no IRQ is triggered even though RXNE == 1 and RXNEIE == 1. \$\endgroup\$ May 30, 2022 at 15:41
  • \$\begingroup\$ So how do you disable the interrupts, and what does the register view shows for interrupt enable bits? \$\endgroup\$
    – Justme
    May 30, 2022 at 15:46
  • \$\begingroup\$ I've added printscreen of CR1 register to my question. I disable interrupts using LL_USART_DisableIT_TXE(__USART__) and LL_USART_DisableIT_TC(__USART__) \$\endgroup\$ May 30, 2022 at 15:52
  • \$\begingroup\$ So how is the USART initialized anyway? \$\endgroup\$
    – Justme
    May 30, 2022 at 16:02
  • \$\begingroup\$ I added Init code into question \$\endgroup\$ May 30, 2022 at 16:16

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.