mirror of https://github.com/lumapu/ahoy.git
lumapu
1 year ago
12 changed files with 313 additions and 324 deletions
@ -1,78 +0,0 @@ |
|||
//-----------------------------------------------------------------------------
|
|||
// 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,196 @@ |
|||
//-----------------------------------------------------------------------------
|
|||
// 2023 Ahoy, https://www.mikrocontroller.net/topic/525778
|
|||
// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/
|
|||
//-----------------------------------------------------------------------------
|
|||
|
|||
#ifndef __CMT_HAL_H__ |
|||
#define __CMT_HAL_H__ |
|||
|
|||
#pragma once |
|||
|
|||
#include "../utils/SpiPatcher.h" |
|||
|
|||
#include <driver/gpio.h> |
|||
|
|||
#define CMT_DEFAULT_SPI_SPEED 4000000 // 4 MHz
|
|||
|
|||
class cmtHal : public SpiPatcherHandle { |
|||
public: |
|||
cmtHal() { |
|||
mSpiPatcher = SpiPatcher::getInstance(SPI2_HOST); |
|||
} |
|||
|
|||
void patch() override { |
|||
esp_rom_gpio_connect_out_signal(mPinSdio, spi_periph_signal[mHostDevice].spid_out, false, false); |
|||
esp_rom_gpio_connect_in_signal(mPinSdio, spi_periph_signal[mHostDevice].spid_in, false); |
|||
esp_rom_gpio_connect_out_signal(mPinClk, spi_periph_signal[mHostDevice].spiclk_out, false, false); |
|||
} |
|||
|
|||
void unpatch() override { |
|||
esp_rom_gpio_connect_out_signal(mPinSdio, SIG_GPIO_OUT_IDX, false, false); |
|||
esp_rom_gpio_connect_in_signal(mPinSdio, GPIO_MATRIX_CONST_ZERO_INPUT, false); |
|||
esp_rom_gpio_connect_out_signal(mPinClk, SIG_GPIO_OUT_IDX, false, false); |
|||
} |
|||
|
|||
void init(int8_t sdio, int8_t clk, int8_t cs, int8_t fcs, int32_t speed = CMT_DEFAULT_SPI_SPEED) { |
|||
mPinSdio = static_cast<gpio_num_t>(sdio); |
|||
mPinClk = static_cast<gpio_num_t>(clk); |
|||
mPinCs = static_cast<gpio_num_t>(cs); |
|||
mPinFcs = static_cast<gpio_num_t>(fcs); |
|||
mSpiSpeed = speed; |
|||
|
|||
mHostDevice = mSpiPatcher->getDevice(); |
|||
|
|||
gpio_reset_pin(mPinSdio); |
|||
gpio_set_direction(mPinSdio, GPIO_MODE_INPUT_OUTPUT); |
|||
gpio_set_level(mPinSdio, 1); |
|||
|
|||
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_reg = { |
|||
.command_bits = 1, |
|||
.address_bits = 7, |
|||
.dummy_bits = 0, |
|||
.mode = 0, |
|||
.duty_cycle_pos = 0, |
|||
.cs_ena_pretrans = 1, |
|||
.cs_ena_posttrans = 1, |
|||
.clock_speed_hz = mSpiSpeed, |
|||
.input_delay_ns = 0, |
|||
.spics_io_num = mPinCs, |
|||
.flags = SPI_DEVICE_HALFDUPLEX | SPI_DEVICE_3WIRE, |
|||
.queue_size = 1, |
|||
.pre_cb = nullptr, |
|||
.post_cb = nullptr |
|||
}; |
|||
ESP_ERROR_CHECK(spi_bus_add_device(mHostDevice, &devcfg_reg, &spi_reg)); |
|||
|
|||
gpio_reset_pin(mPinFcs); |
|||
spi_device_interface_config_t devcfg_fifo = { |
|||
.command_bits = 0, |
|||
.address_bits = 0, |
|||
.dummy_bits = 0, |
|||
.mode = 0, |
|||
.duty_cycle_pos = 0, |
|||
.cs_ena_pretrans = 2, |
|||
.cs_ena_posttrans = static_cast<uint8_t>(2 * mSpiSpeed / 1000000), // >2 us
|
|||
.clock_speed_hz = mSpiSpeed, |
|||
.input_delay_ns = 0, |
|||
.spics_io_num = mPinFcs, |
|||
.flags = SPI_DEVICE_HALFDUPLEX | SPI_DEVICE_3WIRE, |
|||
.queue_size = 1, |
|||
.pre_cb = nullptr, |
|||
.post_cb = nullptr |
|||
}; |
|||
ESP_ERROR_CHECK(spi_bus_add_device(mHostDevice, &devcfg_fifo, &spi_fifo)); |
|||
} |
|||
|
|||
uint8_t readReg(uint8_t addr) { |
|||
uint8_t data; |
|||
|
|||
request_spi(); |
|||
|
|||
spi_transaction_t t = { |
|||
.flags = 0, |
|||
.cmd = 1, |
|||
.addr = addr, |
|||
.length = 0, |
|||
.rxlength = 8, |
|||
.user = NULL, |
|||
.tx_buffer = NULL, |
|||
.rx_buffer = &data |
|||
}; |
|||
ESP_ERROR_CHECK(spi_device_polling_transmit(spi_reg, &t)); |
|||
|
|||
release_spi(); |
|||
|
|||
return data; |
|||
} |
|||
|
|||
void writeReg(uint8_t addr, uint8_t data) { |
|||
request_spi(); |
|||
|
|||
spi_transaction_t t = { |
|||
.flags = 0, |
|||
.cmd = 0, |
|||
.addr = addr, |
|||
.length = 8, |
|||
.rxlength = 0, |
|||
.user = NULL, |
|||
.tx_buffer = &data, |
|||
.rx_buffer = NULL |
|||
}; |
|||
ESP_ERROR_CHECK(spi_device_polling_transmit(spi_reg, &t)); |
|||
|
|||
release_spi(); |
|||
} |
|||
|
|||
void readFifo(uint8_t buf[], uint8_t *len, uint8_t maxlen) { |
|||
request_spi(); |
|||
|
|||
spi_transaction_t t = { |
|||
.flags = 0, |
|||
.cmd = 0, |
|||
.addr = 0, |
|||
.length = 0, |
|||
.rxlength = 8, |
|||
.user = NULL, |
|||
.tx_buffer = NULL, |
|||
.rx_buffer = NULL |
|||
}; |
|||
for (uint8_t i = 0; i < maxlen; i++) { |
|||
if(0 == i) |
|||
t.rx_buffer = len; |
|||
else |
|||
t.rx_buffer = buf + i - 1; |
|||
ESP_ERROR_CHECK(spi_device_polling_transmit(spi_fifo, &t)); |
|||
} |
|||
|
|||
release_spi(); |
|||
} |
|||
void writeFifo(const uint8_t buf[], uint16_t len) { |
|||
request_spi(); |
|||
|
|||
spi_transaction_t t = { |
|||
.flags = 0, |
|||
.cmd = 0, |
|||
.addr = 0, |
|||
.length = 8, |
|||
.rxlength = 0, |
|||
.user = NULL, |
|||
.tx_buffer = NULL, |
|||
.rx_buffer = NULL |
|||
}; |
|||
for (uint16_t i = 0; i < len; i++) { |
|||
t.tx_buffer = buf + i; |
|||
ESP_ERROR_CHECK(spi_device_polling_transmit(spi_fifo, &t)); |
|||
} |
|||
|
|||
release_spi(); |
|||
} |
|||
|
|||
private: |
|||
inline void request_spi() { |
|||
mSpiPatcher->request(this); |
|||
} |
|||
|
|||
inline void release_spi() { |
|||
mSpiPatcher->release(); |
|||
} |
|||
|
|||
private: |
|||
gpio_num_t mPinSdio = GPIO_NUM_NC; |
|||
gpio_num_t mPinClk = GPIO_NUM_NC; |
|||
gpio_num_t mPinCs = GPIO_NUM_NC; |
|||
gpio_num_t mPinFcs = GPIO_NUM_NC; |
|||
int32_t mSpiSpeed = CMT_DEFAULT_SPI_SPEED; |
|||
|
|||
spi_host_device_t mHostDevice; |
|||
spi_device_handle_t spi_reg, spi_fifo; |
|||
SpiPatcher *mSpiPatcher; |
|||
}; |
|||
|
|||
#endif /*__CMT_HAL_H__*/ |
@ -1,183 +0,0 @@ |
|||
//-----------------------------------------------------------------------------
|
|||
// 2023 Ahoy, https://github.com/lumpapu/ahoy
|
|||
// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/
|
|||
//-----------------------------------------------------------------------------
|
|||
|
|||
#ifndef __ESP32_3WSPI_H__ |
|||
#define __ESP32_3WSPI_H__ |
|||
|
|||
#include "Arduino.h" |
|||
#if defined(ESP32) |
|||
#include "driver/spi_master.h" |
|||
#include "esp_rom_gpio.h" // for esp_rom_gpio_connect_out_signal |
|||
|
|||
#define SPI_CLK 1 * 1000 * 1000 // 1MHz
|
|||
|
|||
#define SPI_PARAM_LOCK() \ |
|||
do { \ |
|||
} while (xSemaphoreTake(paramLock, portMAX_DELAY) != pdPASS) |
|||
#define SPI_PARAM_UNLOCK() xSemaphoreGive(paramLock) |
|||
|
|||
// for ESP32 this is the so-called HSPI
|
|||
// for ESP32-S2/S3/C3 this nomenclature does not really exist anymore,
|
|||
// it is simply the first externally usable hardware SPI master controller
|
|||
#define SPI_CMT SPI2_HOST |
|||
|
|||
class esp32_3wSpi { |
|||
public: |
|||
esp32_3wSpi() { |
|||
mInitialized = false; |
|||
} |
|||
|
|||
void setup(uint8_t pinSclk = DEF_CMT_SCLK, uint8_t pinSdio = DEF_CMT_SDIO, uint8_t pinCsb = DEF_CMT_CSB, uint8_t pinFcsb = DEF_CMT_FCSB) { |
|||
paramLock = xSemaphoreCreateMutex(); |
|||
spi_bus_config_t buscfg = { |
|||
.mosi_io_num = pinSdio, |
|||
.miso_io_num = -1, // single wire MOSI/MISO
|
|||
.sclk_io_num = pinSclk, |
|||
.quadwp_io_num = -1, |
|||
.quadhd_io_num = -1, |
|||
.max_transfer_sz = 32, |
|||
}; |
|||
spi_device_interface_config_t devcfg = { |
|||
.command_bits = 1, |
|||
.address_bits = 7, |
|||
.dummy_bits = 0, |
|||
.mode = 0, |
|||
.cs_ena_pretrans = 1, |
|||
.cs_ena_posttrans = 1, |
|||
.clock_speed_hz = SPI_CLK, |
|||
.spics_io_num = pinCsb, |
|||
.flags = SPI_DEVICE_HALFDUPLEX | SPI_DEVICE_3WIRE, |
|||
.queue_size = 1, |
|||
.pre_cb = NULL, |
|||
.post_cb = NULL, |
|||
}; |
|||
|
|||
ESP_ERROR_CHECK(spi_bus_initialize(SPI_CMT, &buscfg, SPI_DMA_DISABLED)); |
|||
ESP_ERROR_CHECK(spi_bus_add_device(SPI_CMT, &devcfg, &spi_reg)); |
|||
|
|||
// FiFo
|
|||
spi_device_interface_config_t devcfg2 = { |
|||
.command_bits = 0, |
|||
.address_bits = 0, |
|||
.dummy_bits = 0, |
|||
.mode = 0, |
|||
.cs_ena_pretrans = 2, |
|||
.cs_ena_posttrans = (uint8_t)(1 / (SPI_CLK * 10e6 * 2) + 2), // >2 us
|
|||
.clock_speed_hz = SPI_CLK, |
|||
.spics_io_num = pinFcsb, |
|||
.flags = SPI_DEVICE_HALFDUPLEX | SPI_DEVICE_3WIRE, |
|||
.queue_size = 1, |
|||
.pre_cb = NULL, |
|||
.post_cb = NULL, |
|||
}; |
|||
ESP_ERROR_CHECK(spi_bus_add_device(SPI_CMT, &devcfg2, &spi_fifo)); |
|||
|
|||
esp_rom_gpio_connect_out_signal(pinSdio, spi_periph_signal[SPI_CMT].spid_out, true, false); |
|||
delay(100); |
|||
|
|||
//pinMode(pinGpio3, INPUT);
|
|||
mInitialized = true; |
|||
} |
|||
|
|||
void writeReg(uint8_t addr, uint8_t reg) { |
|||
if(!mInitialized) |
|||
return; |
|||
|
|||
uint8_t tx_data; |
|||
tx_data = ~reg; |
|||
spi_transaction_t t = { |
|||
.cmd = 1, |
|||
.addr = (uint64_t)(~addr), |
|||
.length = 8, |
|||
.tx_buffer = &tx_data, |
|||
.rx_buffer = NULL |
|||
}; |
|||
SPI_PARAM_LOCK(); |
|||
ESP_ERROR_CHECK(spi_device_polling_transmit(spi_reg, &t)); |
|||
SPI_PARAM_UNLOCK(); |
|||
delayMicroseconds(100); |
|||
} |
|||
|
|||
uint8_t readReg(uint8_t addr) { |
|||
if(!mInitialized) |
|||
return 0; |
|||
|
|||
uint8_t rx_data; |
|||
spi_transaction_t t = { |
|||
.cmd = 0, |
|||
.addr = (uint64_t)(~addr), |
|||
.length = 8, |
|||
.rxlength = 8, |
|||
.tx_buffer = NULL, |
|||
.rx_buffer = &rx_data |
|||
}; |
|||
|
|||
SPI_PARAM_LOCK(); |
|||
ESP_ERROR_CHECK(spi_device_polling_transmit(spi_reg, &t)); |
|||
SPI_PARAM_UNLOCK(); |
|||
delayMicroseconds(100); |
|||
return rx_data; |
|||
} |
|||
|
|||
void writeFifo(uint8_t buf[], uint8_t len) { |
|||
if(!mInitialized) |
|||
return; |
|||
uint8_t tx_data; |
|||
|
|||
spi_transaction_t t = { |
|||
.length = 8, |
|||
.tx_buffer = &tx_data, // reference to write data
|
|||
.rx_buffer = NULL |
|||
}; |
|||
|
|||
SPI_PARAM_LOCK(); |
|||
for(uint8_t i = 0; i < len; i++) { |
|||
tx_data = ~buf[i]; // negate buffer contents
|
|||
ESP_ERROR_CHECK(spi_device_polling_transmit(spi_fifo, &t)); |
|||
delayMicroseconds(4); // > 4 us
|
|||
} |
|||
SPI_PARAM_UNLOCK(); |
|||
} |
|||
|
|||
void readFifo(uint8_t buf[], uint8_t *len, uint8_t maxlen) { |
|||
if(!mInitialized) |
|||
return; |
|||
uint8_t rx_data; |
|||
|
|||
spi_transaction_t t = { |
|||
.length = 8, |
|||
.rxlength = 8, |
|||
.tx_buffer = NULL, |
|||
.rx_buffer = &rx_data |
|||
}; |
|||
|
|||
SPI_PARAM_LOCK(); |
|||
for(uint8_t i = 0; i < maxlen; i++) { |
|||
ESP_ERROR_CHECK(spi_device_polling_transmit(spi_fifo, &t)); |
|||
delayMicroseconds(4); // > 4 us
|
|||
if(0 == i) |
|||
*len = rx_data; |
|||
else |
|||
buf[i-1] = rx_data; |
|||
} |
|||
SPI_PARAM_UNLOCK(); |
|||
} |
|||
|
|||
private: |
|||
spi_device_handle_t spi_reg, spi_fifo; |
|||
bool mInitialized; |
|||
SemaphoreHandle_t paramLock = NULL; |
|||
}; |
|||
#else |
|||
template<uint8_t CSB_PIN=5, uint8_t FCSB_PIN=4> |
|||
class esp32_3wSpi { |
|||
public: |
|||
esp32_3wSpi() {} |
|||
void setup() {} |
|||
void loop() {} |
|||
}; |
|||
#endif |
|||
|
|||
#endif /*__ESP32_3WSPI_H__*/ |
@ -0,0 +1,9 @@ |
|||
//-----------------------------------------------------------------------------
|
|||
// 2023 Ahoy, https://www.mikrocontroller.net/topic/525778
|
|||
// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/
|
|||
//-----------------------------------------------------------------------------
|
|||
|
|||
|
|||
#include "spiPatcher.h" |
|||
|
|||
SpiPatcher *SpiPatcher::mInstance = nullptr; |
@ -0,0 +1,84 @@ |
|||
//-----------------------------------------------------------------------------
|
|||
// 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 { |
|||
protected: |
|||
SpiPatcher(spi_host_device_t dev) : |
|||
mHostDevice(dev), mCurHandle(nullptr) { |
|||
// Use binary semaphore instead of mutex for performance reasons
|
|||
mutex = xSemaphoreCreateBinaryStatic(&mutex_buffer); |
|||
xSemaphoreGive(mutex); |
|||
|
|||
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(mHostDevice, &buscfg, SPI_DMA_DISABLED)); |
|||
} |
|||
|
|||
public: |
|||
SpiPatcher(SpiPatcher &other) = delete; |
|||
void operator=(const SpiPatcher &) = delete; |
|||
|
|||
static SpiPatcher* getInstance(spi_host_device_t dev) { |
|||
if(nullptr == mInstance) |
|||
mInstance = new SpiPatcher(dev); |
|||
return mInstance; |
|||
} |
|||
|
|||
~SpiPatcher() { vSemaphoreDelete(mutex); } |
|||
|
|||
spi_host_device_t getDevice() { |
|||
return mHostDevice; |
|||
} |
|||
|
|||
inline void request(SpiPatcherHandle* handle) { |
|||
xSemaphoreTake(mutex, portMAX_DELAY); |
|||
|
|||
if (mCurHandle != handle) { |
|||
if (mCurHandle) { |
|||
mCurHandle->unpatch(); |
|||
} |
|||
mCurHandle = handle; |
|||
if (mCurHandle) { |
|||
mCurHandle->patch(); |
|||
} |
|||
} |
|||
} |
|||
|
|||
inline void release() { |
|||
xSemaphoreGive(mutex); |
|||
} |
|||
|
|||
protected: |
|||
static SpiPatcher *mInstance; |
|||
|
|||
private: |
|||
const spi_host_device_t mHostDevice; |
|||
SpiPatcherHandle* mCurHandle; |
|||
SemaphoreHandle_t mutex; |
|||
StaticSemaphore_t mutex_buffer; |
|||
}; |
|||
|
|||
#endif /*__SPI_PATCHER_H__*/ |
Loading…
Reference in new issue