sdk 目前还不支持 spi,没有 spi 就失去了很多乐趣,如 easyflash、spi 的屏幕,蓝讯的这次活动我接到了模拟 spi 的任务,下面介绍如何写 rt-thread 的设备驱动层的驱动。(rt-thread的设备 I/O 模型有设备管理层、设备驱动框架层、设备驱动层),我写过一篇使用 timer 的,就属于最接近用户那一层-设备管理层,我们调用 rt_device_find 根据名称查找句柄,之后根据句柄执行 rt_device_read、rt_device_write、rt_device_control 语句完成与底层设备的交互,而最底层的 timer 已经由中科蓝讯的工程师完成了。而这次的模拟 spi 则是写设备驱动层。
设备驱动层的编写有两步:
实现 spi 的驱动程序(模拟 spi 主要通过 io 口模拟 spi 的时序)将裸机程序按 rt-thread 的设备驱动框架封装(主要是自己写的函数原型与 rt-thread 的接口对应上)
在 library 下添加 drv_soft_spi.c 和 drv_soft_spi.h
3.1 drv_soft_spi.c
/*
* Change Logs:
* Date Author Notes
* 2021-06-03 qwz first version
*/
#include "board.h"
#ifdef RT_USING_SPI
#ifdef RT_SPI_SOFT
#include "spi.h"
#include "drv_soft_spi.h"
#include
#define DRV_DEBUG
#define LOG_TAG "drv.spisoft"
#include
enum{
#ifdef BSP_USING_SOFT_SPI1
SOFT_SPI1_INDEX,
#endif
};
//PB2 10 ;PE5 18;PE6 19;PB1 9;
#define SOFT_SPI1_BUS_CONFIG { \
.mosi_pin = 18, \
.miso_pin = 10, \
.sclk_pin = 9, \
.bus_name = "spi0", \ }
static struct ab32_soft_spi_config soft_spi_config[] ={
#ifdef BSP_USING_SOFT_SPI1
SOFT_SPI1_BUS_CONFIG,
#endif
};
static struct ab32_soft_spi soft_spi_bus_obj[sizeof(soft_spi_config) / sizeof(soft_spi_config[0])] = {0};
static rt_err_t ab32_spi_init(struct ab32_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;
}
else {
spi_drv->spi_delay = 24;
}
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;
}
rt_pin_mode(spi_drv->config->mosi_pin,PIN_MODE_OUTPUT_OD);
rt_pin_write(spi_drv->config->mosi_pin,PIN_HIGH);
rt_pin_mode(spi_drv->config->miso_pin,PIN_MODE_INPUT_PULLDOWN);
rt_pin_mode(spi_drv->config->sclk_pin,PIN_MODE_OUTPUT_OD);
if(spi_drv->cpol)
rt_pin_write(spi_drv->config->sclk_pin,PIN_HIGH);
else
rt_pin_write(spi_drv->config->sclk_pin,PIN_LOW);
LOG_D("%s init done", spi_drv->config->bus_name);
return RT_EOK;
}
static inline void spi_delay(rt_uint32_t us){
rt_thread_mdelay(us);
}
static rt_uint32_t soft_spi_read_write_bytes(struct ab32_soft_spi *spi_drv, rt_uint8_t* send_buff,
rt_uint8_t* recv_buff, rt_uint32_t len){
rt_uint8_t dataIndex = 0;
rt_uint8_t time = 1;
for(rt_uint32_t i = 0; icpha){ //CPHA=1
if(rt_pin_read(spi_drv->config->sclk_pin))
{
rt_pin_write(spi_drv->config->sclk_pin,PIN_LOW);
}
else {
rt_pin_write(spi_drv->config->sclk_pin,PIN_HIGH);
} }
if(spi_drv->data_width == 16)
time = 2;
do{
for(rt_uint8_t j = 0; j < 8; j++){
if ((send_buff[dataIndex] & 0x80) != 0){
rt_pin_write(spi_drv->config->mosi_pin,PIN_HIGH);
}else{
rt_pin_write(spi_drv->config->mosi_pin,PIN_LOW);
}
send_buff[dataIndex] <<= 1;
spi_delay(spi_drv->spi_delay);
if(rt_pin_read(spi_drv->config->sclk_pin))
{
rt_pin_write(spi_drv->config->sclk_pin,PIN_LOW);
}
else {
rt_pin_write(spi_drv->config->sclk_pin,PIN_HIGH);
}
recv_buff[dataIndex] <<= 1;
if (rt_pin_read(spi_drv->config->miso_pin))
recv_buff[dataIndex] |= 0x01;
spi_delay(spi_drv->spi_delay);
if(time != 0 || j != 7){
if(rt_pin_read(spi_drv->config->sclk_pin))
{
rt_pin_write(spi_drv->config->sclk_pin,PIN_LOW);
}
else {
rt_pin_write(spi_drv->config->sclk_pin,PIN_HIGH);
} } }
dataIndex++;
}while((--time)==1);
time = 1;
spi_delay(spi_drv->spi_delay);
}
return len;
}
static rt_uint32_t soft_spi_read_bytes(struct ab32_soft_spi *spi_drv, rt_uint8_t* recv_buff, rt_uint32_t
len){
rt_uint8_t send_buff = spi_drv->dummy_data;
rt_uint32_t dataIndex = 0;
rt_uint8_t time = 1;
if(spi_drv->cpha){ //CPHA=1
if(rt_pin_read(spi_drv->config->sclk_pin))
{
rt_pin_write(spi_drv->config->sclk_pin,PIN_LOW);
}
else {
rt_pin_write(spi_drv->config->sclk_pin,PIN_HIGH);
} }
for(rt_uint32_t i = 0; idata_width == 16)
time = 2;
do{
for(rt_uint8_t j = 0; j < 8; j++){
if ((send_buff & 0x80) != 0){
rt_pin_write(spi_drv->config->mosi_pin,PIN_HIGH);
}else{
rt_pin_write(spi_drv->config->mosi_pin,PIN_LOW);
}
send_buff <<= 1;
spi_delay(spi_drv->spi_delay);
if(rt_pin_read(spi_drv->config->sclk_pin))
{
rt_pin_write(spi_drv->config->sclk_pin,PIN_LOW);
}
else {
rt_pin_write(spi_drv->config->sclk_pin,PIN_HIGH);
}
*recv_buff <<= 1;
if (rt_pin_read(spi_drv->config->miso_pin))
{
*recv_buff |= 0x01;
}
else
{
*recv_buff &= 0xfe;
}
spi_delay(spi_drv->spi_delay);
if(time != 0 || j != 7){
if(rt_pin_read(spi_drv->config->sclk_pin))
{
rt_pin_write(spi_drv->config->sclk_pin,PIN_LOW);
}
else {
rt_pin_write(spi_drv->config->sclk_pin,PIN_HIGH);
} } }
recv_buff ++;
dataIndex++;
}while((--time)==1);
time = 1;
spi_delay(spi_drv->spi_delay);
LOG_D("DONE ONE BYTE %d",dataIndex);
LOG_D("%d",spi_drv->spi_delay);
}
return len;
}
static rt_uint32_t soft_spi_write_bytes(struct ab32_soft_spi *spi_drv, rt_uint8_t* send_buff, rt_uint32_t
len){
rt_uint8_t recv_buff = 0;
rt_uint32_t dataIndex = 0;
rt_uint8_t time = 1;
LOG_D("%x",send_buff[0]);
if(spi_drv->cpha){ //CPHA=1
if(rt_pin_read(spi_drv->config->sclk_pin))
{
rt_pin_write(spi_drv->config->sclk_pin,PIN_LOW);
}
else {
rt_pin_write(spi_drv->config->sclk_pin,PIN_HIGH);
} }
for(uint32_t i = 0; idata_width == 16)
time = 2;
do{
for(rt_uint8_t j = 0; j < 8; j++){
if ((send_buff[dataIndex] & 0x80) != 0){
rt_pin_write(spi_drv->config->mosi_pin,PIN_HIGH);
LOG_D("PIN_HIGH");
}else{
rt_pin_write(spi_drv->config->mosi_pin,PIN_LOW);
LOG_D("PIN_LOW");
}
send_buff[dataIndex] <<= 1;
spi_delay(spi_drv->spi_delay);
if(rt_pin_read(spi_drv->config->sclk_pin))
{
rt_pin_write(spi_drv->config->sclk_pin,PIN_LOW);
}
else {
rt_pin_write(spi_drv->config->sclk_pin,PIN_HIGH);
}
recv_buff <<= 1;
if (rt_pin_read(spi_drv->config->miso_pin))
recv_buff |= 0x01;
spi_delay(spi_drv->spi_delay);
if(time != 0 || j != 7){
if(rt_pin_read(spi_drv->config->sclk_pin))
{
rt_pin_write(spi_drv->config->sclk_pin,PIN_LOW);
}
else {
rt_pin_write(spi_drv->config->sclk_pin,PIN_HIGH);
} } }
dataIndex++;
}while((--time)==1);
time = 1;
spi_delay(spi_drv->spi_delay);
}
return len;
}
static 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_uint8_t pin = rt_pin_get("PE.6");
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 ab32_soft_spi *spi_drv = rt_container_of(device->bus, struct ab32_soft_spi, spi_bus);
struct ab32_soft_spi_pin *cs = device->parent.user_data;
if (message->cs_take){
rt_pin_write(cs->GPIO_Pin,PIN_LOW);
}
LOG_D("%s transfer prepare and start", spi_drv->config->bus_name);
LOG_D("%s sendbuf: %02x, recvbuf: %02x, length: %d",
spi_drv->config->bus_name,
(message->send_buf),
((rt_uint8_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, (rt_uint8_t *)send_buf, (rt_uint8_t *)recv_buf,
message_length);
LOG_D("soft_spi_read_write_bytes");
}
else if (message->send_buf){
state = soft_spi_write_bytes(spi_drv, (rt_uint8_t *)send_buf, message_length);
LOG_D("soft_spi_write_bytes");
}
else{
memset((rt_uint8_t *)recv_buf, 0x00, message_length);
state = soft_spi_read_bytes(spi_drv, (rt_uint8_t *)recv_buf, message_length);
LOG_D("soft_spi_read_bytes");
}
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){
rt_pin_write(cs->GPIO_Pin,PIN_HIGH);
}
return message->length;
}
static rt_err_t spi_configure(struct rt_spi_device *device,
struct rt_spi_configuration *configuration){
RT_ASSERT(device != RT_NULL);
RT_ASSERT(configuration != RT_NULL);
struct ab32_soft_spi *spi_drv = rt_container_of(device->bus, struct ab32_soft_spi, spi_bus);
spi_drv->cfg = configuration;
return ab32_spi_init(spi_drv, configuration);
}
static const struct rt_spi_ops ab32_spi_ops ={
.configure = spi_configure,
.xfer = spixfer,
};
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];
result = rt_spi_bus_register(&soft_spi_bus_obj[i].spi_bus, soft_spi_config[i].bus_name,
&ab32_spi_ops);
RT_ASSERT(result == RT_EOK);
LOG_D("%s bus init done", soft_spi_config[i].bus_name);
}
return result;
}
/**
* Attach the spi device to SPI bus, this function must be used after initialization.
*/
rt_err_t rt_soft_spi_device_attach(const char *bus_name, const char *device_name, hal_sfr_t cs_gpiox,
rt_uint8_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 ab32_soft_spi_pin *cs_pin;
/* 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 ab32_soft_spi_pin *)rt_malloc(sizeof(struct ab32_soft_spi_pin));
RT_ASSERT(cs_pin != RT_NULL);
cs_pin->GPIOx = cs_gpiox;
cs_pin->GPIO_Pin = cs_gpio_pin;
rt_pin_mode(cs_pin->GPIO_Pin, PIN_MODE_OUTPUT);
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();
}
INIT_BOARD_EXPORT(rt_soft_spi_init);
#endif
#endif /* RT_USING_SPI */;>;>;>
审核编辑 黄昊宇
-
嵌入式
+关注
关注
5076文章
19045浏览量
303860 -
SPI
+关注
关注
17文章
1702浏览量
91385 -
RT
+关注
关注
0文章
73浏览量
40012
发布评论请先 登录
相关推荐
评论