diff options
| author | kylepengchn <[email protected]> | 2022-03-23 14:16:14 +0800 |
|---|---|---|
| committer | GitHub <[email protected]> | 2022-03-23 14:16:14 +0800 |
| commit | 5810f4de7d04eeda957f63b529f9f81d254ad36c (patch) | |
| tree | 73dc5e5dc34ae4d318cd1da4fc64044289304cc3 /components | |
| parent | 0f2e9a3afb7383fcbc444753c23594ffa2d6308e (diff) | |
[components][drivers][spi]: 基于SPI总线驱动框架添加模拟SPI总线扩展 (#5656)
* 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 <[email protected]>
* Fixed the format and the certificate.
Signed-off-by: kyle <[email protected]>
* Update the certificate data.
Signed-off-by: kyle <[email protected]>
Diffstat (limited to 'components')
| -rwxr-xr-x | components/drivers/Kconfig | 13 | ||||
| -rw-r--r-- | components/drivers/spi/SConscript | 3 | ||||
| -rw-r--r-- | components/drivers/spi/spi-bit-ops.c | 525 | ||||
| -rw-r--r-- | components/drivers/spi/spi-bit-ops.h | 53 |
4 files changed, 593 insertions, 1 deletions
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 <spi-bit-ops.h> +#include <rtdevice.h> + +#define DBG_TAG "SPI" +#ifdef RT_SPI_BITOPS_DEBUG +#define DBG_LVL DBG_LOG +#else +#define DBG_LVL DBG_ERROR +#endif +#include <rtdbg.h> + +#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 <rtdevice.h> + +#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 |
