0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

基于RT-Thread的SPI通讯

嵌入式应用开发 来源:嵌入式应用开发 作者:嵌入式应用开发 2022-08-22 09:28 次阅读

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


审核编辑 黄昊宇

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 嵌入式
    +关注

    关注

    4983

    文章

    18295

    浏览量

    288609
  • SPI
    SPI
    +关注

    关注

    17

    文章

    1615

    浏览量

    89674
  • RT
    RT
    +关注

    关注

    0

    文章

    73

    浏览量

    39859
收藏 人收藏

    评论

    相关推荐

    STM32L051上使用RT-Thread (四、串口通讯

    应用篇-在STM32L051上使用RT-Thread 第四篇,巧妙的使用信号量处理串口通讯
    的头像 发表于 06-28 10:59 4610次阅读
    STM32L051上使用<b class='flag-5'>RT-Thread</b> (四、串口<b class='flag-5'>通讯</b>)

    如何对RT-Thread内核有基本的了解?

    RT-Thread 的时钟管理以时钟节拍为基础,时钟节拍是 RT-Thread 操作系统中最小的时钟单位。
    的头像 发表于 07-19 10:12 6793次阅读
     如何对<b class='flag-5'>RT-Thread</b>内核有基本的了解?

    RT-Thread记录(二、RT-Thread内核启动流程)

    在前面我们RT-Thread Studio工程基础之上讲一讲RT-Thread内核启动流程.
    的头像 发表于 06-20 00:30 4426次阅读
    <b class='flag-5'>RT-Thread</b>记录(二、<b class='flag-5'>RT-Thread</b>内核启动流程)

    RT-Thread编程指南

    RT-Thread编程指南——RT-Thread开发组(2015-03-31)。RT-Thread做为国内有较大影响力的开源实时操作系统,本文是RT-Thread实时操作系统的编程指南
    发表于 11-26 16:06 0次下载

    RT-Thread开发,如何有效学习RT-Thread的五个步骤

    RT-Thread推出RT-Thread Inside战略开放RT-Thread开发平台授权合作,与硬件十万个为什么合作首次推出第一款RT-Inside的开发板——iBox物联网开发套
    的头像 发表于 09-25 09:55 3.4w次阅读
    <b class='flag-5'>RT-Thread</b>开发,如何有效学习<b class='flag-5'>RT-Thread</b>的五个步骤

    RT-ThreadSPI的细节内容

    作为通信协议的两大基础,IIC和SPI两者的应用都非常广泛,上一篇文章讲过了RTT上IIC的移植与实践。 《一步到位!教你RT-Thread上设备IIC驱动移植》 讲完IIC,自然少不了SPI
    的头像 发表于 09-30 15:35 3589次阅读
    <b class='flag-5'>RT-Thread</b>上<b class='flag-5'>SPI</b>的细节内容

    RT-Thread开源作品秀】基于RT-Thread的星务平台研究

    本作品为了验证星务软件在RT-Thread系统运行的可行性,底层是否能够驱动星务软件,同时扩展RT-Thread应用范围。ART-Pi作为卫星下位机,...
    发表于 01-25 18:26 5次下载
    【<b class='flag-5'>RT-Thread</b>开源作品秀】基于<b class='flag-5'>RT-Thread</b>的星务平台研究

    RT-Thread全球技术大会:Kconfig在RT-Thread中的工作机制

    RT-Thread全球技术大会:Kconfig在RT-Thread中的工作机制               审核编辑:彭静
    的头像 发表于 05-27 14:49 1240次阅读
    <b class='flag-5'>RT-Thread</b>全球技术大会:Kconfig在<b class='flag-5'>RT-Thread</b>中的工作机制

    RT-Thread全球技术大会:RT-Thread测试用例集合案例

    RT-Thread全球技术大会:RT-Thread测试用例集合案例           审核编辑:彭静
    的头像 发表于 05-27 16:34 1785次阅读
    <b class='flag-5'>RT-Thread</b>全球技术大会:<b class='flag-5'>RT-Thread</b>测试用例集合案例

    RT-Thread学习笔记 RT-Thread的架构概述

    RT-Thread 简介 作为一名 RTOS 的初学者,也许你对 RT-Thread 还比较陌生。然而,随着你的深入接触,你会逐渐发现 RT-Thread 的魅力和它相较于其他同类型 RTOS
    的头像 发表于 07-09 11:27 4004次阅读
    <b class='flag-5'>RT-Thread</b>学习笔记 <b class='flag-5'>RT-Thread</b>的架构概述

    RT-Thread文档_RT-Thread 简介

    RT-Thread文档_RT-Thread 简介
    发表于 02-22 18:22 5次下载
    <b class='flag-5'>RT-Thread</b>文档_<b class='flag-5'>RT-Thread</b> 简介

    RT-Thread文档_RT-Thread 潘多拉 STM32L475 上手指南

    RT-Thread文档_RT-Thread 潘多拉 STM32L475 上手指南
    发表于 02-22 18:23 7次下载
    <b class='flag-5'>RT-Thread</b>文档_<b class='flag-5'>RT-Thread</b> 潘多拉 STM32L475 上手指南

    RT-Thread文档_RT-Thread SMP 介绍与移植

    RT-Thread文档_RT-Thread SMP 介绍与移植
    发表于 02-22 18:31 7次下载
    <b class='flag-5'>RT-Thread</b>文档_<b class='flag-5'>RT-Thread</b> SMP 介绍与移植

    RT-Thread文档_SPI 设备

    RT-Thread文档_SPI 设备
    发表于 02-22 18:36 1次下载
    <b class='flag-5'>RT-Thread</b>文档_<b class='flag-5'>SPI</b> 设备

    基于RT-Thread Studio学习

    前期准备:从官网下载 RT-Thread Studio,弄个账号登陆,开启rt-thread学习之旅。
    的头像 发表于 05-15 11:00 2595次阅读
    基于<b class='flag-5'>RT-Thread</b> Studio学习