0%
RUNTIMEDASHBOARD
5 OF 8

Code Your Firmware

// coding time

We’re coding in C++, specifically Arduino code. Download the Arduino IDE and use this guide to add your XIAO RP2040 to it, if you’re using that.

Find sample code in the datasheet

Go back to your best friend (the datasheet) and try to find example code or pseudocode tucked near the back. Even if it’s written for a different microcontroller, it’s still very helpful.

Find a code library (if one exists)

Search the Arduino Library Manager and/or the internet for your exact part number. If someone’s already written a library for it, use it. If you’re having trouble getting it to work, then keep reading to write register-level code.

If nothing exists, you’re writing register-level code yourself, which is very doable. Keep reading!

Reading input, getting output to work

Get your input printing real values over Serial first (Serial.println() it and watch the Serial Monitor) before you touch your output logic at all.

SPI and I2C

Every I2C device has an address, check the datasheet (CTRL+F “address”) to find it. It’ll usually show up as a 7-bit binary number, which you convert to hex for your code.

// pull this from your part’s datasheet
#include <Wire.h>
#define SENSOR_ADDR 0x68

Wire.h is Arduino’s I2C library, it’s how you read and write data to your parts. Before you can talk to anything, initialize it with Wire.begin():

void setup() {
Serial.begin(9600);
Wire.begin();
}

To write to a device, wrap your message between beginTransmission() and endTransmission():

Wire.beginTransmission(SENSOR_ADDR);
Wire.write(0x6B);   // register address
Wire.write(0x00);   // value to write
Wire.endTransmission();
Most sensors need waking up

Before they’ll send you real data, CTRL+F “sleep mode” or “power management” in the datasheet to find the right register and value to write.

Getting data back works a little differently, you point to a register, then request bytes from it:

Wire.beginTransmission(SENSOR_ADDR);
Wire.write(0x43);              // starting register for output data
Wire.endTransmission(false);   // false = keep the bus open, don’t hang up yet
Wire.requestFrom(SENSOR_ADDR, 6);

endTransmission(true), the default, means “I’m done talking.” endTransmission(false) means “I’ve got more to say,” which is what you want right before requestFrom() so you can read from the register you just pointed at.

Sensors send data in bytes (8 bits), but most real readings are 16-bit numbers, so you get a high byte and a low byte and have to smush them back together:

int16_t x = (Wire.read() << 8) | Wire.read();

Shift the high byte left by 8, OR it with the low byte, and you’ve got your real 16-bit value.

Finish a working version before the PCB arrives

You won’t be able to fully test this until your PCB physically shows up, but you need something working to submit. Breadboard or jumper-wire test your input and output against your microcontroller ahead of time if you can, get the logic right now, and save fine-tuning (thresholds, calibration, exact timing) for when the real board’s in your hands.

Firmware checklist

backStep 4: Design Your PCB