diff --git a/lib/bsp/device/registry.cpp b/lib/bsp/device/registry.cpp index f15dce7..15a6536 100644 --- a/lib/bsp/device/registry.cpp +++ b/lib/bsp/device/registry.cpp @@ -35,6 +35,7 @@ extern driver &g_i2s_driver_i2s2; extern driver &g_spi_driver_spi0; extern driver &g_spi_driver_spi1; +extern driver &g_spi_driver_spi_slave; extern driver &g_spi_driver_spi3; extern driver &g_sccb_driver_sccb0; @@ -87,6 +88,7 @@ driver_registry_t sys::g_system_drivers[] = { { "/dev/spi0", { std::in_place, &g_spi_driver_spi0 } }, { "/dev/spi1", { std::in_place, &g_spi_driver_spi1 } }, + { "/dev/spi_slave", { std::in_place, &g_spi_driver_spi_slave } }, { "/dev/spi3", { std::in_place, &g_spi_driver_spi3 } }, { "/dev/sccb0", { std::in_place, &g_sccb_driver_sccb0 } }, diff --git a/lib/bsp/device/spi.cpp b/lib/bsp/device/spi.cpp index 1b6f814..f4641ec 100644 --- a/lib/bsp/device/spi.cpp +++ b/lib/bsp/device/spi.cpp @@ -70,6 +70,59 @@ public: int transfer_sequential(k_spi_device_driver &device, gsl::span write_buffer, gsl::span read_buffer); int read_write(k_spi_device_driver &device, gsl::span write_buffer, gsl::span read_buffer); void fill(k_spi_device_driver &device, uint32_t instruction, uint32_t address, uint32_t value, size_t count); + virtual void slave_config(uint32_t data_bit_length, const spi_slave_handler_t &handler) override + { + slave_context_.data_bit_length = data_bit_length; + slave_context_.handler = &handler; + uint8_t slv_oe = 10; + spi_.ssienr = 0x00; + spi_.ctrlr0 = (0x0 << mod_off_) | (0x1 << slv_oe) | ((data_bit_length - 1) << dfs_off_); + spi_.txftlr = 0x00000000; + spi_.rxftlr = 0x00000000; + spi_.imr = 0x00000010; + spi_.ssienr = 0x01; + + pic_set_irq_priority(IRQN_SPI_SLAVE_INTERRUPT, 1); + pic_set_irq_handler(IRQN_SPI_SLAVE_INTERRUPT, on_spi_irq, this); + pic_set_irq_enable(IRQN_SPI_SLAVE_INTERRUPT, 1); + } + + static void on_spi_irq(void *userdata) + { + auto &driver = *reinterpret_cast(userdata); + auto &spi_ = driver.spi_; + uint32_t data; + uint32_t transmit_data; + uint32_t status = spi_.isr; + uint8_t slv_oe = 10; + if (status & 0x10) + { + data = spi_.dr[0]; + if (driver.slave_context_.handler->on_event(data) == SPI_EV_RECV) + { + driver.slave_context_.handler->on_receive(data); + } + if (driver.slave_context_.handler->on_event(data) == SPI_EV_TRANS) + { + transmit_data = driver.slave_context_.handler->on_transmit(data); + spi_.ssienr = 0x00; + spi_.ctrlr0 = (0x0 << driver.mod_off_) | (0x0 << slv_oe) | ((driver.slave_context_.data_bit_length - 1) << driver.dfs_off_); + set_bit_mask(&spi_.ctrlr0, 3 << driver.tmod_off_, 1 << driver.tmod_off_); + spi_.ssienr = 0x01; + spi_.dr[0] = transmit_data; + spi_.dr[0] = transmit_data; + spi_.imr = 0x00000001; + } + } + if (status & 0x01) + { + spi_.ssienr = 0x00; + spi_.ctrlr0 = (0x0 << driver.mod_off_) | (0x1 << slv_oe) | ((driver.slave_context_.data_bit_length - 1) << driver.dfs_off_); + set_bit_mask(&spi_.ctrlr0, 3 << driver.tmod_off_, 2 << driver.tmod_off_); + spi_.imr = 0x00000010; + spi_.ssienr = 0x01; + } + } private: void setup_device(k_spi_device_driver &device); @@ -102,6 +155,7 @@ private: uint8_t frf_off_; SemaphoreHandle_t free_mutex_; + spi_slave_context_t slave_context_; }; /* SPI Device */ @@ -248,12 +302,14 @@ int k_spi_driver::read(k_spi_device_driver &device, gsl::span buffer) spi_.ctrlr1 = rx_frames - 1; spi_.ssienr = 0x01; if (device.frame_format_ == SPI_FF_STANDARD) + { spi_.dr[0] = 0xFFFFFFFF; + } if (rx_frames < SPI_TRANSMISSION_THRESHOLD) { size_t index, fifo_len; - while (rx_buffer_len) + while (rx_frames) { const uint8_t *buffer_it = buffer.data(); write_inst_addr(spi_.dr, &buffer_it, device.inst_width_); @@ -261,17 +317,15 @@ int k_spi_driver::read(k_spi_device_driver &device, gsl::span buffer) spi_.ser = device.chip_select_mask_; fifo_len = spi_.rxflr; - fifo_len = fifo_len < rx_buffer_len ? fifo_len : rx_buffer_len; + fifo_len = fifo_len < rx_frames ? fifo_len : rx_frames; switch (device.buffer_width_) { case 4: - fifo_len = fifo_len / 4 * 4; - for (index = 0; index < fifo_len / 4; index++) + for (index = 0; index < fifo_len; index++) ((uint32_t *)buffer_read)[i++] = spi_.dr[0]; break; case 2: - fifo_len = fifo_len / 2 * 2; - for (index = 0; index < fifo_len / 2; index++) + for (index = 0; index < fifo_len; index++) ((uint16_t *)buffer_read)[i++] = (uint16_t)spi_.dr[0]; break; default: @@ -279,7 +333,7 @@ int k_spi_driver::read(k_spi_device_driver &device, gsl::span buffer) buffer_read[i++] = (uint8_t)spi_.dr[0]; break; } - rx_buffer_len -= fifo_len; + rx_frames -= fifo_len; } } else @@ -574,8 +628,10 @@ void k_spi_driver::setup_device(k_spi_device_driver &device) static k_spi_driver dev0_driver(SPI0_BASE_ADDR, SYSCTL_CLOCK_SPI0, SYSCTL_DMA_SELECT_SSI0_RX_REQ, 6, 16, 8, 21); static k_spi_driver dev1_driver(SPI1_BASE_ADDR, SYSCTL_CLOCK_SPI1, SYSCTL_DMA_SELECT_SSI1_RX_REQ, 6, 16, 8, 21); +static k_spi_driver dev_slave_driver(SPI_SLAVE_BASE_ADDR, SYSCTL_CLOCK_SPI2, SYSCTL_DMA_SELECT_SSI2_RX_REQ, 6, 16, 8, 21); static k_spi_driver dev3_driver(SPI3_BASE_ADDR, SYSCTL_CLOCK_SPI3, SYSCTL_DMA_SELECT_SSI3_RX_REQ, 8, 0, 10, 22); driver &g_spi_driver_spi0 = dev0_driver; driver &g_spi_driver_spi1 = dev1_driver; +driver &g_spi_driver_spi_slave = dev_slave_driver; driver &g_spi_driver_spi3 = dev3_driver; diff --git a/lib/freertos/include/devices.h b/lib/freertos/include/devices.h index 06f708d..87fae92 100644 --- a/lib/freertos/include/devices.h +++ b/lib/freertos/include/devices.h @@ -259,6 +259,15 @@ void i2s_start(handle_t file); */ void i2s_stop(handle_t file); +/** + * @brief Configure SPI slave mode + * + * @param[in] file The SPI controller handle + * @param[in] data_bit_length The length of data bits + * @param[in] handler The SPI slave handler + */ +void spi_slave_config(handle_t file, uint32_t data_bit_length, spi_slave_handler_t *handler); + /** * @brief Register and open a SPI device * diff --git a/lib/freertos/include/kernel/driver.hpp b/lib/freertos/include/kernel/driver.hpp index b3ea89b..423a3b8 100644 --- a/lib/freertos/include/kernel/driver.hpp +++ b/lib/freertos/include/kernel/driver.hpp @@ -236,6 +236,7 @@ class spi_driver : public driver { public: virtual object_ptr get_device(spi_mode_t mode, spi_frame_format_t frame_format, uint32_t chip_select_mask, uint32_t data_bit_length) = 0; + virtual void slave_config(uint32_t data_bit_length, const spi_slave_handler_t &handler) = 0; }; class dvp_driver : public driver diff --git a/lib/freertos/include/osdefs.h b/lib/freertos/include/osdefs.h index ee8e866..8e5a95a 100644 --- a/lib/freertos/include/osdefs.h +++ b/lib/freertos/include/osdefs.h @@ -129,6 +129,19 @@ typedef enum _spi_inst_addr_trans_mode SPI_AITM_AS_FRAME_FORMAT } spi_inst_addr_trans_mode_t; +typedef enum _spi_slave_event +{ + SPI_EV_TRANS, + SPI_EV_RECV, +} spi_slave_event_t; + +typedef struct _spi_slave_handler +{ + void (*on_receive)(uint32_t data); + uint32_t (*on_transmit)(uint32_t data); + spi_slave_event_t (*on_event)(uint32_t data); +} spi_slave_handler_t; + typedef enum _video_format { VIDEO_FMT_RGB565, diff --git a/lib/freertos/kernel/devices.cpp b/lib/freertos/kernel/devices.cpp index 8ffbfbb..9486596 100644 --- a/lib/freertos/kernel/devices.cpp +++ b/lib/freertos/kernel/devices.cpp @@ -430,6 +430,11 @@ void i2s_stop(handle_t file) } /* SPI */ +void spi_slave_config(handle_t file, uint32_t data_bit_length, spi_slave_handler_t *handler) +{ + COMMON_ENTRY(spi); + spi->slave_config(data_bit_length, *handler); +} handle_t spi_get_device(handle_t file, spi_mode_t mode, spi_frame_format_t frame_format, uint32_t chip_select_mask, uint32_t data_bit_length) { diff --git a/lib/hal/include/spi.h b/lib/hal/include/spi.h index bfa71e3..811d462 100644 --- a/lib/hal/include/spi.h +++ b/lib/hal/include/spi.h @@ -98,6 +98,12 @@ typedef struct _spi volatile uint32_t xip_cnt_time_out; volatile uint32_t endian; } __attribute__((packed, aligned(4))) spi_t; + +typedef struct _spi_slave_context +{ + uint32_t data_bit_length; + const spi_slave_handler_t *handler; +} spi_slave_context_t; /* clang-format on */ #ifdef __cplusplus