Skip to content

Scroll Indicator

LightMessenger : Debug deep-dive with Derek

LightMessenger : Debug deep-dive with Derek

This this guest post, Derek aka Codeallnight does a deep-dive into debugging the LightMessenger. It's a fascinating, detailed foray into the challenges of debugging hardware, lessons learned along the way and tips for open-source project maintainers. 

If you like this article, and want to support Derek, please consider using the code DEREK at the Lab401 Checkout (or simply click the link). You'll get 5% off the LightMessenger (and other Lab401 products) and support Derek at the same time!

You can also check out Derek's socials:

🎬 YouTube: @MrDerekJamison

🎮 Discord: @CodeAllNight

🐱 GitHub: Flipper Zero Tutorials

Debugging the Lab401 Light Messenger GPIO Board for Flipper Zero

I recently received a Light Messenger GPIO board from Lab401. While it generally worked well, I encountered an issue where the LEDs would sometimes fail to display the programmed message, even when moving it at the same rate as before.

Thinking it might be a firmware issue, I flashed my Flipper Zero with the official firmware, but the problem persisted. It turns out I was one of the first users of the Light Messenger and was using version 1.1 of the application. Spoiler alert: This rendering issue has been addressed in version 1.2 of the Light Messenger application.

Version 1.1 also had very little documentation on how the device worked, so I had to dig into the code to learn about which pins were used. However, the code was well-structured and modular, making it somewhat easy to navigate.

My Background and Approach

For the past two years, I’ve been creating Flipper Zero tutorials on YouTube and writing sample applications and a wiki for the device. In this blog post, I’ll share my debugging journey, including a few unnecessary detours that didn’t directly contribute to solving the issue but provided valuable insights.

Step 1: Understanding the Hardware

I started by reading the LIS2DH12 accelerometer datasheet, which helped me understand how the X, Y, and Z axis were oriented when the Light Messenger was connected to the Flipper Zero. Most of the movement occurs along the Z-axis when shaking the device. I skipped over SPI and I2C timing details and focused on understanding the relevant registers, which is how you control and get data from the device.

Step 2: Setting Up Debugging Tools

I attempted to use my BlackMagic debugger by connecting DuPont jumper wires between all Light Messenger pins and my Flipper Zero (secured with a breadboard). I then connected my Flipper Zero Wi-Fi Module (flashed with BlackMagic firmware) to pins 9-12 of the Flipper Zero.

However, I discovered that SWC (Flipper Pin 10) was connected to the interrupt 2 pin of the LIS2DH12, which prevented the VS Code debugger from attaching! To work around this, I modified the app_params.h file to use PB2 (Flipper Pin 6) for interrupt 2 instead. I also had to move the wire coming from pin 10 on Light Messenger to connect to pin 6 on the Flipper Zero. This allowed the debugger to connect, but the problem still occurred.

#define LGHTMSG_INT2PIN &gpio_ext_pb2 // Header pin 6 = INT2

Tip for hardware developers: Avoid using Flipper pins 10 & 12 (SWC, SIO) if you want to allow connecting the BlackMagic debugger later.

Step 3: Adjusting Threshold Values

After reading through the app_params.h file, I found that the interrupt thresholds were set at 60, which determines the g-force required for motion detection. I lowered the values to 30, reducing the force needed for an event.

While this adjustment slightly impacted the accuracy of left/right swipes, it helped rule out mechanical issues. However, the problem persisted, so I knew it likely wasn’t caused by a physical connection issue.

Step 4: Adding Debugging Logs

I attempted to use CLI (log debug) to capture events, but oddly enough, the problem seemed to disappear whenever logging was enabled. I suspected this might have changed the timing just enough to mask the issue.

Since I couldn’t rely on logging, I decided to debug using sound cues.

Step 5: Using Sound for Debugging

I modified the code to play:

  • A 440 Hz tone when the direction switched one way
  • A 660 Hz tone when it switched the other way

When the display stopped working, the tones also stopped playing. This meant that either our app_acc_worker thread stopped, or we had an issue in our interrupt routine, or the LIS2DH12 wasn’t triggering interrupts when the device moved.

To investigate further, I removed the wires use for interrupts from the Flipper Zero (pins 4, 6, and one of the GND wires). I then grabbed a resistor and connected it between GND and pin 4, but nothing happened. Moving the resistor to GND and pin 6, I heard the tone. Back to pin 4, I heard the other tone. I was manually triggering the interrupt code; our app_acc_worker thread was still processing events, and it hadn’t crashed.

This was great news—it confirmed that our code was still running! However, for some reason, the LIS2DH12 wasn’t triggering the interrupts when we moved the device.

Step 6: Checking Register Values

Focusing on the LIS2DH12, I thought that perhaps one of the registers were being reset to an incorrect value. I thought that somehow the register was changing value as we were shaking it. I wrote a routine to log register values to a text file on the Flipper Zero’s SD card. Some of the registers are marked as reserved or are for temperature, so I decided to skip over those registers.

By comparing logs from when the device worked versus when it failed, I noticed that register 0x22 had different values:

  • Working state: 0xC0
  • Failing state: 0xC8

Here is a copy of the datasheet talking about register 0x22…

The first digit (C – or 1100 in binary) means I1_CLICK & I1_IA1 were enabled and I1_IA2 and I1_ZYXDA were disabled. The second digit (8 – 1000 in binary) indicates that the “0(1)” bit was set, which, according to the datasheet, must be set to ‘0’ for correct operation.

Step 7: Fixing the Code

I checked drivers\lis2xx12_wrapper.c, which explicitly enabled I1_IA1 and disabled I1_IA2:


lis2dh12_ctrl_reg3_t pin_int1_cfg;
pin_int1_cfg.i1_zyxda = PROPERTY_DISABLE;
pin_int1_cfg.i1_ia1 = PROPERTY_ENABLE;
pin_int1_cfg.i1_ia2 = PROPERTY_DISABLE;
lis2dh12_pin_int1_config_set(stmdev, &pin_int1_cfg);

The drivers\lis2xx12_wrapper.h file defined lis2dh12_ctrl_reg3_t as:


typedef struct {
   uint8_t not_used_01 : 1;
   uint8_t i1_overrun : 1;
   uint8_t i1_wtm : 1;
   uint8_t not_used_02 : 1;
   uint8_t i1_zyxda : 1;
   uint8_t i1_ia2 : 1;
   uint8_t i1_ia1 : 1;    <<<<
   uint8_t i1_click : 1;
} lis2dh12_ctrl_reg3_t;

To fix the issue, I explicitly set not_used_01 and not_used_02 to PROPERTY_DISABLE, and the problem disappeared!

Later, I realized that setting the initial value of our struct to 0 would have prevented this issue in the first place. Updating the code to the following gives the intended result…

lis2dh12_int1_cfg_t int1_cfg = {0};

A small but meaningful improvement would be to rename not_used_02 to must_be_cleared to indicate that its value matters. This would prevent similar mistakes in future development.

Lessons Learned

  • Check uninitialized variables: When working with bit flags in structures, ensure all flags are explicitly set.
  • Avoid Flipper Pins 10 & 12: If you need debugging access, these pins can interfere with BlackMagic debugger connections.
  • Use alternative debugging methods: When logging alters behavior, use another method such as sound or vibration motor.
  • Dumping registers: dumping the register values can help to validate that the device is configured as expected.

This was a fun debugging challenge, and I hope this write-up helps others working on Flipper Zero hardware projects!

🎬 YouTube: @MrDerekJamison

🎮 Discord: @CodeAllNight

🐱 GitHub: Flipper Zero Tutorials

Next article Building the LightMessenger : Product Manufacturing, Part 2

Leave a comment

Comments must be approved before appearing

* Required fields

Cart • 0

Your cart is empty