PDA

View Full Version : PORTB + PORTC Interrupt-On-Change



Aussie Barry
- 17th March 2014, 09:54
Hi All,

I am working on a new project which requires monitoring 9 data lines for an interrupt on change (IOC).
All the program really needs to do is count the number of interrupts on each line, increment individual counters for each occurrence and display the results to a 4x20 LCD display.
PIC16F1829 has ten IOC lines but doesn't have enough I/O ports for the rest of the project.
I could find no search criteria on the Microchip web site for IOC and PIC16F1829 is the best option I have been able to find thus far.

Can anyone suggest an alternate PIC that would handle at least 9 IOC channels PLUS an additional 6 I/O's for 4x20 LCD and 3 I/O's for switches?

I understand a serial LCD display would free up a number of I/O's on the PIC16F1829 for switch functions but I am trying to avoid going down that path unless absolutely necessary.

All suggestions, or alternate recommendations on how to perform the same task, would be greatly appreciated.

Cheers
Barry
VK2XBP

P.S. I also need two ADC lines - just to make it interesting...

HenrikOlsson
- 17th March 2014, 11:15
Hi Barry,
So how often do you expect the inputs to change state? Thosands of times per second, once every week or perhaps somewhere in between?
Do you need to detect BOTH edges of the signal or is either the rising or falling edge?
Are the inputs asynchronous in nature or do they change "in sync" with each other?

I'm asking because perhaps it can be done without interrupts, if a suitable chip isn't available.

Another option to look into is one of the "port expander chips". I've never used them but I think some of them have IOC capabillity but then again it depends on the timing requirements etc.

/Henrik.

Amoque
- 17th March 2014, 11:33
There may also be the possibility that one might "snapshot" all the lines on an interrupt and then compare to the previous "snapshot" to determine which is the different state?

Aussie Barry
- 17th March 2014, 12:23
Hi Guys,

Henrik:
I am checking for break in continuity due to physical movement. My idea is to use weak pull-ups on one side of the data line and ground the other side. Any break in the line would cause a leading edge interrupt.
Due to the mechanical nature of the test, any line could fail irrespective of the other lines. The test period is around 1 minute.
The failure mode could be intermittent (ie momentary break in continuity) or permanent.
The tests are more indicative than quantitative in that I want to know if one (or more) data lines are broken more often than others - the actual count does not need to be specifically accurate.
Ideally there would be no failures during the test but hey, who lives in an ideal world? I has assigned WORD variables to all nine counters - just in case!

Amoque:
I am not sure how a snapshot would work considering any one of the nine data lines can generate the interrupt. What are you proposing?

Cheers
Barry
VK2XBP

Charlie
- 17th March 2014, 12:48
Use an external "OR" gate to generate the interrupt, then read the state of all the pins and increment the counter for the pin that has changed.
Or you could use PIC16(L)F1526/7 but that's a lot of pins and a difficult package to deal with.

FYI I found it using the part chooser on the Microchip site - I've never actually used the device.

Aussie Barry
- 17th March 2014, 13:01
Hi Charlie,

I had thought about the "OR" gate option but I am not sure if the intermittent fault would last long enough to read the state of all the pins after the interrupt was triggered.
The PIC16(L)F1526/7 still only has PORTB IOC as an option so all those other pins don't really help my cause.

Thanks for taking the time to research other option though - greatly appreciated.

Cheers
Barry
VK2XBP

HenrikOlsson
- 17th March 2014, 13:34
Hi Barry,
The question really is how short of an event you MUST be able to capture. If we're talking microseconds then you really NEED hardware interrupts. If we're getting up into millisconds or possibly the hundreds of microseconds range then a software aproach, in line with what I, and I think Amoque was saying, might work - YMMV.

Here's something in the line of what I'm thinking

SignalLines VAR WORD ' Current state of inputs
oldSignalLines VAR WORD ' Previous state of inputs
Result VAR WORD ' Result of XORing

Counter VAR WORD[9] ' 9 counters, one for each line
idx VAR BYTE ' Index variable

' Subroutine to poll and evalute the signal lines, GOSUB this periodically.
Test:
SignalLines.LowByte = PortB ' 8 lines on PortB and...
SignalLines.Bit9 = PortC.0 ' ...and one on PortC.0 for a total of 9.

' Any bit that is set in Result indicates a state change, 1->0 and 0->1.
Result = SignalLines XOR oldSignalLines

' Iterate thru the bits in result and increment the counter for each
' respective counter if the bit is set.
For idx = 0 to 8 ' 9 bits, 9 counters
Counter[idx] = Counter[idx] + Result.Bit0[idx] ' Increment counter if bit is set
NEXT

oldSignalLines = SignalLines ' Clear any mismatch.

RETURN

Compiles but is not tested, meant as food for thought.

/Henrik.

retepsnikrep
- 17th March 2014, 17:03
Henrik

I though this would take ten pages of code and Darrels instant interrupts etc etc
Then you condense it into about 10 lines.

You are a master!!!

Aussie Barry
- 17th March 2014, 21:59
Hi Henrik,

Thanks for the program suggestion and detailed explanation of how it works.
Very nice and succinct code!

I would like to be able to capture events in the single digit millisecond region as a worst case scenario.
The XOR approach opens up more PIC options and I could use one with the fastest clock on offer.
Would you have any idea how long this subroutine would take to complete with a clock speed of say 32MHz or the shortest time achievable between captured events?

I have a bit of thinking to do before making a decision.

Thank you all for your valuable input to this project.

Cheers
Barry
VK2XBP

Aussie Barry
- 18th March 2014, 06:32
Hi All,

I found PIC16F1783 which has Interrupt-On-Change available on all I/O pins.
This device should be able to do everything I am looking at.

Cheers
Barry
VK2XBP

HenrikOlsson
- 18th March 2014, 06:46
Hi Barry,
That's great! While you searched and found that PIC a did some test here, now they are kind of moot but since I did them I'll post the results anyway.

The subroutine code, as written originally takes, 769 cycles (on an 18F part, don't know if it'll be any different on a 16F1x) including the GOSUB and RETURN. At 32MHz that's ~100us.

I thought that was quite a bit to tell you the truth so I tried replacing the array indexing FOR-NEXT loop discrete lines (Counter[0] = Counter[0] + Result.BIT0 and so on) and it went down from 769 to 87(!) cycles. 87 cycles at 32MHz is only ~11us.

The tricky part would obviosuly be to update the LCD during the duration of the test. I think you'd need to write a single character to LCD, GOSUB the test routine write another character, GOSUB the test routine and so on. Obviously not rewriting static information every time.

Anyway, if you've found a suitable device then going the interrupt route is probably better!

/Henrik.

Aussie Barry
- 18th March 2014, 08:55
Hi Henrik,

Thank you for the subroutine timing analysis. 11us is a pretty good result!

I am now looking at ways to handle the interrupts and still trap subsequent events whilst the first event is being acted upon.

With the PIC16F1783 all pins on all ports can be configured to operate as IOC pins. Individual status flags can be read and cleared individually so my approach will be to jump to the ISR on an interrupt event, check which of the nine lines were affected using IF...ELSEIF...ENDIF statements, increment the appropriate error counter, clear the individual IOC flag and then return to the main program. My concern is the method used within the ISR to determine which line generated the interrupt. Is a 9 option deep IF...ELSEIF...ENDIF faster or slower than a 9 option deep SELECT CASE...END SELECT? Or is there a more elegant way of doing this which would take less time?

Comments and suggestions are, once again, welcomed and appreciated.

Cheers
Barry
VK2XBP

Amoque
- 18th March 2014, 12:29
I'm a little confused by your requirements.

You state it is a mechanical system - suggesting some debounce might be necessary(?), or is this part of the fault condition to be counted? You worry for the speed of the system and capturing every event, but then state the count need not be too accurate... The requirements are likely very clear in your mind, but reading... it leaves me wondering, just how fast an event you wish to capture and what constitutes an event?

Here we go into areas I'm not qualified to speak with much expertise...

I had imagined some level of filtering to eliminate the tiniest of glitches - capacitors, as used on power supply, to eliminate noise and other such tiny perturbances and measuring events in the range of a few milliseconds - maybe less, I hadn't really thought of minimal times possible, only to make a stable system that reacts reliably and consistently rather than to every stray passing gamma ray :). Henrik's suggestion to use ORs is much better... I thought to use latching flip-flops to maintain state until the PIC could read and reset in a tight loop/ interrupt. My idea being that mechanical systems are typically pretty slow and messy, and accuracy at the level I work is typically limited to what I can see and measure. This seems not to be the case for your requirements.

Well, in any case it has been an interesting read - and you have determined an answer suitable... back to the bench for me!

Oh, as to your question... I'd likely stack all the flags into a bit array and then loop through as:

For LOOP = 0 to 8 'For each flag
If BIT[LOOP] Then 'If bit is set
CounterWord[LOOP] = CounterWord[LOOP] + 1 'Add one to count
EndIf
Next


...unless, as I was typing, Henrik posted a more artful method in the post following. :(

HenrikOlsson
- 18th March 2014, 12:37
Hi Barry,
I don't see the need for all the IF/ENDIF stuff, care to explain?

Instead, why not do like I did in the previous example:


Counter[0] = Counter[0] + IOCBP.0 ' Positive edge on RB0
Counter[1] = Counter[1] + IOCBP.1 ' Positive edge on RB1
' ....and so on.

IOCBP = 0 ' Clear the interrupt flag registers

' Possibly clear the IOC flag as well IF DT-INTS doesn't do it (I don't know for sure).

If an IOC flag bit IS set the counter will get incremented, if it's not set the counter will not get incremented. If you want to capture negative edges as well then just add a similar block for IOCBN etc. The ISR will take the same amount of time every time which is good and it should be about as quick as my subroutine so you'll probably spend way more time getting in and out of the ISR than actually IN the ISR.

It might be better to read the complete IOCxP register into a temporary register and using that instead. The datasheet does discuss the correct way of doing this ensuring no events gets missed but I haven't really looked into it properly.

/Henrik.

Aussie Barry
- 18th March 2014, 13:08
Hi Amoque,

Please let me clarify my requirements.

I am trying to capture fault conditions so I definitely do not want to de-bounce any of the lines. A fault in this test is defined as an intermittent open circuit and I need to determine not only which lines exhibit fault conditions but also how frequently the faults occur during the test period. The accuracy of an individual line's error count does not have to be to absolute; it is more important to capture a fault condition occurring on any of the other lines whilst processing an fault on an individual line.

For example:
1/. Initial state is set and there are no fault conditions.
2/. Under test conditions, line 1 exhibits a fault condition
3/. Whilst recording line 1 fault condition, line 2 also exhibits a fault condition

In this example I do not want to miss recording the line 2 fault whilst recording the line 1 fault.
If a subsequent fault condition occur on line 1 whilst the initial line 1 fault is being recorded, and some of these slip through, then that is acceptable - not ideal but acceptable. This is what I meant when I stated that "the count need not be too accurate."

So, extreme accuracy in counting individual line faults is not as important as the ability to capture fault events that may occur in quick succession across all nine lines.

An interesting challenge - yes?

I trust this clears up the confusion caused by me not explaining the how's and why's in my previous posts.

Cheers
Barry
VK2XBP

Dave
- 19th March 2014, 11:26
Barry, What is the time between fault conditions? I think I would propose using a couple of port expanders like the PCF8574 with the interrupt lines tied together going to 1 PIC interrupt line. When interrupted just read the port expanders and clear?

Amoque
- 19th March 2014, 11:58
Yes, quite the "sticky wicket". As I see it, your device must be prepared to capture 9 errors simultaneously- and constantly.

I was mistaken in my first assumptions by imagining something like a frame rate where you would have some measure of time between [machine] cycles to do something. I refer to 3/ above - since there is no measure of time allowed to record the event and no lower limit for the event timing (which, in itself provides some opportunity)... it seems impossible to me. The only hope I see is in "If a subsequent fault condition occur on line 1 whilst the initial line 1 fault is being recorded, and some of these slip through, then that is acceptable - not ideal but acceptable."

The closest "solution" I imagine is 9 processors on a common clock, each recording the status of its input on each tick. This will only work to the limits of the clock speed, but it is a start... Or, you might just use a DSO (of the best speed available) as, in the end, this is the function you describe, is it not?

I have had another thought - what of a decade counter on each line? You would not get specific timing, but at regular intervals you could record the number of faults by reading the counter values.

HenrikOlsson
- 19th March 2014, 14:15
Ah, come on guys, I think you are overcomplicating this.
From what I understand it's basically a test rig for flexible cable moving back and forth and the goal is to capture any glitches in the cable as it moves.

Using a PIC with IOC will probably work fine as long as the code for it is written properly. The only thing it will NOT catch is a second (and third and forth and....) fault condition on the very same line that initially caused the interrupt. But then again the absolute fault count per line wasn't that critical and I think that the interrupt latency etc will provide the "perfect" amount debounce (even though the specification said no debounce) for this to work perfectly fine. But again, make sure to read up on how to handle the IOC events in order to not miss events on lines any of the lines that didn't actually cause the interrupt currently being serviced.

Using a port expander, which I also suggested in my first reply, will work but in this case I don't see the benefits, only drawbacks, considering Barry did find a PIC with the needed number of IOC pins.

/Henrik.

towlerg
- 19th March 2014, 15:48
Have I missed something? Why not use a logic analyzer? If it's data presentation that precludes then write a plug-in (both of the obvious candidates provide for them) which will print out the results or give you a go/no go.

Aussie Barry
- 20th March 2014, 09:20
Hi Guys,

Thanks for all the fabulous responses.

1/. Towlerg: "Why not use a logic analyser?" - simply because I don't have one. I also need to replicate this test in other parts of the world so I don't think purchasing multiple logic analysers is a cost effective approach to solving the problem.

2/. Henrik: Great comment! Yes, I do not want to over-complicate the problem. I hope to send my ISR code to the group soon for comment on my approach to handle the IOC event and minimise loss of subsequent events on other lines.

3/. Amoque: Your multiple decade counter suggestion was quite inspirational! I had not thought of it like that but essentially I am trying to replicate the same concept with the PIC16F1783.

4/. Dave: Much of this testing is exploratory so I can't accurately predict what the time between events will be. Ideally there should be no faults at all (obviously) but if there are faults then I want to capture as many events on as many data lines as possible.

I am making good progress on the software side of the project but can't verify anything until the PICs arrive late next week/early the week after. As mentioned above, I will post my ISR code for comment soon. Fingers crossed my methods will not be shot down in flames ;)

I am now concentrating on the hardware side of the project: machining enclosures, mounting LCD displays, push buttons etc but the most trying part will be building jigs to accept the device under test (DUT). Lots of fun ahead for me this weekend!

Cheers
Barry
VK2XBP

Amoque
- 20th March 2014, 11:09
"the most trying part will be building jigs to accept the device under test (DUT)."

I trust that you are looking for every opportunity to use those little Pogo Pin test probes. Those thing seem so cool that I just don't see how any project featuring them can't work.

Aussie Barry
- 20th March 2014, 11:48
Of course! :)

http://au.element14.com/mill-max/0907-2-15-20-75-14-11-0/spring-loaded-pin-pcb/dp/1279883?Ntt=1279883

Cheers
Barry
VK2XBP

Darrel Taylor
- 20th March 2014, 17:07
Interrupts can be very useful for many different purposes ... this isn't one of them.
In fact, interrupts will only slow things down and reduce the resolution of your readings.

A variation of what Henrik was describing might look like this ...
The resolution with WORD variables for the counts is 9uS (16F1783 running at 32Mhz internal OSC).
If the counters are BYTEs, the resolution is 3.5 uS, as measured in the simulator.

With interrupts, using a BASIC language ISR, that resolution will suffer greatly.

DEFINE OSC 32

ANSELA = 0
ANSELB = 0

Results VAR BYTE[9]
Res0 VAR Results[0]
Res1 VAR Results[1]
Res2 VAR Results[2]
Res3 VAR Results[3]
Res4 VAR Results[4]
Res5 VAR Results[5]
Res6 VAR Results[6]
Res7 VAR Results[7]
Res8 VAR Results[8]
IOCA VAR BYTE
IOCB VAR BYTE
Testing VAR PORTC.0

IOCBP = $FF
IOCBF = 0

CLEAR
WHILE !Testing : WEND
PAUSE 20

WHILE Testing
IOCA = IOCAF
IOCAF = 0
IOCB = IOCBF
IOCBF = 0
Res0 = Res0 + IOCA.0
Res1 = Res1 + IOCA.1
Res2 = Res2 + IOCA.2
Res3 = Res3 + IOCA.3
Res4 = Res4 + IOCA.4
Res5 = Res5 + IOCA.5
Res6 = Res6 + IOCB.0
Res7 = Res7 + IOCB.1
Res8 = Res8 + IOCB.2
WEND

Aussie Barry
- 20th March 2014, 20:25
HI All,

I am so glad I didn't show any of you my ISR code...it is embarrassing compared to what Darrel has just shared!

I also need to display results as they occur on a 4x20 LCD. There are two different display screens, one that gives a visual representation if a fault has occurred on any particular data line and another that displays actual fault counts for all nine lines. I don't know the timing requirements for LCDOUT statements but I am sure they will add considerably to the 9uS resolution with WORD variables. I could control the LCDOUT routine such that it only updates the LCD screen if a new fault has occurred. Is it possible to do a comparison using this pseudo-code:

Results VAR WORD[9]
OldResults VAR WORD[9]

IF Results <> OldResults THEN
Goto Display Routine ' break to the routine that updates the LCD screen
OldResults = Results ' Reset OldResults
ENDIF

Cheers
Barry
VK2XBP

towlerg
- 21st March 2014, 03:55
Hi Barry

1/. Towlerg: "Why not use a logic analyser?" - simply because I don't have one. I also need to replicate this test in other parts of the world so I don't think purchasing multiple logic analysers is a cost effective approach to solving the problem.


You can buy a Saleae for 119Euros. Accepted that you'll need an old laptop for display. It'll store billions of samples @ 24Mhz, thats at least a decade better that Darrel is suggesting, and he writes great code. How many samples before the PIC runs out of memory?

Anyways, good luck with the project.

George

Aussie Barry
- 21st March 2014, 05:25
Hi George,

Yes, there are always a number of different ways to "skin a cat" but if I went with the logic analyser route then I would have nothing to design and build using a PIC :)

If we end up with more than a byte's worth of fault counts on any of the nine data lines within a one minute test period then we have more problems to worry about than a PIC running out of memory!

Cheers
Barry
VK2XBP

Aussie Barry
- 26th March 2014, 11:11
Hi All,

I am still waiting for my PIC16F1783 chips to arrive so I have been doing some testing with a PIC16F1829.
I am getting good results but unsure if my code can be improved. Here is the stripped down version for comment.



' Connect LCD D4 to RC4 (Pin 6)
' Connect LCD D5 to RC5 (Pin 5)
' Connect LCD D6 to RC6 (Pin 8)
' Connect LCD D7 to RC7 (Pin 9)
' Connect LCD RS to RC3 (Pin 7)
' Connect LCD E to RC2 (Pin 14)
' Connect Data Line 1 to RA0 (Pin 19)
' Connect Data Line 2 to RA1 (Pin 18)
' Connect Data Line 3 to RA2 (Pin 17)
' Connect Data Line 4 to RA3 (Pin 4)
' Connect Data Line 5 to RA4 (Pin 3)
' Connect Data Line 6 to RA5 (Pin 2)
' Connect Data Line 7 to RB4 (Pin 13)
' Connect Data Line 8 to RB5 (Pin 12)
' Connect Data Line 9 to RB6 (Pin 11)

#CONFIG
__config _CONFIG1, _FOSC_INTOSC & _WDTE_OFF & _MCLRE_OFF & _BOREN_OFF
__config _CONFIG2, _PLLEN_ON & _LVP_OFF & _WRT_HALF
#ENDCONFIG

OSCCON = %11110000 ; Fosc = 32MHz
; Clock determined by Fosc<1:0> Config Word
DEFINE OSC 32 ; Define socillator as 32MHz

' Define LCD registers and bits
Define LCD_DREG PORTC
Define LCD_DBIT 4
Define LCD_RSREG PORTC
Define LCD_RSBIT 3
Define LCD_EREG PORTC
Define LCD_EBIT 2
Define LCD_BITS 4
Define LCD_LINES 4
PAUSE 500 ' Pause to initialise LCD Display


' Define program variables
DisplayFlag var BIT
DisplayFlag = 0

Counter1 var BYTE
Counter2 var BYTE
Counter3 var BYTE
Counter4 var BYTE
Counter5 var BYTE
Counter6 var BYTE
Counter7 var BYTE
Counter8 var BYTE
Counter9 var BYTE
IOCA var BYTE
IOCB var BYTE

Counter1 = 0
Counter2 = 0
Counter3 = 0
Counter4 = 0
Counter5 = 0
Counter6 = 0
Counter7 = 0
Counter8 = 0
Counter9 = 0


ANSELA = 0 ' Disable PORTA ADC
ANSELB = 0 ' Disable PORTB ADC
ANSELC = 0 ' Disable PORTC ADC
DACCON0.7 = 0 ' Disable DAC
CM1CON0.7 = 0 ' Disable comparator 1
CM2CON0.7 = 0 ' Disable comparator 2
TRISC = %00000001 ' Set PORTC.0 and PORTC.1 as digital input
TRISA = %00111111 ' Set PORTA as digital inputs
TRISB = %01110000 ' Set PORTB.4-6 as digital inputs
OPTION_REG.7 = 0 ' Enable Weak Pull-ups
WPUA = %00111111 ' Pull-ups enabled on PORTA.0 - 5
WPUB = %01110000 ' Pull-ups enabled on PORTB.4 - 6
WPUC = %00000001 ' Enable PORTC.0 pull-ups

IOCAP = %00111111 ' Enable IOC rising edge on PORTA.0-5
IOCBP = %01110000 ' Enable IOC rising edge on PORTB.4-6
IOCAN = 0 ' Disable IOC falling edge on PORTA
IOCBN = 0 ' Disable IOC falling edge on PORTB


Main:
IOCA = IOCAF ' Save IOCAF to IOCA
IOCB = IOCBF ' Save IOCBF to IOCB
IOCAF = 0 ' Reset IOCAF
IOCBF = 0 ' Reset IOCBF
IF IOCA > 0 OR IOCB > 0 THEN ' Test if IOC Flags have changed
DisplayFlag = 1 ' If so, set Display flag
ENDIF
Counter1 = Counter1 + IOCA.0
Counter2 = Counter2 + IOCA.1
Counter3 = Counter3 + IOCA.2
Counter4 = Counter4 + IOCA.3
Counter5 = Counter5 + IOCA.4
Counter6 = Counter6 + IOCA.5
Counter7 = Counter7 + IOCB.4
Counter8 = Counter8 + IOCB.5
Counter9 = Counter9 + IOCB.6
IF DisplayFlag = 1 THEN ' Go to Display subroutine if DisplayFlag set
Gosub Display
DisplayFlag = 0 ' Reset DisplayFlag
ENDIF
GOTO Main

Display:
LCDOUT $FE, $80, " Fault Status "
LCDOUT $FE, $C0, "1. ", DEC3 Counter1, " 2. ", DEC3 Counter2, " 3. ", DEC3 Counter3
LCDOUT $FE, $94, "4. ", DEC3 Counter4, " 5. ", DEC3 Counter5, " 6. ", DEC3 Counter6
LCDOUT $FE, $D4, "7. ", DEC3 Counter7, " 8. ", DEC3 Counter8, " E. ", DEC3 Counter9
Return


Any suggested improvements would be greatly appreciated.

Cheers
Barry
VK2XBP

HenrikOlsson
- 26th March 2014, 13:02
Hi Barry,
First suggestion is very minor but still, clear IOCAF immediately after reading it, ie

IOCA = IOCAF ' Save IOCAF to IOCA
IOCAF = 0 ' Reset IOCAF
IOCB = IOCBF ' Save IOCBF to IOCB
IOCBF = 0 ' Reset IOCBF
The longer the time is between reading it and clearing it is the bigger the risk of missing an "event" is. In this case, as I said, very minor but still.

Next suggestion is to really try to tweak the display routine. Measure how long it takes now, then tweak it and compare. You want to make it as quick as you possibly can.
With tweaking I mean things like not rewriting static information each update. Instead, write the static information ONCE and then only update/overwrite what's actually needs to be updated.

You could, for example, use the bits in IOCA and IOCB to determine which counters content actually needs updating on the display. A possible drawback of doing this is that the execution time of the routine isn't constant so it's hard to tell exactly how fast the system will be able to detects consecutive events on the same "line". At the very least, don't rewrite that [ Fault Status ] - waste of time ;-)

As the code is currently written, I think you can skip the DisplayFlag semaphore and just do

IF IOCA > 0 OR IOCB > 0 THEN ' Test if IOC Flags have changed
GOSUB Display
ENDIF
But you may have something else in there preventing you from doing that, I don't know.

Another possible option to flip it around and have the Display routine as part of your main code (with the flag indicating it needs updating) and then GOSUB the code that checks the interrupt flags. That way can insert a GOSUB at various places WITHIN the Display routine (and the rest of the main loop) in an effort to really catch multiple events on the same line.

/Henrik.