diff --git a/lib/CMT2300a/cmt2300a_hal.c b/lib/CMT2300a/cmt2300a_hal.c index 3f7111ca3..7bf1b60ff 100644 --- a/lib/CMT2300a/cmt2300a_hal.c +++ b/lib/CMT2300a/cmt2300a_hal.c @@ -26,9 +26,9 @@ * @name CMT2300A_InitSpi * @desc Initializes the CMT2300A SPI interface. * *********************************************************/ -void CMT2300A_InitSpi(int8_t pin_sdio, int8_t pin_clk, int8_t pin_cs, int8_t pin_fcs) +void CMT2300A_InitSpi(int8_t pin_sdio, int8_t pin_clk, int8_t pin_cs, int8_t pin_fcs, uint32_t spi_speed) { - cmt_spi3_init(pin_sdio, pin_clk, pin_cs, pin_fcs); + cmt_spi3_init(pin_sdio, pin_clk, pin_cs, pin_fcs, spi_speed); } /*! ******************************************************** diff --git a/lib/CMT2300a/cmt2300a_hal.h b/lib/CMT2300a/cmt2300a_hal.h index 8a27251fd..1d6e1f4f3 100644 --- a/lib/CMT2300a/cmt2300a_hal.h +++ b/lib/CMT2300a/cmt2300a_hal.h @@ -36,7 +36,7 @@ extern "C" { #define CMT2300A_GetTickCount() millis() /* ************************************************************************ */ -void CMT2300A_InitSpi(int8_t pin_sdio, int8_t pin_clk, int8_t pin_cs, int8_t pin_fcs); +void CMT2300A_InitSpi(int8_t pin_sdio, int8_t pin_clk, int8_t pin_cs, int8_t pin_fcs, uint32_t spi_speed); uint8_t CMT2300A_ReadReg(uint8_t addr); void CMT2300A_WriteReg(uint8_t addr, uint8_t dat); diff --git a/lib/CMT2300a/cmt2300wrapper.cpp b/lib/CMT2300a/cmt2300wrapper.cpp new file mode 100644 index 000000000..603d1b044 --- /dev/null +++ b/lib/CMT2300a/cmt2300wrapper.cpp @@ -0,0 +1,192 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2023 Thomas Basler and others + */ +#include "cmt2300wrapper.h" +#include "cmt2300a.h" +#include "cmt2300a_params.h" + +CMT2300a::CMT2300a(uint8_t pin_sdio, uint8_t pin_clk, uint8_t pin_cs, uint8_t pin_fcs, uint32_t spi_speed) +{ + _pin_sdio = pin_sdio; + _pin_clk = pin_clk; + _pin_cs = pin_cs; + _pin_fcs = pin_fcs; + _spi_speed = spi_speed; +} + +bool CMT2300a::begin(void) +{ + return _init_pins() && _init_radio(); +} + +bool CMT2300a::isChipConnected() +{ + return CMT2300A_IsExist(); +} + +bool CMT2300a::setPALevel(int8_t level) +{ + uint16_t Tx_dBm_word; + switch (level) { + // for TRx Matching Network Type: 20 dBm + case -10: + Tx_dBm_word = 0x0501; + break; + case -9: + Tx_dBm_word = 0x0601; + break; + case -8: + Tx_dBm_word = 0x0701; + break; + case -7: + Tx_dBm_word = 0x0801; + break; + case -6: + Tx_dBm_word = 0x0901; + break; + case -5: + Tx_dBm_word = 0x0A01; + break; + case -4: + Tx_dBm_word = 0x0B01; + break; + case -3: + Tx_dBm_word = 0x0C01; + break; + case -2: + Tx_dBm_word = 0x0D01; + break; + case -1: + Tx_dBm_word = 0x0E01; + break; + case 0: + Tx_dBm_word = 0x1002; + break; + case 1: + Tx_dBm_word = 0x1302; + break; + case 2: + Tx_dBm_word = 0x1602; + break; + case 3: + Tx_dBm_word = 0x1902; + break; + case 4: + Tx_dBm_word = 0x1C02; + break; + case 5: + Tx_dBm_word = 0x1F03; + break; + case 6: + Tx_dBm_word = 0x2403; + break; + case 7: + Tx_dBm_word = 0x2804; + break; + case 8: + Tx_dBm_word = 0x2D04; + break; + case 9: + Tx_dBm_word = 0x3305; + break; + case 10: + Tx_dBm_word = 0x3906; + break; + case 11: + Tx_dBm_word = 0x4107; + break; + case 12: + Tx_dBm_word = 0x4908; + break; + case 13: + Tx_dBm_word = 0x5309; + break; + case 14: + Tx_dBm_word = 0x5E0B; + break; + case 15: + Tx_dBm_word = 0x6C0C; + break; + case 16: + Tx_dBm_word = 0x7D0C; + break; + // the following values require the double bit: + case 17: + Tx_dBm_word = 0x4A0C; + break; + case 18: + Tx_dBm_word = 0x580F; + break; + case 19: + Tx_dBm_word = 0x6B12; + break; + case 20: + Tx_dBm_word = 0x8A18; + break; + default: + return false; + } + if (level > 16) { // set bit for double Tx value + CMT2300A_WriteReg(CMT2300A_CUS_CMT4, CMT2300A_ReadReg(CMT2300A_CUS_CMT4) | 0x01); // set bit0 + } else { + CMT2300A_WriteReg(CMT2300A_CUS_CMT4, CMT2300A_ReadReg(CMT2300A_CUS_CMT4) & 0xFE); // reset bit0 + } + CMT2300A_WriteReg(CMT2300A_CUS_TX8, Tx_dBm_word >> 8); + CMT2300A_WriteReg(CMT2300A_CUS_TX9, Tx_dBm_word & 0xFF); + + return true; +} + +bool CMT2300a::_init_pins() +{ + CMT2300A_InitSpi(_pin_sdio, _pin_clk, _pin_cs, _pin_fcs, _spi_speed); + + return true; // assuming pins are connected properly +} + +bool CMT2300a::_init_radio() +{ + if (!CMT2300A_Init()) { + return false; + } + + /* config registers */ + CMT2300A_ConfigRegBank(CMT2300A_CMT_BANK_ADDR, g_cmt2300aCmtBank, CMT2300A_CMT_BANK_SIZE); + CMT2300A_ConfigRegBank(CMT2300A_SYSTEM_BANK_ADDR, g_cmt2300aSystemBank, CMT2300A_SYSTEM_BANK_SIZE); + CMT2300A_ConfigRegBank(CMT2300A_FREQUENCY_BANK_ADDR, g_cmt2300aFrequencyBank, CMT2300A_FREQUENCY_BANK_SIZE); + CMT2300A_ConfigRegBank(CMT2300A_DATA_RATE_BANK_ADDR, g_cmt2300aDataRateBank, CMT2300A_DATA_RATE_BANK_SIZE); + CMT2300A_ConfigRegBank(CMT2300A_BASEBAND_BANK_ADDR, g_cmt2300aBasebandBank, CMT2300A_BASEBAND_BANK_SIZE); + CMT2300A_ConfigRegBank(CMT2300A_TX_BANK_ADDR, g_cmt2300aTxBank, CMT2300A_TX_BANK_SIZE); + + // xosc_aac_code[2:0] = 2 + uint8_t tmp; + tmp = (~0x07) & CMT2300A_ReadReg(CMT2300A_CUS_CMT10); + CMT2300A_WriteReg(CMT2300A_CUS_CMT10, tmp | 0x02); + + /* Config GPIOs */ + CMT2300A_ConfigGpio( + CMT2300A_GPIO3_SEL_INT2); + + /* Config interrupt */ + CMT2300A_ConfigInterrupt( + CMT2300A_INT_SEL_TX_DONE, /* Config INT1 */ + CMT2300A_INT_SEL_PKT_OK /* Config INT2 */ + ); + + /* Enable interrupt */ + CMT2300A_EnableInterrupt( + CMT2300A_MASK_TX_DONE_EN | CMT2300A_MASK_PREAM_OK_EN | CMT2300A_MASK_SYNC_OK_EN | CMT2300A_MASK_CRC_OK_EN | CMT2300A_MASK_PKT_DONE_EN); + + CMT2300A_SetFrequencyStep(FH_OFFSET); // set FH_OFFSET (frequency = base freq + 2.5kHz*FH_OFFSET*FH_CHANNEL) + + /* Use a single 64-byte FIFO for either Tx or Rx */ + CMT2300A_EnableFifoMerge(true); + + /* Go to sleep for configuration to take effect */ + if (!CMT2300A_GoSleep()) { + return false; // CMT2300A not switched to sleep mode! + } + + return true; +} diff --git a/lib/CMT2300a/cmt2300wrapper.h b/lib/CMT2300a/cmt2300wrapper.h new file mode 100644 index 000000000..143817b35 --- /dev/null +++ b/lib/CMT2300a/cmt2300wrapper.h @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +#pragma once + +#include + +#define CMT2300A_ONE_STEP_SIZE 2500 // frequency channel step size for fast frequency hopping operation: One step size is 2.5 kHz. +#define CMT_BASE_FREQ 860000000 // from Frequency Bank in cmt2300a_params.h +#define FH_OFFSET 100 // value * CMT2300A_ONE_STEP_SIZE = channel frequency offset +#define CMT_SPI_SPEED 4000000 // 4 MHz + +class CMT2300a { +public: + CMT2300a(uint8_t pin_sdio, uint8_t pin_clk, uint8_t pin_cs, uint8_t pin_fcs, uint32_t _spi_speed = CMT_SPI_SPEED); + + bool begin(void); + + /** + * Checks if the chip is connected to the SPI bus + */ + bool isChipConnected(); + + bool setPALevel(int8_t level); + +private: + /** + * initialize the GPIO pins + */ + bool _init_pins(); + + /** + * initialize radio. + * @warning This function assumes the SPI bus object's begin() method has been + * previously called. + */ + bool _init_radio(); + + int8_t _pin_sdio; + int8_t _pin_clk; + int8_t _pin_cs; + int8_t _pin_fcs; + uint32_t _spi_speed; +}; \ No newline at end of file diff --git a/lib/CMT2300a/cmt_spi3.c b/lib/CMT2300a/cmt_spi3.c index 409782a1d..7092b528d 100644 --- a/lib/CMT2300a/cmt_spi3.c +++ b/lib/CMT2300a/cmt_spi3.c @@ -3,11 +3,9 @@ #include #include // for esp_rom_gpio_connect_out_signal -#define CMT_SPI_CLK 4000000 // 4 MHz - spi_device_handle_t spi_reg, spi_fifo; -void cmt_spi3_init(int8_t pin_sdio, int8_t pin_clk, int8_t pin_cs, int8_t pin_fcs) +void cmt_spi3_init(int8_t pin_sdio, int8_t pin_clk, int8_t pin_cs, int8_t pin_fcs, uint32_t spi_speed) { spi_bus_config_t buscfg = { .mosi_io_num = pin_sdio, @@ -22,7 +20,7 @@ void cmt_spi3_init(int8_t pin_sdio, int8_t pin_clk, int8_t pin_cs, int8_t pin_fc .address_bits = 0, .dummy_bits = 0, .mode = 0, // SPI mode 0 - .clock_speed_hz = CMT_SPI_CLK, + .clock_speed_hz = spi_speed, .spics_io_num = pin_cs, .flags = SPI_DEVICE_HALFDUPLEX | SPI_DEVICE_3WIRE, .queue_size = 1, @@ -40,8 +38,8 @@ void cmt_spi3_init(int8_t pin_sdio, int8_t pin_clk, int8_t pin_cs, int8_t pin_fc .dummy_bits = 0, .mode = 0, // SPI mode 0 .cs_ena_pretrans = 2, - .cs_ena_posttrans = (uint8_t)(1 / (CMT_SPI_CLK * 10e6 * 2) + 2), // >2 us - .clock_speed_hz = CMT_SPI_CLK, + .cs_ena_posttrans = (uint8_t)(1 / (spi_speed * 10e6 * 2) + 2), // >2 us + .clock_speed_hz = spi_speed, .spics_io_num = pin_fcs, .flags = SPI_DEVICE_HALFDUPLEX | SPI_DEVICE_3WIRE, .queue_size = 1, diff --git a/lib/CMT2300a/cmt_spi3.h b/lib/CMT2300a/cmt_spi3.h index a29a03dae..0e77e311f 100644 --- a/lib/CMT2300a/cmt_spi3.h +++ b/lib/CMT2300a/cmt_spi3.h @@ -3,7 +3,7 @@ #include -void cmt_spi3_init(int8_t pin_sdio, int8_t pin_clk, int8_t pin_cs, int8_t pin_fcs); +void cmt_spi3_init(int8_t pin_sdio, int8_t pin_clk, int8_t pin_cs, int8_t pin_fcs, uint32_t spi_speed); void cmt_spi3_write(uint8_t addr, uint8_t dat); uint8_t cmt_spi3_read(uint8_t addr); diff --git a/lib/Hoymiles/src/HoymilesRadio_CMT.cpp b/lib/Hoymiles/src/HoymilesRadio_CMT.cpp index 5d4efc102..e10950c15 100644 --- a/lib/Hoymiles/src/HoymilesRadio_CMT.cpp +++ b/lib/Hoymiles/src/HoymilesRadio_CMT.cpp @@ -7,10 +7,7 @@ #include "crc.h" #include #include -#include -#define CMT2300A_ONE_STEP_SIZE 2500 // frequency channel step size for fast frequency hopping operation: One step size is 2.5 kHz. -#define FH_OFFSET 100 // value * CMT2300A_ONE_STEP_SIZE = channel frequency offset #define HOY_BASE_FREQ 860000000 // Hoymiles base frequency for CMD56 channels is 860.00 MHz #define HOY_BOOT_FREQ 868000000 // Hoymiles boot/init frequency after power up inverter @@ -60,35 +57,6 @@ bool HoymilesRadio_CMT::cmtSwitchDtuFreq(const uint32_t to_freq_kHz) return true; } -bool HoymilesRadio_CMT::cmtConfig(void) -{ - /* Config GPIOs */ - CMT2300A_ConfigGpio( - CMT2300A_GPIO3_SEL_INT2); - - /* Config interrupt */ - CMT2300A_ConfigInterrupt( - CMT2300A_INT_SEL_TX_DONE, /* Config INT1 */ - CMT2300A_INT_SEL_PKT_OK /* Config INT2 */ - ); - - /* Enable interrupt */ - CMT2300A_EnableInterrupt( - CMT2300A_MASK_TX_DONE_EN | CMT2300A_MASK_PREAM_OK_EN | CMT2300A_MASK_SYNC_OK_EN | CMT2300A_MASK_CRC_OK_EN | CMT2300A_MASK_PKT_DONE_EN); - - CMT2300A_SetFrequencyStep(100); // set FH_OFFSET to 100 (frequency = base freq + 2.5kHz*FH_OFFSET*FH_CHANNEL) - - /* Use a single 64-byte FIFO for either Tx or Rx */ - CMT2300A_EnableFifoMerge(true); - - /* Go to sleep for configuration to take effect */ - if (!CMT2300A_GoSleep()) { - return false; // CMT2300A not switched to sleep mode! - } - - return true; -} - bool HoymilesRadio_CMT::cmtSwitchInvAndDtuFreq(const uint64_t inv_serial, const uint32_t from_freq_kHz, const uint32_t to_freq_kHz) { const uint8_t fromChannel = cmtFreqToChan("[cmtSwitchInvAndDtuFreq]", "from_freq_kHz", from_freq_kHz); @@ -301,7 +269,7 @@ enumCMTresult HoymilesRadio_CMT::cmtProcess(void) CMT2300A_DelayMs(20); CMT2300A_GoStby(); - cmtConfig(); + _radio->begin(); cmtNextState = CMT_STATE_IDLE; @@ -318,41 +286,24 @@ enumCMTresult HoymilesRadio_CMT::cmtProcess(void) 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(pin_sdio, pin_clk, pin_cs, pin_fcs); - if (!CMT2300A_Init()) { - Hoymiles.getMessageOutput()->println("CMT2300A_Init() failed!"); - return; - } + _radio.reset(new CMT2300a(pin_sdio, pin_clk, pin_cs, pin_fcs)); - /* config registers */ - CMT2300A_ConfigRegBank(CMT2300A_CMT_BANK_ADDR, g_cmt2300aCmtBank, CMT2300A_CMT_BANK_SIZE); - CMT2300A_ConfigRegBank(CMT2300A_SYSTEM_BANK_ADDR, g_cmt2300aSystemBank, CMT2300A_SYSTEM_BANK_SIZE); - CMT2300A_ConfigRegBank(CMT2300A_FREQUENCY_BANK_ADDR, g_cmt2300aFrequencyBank, CMT2300A_FREQUENCY_BANK_SIZE); // cmtBaseChOff860 need to be changed to the same frequency for channel calculation - CMT2300A_ConfigRegBank(CMT2300A_DATA_RATE_BANK_ADDR, g_cmt2300aDataRateBank, CMT2300A_DATA_RATE_BANK_SIZE); - CMT2300A_ConfigRegBank(CMT2300A_BASEBAND_BANK_ADDR, g_cmt2300aBasebandBank, CMT2300A_BASEBAND_BANK_SIZE); - CMT2300A_ConfigRegBank(CMT2300A_TX_BANK_ADDR, g_cmt2300aTxBank, CMT2300A_TX_BANK_SIZE); + _radio->begin(); cmtBaseChOff860 = (860000000 - HOY_BASE_FREQ) / CMT2300A_ONE_STEP_SIZE / FH_OFFSET; - // xosc_aac_code[2:0] = 2 - tmp = (~0x07) & CMT2300A_ReadReg(CMT2300A_CUS_CMT10); - CMT2300A_WriteReg(CMT2300A_CUS_CMT10, tmp | 0x02); + cmtSwitchDtuFreq(HOYMILES_CMT_WORK_FREQ); // start dtu at work freqency, for fast Rx if inverter is already on and frequency switched - if (!cmtConfig()) { - Hoymiles.getMessageOutput()->println("cmtConfig() failed!"); - return; + if (_radio->isChipConnected()) { + Hoymiles.getMessageOutput()->println("Connection successful"); + } else { + Hoymiles.getMessageOutput()->println("Connection error!!"); } attachInterrupt(digitalPinToInterrupt(pin_gpio3), std::bind(&HoymilesRadio_CMT::handleIntr, this), RISING); - 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"); } void HoymilesRadio_CMT::loop() @@ -451,12 +402,25 @@ void HoymilesRadio_CMT::loop() } } +void HoymilesRadio_CMT::setPALevel(int8_t paLevel) +{ + if (!_isInitialized) { + return; + } + + if (_radio->setPALevel(paLevel)) { + Hoymiles.getMessageOutput()->printf("CMT TX power set to %d dBm\r\n", paLevel); + } else { + Hoymiles.getMessageOutput()->printf("CMT TX power %d dBm is not defined! (min: -10 dBm, max: 20 dBm)\r\n", paLevel); + } +} + bool HoymilesRadio_CMT::isConnected() { if (!_isInitialized) { return false; } - return _ChipConnected; + return _radio->isChipConnected(); } void ARDUINO_ISR_ATTR HoymilesRadio_CMT::handleIntr() diff --git a/lib/Hoymiles/src/HoymilesRadio_CMT.h b/lib/Hoymiles/src/HoymilesRadio_CMT.h index 77bbb2abe..fdcad943a 100644 --- a/lib/Hoymiles/src/HoymilesRadio_CMT.h +++ b/lib/Hoymiles/src/HoymilesRadio_CMT.h @@ -8,6 +8,7 @@ #include #include #include +#include // number of fragments hold in buffer #define FRAGMENT_BUFFER_SIZE 30 @@ -41,6 +42,7 @@ class HoymilesRadio_CMT : public HoymilesRadio { public: void init(int8_t pin_sdio, int8_t pin_clk, int8_t pin_cs, int8_t pin_fcs, int8_t pin_gpio3); void loop(); + void setPALevel(int8_t paLevel); bool isConnected(); @@ -49,19 +51,18 @@ class HoymilesRadio_CMT : public HoymilesRadio { void sendEsbPacket(CommandAbstract* cmd); + std::unique_ptr _radio; + volatile bool _packetReceived = false; std::queue _rxBuffer; TimeoutHelper _rxTimeout; TimeoutHelper _txTimeout; - bool _ChipConnected = false; - String cmtChToFreq(const uint8_t channel); void cmtSwitchChannel(const uint8_t channel); uint8_t cmtFreqToChan(const String& func_name, const String& var_name, const uint32_t freq_kHz); bool cmtSwitchDtuFreq(const uint32_t to_freq_kHz); - bool cmtConfig(void); bool cmtSwitchInvAndDtuFreq(const uint64_t inv_serial, const uint32_t from_freq_kHz, const uint32_t to_freq_kHz); enumCMTresult cmtProcess(void);