3
\$\begingroup\$

I receive data on the UART, using an 8-bit atmega, usually around 5 bytes connected, then a long pause. The total time for one byte (with start+stop bits, I don't use parity) is 160 us. However, the receive interrupt is triggered 60 to 100 us after the stop bit, and nearly half the time it does not trigger at all! (checked with scope)

There were some quite long interrupts, so I blamed them, but after disabling every interrupt besides the UART, the situation remains the same. The UART interrupts finishes in under 10 us (typically 7us) all the time. The signal strength is OK, it's 5V, just as the supply voltage.

First, after realizing that a lot of bytes were lost, I was thinking that the signal frequency was the cause, but I double checked it: the baud rate is perfect, the signal quality looks good, the baud rate error is close to zero. If that was the problem, I would get some lost interrupts (because some bits were lost) but the rest should happen at the proper time, shouldn't it? In my case the interrupt comes very late, if at all, and even when in comes, sometimes it contains rubbish. The signal on the pin is OK, I can read and evaluate it correctly on the scope.

I searched for the typical latency of the UART interrupt, but could not find anything. I strongly suspect that a wild variation between 60 and 100 us should not be normal.

\$\endgroup\$
8
  • \$\begingroup\$ Can you post your code? \$\endgroup\$
    – Oli Glaser
    Jul 16, 2012 at 11:51
  • \$\begingroup\$ @OliGlaser: I doubt posting 3000 lines of code could be of any help. If you are interested in the settings, the clock is 10MHz, UCSR0A=0x01; UCSR0B=0xDC; UCSR0C=0x06; UBRR0H=0x00; UBRR0L=0x09; and I read UDR0 in the interrupt. \$\endgroup\$
    – vsz
    Jul 16, 2012 at 12:02
  • \$\begingroup\$ Yes, please don't post the code! :-) \$\endgroup\$
    – stevenvh
    Jul 16, 2012 at 12:09
  • 1
    \$\begingroup\$ I wasn't thinking of the whole code, just the interrupt, and any other relevant bits. The problem is likely to be with the code, and if so can't be found without looking at it. Simplifying the whole thing (or make a test program) would help find the cause. \$\endgroup\$
    – Oli Glaser
    Jul 16, 2012 at 12:29
  • \$\begingroup\$ Is this some sort of eval board? Do you have a logic level translator in line between your atmega and PC? What line of code are you setting your breakpoint on, is the compiler optimizing it cleverly? Could also be a baud rate issue. Try going the opposite way and sending characters from the atmega to the PC and see if they are received correctly. \$\endgroup\$
    – Joel B
    Jul 16, 2012 at 13:19

4 Answers 4

3
\$\begingroup\$

I'm assuming that you're using the same debugging process I would do in this case -- one of the first instructions in the interrupt routine turns on a LED, and one of the last instructions in the interrupt routine turns that LED off.

Then you used a dual-trace oscilloscope with one probe clipped to the appropriate pin to watch the bytes going into the UART, and the other probe clipped to the pin driving the LED.

I'm assuming your UART-handler interrupt routine ends with the return-from-interrupt instruction (rather than using the return-from-subroutine instruction used by normal instructions).

There are 4 things that can cause a long latency between the end of the last byte of a message and the start of the UART handler:

  • Some previous byte in the message triggering the UART handler, and somehow it takes a long time before interrupts are re-enabled. Some people structure their interrupt routines so that after the UART handler finishes storing a byte in the appropriate buffer, it checks a bunch of other stuff before executing the return-from-interrupt instruction -- it increases jitter and latency, but sometimes those people do it anyway because it improves throughput.

  • Some other interrupt taking a long time to execute before it re-enables the interrupts by executing the return-from-interrupt instruction. (If you can make each and every interrupt turn on and off some other LED, it's pretty easy to see on the o'scope if this is the problem or to rule this out).

  • Some non-interrupt code "temporarily" turning off interrupts. (This increases jitter and latency, but people do it anyway, because it's often the easiest way to prevent data corruption when both some interrupt and some main-loop background task both work with the same piece of data). (If you can make every bit of code that does this turn on and off some other LED, it's pretty easy to see on the o'scope if this is the problem or to rule this out).

  • Instructions that take a long time to execute.

The traditional way to figure out exactly what is causing the problem is to save the current version of your code (you're using TortoiseHg or some other version control system, right?), and then deliberately hack and slash at a temporary copy of your code, stubbing out and completely removing code a few subroutines at a time, re-testing after each round of deletions, until you have a tiny -- yet technically "complete" and runnable -- program that exhibits the same problem.

Far too often people show us bits and pieces of a complete program -- the parts those people think are relevant -- and we can't help them because one of the pieces they omitted is causing the problem.

The process of reducing a program to a small test case is a very useful skill, because often while going through that process, you quickly discover what the real problem is.

Once you have such a tiny -- yet runnable -- program, please post it here. If you figure out what the problem is during that process, please tell us that as well, so the rest of us can avoid that problem.

\$\endgroup\$
0
\$\begingroup\$

Generally UART's with non-real-time code are unreliable. Meaning if you have re-entrant sub routines and indeterminate code execution lengths, can you guarantee the firmware will respond in time to a non-maskable interrupt? But you did disable all of them, so does the IRQ- duration meet the minimum worst case time requirements?

If this becomes a difficult issue, you may need to use buffer data with 16 level deep UARTs and buffer over-run and under run detection and use a polling strategy for data to detect if data is received in buffer. My 1st UART design in 1976 had this problem at first. Then I went to DMA design with polled response less than buffer length with FIFO near full permitting an interrupt.

\$\endgroup\$
0
\$\begingroup\$

You say the baud rate is correct, but I work it out as 62500bps (160us / 10 bits = 16us per bit). This seems a little strange for a serial connection, and an incorrect baud rate would cause similar problems to what you see. That is, the UART may well be interrupting on what it thinks is the stop bit, but which is actually part of the next octet. Naturally, the data will appear corrupt, too :)

When you receive data, can you also read the error flags from the UART? That will tell you why the UART doesn't like the data.

\$\endgroup\$
0
\$\begingroup\$

I'm not familiar with the ATMega, but some controllers use edge-triggered rather than level-sensitive interrupts; on such controllers, an interrupt service routine must check, before it exits, whether all of its associated causes are "satisfied"; if any are not, the routine must loop back and handle them rather than exiting. If an interrupt routine exits without having simultaneously satisfied all of its causes, the interrupt may end up being disabled unless or until some other code causes all of the interrupt's causes to be satisfied.

For example, if a controller uses the same interrupt service routine to handle a UART's incoming and outgoing data, and the service routine starts by handling incoming data and then processing outgoing data. If a byte of incoming data arrives just before the interrupt service routine feeds a byte of outgoing data to the UART, it's possible that the interrupt controller would see a steady level on the interrupt signal from the UART. Before the outgoing byte is loaded, it would want to interrupt because it needed outgoing data. By the time it was loaded, the UART would want to interrupt because it had incoming data. From the point of view of the interrupt controller, however, it would appear that the UART's interrupt service routine was simply ineffective at resolving the interrupt condition, and consequently no further interrupts would be handled for the UART unless or until both the transmit-ready and receive-ready conditions were simultaneously satisfied.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.