This one's a doozy and I'm scratching my head.
Setup:
Here's the code. It's part of the debounce logic for a GPIO input. The GPIO is read via the pac5xxx_tile_register_read
function. The pin is bit 0 in dinsig1
. If dinsig
is 0x01
, that means the GPIO is high. If dinsig
is 0x00
, the GPIO is low.
static uint32_t triggerDebounce = 0;
volatile uint8_t dinsig1 = pac5xxx_tile_register_read(ADDR_DINSIG1);
if ((dinsig1 & 0x01) != 0) //This is the problem line.
triggerDebounce = (triggerDebounce << 1);
else
triggerDebounce = (triggerDebounce << 1) | 1;
The if ((dinsig1 & 0x01) != 0)
instruction is the one causing problems. The code will correctly run until the GPIO goes from high to low, and then low to high (dinsig
goes from 0x01
to 0x00
to 0x01
). dinsig
always reads accurately, but if ((dinsig1 & 0x01) != 0)
evaluates to true.
Here's the disassembly for the if ((dinsig1 & 0x01) != 0)
statement.
0x00004268 ldrb r3, [r7, #7] ;Loads dinsig into r3.
0x0000426a uxtb r3, r3 ;Expands dinsig 3 into a 32 bit word.
0x0000426c and.w r3, r3, #1 ;ANDs dinsig 3 with 0x01 and stores result in r3
0x00004270 cmp r3, #0 ;Compares r3 with 0
0x00004272 beq.n 0x4280 <IsTriggerPressed+40> ; Jumps to address 0x4280 if the ZERO flag is set.
I'm watching the ASPR register register while stepping through the disassembly. The cmp r3, #0
instruction clearly sets the Zero flag, which it should not. Because r3 is 0x01
, and that is not equal to zero.
I'm at a loss here. Is this a branch predictor gone rogue? Tools broken? I know better than to blame the tools because it's virtually always my fault, but I find it hard to believe the CPU is misbehaving.
Thanks for all the suggestions. I fixed the issue by updating GCC to 9.3.1 and GDB to 9.2