20231001增加了端口时钟的配置,在drv_soft_spi.h直接选好端口就配置好时钟了,不需要另外再打开,已经用GD32F407测试过没有问题。
#include <rtthread.h>
#include "gd32f4xx.h"
#include <rtdbg.h>
#include "board.h"
#include <rtdevice.h>
#ifdef RT_USING_SPI
#ifdef BSP_USING_SOFT_SPI
#include "drivers/drv_soft_spi.h"
#include <string.h>
#define LOG_TAG "drv.spisoft"
#if !defined(BSP_USING_SOFT_SPI0) && !defined(BSP_USING_SOFT_SPI1) && !defined(BSP_USING_SOFT_SPI2) && !defined(BSP_USING_SOFT_SPI3)
#error "Please define at least one BSP_USING_SOFT_SPIx"
/* this driver can be disabled at menuconfig → RT-Thread Components → Device Drivers */
#endif
enum{
#ifdef BSP_USING_SOFT_SPI
SOFT_SPI1_INDEX,
#endif
};
/*配置软件模拟SPI端口*/
static struct GD32_soft_spi_config soft_spi_config[] ={
#ifdef BSP_USING_SOFT_SPI0
SOFT_SPI0_BUS_CONFIG,
#endif
#ifdef BSP_USING_SOFT_SPI1
SOFT_SPI1_BUS_CONFIG,
#endif
#ifdef BSP_USING_SOFT_SPI2
SOFT_SPI2_BUS_CONFIG,
#endif
#ifdef BSP_USING_SOFT_SPI3
SOFT_SPI3_BUS_CONFIG,
#endif
};
static struct GD32_soft_spi soft_spi_bus_obj[sizeof(soft_spi_config) / sizeof(soft_spi_config[0])];// = {0};
static rt_err_t GD32_spi_init(struct GD32_soft_spi *spi_drv, struct rt_spi_configuration *cfg){
RT_ASSERT(spi_drv != RT_NULL);
RT_ASSERT(cfg != RT_NULL);
//mode = master
if (cfg->mode & RT_SPI_SLAVE){
return RT_EIO;
}
else
spi_drv->mode = RT_SPI_MASTER;
if (cfg->mode & RT_SPI_3WIRE){
return RT_EIO;
}
if (cfg->data_width == 8 || cfg->data_width == 16)
spi_drv->data_width = cfg->data_width;
else{
return RT_EIO;
}
if (cfg->mode & RT_SPI_CPHA){
spi_drv->cpha = 1;
}
else{
spi_drv->cpha = 0;
}
if (cfg->mode & RT_SPI_CPOL){
spi_drv->cpol = 1;
}
else{
spi_drv->cpol = 0;
}
if (cfg->mode & RT_SPI_NO_CS){
}
else{
}
if (cfg->max_hz >= 1200000){
spi_drv->spi_delay = 0;
}else if (cfg->max_hz >= 1000000){
spi_drv->spi_delay = 8;
}else if (cfg->max_hz >= 830000){
spi_drv->spi_delay = 16;
}
LOG_D("SPI limiting freq: %d, BaudRatePrescaler: %d",
cfg->max_hz,
spi_drv->max_hz);
if (cfg->mode & RT_SPI_MSB){
spi_drv->msb = 1;
}
else{
spi_drv->msb = 0;
}
//init spi pin
#if defined SOC_SERIES_GD32F4xx
gpio_mode_set(spi_drv->config->mosi_pin.GPIOx,GPIO_MODE_OUTPUT,GPIO_PUPD_NONE,spi_drv->config->mosi_pin.GPIO_Pin);
gpio_output_options_set(spi_drv->config->mosi_pin.GPIOx,GPIO_OTYPE_PP,GPIO_OSPEED_50MHZ,spi_drv->config->mosi_pin.GPIO_Pin);
gpio_bit_reset(spi_drv->config->mosi_pin.GPIOx,spi_drv->config->mosi_pin.GPIO_Pin);
gpio_mode_set(spi_drv->config->miso_pin.GPIOx,GPIO_MODE_INPUT,GPIO_PUPD_PULLUP,spi_drv->config->miso_pin.GPIO_Pin);
gpio_mode_set(spi_drv->config->sclk_pin.GPIOx,GPIO_MODE_OUTPUT,GPIO_PUPD_NONE,spi_drv->config->sclk_pin.GPIO_Pin);
gpio_output_options_set(spi_drv->config->sclk_pin.GPIOx,GPIO_OTYPE_PP,GPIO_OSPEED_50MHZ,spi_drv->config->sclk_pin.GPIO_Pin);
#else
gpio_init(spi_drv->config->mosi_pin.GPIOx,GPIO_MODE_OUT_PP,GPIO_OSPEED_50MHZ,spi_drv->config->mosi_pin.GPIO_Pin);
gpio_bit_reset(spi_drv->config->mosi_pin.GPIOx,spi_drv->config->mosi_pin.GPIO_Pin);
gpio_init(spi_drv->config->miso_pin.GPIOx,GPIO_MODE_IPU,GPIO_OSPEED_50MHZ,spi_drv->config->miso_pin.GPIO_Pin);
gpio_init(spi_drv->config->sclk_pin.GPIOx,GPIO_MODE_OUT_PP,GPIO_OSPEED_50MHZ,spi_drv->config->sclk_pin.GPIO_Pin);
#endif
if(spi_drv->cpol)
gpio_bit_set(spi_drv->config->sclk_pin.GPIOx,spi_drv->config->sclk_pin.GPIO_Pin);
else
gpio_bit_reset(spi_drv->config->sclk_pin.GPIOx,spi_drv->config->sclk_pin.GPIO_Pin);
LOG_D("%s init done", spi_drv->config->bus_name);
return RT_EOK;
}
static inline void spi_delay(uint8_t time){
switch(time){
case 16:__nop();
case 15:__nop();
case 14:__nop();
case 13:__nop();
case 12:__nop();
case 11:__nop();
case 10:__nop();
case 9:__nop();
case 8:__nop();
case 7:__nop();
case 6:__nop();
case 5:__nop();
case 4:__nop();
case 3:__nop();
case 2:__nop();
case 1:__nop();
default:
break;
}
}
void GPIO_ToggleBit(uint32_t gpio_periph, uint32_t pin)//引脚反转函数
{
if((uint32_t)RESET !=(GPIO_OCTL(gpio_periph)&(pin)))
{
GPIO_BC(gpio_periph) = (uint32_t)pin;
}
else
{
GPIO_BOP(gpio_periph) = (uint32_t)pin;
}
}
/*模拟SPI读写*/
static rt_uint32_t soft_spi_read_write_bytes(
struct GD32_soft_spi *spi_drv,
uint8_t* send_buff,
uint8_t* recv_buff,
uint32_t len)
{
uint32_t dataIndex = 0;
uint8_t time = 0;
for(uint32_t i = 0; i<len; i++){
if(spi_drv->cpha)GPIO_ToggleBit(spi_drv->config->sclk_pin.GPIOx, spi_drv->config->sclk_pin.GPIO_Pin);//CPHA=1 时钟起始电平
if(spi_drv->data_width == 16)time = 1;else time = 0;
do{
for(uint8_t j = 0; j < 8; j++)
{
if ((send_buff[dataIndex] & 0x80) != 0)gpio_bit_set(spi_drv->config->mosi_pin.GPIOx,spi_drv->config->mosi_pin.GPIO_Pin);
else gpio_bit_reset(spi_drv->config->mosi_pin.GPIOx,spi_drv->config->mosi_pin.GPIO_Pin);
send_buff[dataIndex] <<= 1;
spi_delay(spi_drv->spi_delay);
GPIO_ToggleBit(spi_drv->config->sclk_pin.GPIOx, spi_drv->config->sclk_pin.GPIO_Pin);//HAL_GPIO_TogglePin
recv_buff[dataIndex] <<= 1;
if (gpio_input_bit_get(spi_drv->config->miso_pin.GPIOx, spi_drv->config->miso_pin.GPIO_Pin))
recv_buff[dataIndex] |= 0x01;
spi_delay(spi_drv->spi_delay);
//if(time != 0 || j != 7)//20230928
GPIO_ToggleBit(spi_drv->config->sclk_pin.GPIOx, spi_drv->config->sclk_pin.GPIO_Pin);//HAL_GPIO_TogglePin
}
dataIndex++;
}while(time--);
spi_delay(spi_drv->spi_delay);
}
return len;
}
/*模拟SPI读*/
static rt_uint32_t soft_spi_read_bytes(
struct GD32_soft_spi *spi_drv,
uint8_t* recv_buff,
uint32_t len)
{
uint8_t send_buff = spi_drv->dummy_data;
uint32_t dataIndex = 0;
uint8_t time = 0;
for(uint32_t i = 0; i<len; i++){
if(spi_drv->cpha)GPIO_ToggleBit(spi_drv->config->sclk_pin.GPIOx, spi_drv->config->sclk_pin.GPIO_Pin);//CPHA=1
if(spi_drv->data_width == 16)time = 1;else time = 0;
do{
for(uint8_t j = 0; j < 8; j++){
if ((send_buff & 0x80) != 0){
gpio_bit_set(spi_drv->config->mosi_pin.GPIOx,spi_drv->config->mosi_pin.GPIO_Pin);
}else{
gpio_bit_reset(spi_drv->config->mosi_pin.GPIOx,spi_drv->config->mosi_pin.GPIO_Pin);
}
send_buff <<= 1;
spi_delay(spi_drv->spi_delay);
GPIO_ToggleBit(spi_drv->config->sclk_pin.GPIOx, spi_drv->config->sclk_pin.GPIO_Pin);
recv_buff[dataIndex] <<= 1;
if (gpio_input_bit_get(spi_drv->config->miso_pin.GPIOx, spi_drv->config->miso_pin.GPIO_Pin))
recv_buff[dataIndex] |= 0x01;
spi_delay(spi_drv->spi_delay);
//if(time != 0 || j != 7)//20230928
{
GPIO_ToggleBit(spi_drv->config->sclk_pin.GPIOx, spi_drv->config->sclk_pin.GPIO_Pin);
}
}
dataIndex++;
}while(time--);
spi_delay(spi_drv->spi_delay);
}
return len;
}
static rt_uint32_t soft_spi_write_bytes(struct GD32_soft_spi *spi_drv, uint8_t* send_buff, uint32_t len){
uint8_t recv_buff = 0;
uint32_t dataIndex = 0;
uint8_t time = 0;
for(uint32_t i = 0; i<len; i++){
if(spi_drv->cpha){ //CPHA=1
GPIO_ToggleBit(spi_drv->config->sclk_pin.GPIOx, spi_drv->config->sclk_pin.GPIO_Pin);
}
if(spi_drv->data_width == 16)
time = 1;else time = 0;
do{
for(uint8_t j = 0; j < 8; j++){
if ((send_buff[dataIndex] & 0x80) != 0){
gpio_bit_set(spi_drv->config->mosi_pin.GPIOx,spi_drv->config->mosi_pin.GPIO_Pin);
}else{
gpio_bit_reset(spi_drv->config->mosi_pin.GPIOx,spi_drv->config->mosi_pin.GPIO_Pin);
}
send_buff[dataIndex] <<= 1;
spi_delay(spi_drv->spi_delay);
GPIO_ToggleBit(spi_drv->config->sclk_pin.GPIOx, spi_drv->config->sclk_pin.GPIO_Pin);
recv_buff <<= 1;
if (gpio_input_bit_get(spi_drv->config->miso_pin.GPIOx, spi_drv->config->miso_pin.GPIO_Pin))
recv_buff |= 0x01;
spi_delay(spi_drv->spi_delay);
//if(time != 0 || j != 7)//20230928
{
GPIO_ToggleBit(spi_drv->config->sclk_pin.GPIOx, spi_drv->config->sclk_pin.GPIO_Pin);
}
}
dataIndex++;
}while(time--);
spi_delay(spi_drv->spi_delay);
}
return len;
}
rt_uint32_t spixfer(struct rt_spi_device *device, struct rt_spi_message *message){
rt_uint32_t state;
rt_size_t message_length;
rt_uint8_t *recv_buf;
const rt_uint8_t *send_buf;
RT_ASSERT(device != RT_NULL);
RT_ASSERT(device->bus != RT_NULL);
RT_ASSERT(device->bus->parent.user_data != RT_NULL);
RT_ASSERT(message != RT_NULL);
struct GD32_soft_spi *spi_drv = rt_container_of(device->bus, struct GD32_soft_spi, spi_bus);
struct GD32_soft_spi_pin *cs = device->parent.user_data;
if (message->cs_take){
gpio_bit_reset(cs->GPIOx, cs->GPIO_Pin);
}
LOG_D("%s transfer prepare and start", spi_drv->config->bus_name);
LOG_D("%s sendbuf: %X, recvbuf: %X, length: %d",
spi_drv->config->bus_name,
(uint32_t)message->send_buf,
(uint32_t)message->recv_buf, message->length);
message_length = message->length;
recv_buf = message->recv_buf;
send_buf = message->send_buf;
if(message_length){
if (message->send_buf && message->recv_buf){
state = soft_spi_read_write_bytes(spi_drv, (uint8_t *)send_buf, (uint8_t *)recv_buf, message_length);
}
else if (message->send_buf){
state = soft_spi_write_bytes(spi_drv, (uint8_t *)send_buf, message_length);
}
else{
memset((uint8_t *)recv_buf, 0xff, message_length);
state = soft_spi_read_bytes(spi_drv, (uint8_t *)recv_buf, message_length);
}
if (state != message_length){
LOG_I("spi transfer error : %d", state);
message->length = 0;
}
else{
LOG_D("%s transfer done", spi_drv->config->bus_name);
}
}
if (message->cs_release){
gpio_bit_set(cs->GPIOx, cs->GPIO_Pin);
}
return message->length;
}
//SPI总线设置
rt_err_t rt_soft_spi_configure(struct rt_spi_device *device,
struct rt_spi_configuration *configuration){
RT_ASSERT(device != RT_NULL);
RT_ASSERT(configuration != RT_NULL);
struct GD32_soft_spi *spi_drv = rt_container_of(device->bus, struct GD32_soft_spi, spi_bus);
spi_drv->cfg = configuration;
return GD32_spi_init(spi_drv, configuration);
}
static const struct rt_spi_ops GD32_spi_ops ={
.configure = rt_soft_spi_configure,
.xfer = spixfer,
};
//初始化SPI总线端口 已调用
static int rt_soft_spi_bus_init(void){
rt_err_t result;
for (int i = 0; i < sizeof(soft_spi_config) / sizeof(soft_spi_config[0]); i++){
soft_spi_bus_obj[i].config = &soft_spi_config[i];
soft_spi_bus_obj[i].spi_bus.parent.user_data = &soft_spi_config[i];
rcu_periph_clock_enable(soft_spi_bus_obj[i].config->mosi_pin.RCU_GPIOx);//20230930开启mosi_pin端口时钟
rcu_periph_clock_enable(soft_spi_bus_obj[i].config->miso_pin.RCU_GPIOx);//20230930开启miso_pin端口时钟
rcu_periph_clock_enable(soft_spi_bus_obj[i].config->sclk_pin.RCU_GPIOx);//20230930开启sclk_pin端口时钟
result = rt_spi_bus_register(&soft_spi_bus_obj[i].spi_bus, soft_spi_config[i].bus_name, &GD32_spi_ops);
RT_ASSERT(result == RT_EOK);
LOG_D("%s bus init done", spi_config[i].bus_name);
}
return result;
}
/**
* Attach the spi device to SPI bus, this function must be used after initialization.
*/ //rt_soft_spi_device_attach("spi_s", "CBM53D24", GPIOC , GPIO_PIN_4);
rt_err_t rt_soft_spi_device_attach(const char *bus_name, const char *device_name, uint32_t cs_gpiox, uint16_t cs_gpio_pin){
RT_ASSERT(bus_name != RT_NULL);
RT_ASSERT(device_name != RT_NULL);
rt_err_t result;
struct rt_spi_device *spi_device;
struct GD32_soft_spi_pin *cs_pin;
/* initialize the cs pin && select the slave*/
#if defined SOC_SERIES_GD32F4xx
gpio_mode_set(cs_gpiox,GPIO_MODE_OUTPUT,GPIO_PUPD_PULLUP,cs_gpio_pin);
gpio_output_options_set(cs_gpiox,GPIO_OTYPE_PP,GPIO_OSPEED_50MHZ,cs_gpio_pin);//配置CS片选端口
gpio_bit_set(cs_gpiox, cs_gpio_pin);
#else
gpio_init(cs_gpiox,GPIO_MODE_OUT_PP,GPIO_OSPEED_50MHZ,cs_gpio_pin);// 配置CS片选端口
#endif
/* attach the device to spi bus*/
spi_device = (struct rt_spi_device *)rt_malloc(sizeof(struct rt_spi_device));
RT_ASSERT(spi_device != RT_NULL);
cs_pin = (struct GD32_soft_spi_pin *)rt_malloc(sizeof(struct GD32_soft_spi_pin));
RT_ASSERT(cs_pin != RT_NULL);
cs_pin->GPIOx = cs_gpiox;
cs_pin->GPIO_Pin = cs_gpio_pin;
rcu_periph_clock_enable(cs_pin->RCU_GPIOx);//20230930开启cs_gpio_pin时钟
result = rt_spi_bus_attach_device(spi_device, device_name, bus_name, (void *)cs_pin);
if (result != RT_EOK){
LOG_E("%s attach to %s faild, %d\n", device_name, bus_name, result);
}
RT_ASSERT(result == RT_EOK);
LOG_D("%s attach to %s done", device_name, bus_name);
return result;
}
int rt_soft_spi_init(void){
return rt_soft_spi_bus_init();//注册SPI总线
}
INIT_BOARD_EXPORT(rt_soft_spi_init);
#endif
#endif /* RT_USING_SPI */
/*****************************************以下是drv_soft_spi.h头文件**************************************************************************************************************/
#ifndef __DRV_SOFT_SPI_H_
#define __DRV_SOFT_SPI_H_
#include <rtthread.h>
#include "rtdevice.h"
#include <rthw.h>
#include "gd32f4xx.h"
rt_uint32_t spixfer(struct rt_spi_device *device, struct rt_spi_message *message);
rt_err_t rt_soft_spi_device_attach(const char *bus_name, const char *device_name, uint32_t cs_gpiox, uint16_t cs_gpio_pin);
struct GD32_soft_spi_pin
{
uint32_t GPIOx;
uint16_t GPIO_Pin;
rcu_periph_enum RCU_GPIOx;//20230930
};
struct GD32_soft_spi_config
{
struct GD32_soft_spi_pin mosi_pin;
struct GD32_soft_spi_pin miso_pin;
struct GD32_soft_spi_pin sclk_pin;
char *bus_name;
};
struct GD32_soft_spi_device
{
rt_uint8_t cs_pin;
char *bus_name;
char *device_name;
};
/* GD32 soft spi dirver class */
struct GD32_soft_spi
{
uint8_t mode;//
uint8_t cpha;
uint8_t cpol;
uint8_t data_width;//数据位长度
uint8_t msb;
uint16_t dummy_data;
uint32_t spi_delay;
struct GD32_soft_spi_config *config;//引脚设置
struct rt_spi_configuration *cfg;
struct rt_spi_bus spi_bus;
};
rt_err_t rt_soft_spi_configure(struct rt_spi_device *device,
struct rt_spi_configuration *configuration);
rt_uint32_t soft_spi_write_bytes(struct GD32_soft_spi *spi_drv, uint8_t* send_buff, uint32_t len);
/*根据实际配置相应引脚*/
#ifdef BSP_USING_SOFT_SPI0
#define SOFT_SPI0_BUS_CONFIG \
{ \
GPIOA,GPIO_PIN_7,RCU_GPIOA,/*MOSI*/ \
GPIOA,GPIO_PIN_6,RCU_GPIOA,/*MISO*/ \
GPIOA,GPIO_PIN_5,RCU_GPIOA,/*SCK*/ \
"sspi0" \
}
#endif /* BSP_USING_SOFT_SPI0 */
#ifdef BSP_USING_SOFT_SPI1
#define SOFT_SPI1_BUS_CONFIG \
{ \
GPIOD,GPIO_PIN_5,RCU_GPIOD,/*MOSI*/ \
GPIOD,GPIO_PIN_4,RCU_GPIOD,/*MISO*/ \
GPIOD,GPIO_PIN_6,RCU_GPIOD,/*SCK*/ \
"sspi1" \
}
#endif /* BSP_USING_SOFT_SPI1 */
#ifdef BSP_USING_SOFT_SPI2
#define SOFT_SPI2_BUS_CONFIG \
{ \
GPIOB,GPIO_PIN_0,RCU_GPIOB,/*MOSI*/ \
GPIOB,GPIO_PIN_1,RCU_GPIOB,/*MISO*/ \
GPIOC,GPIO_PIN_5,RCU_GPIOC,/*SCK*/ \
"sspi2" \
}
#endif /* BSP_USING_SOFT_SPI2 */
#ifdef BSP_USING_SOFT_SPI3
#define SOFT_SPI3_BUS_CONFIG \
{ \
GPIOB,GPIO_PIN_0,RCU_GPIOB,/*MOSI*/ \
GPIOB,GPIO_PIN_1,RCU_GPIOB,/*MISO*/ \
GPIOC,GPIO_PIN_5,RCU_GPIOC,/*SCK*/ \
"sspi3" \
}
#endif /* BSP_USING_SOFT_SPI3 */
#endif /*__DRV_SOFT_SPI_H_ */