Rtthread软件SPI GD32

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_ */

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值