Page 1 of 1

Possible issue in USARTv1 driver, serve_interrupt() function

Posted: Sat Dec 20, 2014 12:19 am
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!

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

Posted: Sat Dec 20, 2014 8:23 am
by Giovanni
Hi,

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

Giovanni

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

Posted: Sat Dec 20, 2014 1:59 pm
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.

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

Posted: Sat Dec 20, 2014 2:39 pm
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

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

Posted: Sat Dec 20, 2014 3:42 pm
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();

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

Posted: Sat Dec 20, 2014 4:31 pm
by Giovanni
That is not a problem, it is very short.

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

Giovanni

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

Posted: Sat Dec 20, 2014 7:11 pm
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.

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

Posted: Sun Jan 04, 2015 10:46 am
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