forked from tbnobody/OpenDTU
-
Notifications
You must be signed in to change notification settings - Fork 64
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
851190d
commit 9b9c1e2
Showing
9 changed files
with
371 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
{ | ||
"name": "SpiManager", | ||
"keywords": "spi", | ||
"description": "Library for managing the allocation of dedicated or shared SPI buses on the ESP32.", | ||
"authors": { | ||
"name": "Lennart Ferlemann" | ||
}, | ||
"version": "0.0.1", | ||
"frameworks": "arduino", | ||
"platforms": [ | ||
"espressif32" | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
#include "SpiBus.h" | ||
|
||
#include "SpiBusConfig.h" | ||
#include "SpiCallback.h" | ||
|
||
SpiBus::SpiBus(const std::string &_id, spi_host_device_t _host_device) : | ||
id(_id), | ||
host_device(_host_device), | ||
cur_config(nullptr) | ||
{ | ||
spi_bus_config_t bus_config { | ||
.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 = SPI_MAX_DMA_LEN, | ||
.flags = 0, | ||
.intr_flags = 0 | ||
}; | ||
ESP_ERROR_CHECK(spi_bus_initialize(host_device, &bus_config, SPI_DMA_CH_AUTO)); | ||
} | ||
|
||
SpiBus::~SpiBus() { | ||
ESP_ERROR_CHECK(spi_bus_free(host_device)); | ||
} | ||
|
||
spi_device_handle_t SpiBus::add_device(const std::shared_ptr<SpiBusConfig> &bus_config, spi_device_interface_config_t &device_config) { | ||
if (!SpiCallback::patch(shared_from_this(), bus_config, device_config)) | ||
return nullptr; | ||
|
||
spi_device_handle_t device; | ||
ESP_ERROR_CHECK(spi_bus_add_device(host_device, &device_config, &device)); | ||
return device; | ||
} | ||
|
||
// TODO: add remove_device (with spi_device_acquire_bus) | ||
|
||
void SpiBus::apply_config(SpiBusConfig *config) { | ||
if (cur_config) | ||
cur_config->unpatch(host_device); | ||
cur_config = config; | ||
if (cur_config) | ||
cur_config->patch(host_device); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
#pragma once | ||
|
||
#include <driver/spi_master.h> | ||
|
||
#include <memory> | ||
#include <string> | ||
|
||
class SpiBusConfig; | ||
|
||
class SpiBus : public std::enable_shared_from_this<SpiBus> { | ||
public: | ||
explicit SpiBus(const std::string &id, spi_host_device_t host_device); | ||
SpiBus(const SpiBus&) = delete; | ||
SpiBus &operator=(const SpiBus&) = delete; | ||
~SpiBus(); | ||
|
||
inline __attribute__((always_inline)) void require_config(SpiBusConfig *config) { | ||
if (config == cur_config) | ||
return; | ||
apply_config(config); | ||
} | ||
|
||
inline __attribute__((always_inline)) void free_config(SpiBusConfig *config) { | ||
if (config != cur_config) | ||
return; | ||
apply_config(nullptr); | ||
} | ||
|
||
inline const std::string &get_id() const { | ||
return id; | ||
} | ||
|
||
inline spi_host_device_t get_host_device() const { | ||
return host_device; | ||
} | ||
|
||
spi_device_handle_t add_device(const std::shared_ptr<SpiBusConfig> &bus_config, spi_device_interface_config_t &device_config); | ||
|
||
private: | ||
void apply_config(SpiBusConfig *config); | ||
|
||
std::string id; | ||
spi_host_device_t host_device; | ||
SpiBusConfig *cur_config; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
#include "SpiBusConfig.h" | ||
|
||
#include <driver/gpio.h> | ||
#include <esp_rom_gpio.h> | ||
#include <soc/spi_periph.h> | ||
|
||
SpiBusConfig::SpiBusConfig(gpio_num_t _pin_mosi, gpio_num_t _pin_miso, gpio_num_t _pin_sclk) : | ||
pin_mosi(_pin_mosi), | ||
pin_miso(_pin_miso), | ||
pin_sclk(_pin_sclk) | ||
{ | ||
if (pin_mosi != GPIO_NUM_NC) { | ||
ESP_ERROR_CHECK(gpio_reset_pin(pin_mosi)); | ||
ESP_ERROR_CHECK(gpio_set_direction(pin_mosi, GPIO_MODE_INPUT_OUTPUT)); | ||
} | ||
|
||
if (pin_miso != GPIO_NUM_NC) { | ||
ESP_ERROR_CHECK(gpio_reset_pin(pin_miso)); | ||
ESP_ERROR_CHECK(gpio_set_direction(pin_miso, GPIO_MODE_INPUT)); | ||
} | ||
|
||
if (pin_sclk != GPIO_NUM_NC) { | ||
ESP_ERROR_CHECK(gpio_reset_pin(pin_sclk)); | ||
ESP_ERROR_CHECK(gpio_set_direction(pin_sclk, GPIO_MODE_INPUT_OUTPUT)); | ||
} | ||
} | ||
|
||
SpiBusConfig::~SpiBusConfig() { | ||
if (pin_mosi != GPIO_NUM_NC) | ||
ESP_ERROR_CHECK(gpio_reset_pin(pin_mosi)); | ||
|
||
if (pin_miso != GPIO_NUM_NC) | ||
ESP_ERROR_CHECK(gpio_reset_pin(pin_miso)); | ||
|
||
if (pin_sclk != GPIO_NUM_NC) | ||
ESP_ERROR_CHECK(gpio_reset_pin(pin_sclk)); | ||
} | ||
|
||
void SpiBusConfig::patch(spi_host_device_t host_device) { | ||
if (pin_mosi != GPIO_NUM_NC) { | ||
esp_rom_gpio_connect_out_signal(pin_mosi, spi_periph_signal[host_device].spid_out, false, false); | ||
esp_rom_gpio_connect_in_signal(pin_mosi, spi_periph_signal[host_device].spid_in, false); | ||
} | ||
|
||
if (pin_miso != GPIO_NUM_NC) | ||
esp_rom_gpio_connect_in_signal(pin_miso, spi_periph_signal[host_device].spiq_in, false); | ||
|
||
if (pin_sclk != GPIO_NUM_NC) { | ||
esp_rom_gpio_connect_out_signal(pin_sclk, spi_periph_signal[host_device].spiclk_out, false, false); | ||
esp_rom_gpio_connect_in_signal(pin_sclk, spi_periph_signal[host_device].spiclk_in, false); | ||
} | ||
} | ||
|
||
void SpiBusConfig::unpatch(spi_host_device_t host_device) { | ||
if (pin_mosi != GPIO_NUM_NC) { | ||
esp_rom_gpio_connect_out_signal(pin_mosi, SIG_GPIO_OUT_IDX, false, false); | ||
esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ONE_INPUT, spi_periph_signal[host_device].spid_in, false); | ||
} | ||
|
||
if (pin_miso != GPIO_NUM_NC) | ||
esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ONE_INPUT, spi_periph_signal[host_device].spiq_in, false); | ||
|
||
if (pin_sclk != GPIO_NUM_NC) { | ||
esp_rom_gpio_connect_out_signal(pin_sclk, SIG_GPIO_OUT_IDX, false, false); | ||
esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ONE_INPUT, spi_periph_signal[host_device].spiclk_in, false); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
#pragma once | ||
|
||
#include <hal/gpio_types.h> | ||
#include <hal/spi_types.h> | ||
|
||
class SpiBusConfig { | ||
public: | ||
explicit SpiBusConfig(gpio_num_t pin_mosi, gpio_num_t pin_miso, gpio_num_t pin_sclk); | ||
SpiBusConfig(const SpiBusConfig&) = delete; | ||
SpiBusConfig &operator=(const SpiBusConfig&) = delete; | ||
~SpiBusConfig(); | ||
|
||
void patch(spi_host_device_t host_device); | ||
void unpatch(spi_host_device_t host_device); | ||
|
||
private: | ||
gpio_num_t pin_mosi; | ||
gpio_num_t pin_miso; | ||
gpio_num_t pin_sclk; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
#include "SpiCallback.h" | ||
|
||
#include "SpiBus.h" | ||
|
||
#include <array> | ||
#include <optional> | ||
|
||
namespace SpiCallback { | ||
namespace { | ||
struct CallbackData { | ||
std::shared_ptr<SpiBus> bus; | ||
std::shared_ptr<SpiBusConfig> config; | ||
transaction_cb_t inner_pre_cb; | ||
transaction_cb_t inner_post_cb; | ||
}; | ||
|
||
std::array<std::optional<CallbackData>, SPI_MANAGER_CALLBACK_COUNT> instances; | ||
|
||
template<int N> | ||
void IRAM_ATTR fn_pre_cb(spi_transaction_t *trans) { | ||
instances[N]->bus->require_config(instances[N]->config.get()); | ||
if (instances[N]->inner_pre_cb) | ||
instances[N]->inner_pre_cb(trans); | ||
} | ||
|
||
template<int N> | ||
void IRAM_ATTR fn_post_cb(spi_transaction_t *trans) { | ||
if (instances[N]->inner_post_cb) | ||
instances[N]->inner_post_cb(trans); | ||
} | ||
|
||
template<int N> | ||
inline __attribute__((always_inline)) bool alloc(CallbackData *&instance, transaction_cb_t &pre_cb, transaction_cb_t &post_cb) { | ||
if constexpr (N > 0) { | ||
if (alloc<N - 1>(instance, pre_cb, post_cb)) | ||
return true; | ||
if (!instances[N - 1]) { | ||
instances[N - 1].emplace(); | ||
instance = &*instances[N - 1]; | ||
pre_cb = fn_pre_cb<N - 1>; | ||
post_cb = fn_post_cb<N - 1>; | ||
return true; | ||
} | ||
} | ||
return false; | ||
} | ||
} | ||
|
||
bool patch(const std::shared_ptr<SpiBus> &bus, const std::shared_ptr<SpiBusConfig> &bus_config, spi_device_interface_config_t &device_config) { | ||
CallbackData *instance; | ||
transaction_cb_t pre_cb; | ||
transaction_cb_t post_cb; | ||
if (!alloc<SPI_MANAGER_CALLBACK_COUNT>(instance, pre_cb, post_cb)) | ||
return false; | ||
|
||
instance->bus = bus; | ||
instance->config = bus_config; | ||
instance->inner_pre_cb = device_config.pre_cb; | ||
instance->inner_post_cb = device_config.post_cb; | ||
device_config.pre_cb = pre_cb; | ||
device_config.post_cb = post_cb; | ||
|
||
return true; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
#pragma once | ||
|
||
#include <driver/spi_master.h> | ||
|
||
#include <memory> | ||
|
||
// Pre and post callbacks for 2 buses with 3 devices each | ||
#define SPI_MANAGER_CALLBACK_COUNT 6 | ||
|
||
class SpiBus; | ||
class SpiBusConfig; | ||
|
||
namespace SpiCallback { | ||
bool patch(const std::shared_ptr<SpiBus> &bus, const std::shared_ptr<SpiBusConfig> &bus_config, spi_device_interface_config_t &device_config); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
#include "SpiManager.h" | ||
|
||
SpiManager::SpiManager() { | ||
} | ||
|
||
bool SpiManager::register_bus(spi_host_device_t host_device) { | ||
for (int i = 0; i < SPI_MANAGER_NUM_BUSES; ++i) { | ||
if (available_buses[i]) | ||
continue; | ||
|
||
available_buses[i] = host_device; | ||
return true; | ||
} | ||
|
||
return false; | ||
} | ||
|
||
bool SpiManager::claim_bus(spi_host_device_t &host_device) { | ||
for (int i = SPI_MANAGER_NUM_BUSES - 1; i >= 0; --i) { | ||
if (!available_buses[i]) | ||
continue; | ||
|
||
host_device = *available_buses[i]; | ||
available_buses[i].reset(); | ||
return true; | ||
} | ||
|
||
return false; | ||
} | ||
|
||
spi_device_handle_t SpiManager::alloc_device(const std::string &bus_id, const std::shared_ptr<SpiBusConfig> &bus_config, spi_device_interface_config_t &device_config) { | ||
std::shared_ptr<SpiBus> shared_bus = get_shared_bus(bus_id); | ||
if (!shared_bus) | ||
return nullptr; | ||
|
||
return shared_bus->add_device(bus_config, device_config); | ||
} | ||
|
||
std::shared_ptr<SpiBus> SpiManager::get_shared_bus(const std::string &bus_id) { | ||
// look for existing shared bus | ||
for (int i = 0; i < SPI_MANAGER_NUM_BUSES; ++i) { | ||
if (!shared_buses[i]) | ||
continue; | ||
if (shared_buses[i]->get_id() == bus_id) | ||
return shared_buses[i]; | ||
} | ||
|
||
// create new shared bus | ||
for (int i = 0; i < SPI_MANAGER_NUM_BUSES; ++i) { | ||
if (shared_buses[i]) | ||
continue; | ||
|
||
spi_host_device_t host_device; | ||
if (!claim_bus(host_device)) | ||
return nullptr; | ||
|
||
shared_buses[i] = std::make_shared<SpiBus>(bus_id, host_device); | ||
return shared_buses[i]; | ||
} | ||
|
||
return nullptr; | ||
} | ||
|
||
SpiManager SpiManagerInst; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
#pragma once | ||
|
||
#include "SpiBus.h" | ||
#include "SpiBusConfig.h" | ||
|
||
#include <driver/spi_master.h> | ||
|
||
#include <array> | ||
#include <memory> | ||
#include <optional> | ||
#include <utility> | ||
|
||
#define SPI_MANAGER_NUM_BUSES SOC_SPI_PERIPH_NUM | ||
|
||
class SpiManager { | ||
public: | ||
explicit SpiManager(); | ||
SpiManager(const SpiManager&) = delete; | ||
SpiManager &operator=(const SpiManager&) = delete; | ||
|
||
bool register_bus(spi_host_device_t host_device); | ||
bool claim_bus(spi_host_device_t &host_device); | ||
|
||
spi_device_handle_t alloc_device(const std::string &bus_id, const std::shared_ptr<SpiBusConfig> &bus_config, spi_device_interface_config_t &device_config); | ||
|
||
private: | ||
std::shared_ptr<SpiBus> get_shared_bus(const std::string &bus_id); | ||
|
||
std::array<std::optional<spi_host_device_t>, SPI_MANAGER_NUM_BUSES> available_buses; | ||
std::array<std::shared_ptr<SpiBus>, SPI_MANAGER_NUM_BUSES> shared_buses; | ||
}; | ||
|
||
extern SpiManager SpiManagerInst; |