From 6269bb99c4e231cda8bac8159952e64ef5bbe714 Mon Sep 17 00:00:00 2001 From: crosstyan Date: Wed, 6 Aug 2025 23:54:13 +0800 Subject: [PATCH] feat: add spi_config_t structure and update init function to accept configuration --- inc/hal_spi.hpp | 8 ++++++- src/hal_spi.cpp | 62 ++++++++++++++++++++++++++++--------------------- 2 files changed, 42 insertions(+), 28 deletions(-) diff --git a/inc/hal_spi.hpp b/inc/hal_spi.hpp index 583afc8..003f8b1 100644 --- a/inc/hal_spi.hpp +++ b/inc/hal_spi.hpp @@ -5,6 +5,7 @@ #define B7431E31_4075_4B09_B4B3_EAD0234EFB40 #include #include +#include "hal/spi_types.h" #include "radiolib_definitions.hpp" #include "llcc68_definitions.hpp" #include "utils/app_result.hpp" @@ -36,10 +37,15 @@ constexpr size_t DEFAULT_TIMEOUT_MS = 1000; std::span mut_shared_buffer(); +struct spi_config_t { + spi_host_device_t host_id; + int clock_speed_hz; +}; + /*! \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) { diff --git a/src/hal_spi.cpp b/src/hal_spi.cpp index 3bd13cd..db2ff1f 100644 --- a/src/hal_spi.cpp +++ b/src/hal_spi.cpp @@ -25,7 +25,7 @@ namespace details { /// should satisfy most of the control register write/read /// 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, "DATA_BUFFER_OFFSET must be less than MAX_BUFFER_SIZE"); static uint8_t _shared_buffer[MAX_BUFFER_SIZE]; @@ -39,6 +39,13 @@ namespace details { static std::span 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 statuses) { uint8_t i = 0; @@ -56,7 +63,7 @@ std::span mut_shared_buffer() { return std::span{details::shared_buffer}; } -void init() { +void init(spi_config_t config) { if (details::is_initialized) { return; } @@ -84,19 +91,19 @@ void init() { // See also the phase // 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 = { - .command_bits = 8, + .command_bits = 0, .address_bits = 0, .dummy_bits = 0, .mode = 0, .duty_cycle_pos = 128, - .clock_speed_hz = 10'000'000, + .clock_speed_hz = config.clock_speed_hz, .spics_io_num = CS_PIN, .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_add_device(SPI2_HOST, &dev_config, &details::spi_device)); + ESP_ERROR_CHECK(spi_bus_initialize(config.host_id, &bus_config, SPI_DMA_CH_AUTO)); + ESP_ERROR_CHECK(spi_bus_add_device(config.host_id, &dev_config, &details::spi_device)); gpio_config_t io_conf = { @@ -157,14 +164,14 @@ inline bool wait_for_not_busy(const size_t timeout_ms) { Result read_stream(uint8_t cmd, std::span 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) { 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); spi_transaction_ext_t transaction; @@ -201,14 +208,14 @@ read_stream(uint8_t cmd, std::span data, const size_t timeout_ms) { Result write_stream(uint8_t cmd, std::span 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) { 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()); spi_transaction_ext_t transaction; transaction = spi_transaction_ext_t{ @@ -242,14 +249,14 @@ write_stream(uint8_t cmd, std::span data, const size_t timeout_ms Result read_register(uint16_t reg, std::span 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) { 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 // bytes of address to start receiving data bytes on the next NOP sent. // @@ -290,14 +297,14 @@ read_register(uint16_t reg, std::span data, const size_t timeout_ms) { Result write_register(uint16_t offset, std::span 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) { 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()); 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(SPI_BUFFER_OFFSET_BIT_SIZE), .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) { ESP_LOGE(TAG, "failed to transfer %s (%d)", esp_err_to_name(err), err); return ue_t{error::FAILED}; @@ -373,13 +380,14 @@ read_buffer(uint8_t offset, uint8_t size, const size_t timeout_ms) { Result write_buffer(uint8_t offset, std::span 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)) { 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()); spi_transaction_ext_t transaction;