update: improve documentation and restructure code for modular hardware integration, add CAN communication to HAL, and update KiCad layouts

This commit is contained in:
2026-01-23 22:02:14 +01:00
parent 1de40085fb
commit 0c0b62e2ed
18 changed files with 486 additions and 219 deletions

View File

@@ -541,15 +541,15 @@ impl PlantHal {
}
};
let board_hal: Box<dyn BoardInteraction + Send> = match config.hardware.board {
BoardVersion::Initial => {
initial_hal::create_initial_board(free_pins, config, esp)?
}
BoardVersion::V4 => {
let board_hal: Box<dyn BoardInteraction + Send> = //match config.hardware.board {
//BoardVersion::Initial => {
// initial_hal::create_initial_board(free_pins, config, esp)?
//}
//BoardVersion::V4 => {
v4_hal::create_v4(free_pins, esp, config, battery_interaction, rtc_module)
.await?
}
};
.await?;
//}
//};
HAL { board_hal }
}
@@ -566,11 +566,9 @@ impl PlantHal {
)
.await;
HAL {
board_hal: initial_hal::create_initial_board(
free_pins,
PlantControllerConfig::default(),
esp,
)?,
board_hal: v4_hal::create_v4(free_pins, esp, PlantControllerConfig::default(),
Box::new(NoBatteryMonitor {}), rtc_module)
.await?
}
}
};

View File

@@ -22,6 +22,7 @@ use embassy_time::{Duration, Timer, WithTimeout};
use embedded_can::{Frame, Id};
use esp_hal::gpio::{Flex, Input, InputConfig, Level, Output, OutputConfig, Pull};
use esp_hal::i2c::master::I2c;
use esp_hal::peripherals;
use esp_hal::twai::{EspTwaiError, EspTwaiFrame, StandardId, Twai, TwaiConfiguration, TwaiMode};
use esp_hal::{twai, Async, Blocking};
use ina219::address::{Address, Pin};
@@ -129,7 +130,9 @@ pub struct V4<'a> {
pump_ina: Option<
SyncIna219<I2cDevice<'a, CriticalSectionRawMutex, I2c<'static, Blocking>>, UnCalibrated>,
>,
twai_config: Option<TwaiConfiguration<'static, Blocking>>,
twai_peripheral: Option<esp_hal::peripherals::TWAI0<'static>>,
twai_rx_pin: Option<esp_hal::peripherals::GPIO2<'static>>,
twai_tx_pin: Option<esp_hal::peripherals::GPIO0<'static>>,
can_power: Output<'static>,
extra1: Output<'a>,
@@ -150,6 +153,12 @@ pub(crate) async fn create_v4(
let mut general_fault = Output::new(peripherals.gpio23, Level::Low, OutputConfig::default());
general_fault.set_low();
let twai_peripheral = Some(peripherals.twai);
let twai_rx_pin = Some(peripherals.gpio2);
let twai_tx_pin = Some(peripherals.gpio0);
let extra1 = Output::new(peripherals.gpio6, Level::Low, OutputConfig::default());
let extra2 = Output::new(peripherals.gpio15, Level::Low, OutputConfig::default());
@@ -169,19 +178,13 @@ pub(crate) async fn create_v4(
peripherals.pcnt1,
)?;
let twai_config = Some(TwaiConfiguration::new(
peripherals.twai,
peripherals.gpio2,
peripherals.gpio0,
TWAI_BAUDRATE,
TwaiMode::Normal,
));
let can_power = Output::new(peripherals.gpio22, Level::Low, OutputConfig::default());
let solar_is_day = Input::new(peripherals.gpio7, InputConfig::default());
let light = Output::new(peripherals.gpio10, Level::Low, Default::default());
let charge_indicator = Output::new(peripherals.gpio3, Level::Low, Default::default());
info!("Start pump expander");
let pump_device = I2cDevice::new(I2C_DRIVER.get().await);
let mut pump_expander = Pca9535Immediate::new(pump_device, 32);
for pin in 0..8 {
@@ -191,6 +194,7 @@ pub(crate) async fn create_v4(
let _ = pump_expander.pin_set_low(GPIOBank::Bank1, pin);
}
info!("Start mppt");
let mppt_current = I2cDevice::new(I2C_DRIVER.get().await);
let mppt_ina = match SyncIna219::new(mppt_current, Address::from_pins(Pin::Vcc, Pin::Gnd)) {
Ok(mut ina) => {
@@ -211,6 +215,7 @@ pub(crate) async fn create_v4(
}
};
info!("Start pump current sensor");
let pump_current_dev = I2cDevice::new(I2C_DRIVER.get().await);
let pump_ina = match SyncIna219::new(pump_current_dev, Address::from_pins(Pin::Gnd, Pin::Sda)) {
Ok(ina) => Some(ina),
@@ -252,15 +257,37 @@ pub(crate) async fn create_v4(
config,
battery_monitor,
pump_ina,
twai_config,
twai_peripheral,
twai_rx_pin,
twai_tx_pin,
charger,
extra1,
extra2,
can_power
can_power,
};
Ok(Box::new(v))
}
impl<'a> V4<'a> {
fn teardown_twai(&mut self, old: TwaiConfiguration<Blocking>) {
drop(old);
// Re-acquire the peripheral and pins
let twai = unsafe { peripherals::TWAI0::steal() };
let rx_pin = unsafe { peripherals::GPIO2::steal() };
let tx_pin = unsafe { peripherals::GPIO0::steal() };
// Set pins to low to avoid parasitic powering
let mut rx = Input::new(rx_pin, InputConfig::default().with_pull(Pull::None));
let mut tx = Input::new(tx_pin, InputConfig::default().with_pull(Pull::None));
// Release the pins from Output back to raw pins and store everything
self.twai_peripheral = Some(twai);
self.twai_rx_pin = Some(unsafe { peripherals::GPIO2::steal() });
self.twai_tx_pin = Some(unsafe { peripherals::GPIO0::steal() });
self.can_power.set_low();
}
}
#[async_trait(?Send)]
impl<'a> BoardInteraction<'a> for V4<'a> {
fn get_tank_sensor(&mut self) -> Result<&mut TankSensor<'a>, FatError> {
@@ -352,8 +379,14 @@ impl<'a> BoardInteraction<'a> for V4<'a> {
}
async fn measure_moisture_hz(&mut self) -> FatResult<Moistures> {
self.can_power.set_high();
let config = self.twai_config.take().expect("twai config not set");
let mut twai = config.into_async().start();
let twai_config = TwaiConfiguration::new(
self.twai_peripheral.take().unwrap(),
self.twai_rx_pin.take().unwrap(),
self.twai_tx_pin.take().unwrap(),
TWAI_BAUDRATE,
TwaiMode::Normal,
);
let mut twai = twai_config.into_async().start();
loop {
let rec = twai.receive();
@@ -372,11 +405,7 @@ impl<'a> BoardInteraction<'a> for V4<'a> {
let _ = wait_for_can_measurements(&mut twai, &mut moistures)
.with_timeout(Duration::from_millis(2000))
.await;
self.can_power.set_low();
let config = twai.stop().into_blocking();
self.twai_config.replace(config);
self.teardown_twai(twai.stop().into_blocking());
Ok(moistures)
}
@@ -445,9 +474,17 @@ impl<'a> BoardInteraction<'a> for V4<'a> {
async fn detect_sensors(&mut self) -> FatResult<DetectionResult> {
// Power on CAN transceiver and start controller
self.can_power.set_high();
let config = self.twai_config.take().expect("twai config not set");
let twai_config = TwaiConfiguration::new(
self.twai_peripheral.take().unwrap(),
self.twai_rx_pin.take().unwrap(),
self.twai_tx_pin.take().unwrap(),
TWAI_BAUDRATE,
TwaiMode::Normal,
);
info!("convert can");
let mut as_async = config.into_async().start();
let mut as_async = twai_config.into_async().start();
// Give CAN some time to stabilize
Timer::after_millis(10).await;
@@ -487,8 +524,7 @@ impl<'a> BoardInteraction<'a> for V4<'a> {
.await;
let config = as_async.stop().into_blocking();
self.can_power.set_low();
self.twai_config.replace(config);
self.teardown_twai(config);
let result = moistures.into();

View File

@@ -186,7 +186,6 @@ fn limit_length<const LIMIT: usize>(input: &str, target: &mut heapless::String<L
)
}
}
return;
}
}
}