feat: add spi_config_t structure and update init function to accept configuration
This commit is contained in:
@ -5,6 +5,7 @@
|
|||||||
#define B7431E31_4075_4B09_B4B3_EAD0234EFB40
|
#define B7431E31_4075_4B09_B4B3_EAD0234EFB40
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <span>
|
#include <span>
|
||||||
|
#include "hal/spi_types.h"
|
||||||
#include "radiolib_definitions.hpp"
|
#include "radiolib_definitions.hpp"
|
||||||
#include "llcc68_definitions.hpp"
|
#include "llcc68_definitions.hpp"
|
||||||
#include "utils/app_result.hpp"
|
#include "utils/app_result.hpp"
|
||||||
@ -36,10 +37,15 @@ constexpr size_t DEFAULT_TIMEOUT_MS = 1000;
|
|||||||
|
|
||||||
std::span<uint8_t> mut_shared_buffer();
|
std::span<uint8_t> mut_shared_buffer();
|
||||||
|
|
||||||
|
struct spi_config_t {
|
||||||
|
spi_host_device_t host_id;
|
||||||
|
int clock_speed_hz;
|
||||||
|
};
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\brief Initialize the SPI interface.
|
\brief Initialize the SPI interface.
|
||||||
*/
|
*/
|
||||||
void init();
|
void init(spi_config_t config = {SPI2_HOST, 4'000'000});
|
||||||
|
|
||||||
|
|
||||||
inline error_t status_to_err(const uint8_t status) {
|
inline error_t status_to_err(const uint8_t status) {
|
||||||
|
|||||||
@ -25,7 +25,7 @@ namespace details {
|
|||||||
|
|
||||||
/// should satisfy most of the control register write/read
|
/// should satisfy most of the control register write/read
|
||||||
/// without overlap with the data buffer
|
/// without overlap with the data buffer
|
||||||
constexpr auto DATA_BUFFER_OFFSET = 16;
|
constexpr auto DATA_BUFFER_OFFSET = 24;
|
||||||
static_assert(DATA_BUFFER_OFFSET < MAX_BUFFER_SIZE,
|
static_assert(DATA_BUFFER_OFFSET < MAX_BUFFER_SIZE,
|
||||||
"DATA_BUFFER_OFFSET must be less than MAX_BUFFER_SIZE");
|
"DATA_BUFFER_OFFSET must be less than MAX_BUFFER_SIZE");
|
||||||
static uint8_t _shared_buffer[MAX_BUFFER_SIZE];
|
static uint8_t _shared_buffer[MAX_BUFFER_SIZE];
|
||||||
@ -39,6 +39,13 @@ namespace details {
|
|||||||
static std::span<uint8_t> data_buffer = std::span{_shared_buffer + DATA_BUFFER_OFFSET, MAX_BUFFER_SIZE - DATA_BUFFER_OFFSET};
|
static std::span<uint8_t> data_buffer = std::span{_shared_buffer + DATA_BUFFER_OFFSET, MAX_BUFFER_SIZE - DATA_BUFFER_OFFSET};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* a traditional way to complete an synchronous SPI transaction
|
||||||
|
*
|
||||||
|
* @sa https://github.com/nopnop2002/esp-idf-sx126x/blob/bd26fd20b118c6d57d35b0554d8de80378d614a8/components/ra01s/ra01s.c#L123-L161
|
||||||
|
* @sa https://github.com/IanBurwell/DynamicLRS/blob/c26f7f8dcca0c1b70af0aa6aee3aba3a1652aba6/components/DLRS_LoRadio/radiolib_esp32s3_hal.hpp#L193-L201
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
static constexpr auto verify_statuses = [](std::span<const uint8_t> statuses) {
|
static constexpr auto verify_statuses = [](std::span<const uint8_t> statuses) {
|
||||||
uint8_t i = 0;
|
uint8_t i = 0;
|
||||||
@ -56,7 +63,7 @@ std::span<uint8_t> mut_shared_buffer() {
|
|||||||
return std::span{details::shared_buffer};
|
return std::span{details::shared_buffer};
|
||||||
}
|
}
|
||||||
|
|
||||||
void init() {
|
void init(spi_config_t config) {
|
||||||
if (details::is_initialized) {
|
if (details::is_initialized) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -84,19 +91,19 @@ void init() {
|
|||||||
// See also the phase
|
// See also the phase
|
||||||
// https://docs.espressif.com/projects/esp-idf/en/v5.3.2/esp32/api-reference/peripherals/spi_master.html#spi-transactions
|
// https://docs.espressif.com/projects/esp-idf/en/v5.3.2/esp32/api-reference/peripherals/spi_master.html#spi-transactions
|
||||||
spi_device_interface_config_t dev_config = {
|
spi_device_interface_config_t dev_config = {
|
||||||
.command_bits = 8,
|
.command_bits = 0,
|
||||||
.address_bits = 0,
|
.address_bits = 0,
|
||||||
.dummy_bits = 0,
|
.dummy_bits = 0,
|
||||||
.mode = 0,
|
.mode = 0,
|
||||||
.duty_cycle_pos = 128,
|
.duty_cycle_pos = 128,
|
||||||
.clock_speed_hz = 10'000'000,
|
.clock_speed_hz = config.clock_speed_hz,
|
||||||
.spics_io_num = CS_PIN,
|
.spics_io_num = CS_PIN,
|
||||||
.flags = SPI_DEVICE_NO_DUMMY,
|
.flags = SPI_DEVICE_NO_DUMMY,
|
||||||
.queue_size = 1,
|
.queue_size = 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
ESP_ERROR_CHECK(spi_bus_initialize(SPI2_HOST, &bus_config, SPI_DMA_CH_AUTO));
|
ESP_ERROR_CHECK(spi_bus_initialize(config.host_id, &bus_config, SPI_DMA_CH_AUTO));
|
||||||
ESP_ERROR_CHECK(spi_bus_add_device(SPI2_HOST, &dev_config, &details::spi_device));
|
ESP_ERROR_CHECK(spi_bus_add_device(config.host_id, &dev_config, &details::spi_device));
|
||||||
|
|
||||||
|
|
||||||
gpio_config_t io_conf = {
|
gpio_config_t io_conf = {
|
||||||
@ -157,14 +164,14 @@ inline bool wait_for_not_busy(const size_t timeout_ms) {
|
|||||||
|
|
||||||
Result<Unit, error_t>
|
Result<Unit, error_t>
|
||||||
read_stream(uint8_t cmd, std::span<uint8_t> data, const size_t timeout_ms) {
|
read_stream(uint8_t cmd, std::span<uint8_t> data, const size_t timeout_ms) {
|
||||||
if (not wait_for_not_busy(timeout_ms)) {
|
|
||||||
return ue_t{error::TIMEOUT};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.size() > MAX_BUFFER_SIZE - 1) {
|
if (data.size() > MAX_BUFFER_SIZE - 1) {
|
||||||
return ue_t{error::INVALID_SIZE};
|
return ue_t{error::INVALID_SIZE};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (not wait_for_not_busy(timeout_ms)) {
|
||||||
|
return ue_t{error::TIMEOUT};
|
||||||
|
}
|
||||||
|
|
||||||
auto rx_buffer = details::shared_buffer.subspan(0, data.size() + 1);
|
auto rx_buffer = details::shared_buffer.subspan(0, data.size() + 1);
|
||||||
|
|
||||||
spi_transaction_ext_t transaction;
|
spi_transaction_ext_t transaction;
|
||||||
@ -201,14 +208,14 @@ read_stream(uint8_t cmd, std::span<uint8_t> data, const size_t timeout_ms) {
|
|||||||
|
|
||||||
Result<Unit, error_t>
|
Result<Unit, error_t>
|
||||||
write_stream(uint8_t cmd, std::span<const uint8_t> data, const size_t timeout_ms) {
|
write_stream(uint8_t cmd, std::span<const uint8_t> data, const size_t timeout_ms) {
|
||||||
if (not wait_for_not_busy(timeout_ms)) {
|
|
||||||
return ue_t{error::TIMEOUT};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.size() > MAX_BUFFER_SIZE) {
|
if (data.size() > MAX_BUFFER_SIZE) {
|
||||||
return ue_t{error::INVALID_SIZE};
|
return ue_t{error::INVALID_SIZE};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (not wait_for_not_busy(timeout_ms)) {
|
||||||
|
return ue_t{error::TIMEOUT};
|
||||||
|
}
|
||||||
|
|
||||||
const auto rx_buffer = details::shared_buffer.subspan(0, data.size());
|
const auto rx_buffer = details::shared_buffer.subspan(0, data.size());
|
||||||
spi_transaction_ext_t transaction;
|
spi_transaction_ext_t transaction;
|
||||||
transaction = spi_transaction_ext_t{
|
transaction = spi_transaction_ext_t{
|
||||||
@ -242,14 +249,14 @@ write_stream(uint8_t cmd, std::span<const uint8_t> data, const size_t timeout_ms
|
|||||||
|
|
||||||
Result<Unit, error_t>
|
Result<Unit, error_t>
|
||||||
read_register(uint16_t reg, std::span<uint8_t> data, const size_t timeout_ms) {
|
read_register(uint16_t reg, std::span<uint8_t> data, const size_t timeout_ms) {
|
||||||
if (not wait_for_not_busy(timeout_ms)) {
|
|
||||||
return ue_t{error::TIMEOUT};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.size() > MAX_BUFFER_SIZE - 1) {
|
if (data.size() > MAX_BUFFER_SIZE - 1) {
|
||||||
return ue_t{error::INVALID_SIZE};
|
return ue_t{error::INVALID_SIZE};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (not wait_for_not_busy(timeout_ms)) {
|
||||||
|
return ue_t{error::TIMEOUT};
|
||||||
|
}
|
||||||
|
|
||||||
// Note that the host has to send an NOP after sending the 2
|
// Note that the host has to send an NOP after sending the 2
|
||||||
// bytes of address to start receiving data bytes on the next NOP sent.
|
// bytes of address to start receiving data bytes on the next NOP sent.
|
||||||
//
|
//
|
||||||
@ -290,14 +297,14 @@ read_register(uint16_t reg, std::span<uint8_t> data, const size_t timeout_ms) {
|
|||||||
|
|
||||||
Result<Unit, error_t>
|
Result<Unit, error_t>
|
||||||
write_register(uint16_t offset, std::span<const uint8_t> data, const size_t timeout_ms) {
|
write_register(uint16_t offset, std::span<const uint8_t> data, const size_t timeout_ms) {
|
||||||
if (not wait_for_not_busy(timeout_ms)) {
|
|
||||||
return ue_t{error::TIMEOUT};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.size() > MAX_BUFFER_SIZE) {
|
if (data.size() > MAX_BUFFER_SIZE) {
|
||||||
return ue_t{error::INVALID_SIZE};
|
return ue_t{error::INVALID_SIZE};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (not wait_for_not_busy(timeout_ms)) {
|
||||||
|
return ue_t{error::TIMEOUT};
|
||||||
|
}
|
||||||
|
|
||||||
auto rx_buffer = details::shared_buffer.subspan(0, data.size());
|
auto rx_buffer = details::shared_buffer.subspan(0, data.size());
|
||||||
|
|
||||||
spi_transaction_ext_t transaction;
|
spi_transaction_ext_t transaction;
|
||||||
@ -355,7 +362,7 @@ read_buffer(uint8_t offset, uint8_t size, const size_t timeout_ms) {
|
|||||||
.address_bits = static_cast<uint8_t>(SPI_BUFFER_OFFSET_BIT_SIZE),
|
.address_bits = static_cast<uint8_t>(SPI_BUFFER_OFFSET_BIT_SIZE),
|
||||||
.dummy_bits = 0,
|
.dummy_bits = 0,
|
||||||
};
|
};
|
||||||
esp_err_t err = spi_device_polling_transmit(details::spi_device, &transaction.base);
|
esp_err_t err = spi_device_transmit(details::spi_device, &transaction.base);
|
||||||
if (err != ESP_OK) {
|
if (err != ESP_OK) {
|
||||||
ESP_LOGE(TAG, "failed to transfer %s (%d)", esp_err_to_name(err), err);
|
ESP_LOGE(TAG, "failed to transfer %s (%d)", esp_err_to_name(err), err);
|
||||||
return ue_t{error::FAILED};
|
return ue_t{error::FAILED};
|
||||||
@ -373,13 +380,14 @@ read_buffer(uint8_t offset, uint8_t size, const size_t timeout_ms) {
|
|||||||
|
|
||||||
Result<Unit, error_t>
|
Result<Unit, error_t>
|
||||||
write_buffer(uint8_t offset, std::span<const uint8_t> data_from_host, const size_t timeout_ms) {
|
write_buffer(uint8_t offset, std::span<const uint8_t> data_from_host, const size_t timeout_ms) {
|
||||||
|
if (data_from_host.size() > details::data_buffer.size()) {
|
||||||
|
return ue_t{error::INVALID_SIZE};
|
||||||
|
}
|
||||||
|
|
||||||
if (not wait_for_not_busy(timeout_ms)) {
|
if (not wait_for_not_busy(timeout_ms)) {
|
||||||
return ue_t{error::TIMEOUT};
|
return ue_t{error::TIMEOUT};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data_from_host.size() > details::data_buffer.size()) {
|
|
||||||
return ue_t{error::INVALID_SIZE};
|
|
||||||
}
|
|
||||||
auto rx_buffer = details::data_buffer.subspan(0, data_from_host.size());
|
auto rx_buffer = details::data_buffer.subspan(0, data_from_host.size());
|
||||||
|
|
||||||
spi_transaction_ext_t transaction;
|
spi_transaction_ext_t transaction;
|
||||||
|
|||||||
Reference in New Issue
Block a user