Is there a fault in interrupt simulation in AS-7?

Go To Last Post
33 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

When the program below starts, it sets up a few things (it's well commented), and when it reaches "idle_loop:", it waits for INT0 to be triggered by a mains zero-crossing. 

I simulate the INT0 by clicking PIN[2].  It goes white (and stays white till I click it again).  Even if I press shift-F5 to reset the simulator to the first instruction line, it does not change the colour of PIN[2].

It single-steps onto "brne idle_loop", then on the next single-step, it goes to the INT0 vector, then into the INT0 routine, then on reti, it returns to "cp R8,R9".  The cp is true, and it falls through the branch.  It runs down to "rcall average_time"

 

The "average_time:" routine starts with an identical wait loop - also waiting for R9=1, which is set by the INT0 interrupt.

cp R8,R9       ; R8 = 1
brne average_time

If the program counter (PC) is pointing to the brne when I trigger INT0, the next single-step takes it to the INT0 vector, and on return from the interrupt, it returns to the "cp R8,R9" instruction, which does the test, and falls through the "brne", and everything works every time, but if PC is pointing to the "cp R8,R9" when I click PIN[2], the next single-step takes it to the "brne" (always), and the next one takes it to the INT0 vector (always). 

Now - each time I click the PIN[2] to invoke the interrupt, the PIN[2] square changes from white to grey, or from grey to white.  If I click it and it goes white, the interrupt works as it should, and returns after the reti to "cp R8,R9". which gets tested for R9 being 1, then it falls through the branch and executes the instructions below it.

However, if I click PIN[2] and it turns grey (PC pointing to the "cp R8,R9", remember), it single-steps to the "brne" as before, and invokes the interrupt as before, but on reti, instead of returning to the "cp R8,R9", it returns to the "brne", and the compare does not get done.  The next single-step takes it back to the interrupt, R9 gets incremented again (to 2, because it wasn't cleared), and my simulation falls apart.

Has this been noted before?  Is it a bugette in AS-7, or is it some misunderstanding or bad coding on my part?

 

Here's enough of my code to simulate the question.

.org 0x0
 rjmp main  ; Reset - Address 0
.org 0x1
 rjmp INT0_handler    ; vector for INT0 (address 01)
.org 0x05
 rjmp TCNT0_overflow ; Vector for Timer/Counter0 Overflow

INT0_handler:   ; INT0 vector points here
  ; interrupts are stopped because we're in one.

  in R12,TCNT0  ; save LSB
  mov R11,R14   ; save MSB
  out TCNT0,R9  ; clear the timer
  clr R14       ; MSB (overflow counter)
  inc R9        ; indicates to main that INT0 has completed.
  reti

TCNT0_overflow:
  ; increment overflow counter 
  inc R14    ; number of overflows.  Typically 0x3C-40
  reti


main:
; Load stack register
LDI R16, HIGH(RAMEND) ; Upper byte
OUT SPH,R16 ; to stack pointer
LDI R16, LOW(RAMEND) ; Lower byte
OUT SPL,R16 ; to stack pointer

ldi R16,0x18
out DDRB,R16   ; Set PB3/PB4 OUT.  All other port pins IN
in R16, MCUCR
andi R16,0xbc  ; PUD set to 0 (active- disable pull-ups) and ISC[0:1] set to 0b00
ori R16,0x03   ; MCUCR[0:1] set - rising edge of int0 generates interrupt request
out MCUCR,R16

in R16,TCCR0B
andi R16,0xf8  ; CSO[0:2] set to 0.  Other bits of TCCR0B preserved
ori R16,0x4    ; CSO[0:2] set to 0b001 (clock/256)
out TCCR0B,R16 ; start timer with prescaling of 1/256.  Timer count will be cleared by each INT0 interrupt

ldi R16,0x40
out GIMSK,R16  ; enable external INT0
in R16,TIMSK   ; interrupt mask reg
ori R16,0x02   ; TOIE0 - enable overflow interrupt
out TIMSK,R16

setup_10mS_measurement:  ; for first measurement, which may be invalid
clr R9         ; INT0 indicator 
clr R14	       ; overflow counter
clr R8
inc R8         ; set R8 = 1 as a comparator for R9
sei            ; enable interrupts

idle_loop:
cp R8,R9
brne idle_loop ; loop waiting for R9=1 - INT0 has triggered for the first time (which may give a partial count.
; We have seen the first count - waste it in case it was short.
;========================================
; Start timing in earnest
clr R9   ; re-arm interrupt
clr R2   ; MSB in averaging accumulator
clr R3   ; LSB in averaging accumulator
ldi R16,8
mov R4,R16 ; Count of averaging samples = 8
rcall average_time
rjmp reg_scope   ; eternal routine.  Displays indefinitely

average_time:  ; averages the timer counts over 8 counts
; R4 is the sample number.  We will average 8 of them
cp R8,R9       ; R8 = 1
brne average_time
; INT0 has been triggered
clr R9       ; get ready for the next interrupt
add R3,R12   ; LSB
adc R2,R11   ; R2:R3 accumulate the total
dec R4
brne average_time
; At this point, R4=0, and R2:R3 have accumulated the total of 8 timer counts.
cli      ; disable interrupts
rcall stop_timer  ; We don't need the timer any more.  Let's stop it.
;=========================================================
; You don't need to go this far to simulate my question
;=========================================================
; Divide R2:R3 by 8 (shift them right 3 times)
lsr R2 ; LSb -> [C]  1st time
ror R3 ; [C] -> MSb
lsr R2 ; LSb -> [C]  2nd time
ror R3 ; [C] -> MSb
lsr R2 ; LSb -> [C]  3rd time
ror R3 ; [C] -> MSb  if[C], the division yielded a fraction of more than half.  Increment R3 (eg 3.51 ~= 3.6)
adc R3,R4  ; R4=0, so this simply adds [C] to R3
ret    ; average time is in R2:R3

stop_timer:
in R16,TCCR0B    ; timer control reg
andi R16,0xf8    ; TCCR0B[xxxx x000]
out TCCR0B, R16  ; Stop the clock
reti

reg_scope:  ; displays 4 regs on scope, RS232-style.  This routine works fine.
; not part of this question
; does not return

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

REMEMBER that you should/must save and restore the SREG when you enter and exit an ISR, if any bits get changed within the ISR then on exit you may have some problems.

 

ie

somewhere at the top of the code define a register to use for the purpose, I use R15
.def	save_sreg=r15		;Status reg store during ints.

stop_timer:
    in	    save_sreg,SREG  ;Save Status register
    in      R16,TCCR0B      ; timer control reg
    andi    R16,0xf8        ; TCCR0B[xxxx x000]
    out     TCCR0B, R16     ; Stop the clock
    out	    SREG,save_sreg  ;Restore Status register
    reti

also a nice indentation makes the code look good and prevents people from going cross eyed.

 

You don't have to reserve a register for the above but it may save you many headaches by doing it.

John Samperi

Ampertronics Pty. Ltd.

https://www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Many thanks, John.  You're quite right that I had omitted the save/restore of the SREG (I'm new at this), but doing so has not corrected the issue.  It is exactly the same as described.  I'm sorry, the description was a bit convoluted, but I couldn't think of a way of stating it more simply.  Invoking the symptom is quite complex.  It depends on triggering the interrupt on the right instruction (the compare, not the branch), and when I click PIN[2] to invoke the interrupt, if the PIN[2] square goes white, it returns from the interrupt back to the compare, whereas if the PIN[2] square goes grey, it returns from the interrupt to the instruction after the compare, so the compare never gets done, and the next single-step takes it back to the interrupt (INT0_handler).

 

Thanks for the example you gave, and for the suggested method - however, your worked example was for a regular subroutine, not an ISR - I misled you by returning from it with a reti - but that was an error on my part.  It is called with an RCALL and should have been returned with a RET.  My two interrupt routines are INT0_handler and TCNT0_overflow.  I have saved/restored SREG in them now, though I stepped through them and SREG was not actually changed.  In INT0_handler, "clr R14" sets the Zero flag, then "inc R9" clears it again, so SREG was unchanged, and while single-stepping the program, the TCNT0_overflow ISR never gets called.  Still, I agree, I should be doing this as a matter of habit.

 

Here are my sanitised ISR's - but the simulation fault is still there.  The problem is that the program doesn't run in my MCU either, and I don't know if this is my cause, or whether this is just an artifact of SR-7 and I should be looking for something else.

INT0_handler:   ; INT0 vector points here
  ; interrupts are stopped because we're in one.
  
  in R15,SREG   ; save the status register
  in R12,TCNT0  ; save LSB
  mov R11,R14   ; save MSB
  out TCNT0,R9  ; clear the timer
  clr R14       ; MSB (overflow counter)
  inc R9        ; indicates to main that INT0 has completed.
  out SREG,R15
  reti

TCNT0_overflow:
  ; increment overflow counter 
  in R15,SREG  ;
  inc R14      ; number of overflows.  Typically 0x3C-40
  out SREG,R15 ; restore SREG
  reti

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Tools->Options->Tools->Mask interrupts while stepping

:: Morten

 

(yes, I work for Microchip, yes, I do this in my spare time, now stop sending PMs)

 

The postings on this site are my own and do not represent Microchip’s positions, strategies, or opinions.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks meolsen, I had already done that.  If I had not, I don't think the interrupt would have triggered at all.

 

I found the reason why the program wasn't running.  When it has developed its numbers, it displays them on an oscilloscope, and I had made a mistake in the display routine.  That happens after the section of program that I posted at the top of this thread, so my programming error does not affect the symptoms I was seeing.  Now, the chip runs, but there is still a problem in AS-7.

That means that my fault is definitely looking like an AS-7 issue.

I've had a few suggestions based on the usual errors that newbies make, but has anybody copied my code and tried to reproduce the issue?

 

There is a part of my script that goes ...

; Divide R2:R3 by 8 (shift them right 3 times)
lsr R2 ; LSb -> [C]  1st time
ror R3 ; [C] -> MSb

If my single-step highlight is on the first instruction (lsr R2) and I modify the value of R2 to '4', then execute the single step, the value of R2 goes to '2', so I know that when the single-step highligjt is on an instruction, that instruction has not yet been executed.

 

Now, back to the issue.  In my waiting loop ...

average_time:  ; averages the timer counts over 8 counts
; R4 is the sample number.  We will average 8 of them
cp R8,R9       ; R8 = 1
brne average_time

... if "cp R8,R9" is highlighted, it has not yet been executed.  Before single-stepping, if I invoke INT0 by clicking PIN[2], the interrupt is not invoked immediately.  The single step appears to do the cp test, then go to the branch (brne average_time), then the ISR is invoked.  However, when I clicked PIN[2], if it went white, the reti returns to returns to "cp R8,R9", and the comparison gets tested.

If PIN[2] went grey (which it does on alternate clicks), the reti returns to "brne average_time", and the comparison does not get tested.

 

Is that how it's supposed to work?  Is there something I haven't thought of?  Probably - but if somebody could try it out, that would resolve it.

 

Edited a line out of the prohram inclusion to make it more readable

Last Edited: Tue. Apr 4, 2017 - 10:53 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The way I see it, you should check the status register immediately on entry to the ISR, before you save it. If the flags indicate the comparison has been made, then cp has been executed before the ISR, so returning to the branch is correct. Else, there is a bug in AS 7 and you should report it.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

In reality there is a synchronisation time between the actual pin changing state and the core detecting the interrupt and acting on it. This may be emulated in the simulator.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

El Tangas, "The way I see it, you should check the status register immediately on entry to the ISR"

... but when I trigger the ISR (in the simulator), it follows exactly the same sequence whether PIN[2] was white or grey - but when the ISR returns, it returns to a different instruction depending on whether PIN[2] was white or grey at the moment of triggering the interrupt.  I suppose I'm doing it right- I click PIN[2].  Is there a different way?

 

"Else, there is a bug in AS 7 and you should report it."

I think there is.  I would have preferred  some sort of confirmation before reporting it - but it looks like I'm not going to get anybody on the forum to check it.  Who should I report it to?  Just contact tech support?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

armstack wrote:
Is there a different way?
stimulifile

 

EDIT: that is... http://www.atmel.com/webdoc/simu...

Last Edited: Tue. Apr 4, 2017 - 12:50 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Here is the status reg immediately on entering the ISR

 

... and here it is on exiting the ISR, having been restored.

 

 

The zero flag was set, but us back to its original state.  The next single step takes it to the branch instruction instead of the compare instruction.

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks, clawson,  I searched for it in AS-7 help.

Can you say a bit more about it please?

And even though another method of invoking an INT0 may exist, it poking PIN[2] invalid?

 

Thanks.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

armstack wrote:
Can you say a bit more about it please?

???  He gave you a link...

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

theusch wrote:
??? He gave you a link...
+1

 

The link I gave was the example as it shows the complete picture of what's possible. I thought the interested reader might step back to the start of the section in the manual and read it all...

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yes, I'm sorry, clawson, I simply didn't see the link.  I've had ADHD all my life, and what it can do is impossible to explain to somebody who doesn't have it.  It happens frequently that I don't see things in front of my face.  I've been going through the link you gave, but I didn't understand it very well. I'll have to work through the examples that I found there and also on YouTube and other places, but I'll be doing other things for the next couple of days.

 

Nobody answered my question earlier - is it valid to invoke INT0 by clicking PINB[2] in the AS-7 simulator?  It seems to work - the single stepping goes to the ISR - but I have doubted software so many times in the past (eg compilers), and been wrong, that I'm doubting my program, or my actions, rather than a piece of software that works for other people.  One thing I notice, however, is that if I get  a real-world interrupt on pin 7 (PINB2) of my chip, that signal won't stay at +5V for long.  The signal will be true for < 1mS, so it will be false again long before the next interrupt comes (once every 10mS).  However, when I click PINB[2] in the port on SR-7, it changes colour and never reverts till next time it is clicked, so it looks like a signal that goes TRUE to invoke an interrupt, and is still TRUE next time the interrupt comes along, and only goes FALSE when it is clicked again.  That would be the equivalent of triggering INT0 on state change, but (unless I did it wrong), I have set it to trigger always on a rising edge (MCUCR[1:0] = 0b11 - table 9-2 in the datasheet).  The effect is that the return from the ISR behaves differently if it was triggered by a rising edge (PINB[2] grey->white) than if it was triggered by a falling edge (PINB[2] white->grey).

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

By the way which chip are you using? I can't see it mentioned anywhere.

John Samperi

Ampertronics Pty. Ltd.

https://www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

"Which chip?"  Sorry if I didn't mention, it's the ATtiny85.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ok, I don't have studio 7 installed, so I tried on 6.2, the result was that the cp instruction gets executed twice:

 

1 - cp is highlighted, I trigger the interrupt by clicking B2

2 - cp is executed

3 - branch is highlighted

4 - ISR is executed

5 - returns to cp instruction

6 - cp is executed again

 

So, there is a bug in 6.2 in my opinion. Maybe someone will try in studio 7?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

It would be useless if clicking the port pin was only momentary. In terms of the simulation you set the pin at time X then reset it at X + 1ms in simulated clocks. Maybe the simulator allows you to set the pcint flag? Since all you want to do is fire the interrupt and the level of the port pin is irrelevant to the code.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I simulate the INT0 by clicking PIN[2]

That would be pinB2 correct? I can't get into the ISR no matter how many times I change the status of that pin. Off to breakfast now, maybe later.

 

edit using AS7 1188 by the way.

John Samperi

Ampertronics Pty. Ltd.

https://www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

Last Edited: Tue. Apr 4, 2017 - 11:12 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I had to change Tools->Options->Tools->Mask interrupts while stepping to "false" for it to work (AS6.2).

 

I also confirm that you can trigger the interrupt by writing 0x40 to the GIFR register at memory address 0x5A (I/O 0x3A).

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Tried with AS4.18 and the ISRs happen...now what was the original problem???

John Samperi

Ampertronics Pty. Ltd.

https://www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I had to change Tools->Options->Tools->Mask interrupts while stepping to "false" for it to work

Did the same in AS7 and it still doesn't work for me sad

 

 

 

so I can try using AS4.18. Simulator2 by the way.

John Samperi

Ampertronics Pty. Ltd.

https://www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

Last Edited: Tue. Apr 4, 2017 - 11:54 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yes, it is valid to trigger a pin interrupt by changing the PINn register in the IO-view. Due to the lack of a "physical pin view" we have implemented the PIN registers to represent the actual pin. This means that the PINn registers will show all values output by peripherals (DACs, Timers, USARTs, ...), and any value written to PINn will be treated as pin inputs. You can also trigger interrupts by setting the interrupt flag, so in the case of pin interrupts there are actually two ways to trigger it.

 

Now, I'm sad to say that your issue is actually known. Back in 2011 there was reported an issue on Freaks regarding tiny45 (https://www.avrfreaks.net/forum/t...). Even though tiny85 and tiny45 are separate models they share the same code, so the issue in tiny85 is the same as in tiny45.

The reason we have not fixed this is model yet is that it was made with a tool we no longer have license for. So to fix this we need to redo the model with our current tool. It's in the backlog, but I can't promise when it will be fixed. For reference, our internal issue number is AVRSIM-169.

 

-Jan Egil

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks, at least we know. The OP can always go back to the future and use AS4. devil

John Samperi

Ampertronics Pty. Ltd.

https://www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

AS4 should behave similar in this case, since it basically is the same simulator model in AS4 (Simulator2) as in AS7.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

So I guess in this case the workaround is to use just the flag as trigger. That would be bit 6 of the GIFR register.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yes, that works, John, because it is part of the MCU spec that "The flag is cleared when the interrupt routine is executed" (from the datasheet).  That stops the ISR from being executed twice.  Of course, it's not a simulation of the real world any more, because a hardware interrupt will put a pulse on pin 7 of the chip - it won't directly change the flag.  Thanks for giving it some thought.

 

Finally, I decided not to report it.  My experience with dealing with companies is a lot like dealing with authority - nobody will take much interest, and nothing will be done about it - so why bother?  I know about it, and it won't phase me when simulating, so it's not really a disadvantage to me.  I know how to work around it - by triggering the ISR on the right instruction - and although I'm not 100% sure, I don't think it's happening in the MCU - only in AS-7.  I may devise a test at some point to be certain.  I'm just going to accept it and move on with my project.  Next bit - fast binary division - if I can get it worked out!

Incidentally, I don't have any other version of Studio.  This one works fine (with a small reservation!)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Folks,  I came back to my computer after a day off, and this issue was still on the screen, so I refreshed it and saw John's update at the bottom.  I have just been through it and realised there has ben quite a bit of input to it, so to El Tango, Kartman, je_ruud, John et al, thank you all very much for your attention.  I guess my comment above was misplaced.  I hope it didn't cause offense to anybody.

Mike.

 

[Edit:]  Please consider this thread resolved.

Last Edited: Wed. Apr 5, 2017 - 07:43 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Don't know if your budget allows for an Atmel ICE (or other) with debug wire, the issue should not be there I guess.

John Samperi

Ampertronics Pty. Ltd.

https://www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Just to be clear on what's happening here: the ISR is triggered twice at every change of PB2?

 

I could not get the interrupt to work with AS7 as above so I did try AS4.18 and simulator 2, the double interrupt is happening.

 

Then changed to simulator (older version) and the double interrupt is NOT happening, it only happens once when PB2 changes from low to high.

 

Maybe I'm confused but I have old age on my side......

John Samperi

Ampertronics Pty. Ltd.

https://www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

AS4 has two simulators:

  Simulator:    an instruction set simulator with some peripherals, implemented in C/C++. Discontinued after AS4.

  Simulator2:  made up of .dll-files, approximately one per supported device. Each .dll is made by compiling the RTL-code written by the IC designers to get a behavioral correct model. This is the simulator continued in AS 5,6 and 7.

 

Some of the simulator models in AS7 is the same as in AS4 Simulator2, like for ATtiny85. The bug in this case is located in the RTL-based simulator model for ATtiny85, which is why AS4 Simulator2 should have the bug but AS4 Simulator should not.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

js wrote:
Just to be clear on what's happening here: the ISR is triggered twice at every change of PB2?

Hi John, yes, the ISR is triggered twice, but only because of my code.  "main:" sets R9 to 0, then goes to the wait loop, waiting for R9=1.  It gets set to a 1 by the ISR.  When the ISR returns, it depends on whether the compare (cp R8,R9) gets executed or not.  If it is executed, then it sets the zero flag and the program will drop through the BRNE and will continue with the instructions below it.  If the compare is not executed (ie when the ISR returns to the branch, not to the "cp R8,R9") then PINB[2] is still true, and it goes back to the interrupt (INT0) for a second time.  That's wrong in itself, because INT0 should be triggered by a rising edge, but it seems that it is being triggered by the PIN value being high.

 

HOWEVER - I opened this thread to alert the forum to a possible fault in AS-7 (see the subject line).  It's an easy fault to work around - I'm not looking for help.

 

Last Edited: Thu. Apr 6, 2017 - 06:01 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ok I was just pointing out that the OLD simulator (not simulator2) in AS4.18 seems to be working correctly as je_ruud above seems to indicate also.

John Samperi

Ampertronics Pty. Ltd.

https://www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly