Forums

Interrupt driven UART

Started by gois...@gmail.com October 12, 2006

On Oct 12, 9:09=A0am, "gois...@gmail.com" <gois...@gmail.com> wrote:
> Ico wrote: > > gois...@gmail.com <gois...@gmail.com> wrote: > > > Hi, > > > I'm working with a Toshiba TMP91 series MCU that doesn't seem to have > > > any UART control/status bits to check for empty data register, rx/tx > > > ready, etc, but does have interrupt vectors for serial tx and rx, whi=
ch
> > > is why I think I have to use interrupt driven UART rather than polling > > > it. > > > > I have functions that expect to receive and send a single byte by > > > calling receivebyte and sendbyte functions. However, since it's > > > interrupt based, receivebyte seems to be pretty redundant. What I have > > > now is a UART receive ISR that first does error checking, then copies > > > the rx buffer to a global rx byte variable, and setting a global > > > rx_ready flag to 1. Then my receivebyte function does nothing until t=
he
> > > rx ready flag is set, after which it just clears it. Does this make > > > sense? > > > This might work, but imagine what would happen if a byte is received on=
the
> > uart while your code happens to be doing something else then calling the > > uart_receive function ? =A0Instead of having only one 'global rx variab=
le',
> > consider using a ringbuffer aka 'circular buffer' aka fifo for this. Th=
e RX
> > interrupt stores incoming bytes into the buffer and updates the head an=
d tail
> > pointers, while your uart_receive function reads one byte from the buff=
er, or -
> > if the buffer is empty - waits until new data comes available.Thanks. I=
hadn't thought of that case since I'm only running the UART
> at 9600bps, but I guess better safe than sorry. To implement the fifo, > wouldn't I need to either make a linked list and malloc/free in the > ISR, or use a fixed array but with compression? Either way it seems > like a lot of clock cycles will be taken up in the ISR trying to manage > the FIFO, and I'm concerned with the timing of things due to these > clock cycles used.- Hide quoted text -- Show quoted text -
Ico is right thats the way to do it. Email me and I'll send you some code to show you how.
Mark Borgerson wrote:
> In article <1160642892.522507.50970@c28g2000cwb.googlegroups.com>, > goister@gmail.com says... > > > > Ico wrote: > > > goister@gmail.com <goister@gmail.com> wrote: > > > > Hi, > > > > I'm working with a Toshiba TMP91 series MCU that doesn't seem to have > > > > any UART control/status bits to check for empty data register, rx/tx > > > > ready, etc, but does have interrupt vectors for serial tx and rx, which > > > > is why I think I have to use interrupt driven UART rather than polling > > > > it. > > > > > > > > I have functions that expect to receive and send a single byte by > > > > calling receivebyte and sendbyte functions. However, since it's > > > > interrupt based, receivebyte seems to be pretty redundant. What I have > > > > now is a UART receive ISR that first does error checking, then copies > > > > the rx buffer to a global rx byte variable, and setting a global > > > > rx_ready flag to 1. Then my receivebyte function does nothing until the > > > > rx ready flag is set, after which it just clears it. Does this make > > > > sense? > > > > > > This might work, but imagine what would happen if a byte is received on the > > > uart while your code happens to be doing something else then calling the > > > uart_receive function ? Instead of having only one 'global rx variable', > > > consider using a ringbuffer aka 'circular buffer' aka fifo for this. The RX > > > interrupt stores incoming bytes into the buffer and updates the head and tail > > > pointers, while your uart_receive function reads one byte from the buffer, or - > > > if the buffer is empty - waits until new data comes available. > > > > > > > > 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? > > > > > That's the general scheme. There are a few details to consider: > > 1. why not keep a counter of the bytes in the queue rather than > a simple flag. That way, if your main application goes away > for a long time, it can note that there are many byte in the > buffer, rather than just an indication that one or more > bytes are available. > > 2. You may need to keep track of the possibility of queue > overflow. > > 3. An oft-used trick for circular buffers is to make the > buffer length an exact power of two. Then you can > skip the wraparound test and simply mask the index with > an appropriate value to accomplish the wraparound. > > #define BUFFERLENGTH 64 > > unsigned char buffer[BUFFERLENGTH]; > short bufInputIndex, bufInputAvailable; > // > // add character to buffer and wrap as required > buffer[bufInputIndex++] = ch; > bufInputAvailable++; > bufInputIndex &= (BUFFERLENGTH-1); // masking handles wrap > > > > You can find the source code for a ring buffer, interrupt > driven, serial handler at www.oes.to. Look for the > U4SCFX library link. The code is for an M68K system, but > the source is pretty generic C. > > Mark Borgerson
1/2) Point taken, but at 9600bps and the amount of data that I intend to send, I don't think queue overflow is going to be a big problem, if at all. Still, it's good practice to handle any possible errors. I'll probably do that. 3) Makes sense. I don't know why I didn't think of the powers of 2 solution. Anyway, if I set my buflen to 256 and set the index to unsigned char, I wouldn't even need do any wraparound check would I? It'd automatically wrap :)
CBFalconer wrote:
> "goister@gmail.com" wrote: > > goister@gmail.com 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.
In article <1160710154.445591.255650@i42g2000cwa.googlegroups.com>, 
goister@gmail.com says...
> > Mark Borgerson wrote: > > In article <1160642892.522507.50970@c28g2000cwb.googlegroups.com>, > > goister@gmail.com says... > > > > > > Ico wrote: > > > > goister@gmail.com <goister@gmail.com> wrote: > > > > > Hi, > > > > > I'm working with a Toshiba TMP91 series MCU that doesn't seem to have > > > > > any UART control/status bits to check for empty data register, rx/tx > > > > > ready, etc, but does have interrupt vectors for serial tx and rx, which > > > > > is why I think I have to use interrupt driven UART rather than polling > > > > > it. > > > > > > > > > > I have functions that expect to receive and send a single byte by > > > > > calling receivebyte and sendbyte functions. However, since it's > > > > > interrupt based, receivebyte seems to be pretty redundant. What I have > > > > > now is a UART receive ISR that first does error checking, then copies > > > > > the rx buffer to a global rx byte variable, and setting a global > > > > > rx_ready flag to 1. Then my receivebyte function does nothing until the > > > > > rx ready flag is set, after which it just clears it. Does this make > > > > > sense? > > > > > > > > This might work, but imagine what would happen if a byte is received on the > > > > uart while your code happens to be doing something else then calling the > > > > uart_receive function ? Instead of having only one 'global rx variable', > > > > consider using a ringbuffer aka 'circular buffer' aka fifo for this. The RX > > > > interrupt stores incoming bytes into the buffer and updates the head and tail > > > > pointers, while your uart_receive function reads one byte from the buffer, or - > > > > if the buffer is empty - waits until new data comes available. > > > > > > > > > > > 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? > > > > > > > > That's the general scheme. There are a few details to consider: > > > > 1. why not keep a counter of the bytes in the queue rather than > > a simple flag. That way, if your main application goes away > > for a long time, it can note that there are many byte in the > > buffer, rather than just an indication that one or more > > bytes are available. > > > > 2. You may need to keep track of the possibility of queue > > overflow. > > > > 3. An oft-used trick for circular buffers is to make the > > buffer length an exact power of two. Then you can > > skip the wraparound test and simply mask the index with > > an appropriate value to accomplish the wraparound. > > > > #define BUFFERLENGTH 64 > > > > unsigned char buffer[BUFFERLENGTH]; > > short bufInputIndex, bufInputAvailable; > > // > > // add character to buffer and wrap as required > > buffer[bufInputIndex++] = ch; > > bufInputAvailable++; > > bufInputIndex &= (BUFFERLENGTH-1); // masking handles wrap > > > > > > > > You can find the source code for a ring buffer, interrupt > > driven, serial handler at www.oes.to. Look for the > > U4SCFX library link. The code is for an M68K system, but > > the source is pretty generic C. > > > > Mark Borgerson > > 1/2) Point taken, but at 9600bps and the amount of data that I intend > to send, I don't think queue overflow is going to be a big problem, if > at all. Still, it's good practice to handle any possible errors. I'll > probably do that. > > 3) Makes sense. I don't know why I didn't think of the powers of 2 > solution. Anyway, if I set my buflen to 256 and set the index to > unsigned char, I wouldn't even need do any wraparound check would I? > It'd automatically wrap :) > >
If your processor has 16 or 32-bit registers, it will probably do a masking operation after the increment in any case. It will just be hidden from you by the compiler. Mark Borgerson
In article <1160714459.737590.239920@i3g2000cwc.googlegroups.com>, 
goister@gmail.com says...
> > CBFalconer wrote: > > "goister@gmail.com" wrote: > > > goister@gmail.com 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
Mark Borgerson wrote:
> In article <1160714459.737590.239920@i3g2000cwc.googlegroups.com>, > goister@gmail.com says... > > > > CBFalconer wrote: > > > "goister@gmail.com" wrote: > > > > goister@gmail.com 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 } }
In article <1161059360.210871.120550@m7g2000cwm.googlegroups.com>, 
goister@gmail.com says...
> > Mark Borgerson wrote: > > In article <1160714459.737590.239920@i3g2000cwc.googlegroups.com>, > > goister@gmail.com says... > > > > > > CBFalconer wrote: > > > > "goister@gmail.com" wrote: > > > > > goister@gmail.com 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
Mark Borgerson wrote:
> In article <1161059360.210871.120550@m7g2000cwm.googlegroups.com>, > goister@gmail.com says... > > > > Mark Borgerson wrote: > > > In article <1160714459.737590.239920@i3g2000cwc.googlegroups.com>, > > > goister@gmail.com says... > > > > > > > > CBFalconer wrote: > > > > > "goister@gmail.com" wrote: > > > > > > goister@gmail.com 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? 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 datasheet, 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?
In article <1161134013.648175.59200@b28g2000cwb.googlegroups.com>, 
goister@gmail.com says...
> > Mark Borgerson wrote: > > In article <1161059360.210871.120550@m7g2000cwm.googlegroups.com>, > > goister@gmail.com says... > > > > > > Mark Borgerson wrote: > > > > In article <1160714459.737590.239920@i3g2000cwc.googlegroups.com>, > > > > goister@gmail.com says... > > > > > > > > > > CBFalconer wrote: > > > > > > "goister@gmail.com" wrote: > > > > > > > goister@gmail.com 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 datasheet, 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
Mark Borgerson wrote:
> In article <1161134013.648175.59200@b28g2000cwb.googlegroups.com>, > goister@gmail.com says... > > > > Mark Borgerson wrote: > > > In article <1161059360.210871.120550@m7g2000cwm.googlegroups.com>, > > > goister@gmail.com says... > > > > > > > > Mark Borgerson wrote: > > > > > In article <1160714459.737590.239920@i3g2000cwc.googlegroups.com>, > > > > > goister@gmail.com says... > > > > > > > > > > > > CBFalconer wrote: > > > > > > > "goister@gmail.com" wrote: > > > > > > > > goister@gmail.com 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 datasheet, 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
Sorry for not stating it earlier. I'm actually emulating the ISO7816 smart card interface, so it will be half duplex, so like you said I will probably leave the TX and RX on all the time since they will never clash.