Re: Interrupt driven UART



In article <1161134013.648175.59200@xxxxxxxxxxxxxxxxxxxxxxxxxxxx>,
goister@xxxxxxxxx says...

Mark Borgerson wrote:
In article <1161059360.210871.120550@xxxxxxxxxxxxxxxxxxxxxxxxxxx>,
goister@xxxxxxxxx says...

Mark Borgerson wrote:
In article <1160714459.737590.239920@xxxxxxxxxxxxxxxxxxxxxxxxxxx>,
goister@xxxxxxxxx says...

CBFalconer wrote:
"goister@xxxxxxxxx" wrote:
goister@xxxxxxxxx wrote:

Hmm disregard my previous message. I think I know what you mean. I
think I can implement the fifo with a fixed array size of n, and a head
and tail index rather than pointer(both initialized to 0). The rx isr
will move a byte from the rxbuffer to the fifo head, increment the
head(wrapping back to 0 when head == n) and set the global rx ready
flag, and the receivebyte function will simply wait for the rx ready
flag set by the ISR, then move a byte from the the fifo tail to a local
variable, and increment the tail(wrapping too). Makes sense?

arg, just realized after i hit the "post" button that this might not
work if an rx interrupt occurs between the time the receivebyte
function checks for the rx ready flag, and the time where it clears the
flag. if it happens the be the last byte received in that time period,
then the receivebyte will hang there since it has cleared the flag
while the fifo is still not empty. Instead, I think a better check
would be to compare the head and tail pointers, and if they're not the
same then there's something in the fifo. so the psuedo code looks
something like this

isr() {
fifo[tail++] = rxbuffer;
if (tail == buflen) tail = 0;
}

receivebyte()
while(head == tail);
byte = fifo[head++]
if (head == buflen) head = 0;
return byte;
}

This is probably not good enough, because you need to know both
when the buffer is non-empty and when the buffer is full. The full
condition is used to make a decision on how to proceed when an
interrupt occurs, which may be either to discard the oldest or to
discard the newest, while setting an overrun flag to signify data
lost. With read and write indices into a single buffer you can
decide this with modulo arithmetic, i.e. buffer empty corresponds
to indices equal, and buffer full corresponds to write index one
less than read index. With pointers the modulo arithmetic on the
difference becomes harder.


Hmm, error checking gets complicated though because the receive buffer
is structured as a double buffer. buffer1 gets pumped into buffer2 when
all 8bits are received, and this also generates the interrupt. A buffer
overrun occurs(and appropriate status bit set in status register) when
buffer2 isn't read by the isr before all 8 bits of buffer1 are
received. only buffer2 is accessible.

So there seems to be a couple of errors I have to take care of
1) buffer overrun
2) parity error
3) frame error
4) fifo overrun error

The first 3 I can check by cpu status bits, and the 4th one I can check
by comparing indices, but I'm not sure of the order to check them, how
to organize them, and how to handle them(discarding newest and
requesting for a retransmit?). Here's how I was doing it in my receive
isr:

fifo(tail++) = buffer2;
tail&= buflen - 1;
errFlag = statusregister & mask // check for framing/parity/overrun
error
if (errFlag != 0) { // error
// pulldown I/O line to signal error and request retransmission
}

I'm wondering how the retransmission will occur. Should I have a while
loop that keeps looping within the isr to wait for the retransmission
or should i exit the isr and reenter? And then there's the fifo overrun
error case, not sure how to integrate that in either.


I wouldn't wait inside the interrupt routine for the retransmission.
You don't know how long that will take. It will be at least one
character time, though. You probably don't want to wait in the
interrupt routine that long.


Mark Borgerson

So how about this pseudocode in my ISR then

if (tail+1 == head) { // fifo overflow!
overflow_flag = 1;
// disable UART RX here and handle retransmission
junk = (unsigned char) buffer2; // clears buffer2
// enable RX here
} else { // no fifo overflow!
// check parity error from status reg here
if (parity_error) {
// disable RX here and handle retransmission
junk = (unsigned char) buffer2; // clears buffer2
// enable RX here
} else {
fifo[Tail++] = (unsigned char) buffer2;
Tail &= BUFFLEN - 1; // handles wraparound
}
}

At first glance it looks OK to me. Just remember to decide
whether 'tail' starts with an upper or lower case 'T'! ;-)

The devil will be in the details of "disable RX here and handle
retransmission"

I have also found it instructive to increment an error counter
for each type of error. They can be very handy if you have
to try to diagnose line and communications problems.


Another thing to watch out for is how the UART handles break
signals.

Mark Borgerson

Thanks...

Since I'll be emulating iso7816 over UART, my retransmission handling
will consist of pulling the TX line low for 1 bit period during the 2
stop bits to indicate to the smart card an error and request for a
retransmission.

What do you mean by break signals though?

The BREAK signal is a signal that stays in the start bit state for
several character times. Some systems use it for resynchronizing
or interrupting transmissions. Many standard UARTS will detect this
condition and set a flag in the status register.

Since you had to ask, I assume that you don't have to worry about
it in your system.

Another thing I'm not too sure of - my MCU provides 2 interrupt vectors
for the handling of UARTs - INTTX and INTRX. INTTX occurs when the
buffer has been sent, right after the parity bit, and INTRX occurs when
the buffer has been received, right before the parity bit. There is
also a control register bit that enables or disables receiving. I
didn't see much elaboration on that in the data***, but I'm assuming
that it enables/disables the receiving into the 2 rx buffers of the
MCU. Currently in my sendbyte and receivebyte functions as well as
ISRs, I'm not actually turning the interrupts on and off, i.e. the
interrupts are always enabled. I do however disable the receive bit
when I'm handling retransmission and enable it again afterwards. I
don't suppose this would be a problem right?

That depends on what is happening on the other end of the link. If
it can be sending at any time you are likely to get an error character
if you turn on your receiver when the other end is in the middle
of a transmisssion.

Turning off your transmitter can also be dangerous. You need to
make sure that you don't turn it off until the terminating parity
bit of your last output character is complete.


I would probably leave the transmitter and receiver on all the time.
That way you won't miss characters and you won't mess up your
output.

I must have missed the type of link you are using. Is it only
half-duplex? Can you not have the transmitter and receiver
enabled at the same time?

Mark Borgerson


.


Quantcast