Skip to main content
Graduate II
January 24, 2024
Solved

Issue with uart USART_ISR_EOBF bit

  • January 24, 2024
  • 10 replies
  • 4665 views

Hi

 I have a stm32L433, and setup Uart1 for standard TX and RX with interrupt for both send and receive (9600N81 setup). I don't use any hardware handshake . Within the IRQ routine occasionally the USART_ISR_EOBF bit in the ISR is set , and I am not using smartcard mode , and the EOBIE bit is not set in the CR2 register.. I have the below , and even after its cleared it then keeps getting set and cant get any data.

 

void USART1_IRQHandler(void)

{

unsigned char data;

if(USART1->ISR & USART_ISR_FE)

USART1->ICR |= USART_ICR_FECF;

 

if(USART1->ISR & USART_ISR_EOBF)

USART1->ICR |= USART_ICR_EOBCF;

 

if(USART1->ISR & USART_ISR_RXNE) //RX interupt

{

data=USART1->RDR;

...

 

 

Many thanks

Scott

 

    This topic has been closed for replies.
    Best answer by Tesla DeLorean

    Is the RMW to ICR the appropriate approach?

    What else in ISR is set. Show configuration of the USART and the registers when it fails.

    The Noise, Overrun or Framing Errors are more probable.

    10 replies

    Super User
    January 24, 2024

    Use this button to properly post source code:

    AndrewNeil_0-1706116196271.png

     

    To get that extra row of icons, press this button:

    AndrewNeil_1-1706116196288.png

     

     

    Super User
    January 24, 2024

    I would not expect that bit getting set to prevent receiving incoming bytes.  But I have zero experience using smartcard mode.  And, yes, I understand (or presume) that you are not using smartcode mode, just normal UART.  From the code you posted, it looks like it should flow down to the RXNE block whether or not EOBF is set.  Is that happening? 

    Are you using the HAL libraries?  It doesn't look like it from your code above, or at least you are not using HAL code to respond to the interrupt.

    For STM32 code it is good practice when checking interrupt flags to check BOTH the ISR bit AND the IE bit, and only respond if both are set.  Look at the HAL UART IRQ handler for examples (even if you aren't using HAL), in stm32l4xx_hal_uart.c HAL_UART_IRQHandler().

    SSmit.13Author
    Graduate II
    January 24, 2024

    Hi

       Most times it works fine, its the other times the EOBF is set. When its set, it doesnt run down to the RXNE routine.

    You mention "check BOTH the ISR bit AND the IE bit". I check the ISR register as below, whats the IE bit?

     

    Thanks

    Scott

    
    void SetupUart1Port(void)
    {
    	//////////////////////////
    	//setup serial port...
    	//UART 1
    	//PB6-TX PB7-RX
    	GPIOB->MODER &= ~0b1111000000000000; //clear pins PB6 , PB7
    	GPIOB->MODER |= 0b1010000000000000; //alternate function for both pins
    
    	GPIOB->AFR[0] &= ~0xff000000; //mask out
    	GPIOB->AFR[0] |= 0x77000000; //AF7 for both PB6 and PB7
    
    	GPIOB->OSPEEDR &= ~0xf000; //mask out
    	GPIOB->OSPEEDR |= 0xf000; //speed high for PB7 and PB6
    
    	GPIOB->PUPDR &= ~0xf000; //mask out pullup
    	GPIOB->PUPDR |= 0x5000; //pullup
    
    	RCC->APB2ENR |= RCC_APB2ENR_USART1EN; //enable uart 1 clock
    
    	//??RCC->CCIPR &= ~0xc0;//mask out clock
    	RCC->CCIPR &= ~0xf;//mask out clock
    	RCC->CCIPR |= 0x5;//select SYSCLCK
    
    	USART_Init(USART1,BAUD9600);
    	NVIC_SetPriority(USART1_IRQn,1);
    	NVIC_EnableIRQ(USART1_IRQn);
    	USART1->CR1 &= ~USART_CR1_TXEIE; //clear tx interupt com 1
    	USART1->CR1 |= USART_CR1_RXNEIE; //rx interupt com 1
    }
    
    
    void USART_Init(USART_TypeDef *USARTx,int Baud)
    {
    	USARTx->CR1 &= ~USART_CR1_UE; //disable uart
    	USARTx->CR1 &= ~USART_CR1_M0;// 8 bits
    	USARTx->CR1 &= ~USART_CR1_M1;// 8 bits
    	USARTx->CR2 &= ~USART_CR2_STOP;// 1 stop bit
    	USARTx->CR1 &= ~USART_CR1_PCE;// no parity
    	USARTx->CR1 &= ~USART_CR1_OVER8; //oversample
    	USARTx->BRR = Baud; //set baud
    	USARTx->CR1 |= (USART_CR1_TE | USART_CR1_RE); //enable tx and rx
    	USARTx->CR1 |= USART_CR1_UE; //enable uart
    
    	while((USARTx->ISR & USART_ISR_TEACK)==0); //verify uart is ready for transmission
    	while((USARTx->ISR & USART_ISR_REACK)==0); //verify uart is ready for reception
    }
    
    void USART1_IRQHandler(void)
    {
    	unsigned char data;
    
    	if(USART1->ISR & USART_ISR_FE)
    	 USART1->ICR |= USART_ICR_FECF;
    
    	if(USART1->ISR & USART_ISR_EOBF)
     USART1->ICR |= USART_ICR_EOBCF;
    
    	if(USART1->ISR & USART_ISR_RXNE) //RX interupt
    	{
     data=USART1->RDR;
     ......
     }
    }

     

    Super User
    January 29, 2024

    > When its set, it doesnt run down to the RXNE routine.

    The code you posted SHOULD still get to the RXNE test even if EOBF is set.  Are you saying that when EOBF is set RXNE is not?

    > whats the IE bit

    The "interrupt enable" bit in the CR1 register, for example RXNEIE.  You code should only respond to an interrupt if the interrupt/ISR flag is set AND the corresponding IE bit is set.  Normally this is as issue only when enabling and disabling interrupts, as it is possible to enter the IRQ handler after your code has cleared the IE bit (depends on timing or IRQ vs timing of code and instruction pipelining).  This is mostly "good programming practice" but is likely not the issue here.

     

     

    Graduate II
    January 29, 2024

    Is the RMW to ICR the appropriate approach?

    What else in ISR is set. Show configuration of the USART and the registers when it fails.

    The Noise, Overrun or Framing Errors are more probable.

    SSmit.13Author
    Graduate II
    January 30, 2024

    What I have noticed is if I clear the flags before checking the RXNE flag, then the RXNE  gets cleared.  If I put at the end then works as expected. I am thinking I dont even have to check this flag as I dont use this feature.

    void USART1_IRQHandler(void)
    {
    	unsigned char data;
    	if(USART1->ISR & USART_ISR_FE)
    	 USART1->ICR |= USART_ICR_FECF;
    
    	if(USART1->ISR & USART_ISR_EOBF)
    	 USART1->ICR |= USART_ICR_EOBCF; <<this clears the RXNE bit
    
    	if(USART1->ISR & USART_ISR_RXNE) //RX interupt
    	{
    		data=USART1->RDR;
     ...
     }
    }

     

    Below is the snap shot prior to moving the above to the end..

    SSmit13_1-1706615559612.png

     

    Best Regards

    Scott

     

    Super User
    January 30, 2024

    As @Tesla DeLorean said (or strongly hinted at) - do not do a read-modify-write (RMW) to the ICR (oops, I missed that).   And the "|=" operation is a RMW.  Just write the (single) bit for the flag you want to clear. 

    SSmit.13Author
    Graduate II
    January 30, 2024

    I thought the only way is to either do a |= or read in the register then | the bit and write the result back in.  Either way its read in.  If not how would I set the bit without doing the just mentioned?

     

     

    Graduate II
    January 30, 2024

    The important thing to understand is that these aren't "memories", but bits into a state machine or other combinational logic. The Reference Manual will likely explain or indicate expected behaviour. Doing register level coding requires a lot higher level of awareness to what the peripheral designer implemented, and why.

    Writing SET bits can be done with a singular write instruction.

    Using |= or &= can have other side effects if it reads high or low bits. It's also very inefficient.

    The one that most often caused issues was TIM->SR &= ~1; You'd occasionally end up clearing bits you didn't mean too if an interrupt was latched between the read and write operations.

    Doing this is also very inefficient, the optimizer can't fold actions on a "volatile" memory interactions. Your doing a pair of LOAD/STORE operations when you could do it in half of that.

    	GPIOB->AFR[0] &= ~0xff000000; //mask out
    	GPIOB->AFR[0] |= 0x77000000; //AF7 for both PB6 and PB7
    
    	GPIOB->OSPEEDR &= ~0xf000; //mask out
    	GPIOB->OSPEEDR |= 0xf000; //speed high for PB7 and PB6

    Do this

    GPIOB->AFR[0] = (GPIOB->AFR[0] & ~0xff000000) | 0x77000000; //AF7 for both PB6 and PB7

    Super User
    January 30, 2024

    Just write to it.  Only bits that are "1" do anything.

    if(USART1->ISR & USART_ISR_EOBF) {
     USART1->ICR = USART_ICR_EOBCF; // Clear EOBCF and only EOBCF
    }
    SSmit.13Author
    Graduate II
    January 31, 2024

    I never knew this about only 1 bits do anything, I must have missed that.

     

    Thanks for letting me know

    :grinning_face:

    Super User
    February 2, 2024

    Show your current code.

    SSmit.13Author
    Graduate II
    February 2, 2024

    Below is the UART handler. When I placed a beakpoint  on the   USART1->ICR = USART_ICR_EOBCF; line ,the RXNE =1. As soon as I step onto the next instruction  the RXNE bit is cleared.

    void USART1_IRQHandler(void)
    {
    	unsigned char data;
    
    	if(USART1->ISR & USART_ISR_EOBF)
    	 USART1->ICR = USART_ICR_EOBCF; //after stepping pass this the RXNE is cleared
    
    	if(USART1->ISR & USART_ISR_RXNE) //RX interupt
    	{
    		data=USART1->RDR;
    	 ....
     }

    Scott

    Super User
    February 2, 2024

    So change it as following:

    void USART1_IRQHandler(void)
    {
    	unsigned char data;
    	if(USART1->ISR & USART_ISR_RXNE) //RX interupt
    	{
    		data=USART1->RDR;
    	 ....
     }
    	if(USART1->ISR & USART_ISR_EOBF)
    	 USART1->ICR = USART_ICR_EOBCF; // why this at all, in plain UART mode?
    }
    SSmit.13Author
    Graduate II
    February 2, 2024

    I previously done this, but was wanting to check what you previously said about , only a 1 bit effects the bits in the register. I removed the above line , but was curious why the RXNE bit was cleared. Still dont know what single write without a read would work.

    Super User
    February 2, 2024

    Bits in the ICR register are write-only, so there's no sense in reading it anyway. It can read as all 0's or return some random value.

    Super User
    February 3, 2024

    > As soon as I step onto the next instruction the RXNE bit is cleared.

    One possible explanation - if you have the SFR view open to show the UART registers, it re-reads those registers after every step. If the IDE reads/diplays the RDR register, that will clear the RXNE bit.  The IDE should **NOT** automatically read that register for exactly this reason, and I don't think it does.  But I don't recall for sure.  Or - do you by chance have a "watch" set on the RDR?

    > Still dont know what single write without a read would work.

    Look in the ref manual.  The bits in the ICR register are of type "rc_w1", which it says means "Software can read as well as clear this bit by writing 1. Writing 0 has no effect on the bit value."  Not the most clear explanation to me, but it means you can read the register if you want., but you don't have to.  To clear a bit, write a "1" to that bit position.  Writing a "0" to a bit has no effect.  THAT is why writing a single bit works to clear that bit, you are writing 0's to all the other bits.