AS 7.0.2397: ATmega328PB Simulator issues

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

My fellow AVRFreaks,

 

Environment:

  • Atmel Studio 7.0.2397
  • ATmega328PB
  • GCC Toolchain shipped with AS
  • Windows 10 1909 x64

 

While debugging some ATmega328PB code in the simulator i noticed two issues:

 

  1. Register PCMSK3 in the I/O view (EXTINT) is always shown the have a value of 0x00 although a different value was written to it and is also correctly read back by my code.
    I have not checked if the the other PCMSK registers have the same issue ...
     
  2. Executing a SLEEP instruction (sleep mode idle) seems to permanently hang the simulator and so the whole AS!
    "Break All" as well as "Stop Debugging" have no effect, when trying to close the AS window eventually a dialog pops up saying some operation takes very long and is blocking user input, asks if i want to shut down AS anyway, but selecting yes has no effect.
    Only killing the AS process in task manager works.
    There seems to be and endless loop in the simulator (or somewhere else in AS) as the AS process causes 100% load on one CPU core when it hangs.
    BTW there are two timer interrupts that should eventually fire while the AVR is sleeping and there is a SEI instruction immediately before the SLEEP!
    I also noticed that when i single step (F10) through my C code and hit the SLEEP, AS does not hang but i can single step for ever without any progress in execution, so program counter, cycle counter and stop watch in the Processor Status view do not change at all. When i then continue execution (F5) or change into disassembly view and execute the SLEEP (F10 or F11), AS hangs the same way as described above.

 

Has anyone else seen this issues?

Does anyone know if Microchip is aware of them? Will they fix them?

 

Edit:

Your can find the code and AS project to demonstrate the SLEEP issue here: https://github.com/bmildner/SimpleTaskSwitcher/tree/AS_SLEEP_issue/Test_ATMEGA328PB

The sleep_cpu() is in Switcher.c line 718.

 

Bertolt

Last Edited: Fri. May 8, 2020 - 01:24 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You need to raise a support ticket at Microchip.com so they are aware of this.

 

(1) might be a simple ATDF error that can be corrected by editing the XML

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

1. I can confirm that the PCMSK3 register is not working. It's a bug. Thanks for finding it.

 

2. This is somewhat known, but it's not good that the whole Studio freezes. Sleep is a bit of a tricky thing with the simulator, because everything in the simulator is based around clock cycles. We toggle the input clock signal and evaluates the model until the CPU clock signal has toggled. When the device is in sleep the CPU clock will never toggle, so the process is stuck in an never-ending loop evaluating the simulator model. At the same time nothing really happens in the simulator model when the CPU clock is not running, so the value of simulating sleep is questionable. The normal workaround is to just comment out the sleep instruction when simulating.

We do have made some improvements in our newer models (ATtiny817 and newer) to support sleep. I'll see if I'm able to port those changes to the mega328pb model when fixing 1. 

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

@Je_ruud: Thanks a lot for taking care of these issues!

 

I was not aware that SLEEP was not really supported by the sim, or maybe i was at some point and have already forgotten ... :)

While i would certainly prefer the backport to the ATmega328PB model (actually to all models for AVRs that are still in production, but apparently everyone got his own little maintenance hell wink), why not ignore and report SLEEP as an unknown upcode or even better as not supported by the sim ("Simulator encountered currently not supported SLEEP instruction at <address>. Sending free beer to <ASDevDep@Microchip.Norway> may help to changes this!") for those models that don't support it any ways?

 

Bertolt

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

I might have found another issue with the mega328PB simulator or with my understanding how the timers work ...

 

I'm using Timer/Counter 2 in CTC mode, initialized as follows:

  TCCR2A = (1 << WGM21);
  OCR2A = 39;
  OCR2B = 39;
  TCNT2 = 0;
  TIMSK2 = (1 << OCIE2A) | (1 << OCIE2B);
  TCCR2B = (1 << CS21) | (1 << CS22);

 

So i'm using both output compare registers, initially both with the same value and have both compare match IRQs enabled (=> they both fire at the same time).

 

Eventually OCR2B is changed by setting it to the current value of TCNT2!

 

What i would expect is:

  1. Setting OCR2B to TCNT2 will not trigger a output compare match (OCF2B not set)
  2. Next output compare match B (OCF2B set) will be when TCNT2 reaches the value in OCR2B (after reaching TOP = OCR2A and starting again from 0)

 

What i see in the simulator is:

  1. Setting OCR2B to TCNT2 does not trigger a output compare match (OCF2B not set)  yes
  2. Every time TCNT2 is incremented, output compare match B is triggered (OCF2B gets set) no
    I can see it in the I/O view for TC2 as well as in the behavior of my code.
    Haven't checked if this only happens as long as TCNT2 > OCR2B or not.

 

So, are my assumptions how the timers work correct and this is an issue with the simulator, or am i screwed cause i failed at understanding them?

 

Bertolt

Last Edited: Mon. May 11, 2020 - 07:46 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

This is a case where I'm inclined to ask: How does a real device behave?

 

The timer is purely digital and synthesizable, which means that we don't have to touch it at all when generating the simulator model. We get the behaviour from the RTL code. So unless Verilator modelled the RTL behaviour wrong, this is how a real device will behave in the same situation.

 

I'm not able to test this right now, but if somebody else with a ATmega328PB close at hand and some time to spare could give it a go, that would be interesting.

 

A theory by a colleague of mine is that this is expected, but not very well documented behaviour:

When OCR2B < TCNT2 < OCR2A, then you get a compareB interrupt on every count.

A workaround could be to disable OCIE2B on compareB interrupt, and reenable it on compareA interrupt.

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

@bmildner, I am not able to reproduce your issue in the simulator. I get an expected single interrupt on both TIMER2_COMPA_vect and TIMER2_COMPB_vect for each loop of the timer.

 

The only time I got more interrupts on TIMER2_COMPB_vect was when I managed to do the compare with TCNT2 while it matched (29), but the write to OCR2B happend after TCNT2 had incremented (30):

    while (1)
    {
        if (TCNT2 == 29)
        {
            OCR2B = TCNT2;
        }
    }

 

Can you post the part of the code where OCR2B is changed by setting it to the current value of TCNT2? 

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

@Je_ruud: Again, thanks a lot for taking the time to look into this!

 

You are right, testing it on real hardware would be the way to go. Unfortunately i do not have a board with a mega328PB at hand right now ...

 

Given the description in 21.5 Output Compare Unit and Figure 21-3. Output Compare Unit, Block Diagram in the datasheet, i find this behaviour more than strange and unexpected!

 

Thanks for the workaround tip!

 

 

@echoromeo: Thanks for taking the time!

 

This is very strange!

 

I also do not have a short code sample to demonstrate this, sorry.

 

However, the whole project i'm seeing this with is on GitHub and it is easy to reproduce!

 

  • do a git clone of https://github.com/bmildner/Simp...
  • switch to branch AS7TimerIssue
  • open AS solution .\Test_ATMEGA328PB\Test_ATMEGA328PB.atsln
  • switch to Debug configuration and build
  • set break point in SwitcherConfig.h line 110 (inline function ResetPreemptiveSwitchTimer()), this is where OCR2B is set to TCNT2
  • run in simulator
  • when execution stops at the break point you should be at cycle count (cc) 5422, PC:0x569, OCR2A = 0x27, OCR2B = 0x27, TCTN2 = 0x0f, OCF2A = 0, OCF2B = 0, OCIE2A = 0, OCIE2B = 0, SREG_I = 1
  • if you then step through the disassembly, at cc:5432, PC:0x571, OCR2B has actually been updated with its new value 0x0f, OCF2B is not set, OCR2B = 0x0f
  • when stepping further nothing of interest happens until, at cc:5547, PC:0x5ce, TCNT2 is incremented to 0x10 and OCF2B is set, TCNT2 = 0x10, OCF2B = 1
  • then my code check if OCF2B is set at about cc:5678, PC:0x653
  • and resets it at cc:5695, PC:0x662, OCF2B = 0
  • OCR2B gets reset to TCNT2 again at cc:5722, PC:0x571, OCR2B = 0x10
  • and TCNT2 is incremented and OCF2B is set again at cc:5802, PC:0x5bb, TCNT2 = 0x11, OCF2B = 1
  • ...

 

Basically this would cause an endless loop if not the timing had sufficiently changed when TCNT2 reaches 0x16 that OCF2B apparently gets set after my code checks it ...

 

Bertolt

 

 

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

@echoromeo:

 

I just noticed that the code for resetting OCF2B (and OCF2A and PCIFR, in SwitcherConfig.h:85ff, functions ResetPreemptiveSwitchIrqFlag(), ResetSwitcherTickIrqFlag() and ResetForcedSwitchIrqFlag()) is broken, writes wrong value to TIFR2 ...

 

You can find the current implementation, incl. fix for this, in branch ImplementTaskList.

I will leave the AS7TimerIssue branch unchanged to not change the precise timings and addresses in my description above!

 

Fixing this does not change the behaviour of TC2 as far as i can see!

 

Bertolt

Last Edited: Wed. May 13, 2020 - 07:50 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

@bmildner, it looks like the problem is that OCF2B is set when TCNT2 transitions from OCR2B to OCR2B+1, not from OCR2B-1 to OCR2B. The same goes for OCF2A, it is set when TCNT2 transitions from OCR2A to 0x00.

I confirmed that the behavior was identical on an ATmega328P in simulator and silicon. I did not have an ATmega328PB in my home office but this should not matter for TC2.

 

Changing line 110 to OCR2B=TCNT2-1 should hopefully fix your problem?

 

Link to timing diagram in the datasheet: http://onlinedocs.microchip.com/...

Last Edited: Wed. May 13, 2020 - 09:44 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

bmildner wrote:
Eventually OCR2B is changed by setting it to the current value of TCNT2!

 

I completely missed this comment. This explains it. The timer is explicitly implemented to trigger an interrupt if you accidentally set OCR2B to the TCNT2 value, intentionally or not. If you do this in the interrupt routine you will create an endless stream of interrupts.

Last Edited: Wed. May 13, 2020 - 12:54 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

@echoromeo &

@je_ruud:

 

D'oh! I somehow completely ignored that my code will reset OCR2B to TCNT2 every time OCF2B is set ... sorry for the confusion!

 

Yes, setting OCR2B to TCNT2-1 fixes it!

 

After looking at the timing diagram and re-reading 21.5 Output Compare Unit in the datasheet, this makes perfect sense now.

 

Again, thanks a lot for your help to both of you!

 

Bertolt