mirror of
https://github.com/lumapu/ahoy.git
synced 2025-04-28 17:56:21 +02:00
started implementation of ethernet for opendtufusion board
This commit is contained in:
parent
cfef2ce63a
commit
7c62df071f
10 changed files with 556 additions and 50 deletions
|
@ -26,7 +26,10 @@ def applyPatch(libName, patchFile):
|
|||
|
||||
|
||||
# list of patches to apply (relative to /src)
|
||||
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")
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
//-------------------------------------
|
||||
#define VERSION_MAJOR 0
|
||||
#define VERSION_MINOR 8
|
||||
#define VERSION_PATCH 13
|
||||
#define VERSION_PATCH 14
|
||||
|
||||
//-------------------------------------
|
||||
typedef struct {
|
||||
|
|
|
@ -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())
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
141
src/eth/ethSpi.h
Normal file
141
src/eth/ethSpi.h
Normal file
|
@ -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(ð_config, ð_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*/
|
|
@ -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
|
||||
#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
|
||||
#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
|
||||
#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));
|
||||
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
Normal file
241
src/hm/nrfHal.h
Normal file
|
@ -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
Normal file
78
src/hm/spiPatcher.h
Normal file
|
@ -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
Normal file
17
src/hm/spiPatcherHandle.h
Normal file
|
@ -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__*/
|
|
@ -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…
Add table
Reference in a new issue