ATmega328P - LDS instruction takes hundreds of cycles

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

Dear All,

 

I'm facing a strange problem with my code. I'm writing a small program on an ATmega328P (based on arduino hardware but written and compiled in C with AS7).

 

A 100ms timer interrupt triggers a global volatile flag periodically. The main loop checks this flag value and starts something if set. While debugging step by step, I noticed that this simple instruction took many many cycles. I don't know how much exactly, I'm just looking at the TCNT register which usually grows step by step, but when I step over this instruction, the timer increase of thousands counts.

 

I checked the disassembly listing which looks correct : 

 

        if (g_u8_flag100ms)
00000065  LDS R24,0x0102		Load direct from data space 
00000067  TST R24		Test for Zero or Minus 
00000068  BREQ PC+0x1F		Branch if equal 

stepping over the #65 line took around 4000 cycles on my timer (wich runs at Fck/64). The #67 instruction also takes thousand of cycles!

 

- Of course, I disabled "keep timers running in stop mode" in the debugger options.

- I tried with 4 different boards (3 different arduino, and another self made board with the same ATmega328P), they all show the problem.

- I tried to disable global interrupts, without success

- I trieds two different debuggers: AVR Dragon and AVR Ice, they do the same.

- The simulator doesn't show the problem. With it, the instruction takes 2 cycles as it should do.

 

The global main program looks like this : 

 

#include <avr/interrupt.h>
#include <stdint.h>
#include "main.h"
#include "mcu.h"
#define var_globale
#include "var.h"
  
volatile uint16_t g_u16_current_time;
volatile uint8_t g_u8_counter100ms;
volatile uint8_t g_u8_flag100ms;

/****************************************************************************
  Function : void main(void)
  main function
****************************************************************************/
void main(void)
 {
  uint8_t u8_blinkCounter;
      
  stateLevel0 stateMachine;
  
  g_u16_current_time = 0;
  g_u8_flag100ms = 0;
  u8_blinkCounter = 0;

  //Setup ports
  MCU_InitPorts();
  //Enable Tick Timer
  MCU_EnableTimer1();
  //Enable interrupts
  sei();
  //State Machine Update
  stateMachine = IDLE;

  do
  {
    switch (stateMachine)
    {
      case IDLE:
      {               
        //State Machine update
        if (g_u8_flag100ms)
          stateMachine = TICK_100MS;
        break;
      }

      case TICK_100MS:
      {
        g_u8_flag100ms = 0;

        //Blinking LED management
        if (u8_blinkCounter)
          u8_blinkCounter--;
        else
        {
          BLINK_LED1;
          u8_blinkCounter = BLINK_PERIOD;
        }
        //Go back to previous state
        stateMachine = IDLE;

        break;
      }
      default: {stateMachine = IDLE;break;}
    }
  }
  while (1);
}

 

The g_u8_flag100ms is set in the TIMER interrupt : 

 

/****************************************************************************
  Function : ISR(TIMER1_COMPA_vect)
  Interrupt routine called every 50ms
****************************************************************************/
ISR(TIMER1_COMPA_vect)
{
  //Here every 50ms
  static uint8_t u8_100msCounter = 0;
  
  //100ms tick
  if (u8_100msCounter)
    u8_100msCounter--;
  else
  {
    //Here every 100ms
    u8_100msCounter = TIMER_1_100MS_PERIOD - 1;
    //Update flag
    g_u8_flag100ms = 1;
  }
  
  //Update  counter
  g_u16_current_time += 50;
    		       
  return;
}

The disassembly listing for this interrupt is interesting : 

 

  if (u8_100msCounter)
000000DF  LDS R24,0x0100		Load direct from data space 
000000E1  TST R24		Test for Zero or Minus 
000000E2  BREQ PC+0x07		Branch if equal 
    u8_100msCounter--;
000000E3  LDS R24,0x0100		Load direct from data space 
000000E5  SUBI R24,0x01		Subtract immediate 
000000E6  STS 0x0100,R24		Store direct to data space 
000000E8  RJMP PC+0x0007		Relative jump 

The #DF line took 8000 timer counts (*64 prescaler cycles), BUT not always... Sometimes it goes OK in 2 cycles... ?!

 

Do you have an idea on what I did wrong frown? Silicon bug?

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

Bobbylebob wrote:
The simulator doesn't show the problem. With it, the instruction takes 2 cycles as it should do.

 

What happens if you run the program without using the debuggers?  Does it operate properly?

 

Also,

 //Here every 50ms
  static uint8_t u8_100msCounter = 0;
  
  //100ms tick
  if (u8_100msCounter)
    u8_100msCounter--;

I may be wrong here, but when will this ever run?  You reset u8_100msCounter to 0 every time the ISR fires.

 

your LED is going to be flashing VERY fast.  You might not even see it.  I would suggest changing the delay to something longer for test purposes so you don't mistakenly think the LED is on all the time.

 

One more thought.  Rather than go through such a complicated LED blinking application you could simply set up the timer and in the ISR toggle the bit attached to the LED with an XOR.  Then in the MAIN, anfter you run your INIT loop, sit in an empty WHILE() loop and the timer does the rest.

 

JIm

I would rather attempt something great and fail, than attempt nothing and succeed - Fortune Cookie

 

"The critical shortage here is not stuff, but time." - Johan Ekdahl

 

"Step N is required before you can do step N+1!" - ka7ehk

 

"If you want a career with a known path - become an undertaker. Dead people don't sue!" - Kartman

"Why is there a "Highway to Hell" and only a "Stairway to Heaven"? A prediction of the expected traffic load?"  - Lee "theusch"

 

Speak sweetly. It makes your words easier to digest when at a later date you have to eat them ;-)  - Source Unknown

Please Read: Code-of-Conduct

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB, RSLogix user

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

Set a breakpoint the RUN across the code to be tested. You can't step it - the timer continues to run and a step could take a large fraction of a second. 

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

Please post a complete buildable project.   e.g. for AS7

 

I can't see anything that is obviously wrong.    But it is difficult to follow your snippets.

 

Regarding the debugger.   It is easier to set a breakpoint and run to it than single-step.

For example.  You can set a breakpoint in the Timer ISR().   Run the Simulator.   Read off the elapsed time or cycle count since last hit.

 

David.

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

david.prentice wrote:
Run the Simulator.
jgmdesign wrote:
Bobbylebob wrote: The simulator doesn't show the problem. With it, the instruction takes 2 cycles as it should do.

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

I would expect the Simulator to work just fine.
If it does not, then it becomes an interesting problem. And wise to post the buildable project.
.
The beauty of the internet is that you can get assistance from anyone, anywhere in the world.
And if you provide the exact code, they can reproduce your problem (or give a solution)
.
David.

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

jgmdesign wrote:

 //Here every 50ms
  static uint8_t u8_100msCounter = 0;

  //100ms tick
  if (u8_100msCounter)
    u8_100msCounter--;

I may be wrong here, but when will this ever run?  You reset u8_100msCounter to 0 every time the ISR fires.

 

The u8_100msCounter is not reset on every ISR, it's just initialised on first call. On next calls, it is set to TIMER_1_100MS_PERIOD which equals to 6, which gives a 1 Hz blinking period.

 

I agree this code is very complicated for blinking a LED but it is a part of a greater project using QTouch. Facing this problem, I removed all I can to give you a simplified version of the code.

 

clawson wrote:

Set a breakpoint the RUN across the code to be tested. You can't step it - the timer continues to run and a step could take a large fraction of a second. 

 

I have exactly the same behavioral with breakpoints or single step. 

 

I tried to blink two leds at a time. One was triggered directly in the ISR, its frequency was exactly 1Hz. The second led was triggered in the main loop, in the 100ms tick with a postscaler of 5. Both LEDs started synchronously, but after a few periods, the one driven by the main loop started to slow down, missing some 100ms ticks. It shows an erratic blinking, missed periods are easily seen by eyes.

 

I'll post the whole project on wednesday when I'll be back to work. 

 

Thanks guys! smiley

 

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

Bobbylebob wrote:
I have exactly the same behavioral with breakpoints or single step.   
simply don't believe it. There's clearly something wrong about the way you are observing this phenomenon. An LDS takes exactly as many cycles as the opcode manual says it does. Perhaps you will follow David's advice and post a complete test project together with exact step by step instructions so other's here can take a look at what it is you are doing wrong?

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

You say you disabled the timer, but what about other interrupts that may be occurring between each step or breakpoint?

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

jgmdesign wrote:
You reset u8_100msCounter to 0 every time the ISR fires.

Bobbylebob wrote:
The u8_100msCounter is not reset on every ISR, it's just initialised on first call.

 

Bobbylebob is correct - see further discussion about static locals: https://www.avrfreaks.net/forum/s... (and note that it's nothing specifically to do with ISRs)

 

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yeah i split the thread with regards to the static variable. I missed not removing that comment. Sorry

Jim

I would rather attempt something great and fail, than attempt nothing and succeed - Fortune Cookie

 

"The critical shortage here is not stuff, but time." - Johan Ekdahl

 

"Step N is required before you can do step N+1!" - ka7ehk

 

"If you want a career with a known path - become an undertaker. Dead people don't sue!" - Kartman

"Why is there a "Highway to Hell" and only a "Stairway to Heaven"? A prediction of the expected traffic load?"  - Lee "theusch"

 

Speak sweetly. It makes your words easier to digest when at a later date you have to eat them ;-)  - Source Unknown

Please Read: Code-of-Conduct

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB, RSLogix user

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

To be sure, I disabled the global interrupt bit before trying to step over this instruction.

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

Bobbylebob wrote:

ATmega328P - LDS instruction takes hundreds of cycles

stepping over the #65 line took around 4000 cycles on my timer (wich runs at Fck/64). The #67 instruction also takes thousand of cycles!

 

- Of course, I disabled "keep timers running in stop mode" in the debugger options.

- I tried with 4 different boards (3 different arduino, and another self made board with the same ATmega328P), they all show the problem.

- I tried to disable global interrupts, without success

- I trieds two different debuggers: AVR Dragon and AVR Ice, they do the same.

- The simulator doesn't show the problem. With it, the instruction takes 2 cycles as it should do.

Do you have an idea on what I did wrong frown? Silicon bug?

Nope, not silicon bug. Think about it : Such a bug would be caught really early.

 

The simulator will be correct.

Most MCU debuggers  'try' to keep the peripherals in phase with what the user expects, but that requires complex gating of the clocks, and that is not always 100%.

So you can expect deep inspection of timers, etc, to sometimes not line up.

 

Just like you would not expect to be able to single-step a software UART, and see real time pin changes, any time you break/step, MCU peripheral-time becomes somewhat elastic.

 

Bobbylebob wrote:

I agree this code is very complicated for blinking a LED but it is a part of a greater project using QTouch. Facing this problem, I removed all I can to give you a simplified version of the code.

I have exactly the same behavioral with breakpoints or single step. 

 

I tried to blink two leds at a time. One was triggered directly in the ISR, its frequency was exactly 1Hz. The second led was triggered in the main loop, in the 100ms tick with a postscaler of 5. Both LEDs started synchronously, but after a few periods, the one driven by the main loop started to slow down, missing some 100ms ticks. It shows an erratic blinking, missed periods are easily seen by eyes.

 You should be able to place simple counters in the INT and Delay loops, and compare those.

 

I would certainly expect some creep, aka 'phase walking', if you code one LED via a delay, and another via INT 

If you use a flag generated by the interrupt, as the engine of another delay, that should be coarse phase locked, (< 100ms) with some fine software jitter, depending on what else the main loop is doing.

 

If you use 100ms tick to derive a main() based /10, that can (in theory) miss flag beats, but only if something in the main loop, keeps the MCU busy for > 100ms.

 

 

Addit:

If you do have a situation where rare functions in main can be > basetick, you can change from a boolean 0.1 to a simple small counter.

ie increment the byte-sized tick-var inside INT, and then add-then-clear in the main polling case. (add-then-clear should be atomic, to avoid any aperture effect of 'INT after add but before clear')

In those rare cases, tick-var is 2,3, instead of 1, and you have short term jitter but avoid long term creep.

Last Edited: Mon. Apr 17, 2017 - 12:07 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

OK guys,

 

I've written a new dummy project with the same structure and I got exactly the same behaviour.

 

You can download it here : http://bobbylebob.ddns.net/fbsha...

 

This code is very simplified. A 10ms timer interrupt sets a global flag every 100ms.

The main loop does nothing more than checking this flag and updating a register every time the flag is set.

 

The main program looks like this:

void main(void)
{  
  stateLevel0 stateMachine = INIT;
  uint8_t u8_step;
  
  do
  {
    // Autonomous loop which performs Capacitive sensing when needed    
    if (g_u8_flag100ms)
    {
      g_u8_flag100ms = 0;
      if (u8_step < 7)
        u8_step++;
      else
        u8_step = 0;
        
      PORTB = (1<<u8_step);
    }
    
    switch (stateMachine)
    {
      case INIT:
        g_u16_current_time = 0;
        //Setup ports
        MCU_InitPorts();
        //Enable Tick Timer
        MCU_EnableTimer0();    
        sei();
        stateMachine = RUN;
      break;     
      
      case RUN:
        //Useless function...
        PORTD = (uint8_t)(g_u16_current_time & 0x00ff);
      break;
     
      default:break;
    }
  }
  while (1);
}

Start a debuging session through debugwire on a ATmega328P board.

Set a breakpoint on lines 

if (g_u8_flag100ms)

and

switch (stateMachine)

Display microcontroler's IO registers and look at TCNT0

 

- Run some initialisation cycles and stop on the first breakpoint. For example, the TCNT0 register is now 0x15. (Timer 0 runs with a prescaler of 1024).

- Check if g_u8_flag100ms is equal to 0 to avoid going into the condition.

- Run to the next break point, on the statemachine. There is normally nothing more to do than a simple conditionnal test.

TCNT0 now equals to 0x1B, meaning more than 5k cycles elapsed since last breakpoint!

 

Let's explore deeper:

 

- Run again to the first breakpoint.

- Display assembly listing. Here we can see :

    if (g_u8_flag100ms)
0000004E  LDS R24,0x0101		Load direct from data space 
00000050  TST R24		Test for Zero or Minus 
00000051  BREQ PC+0x19		Branch if equal 

- Check TCNT0 value (0x22) and just run one step over LDS instruction

- Check the new TCNT0 value (0x74 for me... This single LDS instruction took 82*1024 cycles...).

 

Last test:

- Add g_u16_current_time to Watch. This counter is increased by 10 every 10ms interrupt.

- Stop to the first breakpoint (g_u8_flag100ms test).

- Run to the second one. g_u16_current_time increased by 20, meaning the 10ms interrupt was called twice between these two instructions.

 

Suprising isn't it?

 

The software does almost nothing in its main loop... Why is it so slow???

 

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

I agree.   It seems to take a long time to go from breakpoint #1 to #3

 

OTOH,  you have got 3 breakpoints.   I don't think that the debugWIRE hardware will be happy.   So there will be a lot of Flash page re-writes.

 

I suspect that you really want

ISR (TIMER0_COMPA_vect)
{
  static uint8_t u8_counter = 0;

  g_u16_current_time += 10;

  u8_counter++;

	if (u8_counter >= 10) {
		u8_counter = 0;     // reset the counter
		g_u8_flag100ms = 1;
	}

  return;
}

David.

 

Edit.  Remove breakpoints #1, #3.   Just keep #2.    Then run.   Observe g_u16_current_time and stateMachine in a Watch window.  And TCNT0 in I/O window.

Last Edited: Mon. Apr 17, 2017 - 01:24 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Any chance you are running this on the internal RC oscillator?  I doubt it will cause such a drastic drift, but it can cause some.

 

Jim

I would rather attempt something great and fail, than attempt nothing and succeed - Fortune Cookie

 

"The critical shortage here is not stuff, but time." - Johan Ekdahl

 

"Step N is required before you can do step N+1!" - ka7ehk

 

"If you want a career with a known path - become an undertaker. Dead people don't sue!" - Kartman

"Why is there a "Highway to Hell" and only a "Stairway to Heaven"? A prediction of the expected traffic load?"  - Lee "theusch"

 

Speak sweetly. It makes your words easier to digest when at a later date you have to eat them ;-)  - Source Unknown

Please Read: Code-of-Conduct

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB, RSLogix user

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

 

You don't clear u8_counter in ISR! (in your project code)

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

jgmdesign wrote:

Any chance you are running this on the internal RC oscillator?  I doubt it will cause such a drastic drift, but it can cause some.

 

Jim

 

I tried to run from 16MHz Xtal and from internal oscillator but it doesn't change anything. We could of course measure a frequency drift of some percents but it wouldn't explain the number of cycles lost.

 

sparrow2 wrote:

 

You don't clear u8_counter in ISR! (in your project code)

 

You're right, I wrote this small project quickly this afternoon only to check the problem. It is not a real application.

 

The code should be 

	if (u8_counter >= 10) {
		u8_counter = 0;     // reset the counter
		g_u8_flag100ms = 1;

 

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

david.prentice wrote:

Edit.  Remove breakpoints #1, #3.   Just keep #2.    Then run.   Observe g_u16_current_time and stateMachine in a Watch window.  And TCNT0 in I/O window.

 

I agree, with only one breakpoint #2 on  g_u8_flag100ms = 0;

We can see that these instructions are called every 100ms, that's the goal of the software, that works pretty great. But the problem is that before entering this condition, the main loop should have time to do thousands of cycles jumping from "if (g_u8_flag100ms)" to "switch(stateMachine)". It has nothing else to do.

 

If you keep only one breakpoint on "if (g_u8_flag100ms)", you'll see that TCNT0 increases of some units (not every time the same value...) between each loop. With a prescaler of 1024, it confirms thousands of cycles are lost.

I agree it is not an issue in this example, but it means my main loop looses many cyclces (and CPU load) doing nothing... And that becomes an issue in my real application.

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

I don't know the debugger (I don't use one).

But are you sure that the timer stop when you hit a break point? (often there is a setting for it to do or not).

(this is why I don't use a debugger for simple things like this, but would flip a port pin in each loop or so, and then look at the time between "pings").

Or perhaps in this case place a counter in the do loop, and from the ISR see how many loops there a between each ISR. 

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

I also don't use a debugger with AVR (I do however trust the simulator). It seems likely this is an issue with debugging. You can try to verify that by wrapping the code in the main loop with:

    uint8_t startCount = TCNT0;
    .
    .
    .
    uint8_t endCount = TCNT0;
    if (endCount != 0 && !(endCount == startCount || endCount == (uint8_t)(startCount + 1))) {
        static volatile int err = 0;
        err++;
    }
    

i.e., we expect the loop code to take less than one count of TCNT0 (so at most one increment).
Put a break point on the err++ line (and that should be the only active break point). If there is a real issue it should hit according to the description in post #14.
/Lars

 

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

sparrow2 wrote:
But are you sure that the timer stop when you hit a break point? (often there is a setting for it to do or not).

I've been following this with curiosity.

david.prentice wrote:
OTOH, you have got 3 breakpoints. I don't think that the debugWIRE hardware will be happy. So there will be a lot of Flash page re-writes.

Perhaps David hit on something.  If a "soft" breakpoint with a rewrite, then perhaps by the time the breakpoint handling is completed (the actual breakpoint rewritten?) and control given to the user, many cycles have elapsed.

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

I was also thinking that it could be caused by breakpoints. I removed them all and ran the program continuously but LED behaviour was erratic. I had one led blinked by the ISR (@ 1Hz), and another one blinked in the main loop. The last one regularly missed 100ms periods causing an out of phase blinking compared to the other one. This confirms the main loop was sometimes busy for more than 100ms...

 

sparrow2 wrote:

But are you sure that the timer stop when you hit a break point? (often there is a setting for it to do or not).

 

I'm sure of that! The option is unchecked and timer is really stopped during step by step. The problem only appears around LDS instruction...

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

I've just tried to compile the program and run it on an ATtiny88 instead of ATmega328. The problem is still there...

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

DebugWire (unlike JTAG) does not use address comparators to match PC to implement breakpoints. It always does breakpoints by temporarily modifying the flash to replace the breaking instruction with BREAK. That's why the datasheet has that dire warning about wearing out flash and not to use any CPU you have been heavily debugging in production. So, yes, the act of breaking (then putting back the original opcode) could be "heavy". Obviously it's more of a problem for single stepping than run & break operations. 

 

Personally I'd always develop on JTAG AVRs. 

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

Dear Clawson,

 

I think you're right.

 

I wrote a simplified main loop :

 

void main(void)
{  
  uint32_t u32_loopCounter;
  
  u32_loopCounter = 0;
  //Setup ports
  MCU_InitPorts();
  //Enable Tick Timer
  MCU_EnableTimer0();
  sei();
          
  do
  {
    //Count number of cycles
    u32_loopCounter++;
    // Autonomous loop which performs Capacitive sensing when needed
    if (g_u8_flag100ms)
    {
      g_u8_flag100ms = 0;
      //Useless... 
      u32_loopCounter = 0;
      PORTD = (uint8_t)(u32_loopCounter & 0xff);
    }
  }
  while (1);
}

I just put a breakpoint on 

g_u8_flag100ms = 0;

And watched u32_loopCounter to measure how much cycles were completed. I got values around 50k cycles in 100ms, which seems correct. However, as soon as I set a breakpoint on if (g_u8_flag100ms), I'm only able to run 6 cycles in 100ms. If I remove this breakpoint and do step by step, timer upcounts normally.

 

I didn't know setting a breakpoint with debugwire was so complicated "under the hood"... This does not explain my synchronisation problem between my two LED test but this might be an independant problem I'll have to check...

 

Thanks all for your help !

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

Bobbylebob wrote:
I removed them all and ran the program continuously but LED behaviour was erratic. I had one led blinked by the ISR (@ 1Hz), and another one blinked in the main loop. The last one regularly missed 100ms periods causing an out of phase blinking compared to the other one. This confirms the main loop was sometimes busy for more than 100ms...

Let's see that complete test program...

 

(and debugWire was disconnected for that test?)

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.

Last Edited: Mon. Apr 17, 2017 - 09:11 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Bobbylebob wrote:

And watched u32_loopCounter to measure how much cycles were completed. I got values around 50k cycles in 100ms, which seems correct. However, as soon as I set a breakpoint on if (g_u8_flag100ms), I'm only able to run 6 cycles in 100ms. If I remove this breakpoint and do step by step, timer upcounts normally.

I didn't know setting a breakpoint with debugwire was so complicated "under the hood"

 

All small MCUs have simplified on chip debug, so do not expect perfect real-time action.

 

Bobbylebob wrote:

This does not explain my synchronisation problem between my two LED test but this might be an independant problem I'll have to check...

To check CPU usage/cycles available, you can toggle a pin on the wait side of main loop, and connect a frequency counter.

1) Disable INT and measure the freq, should be some SysCLK/ModestN

2) Enable INT, and measure the freq, this will reduce from 1) by some amount related to INT+Branch cycles, and shows how much 'spare' you really have - Zero debug hardware active.

 

3) If you still suspect creep, you need to remove Debug from the Test loop, so run 2 counters, and break once and only when one is 100, or 255 or some larger value.

Check the other counter you expect to track. Do not expect 'real-time' to preserve across break points.

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

theusch wrote:
Let's see that complete test program... (and debugWire was disconnected for that test?)

 

AS asked in post #2:

jgmdesign wrote:
What happens if you run the program without using the debuggers? Does it operate properly?

 

 

JIm

I would rather attempt something great and fail, than attempt nothing and succeed - Fortune Cookie

 

"The critical shortage here is not stuff, but time." - Johan Ekdahl

 

"Step N is required before you can do step N+1!" - ka7ehk

 

"If you want a career with a known path - become an undertaker. Dead people don't sue!" - Kartman

"Why is there a "Highway to Hell" and only a "Stairway to Heaven"? A prediction of the expected traffic load?"  - Lee "theusch"

 

Speak sweetly. It makes your words easier to digest when at a later date you have to eat them ;-)  - Source Unknown

Please Read: Code-of-Conduct

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB, RSLogix user

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

Il post the real application program tommorow, I'm not at work today and have no remote access to my files...