summaryrefslogtreecommitdiff
path: root/components
diff options
context:
space:
mode:
authorkylepengchn <[email protected]>2022-03-23 14:16:14 +0800
committerGitHub <[email protected]>2022-03-23 14:16:14 +0800
commit5810f4de7d04eeda957f63b529f9f81d254ad36c (patch)
tree73dc5e5dc34ae4d318cd1da4fc64044289304cc3 /components
parent0f2e9a3afb7383fcbc444753c23594ffa2d6308e (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-xcomponents/drivers/Kconfig13
-rw-r--r--components/drivers/spi/SConscript3
-rw-r--r--components/drivers/spi/spi-bit-ops.c525
-rw-r--r--components/drivers/spi/spi-bit-ops.h53
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