Skip to content

Commit

Permalink
supporting I2C CAN Bus, MCP2515 and CAN0 for batteries and charger
Browse files Browse the repository at this point in the history
  • Loading branch information
skippermeister committed Aug 16, 2024
1 parent ed51c3e commit db20f07
Show file tree
Hide file tree
Showing 44 changed files with 918 additions and 446 deletions.
18 changes: 9 additions & 9 deletions docs/DeviceProfiles/ESP32_S3_USB_CMT_HUAWEI.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@
"rs232_tx3": -1
},
"battery": {
"rs232_tx": 47,
"rs232_rx": 45,
"rs232_tx": 45,
"rs232_rx": 47,
"wakeup": 21
},
"charger": {
Expand Down Expand Up @@ -79,9 +79,9 @@
"rs232_tx3": -1
},
"battery": {
"rs232_tx": 47,
"rs232_rx": 45,
"wakeup": 21
"rs485_tx": 45,
"rs485_rx": 47,
"rs485_rts": 21
},
"charger": {
"can0_rx": 3,
Expand Down Expand Up @@ -130,15 +130,15 @@
"rs232_tx3": -1
},
"battery": {
"rs485_tx": 47,
"rs485_rx": 45,
"rs485_tx": 45,
"rs485_rx": 47,
"rs485_rts": 21
},
"charger": {
"mcp2515_irq": 4,
"mcp2515_clk": 5,
"mcp2515_miso": 6,
"mcp2515_mosi": 7,
"mcp2515_mosi": 6,
"mcp2515_miso": 7,
"mcp2515_cs": 15,
"power": 16
},
Expand Down
4 changes: 3 additions & 1 deletion include/BatteryCanReceiver.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <driver/twai.h>
#include <SPI.h>
#include <mcp_can.h>
#include <Longan_I2C_CAN_Arduino.h>
#include <Arduino.h>

class BatteryCanReceiver : public BatteryProvider {
Expand All @@ -25,14 +26,15 @@ class BatteryCanReceiver : public BatteryProvider {
float scaleValue(int16_t value, float factor);
bool getBit(uint8_t value, uint8_t bit);

char const* _providerName = "Battery CAN";
char _providerName[32] = "Battery CAN";

bool _initialized = false;

private:
int _mcp2515_irq;
SPIClass *SPI = nullptr;
MCP_CAN *_CAN = nullptr;
I2C_CAN *i2c_can = nullptr;
};

#endif
3 changes: 3 additions & 0 deletions include/Configuration.h
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,9 @@ struct PowerLimiter_CONFIG_T {
uint32_t FullSolarPassThroughSoc;
float FullSolarPassThroughStartVoltage;
float FullSolarPassThroughStopVoltage;
#ifdef USE_SURPLUSPOWER
bool SurplusPowerEnabled;
#endif
};

enum BatteryVoltageUnit { Volts = 0, DeciVolts = 1, CentiVolts = 2, MilliVolts = 3 };
Expand Down
14 changes: 3 additions & 11 deletions include/Huawei_can.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <Longan_I2C_CAN_Arduino.h>
#include <mutex>
#include <TaskSchedulerDeclarations.h>
#include "PinMapping.h"

#ifndef HUAWEI_PIN_MISO
#define HUAWEI_PIN_MISO 12
Expand Down Expand Up @@ -102,27 +103,18 @@ class HuaweiCanCommClass {
uint32_t getParameterValue(uint8_t parameter);
void setParameterValue(uint16_t in, uint8_t parameterType);

bool isMCP2515Provider() { return _provider == CAN_Provider_t::MCP2515; }
bool isMCP2515Provider() { return PinMapping.get()charger.provider == Charger_Provider_t::MCP2515; }

private:
void sendRequest();
byte sendMsgBuf(uint32_t identifier, uint8_t extd, uint8_t len, uint8_t *data);
bool enable(void);

twai_general_config_t g_config;
SPIClass *SPI;
MCP_CAN *_CAN;
I2C_CAN *i2c_can;
uint8_t _mcp2515Irq; // IRQ pin
uint32_t _nextRequestMillis = 0; // When to send next data request to PSU

enum class CAN_Provider_t {
UNDEFINED=0,
CAN0=1,
I2C=2,
MCP2515=3
};
CAN_Provider_t _provider = CAN_Provider_t::UNDEFINED;
uint32_t _nextRequestMillis = 0; // When to send next data request to PSU

std::mutex _mutex;

Expand Down
1 change: 1 addition & 0 deletions include/Led_Strip.h
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,7 @@ class LedStripClass {

LedRGBState_t _ledRGBState[LED_COUNT];
LedRGBState_t _allMode;
const Led_Config_T *cLed = nullptr;
};

extern LedStripClass LedStrip;
Expand Down
13 changes: 3 additions & 10 deletions include/MeanWell_can.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <mcp_can.h>
#include <Longan_I2C_CAN_Arduino.h>
#include <AsyncJson.h>
#include "PinMapping.h"

#define MEANWELL_MINIMAL_SET_VOLTAGE 42

Expand Down Expand Up @@ -171,7 +172,7 @@ class MeanWellCanClass {

uint32_t getEEPROMwrites() { return EEPROMwrites;}

bool isMCP2515Provider() { return _provider == CAN_Provider_t::MCP2515; }
bool isMCP2515Provider() { return PinMapping.get().charger.provider == Charger_Provider_t::MCP2515; }

private:
void loop();
Expand All @@ -181,7 +182,6 @@ class MeanWellCanClass {
void updateEEPROMwrites2NVS();

void switchChargerOff(const char* reason);
bool enable(void);
bool getCanCharger(void);
bool parseCanPackets(void);
void calcPower();
Expand All @@ -198,7 +198,6 @@ class MeanWellCanClass {
float calcEfficency(float x);
void setupParameter(void);

twai_general_config_t g_config;
I2C_CAN* i2c_can;
SPIClass* spi;
MCP_CAN* CAN;
Expand Down Expand Up @@ -226,13 +225,7 @@ class MeanWellCanClass {
bool _lastPowerCommandSuccess;
bool _setupParameter = true;

enum class CAN_Provider_t {
UNDEFINED=0,
CAN0=1,
I2C=2,
MCP2515=3
};
CAN_Provider_t _provider = CAN_Provider_t::UNDEFINED;
char _providerName[32] = "Meanwell CAN";

const uint8_t ChargerID = 0x03;
uint32_t EEPROMwrites;
Expand Down
6 changes: 5 additions & 1 deletion include/PinMapping.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,10 @@ struct MCP2515_t {
int8_t cs;
};

enum Charger_Provider_t { undefined=0, CAN0=1, MCP2515=2, I2C0=3, I2C1=4};
enum class Charger_Provider_t { undefined=0, CAN0=1, MCP2515=2, I2C0=3, I2C1=4};
struct CHARGER_t {
Charger_Provider_t provider;
const char *providerName;
union {
struct {
int8_t rx;
Expand All @@ -43,6 +44,7 @@ struct CHARGER_t {

enum class Battery_Provider_t { undefined=0, CAN0=1, MCP2515=2, I2C0=3, I2C1=4, RS232=5, RS485=6};
struct Battery_t {
const char *providerName;
Battery_Provider_t provider;
union {
#if defined(USE_PYLONTECH_CAN_RECEIVER) || defined(USE_PYTES_CAN_RECEIVER)
Expand Down Expand Up @@ -187,6 +189,8 @@ class PinMappingClass {
void createPinMappingJson() const;

PinMapping_t _pinMapping;

const char* help[7] = {"unknown", "CAN0 Bus", "MCP2515", "I2C0/CAN", "I2C1/CAN", "RS232", "RS485"};
};

extern PinMappingClass PinMapping;
47 changes: 47 additions & 0 deletions include/Statistic.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#pragma once

#ifdef USE_SURPLUSPOWER

template <typename T>
class WeightedAVG {
public:
WeightedAVG(int16_t factor)
: _countMax(factor)
, _count(0), _countNum(0), _avgV(0), _minV(0), _maxV(0), _lastV(0) {}

void addNumber(const T& num) {
if (_count == 0){
_count++;
_avgV = num;
_minV = num;
_maxV = num;
_countNum = 1;
} else {
if (_count < _countMax)
_count++;
_avgV = (_avgV * (_count - 1) + num) / _count;
if (num < _minV) _minV = num;
if (num > _maxV) _maxV = num;
_countNum++;
}
_lastV = num;
}

void reset(void) { _count = 0; _avgV = 0; _minV = 0; _maxV = 0; _lastV = 0; _countNum = 0; }
void reset(const T& num) { _count = 0; addNumber(num); }
T getAverage() const { return _avgV; }
T getMin() const { return _minV; }
T getMax() const { return _maxV; }
T getLast() const { return _lastV; }
int32_t getCounts() const { return _countNum; }

private:
int16_t _countMax; // weighting factor (10 => 1/10 => 10%)
int16_t _count; // counter (0 - _countMax)
int32_t _countNum; // counts the amount of added numbers
T _avgV; // average value
T _minV; // minimum value
T _maxV; // maximum value
T _lastV; // last value
};
#endif
56 changes: 56 additions & 0 deletions include/SurplusPower.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
#pragma once

#ifdef USE_SURPLUSPOWER

#include <Arduino.h>
#include <frozen/string.h>
#include "Statistic.h"


class SurplusPowerClass {
public:
SurplusPowerClass() = default;
~SurplusPowerClass() = default;

bool useSurplusPower(void) const;
int32_t calcSurplusPower(int32_t const requestedPower);

private:
enum class SurplusState : uint8_t {
IDLE = 0,
TRY_MORE = 1,
REDUCE_POWER = 2,
IN_TARGET = 3,
MAXIMUM_POWER = 4,
};

enum class Text : uint8_t {
Q_NODATA = 0,
Q_EXCELLENT = 1,
Q_GOOD = 2,
Q_BAD = 3,
T_HEAD = 4
};

frozen::string const& getStatusText(SurplusPowerClass::SurplusState state);
frozen::string const& getText(SurplusPowerClass::Text tNr);
void handleQualityCounter(void);

// to handle regulation
SurplusState _surplusState = SurplusState::IDLE; // actual regulation state
float _absorptionVoltage = -1.0f; // from MPPT
float _floatVoltage = -1.0f; // from MPPT
int32_t _powerStep = 50; // power step size in W (default)
int32_t _surplusPower = 0; // actual surplus power
int32_t _inTargetTime = 0; // records the time we hit the target power
WeightedAVG<float> _avgMPPTVoltage {3}; // the average helps to smooth the regulation

// to handle the quality counter
int8_t _qualityCounter = 0; // quality counter
WeightedAVG<float> _qualityAVG {20}; // quality counter average
int32_t _lastAddPower = 0; // last power step
};

extern SurplusPowerClass SurplusPower;

#endif
1 change: 1 addition & 0 deletions include/VictronMppt.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ class VictronMpptClass {
enum class MPPTVoltage : uint8_t {
ABSORPTION = 0,
FLOAT = 1,
BATTERY = 2
};
float getVoltage(MPPTVoltage kindOf) const;

Expand Down
3 changes: 3 additions & 0 deletions lib/Hoymiles/src/HoymilesRadio_CMT.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -256,11 +256,14 @@ uint32_t HoymilesRadio_CMT::getInvBootFrequency() const
return countryDefinition.at(_countryMode).Freq_StartUp;
}

//void IRAM_ATTR HoymilesRadio_CMT::handleInt1()
void ARDUINO_ISR_ATTR HoymilesRadio_CMT::handleInt1()
{
_packetSent = true;
}


//void IRAM_ATTR HoymilesRadio_CMT::handleInt2()
void ARDUINO_ISR_ATTR HoymilesRadio_CMT::handleInt2()
{
_packetReceived = true;
Expand Down
2 changes: 2 additions & 0 deletions lib/Hoymiles/src/HoymilesRadio_CMT.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ class HoymilesRadio_CMT : public HoymilesRadio {
std::vector<CountryFrequencyList_t> getCountryFrequencyList() const;

private:
// void IRAM_ATTR handleInt1();
// void IRAM_ATTR handleInt2();
void ARDUINO_ISR_ATTR handleInt1();
void ARDUINO_ISR_ATTR handleInt2();

Expand Down
1 change: 1 addition & 0 deletions lib/Hoymiles/src/HoymilesRadio_NRF.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ void HoymilesRadio_NRF::openWritingPipe(const serial_u serial)
_radio->openWritingPipe(s.u64);
}

// void IRAM_ATTR HoymilesRadio_NRF::handleIntr()
void ARDUINO_ISR_ATTR HoymilesRadio_NRF::handleIntr()
{
_packetReceived = true;
Expand Down
3 changes: 2 additions & 1 deletion lib/Hoymiles/src/HoymilesRadio_NRF.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ class HoymilesRadio_NRF : public HoymilesRadio {

private:
void ARDUINO_ISR_ATTR handleIntr();
// void IRAM_ATTR handleIntr();
uint8_t getRxNxtChannel();
uint8_t getTxNxtChannel();
void switchRxCh();
Expand All @@ -43,4 +44,4 @@ class HoymilesRadio_NRF : public HoymilesRadio {
volatile bool _packetReceived = false;

std::queue<fragment_t> _rxBuffer;
};
};
2 changes: 1 addition & 1 deletion lib/VeDirectFrameHandler/VeDirectFrameHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ void VeDirectFrameHandler<T>::init(char const* who, int8_t rx, int8_t tx,
_vedirectSerial = std::make_unique<HardwareSerial>(hwSerialPort);
_vedirectSerial->setRxBufferSize(512); // increased from default (256) to 512 Byte to avoid overflow
_vedirectSerial->end(); // make sure the UART will be re-initialized
_vedirectSerial->begin(19200, SERIAL_8N1, rx, tx);
_vedirectSerial->begin(19200, SERIAL_8N1, rx, tx);
_vedirectSerial->flush();
_canSend = (tx != -1);
_msgOut = msgOut;
Expand Down
1 change: 1 addition & 0 deletions platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ board_build.flash_mode = qio
board_build.partitions = partitions_custom_16mb.csv
board_upload.flash_size = 16MB
build_flags = ${env.build_flags}
-DUSE_SURPLUSPOWER=1
-DUSE_RADIO_NRF=1
-DUSE_RADIO_CMT=1
-DUSE_PYLONTECH_RS485_RECEIVER=1
Expand Down
Loading

0 comments on commit db20f07

Please sign in to comment.