Browse Source

started implementation of ethernet for opendtufusion board

pull/1262/head
lumapu 1 year ago
parent
commit
7c62df071f
  1. 5
      scripts/applyPatches.py
  2. 2
      src/defines.h
  3. 10
      src/eth/ahoyeth.cpp
  4. 6
      src/eth/ahoyeth.h
  5. 141
      src/eth/ethSpi.h
  6. 102
      src/hm/hmRadio.h
  7. 241
      src/hm/nrfHal.h
  8. 78
      src/hm/spiPatcher.h
  9. 17
      src/hm/spiPatcherHandle.h
  10. 6
      src/platformio.ini

5
scripts/applyPatches.py

@ -26,7 +26,10 @@ def applyPatch(libName, patchFile):
# list of patches to apply (relative to /src)
applyPatch("ESP Async WebServer", "../patches/AsyncWeb_Prometheus.patch")
if env['PIOENV'][:22] != "opendtufusion-ethernet":
applyPatch("ESP Async WebServer", "../patches/AsyncWeb_Prometheus.patch")
if env['PIOENV'][:13] == "opendtufusion":
applyPatch("GxEPD2", "../patches/GxEPD2_SW_SPI.patch")
if env['PIOENV'][:22] == "opendtufusion-ethernet":
applyPatch("RF24", "../patches/RF24_Hal.patch")

2
src/defines.h

@ -13,7 +13,7 @@
//-------------------------------------
#define VERSION_MAJOR 0
#define VERSION_MINOR 8
#define VERSION_PATCH 13
#define VERSION_PATCH 14
//-------------------------------------
typedef struct {

10
src/eth/ahoyeth.cpp

@ -11,7 +11,6 @@
#endif
#include "ahoyeth.h"
//-----------------------------------------------------------------------------
ahoyeth::ahoyeth()
{
@ -41,8 +40,11 @@ void ahoyeth::setup(settings_t *config, uint32_t *utcTimestamp, OnNetworkCB onNe
if(!ETH.config(ip, gateway, mask, dns1, dns2))
DPRINTLN(DBG_ERROR, F("failed to set static IP!"));
}
#if defined(CONFIG_IDF_TARGET_ESP32S3)
mEthSpi.begin(DEF_ETH_MISO_PIN, DEF_ETH_MOSI_PIN, DEF_ETH_SCK_PIN, DEF_ETH_CS_PIN, DEF_ETH_IRQ_PIN, DEF_ETH_RST_PIN);
#else
ETH.begin(DEF_ETH_MISO_PIN, DEF_ETH_MOSI_PIN, DEF_ETH_SCK_PIN, DEF_ETH_CS_PIN, DEF_ETH_IRQ_PIN, ETH_SPI_CLOCK_MHZ, ETH_SPI_HOST);
#endif
}
@ -155,7 +157,11 @@ void ahoyeth::onEthernetEvent(WiFiEvent_t event, arduino_event_info_t info)
case ARDUINO_EVENT_ETH_GOT_IP:
if (!ESP32_W5500_eth_connected)
{
#if defined (CONFIG_IDF_TARGET_ESP32S3)
AWS_LOG3(F("ETH MAC: "), mEthSpi.macAddress(), F(", IPv4: "), ETH.localIP());
#else
AWS_LOG3(F("ETH MAC: "), ETH.macAddress(), F(", IPv4: "), ETH.localIP());
#endif
if (ETH.fullDuplex())
{

6
src/eth/ahoyeth.h

@ -13,6 +13,7 @@
#include <AsyncUDP.h>
#include <DNSServer.h>
#include "ethSpi.h"
#include "../utils/dbg.h"
#include "../config/config.h"
#include "../config/settings.h"
@ -45,6 +46,9 @@ class ahoyeth {
void onEthernetEvent(WiFiEvent_t event, arduino_event_info_t info);
private:
#if defined(CONFIG_IDF_TARGET_ESP32S3)
EthSpi mEthSpi;
#endif
settings_t *mConfig;
uint32_t *mUtcTimestamp;
@ -57,4 +61,4 @@ class ahoyeth {
};
#endif /*__AHOYETH_H__*/
#endif /* defined(ETHERNET) */
#endif /* defined(ETHERNET) */

141
src/eth/ethSpi.h

@ -0,0 +1,141 @@
//-----------------------------------------------------------------------------
// 2023 Ahoy, https://www.mikrocontroller.net/topic/525778
// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/
//-----------------------------------------------------------------------------
#if defined(CONFIG_IDF_TARGET_ESP32S3)
#if defined(ETHERNET)
#ifndef __ETH_SPI_H__
#define __ETH_SPI_H__
#pragma once
#include <Arduino.h>
#include <esp_netif.h>
#include <WiFiGeneric.h>
#include <driver/spi_master.h>
// Functions from WiFiGeneric
void tcpipInit();
void add_esp_interface_netif(esp_interface_t interface, esp_netif_t* esp_netif);
class EthSpi {
public:
EthSpi() :
eth_handle(nullptr),
eth_netif(nullptr) {}
void begin(int8_t pin_miso, int8_t pin_mosi, int8_t pin_sclk, int8_t pin_cs, int8_t pin_int, int8_t pin_rst) {
gpio_reset_pin(static_cast<gpio_num_t>(pin_rst));
gpio_set_direction(static_cast<gpio_num_t>(pin_rst), GPIO_MODE_OUTPUT);
gpio_set_level(static_cast<gpio_num_t>(pin_rst), 0);
gpio_reset_pin(static_cast<gpio_num_t>(pin_sclk));
gpio_reset_pin(static_cast<gpio_num_t>(pin_mosi));
gpio_reset_pin(static_cast<gpio_num_t>(pin_miso));
gpio_reset_pin(static_cast<gpio_num_t>(pin_cs));
gpio_set_pull_mode(static_cast<gpio_num_t>(pin_miso), GPIO_PULLUP_ONLY);
// Workaround, because calling gpio_install_isr_service directly causes issues with attachInterrupt later
attachInterrupt(digitalPinToInterrupt(pin_int), nullptr, CHANGE);
detachInterrupt(digitalPinToInterrupt(pin_int));
gpio_reset_pin(static_cast<gpio_num_t>(pin_int));
gpio_set_pull_mode(static_cast<gpio_num_t>(pin_int), GPIO_PULLUP_ONLY);
spi_bus_config_t buscfg = {
.mosi_io_num = pin_mosi,
.miso_io_num = pin_miso,
.sclk_io_num = pin_sclk,
.quadwp_io_num = -1,
.quadhd_io_num = -1,
.data4_io_num = -1,
.data5_io_num = -1,
.data6_io_num = -1,
.data7_io_num = -1,
.max_transfer_sz = 0, // uses default value internally
.flags = 0,
.intr_flags = 0
};
ESP_ERROR_CHECK(spi_bus_initialize(SPI3_HOST, &buscfg, SPI_DMA_CH_AUTO));
spi_device_interface_config_t devcfg = {
.command_bits = 16, // actually address phase
.address_bits = 8, // actually command phase
.dummy_bits = 0,
.mode = 0,
.duty_cycle_pos = 0,
.cs_ena_pretrans = 0, // only 0 supported
.cs_ena_posttrans = 0, // only 0 supported
.clock_speed_hz = 20000000, // stable with on OpenDTU Fusion Shield
.input_delay_ns = 0,
.spics_io_num = pin_cs,
.flags = 0,
.queue_size = 20,
.pre_cb = nullptr,
.post_cb = nullptr
};
spi_device_handle_t spi;
ESP_ERROR_CHECK(spi_bus_add_device(SPI3_HOST, &devcfg, &spi));
// Reset sequence
delayMicroseconds(500);
gpio_set_level(static_cast<gpio_num_t>(pin_rst), 1);
delayMicroseconds(1000);
// Arduino function to start networking stack if not already started
tcpipInit();
ESP_ERROR_CHECK(tcpip_adapter_set_default_eth_handlers()); // ?
eth_w5500_config_t w5500_config = ETH_W5500_DEFAULT_CONFIG(spi);
w5500_config.int_gpio_num = pin_int;
eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG();
mac_config.rx_task_stack_size = 4096;
esp_eth_mac_t *mac = esp_eth_mac_new_w5500(&w5500_config, &mac_config);
eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG();
phy_config.reset_gpio_num = -1;
esp_eth_phy_t *phy = esp_eth_phy_new_w5500(&phy_config);
esp_eth_config_t eth_config = ETH_DEFAULT_CONFIG(mac, phy);
ESP_ERROR_CHECK(esp_eth_driver_install(&eth_config, &eth_handle));
// Configure MAC address
uint8_t mac_addr[6];
ESP_ERROR_CHECK(esp_efuse_mac_get_default(mac_addr));
mac_addr[5] |= 0x03; // derive ethernet MAC address from base MAC address
ESP_ERROR_CHECK(esp_eth_ioctl(eth_handle, ETH_CMD_S_MAC_ADDR, mac_addr));
esp_netif_config_t netif_config = ESP_NETIF_DEFAULT_ETH();
eth_netif = esp_netif_new(&netif_config);
ESP_ERROR_CHECK(esp_netif_attach(eth_netif, esp_eth_new_netif_glue(eth_handle)));
// Add to Arduino
add_esp_interface_netif(ESP_IF_ETH, eth_netif);
ESP_ERROR_CHECK(esp_eth_start(eth_handle));
}
String macAddress() {
uint8_t mac_addr[6] = {0, 0, 0, 0, 0, 0};
esp_eth_ioctl(eth_handle, ETH_CMD_G_MAC_ADDR, mac_addr);
char mac_addr_str[24];
snprintf(mac_addr_str, sizeof(mac_addr_str), "%02X:%02X:%02X:%02X:%02X:%02X", mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]);
return String(mac_addr_str);
}
private:
esp_eth_handle_t eth_handle;
esp_netif_t *eth_netif;
};
#endif /*__ETH_SPI_H__*/
#endif /*ETHERNET*/
#endif /*CONFIG_IDF_TARGET_ESP32S3*/

102
src/hm/hmRadio.h

@ -9,6 +9,7 @@
#include <RF24.h>
#include "SPI.h"
#include "radio.h"
#include "nrfHal.h"
#define SPI_SPEED 1000000
@ -28,7 +29,7 @@ const char* const rf24AmpPowerNames[] = {"MIN", "LOW", "HIGH", "MAX"};
template <uint8_t IRQ_PIN = DEF_NRF_IRQ_PIN, uint8_t CE_PIN = DEF_NRF_CE_PIN, uint8_t CS_PIN = DEF_NRF_CS_PIN, uint8_t AMP_PWR = RF24_PA_LOW, uint8_t SCLK_PIN = DEF_NRF_SCLK_PIN, uint8_t MOSI_PIN = DEF_NRF_MOSI_PIN, uint8_t MISO_PIN = DEF_NRF_MISO_PIN, uint32_t DTU_SN = 0x81001765>
class HmRadio : public Radio {
public:
HmRadio() : mNrf24(CE_PIN, CS_PIN, SPI_SPEED) {
HmRadio() {
mDtuSn = DTU_SN;
mIrqRcvd = false;
}
@ -36,6 +37,14 @@ class HmRadio : public Radio {
void setup(bool *serialDebug, bool *privacyMode, bool *printWholeTrace, uint8_t irq = IRQ_PIN, uint8_t ce = CE_PIN, uint8_t cs = CS_PIN, uint8_t sclk = SCLK_PIN, uint8_t mosi = MOSI_PIN, uint8_t miso = MISO_PIN) {
DPRINTLN(DBG_VERBOSE, F("hmRadio.h:setup"));
#if defined(CONFIG_IDF_TARGET_ESP32S3)
DBGPRINTLN("1");
delay(300);
mNrfHal->init(mosi, miso, sclk, cs, ce);
mNrf24 = new RF24(mNrfHal);
#else
mNrf24 = new RF24(CE_PIN, CS_PIN, SPI_SPEED);
#endif
pinMode(irq, INPUT_PULLUP);
mSerialDebug = serialDebug;
@ -56,39 +65,45 @@ class HmRadio : public Radio {
DTU_RADIO_ID = ((uint64_t)(((mDtuSn >> 24) & 0xFF) | ((mDtuSn >> 8) & 0xFF00) | ((mDtuSn << 8) & 0xFF0000) | ((mDtuSn << 24) & 0xFF000000)) << 8) | 0x01;
#ifdef ESP32
#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
mSpi = new SPIClass(HSPI);
#else
mSpi = new SPIClass(VSPI);
#if !defined(CONFIG_IDF_TARGET_ESP32S3)
#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S2
mSpi = new SPIClass(HSPI);
#else
mSpi = new SPIClass(VSPI);
#endif
mSpi->begin(sclk, miso, mosi, cs);
#endif
mSpi->begin(sclk, miso, mosi, cs);
#else
//the old ESP82xx cannot freely place their SPI pins
mSpi = new SPIClass();
mSpi->begin();
#endif
mNrf24.begin(mSpi, ce, cs);
mNrf24.setRetries(3, 15); // 3*250us + 250us and 15 loops -> 15ms
mNrf24.setChannel(mRfChLst[mRxChIdx]);
mNrf24.startListening();
mNrf24.setDataRate(RF24_250KBPS);
mNrf24.setAutoAck(true);
mNrf24.enableDynamicAck();
mNrf24.enableDynamicPayloads();
mNrf24.setCRCLength(RF24_CRC_16);
mNrf24.setAddressWidth(5);
mNrf24.openReadingPipe(1, reinterpret_cast<uint8_t*>(&DTU_RADIO_ID));
#if defined(CONFIG_IDF_TARGET_ESP32S3)
mNrf24->begin();
#else
mNrf24->begin(mSpi, ce, cs);
#endif
mNrf24->setRetries(3, 15); // 3*250us + 250us and 15 loops -> 15ms
mNrf24->setChannel(mRfChLst[mRxChIdx]);
mNrf24->startListening();
mNrf24->setDataRate(RF24_250KBPS);
mNrf24->setAutoAck(true);
mNrf24->enableDynamicAck();
mNrf24->enableDynamicPayloads();
mNrf24->setCRCLength(RF24_CRC_16);
mNrf24->setAddressWidth(5);
mNrf24->openReadingPipe(1, reinterpret_cast<uint8_t*>(&DTU_RADIO_ID));
// enable all receiving interrupts
mNrf24.maskIRQ(false, false, false);
mNrf24->maskIRQ(false, false, false);
mNrf24.setPALevel(1); // low is default
mNrf24->setPALevel(1); // low is default
if(mNrf24.isChipConnected()) {
if(mNrf24->isChipConnected()) {
DPRINTLN(DBG_INFO, F("Radio Config:"));
mNrf24.printPrettyDetails();
mNrf24->printPrettyDetails();
DPRINT(DBG_INFO, F("DTU_SN: 0x"));
DBGPRINTLN(String(mDtuSn, HEX));
} else
@ -100,14 +115,14 @@ class HmRadio : public Radio {
return; // nothing to do
mIrqRcvd = false;
bool tx_ok, tx_fail, rx_ready;
mNrf24.whatHappened(tx_ok, tx_fail, rx_ready); // resets the IRQ pin to HIGH
mNrf24.flush_tx(); // empty TX FIFO
mNrf24->whatHappened(tx_ok, tx_fail, rx_ready); // resets the IRQ pin to HIGH
mNrf24->flush_tx(); // empty TX FIFO
// start listening
//mNrf24.setChannel(23);
//mNrf24->setChannel(23);
//mRxChIdx = 0;
mNrf24.setChannel(mRfChLst[mRxChIdx]);
mNrf24.startListening();
mNrf24->setChannel(mRfChLst[mRxChIdx]);
mNrf24->startListening();
if(NULL == mLastIv) // prevent reading on NULL object!
return;
@ -128,7 +143,7 @@ class HmRadio : public Radio {
// switch to next RX channel
if(++mRxChIdx >= RF_CHANNELS)
mRxChIdx = 0;
mNrf24.setChannel(mRfChLst[mRxChIdx]);
mNrf24->setChannel(mRfChLst[mRxChIdx]);
startMicros = micros() + 5110;
}
// not finished but time is over
@ -140,7 +155,7 @@ class HmRadio : public Radio {
bool isChipConnected(void) {
//DPRINTLN(DBG_VERBOSE, F("hmRadio.h:isChipConnected"));
return mNrf24.isChipConnected();
return mNrf24->isChipConnected();
}
void sendControlPacket(Inverter<> *iv, uint8_t cmd, uint16_t *data, bool isRetransmit) {
@ -229,31 +244,31 @@ class HmRadio : public Radio {
}
uint8_t getDataRate(void) {
if(!mNrf24.isChipConnected())
if(!mNrf24->isChipConnected())
return 3; // unknown
return mNrf24.getDataRate();
return mNrf24->getDataRate();
}
bool isPVariant(void) {
return mNrf24.isPVariant();
return mNrf24->isPVariant();
}
private:
inline bool getReceived(void) {
bool tx_ok, tx_fail, rx_ready;
mNrf24.whatHappened(tx_ok, tx_fail, rx_ready); // resets the IRQ pin to HIGH
mNrf24->whatHappened(tx_ok, tx_fail, rx_ready); // resets the IRQ pin to HIGH
bool isLastPackage = false;
while(mNrf24.available()) {
while(mNrf24->available()) {
uint8_t len;
len = mNrf24.getDynamicPayloadSize(); // if payload size > 32, corrupt payload has been flushed
len = mNrf24->getDynamicPayloadSize(); // if payload size > 32, corrupt payload has been flushed
if (len > 0) {
packet_t p;
p.ch = mRfChLst[mRxChIdx];
p.len = (len > MAX_RF_PAYLOAD_SIZE) ? MAX_RF_PAYLOAD_SIZE : len;
p.rssi = mNrf24.testRPD() ? -64 : -75;
p.rssi = mNrf24->testRPD() ? -64 : -75;
p.millis = millis() - mMillis;
mNrf24.read(p.packet, p.len);
mNrf24->read(p.packet, p.len);
if (p.packet[0] != 0x00) {
if(!checkIvSerial(p.packet, mLastIv)) {
DPRINT(DBG_WARN, "RX other inverter ");
@ -281,7 +296,7 @@ class HmRadio : public Radio {
}
void sendPacket(Inverter<> *iv, uint8_t len, bool isRetransmit, bool appendCrc16=true) {
mNrf24.setPALevel(iv->config->powerLevel & 0x03);
mNrf24->setPALevel(iv->config->powerLevel & 0x03);
updateCrcs(&len, appendCrc16);
// set TX and RX channels
@ -303,10 +318,10 @@ class HmRadio : public Radio {
DBGHEXLN(mTxBuf[9]);
}
mNrf24.stopListening();
mNrf24.setChannel(mTxChIdx);
mNrf24.openWritingPipe(reinterpret_cast<uint8_t*>(&iv->radioId.u64));
mNrf24.startWrite(mTxBuf, len, false); // false = request ACK response
mNrf24->stopListening();
mNrf24->setChannel(mTxChIdx);
mNrf24->openWritingPipe(reinterpret_cast<uint8_t*>(&iv->radioId.u64));
mNrf24->startWrite(mTxBuf, len, false); // false = request ACK response
mMillis = millis();
mLastIv = iv;
@ -336,7 +351,8 @@ class HmRadio : public Radio {
uint32_t mMillis;
SPIClass* mSpi;
RF24 mNrf24;
RF24 *mNrf24;
nrfHal *mNrfHal;
Inverter<> *mLastIv = NULL;
};

241
src/hm/nrfHal.h

@ -0,0 +1,241 @@
//-----------------------------------------------------------------------------
// 2023 Ahoy, https://www.mikrocontroller.net/topic/525778
// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/
//-----------------------------------------------------------------------------
#ifndef __NRF_HAL_H__
#define __NRF_HAL_H__
#pragma once
#include "spiPatcher.h"
#include <esp_rom_gpio.h>
#include <RF24_hal.h>
#define NRF_MAX_TRANSFER_SZ 64
#define NRF_DEFAULT_SPI_SPEED 10000000 // 10 MHz
class nrfHal: public RF24_hal, public SpiPatcherHandle {
public:
nrfHal() : mSpiPatcher(SPI2_HOST) {}
void patch() override {
esp_rom_gpio_connect_out_signal(mPinMosi, spi_periph_signal[host_device].spid_out, false, false);
esp_rom_gpio_connect_in_signal(mPinMiso, spi_periph_signal[host_device].spiq_in, false);
esp_rom_gpio_connect_out_signal(mPinClk, spi_periph_signal[host_device].spiclk_out, false, false);
}
void unpatch() override {
esp_rom_gpio_connect_out_signal(mPinMosi, SIG_GPIO_OUT_IDX, false, false);
esp_rom_gpio_connect_in_signal(mPinMiso, GPIO_MATRIX_CONST_ZERO_INPUT, false);
esp_rom_gpio_connect_out_signal(mPinClk, SIG_GPIO_OUT_IDX, false, false);
}
void init(int8_t mosi, int8_t miso, int8_t sclk, int8_t cs, int8_t en, int32_t speed = 0) {
DHEX(mosi);
DBGPRINT(" ");
DHEX(miso);
DBGPRINT(" ");
DHEX(sclk);
DBGPRINT(" ");
DHEX(cs);
DBGPRINT(" ");
DHEX(en);
DBGPRINTLN(" ");
delay(300);
mPinMosi = static_cast<>(mosi);
DBGPRINTLN("21");
delay(300);
mPinMiso = static_cast<gpio_num_t>(miso);
DBGPRINTLN("22");
delay(300);
mPinClk = static_cast<gpio_num_t>(sclk);
DBGPRINTLN("23");
delay(300);
mPinCs = static_cast<gpio_num_t>(cs);
DBGPRINTLN("24");
delay(300);
mPinEn = static_cast<gpio_num_t>(en);
DBGPRINTLN("25");
delay(300);
mSpiSpeed = speed;
DBGPRINTLN("3");
delay(300);
host_device = mSpiPatcher.init();
DBGPRINTLN("4");
delay(300);
gpio_reset_pin(mPinMosi);
gpio_set_direction(mPinMosi, GPIO_MODE_OUTPUT);
gpio_set_level(mPinMosi, 1);
gpio_reset_pin(mPinMiso);
gpio_set_direction(mPinMiso, GPIO_MODE_INPUT);
gpio_reset_pin(mPinClk);
gpio_set_direction(mPinClk, GPIO_MODE_OUTPUT);
gpio_set_level(mPinClk, 0);
gpio_reset_pin(mPinCs);
spi_device_interface_config_t devcfg = {
.command_bits = 0,
.address_bits = 0,
.dummy_bits = 0,
.mode = 0,
.duty_cycle_pos = 0,
.cs_ena_pretrans = 0,
.cs_ena_posttrans = 0,
.clock_speed_hz = mSpiSpeed,
.input_delay_ns = 0,
.spics_io_num = mPinCs,
.flags = 0,
.queue_size = 1,
.pre_cb = nullptr,
.post_cb = nullptr
};
ESP_ERROR_CHECK(spi_bus_add_device(host_device, &devcfg, &spi));
gpio_reset_pin(mPinEn);
gpio_set_direction(mPinEn, GPIO_MODE_OUTPUT);
gpio_set_level(mPinEn, 0);
}
bool begin() override {
return true;
}
void end() override {}
void ce(bool level) override {
gpio_set_level(mPinEn, level);
}
uint8_t write(uint8_t cmd, const uint8_t* buf, uint8_t len) override {
uint8_t data[NRF_MAX_TRANSFER_SZ];
data[0] = cmd;
std::copy(&buf[0], &buf[len], &data[1]);
request_spi();
size_t spiLen = (static_cast<size_t>(len) + 1u) << 3;
spi_transaction_t t = {
.flags = 0,
.cmd = 0,
.addr = 0,
.length = spiLen,
.rxlength = spiLen,
.user = NULL,
.tx_buffer = data,
.rx_buffer = data
};
ESP_ERROR_CHECK(spi_device_polling_transmit(spi, &t));
release_spi();
return data[0]; // status
}
uint8_t write(uint8_t cmd, const uint8_t* buf, uint8_t data_len, uint8_t blank_len) override {
uint8_t data[NRF_MAX_TRANSFER_SZ];
data[0] = cmd;
memset(data, 0, NRF_MAX_TRANSFER_SZ);
std::copy(&buf[0], &buf[data_len], &data[1]);
request_spi();
size_t spiLen = (static_cast<size_t>(data_len) + static_cast<size_t>(blank_len) + 1u) << 3;
spi_transaction_t t = {
.flags = 0,
.cmd = 0,
.addr = 0,
.length = spiLen,
.rxlength = spiLen,
.user = NULL,
.tx_buffer = data,
.rx_buffer = data
};
ESP_ERROR_CHECK(spi_device_polling_transmit(spi, &t));
release_spi();
return data[0]; // status
}
uint8_t read(uint8_t cmd, uint8_t* buf, uint8_t len) override {
uint8_t data[NRF_MAX_TRANSFER_SZ];
data[0] = cmd;
memset(&data[1], 0xff, len);
request_spi();
size_t spiLen = (static_cast<size_t>(len) + 1u) << 3;
spi_transaction_t t = {
.flags = 0,
.cmd = 0,
.addr = 0,
.length = spiLen,
.rxlength = spiLen,
.user = NULL,
.tx_buffer = data,
.rx_buffer = data
};
ESP_ERROR_CHECK(spi_device_polling_transmit(spi, &t));
release_spi();
std::copy(&data[1], &data[len+1], buf);
return data[0]; // status
}
uint8_t read(uint8_t cmd, uint8_t* buf, uint8_t data_len, uint8_t blank_len) override {
uint8_t data[NRF_MAX_TRANSFER_SZ];
data[0] = cmd;
memset(&data[1], 0xff, (data_len + blank_len));
request_spi();
size_t spiLen = (static_cast<size_t>(data_len) + static_cast<size_t>(blank_len) + 1u) << 3;
spi_transaction_t t = {
.flags = 0,
.cmd = 0,
.addr = 0,
.length = spiLen,
.rxlength = spiLen,
.user = NULL,
.tx_buffer = data,
.rx_buffer = data
};
ESP_ERROR_CHECK(spi_device_polling_transmit(spi, &t));
release_spi();
std::copy(&data[1], &data[data_len+1], buf);
return data[0]; // status
}
private:
inline void request_spi() {
mSpiPatcher.request(this);
}
inline void release_spi() {
mSpiPatcher.release();
}
private:
gpio_num_t mPinMosi = GPIO_NUM_NC;
gpio_num_t mPinMiso = GPIO_NUM_NC;
gpio_num_t mPinClk = GPIO_NUM_NC;
gpio_num_t mPinCs = GPIO_NUM_NC;
gpio_num_t mPinEn = GPIO_NUM_NC;
int32_t mSpiSpeed = NRF_DEFAULT_SPI_SPEED;
spi_host_device_t host_device;
spi_device_handle_t spi;
SpiPatcher mSpiPatcher;
};
#endif /*__NRF_HAL_H__*/

78
src/hm/spiPatcher.h

@ -0,0 +1,78 @@
//-----------------------------------------------------------------------------
// 2023 Ahoy, https://www.mikrocontroller.net/topic/525778
// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/
//-----------------------------------------------------------------------------
#ifndef __SPI_PATCHER_H__
#define __SPI_PATCHER_H__
#pragma once
#include "spiPatcherHandle.h"
#include <driver/spi_master.h>
#include <freertos/semphr.h>
class SpiPatcher {
public:
explicit SpiPatcher(spi_host_device_t host_device) :
host_device(host_device), initialized(false), cur_handle(nullptr) {
// Use binary semaphore instead of mutex for performance reasons
mutex = xSemaphoreCreateBinaryStatic(&mutex_buffer);
xSemaphoreGive(mutex);
}
~SpiPatcher() { vSemaphoreDelete(mutex); }
spi_host_device_t init() {
if (!initialized) {
initialized = true;
spi_bus_config_t buscfg = {
.mosi_io_num = -1,
.miso_io_num = -1,
.sclk_io_num = -1,
.quadwp_io_num = -1,
.quadhd_io_num = -1,
.data4_io_num = -1,
.data5_io_num = -1,
.data6_io_num = -1,
.data7_io_num = -1,
.max_transfer_sz = SOC_SPI_MAXIMUM_BUFFER_SIZE,
.flags = 0,
.intr_flags = 0
};
ESP_ERROR_CHECK(spi_bus_initialize(host_device, &buscfg, SPI_DMA_DISABLED));
}
return host_device;
}
inline void request(SpiPatcherHandle* handle) {
xSemaphoreTake(mutex, portMAX_DELAY);
if (cur_handle != handle) {
if (cur_handle) {
cur_handle->unpatch();
}
cur_handle = handle;
if (cur_handle) {
cur_handle->patch();
}
}
}
inline void release() {
xSemaphoreGive(mutex);
}
private:
const spi_host_device_t host_device;
bool initialized;
SpiPatcherHandle* cur_handle;
SemaphoreHandle_t mutex;
StaticSemaphore_t mutex_buffer;
};
#endif /*__SPI_PATCHER_H__*/

17
src/hm/spiPatcherHandle.h

@ -0,0 +1,17 @@
//-----------------------------------------------------------------------------
// 2023 Ahoy, https://www.mikrocontroller.net/topic/525778
// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/
//-----------------------------------------------------------------------------
#ifndef __SPI_PATCHER_HANDLE_H__
#define __SPI_PATCHER_HANDLE_H__
#pragma once
class SpiPatcherHandle {
public:
virtual ~SpiPatcherHandle() {}
virtual void patch() = 0;
virtual void unpatch() = 0;
};
#endif /*__SPI_PATCHER_HANDLE_H__*/

6
src/platformio.ini

@ -91,8 +91,7 @@ monitor_filters =
platform = espressif32
board = esp32dev
lib_deps =
khoih-prog/AsyncWebServer_ESP32_W5500
khoih-prog/AsyncUDP_ESP32_W5500
https://github.com/yubox-node-org/ESPAsyncWebServer
nrf24/RF24 @ ^1.4.8
paulstoffregen/Time @ ^1.6.1
https://github.com/bertmelis/espMqttClient#v1.5.0
@ -152,7 +151,7 @@ board = esp32-s3-devkitc-1
lib_deps =
khoih-prog/AsyncWebServer_ESP32_W5500
khoih-prog/AsyncUDP_ESP32_W5500
nrf24/RF24 @ ^1.4.8
https://github.com/nrf24/RF24 @ ^1.4.8
paulstoffregen/Time @ ^1.6.1
https://github.com/bertmelis/espMqttClient#v1.5.0
bblanchon/ArduinoJson @ ^6.21.3
@ -184,6 +183,7 @@ build_flags = ${env.build_flags}
-DDEF_LED1=17
-DLED_ACTIVE_HIGH
-DARDUINO_USB_MODE=1
-DARDUINO_USB_CDC_ON_BOOT=1
monitor_filters =
esp32_exception_decoder, colorize

Loading…
Cancel
Save