Exercises 00 & 01 working, Documentation still in progress, moving to my source control server.

This commit is contained in:
John Poole 2026-02-13 14:03:09 -08:00
commit 8cf97e0e5a
15 changed files with 541 additions and 0 deletions

View file

View file

@ -0,0 +1,43 @@
; 20260212 ChatGPT
; $Id$
; $HeadURL$
[platformio]
default_envs = node_a
[env]
platform = espressif32
framework = arduino
board = esp32-s3-devkitc-1
monitor_speed = 115200
lib_deps =
jgromes/RadioLib@^6.6.0
; Common build flags (pins from Meshtastic tbeam-s3-core variant.h)
build_flags =
-D LORA_CS=10
-D LORA_MOSI=11
-D LORA_SCK=12
-D LORA_MISO=13
-D LORA_RESET=5
-D LORA_DIO1=1
-D LORA_BUSY=4
-D LORA_TCXO_VOLTAGE=1.8
-D ARDUINO_USB_MODE=1
-D ARDUINO_USB_CDC_ON_BOOT=1
; Radio params for println/printf + RadioLib init
-D LORA_FREQ=915.000
-D LORA_SF=7
-D LORA_BW=125
-D LORA_CR=5
[env:node_a]
build_flags =
${env.build_flags}
-D NODE_LABEL=\"A\"
[env:node_b]
build_flags =
${env.build_flags}
-D NODE_LABEL=\"B\"

View file

@ -0,0 +1,60 @@
#include <Arduino.h>
#include <SPI.h>
#include <RadioLib.h>
#ifndef LORA_FREQ
#define LORA_FREQ 915.000
#endif
#ifndef LORA_SF
#define LORA_SF 7
#endif
#ifndef LORA_BW
#define LORA_BW 125
#endif
#ifndef LORA_CR
#define LORA_CR 5
#endif
// SX1262 on T-Beam Supreme (tbeam-s3-core pinout)
SX1262 radio = new Module(LORA_CS, LORA_DIO1, LORA_RESET, LORA_BUSY);
int state; // = radio.begin(915.0, 125.0, 7, 5, 0x12, 14);
void setup() {
Serial.begin(115200);
delay(2000); // give USB time to enumerate
Serial.println("Booting LoRa test...");
Serial.println();
Serial.println("Initializing radio...");
SPI.begin(LORA_SCK, LORA_MISO, LORA_MOSI, LORA_CS);
Serial.printf("Radio chip: SX1262\r\n");
Serial.printf("Frequency: %.3f MHz\r\n", (double)LORA_FREQ);
Serial.printf("SF: %d BW: %d CR: %d\r\n", LORA_SF, LORA_BW, LORA_CR);
int state = radio.begin(915.0, 125.0, 7, 5, 0x12, 14);
Serial.printf("radio.begin returned: %d\r\n", state);
}
void loop() {
static uint32_t counter = 0;
Serial.printf("alive %lu\n", counter++);
Serial.println("Sending test frame...");
int tx = radio.transmit("USB RADIO CHECK");
Serial.printf("TX state: %d\r\n", tx);
// we're not expecting to receive anything, just testing that we
// can call Receive()
Serial.println("Starting receive...");
state = radio.startReceive();
Serial.printf("startReceive returned: %d\r\n", state);
delay(1000);
}

View file

@ -0,0 +1,37 @@
; 20260212 ChatGPT
; $Id$
; $HeadURL$
[platformio]
default_envs = node_a
[env]
platform = espressif32
framework = arduino
board = esp32-s3-devkitc-1
monitor_speed = 115200
lib_deps =
jgromes/RadioLib@^6.6.0
; Common build flags (pins from Meshtastic tbeam-s3-core variant.h)
build_flags =
-D LORA_CS=10
-D LORA_MOSI=11
-D LORA_SCK=12
-D LORA_MISO=13
-D LORA_RESET=5
-D LORA_DIO1=1
-D LORA_BUSY=4
-D LORA_TCXO_VOLTAGE=1.8
-D ARDUINO_USB_MODE=1
-D ARDUINO_USB_CDC_ON_BOOT=1
[env:node_a]
build_flags =
${env.build_flags}
-D NODE_LABEL=\"A\"
[env:node_b]
build_flags =
${env.build_flags}
-D NODE_LABEL=\"B\"

View file

@ -0,0 +1,148 @@
// 20260212 ChatGPT
// $Id$
// $HeadURL$
#include <Arduino.h>
#include <SPI.h>
#include <RadioLib.h>
// --- Compile-time label ---
#ifndef NODE_LABEL
#define NODE_LABEL "?"
#endif
// --- Pins injected via platformio.ini build_flags ---
#ifndef LORA_CS
#error "LORA_CS not defined"
#endif
#ifndef LORA_DIO1
#error "LORA_DIO1 not defined"
#endif
#ifndef LORA_RESET
#error "LORA_RESET not defined"
#endif
#ifndef LORA_BUSY
#error "LORA_BUSY not defined"
#endif
// SX1262 on T-Beam Supreme (tbeam-s3-core pinout)
SX1262 radio = new Module(LORA_CS, LORA_DIO1, LORA_RESET, LORA_BUSY);
static volatile bool g_rx_flag = false;
static void onDio1Rise() {
g_rx_flag = true;
}
static void print_config() {
Serial.printf("Node=%s\n", NODE_LABEL);
Serial.printf("Pins: CS=%d DIO1=%d RST=%d BUSY=%d SCK=%d MISO=%d MOSI=%d\r\n",
(int)LORA_CS, (int)LORA_DIO1, (int)LORA_RESET, (int)LORA_BUSY,
(int)LORA_SCK, (int)LORA_MISO, (int)LORA_MOSI);
Serial.printf("LoRa: freq=915.0 BW=125 SF=7 CR=5 txp=14\r\n");
}
void setup() {
Serial.begin(115200);
delay(250);
Serial.println();
Serial.println("Exercise 01: LoRa ASCII ping-pong (serial only)");
// Ensure SPI pins match the variant
SPI.begin(LORA_SCK, LORA_MISO, LORA_MOSI, LORA_CS);
int state = radio.begin(915.0 /* MHz */, 125.0 /* kHz */, 7 /* SF */, 5 /* CR */, 0x12 /* sync */, 14 /* dBm */);
if (state != RADIOLIB_ERR_NONE) {
Serial.printf("ERROR: radio.begin failed, code=%d\r\n", state);
while (true) delay(1000);
}
// Match Meshtastic-like wiring assumptions for SX1262 modules:
// - DIO2 used as RF switch
// - TCXO at 1.8V
//OLD radio.setDio2AsRfSwitch(true);
//OLD radio.setTcxoVoltage((float)LORA_TCXO_VOLTAGE);
// below is replacement for above 2 lines:
//maybe_setDio2AsRfSwitch(radio, true);
//maybe_setTcxoVoltage(radio, (float)LORA_TCXO_VOLTAGE);
// end of replacement
// Set up RX interrupt
radio.setDio1Action(onDio1Rise);
// Start receiving
state = radio.startReceive();
if (state != RADIOLIB_ERR_NONE) {
Serial.printf("ERROR: startReceive failed, code=%d\r\n", state);
while (true) delay(1000);
}
print_config();
}
void loop() {
// Periodic TX (with a label-based offset to reduce collisions)
static uint32_t next_tx_ms = 0;
static uint32_t iter = 0;
uint32_t now = millis();
if (next_tx_ms == 0) {
// Offset A and B so they don't always collide
uint32_t offset = (NODE_LABEL[0] == 'A') ? 500 : 1500;
next_tx_ms = now + offset;
}
if ((int32_t)(now - next_tx_ms) >= 0) {
next_tx_ms = now + 2000; // 2 seconds for this smoke test
// String msg = String("I am ") + NODE_LABEL + " iter=" + String(iter++);
String msg = String(" ") + NODE_LABEL + " sends greetings. iter=" + String(iter++);
Serial.printf("TX: %s\r\n", msg.c_str());
//int tx = radio.transmit(msg);
//if (tx != RADIOLIB_ERR_NONE) {
// Serial.printf("TX ERROR code=%d\r\n", tx);
// }
// After transmit, resume RX
//radio.startReceive();
// DIO1 triggers on TX-done as well as RX-done.
// If left armed, TX completion looks like RX.
g_rx_flag = false;
radio.clearDio1Action();
int tx = radio.transmit(msg);
if (tx != RADIOLIB_ERR_NONE) {
Serial.printf("TX ERROR code=%d\r\n", tx);
}
// Re-arm RX interrupt and resume RX
g_rx_flag = false;
radio.setDio1Action(onDio1Rise);
radio.startReceive();
}
// RX handling
if (g_rx_flag) {
g_rx_flag = false;
String rx;
int state = radio.readData(rx);
if (state == RADIOLIB_ERR_NONE) {
Serial.printf("RX: %s | RSSI=%.1f SNR=%.1f\r\n",
rx.c_str(), radio.getRSSI(), radio.getSNR());
} else {
Serial.printf("RX ERROR code=%d\r\n", state);
}
// Keep receiving
radio.startReceive();
}
delay(5);
}

76
exercises/README.md Normal file
View file

@ -0,0 +1,76 @@
## Buttons
There are three buttons
![T-Beam SUPREME](../img/20260212_182225_Thu.png)
![](../img/20260212_182300_Thu.png)
From Antenna to USB port:
1) RESET
2) POWER
3) BOOT
![](../img/20260212_184521_Thu.png)
## RESET
The RESET button only needs to be depressed for less than 1 second. Doing so will cause the unit to reboot. If you have a "screen" monitor on the USB device, it will be disconnected. A good way to capture boot posting messages from within the unit is to have your command in a console ready to execute by depressing the RETURN key and you depress RETURN immediately after you depress the unit's RESET button, possibly allowing 1/2 second to allow kernel to recognize the new USB device, i.e. /dev/ttyACM0
## POWER
If your unit is powered OFF, simply depress the POWER button will start the unit. If the unit is powered ON, then depressing the POWER button and holding it down for 6 second will cause the unit to power down. The OLED display will go dark when the unit has successfully been powered down.
## BOOT
A) TODO: what happens when unit is powered ON?
B) TODO: what happens when unit is powered OFF?
C) To upload new binary image: depress the BOOT button and hold down, then while holding down the BOOT button disconnect the USB line and then reconnect the USB line and then lift up on the BOOT button. This will cause the unit to await an upload of an image to be stored in its FLASH memory. See further how to flash a new image in the section "Flashing Binary". Note: although the uploader may state it is trying to reset after successful installation of the new image, it seems that software attempt does not work and you have to manually depress the unit's RESET button to force a RESET. Remember, if you want to see the boot's posting, you should have your terminal ready to run "screen" so you capture the initial postings after you click RESET.
# Exercises
These are progressve tests you can run to confirm how to access the unit's functionality and validate your workbench.
Exercise 00: 00_usb_radio_check
Exercise 01: ASCII ping-pong over LoRa (serial only)
Exercise 02: Add OLED display
Exercise 03: Add SD logging
Exercise 04: Replace ASCII payload with microR packets
Exercise 05: SD provisioning with identity.bin, peer list, beacon
Each exercise is self-contained:
its own platformio.ini
its own src/main.cpp
its own README.md with exact commands
To clean:
pio run -t clean
Nuclear option:
rm -rf .pio
Rebuild:
pio run -e node_a
pio run -e node_b
## Upload existing firmware (will not recompile if unchanged)
### Upload node A (set your port)
pio run -e node_a -t upload --upload-port /dev/ttyACM0
### Upload node B
pio run -e node_b -t upload --upload-port /dev/ttyACM1
To monitor both:
screen /dev/ttyACM0 115200
screen /dev/ttyACM1 115200
Attach antennas (transmitting without antenna will cause power feedback and likely destroy your circuits)
Keep boards at least ~30 cm apart so you dont desense the receivers.
shared board pin headers in one place:
shared/
boards/
tbeam-s3-core_pins.h