[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 <kylepengchn@163.com> * Fixed the format and the certificate. Signed-off-by: kyle <kylepengchn@163.com> * Update the certificate data. Signed-off-by: kyle <kylepengchn@163.com>
This commit is contained in:
parent
0f2e9a3afb
commit
5810f4de7d
|
@ -64,6 +64,12 @@ config RT_USING_SPI2
|
||||||
select RT_USING_SPI
|
select RT_USING_SPI
|
||||||
default n
|
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
|
config RT_USING_I2C0
|
||||||
bool "Using I2C0"
|
bool "Using I2C0"
|
||||||
select RT_USING_I2C
|
select RT_USING_I2C
|
||||||
|
|
|
@ -16,6 +16,10 @@ CPPPATH = [cwd]
|
||||||
if GetDepend('RT_USING_SPI'):
|
if GetDepend('RT_USING_SPI'):
|
||||||
src += ['drv_spi.c']
|
src += ['drv_spi.c']
|
||||||
|
|
||||||
|
# add softspi drivers.
|
||||||
|
if GetDepend('RT_USING_SPI_BITOPS'):
|
||||||
|
src += ['drv_soft_spi.c']
|
||||||
|
|
||||||
# add i2c drivers.
|
# add i2c drivers.
|
||||||
if GetDepend('RT_USING_I2C'):
|
if GetDepend('RT_USING_I2C'):
|
||||||
src += ['drv_i2c.c']
|
src += ['drv_i2c.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 <board.h>
|
||||||
|
#include <rtthread.h>
|
||||||
|
|
||||||
|
#if defined(RT_USING_SPI) && defined(RT_USING_SPI_BITOPS) && defined(RT_USING_PIN)
|
||||||
|
#include <rtdevice.h>
|
||||||
|
#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 <rtdbg.h>
|
||||||
|
|
||||||
|
#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
|
|
@ -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__
|
|
@ -229,6 +229,17 @@ config RT_USING_SPI
|
||||||
default n
|
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
|
config RT_USING_QSPI
|
||||||
bool "Enable QSPI mode"
|
bool "Enable QSPI mode"
|
||||||
default n
|
default n
|
||||||
|
|
|
@ -6,6 +6,9 @@ src = ['spi_core.c', 'spi_dev.c']
|
||||||
CPPPATH = [cwd, cwd + '/../include']
|
CPPPATH = [cwd, cwd + '/../include']
|
||||||
LOCAL_CFLAGS = ''
|
LOCAL_CFLAGS = ''
|
||||||
|
|
||||||
|
if GetDepend('RT_USING_SPI_BITOPS'):
|
||||||
|
src += ['spi-bit-ops.c']
|
||||||
|
|
||||||
if GetDepend('RT_USING_QSPI'):
|
if GetDepend('RT_USING_QSPI'):
|
||||||
src += ['qspi_core.c']
|
src += ['qspi_core.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);
|
||||||
|
}
|
|
@ -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
|
Loading…
Reference in New Issue