diff --git a/components/drivers/spi/Kconfig b/components/drivers/spi/Kconfig index 8925d8e9e8..f2fbd7edad 100644 --- a/components/drivers/spi/Kconfig +++ b/components/drivers/spi/Kconfig @@ -14,6 +14,183 @@ config RT_USING_SPI default n endif + menuconfig RT_USING_SOFT_SPI + bool "Use GPIO to soft simulate SPI" + default n + select RT_USING_PIN + select RT_USING_SPI_BITOPS + if RT_USING_SOFT_SPI + menuconfig RT_USING_SOFT_SPI0 + bool "Enable SPI0 Bus (software simulation)" + default y + if RT_USING_SOFT_SPI0 + config RT_SOFT_SPI0_SCK_PIN + int "SCK pin number" + range 0 32767 + default 1 + config RT_SOFT_SPI0_MISO_PIN + int "MISO pin number" + range 0 32767 + default 2 + config RT_SOFT_SPI0_MOSI_PIN + int "MOSI pin number" + range 0 32767 + default 3 + config RT_SOFT_SPI0_BUS_NAME + string "Bus name" + default "spi0" + config RT_SOFT_SPI0_TIMING_DELAY + int "Timing delay (us)" + range 0 32767 + default 1 + endif + menuconfig RT_USING_SOFT_SPI1 + bool "Enable SPI1 Bus (software simulation)" + default y + if RT_USING_SOFT_SPI1 + config RT_SOFT_SPI1_SCK_PIN + int "SCK pin number" + range 0 32767 + default 4 + config RT_SOFT_SPI1_MISO_PIN + int "MISO pin number" + range 0 32767 + default 5 + config RT_SOFT_SPI1_MOSI_PIN + int "MOSI pin number" + range 0 32767 + default 6 + config RT_SOFT_SPI1_BUS_NAME + string "Bus name" + default "spi1" + config RT_SOFT_SPI1_TIMING_DELAY + int "Timing delay (us)" + range 0 32767 + default 1 + endif + menuconfig RT_USING_SOFT_SPI2 + bool "Enable SPI2 Bus (software simulation)" + default n + if RT_USING_SOFT_SPI2 + config RT_SOFT_SPI2_SCK_PIN + int "SCK pin number" + range 0 32767 + default 7 + config RT_SOFT_SPI2_MISO_PIN + int "MISO pin number" + range 0 32767 + default 8 + config RT_SOFT_SPI2_MOSI_PIN + int "MOSI pin number" + range 0 32767 + default 9 + config RT_SOFT_SPI2_BUS_NAME + string "Bus name" + default "spi2" + config RT_SOFT_SPI2_TIMING_DELAY + int "Timing delay (us)" + range 0 32767 + default 1 + endif + menuconfig RT_USING_SOFT_SPI3 + bool "Enable SPI3 Bus (software simulation)" + default n + if RT_USING_SOFT_SPI3 + config RT_SOFT_SPI3_SCK_PIN + int "SCK pin number" + range 0 32767 + default 10 + config RT_SOFT_SPI3_MISO_PIN + int "MISO pin number" + range 0 32767 + default 11 + config RT_SOFT_SPI3_MOSI_PIN + int "MOSI pin number" + range 0 32767 + default 12 + config RT_SOFT_SPI3_BUS_NAME + string "Bus name" + default "spi3" + config RT_SOFT_SPI3_TIMING_DELAY + int "Timing delay (us)" + range 0 32767 + default 1 + endif + menuconfig RT_USING_SOFT_SPI4 + bool "Enable SPI4 Bus (software simulation)" + default n + if RT_USING_SOFT_SPI4 + config RT_SOFT_SPI4_SCK_PIN + int "SCK pin number" + range 0 32767 + default 13 + config RT_SOFT_SPI4_MISO_PIN + int "MISO pin number" + range 0 32767 + default 14 + config RT_SOFT_SPI4_MOSI_PIN + int "MOSI pin number" + range 0 32767 + default 15 + config RT_SOFT_SPI4_BUS_NAME + string "Bus name" + default "spi4" + config RT_SOFT_SPI4_TIMING_DELAY + int "Timing delay (us)" + range 0 32767 + default 1 + endif + menuconfig RT_USING_SOFT_SPI5 + bool "Enable SPI5 Bus (software simulation)" + default n + if RT_USING_SOFT_SPI5 + config RT_SOFT_SPI5_SCK_PIN + int "SCK pin number" + range 0 32767 + default 16 + config RT_SOFT_SPI5_MISO_PIN + int "MISO pin number" + range 0 32767 + default 17 + config RT_SOFT_SPI5_MOSI_PIN + int "MOSI pin number" + range 0 32767 + default 18 + config RT_SOFT_SPI5_BUS_NAME + string "Bus name" + default "spi5" + config RT_SOFT_SPI5_TIMING_DELAY + int "Timing delay (us)" + range 0 32767 + default 1 + endif + menuconfig RT_USING_SOFT_SPI6 + bool "Enable SPI6 Bus (software simulation)" + default n + if RT_USING_SOFT_SPI6 + config RT_SOFT_SPI6_SCK_PIN + int "SCK pin number" + range 0 32767 + default 19 + config RT_SOFT_SPI6_MISO_PIN + int "MISO pin number" + range 0 32767 + default 20 + config RT_SOFT_SPI6_MOSI_PIN + int "MOSI pin number" + range 0 32767 + default 21 + config RT_SOFT_SPI6_BUS_NAME + string "Bus name" + default "spi6" + config RT_SOFT_SPI6_TIMING_DELAY + int "Timing delay (us)" + range 0 32767 + default 1 + endif + + endif + config RT_USING_QSPI bool "Enable QSPI mode" default n diff --git a/components/drivers/spi/SConscript b/components/drivers/spi/SConscript index 6897dab6d3..fc608c46ae 100644 --- a/components/drivers/spi/SConscript +++ b/components/drivers/spi/SConscript @@ -10,6 +10,9 @@ LOCAL_CFLAGS = '' if GetDepend('RT_USING_SPI_BITOPS'): src += ['dev_spi_bit_ops.c'] +if GetDepend('RT_USING_SOFT_SPI'): + src += ['dev_soft_spi.c'] + if GetDepend('RT_USING_QSPI'): src += ['dev_qspi_core.c'] diff --git a/components/drivers/spi/dev_soft_spi.c b/components/drivers/spi/dev_soft_spi.c new file mode 100644 index 0000000000..a308299f6c --- /dev/null +++ b/components/drivers/spi/dev_soft_spi.c @@ -0,0 +1,269 @@ +/* + * Copyright (c) 2006-2025 RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2025-01-23 CYFS first version + */ +#include +#include +#include + +#ifdef RT_USING_SOFT_SPI +#if !defined(RT_USING_SOFT_SPI0) &&\ + !defined(RT_USING_SOFT_SPI1) && !defined(RT_USING_SOFT_SPI2) &&\ + !defined(RT_USING_SOFT_SPI3) && !defined(RT_USING_SOFT_SPI4) &&\ + !defined(RT_USING_SOFT_SPI5) && !defined(RT_USING_SOFT_SPI6) + #error "Please define at least one RT_USING_SOFT_SPIx" + /* + This driver can be disabled at: + menuconfig -> RT-Thread Components -> Device Drivers -> Using I2C device drivers + */ +#endif + +#define DBG_ENABLE +#define DBG_TAG "SPI_S" +#ifdef RT_SPI_BITOPS_DEBUG + #define DBG_LEVEL DBG_LOG +#endif +#include + +/* spi config class */ +struct rt_soft_spi_config +{ + rt_base_t sck; + rt_base_t miso; + rt_base_t mosi; + rt_uint32_t timing_delay; + const char *bus_name; +}; + +/* spi dirver class */ +struct rt_soft_spi +{ + struct rt_spi_bit_obj spi; + struct rt_spi_bit_ops ops; + struct rt_soft_spi_config *cfg; +}; + +static struct rt_soft_spi_config soft_spi_config[] = +{ +#ifdef RT_USING_SOFT_SPI0 + { + .sck = RT_SOFT_SPI0_SCK_PIN, + .miso = RT_SOFT_SPI0_MISO_PIN, + .mosi = RT_SOFT_SPI0_MOSI_PIN, + .timing_delay = RT_SOFT_SPI0_TIMING_DELAY, + .bus_name = RT_SOFT_SPI0_BUS_NAME, + }, +#endif /*RT_USING_SOFT_SPI0*/ +#ifdef RT_USING_SOFT_SPI1 + { + .sck = RT_SOFT_SPI1_SCK_PIN, + .miso = RT_SOFT_SPI1_MISO_PIN, + .mosi = RT_SOFT_SPI1_MOSI_PIN, + .timing_delay = RT_SOFT_SPI1_TIMING_DELAY, + .bus_name = RT_SOFT_SPI1_BUS_NAME, + }, +#endif /*RT_USING_SOFT_SPI1*/ +#ifdef RT_USING_SOFT_SPI2 + { + .sck = RT_SOFT_SPI2_SCK_PIN, + .miso = RT_SOFT_SPI2_MISO_PIN, + .mosi = RT_SOFT_SPI2_MOSI_PIN, + .timing_delay = RT_SOFT_SPI2_TIMING_DELAY, + .bus_name = RT_SOFT_SPI2_BUS_NAME, + }, +#endif /*RT_USING_SOFT_SPI2*/ +#ifdef RT_USING_SOFT_SPI3 + { + .sck = RT_SOFT_SPI3_SCK_PIN, + .miso = RT_SOFT_SPI3_MISO_PIN, + .mosi = RT_SOFT_SPI3_MOSI_PIN, + .timing_delay = RT_SOFT_SPI3_TIMING_DELAY, + .bus_name = RT_SOFT_SPI3_BUS_NAME, + }, +#endif /*RT_USING_SOFT_SPI3*/ +#ifdef RT_USING_SOFT_SPI4 + { + .sck = RT_SOFT_SPI4_SCK_PIN, + .miso = RT_SOFT_SPI4_MISO_PIN, + .mosi = RT_SOFT_SPI4_MOSI_PIN, + .timing_delay = RT_SOFT_SPI4_TIMING_DELAY, + .bus_name = RT_SOFT_SPI4_BUS_NAME, + }, +#endif /*RT_USING_SOFT_SPI4*/ +#ifdef RT_USING_SOFT_SPI5 + { + .sck = RT_SOFT_SPI5_SCK_PIN, + .miso = RT_SOFT_SPI5_MISO_PIN, + .mosi = RT_SOFT_SPI5_MOSI_PIN, + .timing_delay = RT_SOFT_SPI5_TIMING_DELAY, + .bus_name = RT_SOFT_SPI5_BUS_NAME, + }, +#endif /*RT_USING_SOFT_SPI5*/ +#ifdef RT_USING_SOFT_SPI6 + { + .sck = RT_SOFT_SPI6_SCK_PIN, + .miso = RT_SOFT_SPI6_MISO_PIN, + .mosi = RT_SOFT_SPI6_MOSI_PIN, + .timing_delay = RT_SOFT_SPI6_TIMING_DELAY, + .bus_name = RT_SOFT_SPI6_BUS_NAME, + }, +#endif /*RT_USING_SOFT_SPI6*/ + +}; + +static struct rt_soft_spi spi_obj[sizeof(soft_spi_config) / sizeof(soft_spi_config[0])]; + +static void spi_soft_pin_init(struct rt_soft_spi * soft_spi) +{ + struct rt_soft_spi_config *cfg = (struct rt_soft_spi_config *)soft_spi->cfg; + rt_pin_mode(cfg->sck, PIN_MODE_OUTPUT); + rt_pin_mode(cfg->miso, PIN_MODE_INPUT); + rt_pin_mode(cfg->mosi, PIN_MODE_OUTPUT); + + rt_pin_write(cfg->miso, PIN_HIGH); + rt_pin_write(cfg->sck, PIN_HIGH); + rt_pin_write(cfg->mosi, PIN_HIGH); +} + + +static void spi_soft_tog_sclk(void *data) +{ + struct rt_soft_spi_config *cfg = (struct rt_soft_spi_config *)data; + if(rt_pin_read(cfg->sck) == PIN_HIGH) + { + rt_pin_write(cfg->sck, PIN_LOW); + } + else + { + rt_pin_write(cfg->sck, PIN_HIGH); + } +} + +static void spi_soft_set_sclk(void *data, rt_int32_t state) +{ + struct rt_soft_spi_config *cfg = (struct rt_soft_spi_config *)data; + if (state) + { + rt_pin_write(cfg->sck, PIN_HIGH); + } + else + { + rt_pin_write(cfg->sck, PIN_LOW); + } +} + +static void spi_soft_set_mosi(void *data, rt_int32_t state) +{ + struct rt_soft_spi_config *cfg = (struct rt_soft_spi_config *)data; + if (state) + { + rt_pin_write(cfg->mosi, PIN_HIGH); + } + else + { + rt_pin_write(cfg->mosi, PIN_LOW); + } +} + +static void spi_soft_set_miso(void *data, rt_int32_t state) +{ + struct rt_soft_spi_config *cfg = (struct rt_soft_spi_config *)data; + if (state) + { + rt_pin_write(cfg->miso, PIN_HIGH); + } + else + { + rt_pin_write(cfg->miso, PIN_LOW); + } +} + +static rt_int32_t spi_soft_get_sclk(void *data) +{ + struct rt_soft_spi_config *cfg = (struct rt_soft_spi_config *)data; + return rt_pin_read(cfg->sck); +} + +static rt_int32_t spi_soft_get_mosi(void *data) +{ + struct rt_soft_spi_config *cfg = (struct rt_soft_spi_config *)data; + return rt_pin_read(cfg->mosi); +} + +static rt_int32_t spi_soft_get_miso(void *data) +{ + struct rt_soft_spi_config *cfg = (struct rt_soft_spi_config *)data; + return rt_pin_read(cfg->miso); +} + +static void spi_soft_dir_mosi(void *data, rt_int32_t state) +{ + struct rt_soft_spi_config *cfg = (struct rt_soft_spi_config *)data; + if (state) + { + rt_pin_mode(cfg->mosi, PIN_MODE_INPUT); + } + else + { + rt_pin_mode(cfg->mosi, PIN_MODE_OUTPUT); + } +} + +static void spi_soft_dir_miso(void *data, rt_int32_t state) +{ + struct rt_soft_spi_config *cfg = (struct rt_soft_spi_config *)data; + if (state) + { + rt_pin_mode(cfg->miso, PIN_MODE_INPUT); + } + else + { + rt_pin_mode(cfg->miso, PIN_MODE_OUTPUT); + } +} + +static struct rt_spi_bit_ops soft_spi_ops= +{ + .data = RT_NULL, + .pin_init = RT_NULL, + .tog_sclk = spi_soft_tog_sclk, + .set_sclk = spi_soft_set_sclk, + .set_mosi = spi_soft_set_mosi, + .set_miso = spi_soft_set_miso, + .get_sclk = spi_soft_get_sclk, + .get_mosi = spi_soft_get_mosi, + .get_miso = spi_soft_get_miso, + .dir_mosi = spi_soft_dir_mosi, + .dir_miso = spi_soft_dir_miso, + .udelay = rt_hw_us_delay, +}; + +/* Soft SPI initialization function */ +int rt_soft_spi_init(void) +{ + rt_size_t obj_num = sizeof(spi_obj) / sizeof(struct rt_soft_spi); + rt_err_t result; + + for (rt_size_t i = 0; i < obj_num; i++) + { + rt_memcpy(&spi_obj[i].ops, &soft_spi_ops, sizeof(struct rt_spi_bit_ops)); + spi_obj[i].ops.data = (void *)&soft_spi_config[i]; + spi_obj[i].spi.ops = &soft_spi_ops; + spi_obj[i].cfg = (void *)&soft_spi_config[i]; + spi_soft_pin_init(&spi_obj[i]); + spi_obj[i].spi.ops->delay_us = soft_spi_config[i].timing_delay; + result = rt_spi_bit_add_bus(&spi_obj[i].spi, soft_spi_config[i].bus_name, &spi_obj[i].ops); + RT_ASSERT(result == RT_EOK); + } + + return RT_EOK; +} +INIT_PREV_EXPORT(rt_soft_spi_init); + +#endif /* RT_USING_SOFT_SPI */ + diff --git a/components/drivers/spi/dev_spi_bit_ops.c b/components/drivers/spi/dev_spi_bit_ops.c index d2a26a766d..4f216a9a3b 100644 --- a/components/drivers/spi/dev_spi_bit_ops.c +++ b/components/drivers/spi/dev_spi_bit_ops.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006-2024, RT-Thread Development Team + * Copyright (c) 2006-2025 RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * @@ -87,11 +87,23 @@ rt_inline rt_ssize_t spi_xfer_4line_data8(struct rt_spi_bit_ops *ops, TOG_SCLK(ops); - if (config->mode & RT_SPI_MSB) { rx_data <<= 1; bit = 0x01; } - else { rx_data >>= 1; bit = 0x80; } + if (config->mode & RT_SPI_MSB) + { + rx_data <<= 1; bit = 0x01; + } + else + { + rx_data >>= 1; bit = 0x80; + } - if (GET_MISO(ops)) { rx_data |= bit; } - else { rx_data &= ~bit; } + if (GET_MISO(ops)) + { + rx_data |= bit; + } + else + { + rx_data &= ~bit; + } spi_delay2(ops); @@ -150,11 +162,23 @@ rt_inline rt_ssize_t spi_xfer_4line_data16(struct rt_spi_bit_ops *ops, TOG_SCLK(ops); - if (config->mode & RT_SPI_MSB) { rx_data <<= 1; bit = 0x0001; } - else { rx_data >>= 1; bit = 0x8000; } + if (config->mode & RT_SPI_MSB) + { + rx_data <<= 1; bit = 0x0001; + } + else + { + rx_data >>= 1; bit = 0x8000; + } - if (GET_MISO(ops)) { rx_data |= bit; } - else { rx_data &= ~bit; } + if (GET_MISO(ops)) + { + rx_data |= bit; + } + else + { + rx_data &= ~bit; + } spi_delay2(ops); @@ -244,11 +268,23 @@ rt_inline rt_ssize_t spi_xfer_3line_data8(struct rt_spi_bit_ops *ops, TOG_SCLK(ops); - if (config->mode & RT_SPI_MSB) { rx_data <<= 1; bit = 0x01; } - else { rx_data >>= 1; bit = 0x80; } + if (config->mode & RT_SPI_MSB) + { + rx_data <<= 1; bit = 0x01; + } + else + { + rx_data >>= 1; bit = 0x80; + } - if (GET_MOSI(ops)) { rx_data |= bit; } - else { rx_data &= ~bit; } + if (GET_MOSI(ops)) + { + rx_data |= bit; + } + else + { + rx_data &= ~bit; + } spi_delay2(ops); @@ -345,11 +381,23 @@ rt_inline rt_ssize_t spi_xfer_3line_data16(struct rt_spi_bit_ops *ops, TOG_SCLK(ops); - if (config->mode & RT_SPI_MSB) { rx_data <<= 1; bit = 0x0001; } - else { rx_data >>= 1; bit = 0x8000; } + if (config->mode & RT_SPI_MSB) + { + rx_data <<= 1; bit = 0x0001; + } + else + { + rx_data >>= 1; bit = 0x8000; + } - if (GET_MOSI(ops)) { rx_data |= bit; } - else { rx_data &= ~bit; } + if (GET_MOSI(ops)) + { + rx_data |= bit; + } + else + { + rx_data &= ~bit; + } spi_delay2(ops); @@ -456,15 +504,14 @@ rt_ssize_t spi_bit_xfer(struct rt_spi_device *device, struct rt_spi_message *mes rt_pin_write(cs_pin, PIN_LOW); } spi_delay(ops); + } /* spi phase */ - if (config->mode & RT_SPI_CPHA) + if ((config->mode & RT_SPI_CPHA)) { spi_delay(ops); TOG_SCLK(ops); } - } - if (config->mode & RT_SPI_3WIRE) { if (config->data_width <= 8) @@ -487,10 +534,15 @@ rt_ssize_t spi_bit_xfer(struct rt_spi_device *device, struct rt_spi_message *mes length = spi_xfer_4line_data16(ops, config, message->send_buf, message->recv_buf, message->length); } } - /* release CS */ - if (message->cs_take && !(device->config.mode & RT_SPI_NO_CS) && (cs_pin != PIN_NONE)) + if (message->cs_release && !(device->config.mode & RT_SPI_NO_CS) && (cs_pin != PIN_NONE)) { + + if ((config->mode & RT_SPI_CPOL) && !GET_SCLK(ops)) + { + spi_delay(ops); + TOG_SCLK(ops); + } spi_delay(ops); if (device->config.mode & RT_SPI_CS_HIGH) { @@ -501,6 +553,7 @@ rt_ssize_t spi_bit_xfer(struct rt_spi_device *device, struct rt_spi_message *mes rt_pin_write(cs_pin, PIN_HIGH); } LOG_I("spi release cs\n"); + } return length; diff --git a/components/drivers/spi/dev_spi_core.c b/components/drivers/spi/dev_spi_core.c index d84aaac055..3a3008d6e7 100644 --- a/components/drivers/spi/dev_spi_core.c +++ b/components/drivers/spi/dev_spi_core.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006-2023, RT-Thread Development Team + * Copyright (c) 2006-2025 RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * @@ -140,7 +140,7 @@ rt_err_t rt_spi_bus_configure(struct rt_spi_device *device) result = rt_mutex_take(&(device->bus->lock), RT_WAITING_FOREVER); if (result == RT_EOK) { - if (device->bus->owner == device) + if (device->bus->owner == RT_NULL || device->bus->owner == device) { /* current device is using, re-configure SPI bus */ result = device->bus->ops->configure(device, &device->config);