mirror of https://github.com/lumapu/ahoy.git
lumapu
1 year ago
10 changed files with 557 additions and 51 deletions
@ -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*/ |
@ -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__*/ |
@ -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__*/ |
@ -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__*/ |
Loading…
Reference in new issue