First step towards a modular CMT2300 driver similar to the NRF24 one

This commit is contained in:
Thomas Basler 2023-03-22 19:59:03 +01:00
parent 035fdbc54a
commit 098691af9d
8 changed files with 268 additions and 71 deletions

View File

@ -26,9 +26,9 @@
* @name CMT2300A_InitSpi * @name CMT2300A_InitSpi
* @desc Initializes the CMT2300A SPI interface. * @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);
} }
/*! ******************************************************** /*! ********************************************************

View File

@ -36,7 +36,7 @@ extern "C" {
#define CMT2300A_GetTickCount() millis() #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); uint8_t CMT2300A_ReadReg(uint8_t addr);
void CMT2300A_WriteReg(uint8_t addr, uint8_t dat); void CMT2300A_WriteReg(uint8_t addr, uint8_t dat);

View File

@ -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;
}

View File

@ -0,0 +1,42 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <stdint.h>
#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;
};

View File

@ -3,11 +3,9 @@
#include <driver/spi_master.h> #include <driver/spi_master.h>
#include <esp_rom_gpio.h> // for esp_rom_gpio_connect_out_signal #include <esp_rom_gpio.h> // for esp_rom_gpio_connect_out_signal
#define CMT_SPI_CLK 4000000 // 4 MHz
spi_device_handle_t spi_reg, spi_fifo; 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 = { spi_bus_config_t buscfg = {
.mosi_io_num = pin_sdio, .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, .address_bits = 0,
.dummy_bits = 0, .dummy_bits = 0,
.mode = 0, // SPI mode 0 .mode = 0, // SPI mode 0
.clock_speed_hz = CMT_SPI_CLK, .clock_speed_hz = spi_speed,
.spics_io_num = pin_cs, .spics_io_num = pin_cs,
.flags = SPI_DEVICE_HALFDUPLEX | SPI_DEVICE_3WIRE, .flags = SPI_DEVICE_HALFDUPLEX | SPI_DEVICE_3WIRE,
.queue_size = 1, .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, .dummy_bits = 0,
.mode = 0, // SPI mode 0 .mode = 0, // SPI mode 0
.cs_ena_pretrans = 2, .cs_ena_pretrans = 2,
.cs_ena_posttrans = (uint8_t)(1 / (CMT_SPI_CLK * 10e6 * 2) + 2), // >2 us .cs_ena_posttrans = (uint8_t)(1 / (spi_speed * 10e6 * 2) + 2), // >2 us
.clock_speed_hz = CMT_SPI_CLK, .clock_speed_hz = spi_speed,
.spics_io_num = pin_fcs, .spics_io_num = pin_fcs,
.flags = SPI_DEVICE_HALFDUPLEX | SPI_DEVICE_3WIRE, .flags = SPI_DEVICE_HALFDUPLEX | SPI_DEVICE_3WIRE,
.queue_size = 1, .queue_size = 1,

View File

@ -3,7 +3,7 @@
#include <stdint.h> #include <stdint.h>
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); void cmt_spi3_write(uint8_t addr, uint8_t dat);
uint8_t cmt_spi3_read(uint8_t addr); uint8_t cmt_spi3_read(uint8_t addr);

View File

@ -7,10 +7,7 @@
#include "crc.h" #include "crc.h"
#include <FunctionalInterrupt.h> #include <FunctionalInterrupt.h>
#include <cmt2300a.h> #include <cmt2300a.h>
#include <cmt2300a_params.h>
#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_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 #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; 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) 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); 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_DelayMs(20);
CMT2300A_GoStby(); CMT2300A_GoStby();
cmtConfig(); _radio->begin();
cmtNextState = CMT_STATE_IDLE; 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) 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; _dtuSerial.u64 = 0;
uint8_t tmp;
CMT2300A_InitSpi(pin_sdio, pin_clk, pin_cs, pin_fcs); _radio.reset(new CMT2300a(pin_sdio, pin_clk, pin_cs, pin_fcs));
if (!CMT2300A_Init()) {
Hoymiles.getMessageOutput()->println("CMT2300A_Init() failed!");
return;
}
/* config registers */ _radio->begin();
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);
cmtBaseChOff860 = (860000000 - HOY_BASE_FREQ) / CMT2300A_ONE_STEP_SIZE / FH_OFFSET; cmtBaseChOff860 = (860000000 - HOY_BASE_FREQ) / CMT2300A_ONE_STEP_SIZE / FH_OFFSET;
// xosc_aac_code[2:0] = 2 cmtSwitchDtuFreq(HOYMILES_CMT_WORK_FREQ); // start dtu at work freqency, for fast Rx if inverter is already on and frequency switched
tmp = (~0x07) & CMT2300A_ReadReg(CMT2300A_CUS_CMT10);
CMT2300A_WriteReg(CMT2300A_CUS_CMT10, tmp | 0x02);
if (!cmtConfig()) { if (_radio->isChipConnected()) {
Hoymiles.getMessageOutput()->println("cmtConfig() failed!"); Hoymiles.getMessageOutput()->println("Connection successful");
return; } else {
Hoymiles.getMessageOutput()->println("Connection error!!");
} }
attachInterrupt(digitalPinToInterrupt(pin_gpio3), std::bind(&HoymilesRadio_CMT::handleIntr, this), RISING); 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; _isInitialized = true;
Hoymiles.getMessageOutput()->println("CMT init successful");
} }
void HoymilesRadio_CMT::loop() 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() bool HoymilesRadio_CMT::isConnected()
{ {
if (!_isInitialized) { if (!_isInitialized) {
return false; return false;
} }
return _ChipConnected; return _radio->isChipConnected();
} }
void ARDUINO_ISR_ATTR HoymilesRadio_CMT::handleIntr() void ARDUINO_ISR_ATTR HoymilesRadio_CMT::handleIntr()

View File

@ -8,6 +8,7 @@
#include <Arduino.h> #include <Arduino.h>
#include <memory> #include <memory>
#include <queue> #include <queue>
#include <cmt2300wrapper.h>
// number of fragments hold in buffer // number of fragments hold in buffer
#define FRAGMENT_BUFFER_SIZE 30 #define FRAGMENT_BUFFER_SIZE 30
@ -41,6 +42,7 @@ class HoymilesRadio_CMT : public HoymilesRadio {
public: public:
void init(int8_t pin_sdio, int8_t pin_clk, int8_t pin_cs, int8_t pin_fcs, int8_t pin_gpio3); 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 loop();
void setPALevel(int8_t paLevel);
bool isConnected(); bool isConnected();
@ -49,19 +51,18 @@ private:
void sendEsbPacket(CommandAbstract* cmd); void sendEsbPacket(CommandAbstract* cmd);
std::unique_ptr<CMT2300a> _radio;
volatile bool _packetReceived = false; volatile bool _packetReceived = false;
std::queue<fragment_t> _rxBuffer; std::queue<fragment_t> _rxBuffer;
TimeoutHelper _rxTimeout; TimeoutHelper _rxTimeout;
TimeoutHelper _txTimeout; TimeoutHelper _txTimeout;
bool _ChipConnected = false;
String cmtChToFreq(const uint8_t channel); String cmtChToFreq(const uint8_t channel);
void cmtSwitchChannel(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); 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 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); bool cmtSwitchInvAndDtuFreq(const uint64_t inv_serial, const uint32_t from_freq_kHz, const uint32_t to_freq_kHz);
enumCMTresult cmtProcess(void); enumCMTresult cmtProcess(void);