Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 84 additions & 1 deletion variants/m5stack_unit_c6l/UnitC6LBoard.h
Original file line number Diff line number Diff line change
@@ -1,15 +1,98 @@

#pragma once

#include <Arduino.h>
#include <Wire.h>
#include <helpers/ESP32Board.h>

// PI4IOE5V6408 I2C GPIO expander - controls RF switch, LNA, and LoRa reset
// Sits on the internal I2C bus (SDA=10, SCL=8), which is configured as
// the primary Wire bus via PIN_BOARD_SDA/SCL in platformio.ini.
// ESP32-C6 only has ONE I2C hardware peripheral - do NOT use TwoWire(1).

#define PI4IO_ADDR 0x43
#define PI4IO_REG_CHIP_RESET 0x01
#define PI4IO_REG_IO_DIR 0x03
#define PI4IO_REG_OUT_SET 0x05
#define PI4IO_REG_OUT_H_IM 0x07
#define PI4IO_REG_IN_DEF_STA 0x09
#define PI4IO_REG_PULL_EN 0x0B
#define PI4IO_REG_PULL_SEL 0x0D
#define PI4IO_REG_INT_MASK 0x11
#define PI4IO_REG_IRQ_STA 0x13

class UnitC6LBoard : public ESP32Board {
public:
void begin() {
ESP32Board::begin();
ESP32Board::begin(); // This calls Wire.begin(10, 8) via PIN_BOARD_SDA/SCL
initGPIOExpander();
}

const char* getManufacturerName() const override {
return "Unit C6L";
}

private:
void i2cWrite(uint8_t reg, uint8_t value) {
Wire.beginTransmission(PI4IO_ADDR);
Wire.write(reg);
Wire.write(value);
Wire.endTransmission();
}

uint8_t i2cRead(uint8_t reg) {
Wire.beginTransmission(PI4IO_ADDR);
Wire.write(reg);
Wire.endTransmission();
Wire.requestFrom((uint8_t)PI4IO_ADDR, (uint8_t)1);
return Wire.read();
}


void initGPIOExpander() {
// Matches Meshtastic's c6l_init() in variant.cpp
// Uses Wire (already on SDA=10, SCL=8 from ESP32Board::begin)


// Reset expander
i2cWrite(PI4IO_REG_CHIP_RESET, 0xFF);
delay(10);
i2cRead(PI4IO_REG_CHIP_RESET);
delay(10);

// P6 (RF switch) and P7 (LoRa reset) as outputs
i2cWrite(PI4IO_REG_IO_DIR, 0b11000000);
delay(10);

// Disable high-impedance on P2-P5
i2cWrite(PI4IO_REG_OUT_H_IM, 0b00111100);
delay(10);

// Pull-up on P0, P1, P6, P7; pull-down on others
i2cWrite(PI4IO_REG_PULL_SEL, 0b11000011);
delay(10);
i2cWrite(PI4IO_REG_PULL_EN, 0b11000011);
delay(10);

// Button defaults (P0, P1 default HIGH - active low buttons)
i2cWrite(PI4IO_REG_IN_DEF_STA, 0b00000011);
delay(10);

// Interrupt mask: only P0, P1 generate interrupts
i2cWrite(PI4IO_REG_INT_MASK, 0b11111100);
delay(10);

// Set P7 HIGH (LoRa out of reset)
i2cWrite(PI4IO_REG_OUT_SET, 0b10000000);
delay(10);

// Clear pending IRQ
i2cRead(PI4IO_REG_IRQ_STA);

// Set P6 HIGH (RF switch -> routes antenna to LoRa)
uint8_t out = i2cRead(PI4IO_REG_OUT_SET);
out |= (1 << 6);
i2cWrite(PI4IO_REG_OUT_SET, out);

}
};
37 changes: 30 additions & 7 deletions variants/m5stack_unit_c6l/platformio.ini
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
[M5Stack_Unit_C6L]
extends = esp32c6_base
board = esp32-c6-devkitm-1
board_upload.flash_size = 16MB
board_build.flash_size = 16MB
board_build.partitions = min_spiffs.csv ; get around 4mb flash limit
build_flags =
${esp32c6_base.build_flags}
${sensor_base.build_flags}
-I variants/m5stack_unit_c6l
-D P_LORA_TX_LED=15
; P_LORA_TX_LED removed - GPIO15 is SSD1306 OLED reset pin, not a TX LED
; (C6L has WS2812C RGB LED on GPIO2, no discrete TX LED)
-D P_LORA_SCLK=20
-D P_LORA_MISO=22
-D P_LORA_MOSI=21
Expand All @@ -15,19 +18,19 @@ build_flags =
-D P_LORA_BUSY=19
-D P_LORA_RESET=-1
-D PIN_BUZZER=11
-D PIN_BOARD_SDA=16
-D PIN_BOARD_SCL=17
-D SX126X_RXEN=5
; I2C bus: primary bus goes to PI4IOE5V6408 GPIO expander (internal)
; ESP32-C6 only has ONE I2C hardware peripheral, so Wire must be on these pins.
-D PIN_BOARD_SDA=10
-D PIN_BOARD_SCL=8
; SX126X_RXEN removed - RF switch is on I2C expander (PI4IOE5V6408), not ESP32 GPIO
-D SX126X_DIO2_AS_RF_SWITCH=true
-D SX126X_DIO3_TCXO_VOLTAGE=1.8
-D SX126X_DIO3_TCXO_VOLTAGE=3.0
-D SX126X_CURRENT_LIMIT=140
-D SX126X_RX_BOOSTED_GAIN=1
-D RADIO_CLASS=CustomSX1262
-D WRAPPER_CLASS=CustomSX1262Wrapper
-D LORA_TX_POWER=22
-D DISABLE_WIFI_OTA=1
-D GPS_RX=4
-D GPS_TX=5
build_src_filter = ${esp32c6_base.build_src_filter}
+<../variants/m5stack_unit_c6l>
+<UnitC6LBoard.cpp>
Expand Down Expand Up @@ -88,6 +91,26 @@ lib_deps =
densaugeo/base64 @ ~1.4.0
end2endzone/NonBlockingRTTTL@^1.3.0

[env:M5Stack_Unit_C6L_companion_radio_wifi]
extends = M5Stack_Unit_C6L
build_flags = ${M5Stack_Unit_C6L.build_flags}
-D MAX_CONTACTS=350
-D MAX_GROUP_CHANNELS=40
-D WIFI_DEBUG_LOGGING=1
-D WIFI_SSID='"myssid"'
-D WIFI_PWD='"mypwd"'
-D OFFLINE_QUEUE_SIZE=256
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
build_src_filter = ${M5Stack_Unit_C6L.build_src_filter}
+<helpers/esp32/*.cpp>
-<helpers/esp32/ESPNOWRadio.cpp>
+<../examples/companion_radio/*.cpp>
lib_deps =
${M5Stack_Unit_C6L.lib_deps}
densaugeo/base64 @ ~1.4.0
end2endzone/NonBlockingRTTTL@^1.3.0

[env:M5Stack_Unit_C6L_companion_radio_usb]
extends = M5Stack_Unit_C6L
build_flags = ${M5Stack_Unit_C6L.build_flags}
Expand Down