Browse Source

wip

pull/2568/head
Christos Themelis 3 months ago
parent
commit
da3d734e4b
  1. 32
      examples/simple_secure_chat_ui/main.cpp
  2. 76
      src/helpers/esp32/SenseCapHAL.h
  3. 10
      variants/sensecap_indicator-espnow/target.cpp

32
examples/simple_secure_chat_ui/main.cpp

@ -848,9 +848,11 @@ void initializeMesh() {
Serial.println("[mesh] the_mesh.begin() done");
float freq = the_mesh.getFreqPref();
uint8_t txpwr = the_mesh.getTxPowerPref();
Serial.printf("[mesh] Radio params: freq=%.3f MHz BW=%d SF=%d CR=%d TX=%d dBm\n",
freq, LORA_BW, LORA_SF, LORA_CR, txpwr);
// Always use the build-defined TX power; saved prefs may contain a stale
// value from a previous firmware version with a different default.
uint8_t txpwr = LORA_TX_POWER;
Serial.printf("[mesh] Radio params: freq=%.3f MHz BW=%.1f SF=%d CR=%d TX=%d dBm\n",
freq, (float)LORA_BW, (int)LORA_SF, (int)LORA_CR, (int)txpwr);
radio_set_params(freq, LORA_BW, LORA_SF, LORA_CR);
radio_set_tx_power(txpwr);
@ -884,10 +886,32 @@ void setup() {
initializeUI();
createTasks();
lv_timer_handler();
// ── Let LVGL render the initial UI before suspending ───────────────────────
// configureDisplay() fills the RGB framebuffer with black. LVGL needs at
// least one lv_timer_handler() cycle to paint the initial screen into that
// framebuffer. Since lvgl_task (Core 0) runs in parallel with setup()
// (Core 1), a short delay here gives it time to complete the first render,
// so the display shows the UI rather than a blank screen during radio init.
delay(100);
// ── Suspend LVGL task before radio init ────────────────────────────────────
// radio_init() calls Wire.end()/Wire.begin() while the LVGL touch callback
// (my_touchpad_read) also accesses Wire. Suspending lvgl_task eliminates
// the race; the I2C mutex (g_i2c_mutex) guards all Wire access once it is
// created inside radio_init().
Serial.println("[setup] Suspending LVGL task for radio init...");
vTaskSuspend(t_core0_lvgl);
initializeMesh();
// Mark entire LVGL screen dirty so the first lv_timer_handler() tick
// after resume flushes the full UI.
lv_obj_invalidate(lv_scr_act());
Serial.println("[setup] Resuming LVGL task...");
vTaskResume(t_core0_lvgl);
vTaskResume(t_core1_core);
Serial.println("Setup completed");

76
src/helpers/esp32/SenseCapHAL.h

@ -28,6 +28,7 @@
#include <SPI.h>
#include <freertos/FreeRTOS.h>
#include <freertos/semphr.h>
#include <driver/gpio.h>
class SenseCapHAL : public ArduinoHal {
TwoWire* _wire;
@ -111,19 +112,76 @@ public:
}
// ── Overrides ──────────────────────────────────────────────────────────
//
// SOFTWARE SPI — we bit-bang GPIO 41/47/48 directly instead of using
// the hardware FSPI peripheral. Calling spi.begin(41,47,48) routes
// those pins through the ESP32-S3 GPIO matrix to FSPI, which silently
// disables LovyanGFX's LCD_CAM framebuffer output (blank display).
// Software SPI avoids that conflict entirely; the SX1262 works fine
// at the ~500 kHz rate the bit-bang produces.
// ArduinoHal::init() only calls spiBegin() when initInterface==true,
// which is false when an explicit SPIClass& is supplied. Override to
// always call our spiBegin().
void init() override { spiBegin(); }
// Initialize SPI with the correct pin numbers for SenseCAP Indicator.
void spiBegin() override {
this->spi->begin(_sclk, _miso, _mosi);
Serial.printf("[SenseCapHAL] SPI begin: SCLK=%d MISO=%d MOSI=%d\n",
_sclk, _miso, _mosi);
// ── IMPORTANT ──────────────────────────────────────────────────────────
// We must NOT call ::pinMode() here. ::pinMode() calls gpio_reset_pin()
// which disrupts the GPIO matrix signal routing used by LovyanGFX's
// Bus_RGB LCD_CAM driver — blanking the display permanently.
//
// We also must NOT use gpio_set_direction() alone: it does not call
// PIN_FUNC_SELECT, so the IO_MUX for GPIO 41/48 may remain pointed at
// the JTAG MTDI/MTCK function (restored by LovyanGFX's pin_backup_t
// after lcd.begin()). With IO_MUX in JTAG function the physical pins
// bypass the GPIO matrix entirely, making soft-SPI write nothing.
//
// Fix: gpio_config() sets IO_MUX → PIN_FUNC_GPIO (via PIN_FUNC_SELECT)
// AND enables GPIO output via the GPIO matrix (SIG_GPIO_OUT_IDX), all
// without ever calling gpio_reset_pin().
// ───────────────────────────────────────────────────────────────────────
gpio_config_t out_conf = {};
out_conf.pin_bit_mask = (1ULL << _sclk) | (1ULL << _mosi);
out_conf.mode = GPIO_MODE_OUTPUT;
out_conf.pull_up_en = GPIO_PULLUP_DISABLE;
out_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
out_conf.intr_type = GPIO_INTR_DISABLE;
gpio_config(&out_conf);
gpio_config_t in_conf = {};
in_conf.pin_bit_mask = (1ULL << _miso);
in_conf.mode = GPIO_MODE_INPUT;
in_conf.pull_up_en = GPIO_PULLUP_DISABLE;
in_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
in_conf.intr_type = GPIO_INTR_DISABLE;
gpio_config(&in_conf);
gpio_set_level((gpio_num_t)_sclk, 0);
gpio_set_level((gpio_num_t)_mosi, 0);
Serial.printf("[SenseCapHAL] SPI (soft) SCLK=%d MOSI=%d MISO=%d\n",
_sclk, _mosi, _miso);
}
// ArduinoHal::init() only calls spiBegin() when initInterface==true,
// which is NOT set when an explicit SPIClass& is passed to the constructor.
// Override init() to always initialise SPI with our custom pins.
void init() override {
spiBegin();
void spiBeginTransaction() override { /* no-op for soft SPI */ }
void spiEndTransaction() override { /* no-op for soft SPI */ }
void spiEnd() override { /* no-op for soft SPI */ }
// SPI Mode 0: CPOL=0 (CLK idles LOW), CPHA=0 (sample on rising edge)
void spiTransfer(uint8_t* out, size_t len, uint8_t* in) override {
for (size_t i = 0; i < len; i++) {
uint8_t txByte = out ? out[i] : 0xFF;
uint8_t rxByte = 0;
for (int b = 7; b >= 0; b--) {
::digitalWrite(_mosi, (txByte >> b) & 1);
::delayMicroseconds(1); // MOSI setup time
::digitalWrite(_sclk, HIGH);
rxByte |= (uint8_t)(::digitalRead(_miso) << b); // sample on rising edge
::delayMicroseconds(1); // hold time
::digitalWrite(_sclk, LOW);
}
if (in) in[i] = rxByte;
}
}
void pinMode(uint32_t pin, uint32_t mode) override {

10
variants/sensecap_indicator-espnow/target.cpp

@ -61,11 +61,11 @@ ESP32Board board;
#define LORA_DIO1 (3 | IO_EXPANDER) // TCA9535 port-0 pin 3 (0x43)
// → interrupt fires on GPIO 42
static SPIClass spi(FSPI);
// Custom RadioLib HAL: routes expander pins through TCA9535 (I2C 0x20)
// and inits SPI with the correct pins on first use.
static SenseCapHAL radio_hal(spi, LORA_SCLK, LORA_MISO, LORA_MOSI, 0x20, &Wire);
// Custom RadioLib HAL: routes expander pins through TCA9535 (I2C 0x20).
// Uses software (bit-bang) SPI on SCLK/MOSI/MISO to avoid taking the
// hardware FSPI peripheral, which would disrupt LovyanGFX's LCD_CAM output.
// SPI is passed as a placeholder only — all SPI methods are overridden.
static SenseCapHAL radio_hal(SPI, LORA_SCLK, LORA_MISO, LORA_MOSI, 0x20, &Wire);
// SX1262 module using the custom HAL
RADIO_CLASS radio = new Module(&radio_hal, LORA_NSS, LORA_DIO1, LORA_RESET, LORA_BUSY);

Loading…
Cancel
Save