Problems with Mega48/Mega88 async timer

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

Has anyone else seen this problem? A Mega48 or Mega88 is running on the internal RC oscillator (8MHz) with timer 2 set up as asynchronous from a 32.768KHz watch crystal, and prescaled so that it gives an overflow interrupt every second. So far so good. Now set up another interrupt on either of the timer 2 compare registers, with the compare register set to 0xFF, i.e. it interrupts about 4ms before the overflow. Still OK. Now, make the compare register interrupt routine write to any of the timer 2 resgiters (such as it would do if it needed to update its own compare register for the next interrupt) - it doesn't have to change the register value, only write to it. Now the overflow interrupt which should have happened 4 milliseconds later fails to happen, and one second of the real-time counter is lost.

A possible clue is that an asynchronous interrupt actually happens one count later than the value in the compare register (or at 0x01, for the overflow interrupt), so when a compare interrupt happens for a value of 0xFF, the counter is already at 0x00, and is presumably priming the logic for the overflow interrupt. Writing to any of the asynchronous registers seems to abort this process. However, a similar problem does not seem to happen between the two compare interrupts - it is only the overflow interrupt which has problems.

Unfortunately this means it isn't possible to have an overflow interrupt reliably counting seconds, and two independent compare interrupts counting shorter intervals, unless the code is fudged to make sure neither of the compare registers ever gets set to 0xFF.

I reported this to Atmel last December, but they said they knew of no such problem. So far I've simply programmed around it by using one of the compare registers as a fixed 1-second interrupt, but now I really need to use both compares in addition to the overflow. Does anyone know of an easy way around this?

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

Is any of this problem in some simulator software or is it in the real chip running at full speed without any hardware debugger intervention?

It would help if you could show us your code on how you setup the timer 2 registers.

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

Mike B wrote:
Is any of this problem in some simulator software or is it in the real chip running at full speed without any hardware debugger intervention?

It would help if you could show us your code on how you setup the timer 2 registers.

The CPU is running full,speed, unencumbered by any debugging devices. I did have it going into idle mode between interrupts, and I had my own debugging routine dumping memory to the serial port, but I have now removed these. The foreground program is now just a tight loop with a WDR instruction to reset the watchdog. The T2 overflow interrupt simply toggles PC4 high and low (connected to a LED). The T2 compare A interrupt simply reads OCR2A, adds 3, and writes it back, so that one second out of three it will hit 0xFF.

The circuit consists of the CPU chip, 32K crystal, and a LED on PC4. Nothing else. Fuses are programmed to 0xCF42, extended fuses to 0xFF. 5-volt power supply into a DIL Mega48/88-20PI. The Mega48 has date code 0431A; the Mega88 has date code 0450. I've just tried it with a new Mega88 (date 0515) and Mega168 (date 0452), and the problem is the same.

I/O registers are at reset values except: PORTB=PORTC=PORTD=0xFF, DDRC=0x10 (for the LED), UCSR0C=0x06 (left-over from removed serial code), ASSR=0x20, TCCR2A=0x00, TCCR2B=0x05, ASSR=0x20, TIMSK2=0x03.

With this set-up, the LED should flash on and off once a second, completing a cycle in 2 seconds. What actually happens is that it misses one transition out of three - the one where the OCR2A interrupt happened at 0xFF, so that (for example) 10 cycles of the LED take 30 seconds instead of 20. If the OCR2A interrupt is changed to incrememt the compare register by 2 instead of 3 (so it never hits 0xFF), the LED flash returns to normal.

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

Mike B wrote:
It would help if you could show us your code on how you setup the timer 2 registers.

OK, here's the program stripped to the absolute bare bones. The LED on PC4 will flash once every 3 seconds, instead of every 2 seconds as it should. Change the "SUBI" instruction to subtract -2 (or any even number) instead of -3, and the LED flash returns to normal.

Note that my assembler expects I/O port addresses to be specified as their memory-mapped form, i.e. 0x20 higher than the addresses in the IN and OUT instructions. Also, it assembles LDS/STS for IN/OUT where the memory-mapped address is 0x60 or above. This code may have to be modified for use with an assembler which does not do this.

ASSR:   EQU     0xB6
OCR2A:  EQU     0xB3
TCCR2B: EQU     0xB1
TIMSK2: EQU     0x70
SREG:   EQU     0x5F
SPH:    EQU     0x5E
SPL:    EQU     0x5D
PORTC:  EQU     0x28
DDRC:   EQU     0x27
R0:     EQU     0
R24:    EQU     24
R25:    EQU     25
        ORG     0
        RJMP    RESET
        RETI
        RETI
        RETI
        RETI
        RETI
        RETI
        RJMP    T2CMPA
        RETI
        RJMP    T2OVF
        RETI
        RETI
        RETI
        RETI
        RETI
        RETI
        RETI
        RETI
        RETI
        RETI
        RETI
        RETI
        RETI
        RETI
        RETI
        RETI
RESET:  LDI     R24,0xFF
        OUT     SPL,R24
        LDI     R24,1
        OUT     SPH,R24  
        LDI     R24,0x10
        OUT     DDRC,R24
        LDI     R24,0x20
        OUT     ASSR,R24
        LDI     R24,0x05
        OUT     TCCR2B,R24
WAIT:   IN      R24,ASSR
        ANDI    R24,0x1F
        BRNE    WAIT
        LDI     R24,0x03
        OUT     TIMSK2,R24
        SEI
LOOP:   WDR
        RJMP    LOOP
T2CMPA: IN      R0,SREG
        IN      R25,OCR2A
        SUBI    R25,-3
        OUT     OCR2A,R25
        OUT     SREG,R0
        RETI
T2OVF:  SBIS    PORTC,4
        RJMP    T2OVF1
        CBI     PORTC,4
        RETI
T2OVF1: SBI     PORTC,4
        RETI
        END
Last Edited: Thu. Sep 22, 2005 - 01:55 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If your real program doesn't set up the stack pointer, weird things will happen. Try again with SPL/SPH set up.

Lee

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:
If your real program doesn't set up the stack pointer, weird things will happen. Try again with SPL/SPH set up.

Lee

I've hit that problem before, when I first started using AVRs, but not with the Mega48/88/168. If you look at the datasheet, you will see that these devices helpfully preset the stack pointer to the top of RAM. Also, if it was a stack pointer problem, then changing the SUBI instruction to avoid hitting 0xFF would not have caused the problem to go away.

In any case, as I explained, this was s stripped-down version of a more complex program in which the problem was first noticed, and in which all of the necessary initialisation had been carried out.

I have been programming AVRs since they first came out, so I think it is unlikely the problem is due to any elementary misunderstanding by me about the basic workings of these chips. I'm convinced we have a genuine chip problem here - unless of course someone can explain otherwise, but any such explanation is likely to be rather more complex than simply failing to preset the stack pointer (or getting interrupt priorities wrong, as my first reply from Atmel seemed to suggest).

Just to be sure, I've modified the program to preset SP - it makes no difference to the problem.

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

Hi,

Off topic:

Quote:
If you look at the datasheet, you will see that these devices helpfully preset the stack pointer to the top of RAM.

I have to admit when I first read that I said "bullshit". It is, in fact, quite true...very interesting. Why would the mega48/88/168 have this feature and the mega325/3250/645/6450 would not I wonder. The m325 etc. was the only newer AVR device I checked.

Regards,
Steve

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

Mike B wrote:
Well, I see a big problem right away. You are trying to use the IN instruction outside of its allowed range:

etc. ... etc. ...

Thanks for the programming lesson, but as I explained, my assembler does work in exactly the way tou describe. Try substituting LDS for IN and STS for OUT throughout. Also, "NAME: EQU VALUE" does indeed define a symbol "NAME" with the specified value - a common way to do equates in many assemblers of my acquaintance, though clearly not yours.

I don't need macros to substitute LDS/STS for IN/OUT, as my assembler does this automatically with IN and OUT themselves. It also has lots of other enhanced opcodes, but I deliberately wrote the program without them to avoid confusion. Unfortunately I forgot about the IN/OUT issue - I've got so used to using the enhanced opcodes that I often forget they are there.

The reason why you don't recognise the assembler is because I wrote it myself. It was originally developed for Intel 8080 code, then Z80, 6502, F8, 64180, 8086 and finally AVR (to name but a few). The syntax for things like EQU was inherited from these earlier code sets, and I haven't bothered to change the core operation of the assembler to suit the current fashion with the code I am emulating.

Anyway, this is not a debate about the merits or otherwise of my assembler. I'm sure it's clear what the code is supposed to to, and it could easily be converted to the assembler of your choice. The program does assemble, and run, and it illustrates the AVR problem I described.

Is this any better? Some of the LDS/STS are not optimal, but it should illustrate the issue. I assume "ORG" and "END" are sufficiently self-explanatory, if you need to change them.

.EQU ASSR=0xB6
.EQU OCR2A=0xB3
.EQU TCCR2B=0xB1
.EQU TIMSK2=0x70
.EQU SREG=0x5F
.EQU SPH=0x5E
.EQU SPL=0x5D
.EQU PORTC=0x28
.EQU DDRC=0x27
.EQU R0=0
.EQU R24=24
.EQU R25=25
        ORG     0
        RJMP    RESET
        RETI
        RETI
        RETI
        RETI
        RETI
        RETI
        RJMP    T2CMPA
        RETI
        RJMP    T2OVF
        RETI
        RETI
        RETI
        RETI
        RETI
        RETI
        RETI
        RETI
        RETI
        RETI
        RETI
        RETI
        RETI
        RETI
        RETI
        RETI
RESET:  LDI     R24,0xFF
        STS     SPL,R24
        LDI     R24,1
        STS     SPH,R24
        LDI     R24,0x10
        STS     DDRC,R24
        LDI     R24,0x20
        STS     ASSR,R24
        LDI     R24,0x05
        STS     TCCR2B,R24
WAIT:   LDS     R24,ASSR
        ANDI    R24,0x1F
        BRNE    WAIT
        LDI     R24,0x03
        STS     TIMSK2,R24
        SEI
LOOP:   WDR
        RJMP    LOOP
T2CMPA: LDS     R0,SREG
        LDS     R25,OCR2A
        SUBI    R25,-3
        STS     OCR2A,R25
        STS     SREG,R0
        RETI
T2OVF:  SBIS    PORTC-0x20,4
        RJMP    T2OVF1
        CBI     PORTC-0x20,4
        RETI
T2OVF1: SBI     PORTC-0x20,4
        RETI
        END
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I found all this very interesting. My eye is always drawn directly to the code and I fell into a trap of my own making. Immediately after making my reply, I finally read the writing above your code :oops:, and quickly deleted my post. It was only there for about 30 seconds at the most, but it appears to have hung around longer somehow since you saw it.

Have you ever taken that test where you are told to completely read the instructions first, before writing any answers. The instructions tell you to put your pencil down and not answer any questions. I just answered all the test questions :).

I apologize, the programming lesson was purely my own accident and never intended as any kind of slight or insult to you.

The few things I would say about a home grown assembler aside from its being cool (unless it has had a large installed base and time to beat the bugs out of it), is that the critical timer2 binary opcodes in your program should be checked before relying on them to be correct. It must be especially hard to get traction on your complaint with ATMEL support in this case?

First off your code:

T2OVF: SBIS PORTC,4 
RJMP T2OVF1 
	CBI PORTC,4 
	RETI 
T2OVF1: SBI PORTC,4 
	RETI

appears to only toggle pin 4 on PORT C. It can be replaced with:

PINC:   EQU     0x26
T2OVF: SBI     PINC,4
	RETI

Page 71 on the 06/05 data sheet. It does not help with your problem, I just wanted to point it out.

I never saw TCCR2A, so I assume you left it in the reset state of all zeros.

You only execute the WAIT routine before writing to TIMSK2, but these ASSR status bits do not have anything to do with TIMSK2 (page 156). These bits are for the TCNT2, OCR2A, OCR2B, TCCR2A and TCCR2B registers. There is no WAIT before writing to OCR2A. Try moving the WAIT code over to the T2CMPA: routine.

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

Mike B wrote:
I found all this very interesting. My eye is always drawn directly to the code and I fell into a trap of my own making. Immediately after making my reply, I finally read the writing above your code :oops:, and quickly deleted my post. It was only there for about 30 seconds at the most, but it appears to have hung around longer somehow since you saw it.

I had email notification set, and I run my own mail server so there was no delay receiving it. I suppose I must have been sitting at the keyboard as the email came in.

Quote:
Have you ever taken that test where you are told to completely read the instructions first, before writing any answers. The instructions tell you to put your pencil down and not answer any questions. I just answered all the test questions :).

I haven't heard that one. I did hear a tale of a student who went to the viva for his PhD bearing a bottle of malt whisky, which he put on the desk. When he left, with his doctorate, he picked it up again and put it in his bag. The examiners asked him what it was for, and he pointed out a paragraph in his thesis: "The examiner who draws attention to this paragraph will receive a bottle of malt whisky". Needless to say, none of them had read the thesis at all.

I plan to try a stunt like that with some of my program documentation one day.

Quote:
I apologize, the programming lesson was purely my own accident and never intended as any kind of slight or insult to you.

No offence taken. I know it's easy in forums like these to assume that most questioners are newbies who don't know what they are talking about, and so jump onto the first apparent error as the cause of the problem. However, if I really was so new to the job that I couldn't get a simple assembler program to run, is it likely I would have diagnosed a specific problem with the timer?

Quote:
The few things I would say about a home grown assembler aside from its being cool (unless it has had a large installed base and time to beat the bugs out of it), is that the critical timer2 binary opcodes in your program should be checked before relying on them to be correct. It must be especially hard to get traction on your complaint with ATMEL support in this case?

I've been using the assembler since the late 1970s, and then AVR version since 1999, with many thousands of lines of code written, so I think I can be pretty sure the opcodes are right. In any case, I already have a program running successfully using the two compare register interrupts - one of them set permanently to interrupt at count=0. It's just that I need the extra compare interrupt for variable delays, so I need to use the real overflow interrupt as the master seconds counter.

Quote:
First off your code:
T2OVF: SBIS PORTC,4 
RJMP T2OVF1 
	CBI PORTC,4 
	RETI 
T2OVF1: SBI PORTC,4 
	RETI

appears to only toggle pin 4 on PORT C. It can be replaced with:

PINC:   EQU     0x26
T2OVF: SBI     PINC,4
	RETI

Page 71 on the 06/05 data sheet. It does not help with your problem, I just wanted to point it out.


Neat. I hadn't spotted that. Is this new for the Mega48/88/168 chips? A lot of my common code modules need to work with older AVRs, and I'm getting a bit tired of putting in conditional code to cover the variations between chips: opcodes present or absent, 2-word skips supported, SBI/CBI possible for various I/O registers, and so on - but I suppose the alternative would be a fossilised product which never improves.

Quote:
I never saw TCCR2A, so I assume you left it in the reset state of all zeros.

Correct.

Quote:
You only execute the WAIT routine before writing to TIMSK2, but these ASSR status bits do not have anything to do with TIMSK2 (page 156). These bits are for the TCNT2, OCR2A, OCR2B, TCCR2A and TCCR2B registers. There is no WAIT before writing to OCR2A. Try moving the WAIT code over to the T2CMPA: routine.

It was belt and braces. I agree it shouldn't matter, but I was following the instructions in the datasheet to the letter (see the bottom of page 104). Adding an ASSR wait to the T2CMPA routine doesn't help - the damage is already done, and making the CPU remain with interrupts off for a further 60 microseconds or so won't help (I've just tried it - it didn't make any difference).

In fact, even writing to a T2 register from a non-interrupt routine causes the loss of an overflow interrupt, if it happens just as the counter overflows from 0xFF to zero. It seems the only safe time to write to any of the T2 registers is in a T2 compare interrupt routine where the compare register is not 0xFF - very messy, but at least it suggests a possible work-around for the problem.

Anyway, all very interesting, but have you been able to run my test program and confirm the problem? I'd appreciate some assurance that I haven't made some obscure mistake here.

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

Mike B wrote:
You only execute the WAIT routine before writing to TIMSK2, but these ASSR status bits do not have anything to do with TIMSK2 (page 156). These bits are for the TCNT2, OCR2A, OCR2B, TCCR2A and TCCR2B registers. There is no WAIT before writing to OCR2A. Try moving the WAIT code over to the T2CMPA: routine.

Some progress at last! Putting in an ASSR wait didn't help, since the registers are not busy at the time, but you got me thinking about putting in a fixed delay loop before writing to OCR2A. I tried various delays, and to no great surprise, if I delay by about 31 microseconds from the compare interrupt event (i.e. one cycle of the 32K crystal clock), it suddenly works properly again.

Holding up the program for 31 microsecs with interrupts off isn't really an acceptable work-around, but I think it proves there is a real problem here. Time for another email to Atmel, I think.

It's amazing how often just talking over a problem with someone leads to clues to finding its cause :)

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

I looked at some of the data sheets I keep around (not a complete set) and saw the new write to PINn to invert its state function in these chips:

tiny25
tiny45
tiny85
tiny2313
at90can128
mega164
mega324
mega644
mega165
mega169
mega325
mega3250
mega645
mega6450
mega329
mega3290
mega649
mega6490
mega406
mega48
mega88
mega168
mega640
mega1280
mega1281
mega2560
mega2561
at90pwm2b
at90pwm3b

Many of these chips do not exist yet. Odds are this write to PINn feature is now standard on all newer parts.

I have also fought the backwards compatibility monster. Partly, it depends on your position. If you are supporting the parts or products that use them, then backwards compatibility is usually a boon (less work for you, less upset in the installed base). If you are developing new parts or projects, then its usually an anchor that drags you down and makes you cry over lost opportunities for vast improvements. If you do both support and development, then you live in the state of confusion :). After all, engineering is all about trade offs.

The data sheet said writing to a register while the temporary register was busy with a transfer could cause an unintended interrupt. My original thought was a LED driven by an inverting interrupt routine would not be able to display a spurious interrupt that occurs just before or just after the legitimate interrupt. This behavior would mask the real interrupt and create the illusion that the real interrupt never happened. If you used something like 3 or 4 LEDs in a binary counter output display rather than one inverting LED, you could see if you have this type of problem.

Depending on how fast you can respond to the overflow interrupt (i.e. contention from the time spent servicing the compare interrupt if it coincides with the lower priority overflow interrupt), it could cause two overflow interrupts (one real and one spurious) to stack up before the overflow interrupt is serviced. This would cause a single overflow interrupt response to multiple overflow interrupt events. It would not even show up on an interrupt driven binary counter LED display. The only possible correlation this could have to your problem might be a longer time spent in the compare interrupt could mask an occasional (multiple event synchronization dependent) misbehaving overflow interrupt and make a problem “appear” to go away.

There is also the compare match blocking behavior. Anytime a new compare match OCR2n value is written too close to the next TCNT2 value, the next compare interrupt may get blocked. Since the actual write timing for OCR2n depends on the temporary register transfer, I have no idea what the real timing requirements are actually based on (unlike the synchronous mode rules which are definitive). Since a compare match adds 3 to the ORC2n value, it seems it would probably never get compare blocked, given the roughly 4 ms TCNT2 interval vs the 8 MHz clock that drives the ORC2n write. This could not affect the overflow interrupt, so it should not have contributed to your problem, unless not executing a particular compare match interrupt is part of the problem. Its a real long shot, but try changing the +3 to something larger for testing purposes (i.e. make sure TCNT2 is never close enough to OCR2A in value to ever cause any blocking, whatever the unknown temporary register delays are).

Gathering more information will either strengthen or weaken your case for an AVR timer2 problem.

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

Mike B wrote:
Gathering more information will either strengthen or weaken your case for an AVR timer2 problem.

I just got a couple of emails back from Atmel. It seems there really is a problem. I'm pleased it didn't turn out I was missing something - though I suppose it would have been easier to correct an error in my code than wait for a chip update.

It should be described in future data sheets.

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

@timbierman

Would you be so kind as of describe the problem in this thread (for undocumented Erratas)

https://www.avrfreaks.net/index.p...

/Bingo