Skip to content
HardwarePhase 1 · Lesson 1.1a

Getting PlatformIO talking to the Discovery kit

Phase 1 begins not with a soldering iron but with toolchain dignity — PlatformIO, the STM32 Discovery kit, and the unshowy work of getting a board to report its first raw LoRa packet.

Slav Pilus
Learning in public · Corby, England

Phase 0 was two posts of reading — the family tree of LPWAN, the difference between LoRa and LoRaWAN. Reading is comfortable. Phase 1 is where it stops being comfortable, because Phase 1 is hardware.

The last post promised the soldering iron would come out. It will — but not in this post. Before any of that there is a quieter job, the one every tutorial skips because it photographs badly: getting a development board to flash, reliably and reproducibly, from a single command. Skip it and every later post in this series is built on sand.

So this lesson has a deliberately small goal. One board — the STM32 B-L072Z-LRWAN1 Discovery kit — transmitting raw LoRa packets on 868 MHz. No LoRaWAN. No receiver yet. Just the toolchain, and a radio that will at least claim to be alive.

Bench · 2026-05-23
The STM32 B-L072Z-LRWAN1 Discovery kit on a wooden desk — a long blue development board with the square Murata radio module and an SMA antenna connector at one end — connected by a micro-USB lead through a small silver USB hub to a laptop off the left of the frame.
The whole bench for this lesson: the Discovery kit and one micro-USB lead. The onboard ST-Link carries power, flashing, and serial over that single cable — no other wiring, no soldering.

Why PlatformIO

ST will hand you STM32CubeIDE for free, and it works. I'm not using it. The reason is this series, not the IDE: every post is meant to be reproducible by a reader, and a reproducible build is one that lives in a file you can copy, not a sequence of menu clicks I'd have to screenshot. PlatformIO builds from a single platformio.ini. That file pins the platform, the framework, and the library versions, and a reader who copies it gets — within reason — my build, not their best guess at it.

PlatformIO Core is a command-line tool: brew install platformio, and pio --version reports 6.1.19. There is also an official IDE extension, and here is the first small yak-shave of the day. I don't run stock VS Code — my editor is one of the newer VS Code forks — and the official PlatformIO extension only publishes cleanly to the genuine Microsoft marketplace. On a fork you get a search page of well-meaning community re-uploads instead. I closed that tab. The CLI is the tool; the extension is only buttons wrapped around it, and the buttons are not the part you reproduce.

The first build

pio run. The first build of a new project is slow in an honest way — PlatformIO goes and fetches the STM32 platform, the ARM toolchain, and the Arduino framework before it compiles a line. A little under three minutes — 164 seconds — and then [SUCCESS].

The numbers worth writing down: the firmware is 22,640 bytes, which is 11.5% of the STM32L072's 192 KB of flash, and it uses 1,544 bytes of RAM. A LoRa transmitter is a small thing. There is also exactly one compiler warning — a deprecation notice from inside the LoRa library itself, not my code, and not worth silencing, because the day there's a real warning I want to see it standing on its own.

What a generic library does not know

The firmware leans on arduino-LoRa, a library that speaks to the Semtech SX1276 — the radio chip inside the Discovery kit's Murata module. It is a generic library, and the Discovery kit is not a generic board. Three things on it a generic library will never do for you:

  • The 32 MHz reference the radio runs on is a TCXO, and its power is gated behind a microcontroller pin. No pin driven, no clock.
  • The SX1276 then has to be told it is listening to a TCXO rather than driving its own crystal — one bit, in one register (0x4B).
  • And there is an RF switch sitting between the radio and the antenna socket. The transmit output only reaches the SMA connector when one specific line is held high.

Miss any one of the three and nothing obvious breaks. The code compiles. The board boots. The serial log ticks over happily. And nothing leaves the antenna. The firmware for this lesson does all three by hand, explicitly, with comments — because that gap, between a program that runs and a radio that actually works, is the thing this whole series is really about.

The board was asleep

pio run -t upload. First attempt: Error: init mode failed (unable to connect to the target).

This one took a minute to understand, because the ST-Link itself was plainly fine — pio device list saw it, named it, gave its serial number. The debugger was present. The chip behind it would not answer.

The reason turns out to be almost funny. A Discovery kit ships running ST's factory LoRaWAN demo, and that demo is a good low-power citizen: between transmissions it drops the STM32L0 into a deep STOP mode. A microcontroller in STOP mode has gated its own debug clock. The debugger knocks; the house is dark.

The fix is to flash it under reset: hold the board's RESET button down, start the upload, and release it as the debugger attaches — which catches the CPU at the reset vector, before it has run a single line of the sleep code. Verified OK, 4.25 seconds. And it only bites once: my firmware loops on an ordinary delay and never sleeps that deeply, so every upload after the first simply connected.

The radio, as far as it will admit

pio device monitor, 115200 baud. I attached it a couple of minutes after flashing, so the counter had already climbed:

Broch Signal — Lesson 1.1a — raw LoRa, TX-only
LoRa.begin()... ok
config: 868.1 MHz  SF7  BW125  CR4/5  14 dBm  PA_BOOST
transmitting one packet every 10 s...
...
TX #15  "BrochSignal 1.1a #15"  20 bytes  in 52 ms
TX #16  "BrochSignal 1.1a #16"  20 bytes  in 52 ms
TX #17  "BrochSignal 1.1a #17"  20 bytes  in 52 ms

A 20-byte packet, 52 milliseconds on the air, once every ten seconds, and the green LED on the board blinking in time with each line. Hold onto that 52 ms — it is the real, measured time the radio spent keying the air for one very small message, and it comes back the moment duty cycle starts to matter.

Now the honest part. This is transmit-only. The board tells me it transmitted: the radio accepted its configuration, entered transmit mode, and reported the packet done. I believe it. But "the board says so" is not the same as "another radio heard it" — no signal has been independently confirmed to have left Corby. That confirmation is the next post.

What this bought

Not much that photographs well: a board that flashes from one command, the same way every time, and a radio that — by its own testimony — is alive. Toolchain dignity. It is load-bearing precisely because it is dull; everything in Phase 1 now has somewhere solid to stand.

Next: the second board, the diymore LoRa V4, brought up as a receiver — and the first packet that one radio sends and another actually hears.

If you have the same Discovery kit and your first upload behaved differently — or didn't fight you at all — I'd like to hear about it. Copy the firmware from the companion repo below, run pio run, and you should land on the same 22,640 bytes.