2020-06-18 02:35 AM
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++;
}
}
Solved! Go to Solution.
2020-06-18 04:17 AM
Using
LL_USART_EnableLIN(USART1);
causes the SBK flag not to be set when interrupts do fire, and causes interrupts to not be continuous.
2020-06-18 03:07 AM
> 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.
2020-06-18 03:37 AM
@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.
2020-06-18 03:49 AM
@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?
2020-06-18 04:16 AM
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.
2020-06-18 04:17 AM
Using
LL_USART_EnableLIN(USART1);
causes the SBK flag not to be set when interrupts do fire, and causes interrupts to not be continuous.
2020-06-18 04:20 AM
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.
2020-06-18 04:27 AM
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.
2020-06-18 05:10 AM
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
2021-02-02 09:54 PM
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