Re: writing ISR for UART



In article <tpudnZrLEfg_VzbanZ2dnUVZ_hSdnZ2d@xxxxxxxxxxxx>, dta@xxxxxxxx
says...
"Mark Borgerson" <mborgerson@xxxxxxxxxxx> wrote in message
news:MPG.22154ead1195c0b0989797@xxxxxxxxxxxxxxxxxxxxxxxxx
In article <MN2dnVFbIrGdszbanZ2dnUVZ_uidnZ2d@xxxxxxxxxxxx>, dta@xxxxxxxx
says...
"sohagiut" <sohagiut@xxxxxxxxx> wrote in message
news:7vednWJSV7sVfjfanZ2dnUVZ_r2nnZ2d@xxxxxxxxxxxxxxx
hy, i am not very expert in C. Can any one give me a sample example on
ISR
for UART.i am using MPLAB with c18. how to write IRQ in ISR. also how
can
i add "case" in side ISR? can any one give me any tips or any link.

Generally speaking, most compilers have an _interrupt_ keyword or similar
that tell the compiler that it must restore the status register and
perhaps
other registers when returning from an interrupt.

"case" is safe inside an ISR.

Most of the classic families of bugs with ISRs have to do with shared RAM
or
shared memory. This falls under the category of IPC problems in computer
science, i.e.:

http://en.wikipedia.org/wiki/Inter-process_communication

I wish I had the time to enumerate everything you can do wrong with an
ISR
(regrettably, I have a day job and my fingers are old), but the most
common
error is to fail to realize that the interrupt may occur at any time.
You
need to have a critical section protocol to prevent interrupts when
modifying data structures or hardware that are shared. The most common
technique is to disable interrupts for a short period of time.

For example, in the code below, if the interrupt occurs between
approximately points /* 1 */ and /* 2 */ there may be serious logical
trouble. I'll leave it to you to figure out why.

struct
{
int putpoint;
int getpoint;
int nchars;
unsigned char body[QSIZE];
} queue;

_interrupt_ void rx_isr(void)
{
unsigned char c;

/* Get c from hardware */

if (queue.nchars < QSIZE)
{
queue.body[queue.putpoint] = c;
queue.nchars++;
queue.putpoint++;
if (queue.putpoint >= QSIZE)
queue.putpoint = 0;
}
}


unsigned char get_a_char_from_queue(void)
{
unsigned char return_value = 0;

/* 1 */
if (queue.nchars)
{
queue.nchars--;
**** INTERRUPT HAPPENS HERE ****
return_value = queue.body[queue.getpoint];
queue.getpoint++;
if (queue.getpoint >= QSIZE)
queue.getpoint = 0;
}
/* 2 */

return(return_value);
}

This looks a lot like code I've used successfully for more than
a decade. Is there really a problem if q.nchars is accessed
atomically and the q.nchars-- operation occurs in a single
uninterruptible instruction? On the 68K machine where i
run the code,
q.nchars--; becomes subq.w #1, 4(A1)


so if the interrupt handler adds a character to the queue while
the get_a_char_from_queue() function is executing there
should be no problems. q.nchars is the only variable that
is modified by both the interrupt handler and by the
getchar routine.

I forsee a problem if queue.nchars was a 16-bit or
32-bit integer and the code was running on an 8-bit
processor. nchars could get messed up if an interrupt
occured between the mulitple instructions needed to
decrement the value.

First of all, I just wanted to say _something_ to the OP ... I really can't
generate high-quality examples when I don't have a lot of time to throw at
it.

That being said, are you __SURE__ that is the only problem?

How about this scenario:

a)The queue is full.

b)The "get" code executes to the point marked above as "INTERRUPT HAPPENS
HERE".

c)The interrupt runs and overwrites the character that was to be retrieved.
The issue is that the count has been decremented before the character from
the queue body has been copied out.

Good point. I looked at my code and I find that I don't decrement the
queue length until AFTER I fetch the character. That's why I said your
example looked a lot like my code---but I didn't say it was identical.


No matter how you write the code, you are going to have problems with
data integrity if the queue becomes full. No amount of interrupt
masking will save you from that problem!

I think this discussion points out one of the reasons that
it is a really good idea to understand the processor and
the assembly language if you are going to write interrupt
handlers.

Perhaps. But it also points out that human beings aren't made to produce
software and that any of us can screw up a trivial example.

Which is why it's always good to test your code with extreme cases
before you release it to your customers. That won't eliminate all
problems, but it can reduce their frequency.

It might also point out the fact that I'm never wrong (*).



The only programmers I know that have never produced a bug are those
that haven't finished their first real application!

It's much easier to never be wrong than it is to always be right.
You can achieve the former by doing nothing!

Thanks for the examples. Just because nobody has complained about
my ISRs and queue handlers in the last 10 years doesn't mean the
code is perfect. It's always a good idea to reexamine old code
before you decide you can simply copy and paste the code into
a new compiler with a different processor.


Mark Borgerson
.



Relevant Pages

  • Re: writing ISR for UART
    ... int putpoint; ... so if the interrupt handler adds a character to the queue while ... detect whether a character is available. ...
    (comp.arch.embedded)
  • Re: writing ISR for UART
    ... so if the interrupt handler adds a character to the queue while ... and a little care to avoid buffer overflows) is safe on ... detect whether a character is available. ...
    (comp.arch.embedded)
  • Re: writing ISR for UART
    ... so if the interrupt handler adds a character to the queue while ... nchars could get messed up if an interrupt ... I've seen and used queue code that compares the get and put pointers to detect whether a character is available. ...
    (comp.arch.embedded)
  • Re: Shared Data Problem
    ... In that case the ISR also needs to set a flag ... This works of course if the background task ... If you must ensure no data is ever lost, the queue is necessary. ... It depends on the timing of the interrupt. ...
    (comp.arch.embedded)
  • Re: Interrupts are not coming sometime in NIC miniport
    ... An ISR should do only what is absolutely necessary, ... This is usually done by reading some interrupt register on the ... The DPC then does all the real work. ... Fill up blob with data from the NICs data buffers. ...
    (microsoft.public.development.device.drivers)