UARTs and interrupts

Hi all,

I have been writing code for the ds80c320 and xa-g49 and need a few questions answered that i'm unsure about.

  1. Say i have timer 0 set to interrupt on overflow. If in another interrupt routine I disable all interrupts, then timer 0 happens to overflow, and then I enable all interrupts, while the timer 0 overflow isr then run, or was it missed?

***

I use interrupt driven serial comms reading / writing into ring buffers. Also timer 0 is interrupting on overflow, and an external uart is interrupting with data as well.

  1. Do i need to disable uart/all interrupts when placing characters into the ring buffer?

  1. In the transmit and receive isr's do I need to disable/enable any interrupts in these?

I've had problems before with the internal uart stopping. I would turn of the uart interrupt when writing to the ring buffer, and in the isr(s). This was fixed by turning off all the interrupts at these times.. (there were three other interrupt sources).

  1. Right now I turn off all interrupts when writing to the ring buffer and in the uart isr's. Is this necessary?

Any answers/comments/gems of information appreciated..

ROss

Reply to
Ross Marchant
Loading thread data ...

I'm not much up on 8051 variants, but in general, interrupts are not lost - they "pend". If you have all interrupts disabled at the time that your counter overflows, the overflow int would pend until you re-enabled interrupts. At some point, you re-enable interrupts and the overflow int would assert, taking you to your overflow ISR.

that's a pretty typical setup.

if the processor supports it, you usually want to disable only the uart interrupt when messing with your uaart queue pointers. Leave the others enabled for better response to those ints.

In most MCUs that I've seen, all ints are disabled by the MCU hardware on int acknowlege (entry into your ISR). (they pend as needed) You have to explicitly re-enable them during the ISR. You haven't said what language you use - a C complier may insert the all-int-enable instructions for you at the end of your ISR code. In assy (with a MCU that supports int priorities) you have separate instructions for enabling ints of lower vs ints of higher priority. (I don't know if your processor supports int priorities - probably not so ignore that last bit)

this stuff gets kinda tricky and if you don't know what the hardware will do, it could be quite confusing. The datasheet should tell you. If not, lookup the data sheet/books for the original part (intel?) that your chip is based on. Me-too vendors tend to omit the fundamentals in their docs. The

8051 has been me-too-ed for decades, now.

probably not. RTFM

HTH, Bob

Reply to
Bob

Reply to
Ross Marchant

Maybe yes, maybe no. It depends on how you've written your ring buffer handler. It's fairly simple to impliment a ring buffer for which interrupts don't need to be disabled.

We'd have to see the code to tell you.

--
Grant Edwards                   grante             Yow!  Don't SANFORIZE me!!
                                  at               
                               visi.com
Reply to
Grant Edwards

interrupt

and then

was it

buffers.

into the

turn of

isr(s). This

were

buffer and

Reply to
yossi_sr

You didn't tell us what is the priority of interrupts in your system ( timer0,serial rx/tx etc..).If all ring buffer activity is done within the serial RX/TX interrupt , and the timer0 interrupts has higher priority , it's needless to disable timer0 interrupt providing that you don't access serial ring buffers in timer0 interrupt. Also , it is important how your system uses your ring buffers. If for example , the high level driver extracts bytes from the receive buffer , it should disable serial RX interrupt until the pointers are updated , otherwise confusion may happen. In 8051 and its derivatives , the serial RX and TX interrupts are together so you are disabling both, but there should be no problem with this. Yossi

Reply to
yossi_sr

My own experience follows the teaching of one of my mentors in that one very rarely (if ever) needs to disable interrupts. In the 8051 world, use interrupt priority, short service routines and amenable data structures. In all of our 8051 communication products, I can not think of one that runs with interrupts disabled. Being an assembly language dinosaur helps here.

Reply to
Noone

all

OK so how do you do a ring buffer without disabling interrupts during RX read , or a Tx write? The Interrupt could hit during that time. The Keil C sample disables RI during that time.

Reply to
Neil Kurzman

or a

that

The basic principle in avoiding interrupt disabling is to make sure that only one partner updates a specific variable (unless the hardware supports some kind of interlocked manipulate and test instructions) and maintaining a strict rules in which order variables are updated.

One way of doing a ring buffer is to have two globally visible pointers, one for writing and the other for reading the ring buffer.

On the insertion side, first verify that there is space for at least one byte in the ring buffer by comparing the visible pointers. Make a private copy (e.g. a register) of the write pointer, update it to point to the first free location, insert the byte into that location and finally copy the private pointer to the globally visible write pointer. Depending on the OS, you might inform the reader about new data e.g. by raising a signal.

On the reading side, verify that there is at least one byte in the buffer by comparing the publicly visible pointers. Extract the byte, make a private copy (a register) of the read pointer, update it to point to the next position and write the updated value to the globally visible read pointer.

When using C/C++, it is very important to declare the globally visible pointers with the volatile attribute to prevent the compiler from optimising the pointer references.

Paul

Reply to
Paul Keinanen

The only issue with using pointers (or indecii) on ring buffers is the issue of when the pointers are identical knowing whether the buffer is full or empty. Especially on RX buffers as this is truely aysnchronous to the system

Better still keep all the functions related in one or two modules where the only globally visible parts of that module are function calls and definitions (baud rates, error codes) and the like. The module will need access to globally defined information like I/O registers. A second module maybe needed to handle setting of timers or other external timers for baud rate generation depending on platforms.

--
Paul Carpenter          | paul@pcserviceselectronics.co.uk
    PC Services
              GNU H8 & mailing list info
             For those web sites you hate
Reply to
Paul Carpenter

during RX read ,

disables RI

hardware

a

globally

the

aysnchronous

For this you leave one slot empty, the empty condition is when both pointers are equal and the full is when there is only one slot in between.

visible

where

need

module

Reply to
Lanarcam

That is only a problem, if you can not resist the temptation to use the last free position in the ring buffer :-).

If you declare "buffer full" at N-1 elements in the buffer (instead of at N elements), you can avoid the ambiguity.

Paul

Reply to
Paul Keinanen

Not really. Just define that when the pointers are equal, the buffer is empty. More generally, the number of items in the buffer is the difference between the pointers modulo the buffer length. This simplification means that your buffer needs no other state information besides the two pointers, and each pointer is updated by only one process, so there's no need for critical sections at all. Sure, this means that you can't fill that last spot in the buffer, but if you really need that, you're probably running too close to the edge for the system to be reliable anyway.

-- Dave Tweed

Reply to
David Tweed

It is a common pitfall many people get wrong, that is why it was mentioned in the context of the description I followed up on.

--
Paul Carpenter          | paul@pcserviceselectronics.co.uk
    PC Services
              GNU H8 & mailing list info
             For those web sites you hate
Reply to
Paul Carpenter

Not really, when you have uncoordinated processes accessing the data at random times. This will be the situation when you have, for example, an interrupt driven process filling the buffer, and another process emptying it. In this case you need a critical section, which you can implement by disabling and reenabling interrupts.

MAIN_PROCESS INTERRUPT_PROCESS 1: read input ptr read output ptr compare ptrs if empty goto 1 read output data increment output ptr write output ptr back other operations

2: read output ptr read input ptr compare ptrs if full go to 2 write input data via ptr advance ptr write input ptr back other operations

Now shuffle these two sequences around and intermix them, and you will find that you have to make the decision sequence (up to compare ptrs) critical sections. The compares decide whether there is data to be taken (not empty) or space to be filled (not full).

In some systems you can have other problems if the write actions are not single operations, such as writing high and low bytes of pointers, with interrupts between them.

You can interchange the roles of MAIN and INTERRUPT PROCESS, and have the same problem. In fact both may be interrupt driven (for example by a background data transfer operation). In that case the natural inhibition of further interrupts during interrupt service can implement the critical section function.

--
 Some informative links:
   news:news.announce.newusers
   http://www.geocities.com/nnqweb/
   http://www.catb.org/~esr/faqs/smart-questions.html
   http://www.caliburn.nl/topposting.html
   http://www.netmeister.org/news/learn2quote.html
Reply to
CBFalconer

1: read input ptr In some systems you can have other problems if the write actions

With extremely primitive processors you would have to perform the comparison byte by byte, first compare the high bytes of the pointers and then the low bytes of these two pointers. If the insertion "full" check is needed on the interrupt side, then a critical section is indeed needed.

The "empty" check on the main program side can be done by reading the high and low bytes multiple times until the same value is returned in two consecutive reads. Since we are interested only if in and out pointer have the same value, a difference in either byte would indicate that the buffer is not empty when the input pointer is compared twice. Thus the only need for a critical section would be the input overflow test, if such overflows can happen or the "overflow" status is needed. For complex processors allowing unaligned access, partial pointer update would be a problem if the pointers are unaligned and thus split into two memory words, especially at the cache line border or virtual memory page boundary. Using aligned pointers solves this problem, especially with packed structures, the pointers should be placed in the beginning of structure to ensure proper alignment.

Paul

Reply to
Paul Keinanen

I certainly hope you would never recommend a potential infinite loop inside an ISR. Your ISR code really should produce an error if the buffer is full.

This is commonly known as the shared data problem and can occur whenever two independent processes share data and the operations on the data are not atomic.

Ian

Reply to
Ian Bell

snip

Depends, if the read of each pointer is not atomic i.e. requires more than one instruction, then it can be interrupted part way through the read, its value altered then the read completed. This is the well known shared data problem.

Ian

Reply to
Ian Bell

... snip ...

Of course not. That was just to illustrate the cause of the problems. You have all sorts of mechanisms, including signal/wait, monitors, etc. available.

--
 Some informative links:
   news:news.announce.newusers
   http://www.geocities.com/nnqweb/
   http://www.catb.org/~esr/faqs/smart-questions.html
   http://www.caliburn.nl/topposting.html
   http://www.netmeister.org/news/learn2quote.html
Reply to
CBFalconer

Or some counter is incremented each time a new item is placed in the buffer. The sender increments the counter that the receiver reads and stores in a local variable. On the next cycle the receiver checks the counter against its local variable in order to see if new items were added to the buffer.

The receiver reads the counter but never writes to it, thus it needs not to be protected by a semaphore or the like.

The receiver then reads the data and increments another counter. The sender will check that counter in order to verify that the buffer is not full.

This works well if you have a periodic activation of the receiver or if the sender activates the receiver whenever the counter is incremented.

The counter must be incremented once the data has been put to the buffer not before. Then if the sender is interrupted by the receiver after the data were written but before the counter was incremented, the receiver will not retrieve them since the counter will be equal to the local value.

Reply to
Lanarcam

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.