Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support current sensing on MK7 #184

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
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
1 change: 1 addition & 0 deletions platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@ board = esp32-s3-wroom-1-n16
board_build.partitions = partitions.csv
lib_deps =
${esp32base.lib_deps}
RobTillaart/INA219 @ ^0.4.0
build_flags =
${esp32base.build_flags}
-DMK7
Expand Down
5 changes: 3 additions & 2 deletions src/devices/Device.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -275,9 +275,10 @@ class ConfiguredKernel {
}
}

TDeviceDefinition deviceDefinition;
I2CManager i2c;
TDeviceDefinition deviceDefinition { i2c };
ConsoleProvider consoleProvider;
Kernel<TDeviceConfiguration> kernel { deviceDefinition.config, deviceDefinition.mqttConfig, deviceDefinition.statusLed };
Kernel<TDeviceConfiguration> kernel { i2c, deviceDefinition.config, deviceDefinition.mqttConfig, deviceDefinition.statusLed };
const shared_ptr<BatteryDriver> battery;
};

Expand Down
6 changes: 3 additions & 3 deletions src/devices/UglyDucklingMk4.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ static gpio_num_t TXD0 = Pin::registerPin("TXD0", GPIO_NUM_43);

class UglyDucklingMk4 : public DeviceDefinition<Mk4Config> {
public:
UglyDucklingMk4()
UglyDucklingMk4(I2CManager& i2c)
: DeviceDefinition<Mk4Config>(
pins::STATUS,
pins::BOOT) {
Expand Down Expand Up @@ -96,8 +96,8 @@ class UglyDucklingMk4 : public DeviceDefinition<Mk4Config> {
pins::VALVE_SLEEP
};

const ServiceRef<PwmMotorDriver> motor { "motor", motorDriver };
const std::list<ServiceRef<PwmMotorDriver>> motors { motor };
const ServiceRef<CurrentSensingMotorDriver> motor { "motor", motorDriver };
const ServiceContainer<CurrentSensingMotorDriver> motors { { motor } };

ValveFactory valveFactory { motors, ValveControlStrategyType::NormallyClosed };
FlowMeterFactory flowMeterFactory;
Expand Down
8 changes: 4 additions & 4 deletions src/devices/UglyDucklingMk5.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ static gpio_num_t TXD0 = Pin::registerPin("TXD0", GPIO_NUM_43);

class UglyDucklingMk5 : public DeviceDefinition<Mk5Config> {
public:
UglyDucklingMk5()
UglyDucklingMk5(I2CManager& i2c)
: DeviceDefinition<Mk5Config>(
pins::STATUS,
pins::BOOT) {
Expand Down Expand Up @@ -108,9 +108,9 @@ class UglyDucklingMk5 : public DeviceDefinition<Mk5Config> {
pins::NSLEEP
};

const ServiceRef<PwmMotorDriver> motorA { "a", motorADriver };
const ServiceRef<PwmMotorDriver> motorB { "b", motorBDriver };
const std::list<ServiceRef<PwmMotorDriver>> motors { motorA, motorB };
const ServiceRef<CurrentSensingMotorDriver> motorA { "a", motorADriver };
const ServiceRef<CurrentSensingMotorDriver> motorB { "b", motorBDriver };
const ServiceContainer<CurrentSensingMotorDriver> motors { { motorA, motorB } };

ValveFactory valveFactory { motors, ValveControlStrategyType::Latching };
FlowMeterFactory flowMeterFactory;
Expand Down
13 changes: 9 additions & 4 deletions src/devices/UglyDucklingMk6.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <kernel/Kernel.hpp>
#include <kernel/Service.hpp>
#include <kernel/drivers/BatteryDriver.hpp>
#include <kernel/drivers/CurrentSenseDriver.hpp>
#include <kernel/drivers/Drv8833Driver.hpp>
#include <kernel/drivers/LedDriver.hpp>

Expand Down Expand Up @@ -86,7 +87,7 @@ class Mk6Config

class UglyDucklingMk6 : public DeviceDefinition<Mk6Config> {
public:
UglyDucklingMk6()
UglyDucklingMk6(I2CManager& i2c)
: DeviceDefinition<Mk6Config>(
pins::STATUS,
pins::BOOT) {
Expand Down Expand Up @@ -119,9 +120,13 @@ class UglyDucklingMk6 : public DeviceDefinition<Mk6Config> {
config.motorNSleepPin.get()
};

const ServiceRef<PwmMotorDriver> motorA { "a", motorDriver.getMotorA() };
const ServiceRef<PwmMotorDriver> motorB { "b", motorDriver.getMotorB() };
const std::list<ServiceRef<PwmMotorDriver>> motors { motorA, motorB };
SimpleCurrentSenseDriver currentSense { pins::DIPROPI };
ExternalCurrentSensingMotorDriver motorADriver { motorDriver.getMotorA(), currentSense };
ExternalCurrentSensingMotorDriver motorBDriver { motorDriver.getMotorB(), currentSense };

const ServiceRef<CurrentSensingMotorDriver> motorA { "a", motorADriver };
const ServiceRef<CurrentSensingMotorDriver> motorB { "b", motorBDriver };
const ServiceContainer<CurrentSensingMotorDriver> motors { { motorA, motorB } };

ValveFactory valveFactory { motors, ValveControlStrategyType::Latching };
FlowMeterFactory flowMeterFactory;
Expand Down
16 changes: 11 additions & 5 deletions src/devices/UglyDucklingMk7.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <kernel/Service.hpp>
#include <kernel/drivers/Bq27220Driver.hpp>
#include <kernel/drivers/Drv8833Driver.hpp>
#include <kernel/drivers/Ina219Driver.hpp>
#include <kernel/drivers/LedDriver.hpp>

#include <peripherals/Peripheral.hpp>
Expand Down Expand Up @@ -84,10 +85,11 @@ class Mk7Config

class UglyDucklingMk7 : public DeviceDefinition<Mk7Config> {
public:
UglyDucklingMk7()
UglyDucklingMk7(I2CManager& i2c)
: DeviceDefinition<Mk7Config>(
pins::STATUS,
pins::BOOT) {
pins::BOOT)
, currentSense(i2c, pins::SDA, pins::SCL) {
}

virtual std::shared_ptr<BatteryDriver> createBatteryDriver(I2CManager& i2c) override {
Expand All @@ -113,9 +115,13 @@ class UglyDucklingMk7 : public DeviceDefinition<Mk7Config> {
pins::LOADEN,
};

const ServiceRef<PwmMotorDriver> motorA { "a", motorDriver.getMotorA() };
const ServiceRef<PwmMotorDriver> motorB { "b", motorDriver.getMotorB() };
const std::list<ServiceRef<PwmMotorDriver>> motors { motorA, motorB };
Ina219Driver currentSense;
ExternalCurrentSensingMotorDriver motorADriver { motorDriver.getMotorA(), currentSense };
ExternalCurrentSensingMotorDriver motorBDriver { motorDriver.getMotorB(), currentSense };

const ServiceRef<CurrentSensingMotorDriver> motorA { "a", motorADriver };
const ServiceRef<CurrentSensingMotorDriver> motorB { "b", motorBDriver };
const ServiceContainer<CurrentSensingMotorDriver> motors { { motorA, motorB } };

ValveFactory valveFactory { motors, ValveControlStrategyType::Latching };
FlowMeterFactory flowMeterFactory;
Expand Down
78 changes: 77 additions & 1 deletion src/kernel/I2CManager.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

#include <map>
#include <utility>
#include <exception>

#include <Arduino.h>
#include <Wire.h>
Expand All @@ -25,8 +24,85 @@ struct I2CConfig {
}
};

class I2CAccessor {
public:
I2CAccessor(TwoWire& wire, uint8_t address)
: wire(wire)
, address(address) {
}

bool begin() {
wire.beginTransmission(address);
return wire.endTransmission() == 0;
}

bool readFrom(uint8_t reg, uint8_t* buffer, size_t length) {
wire.beginTransmission(address);
wire.write(reg);
auto txResult = wire.endTransmission();
if (txResult != 0) {
Log.error("Failed to write to 0x%02x: %d", reg, txResult);
return false;
}

auto rxResult = wire.requestFrom(address, (uint8_t) length);
if (rxResult != length) {
Log.error("Failed to read from 0x%02x: %d", reg, rxResult);
return false;
}
for (size_t i = 0; i < length; i++) {
buffer[i] = wire.read();
// Log.trace("Read 0x%02x from 0x%02x", buffer[i], reg);
}
return true;
}

bool writeTo(uint8_t reg, const uint8_t* buffer, size_t length) {
wire.beginTransmission(address);
wire.write(reg);
for (size_t i = 0; i < length; i++) {
// Log.trace("Writing 0x%02x to 0x%02x", buffer[i], reg);
wire.write(buffer[i]);
}
return wire.endTransmission() == 0;
}

uint8_t readByte(uint8_t reg) {
uint8_t buffer;
readFrom(reg, &buffer, 1);
return buffer;
}

uint16_t readWord(uint8_t reg) {
uint16_t buffer;
readFrom(reg, reinterpret_cast<uint8_t*>(&buffer), 2);
return buffer;
}

int16_t readSignedWord(uint8_t reg) {
return static_cast<int16_t>(readWord(reg));
}

bool writeWord(uint8_t reg, uint16_t value) {
uint16_t buffer = value;
return writeTo(reg, reinterpret_cast<uint8_t*>(&buffer), 2);
}

private:
TwoWire& wire;
uint8_t address;
};

class I2CManager {
public:
I2CAccessor getAccessorFor(const I2CConfig& config) {
return getAccessorFor(config.sda, config.scl, config.address);
}

I2CAccessor getAccessorFor(gpio_num_t sda, gpio_num_t scl, uint8_t address) {
return I2CAccessor(getWireFor(sda, scl), address);
}

TwoWire& getWireFor(const I2CConfig& config) {
return getWireFor(config.sda, config.scl);
}
Expand Down
5 changes: 3 additions & 2 deletions src/kernel/Kernel.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,10 @@ static const String& getMacAddress() {
template <typename TDeviceConfiguration>
class Kernel {
public:
Kernel(TDeviceConfiguration& deviceConfig, MqttDriver::Config& mqttConfig, LedDriver& statusLed)
Kernel(I2CManager i2c, TDeviceConfiguration& deviceConfig, MqttDriver::Config& mqttConfig, LedDriver& statusLed)
: version(VERSION)
, deviceConfig(deviceConfig)
, i2c(i2c)
, mqttConfig(mqttConfig)
, statusLed(statusLed) {

Expand Down Expand Up @@ -258,6 +259,7 @@ class Kernel {
TDeviceConfiguration& deviceConfig;

public:
I2CManager i2c;
SleepManager sleepManager { deviceConfig.sleepWhenIdle.get() };

private:
Expand Down Expand Up @@ -286,7 +288,6 @@ class Kernel {
public:
MqttDriver mqtt { networkReadyState, mdns, mqttConfig, deviceConfig.instance.get(), mqttReadyState };
SwitchManager switches;
I2CManager i2c;
};

} // namespace farmhub::kernel
73 changes: 10 additions & 63 deletions src/kernel/drivers/Bq27220Driver.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,13 @@ namespace farmhub::kernel::drivers {

class Bq27220Driver : public BatteryDriver {
public:
Bq27220Driver(I2CManager& i2c, gpio_num_t sda, gpio_num_t scl, const uint8_t address = 0x55)
: wire(i2c.getWireFor(sda, scl))
Bq27220Driver(I2CManager& i2cManager, gpio_num_t sda, gpio_num_t scl, const uint8_t address = 0x55)
: i2c(i2cManager.getAccessorFor(sda, scl, address))
, address(address) {
Log.info("Initializing BQ27220 driver on SDA %d, SCL %d",
sda, scl);

wire.beginTransmission(address);
if (wire.endTransmission() != 0) {
if (!i2c.begin()) {
// TODO Throw an actual exception?
Log.error("BQ27220 not found at address 0x%02x", address);
return;
Expand All @@ -38,86 +37,34 @@ class Bq27220Driver : public BatteryDriver {

float getVoltage() override {
// Log.trace("Capacityt: %d/%d", readWord(0x10), readWord(0x12));
return readWord(0x08) / 1000.0;
return i2c.readWord(0x08) / 1000.0;
}

float getCurrent() {
return readSigned(0x0C) / 1.0;
return i2c.readSignedWord(0x0C) / 1.0;
}

float getTemperature() {
return readWord(0x06) * 0.1 - 273.2;
return i2c.readWord(0x06) * 0.1 - 273.2;
}

protected:
void populateTelemetry(JsonObject& json) override {
BatteryDriver::populateTelemetry(json);
json["current"] = getCurrent();
auto status = readWord(0x0A);
auto status = i2c.readWord(0x0A);
json["status"] = status;
json["charging"] = (status & 0x0001) == 0;
json["temperature"] = getTemperature();
}

private:
bool readFrom(uint8_t reg, uint8_t* buffer, size_t length) {
wire.beginTransmission(address);
wire.write(reg);
auto txResult = wire.endTransmission();
if (txResult != 0) {
Log.error("Failed to write to 0x%02x: %d", reg, txResult);
return false;
}

auto rxResult = wire.requestFrom(address, (uint8_t) length);
if (rxResult != length) {
Log.error("Failed to read from 0x%02x: %d", reg, rxResult);
return false;
}
for (size_t i = 0; i < length; i++) {
buffer[i] = wire.read();
// Log.trace("Read 0x%02x from 0x%02x", buffer[i], reg);
}
return true;
}

bool writeTo(uint8_t reg, const uint8_t* buffer, size_t length) {
wire.beginTransmission(address);
wire.write(reg);
for (size_t i = 0; i < length; i++) {
// Log.trace("Writing 0x%02x to 0x%02x", buffer[i], reg);
wire.write(buffer[i]);
}
return wire.endTransmission() == 0;
}

uint8_t readByte(uint8_t reg) {
uint8_t buffer;
readFrom(reg, &buffer, 1);
return buffer;
}

uint16_t readWord(uint8_t reg) {
uint16_t buffer;
readFrom(reg, reinterpret_cast<uint8_t*>(&buffer), 2);
return buffer;
}

int16_t readSigned(uint8_t reg) {
return static_cast<int16_t>(readWord(reg));
}

bool writeWord(uint8_t reg, uint16_t value) {
uint16_t buffer = value;
return writeTo(reg, reinterpret_cast<uint8_t*>(&buffer), 2);
}

uint16_t readControlWord(uint16_t subcommand) {
writeWord(0x00, subcommand);
return readByte(0x40) | (readByte(0x41) << 8);
i2c.writeWord(0x00, subcommand);
return i2c.readByte(0x40) | (i2c.readByte(0x41) << 8);
}

TwoWire& wire;
I2CAccessor i2c;
const uint8_t address;
};

Expand Down
29 changes: 29 additions & 0 deletions src/kernel/drivers/CurrentSenseDriver.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#pragma once

#include <Arduino.h>

namespace farmhub::kernel::drivers {
class CurrentSenseDriver {

public:
virtual double readCurrent() = 0;
};

class SimpleCurrentSenseDriver
: public CurrentSenseDriver {
public:
SimpleCurrentSenseDriver(gpio_num_t pin, double scale = 4096)
: pin(pin)
, scale(scale) {
pinMode(pin, INPUT);
}

double readCurrent() override {
return analogRead(pin) / scale;
}

private:
gpio_num_t pin;
double scale;
};
} // namespace farmhub::kernel::drivers
Loading
Loading