Hi all,
I am having some strange problems with the loop_until_bit_is_clear macro.
I am using it within a larger code, like this:
volatile uint8_t bit; uint8_t i, byte, parity; TCCR3A = 0x0C; DDRC &= ~(_BV(PC4)); PORTC |= _BV(PC4); loop_until_bit_is_clear(PINC, PC4); // BK1 PORTB |= ~(_BV(PB0)); // BK2
This code is within a function. PINC4 is connected to an external input. At some point PINC4 will become 0 for a short period of time (9us) and I want my code to continue only at that point.
I am debugging using AVR Dragon. My chip is AT90USB1287.
I have two breakpoints, BK1 and BK2.
When I stop on the first breakpoint and I turn on the disassembler window, I get this:
+00000360: 92EF PUSH R14 Push register on stack +00000361: 92FF PUSH R15 Push register on stack +00000362: 930F PUSH R16 Push register on stack +00000363: 931F PUSH R17 Push register on stack +00000364: 93DF PUSH R29 Push register on stack +00000365: 93CF PUSH R28 Push register on stack +00000366: 920F PUSH R0 Push register on stack +00000367: B7CD IN R28,0x3D In from I/O location +00000368: B7DE IN R29,0x3E In from I/O location +00000369: 2F08 MOV R16,R24 Copy register +0000036A: 01FB MOVW R30,R22 Copy register pair 280: TCCR3A = 0x0C; +0000036B: E08C LDI R24,0x0C Load immediate +0000036C: 3480 CPI R24,0x40 Compare with immediate +0000036D: 8599 LDD R25,Y+9 Load indirect with displacement 281: DDRC &= ~(_BV(PC4)); +0000036E: 98B1 CBI 0x16,1 282: PORTC |= _BV(PC4); +0000036F: 3444 CPI R20,0x44 Compare with immediate 285: loop_until_bit_is_clear(PINC, PC4); +00000370: 8599 LDD R25,Y+9 Load indirect with displacement +00000371: CFB1 RJMP PC-0x004E Relative jump
The first issue that we can see is that the assembler code generated is not quite what I would expected, i.e.
SBIC 0x06,4 RJMP PC-0x0001
Any ideas on this issue?
Then I disable BK1 and I let the program run until the external input becomes 0 and thus BK2 fires. Thus I have my program/chip stopped on top of BK2 (see above).
The first problem that I encounter is that PINC4 seems to be high in the AVR Studio 4 I/O view, even though my code should reach that point only if PINC4 was low previously. Maybe between the compare and the break instruction the external input already came back to 1, I don't know.
Secondly, opening the disassembler window again, I see this code:
+00000360: 92EF PUSH R14 Push register on stack +00000361: 92FF PUSH R15 Push register on stack +00000362: 930F PUSH R16 Push register on stack +00000363: 931F PUSH R17 Push register on stack +00000364: 93DF PUSH R29 Push register on stack +00000365: 93CF PUSH R28 Push register on stack +00000366: 920F PUSH R0 Push register on stack +00000367: B7CD IN R28,0x3D In from I/O location +00000368: B7DE IN R29,0x3E In from I/O location +00000369: 2F08 MOV R16,R24 Copy register +0000036A: 01FB MOVW R30,R22 Copy register pair 280: TCCR3A = 0x0C; +0000036B: E08C LDI R24,0x0C Load immediate +0000036C: 93800090 STS 0x0090,R24 Store direct to data space 281: DDRC &= ~(_BV(PC4)); +0000036E: 853C LDD R19,Y+12 Load indirect with displacement 282: PORTC |= _BV(PC4); +0000036F: 9AB1 SBI 0x16,1 Set bit in I/O register 285: loop_until_bit_is_clear(PINC, PC4); +00000370: 9934 SBIC 0x06,4 Skip if bit in I/O register cleared +00000371: 85FE LDD R31,Y+14 Load indirect with displacement
As you can see the code somehow "magically" transformed in the meanwhile.
Can anybody please explain me what could have happened? Why am I seeing such changes using the disassembler window? Should I use something else to analyse each instruction?
I've seen some other posts related to the loop_until_bit_is_clear/set macros but I am not sure if I am under the same circumstances. Is my issue something known? Am I doing something wrong?
If I use this code instead:
while(bit_is_set(PINC, PC4));
then the assembler seems fine:
286: while(bit_is_set(PINC, PC4)); +00000370: 9934 SBIC 0x06,4 Skip if bit in I/O register cleared +00000371: CFFE RJMP PC-0x0001 Relative jump
Most importantly, the assembler code remains the same, even when I go to the second breakpoint, BK2. It does not "magically" modifies.
So I could say that using while(bit_is_set(..)) is better/safer than using loop_until_bit_is_clear(..). However I am not sure if I am doing something wrong, this is a known issue or if there is a bug somewhere. Maybe someone can clarify this to me.
Thank you,
Omar