Flipping pin not working in simulator (atmel studio)

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

Hi

 I'm trying to follow this tutorial so I reckon the stuff I'm trying should work.

Here'se the code, it's not working as expected and it's driving me nuts.

 

int main(void)
{
    DDRB = 0xFF;                         // Data direction for pins on PortB = output

    while(1)
    {
        PORTB ^= 1 << PINB0;       // toggle PortB Pin0 

    }
}

In the tutorial, the code is compiled and uploaded to the chip and seems to run (led is indeed blinking).

I'm trying to simulate this in Atmel studio 6.2. I set a break point in the while-loop and it breaks once only.

After that, it doesn't break anymore and the IDE is just "Running". The registers are not changing.

 

I found a few tutorials on this, seems to be kind of "Hello World" of pin-toggling. None of the variations I tried works for me though (for pin 0).

The closest I've gotten is with:

    PORTB ^= 0xFF;   // working, toggles all pins on PortB

    PORTB ^= 0x80;  // working, toggles the 8'th pin only

 

Is it a bug in the simulator or am I doing it wrong?

 

 

 

This topic has a solution.

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

Is it a bug in the simulator or ...

There is another recent thread with very similar symptoms.  I was able to re-create that poster's similar situation.   Whether it is the Simulator itself, I don't know.  I'll try to hunt up the thread for you.  It appeared to me that a very tight loop, single C statement in the main loop or the ISR, that there were simulator artifacts.

 

I added a dummy statement, "PORTD++;" (as this is volatile it forces code generation) to the single-statement loop and ISR, and then the simulator was much happier.  Or at least easier to understand. ;)

 

edit:  See https://www.avrfreaks.net/forum/t...

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: Tue. Jan 20, 2015 - 12:08 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The registers are not changing.

The registers will not change unless it hits a break point. Why it is not hitting the break point I don't know. PORTB ^= 1 << PINB0 is no different that PORTB ^=  0x01.

Regards,
Steve A.

The Board helps those that help themselves.

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

PORTB ^= 1 << PINB0 is no different that PORTB ^=  0x01.

;)  After this discussion has concluded, someone will bring up "PINB = 0x01;"  

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.

This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

This intrigued me so I thought I'd try it and I see exactly what's going on. The code:

    while(1)
    {
        PORTB ^= 1 << PINB0;       // toggle PortB Pin0
    }

actually generates this:

		PORTB ^= 1 << PINB0;       // toggle PortB Pin0
0000003F  LDI R25,0x01		Load immediate 
--- No source file -------------------------------------------------------------
00000040  IN R24,0x05		In from I/O location 
00000041  EOR R24,R25		Exclusive OR 
00000042  OUT 0x05,R24		Out to I/O location 
00000043  RJMP PC-0x0003		Relative jump 

The target of the RJMP there is 0x0040 not 0x003F yet when you are looking at the C source and put a break on the PORTB= line it is actually placed in the code on that LDI. yet that is "one time only" code. It is part of the "PORTB ^= 1 << PINB0;" statement but it only needs to be done once. After that, once R25 contains 0x01 then it can be used in the loop to do the XOR but the sequence of opcode execution for this C statement (including the while loop) is:

 

LDI

IN

EOR

OUT

RJMP

IN

EOR

OUT

RJMP

IN

EOR

OUT

RJMP

etc.

 

So the LDI only needs to be done once outside the loop. Unfortunately, as the LDI is part of the PORTB= line the debugger naturally puts the breakpoint on it, not realising that it is an "execute once" operation.

 

Once again this is just an artefact of optimisation. If the code is built without optimisation then the code generated is:

		PORTB ^= 1 << PINB0;       // toggle PortB Pin0
00000046  LDI R24,0x25		Load immediate 
00000047  LDI R25,0x00		Load immediate 
00000048  LDI R18,0x25		Load immediate 
00000049  LDI R19,0x00		Load immediate 
0000004A  MOVW R30,R18		Copy register pair 
0000004B  LDD R19,Z+0		Load indirect with displacement 
0000004C  LDI R18,0x01		Load immediate 
0000004D  EOR R18,R19		Exclusive OR 
0000004E  MOVW R30,R24		Copy register pair 
0000004F  STD Z+0,R18		Store indirect with displacement 
	}
00000050  RJMP PC-0x000A		Relative jump 

In this case the RJMP goes all the way back to the very first LDI here (which is also where the breakpoint is placed) and it's actually the "LDI R18,0x01" that is in the middle of the loop that is doing the equivalent of "LDI R25,0x01" in the first code. So in this case the breakpoint opcode is within the loop and will be hit on every iteration.

 

However in every setting of optimization above -O0 the LDI that loads 0x01 to be used in EOR is (quite rightly!) moved outside the loop.

 

To my mind the solution here is NOT to turn optimization off. Instead it is to switch from the C view to the mixed C+Asm view and place the breakpoint on an opcode that IS within the loop.

Last Edited: Tue. Jan 20, 2015 - 06:40 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Nice digging, Cliff.  That would explain at least most of the situation in the similar thread I linked to above.  I looked at some of the code and did a bit in mixed view, but didn't dig as deeply as you did.

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

Thanks everyone for digging into this, I'm really grateful for all your effort, it's now quite clear what's happening.

Also thanks for bringing the disassembly window to my attention,  great tool.

 

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

Also thanks for bringing the disassembly window to my attention,  great tool.

 

NO DISASSEMBLE! - NO DISASSEMBLE!  Johnny 5 Short Circuit

Don't tell that to Johnny5. ;)

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.