cancel
Showing results for 
Search instead for 
Did you mean: 

Serial interrupts call USART1_IRQHandler() continuously, how do I slow or stop them so that the application code can run?

CDew.1
Associate III

Serial port interrupts are firing continuously, so that the application code does not run.

I'm using an STM32H743, on the Nucleo board.

Initially, USART3 worked properly for a few weeks, then failed in this manner. I then moved to USART1, which worked for a few weeks, then also failed like this. The testing was done with RX grounded and TX left unconnected. The same results are obtained if RX is left floating.

The following flags are observed as set on each interrupt:

BUSY, CM, CTS, EOB, IBD, NE, ORE, REACK, RTO, RXFF, SBK, TXFT, WKUP.

I am only looking for RXNE, TC, and TXE. (For receiving bytes and sending bytes.)

What can I do to stop USART1_IRQHandler() being called continuously?

P.S. I configure the port with the (mostly) generated:

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_AHB4_GRP1_EnableClock(LL_AHB4_GRP1_PERIPH_GPIOB);
  /**USART1 GPIO Configuration  
  PB15   ------> USART1_RX
  PB6   ------> USART1_TX 
  */
  GPIO_InitStruct.Pin = LL_GPIO_PIN_15;
  GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
  GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW;
  GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
  GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
  GPIO_InitStruct.Alternate = LL_GPIO_AF_4;
  LL_GPIO_Init(GPIOB, &GPIO_InitStruct);
 
  GPIO_InitStruct.Pin = LL_GPIO_PIN_6;
  GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
  GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW;
  GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
  GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
  GPIO_InitStruct.Alternate = LL_GPIO_AF_7;
  LL_GPIO_Init(GPIOB, &GPIO_InitStruct);
 
  /* USART1 interrupt Init */
  NVIC_SetPriority(USART1_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),0, 0));
  NVIC_EnableIRQ(USART1_IRQn);
 
  /* USER CODE BEGIN USART1_Init 1 */
  //return;
  /* USER CODE END USART1_Init 1 */
  USART_InitStruct.PrescalerValue = LL_USART_PRESCALER_DIV1;
  USART_InitStruct.BaudRate = 115200; //38400;
  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_SetTXFIFOThreshold(USART1, LL_USART_FIFOTHRESHOLD_1_8);
  LL_USART_SetRXFIFOThreshold(USART1, LL_USART_FIFOTHRESHOLD_1_8);
  LL_USART_DisableFIFO(USART1);
  LL_USART_ConfigAsyncMode(USART1);
 
  /* USER CODE BEGIN WKUPType USART1 */
 
  /* USER CODE END WKUPType USART1 */
 
  LL_USART_Enable(USART1);
 
  /* Polling USART1 initialisation */
  while((!(LL_USART_IsActiveFlag_TEACK(USART1))) || (!(LL_USART_IsActiveFlag_REACK(USART1))))
  {
  }
  /* USER CODE BEGIN USART1_Init 2 */
 
  LL_USART_EnableIT_RXNE(USART1);
  /* USER CODE END USART1_Init 2 */
 
}

and I catch the flags with:

/*
 * @brief Should be called only by UART/USARTx_IRQHandler()
 */
void port_irq_handler(struct port *port)
{
	if (LL_USART_IsActiveFlag_ABR(port->usart)) {
		port->stats.abr++;
	}
	if (LL_USART_IsActiveFlag_ABRE(port->usart)) {
		port->stats.abre++;
	}
	if (LL_USART_IsActiveFlag_BUSY(port->usart)) {
		port->stats.busy++;
	}
	if (LL_USART_IsActiveFlag_CM(port->usart)) {
		port->stats.cm++;
	}
	if (LL_USART_IsActiveFlag_CTS(port->usart)) {
		port->stats.cts++;
	}
	if (LL_USART_IsActiveFlag_EOB(port->usart)) {
		port->stats.eob++;
	}
	if (LL_USART_IsActiveFlag_FE(port->usart)) {
		port->stats.fe++;
	}
	if (LL_USART_IsActiveFlag_IDLE(port->usart)) {
		port->stats.idle++;
		LL_USART_ClearFlag_IDLE(port->usart);
	}
	if (LL_USART_IsActiveFlag_LBD(port->usart)) {
		port->stats.lbd++;
	}
	if (LL_USART_IsActiveFlag_NE(port->usart)) {
		port->stats.ne++;
	}
	if (LL_USART_IsActiveFlag_ORE(port->usart)) {
		port->stats.ore++;
	}
	if (LL_USART_IsActiveFlag_PE(port->usart)) {
		port->stats.pe++;
	}
	if (LL_USART_IsActiveFlag_REACK(port->usart)) {
		port->stats.reack++;
	}
	if (LL_USART_IsActiveFlag_RTO(port->usart)) {
		port->stats.rto++;
	}
	if (LL_USART_IsActiveFlag_RWU(port->usart)) {
		port->stats.rwu++;
	}
	if (LL_USART_IsActiveFlag_RXFF(port->usart)) {
		port->stats.rxff++;
	}
	if (LL_USART_IsActiveFlag_RXFT(port->usart)) {
		port->stats.rxft++;
	}
	if (LL_USART_IsActiveFlag_RXNE(port->usart)) {
		port->stats.rxne++;
		uint8_t b = LL_USART_ReceiveData8(port->usart);
		circbuf_push(&port->rxcircbuf, b);
	}
	if (LL_USART_IsActiveFlag_RXNE_RXFNE(port->usart)) {
		port->stats.rxne_rxfne++;
	}
	if (LL_USART_IsActiveFlag_SBK(port->usart)) {
		port->stats.sbk++;
	}
	if (LL_USART_IsEnabledIT_TC(port->usart)) {
		if (LL_USART_IsActiveFlag_TC(port->usart)) {
			port->stats.tc++;
			LL_USART_DisableIT_TC(port->usart);
			port_run(port);
		}
	}
	if (LL_USART_IsActiveFlag_TC(port->usart)) {
		port->stats.tc++;
		if (port->txbusy) {
			port->txbusy = 0;
		} else {
			Error_Handler();
		}
		LL_USART_DisableIT_TC(port->usart);
	}
	if (LL_USART_IsActiveFlag_TCBGT(port->usart)) {
		port->stats.tcbgt++;
	}
	if (LL_USART_IsActiveFlag_TEACK(port->usart)) {
		port->stats.teack++;
	}
	if (LL_USART_IsActiveFlag_TXE(port->usart)) {
		port->stats.txe++;
		if (LL_USART_IsEnabledIT_TXE(port->usart)) {
			LL_USART_DisableIT_TXE(port->usart);
			port_run(port);
		}
	}
	if (LL_USART_IsActiveFlag_TXE_TXFNF(port->usart)) {
		port->stats.txe_txfnf++;
	}
	if (LL_USART_IsActiveFlag_TXFE(port->usart)) {
		port->stats.txfe++;
	}
	if (LL_USART_IsActiveFlag_TXFT(port->usart)) {
		port->stats.txft++;
	}
	if (LL_USART_IsActiveFlag_UDR(port->usart)) {
		port->stats.udr++;
	}
	if (LL_USART_IsActiveFlag_WKUP(port->usart)) {
		port->stats.wkup++;
	}
	if (LL_USART_IsActiveFlag_nCTS(port->usart)) {
		port->stats.ncts++;
	}
}

1 ACCEPTED SOLUTION

Accepted Solutions
CDew.1
Associate III

Using  

LL_USART_EnableLIN(USART1);

causes the SBK flag not to be set when interrupts do fire, and causes interrupts to not be continuous.

View solution in original post

10 REPLIES 10
berendi
Principal

> The testing was done with RX grounded and TX left unconnected. The same results are obtained if RX is left floating.

Yes, both of them will cause error conditions.

> I am only looking for RXNE, TC, and TXE. (For receiving bytes and sending bytes.)

> What can I do to stop USART1_IRQHandler() being called continuously?

Enable only the interrupt requests corresponding to these status bits. See Table 400. USART interrupt requests in the reference manual.

Review the reference manual to see what flag is set on what condition, and how to clear it. Never assume that any HAL or LL function does what you think it should do. Always check the contents of the hardware registers against their descriptions in the reference manual.

Read the status register only once in the interrupt handler for some speed improvement.

CDew.1
Associate III

@berendi​ Thanks for commenting.

Why would a grounded RX cause error conditions? (I can understand a floating value causing random 1s and 0s.)

My signal, when connected, will look like:

1          _____________   ___         _   _______________                 3V3
  ________|             |_|   |_______| |_|               |_______________
0                                                         *                0V
    free     held/idle   S 1 1 0 0 0 0 1 0 S   held/idle        free
 
                               byte 'C'

Byte reading should start on falling edges. A continuous high or low should not be interpreted as data. (The switch from a continuous high to continuous low (*) will cause a transient framing error, as a high stop bit is not present 9.5 bit periods after the falling edge.)

In my test here, RX is just continuously low.

CDew.1
Associate III

@berendi​ 

I just tested it with RX pulled high through 10K, and the errors stop.

So you're right about grounding RX causing errors.

But why does grounding RX cause continuous errors, and how can that be stopped?

berendi
Principal

Because UARTs work that way. Read the USART/UART chapter in the reference manual.

Some flags are really weird, they should not be set at all . Post the contents of the UART registers. Make sure that the interrupt handler is really accessing the UART which it should.

CDew.1
Associate III

Using  

LL_USART_EnableLIN(USART1);

causes the SBK flag not to be set when interrupts do fire, and causes interrupts to not be continuous.

RMcCa
Senior II

Uarts use idle high logic, so grounding rx will cause errors. I get around this in my own code by using a rising edge exti interrupt on the rx pin to enable the uart and disable the exti​. The uart isr then disables the uart and reenables the exti at the end of the message.

berendi
Principal

Post the contents of the UART registers, verify their values against their descriptions in the reference manual. This UART has way too many options to be able to guess its working through barely documented functions that might or might not do what you think they should do.

The usual pitfall with USART in STM32 is, that ORE causes interrupt if RXNEIE is set. In other words, ORE *must* be handled together with RXNE.

JW

JChrist
Associate III

I'm using a STM32F446 and recently upgraded firmware from 1.24 to 1.25 and noticed that all my GPIO_InitStruct.Pull changed from LL_GPIO_PULL_UP to LL_GPIO_PULL_NO.

This is causing all kinds of havoc if I leave them this way as well as if I set them all back to LL_GPIO_PULL_UP. As of right now I've selectively turned on pullup's for Rx lines and I've calmed the issues but I not feeling very warm an fuzzy about V1.25 firmware.

Jacob