Allow dynamic pin mapping for CMT module

This commit is contained in:
Thomas Basler 2023-03-08 20:12:22 +01:00
parent 3c0d89f599
commit 45882543b6
19 changed files with 174 additions and 90 deletions

View File

@ -91,6 +91,11 @@ The json file can contain multiple profiles. Each profile requires a name and di
| nrf24.irq | number | Interrupt Pin |
| nrf24.en | number | Enable Pin |
| nrf24.cs | number | Chip Select Pin |
| cmt.sdio | number | SDIO Pin |
| cmt.clk | number | CLK Pin |
| cmt.cs | number | CS Pin |
| cmt.fcs | number | FCS Pin |
| cmt.gpio3 | number | GPIO3 Pin |
| eth.enabled | boolean | Enable/Disable the ethernet stack |
| eth.phy_addr | number | Unique PHY addr |
| eth.power | number | Power Pin (if available). Use -1 for not assigned pins. |

View File

@ -18,6 +18,13 @@ struct PinMapping_t {
int8_t nrf24_irq;
int8_t nrf24_en;
int8_t nrf24_cs;
int8_t cmt_clk;
int8_t cmt_cs;
int8_t cmt_fcs;
int8_t cmt_gpio3;
int8_t cmt_sdio;
int8_t eth_phy_addr;
bool eth_enabled;
int eth_power;
@ -40,6 +47,7 @@ public:
PinMapping_t& get();
bool isValidNrf24Config();
bool isValidCmt2300Config();
bool isValidEthConfig();
private:

View File

@ -26,9 +26,9 @@
* @name CMT2300A_InitSpi
* @desc Initializes the CMT2300A SPI interface.
* *********************************************************/
void CMT2300A_InitSpi(void)
void CMT2300A_InitSpi(int8_t pin_sdio, int8_t pin_clk, int8_t pin_cs, int8_t pin_fcs)
{
cmt_spi3_init();
cmt_spi3_init(pin_sdio, pin_clk, pin_cs, pin_fcs);
}
/*! ********************************************************

View File

@ -36,7 +36,7 @@ extern "C" {
#define CMT2300A_GetTickCount() millis()
/* ************************************************************************ */
void CMT2300A_InitSpi(void);
void CMT2300A_InitSpi(int8_t pin_sdio, int8_t pin_clk, int8_t pin_cs, int8_t pin_fcs);
uint8_t CMT2300A_ReadReg(uint8_t addr);
void CMT2300A_WriteReg(uint8_t addr, uint8_t dat);

View File

@ -7,12 +7,12 @@
spi_device_handle_t spi_reg, spi_fifo;
void cmt_spi3_init(void)
void cmt_spi3_init(int8_t pin_sdio, int8_t pin_clk, int8_t pin_cs, int8_t pin_fcs)
{
spi_bus_config_t buscfg = {
.mosi_io_num = CMT_PIN_SDIO,
.mosi_io_num = pin_sdio,
.miso_io_num = -1, // single wire MOSI/MISO
.sclk_io_num = CMT_PIN_CLK,
.sclk_io_num = pin_clk,
.quadwp_io_num = -1,
.quadhd_io_num = -1,
.max_transfer_sz = 32,
@ -23,7 +23,7 @@ void cmt_spi3_init(void)
.dummy_bits = 0,
.mode = 0, // SPI mode 0
.clock_speed_hz = CMT_SPI_CLK,
.spics_io_num = CMT_PIN_CS,
.spics_io_num = pin_cs,
.flags = SPI_DEVICE_HALFDUPLEX | SPI_DEVICE_3WIRE,
.queue_size = 1,
.pre_cb = NULL,
@ -42,7 +42,7 @@ void cmt_spi3_init(void)
.cs_ena_pretrans = 2,
.cs_ena_posttrans = (uint8_t)(1 / (CMT_SPI_CLK * 10e6 * 2) + 2), // >2 us
.clock_speed_hz = CMT_SPI_CLK,
.spics_io_num = CMT_PIN_FCS,
.spics_io_num = pin_fcs,
.flags = SPI_DEVICE_HALFDUPLEX | SPI_DEVICE_3WIRE,
.queue_size = 1,
.pre_cb = NULL,
@ -50,7 +50,7 @@ void cmt_spi3_init(void)
};
ESP_ERROR_CHECK(spi_bus_add_device(SPI2_HOST, &devcfg2, &spi_fifo));
esp_rom_gpio_connect_out_signal(CMT_PIN_SDIO, spi_periph_signal[SPI2_HOST].spid_out, true, false);
esp_rom_gpio_connect_out_signal(pin_sdio, spi_periph_signal[SPI2_HOST].spid_out, true, false);
delay(100);
}

View File

@ -3,7 +3,7 @@
#include <stdint.h>
void cmt_spi3_init(void);
void cmt_spi3_init(int8_t pin_sdio, int8_t pin_clk, int8_t pin_cs, int8_t pin_fcs);
void cmt_spi3_write(uint8_t addr, uint8_t dat);
uint8_t cmt_spi3_read(uint8_t addr);

View File

@ -3,12 +3,12 @@
* Copyright (C) 2022 Thomas Basler and others
*/
#include "Hoymiles.h"
#include "inverters/HM_1CH.h"
#include "inverters/HM_2CH.h"
#include "inverters/HM_4CH.h"
#include "inverters/HMS_1CH.h"
#include "inverters/HMS_2CH.h"
#include "inverters/HMS_4CH.h"
#include "inverters/HM_1CH.h"
#include "inverters/HM_2CH.h"
#include "inverters/HM_4CH.h"
#include <Arduino.h>
#define HOY_SEMAPHORE_TAKE() xSemaphoreTake(_xSemaphore, portMAX_DELAY)
@ -16,32 +16,49 @@
HoymilesClass Hoymiles;
void HoymilesClass::init(SPIClass* initialisedSpiBus, uint8_t pinCE, uint8_t pinIRQ)
void HoymilesClass::init()
{
_xSemaphore = xSemaphoreCreateMutex();
HOY_SEMAPHORE_GIVE(); // release before first use
_pollInterval = 0;
_radioNrf.reset(new HoymilesRadio_NRF());
_radioNrf->init(initialisedSpiBus, pinCE, pinIRQ);
_radioCmt.reset(new HoymilesRadio_CMT());
_radioCmt->init();
}
void HoymilesClass::initNRF(SPIClass* initialisedSpiBus, uint8_t pinCE, uint8_t pinIRQ)
{
_radioNrf->init(initialisedSpiBus, pinCE, pinIRQ);
}
void HoymilesClass::initCMT(int8_t pin_sdio, int8_t pin_clk, int8_t pin_cs, int8_t pin_fcs, int8_t pin_gpio3)
{
_radioCmt->init(pin_sdio, pin_clk, pin_cs, pin_fcs, pin_gpio3);
}
void HoymilesClass::loop()
{
HOY_SEMAPHORE_TAKE();
if (_radioNrf->isInitialized()) {
_radioNrf->loop();
}
if (_radioCmt->isInitialized()) {
_radioCmt->loop();
}
if (getNumInverters() > 0) {
if (millis() - _lastPoll > (_pollInterval * 1000)) {
static uint8_t inverterPos = 0;
if (_radioNrf->isIdle() && _radioCmt->isIdle()) {
std::shared_ptr<InverterAbstract> iv = getInverterByPos(inverterPos);
if (iv != nullptr) {
if ((iv == nullptr) || ((iv != nullptr) && (!iv->getRadio()->isInitialized()))) {
if (++inverterPos >= getNumInverters()) {
inverterPos = 0;
}
}
if (iv != nullptr && iv->getRadio()->isInitialized() && iv->getRadio()->isIdle()) {
_messageOutput->print("Fetch inverter: ");
_messageOutput->println(iv->serial(), HEX);
@ -76,15 +93,15 @@ void HoymilesClass::loop()
_messageOutput->println("Request device info");
iv->sendDevInfoRequest();
}
}
if (++inverterPos >= getNumInverters()) {
inverterPos = 0;
}
}
_lastPoll = millis();
}
}
}
HOY_SEMAPHORE_GIVE();
}

View File

@ -15,7 +15,9 @@
class HoymilesClass {
public:
void init(SPIClass* initialisedSpiBus, uint8_t pinCE, uint8_t pinIRQ);
void init();
void initNRF(SPIClass* initialisedSpiBus, uint8_t pinCE, uint8_t pinIRQ);
void initCMT(int8_t pin_sdio, int8_t pin_clk, int8_t pin_cs, int8_t pin_fcs, int8_t pin_gpio3);
void loop();
void setMessageOutput(Print* output);

View File

@ -62,3 +62,13 @@ void HoymilesRadio::dumpBuf(const char* info, uint8_t buf[], uint8_t len)
}
Hoymiles.getMessageOutput()->println("");
}
bool HoymilesRadio::isInitialized()
{
return _isInitialized;
}
bool HoymilesRadio::isIdle()
{
return !_busyFlag;
}

View File

@ -11,6 +11,9 @@ public:
serial_u DtuSerial();
virtual void setDtuSerial(uint64_t serial);
bool isIdle();
bool isInitialized();
template <typename T>
T* enqueCommand()
{
@ -29,4 +32,6 @@ protected:
serial_u _dtuSerial;
std::queue<std::shared_ptr<CommandAbstract>> _commandQueue;
bool _isInitialized = false;
bool _busyFlag = false;
};

View File

@ -222,7 +222,7 @@ enumCMTresult HoymilesRadio_CMT::cmtProcess(void)
cmtRxTimeoutCnt++;
} else {
uint32_t invSerial = cmtTxBuffer[1] << 24 | cmtTxBuffer[2] << 16 | cmtTxBuffer[3] << 8 | cmtTxBuffer[4]; // read inverter serial from last Tx buffer
cmtSwitchInvAndDtuFreq(invSerial, HOY_BOOT_FREQ / 1000, CMT_WORK_FREQ);
cmtSwitchInvAndDtuFreq(invSerial, HOY_BOOT_FREQ / 1000, HOYMILES_CMT_WORK_FREQ);
}
nRes = CMT_RX_TIMEOUT;
@ -315,12 +315,12 @@ enumCMTresult HoymilesRadio_CMT::cmtProcess(void)
return nRes;
}
void HoymilesRadio_CMT::init()
void HoymilesRadio_CMT::init(int8_t pin_sdio, int8_t pin_clk, int8_t pin_cs, int8_t pin_fcs, int8_t pin_gpio3)
{
_dtuSerial.u64 = 0;
uint8_t tmp;
CMT2300A_InitSpi();
CMT2300A_InitSpi(pin_sdio, pin_clk, pin_cs, pin_fcs);
if (!CMT2300A_Init()) {
Hoymiles.getMessageOutput()->println("CMT2300A_Init() failed!");
return;
@ -345,11 +345,12 @@ void HoymilesRadio_CMT::init()
return;
}
attachInterrupt(digitalPinToInterrupt(CMT_PIN_GPIO3), std::bind(&HoymilesRadio_CMT::handleIntr, this), RISING);
attachInterrupt(digitalPinToInterrupt(pin_gpio3), std::bind(&HoymilesRadio_CMT::handleIntr, this), RISING);
cmtSwitchDtuFreq(CMT_WORK_FREQ); // start dtu at work freqency, for fast Rx if inverter is already on and frequency switched
cmtSwitchDtuFreq(HOYMILES_CMT_WORK_FREQ); // start dtu at work freqency, for fast Rx if inverter is already on and frequency switched
_ChipConnected = true;
_isInitialized = true;
Hoymiles.getMessageOutput()->println("CMT init successful");
}
@ -447,11 +448,6 @@ void HoymilesRadio_CMT::loop()
}
}
bool HoymilesRadio_CMT::isIdle()
{
return !_busyFlag;
}
bool HoymilesRadio_CMT::isConnected()
{
return _ChipConnected;

View File

@ -39,10 +39,9 @@ typedef enum {
class HoymilesRadio_CMT : public HoymilesRadio {
public:
void init();
void init(int8_t pin_sdio, int8_t pin_clk, int8_t pin_cs, int8_t pin_fcs, int8_t pin_gpio3);
void loop();
bool isIdle();
bool isConnected();
private:
@ -55,8 +54,6 @@ private:
std::queue<fragment_t> _rxBuffer;
TimeoutHelper _rxTimeout;
bool _busyFlag = false;
bool _ChipConnected = false;
String cmtChToFreq(const uint8_t channel);

View File

@ -33,6 +33,7 @@ void HoymilesRadio_NRF::init(SPIClass* initialisedSpiBus, uint8_t pinCE, uint8_t
openReadingPipe();
_radio->startListening();
_isInitialized = true;
}
void HoymilesRadio_NRF::loop()
@ -159,11 +160,6 @@ void HoymilesRadio_NRF::setDtuSerial(uint64_t serial)
openReadingPipe();
}
bool HoymilesRadio_NRF::isIdle()
{
return !_busyFlag;
}
bool HoymilesRadio_NRF::isConnected()
{
return _radio->isChipConnected();

View File

@ -20,7 +20,6 @@ public:
virtual void setDtuSerial(uint64_t serial);
bool isIdle();
bool isConnected();
bool isPVariant();
@ -46,6 +45,4 @@ private:
std::queue<fragment_t> _rxBuffer;
TimeoutHelper _rxTimeout;
bool _busyFlag = false;
};

View File

@ -96,6 +96,11 @@ bool InverterAbstract::getEnableCommands()
return _enableCommands;
}
HoymilesRadio* InverterAbstract::getRadio()
{
return _radio;
}
AlarmLogParser* InverterAbstract::EventLog()
{
return _alarmLogParser.get();

View File

@ -64,6 +64,8 @@ public:
virtual bool sendRestartControlRequest() = 0;
virtual bool resendPowerControlRequest() = 0;
HoymilesRadio* getRadio();
AlarmLogParser* EventLog();
DevInfoParser* DevInfo();
PowerCommandParser* PowerCommand();

View File

@ -56,12 +56,7 @@ build_flags = ${env.build_flags}
-DHOYMILES_PIN_IRQ=16
-DHOYMILES_PIN_CE=4
-DHOYMILES_PIN_CS=5
-DCMT_PIN_CLK=18
-DCMT_PIN_SDIO=23
-DCMT_PIN_CS=5
-DCMT_PIN_FCS=4
-DCMT_PIN_GPIO3=15
-DCMT_WORK_FREQ=865000
-DHOYMILES_CMT_WORK_FREQ=865000
[env:olimex_esp32_poe]

View File

@ -22,11 +22,19 @@ void InverterSettingsClass::init()
// Initialize inverter communication
MessageOutput.print("Initialize Hoymiles interface... ");
if (PinMapping.isValidNrf24Config()) {
if (PinMapping.isValidNrf24Config() || PinMapping.isValidCmt2300Config()) {
SPIClass* spiClass = new SPIClass(VSPI);
spiClass->begin(pin.nrf24_clk, pin.nrf24_miso, pin.nrf24_mosi, pin.nrf24_cs);
Hoymiles.setMessageOutput(&MessageOutput);
Hoymiles.init(spiClass, pin.nrf24_en, pin.nrf24_irq);
Hoymiles.init();
if (PinMapping.isValidNrf24Config()) {
Hoymiles.initNRF(spiClass, pin.nrf24_en, pin.nrf24_irq);
}
if (PinMapping.isValidCmt2300Config()) {
Hoymiles.initCMT(pin.cmt_sdio, pin.cmt_clk, pin.cmt_cs, pin.cmt_fcs, pin.cmt_gpio3);
}
MessageOutput.println(" Setting radio PA level... ");
Hoymiles.getRadioNrf()->setPALevel((rf24_pa_dbm_e)config.Dtu_PaLevel);

View File

@ -38,6 +38,26 @@
#define LED1 -1
#endif
#ifndef CMT_CLK
#define CMT_CLK -1
#endif
#ifndef CMT_CS
#define CMT_CS -1
#endif
#ifndef CMT_FCS
#define CMT_FCS -1
#endif
#ifndef CMT_GPIO3
#define CMT_GPIO3 -1
#endif
#ifndef CMT_SDIO
#define CMT_SDIO -1
#endif
PinMappingClass PinMapping;
PinMappingClass::PinMappingClass()
@ -50,6 +70,12 @@ PinMappingClass::PinMappingClass()
_pinMapping.nrf24_miso = HOYMILES_PIN_MISO;
_pinMapping.nrf24_mosi = HOYMILES_PIN_MOSI;
_pinMapping.cmt_clk = CMT_CLK;
_pinMapping.cmt_cs = CMT_CS;
_pinMapping.cmt_fcs = CMT_FCS;
_pinMapping.cmt_gpio3 = CMT_GPIO3;
_pinMapping.cmt_sdio = CMT_SDIO;
#ifdef OPENDTU_ETHERNET
_pinMapping.eth_enabled = true;
#else
@ -104,6 +130,12 @@ bool PinMappingClass::init(const String& deviceMapping)
_pinMapping.nrf24_miso = doc[i]["nrf24"]["miso"] | HOYMILES_PIN_MISO;
_pinMapping.nrf24_mosi = doc[i]["nrf24"]["mosi"] | HOYMILES_PIN_MOSI;
_pinMapping.cmt_clk = doc[i]["cmt"]["clk"] | CMT_CLK;
_pinMapping.cmt_cs = doc[i]["cmt"]["cs"] | CMT_CS;
_pinMapping.cmt_fcs = doc[i]["cmt"]["fcs"] | CMT_FCS;
_pinMapping.cmt_gpio3 = doc[i]["cmt"]["gpio3"] | CMT_GPIO3;
_pinMapping.cmt_sdio = doc[i]["cmt"]["sdio"] | CMT_SDIO;
#ifdef OPENDTU_ETHERNET
_pinMapping.eth_enabled = doc[i]["eth"]["enabled"] | true;
#else
@ -143,6 +175,15 @@ bool PinMappingClass::isValidNrf24Config()
&& _pinMapping.nrf24_mosi >= 0;
}
bool PinMappingClass::isValidCmt2300Config()
{
return _pinMapping.cmt_clk >= 0
&& _pinMapping.cmt_cs >= 0
&& _pinMapping.cmt_fcs >= 0
&& _pinMapping.cmt_gpio3 >= 0
&& _pinMapping.cmt_sdio >= 0;
}
bool PinMappingClass::isValidEthConfig()
{
return _pinMapping.eth_enabled;