This post continues after Keyboard from scratch. I messed up. I don’t know the exact details yet, but for some reason with the code linked in the previous post, the interrupts don’t come through.
So, back to blinky we go.
Blinky?
Blinky is quite literally the example that just lights up an LED for a second then turns it off for a second again. The code is pretty simple and just downloaded from upstream.
So, stepwise we iterate on building up interrupt driven code again, to see what’s going wrong here.
Add GPIO IN
Step one, add GPIO read to see whether what we are doing on the outside of the device actually has the impact on MCU state that we want.
The code is pretty simple, the only line that might be interesting is
gpio_init(LED_GPIO_PORT, GPIO_MODE_IPU, GPIO_OSPEED_50MHZ, GPIO_PIN_3);
because I use GPIO_MODE_IPU
.
This causes the MCU to pull up voltage on the GPIO to operation level with a pull up resistor.
Since we don’t invert the signal, by default the input will be active and we shorten it to ground for inactive.
Cool, this worked. I don’t have a video, so you have to trust me.
Wire in the interrupt
Mostly due to me being silly, this is split in two steps. First I wired in the interrupt while not relying on it for device control. The code allows to check if the interrupt is triggered with a debugger.
+void EXTI3_IRQHandler(void) __attribute__((used));
is interesting, because of the attribute. Interrupts aren’t referenced by other code, so we need to tell the compiler that we really need it. At least I think so. It’s referenced and shadows a weak definition in firmware code, but I’d rather make sure.
Everything else is pretty straight forward or copy pasted from example code in the firmware.
Actually using the interrupt
Finally, we wire everythign in again. The patch doesn’t do much either. Mainly sets run volatile
to prevent optimizing it out and replaces the gpio queries by access to run variable.
Well, and it sets up the correct GPIO clock. I’m actually not sure how I got this far without running into issues with this. But it made for a nice bit of confusion when the reverting to previous state didn’t work either.
Debugging the main application
Ok, back to our main project, let’s cut it down to roughly where blinky was at in the end.
So let’s cut down to a minimal code that works.
Success! This is a bit more directly interrupt driven than blinky, but it works, which was the main point.
Ok, slowly add stuff back in. First peripheral RCUs. Works fine.
Next peripheral setup. This code still works like a charm. And even prints over UART before it goes into the blocking loop.
Well, it’s somewhere in the USB setup. I can’t say that I’m particularily surprised.
RCU and timer are fine as well. Even threw in a quick user of the timer interrupt to demonstrate it also responds.
With a bit more testing, it becomes obvious that systick\_config
is the offender. Code looks like this.
Note that I had to remove the interrupt attribute from the handler, to prevent corruption.
After a bit of refactoring, let’s continue with Interrupts ahoi