From 5810f4de7d04eeda957f63b529f9f81d254ad36c Mon Sep 17 00:00:00 2001 From: kylepengchn <88711779+kylepengchn@users.noreply.github.com> Date: Wed, 23 Mar 2022 14:16:14 +0800 Subject: [PATCH] =?UTF-8?q?[components][drivers][spi]:=20=E5=9F=BA?= =?UTF-8?q?=E4=BA=8ESPI=E6=80=BB=E7=BA=BF=E9=A9=B1=E5=8A=A8=E6=A1=86?= =?UTF-8?q?=E6=9E=B6=E6=B7=BB=E5=8A=A0=E6=A8=A1=E6=8B=9FSPI=E6=80=BB?= =?UTF-8?q?=E7=BA=BF=E6=89=A9=E5=B1=95=20(#5656)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * add soft-spi * add spi-bit-ops.c/h to components/drivers/spi * add a drv_soft_spi example for gd32303e-eval Signed-off-by: kyle * Fixed the format and the certificate. Signed-off-by: kyle * Update the certificate data. Signed-off-by: kyle --- bsp/gd32303e-eval/Kconfig | 6 + bsp/gd32303e-eval/drivers/SConscript | 6 +- bsp/gd32303e-eval/drivers/drv_soft_spi.c | 303 +++++++++++++ bsp/gd32303e-eval/drivers/drv_soft_spi.h | 24 ++ components/drivers/Kconfig | 13 +- components/drivers/spi/SConscript | 3 + components/drivers/spi/spi-bit-ops.c | 525 +++++++++++++++++++++++ components/drivers/spi/spi-bit-ops.h | 53 +++ 8 files changed, 931 insertions(+), 2 deletions(-) create mode 100644 bsp/gd32303e-eval/drivers/drv_soft_spi.c create mode 100644 bsp/gd32303e-eval/drivers/drv_soft_spi.h create mode 100644 components/drivers/spi/spi-bit-ops.c create mode 100644 components/drivers/spi/spi-bit-ops.h diff --git a/bsp/gd32303e-eval/Kconfig b/bsp/gd32303e-eval/Kconfig index 8287403eeb..92419a3aa0 100644 --- a/bsp/gd32303e-eval/Kconfig +++ b/bsp/gd32303e-eval/Kconfig @@ -64,6 +64,12 @@ config RT_USING_SPI2 select RT_USING_SPI default n +config RT_USING_SPI3 + bool "Using SPI2 BUS (software simulation)" + select RT_USING_SPI + select RT_USING_SPI_BITOPS + default n + config RT_USING_I2C0 bool "Using I2C0" select RT_USING_I2C diff --git a/bsp/gd32303e-eval/drivers/SConscript b/bsp/gd32303e-eval/drivers/SConscript index ef03e2dcf0..306cd7e720 100644 --- a/bsp/gd32303e-eval/drivers/SConscript +++ b/bsp/gd32303e-eval/drivers/SConscript @@ -15,7 +15,11 @@ CPPPATH = [cwd] # add spi drivers. if GetDepend('RT_USING_SPI'): src += ['drv_spi.c'] - + +# add softspi drivers. +if GetDepend('RT_USING_SPI_BITOPS'): + src += ['drv_soft_spi.c'] + # add i2c drivers. if GetDepend('RT_USING_I2C'): src += ['drv_i2c.c'] diff --git a/bsp/gd32303e-eval/drivers/drv_soft_spi.c b/bsp/gd32303e-eval/drivers/drv_soft_spi.c new file mode 100644 index 0000000000..bd24256a85 --- /dev/null +++ b/bsp/gd32303e-eval/drivers/drv_soft_spi.c @@ -0,0 +1,303 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2021-10-11 kyle first implementation. + */ + +#include "drv_soft_spi.h" +#include +#include + +#if defined(RT_USING_SPI) && defined(RT_USING_SPI_BITOPS) && defined(RT_USING_PIN) +#include +#include "spi-bit-ops.h" + +#define DBG_TAG "drv.SPI" +#ifdef RT_SPI_DEBUG +#define DBG_LVL DBG_LOG +#else +#define DBG_LVL DBG_WARNING +#endif +#include + +#ifndef ITEM_NUM +#define ITEM_NUM(items) sizeof(items) / sizeof(items[0]) +#endif + +struct gd32_spi_bit_data +{ + struct + { + rcu_periph_enum clk; + rt_uint32_t port; + rt_uint32_t pin; + } sclk, mosi, miso; +}; + + +rt_inline FlagStatus GPIO_OUTPUT_BIT_GET(uint32_t gpio_periph, uint32_t pin) +{ + if((uint32_t)RESET !=(GPIO_OCTL(gpio_periph)&(pin))){ + return SET; + }else{ + return RESET; + } +} + +rt_inline void GPIO_BIT_RESET(uint32_t gpio_periph, uint32_t pin) +{ + GPIO_BC(gpio_periph) = (uint32_t)pin; +} + +rt_inline void GPIO_BIT_SET(uint32_t gpio_periph, uint32_t pin) +{ + GPIO_BOP(gpio_periph) = (uint32_t)pin; +} + +rt_inline FlagStatus GPIO_INPUT_BIT_GET(uint32_t gpio_periph,uint32_t pin) +{ + if((uint32_t)RESET != (GPIO_ISTAT(gpio_periph)&(pin))){ + return SET; + }else{ + return RESET; + } +} + +rt_inline void GPIO_INIT(uint32_t gpio_periph, uint32_t mode, uint32_t speed, uint32_t pin) +{ + uint16_t i; + uint32_t temp_mode = 0U; + uint32_t reg = 0U; + + /* GPIO mode configuration */ + temp_mode = (uint32_t)(mode & ((uint32_t)0x0FU)); + + /* GPIO speed configuration */ + if(((uint32_t)0x00U) != ((uint32_t)mode & ((uint32_t)0x10U))){ + /* output mode max speed:10MHz,2MHz,50MHz */ + temp_mode |= (uint32_t)speed; + } + + /* configure the eight low port pins with GPIO_CTL0 */ + for(i = 0U;i < 8U;i++){ + if((1U << i) & pin){ + reg = GPIO_CTL0(gpio_periph); + + /* clear the specified pin mode bits */ + reg &= ~GPIO_MODE_MASK(i); + /* set the specified pin mode bits */ + reg |= GPIO_MODE_SET(i, temp_mode); + + /* set IPD or IPU */ + if(GPIO_MODE_IPD == mode){ + /* reset the corresponding OCTL bit */ + GPIO_BC(gpio_periph) = (uint32_t)((1U << i) & pin); + }else{ + /* set the corresponding OCTL bit */ + if(GPIO_MODE_IPU == mode){ + GPIO_BOP(gpio_periph) = (uint32_t)((1U << i) & pin); + } + } + /* set GPIO_CTL0 register */ + GPIO_CTL0(gpio_periph) = reg; + } + } + /* configure the eight high port pins with GPIO_CTL1 */ + for(i = 8U;i < 16U;i++){ + if((1U << i) & pin){ + reg = GPIO_CTL1(gpio_periph); + + /* clear the specified pin mode bits */ + reg &= ~GPIO_MODE_MASK(i - 8U); + /* set the specified pin mode bits */ + reg |= GPIO_MODE_SET(i - 8U, temp_mode); + + /* set IPD or IPU */ + if(GPIO_MODE_IPD == mode){ + /* reset the corresponding OCTL bit */ + GPIO_BC(gpio_periph) = (uint32_t)((1U << i) & pin); + }else{ + /* set the corresponding OCTL bit */ + if(GPIO_MODE_IPU == mode){ + GPIO_BOP(gpio_periph) = (uint32_t)((1U << i) & pin); + } + } + /* set GPIO_CTL1 register */ + GPIO_CTL1(gpio_periph) = reg; + } + } +} + +#define GPIO_SET_OUTPUT(port, pin) GPIO_INIT(port, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, pin) +#define GPIO_SET_INPUT(port, pin) GPIO_INIT(port, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, pin) + + +static void gpio_tog_sclk(void *data) +{ + struct gd32_spi_bit_data *bd = data; + + if (GPIO_OUTPUT_BIT_GET(bd->sclk.port, bd->sclk.pin) == SET) + { + GPIO_BIT_RESET(bd->sclk.port, bd->sclk.pin); + } + else + { + GPIO_BIT_SET(bd->sclk.port, bd->sclk.pin); + } +} + +static void gpio_set_sclk(void *data, rt_int32_t state) +{ + struct gd32_spi_bit_data *bd = data; + + if (state) + { + GPIO_BIT_SET(bd->sclk.port, bd->sclk.pin); + } + else + { + GPIO_BIT_RESET(bd->sclk.port, bd->sclk.pin); + } +} + +static void gpio_set_mosi(void *data, rt_int32_t state) +{ + struct gd32_spi_bit_data *bd = data; + + if (state) + { + GPIO_BIT_SET(bd->mosi.port, bd->mosi.pin); + } + else + { + GPIO_BIT_RESET(bd->mosi.port, bd->mosi.pin); + } +} + +static void gpio_set_miso(void *data, rt_int32_t state) +{ + struct gd32_spi_bit_data *bd = data; + + if (state) + { + GPIO_BIT_SET(bd->miso.port, bd->miso.pin); + } + else + { + GPIO_BIT_RESET(bd->miso.port, bd->miso.pin); + } +} + +static rt_int32_t gpio_get_sclk(void *data) +{ + struct gd32_spi_bit_data *bd = data; + + return GPIO_INPUT_BIT_GET(bd->sclk.port, bd->sclk.pin); +} + +static rt_int32_t gpio_get_mosi(void *data) +{ + struct gd32_spi_bit_data *bd = data; + + return GPIO_INPUT_BIT_GET(bd->mosi.port, bd->mosi.pin); +} + +static rt_int32_t gpio_get_miso(void *data) +{ + struct gd32_spi_bit_data *bd = data; + + return GPIO_INPUT_BIT_GET(bd->miso.port, bd->miso.pin); +} + +static void gpio_dir_mosi(void *data, rt_int32_t state) +{ + struct gd32_spi_bit_data *bd = data; + + if (state) + { + GPIO_SET_INPUT(bd->mosi.port, bd->mosi.pin); + } + else + { + GPIO_SET_OUTPUT(bd->mosi.port, bd->mosi.pin); + } +} + +static void gpio_dir_miso(void *data, rt_int32_t state) +{ + struct gd32_spi_bit_data *bd = data; + + if (state) + { + GPIO_SET_INPUT(bd->miso.port, bd->miso.pin); + } + else + { + GPIO_SET_OUTPUT(bd->miso.port, bd->miso.pin); + } +} + +static void gpio_udelay(rt_uint32_t us) +{ + int i = ((rcu_clock_freq_get(CK_SYS) / 4000000) * us); + + while (i) + { + i--; + } +} + +static void soft_spi_gpio_init(const struct gd32_spi_bit_data *bd) +{ + rcu_periph_clock_enable(bd->sclk.clk); + rcu_periph_clock_enable(bd->mosi.clk); + rcu_periph_clock_enable(bd->miso.clk); + + gpio_init(bd->sclk.port, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, bd->sclk.pin); + gpio_init(bd->mosi.port, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, bd->mosi.pin); + gpio_init(bd->miso.port, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, bd->miso.pin); + + GPIO_BIT_SET(bd->sclk.port, bd->sclk.pin); + GPIO_BIT_SET(bd->mosi.port, bd->mosi.pin); + GPIO_BIT_SET(bd->miso.port, bd->miso.pin); +} + +int rt_soft_spi_init(void) +{ + int result = 0; + + { + static const struct gd32_spi_bit_data spi1_bdata = + { + .sclk = { RCU_GPIOB, GPIOB, GPIO_PIN_13}, + .mosi = { RCU_GPIOB, GPIOB, GPIO_PIN_15}, + .miso = { RCU_GPIOB, GPIOB, GPIO_PIN_14}, + }; + static struct rt_spi_bit_ops spi1_bops = + { + .data = (void *)&spi1_bdata, + .tog_sclk = gpio_tog_sclk, + .set_sclk = gpio_set_sclk, + .set_mosi = gpio_set_mosi, + .set_miso = gpio_set_miso, + .get_sclk = gpio_get_sclk, + .get_mosi = gpio_get_mosi, + .get_miso = gpio_get_miso, + .dir_mosi = gpio_dir_mosi, + .dir_miso = gpio_dir_miso, + .udelay = gpio_udelay, + }; + struct rt_spi_bit_obj spi1_obj; + + soft_spi_gpio_init(&spi1_bdata); + rt_spi_bit_add_bus(&spi1_obj, "spi3", &spi1_bops); + } + + return result; +} +INIT_BOARD_EXPORT(rt_soft_spi_init); +#endif diff --git a/bsp/gd32303e-eval/drivers/drv_soft_spi.h b/bsp/gd32303e-eval/drivers/drv_soft_spi.h new file mode 100644 index 0000000000..1db0a691e9 --- /dev/null +++ b/bsp/gd32303e-eval/drivers/drv_soft_spi.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2021-10-11 kyle first implementation. + */ + +#ifndef __DRV_SOFT_SPI_H__ +#define __DRV_SOFT_SPI_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +int rt_soft_spi_init(void); + +#ifdef __cplusplus +} +#endif + +#endif // __DRV_SPI_H__ diff --git a/components/drivers/Kconfig b/components/drivers/Kconfig index d197bd246e..18f074ed70 100755 --- a/components/drivers/Kconfig +++ b/components/drivers/Kconfig @@ -228,7 +228,18 @@ config RT_USING_SPI bool "Using SPI Bus/Device device drivers" default n - if RT_USING_SPI + if RT_USING_SPI + config RT_USING_SPI_BITOPS + select RT_USING_PIN + bool "Use GPIO to simulate SPI" + default n + + if RT_USING_SPI_BITOPS + config RT_SPI_BITOPS_DEBUG + bool "Use simulate SPI debug message" + default n + endif + config RT_USING_QSPI bool "Enable QSPI mode" default n diff --git a/components/drivers/spi/SConscript b/components/drivers/spi/SConscript index 81d2c4c8a0..b409f1196c 100644 --- a/components/drivers/spi/SConscript +++ b/components/drivers/spi/SConscript @@ -6,6 +6,9 @@ src = ['spi_core.c', 'spi_dev.c'] CPPPATH = [cwd, cwd + '/../include'] LOCAL_CFLAGS = '' +if GetDepend('RT_USING_SPI_BITOPS'): + src += ['spi-bit-ops.c'] + if GetDepend('RT_USING_QSPI'): src += ['qspi_core.c'] diff --git a/components/drivers/spi/spi-bit-ops.c b/components/drivers/spi/spi-bit-ops.c new file mode 100644 index 0000000000..253c471849 --- /dev/null +++ b/components/drivers/spi/spi-bit-ops.c @@ -0,0 +1,525 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2021-10-11 kyle first version + */ + +#include +#include + +#define DBG_TAG "SPI" +#ifdef RT_SPI_BITOPS_DEBUG +#define DBG_LVL DBG_LOG +#else +#define DBG_LVL DBG_ERROR +#endif +#include + +#define TOG_SCLK(ops) ops->tog_sclk(ops->data) +#define SET_SCLK(ops, val) ops->set_sclk(ops->data, val) +#define SET_MOSI(ops, val) ops->set_mosi(ops->data, val) +#define SET_MISO(ops, val) ops->set_miso(ops->data, val) +#define GET_SCLK(ops) ops->get_sclk(ops->data) +#define GET_MOSI(ops) ops->get_mosi(ops->data) +#define GET_MISO(ops) ops->get_miso(ops->data) +#define DIR_MOSI(ops, val) ops->dir_mosi(ops->data, val) +#define DIR_MISO(ops, val) ops->dir_miso(ops->data, val) + +rt_inline void spi_delay(struct rt_spi_bit_ops *ops) +{ + ops->udelay((ops->delay_us + 1) >> 1); +} + +rt_inline void spi_delay2(struct rt_spi_bit_ops *ops) +{ + ops->udelay(ops->delay_us); +} + +#define SCLK_H(ops) SET_SCLK(ops, 1) +#define SCLK_L(ops) SET_SCLK(ops, 0) +#define MOSI_H(ops) SET_MOSI(ops, 1) +#define MOSI_L(ops) SET_MOSI(ops, 0) +#define MOSI_IN(ops) DIR_MOSI(ops, 1) +#define MOSI_OUT(ops) DIR_MOSI(ops, 0) +#define MISO_IN(ops) DIR_MISO(ops, 1) +#define MISO_OUT(ops) DIR_MISO(ops, 0) + +rt_inline rt_size_t spi_xfer_4line_data8(struct rt_spi_bit_ops *ops, + struct rt_spi_configuration *config, + const void *send_buf, + void *recv_buf, + rt_size_t length) +{ + int i = 0; + + RT_ASSERT(ops != RT_NULL); + RT_ASSERT(length != 0); + + { + const rt_uint8_t *send_ptr = send_buf; + rt_uint8_t *recv_ptr = recv_buf; + rt_uint32_t size = length; + + while (size--) + { + rt_uint8_t tx_data = 0xFF; + rt_uint8_t rx_data = 0xFF; + rt_uint8_t bit = 0; + + if (send_buf != RT_NULL) + { + tx_data = *send_ptr++; + } + + for (i = 0; i < 8; i++) + { + if (config->mode & RT_SPI_MSB) { bit = tx_data & (0x1 << (7 - i)); } + else { bit = tx_data & (0x1 << i); } + + if (bit) MOSI_H(ops); + else MOSI_L(ops); + + spi_delay2(ops); + + TOG_SCLK(ops); + + 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; } + + spi_delay2(ops); + + if (!(config->mode & RT_SPI_CPHA) || (size != 0) || (i < 7)) + { + TOG_SCLK(ops); + } + } + + if (recv_buf != RT_NULL) + { + *recv_ptr++ = rx_data; + } + } + } + + return length; +} + +rt_inline rt_size_t spi_xfer_4line_data16(struct rt_spi_bit_ops *ops, + struct rt_spi_configuration *config, + const void *send_buf, + void *recv_buf, + rt_size_t length) +{ + int i = 0; + + RT_ASSERT(ops != RT_NULL); + RT_ASSERT(length != 0); + + { + const rt_uint16_t *send_ptr = send_buf; + rt_uint16_t *recv_ptr = recv_buf; + rt_uint32_t size = length; + + while (size--) + { + rt_uint16_t tx_data = 0xFFFF; + rt_uint16_t rx_data = 0xFFFF; + rt_uint16_t bit = 0; + + if (send_buf != RT_NULL) + { + tx_data = *send_ptr++; + } + + for (i = 0; i < 16; i++) + { + if (config->mode & RT_SPI_MSB) { bit = tx_data & (0x1 << (15 - i)); } + else { bit = tx_data & (0x1 << i); } + + if (bit) MOSI_H(ops); + else MOSI_L(ops); + + spi_delay2(ops); + + TOG_SCLK(ops); + + 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; } + + spi_delay2(ops); + + if (!(config->mode & RT_SPI_CPHA) || (size != 0) || (i < 15)) + { + TOG_SCLK(ops); + } + } + + if (recv_buf != RT_NULL) + { + *recv_ptr++ = rx_data; + } + } + } + + return length; +} + +rt_inline rt_size_t spi_xfer_3line_data8(struct rt_spi_bit_ops *ops, + struct rt_spi_configuration *config, + const void *send_buf, + void *recv_buf, + rt_size_t length) +{ + int i = 0; + + RT_ASSERT(ops != RT_NULL); + RT_ASSERT(length != 0); + + { + const rt_uint8_t *send_ptr = send_buf; + rt_uint8_t *recv_ptr = recv_buf; + rt_uint32_t size = length; + rt_uint8_t send_flg = 0; + + if ((send_buf != RT_NULL) || (recv_buf == RT_NULL)) + { + MOSI_OUT(ops); + send_flg = 1; + } + else + { + MOSI_IN(ops); + } + + while (size--) + { + rt_uint8_t tx_data = 0xFF; + rt_uint8_t rx_data = 0xFF; + rt_uint8_t bit = 0; + + if (send_buf != RT_NULL) + { + tx_data = *send_ptr++; + } + + if (send_flg) + { + for (i = 0; i < 8; i++) + { + if (config->mode & RT_SPI_MSB) { bit = tx_data & (0x1 << (7 - i)); } + else { bit = tx_data & (0x1 << i); } + + if (bit) MOSI_H(ops); + else MOSI_L(ops); + + spi_delay2(ops); + + TOG_SCLK(ops); + + spi_delay2(ops); + + if (!(config->mode & RT_SPI_CPHA) || (size != 0) || (i < 7)) + { + TOG_SCLK(ops); + } + } + + rx_data = tx_data; + } + else + { + for (i = 0; i < 8; i++) + { + spi_delay2(ops); + + TOG_SCLK(ops); + + 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; } + + spi_delay2(ops); + + if (!(config->mode & RT_SPI_CPHA) || (size != 0) || (i < 7)) + { + TOG_SCLK(ops); + } + } + + } + + if (recv_buf != RT_NULL) + { + *recv_ptr++ = rx_data; + } + } + + if (!send_flg) + { + MOSI_OUT(ops); + } + } + + return length; +} + +rt_inline rt_size_t spi_xfer_3line_data16(struct rt_spi_bit_ops *ops, + struct rt_spi_configuration *config, + const void *send_buf, + void *recv_buf, + rt_size_t length) +{ + int i = 0; + + RT_ASSERT(ops != RT_NULL); + RT_ASSERT(length != 0); + + { + const rt_uint16_t *send_ptr = send_buf; + rt_uint16_t *recv_ptr = recv_buf; + rt_uint32_t size = length; + rt_uint8_t send_flg = 0; + + if ((send_buf != RT_NULL) || (recv_buf == RT_NULL)) + { + MOSI_OUT(ops); + send_flg = 1; + } + else + { + MOSI_IN(ops); + } + + while (size--) + { + rt_uint16_t tx_data = 0xFFFF; + rt_uint16_t rx_data = 0xFFFF; + rt_uint16_t bit = 0; + + if (send_buf != RT_NULL) + { + tx_data = *send_ptr++; + } + + if (send_flg) + { + for (i = 0; i < 16; i++) + { + if (config->mode & RT_SPI_MSB) { bit = tx_data & (0x1 << (15 - i)); } + else { bit = tx_data & (0x1 << i); } + + if (bit) MOSI_H(ops); + else MOSI_L(ops); + + spi_delay2(ops); + + TOG_SCLK(ops); + + spi_delay2(ops); + + if (!(config->mode & RT_SPI_CPHA) || (size != 0) || (i < 15)) + { + TOG_SCLK(ops); + } + } + + rx_data = tx_data; + } + else + { + for (i = 0; i < 16; i++) + { + spi_delay2(ops); + + TOG_SCLK(ops); + + 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; } + + spi_delay2(ops); + + if (!(config->mode & RT_SPI_CPHA) || (size != 0) || (i < 15)) + { + TOG_SCLK(ops); + } + } + + } + + if (recv_buf != RT_NULL) + { + *recv_ptr++ = rx_data; + } + } + + if (!send_flg) + { + MOSI_OUT(ops); + } + } + + return length; +} + +rt_err_t spi_bit_configure(struct rt_spi_device *device, struct rt_spi_configuration *configuration) +{ + struct rt_spi_bit_obj *obj = rt_container_of(device->bus, struct rt_spi_bit_obj, bus); + struct rt_spi_bit_ops *ops = obj->ops; + + RT_ASSERT(device != RT_NULL); + RT_ASSERT(configuration != RT_NULL); + + if (configuration->mode & RT_SPI_SLAVE) + { + return -RT_EIO; + } + + if (configuration->mode & RT_SPI_CPOL) + { + SCLK_H(ops); + } + else + { + SCLK_L(ops); + } + + if (configuration->max_hz < 200000) + { + ops->delay_us = 1; + } + else + { + ops->delay_us = 0; + } + + rt_memcpy(&obj->config, configuration, sizeof(struct rt_spi_configuration)); + + return RT_EOK; +} + +rt_uint32_t spi_bit_xfer(struct rt_spi_device *device, struct rt_spi_message *message) +{ + struct rt_spi_bit_obj *obj = rt_container_of(device->bus, struct rt_spi_bit_obj, bus); + struct rt_spi_bit_ops *ops = obj->ops; + struct rt_spi_configuration *config = &obj->config; + rt_base_t cs_pin = (rt_base_t)device->parent.user_data; + + RT_ASSERT(device != NULL); + RT_ASSERT(message != NULL); + +#ifdef RT_SPI_BITOPS_DEBUG + if (!ops->tog_sclk || !ops->set_sclk || !ops->get_sclk) + { + LOG_E("SPI bus error, SCLK line not defined"); + } + if (!ops->set_mosi || !ops->get_mosi) + { + LOG_E("SPI bus error, MOSI line not defined"); + } + if (!ops->set_miso || !ops->get_miso) + { + LOG_E("SPI bus error, MISO line not defined"); + } +#endif + + /* take CS */ + if (message->cs_take) + { + LOG_I("spi take cs\n"); + rt_pin_write(cs_pin, PIN_LOW); + spi_delay(ops); + + /* spi phase */ + if (config->mode & RT_SPI_CPHA) + { + spi_delay(ops); + TOG_SCLK(ops); + } + } + + if (config->mode & RT_SPI_3WIRE) + { + if (config->data_width <= 8) + { + spi_xfer_3line_data8(ops, + config, + message->send_buf, + message->recv_buf, + message->length); + } + else if (config->data_width <= 16) + { + spi_xfer_3line_data16(ops, + config, + message->send_buf, + message->recv_buf, + message->length); + } + } + else + { + if (config->data_width <= 8) + { + spi_xfer_4line_data8(ops, + config, + message->send_buf, + message->recv_buf, + message->length); + } + else if (config->data_width <= 16) + { + spi_xfer_4line_data16(ops, + config, + message->send_buf, + message->recv_buf, + message->length); + } + } + + /* release CS */ + if (message->cs_release) + { + spi_delay(ops); + rt_pin_write(cs_pin, PIN_HIGH); + LOG_I("spi release cs\n"); + } + + return message->length; +} + +static const struct rt_spi_ops spi_bit_bus_ops = +{ + .configure = spi_bit_configure, + .xfer = spi_bit_xfer, +}; + +rt_err_t rt_spi_bit_add_bus(struct rt_spi_bit_obj *obj, + const char *bus_name, + struct rt_spi_bit_ops *ops) +{ + obj->ops = ops; + obj->config.data_width = 8; + obj->config.max_hz = 1 * 1000 * 1000; + obj->config.mode = RT_SPI_MASTER | RT_SPI_MSB | RT_SPI_MODE_0; + + /* idle status */ + if (obj->config.mode & RT_SPI_CPOL) SCLK_H(ops); + else SCLK_L(ops); + + return rt_spi_bus_register(&obj->bus, bus_name, &spi_bit_bus_ops); +} diff --git a/components/drivers/spi/spi-bit-ops.h b/components/drivers/spi/spi-bit-ops.h new file mode 100644 index 0000000000..2f39548e15 --- /dev/null +++ b/components/drivers/spi/spi-bit-ops.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2006-2018, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2021-10-11 kyle first version + */ + +#ifndef __SPI_BIT_OPS_H__ +#define __SPI_BIT_OPS_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct rt_spi_bit_ops +{ + void *const data; /* private data for lowlevel routines */ + void (*const tog_sclk)(void *data); + void (*const set_sclk)(void *data, rt_int32_t state); + void (*const set_mosi)(void *data, rt_int32_t state); + void (*const set_miso)(void *data, rt_int32_t state); + rt_int32_t (*const get_sclk)(void *data); + rt_int32_t (*const get_mosi)(void *data); + rt_int32_t (*const get_miso)(void *data); + + void (*const dir_mosi)(void *data, rt_int32_t state); + void (*const dir_miso)(void *data, rt_int32_t state); + + void (*const udelay)(rt_uint32_t us); + rt_uint32_t delay_us; /* sclk、mosi and miso line delay */ +}; + +struct rt_spi_bit_obj +{ + struct rt_spi_bus bus; + struct rt_spi_bit_ops *ops; + struct rt_spi_configuration config; +}; + +rt_err_t rt_spi_bit_add_bus(struct rt_spi_bit_obj *obj, + const char *bus_name, + struct rt_spi_bit_ops *ops); + +#ifdef __cplusplus +} +#endif + +#endif