Possible issue in USARTv1 driver, serve_interrupt() function

ChibiOS public support forum for topics related to the STMicroelectronics STM32 family of micro-controllers.

Moderator: RoccoMarco

Post Reply
gicho
Posts: 16
Joined: Sun Aug 24, 2014 8:44 am

Possible issue in USARTv1 driver, serve_interrupt() function

Post by gicho »

Hi,
while investigating a complex problem I saw that in some cases my threads are stopping without obviuous reason.
If I pause the debugger at that moment, I see that the SW is constantly calling VectorD4(). The vector in its turn calls the serve_interrupt(). This is generally correct, but the value of the status register is 0x98 (152). This means that the overflow flag is set - ok, I am running at 921Kbps with USART interrupt at the highest priority (4).

In fact the problem is that the code in the serve_interrupt() cannot handle this specific case. Stepping inside I saw that it does not enter in any of the If's, even the expected block:

Code: Select all

  /* Data available.*/
  chSysLockFromIsr();
  while (sr & USART_SR_RXNE) {
    /* Error condition detection.*/
    if (sr & (USART_SR_ORE | USART_SR_NE | USART_SR_FE  | USART_SR_PE))
      set_error(sdp, sr);
    sdIncomingDataI(sdp, u->DR);
    sr = u->SR;
  }


I set a breakpoint at the "set_error()" line to verify if it gets called at least once. But the debugger does not stop there at all (even after starting new debug session and observing long period of normal operation of the SW and reaching to the hanging point after that).

I am using F401 and so I checked the reference manual - RM0368, DocID025350 Rev 2. At page 535, point 19.6.1 Status register (USART_SR), I see that there are different sequences to reset (ack) different bits. For ORE bit this is done with sequence of reading of SR then DR. Some other bits are cleared by reading just SR.

I am not sure if the current code is wrong, maybe the used sequence will fit all the possible bits.

But I still face my original problem and I don't see how the serve_interrupt() will handle my case (SR=0x98) to get out of the overrun - and unlock my threads.

I desperately need some advice - I will try to patch the serve_interrupt() to be able to continue my work.

Thanks in advance!
User avatar
Giovanni
Site Admin
Posts: 14892
Joined: Wed May 27, 2009 8:48 am
Has thanked: 1202 times
Been thanked: 996 times

Re: Possible issue in USARTv1 driver, serve_interrupt() func

Post by Giovanni »

Hi,

I will give it a look. It could be helpful to have a simple application showing the problem.

Giovanni
gicho
Posts: 16
Joined: Sun Aug 24, 2014 8:44 am

Re: Possible issue in USARTv1 driver, serve_interrupt() func

Post by gicho »

I cannot simplify it, it hangs only with the complex project when all threads are active. Also, it does not appear instantly, I need to run the device for at least several minutes to get the problem.
Meanwhile I made a "hack" to the serve_interrupt() - it just check if ORE bit is set and makes the "read SR, read DR" sequence to remove it. A breakpoint in the new code proved that sporadically (once in several minutes) my new code triggers. Even better, this (seems to) resolves my threads hanging problem, as expected. I will keep on testing.
User avatar
Giovanni
Site Admin
Posts: 14892
Joined: Wed May 27, 2009 8:48 am
Has thanked: 1202 times
Been thanked: 996 times

Re: Possible issue in USARTv1 driver, serve_interrupt() func

Post by Giovanni »

That ISR has always been problematic, we had several tickets there, probably this is why ST changed the USARTs in newer devices.

About your system, do you have particularly large critical zones?

Giovanni
gicho
Posts: 16
Joined: Sun Aug 24, 2014 8:44 am

Re: Possible issue in USARTv1 driver, serve_interrupt() func

Post by gicho »

I never lock anything in my threads.
I am using period/width callbacks with ICU driver and have some code inside, I know it runs in the interrupt context. But I don't use locking in my code (in the callback).
I had ADC callback too and it was using chSysLockFromIsr()/Unlock() around the call of adcStopConversionI(adcp). This callback was removed several days ago and it is not used anymore.

I made a C/C++ search in my project about chSysLock() calls. The only reference to this function is where I am "purging" the received data over serial like that:

Code: Select all

   
chSysLock();
sdResetI((SerialDriver*)hSerial);
chSysUnlock();
User avatar
Giovanni
Site Admin
Posts: 14892
Joined: Wed May 27, 2009 8:48 am
Has thanked: 1202 times
Been thanked: 996 times

Re: Possible issue in USARTv1 driver, serve_interrupt() func

Post by Giovanni »

That is not a problem, it is very short.

Do you have debug options enabled? assertions, checks, state checker?

Giovanni
gicho
Posts: 16
Joined: Sun Aug 24, 2014 8:44 am

Re: Possible issue in USARTv1 driver, serve_interrupt() func

Post by gicho »

Everything without the debug trace. Yesterday I even enabled it (the debug trace) to check context switches to get a hint if anything runs after overrun error. What I saw is that the buffer pointer is not moving any more after the constant interrupt problem.
User avatar
Giovanni
Site Admin
Posts: 14892
Joined: Wed May 27, 2009 8:48 am
Has thanked: 1202 times
Been thanked: 996 times

Re: Possible issue in USARTv1 driver, serve_interrupt() func

Post by Giovanni »

I can't imagine why it is not getting into the set_error(), I cannot replicate this. Could you try compiling using -O0? it is possible that optimizations hide the execution of that code to the debugger.

Probably the data rate is just too high for a buffered driver, this is why you are getting overruns. You should consider using the UART driver instead, it is unbuffered and uses DMA.

Giovanni
Post Reply