rt-thread-official/bsp/gd32303e-eval/drivers/drv_soft_spi.c

304 lines
7.4 KiB
C

/*
* Copyright (c) 2006-2022, 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