Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
AB32VG1
RT-Thread Studio
设备驱动框架
【中科蓝讯】AB32VG1测评模拟SPI(驱动移植心得)
发布于 2021-03-20 17:16:18 浏览:2728
订阅该版
[tocm] 本次接到的测评任务是测评SPI,久经波折,总算将这个驱动怼出来了,经过这段时间的摸索,初步学习到了如何去写rtthread的底层驱动。 项目是在 @yushigengyu [stm32模拟spi设备驱动]的基础上修改的,主要改动是更换了与ab32vg1相关的spi底层实现。(https://club.rt-thread.org/ask/question/424544.html) 本次测评的目的: - 介绍模拟spi驱动移植的过程 - 测试ab32vg1的工作稳定性 # 一、模拟spi驱动移植 ## 1.1 rtthread设备驱动框架和本次移植思路 ### 1.1.1 spi驱动框架 ![image.png](https://oss-club.rt-thread.org/uploads/20210320/481aba3b8a2441ce568a75dcabace503.png) ![image.png](https://oss-club.rt-thread.org/uploads/20210320/f86ef63d5adb46c9a884649f31e4f00d.png) ### 1.1.2 移植思路 看了一遍 @yushigengyu 大神的代码,程序最后面的代码逐层调用前面的代码,最后一个函数的挂载操作将spi的配置函数和传输函数的地址给了rtt的spi设备管理器,由此这一页内的函数都由rtthread操作系统管理。我的思路是模仿大神的思路去实现ab32vg1的模拟spi驱动。 ## 1.2 核心的几个移植步骤和代码 ### 1.2.1 在rtt studio使能spi设备驱动,在生成的工程的board.h添加模拟spi需要的宏定义 ```c #define RT_SPI_SOFT //模拟spi使能宏 #define BSP_USING_SOFT_SPI1 //使能spi1 ``` ### 1.2.2 spi配置宏 模拟spi使用的三个引脚的引脚号和spi总线名称 ```c #define SOFT_SPI1_BUS_CONFIG { \ .mosi_pin = 18, \ .miso_pin = 10, \ .sclk_pin = 9, \ .bus_name = "spi0", \ } ``` ### 1.2.3 ab32_spi_init函数使用rtthread的pin驱动框架初始化模拟spi外设引脚。 ```c rt_pin_mode(spi_drv->config->mosi_pin,PIN_MODE_OUTPUT_OD); ``` ### 1.2.4 实现模拟spi延时函数 对ab32vg1的us延时不熟悉,用rtthread_mdelay函数延时。 ```c static inline void spi_delay(rt_uint32_t ms){ rt_thread_mdelay(ms); } ``` ### 1.2.5 模拟spi读写函数 spi的时钟sclk反转使用rtt的pin框架读取状态后进行翻转,用移位操作来完成一个字节的里每一位的传输,用rtt的pin框架读取引脚状态。 ```c 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"); } //LOG_D("j:%d",j); send_buff[dataIndex] <<= 1; spi_delay(spi_drv->spi_delay); //hal_gpio_toggle(GPIOAN, 2); 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){ //hal_gpio_toggle(GPIOAN, 2); 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); } } } ``` ### 1.2.6 spi注册 上面的1.2.1到1.2.6完成的工作都是为了注册做铺垫,在注册过程中,将前面的配置和读写操作注册给rtthread管理。 ```c 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; } ``` ### 1.2.7 spi驱动挂载 在rtthread中,attach是将一个设备加入到链表进行管理,此处的attach也相同。 ```c 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; } ``` # 二、测试 ## 2.1 测试代码 ```c #define W25Q_SPI_DEVICE_NAME "spi10" static void spi_w25q_sample(int argc,char *argv[]) { struct rt_spi_device *spi_dev_w25q; char name[RT_NAME_MAX]; //rt_uint8_t w25x_read_id = 0x9f; rt_uint8_t id[5]={0}; rt_soft_spi_device_attach("spi0","spi10",RT_NULL,8); rt_strncpy(name, W25Q_SPI_DEVICE_NAME, RT_NAME_MAX); //查找spi设备获取地址 spi_dev_w25q = (struct rt_spi_device *)rt_device_find(name); if(!spi_dev_w25q) { rt_kprintf("spi sample run failed\n"); } else { // rt_spi_send_then_recv(spi_dev_w25q, &w25x_read_id, 1, id, 5); // rt_kprintf("read id:%x%x\n",id[3],id[4]); //方式二 struct rt_spi_configuration cfg; cfg.data_width = 8; cfg.mode = RT_SPI_MASTER | RT_SPI_MSB | RT_SPI_MODE_3; cfg.max_hz = 1*1000; //1.92 M rt_spi_configure(spi_dev_w25q, &cfg); struct rt_spi_message msg1, msg2; while(1){ w25x_device_id[0] = 0x90; w25x_device_id[1] = 0x00; w25x_device_id[2] = 0x00; w25x_device_id[3] = 0x00; msg1.send_buf = w25x_device_id; msg1.recv_buf = RT_NULL; msg1.length = 4; msg1.cs_take = 1; msg1.cs_release = 0; msg1.next = &msg2; msg2.send_buf = RT_NULL; msg2.recv_buf = id; msg2.length = 5; msg2.cs_take = 0; msg2.cs_release = 1; msg2.next = RT_NULL; rt_spi_transfer_message(spi_dev_w25q, &msg1); rt_kprintf("use rt_spi_transfer_message() read w25q ID is:%02x %02x %02x %02x %02x\n", id[0],id[1],id[2],id[3], id[4]); rt_thread_mdelay(1000); } // rt_spi_transfer(spi_dev_w25q,&w25x_read_id,id,1); rt_kprintf("use rt_spi_transfer_message() read w25q ID is:%x%x\n", id[3], id[4]); } } MSH_CMD_EXPORT(spi_w25q_sample, spi w25q sample); ``` ## 2.2 测试结果 用逻辑分析仪可以看到,实现了spi通信读取w25q64的id号。 ![image.png](https://oss-club.rt-thread.org/uploads/20210320/6761fa95e24885b7bbe0b5c24f59aa4a.png) 在蓝讯的终端输入list_device也可以看到成功注册到了spi设备。 ![image.png](https://oss-club.rt-thread.org/uploads/20210320/a09942fff8425a3625114a8a88c1777a.png) # 三、存在的问题 ##3.1 用于spi传输的message会清零,特意定义成const类型还是会被清零,不知道是不是芯片内存问题。 ```c 用于send_buf的全局变量w25x_device_id rt_uint8_t w25x_device_id[4] = {0x90,0x00,0x00,0x00}; 第二次访问数据莫名其妙清零了。 ``` ## 3.2 spi读取函数需改进 目前用逻辑分析仪可以看到通信正常,w25q64响应了0x90命令,也返回了正确的id值。 # 四、心得体会 本次测评感谢群里小伙伴的鼓励,他们都觉得很简单,这个过程让我成长了不少,初始我只是一个只会使用rtthread软件包的人,经过这20多天的学习,逐渐对较底层的驱动有了了解,也对rtthread这个操作系统的架构有了更深刻的认识,本次分享主要是我在这段时间对驱动的一些认识。 最后感谢rtthread和中科蓝讯提供的平台。 # 五、项目地址 [码云地址](https://gitee.com/qinchang199/test_ab32vg1_softspi.git) # 六、参考链接 [yushigengyu分享的stm32模拟spi驱动](https://club.rt-thread.org/ask/question/424544.html)
3
条评论
默认排序
按发布时间排序
登录
注册新账号
关于作者
happycode999
这家伙很懒,什么也没写!
文章
28
回答
6
被采纳
0
关注TA
发私信
相关文章
1
rt_thread studio 啥时候能用呢
2
RT_Thread使用反馈帖子
3
RTT studio 下的 AT指令问题。
4
什么时候RTT Sdudio支持Ubuntu,Deepin和UOS操作系统
5
rt thread Studio 关于J-LINK下载问题
6
RT-Thread studio 调试设置问题
7
RTT-Studio 如何设置调试配置参数?
8
rt_thread studio 软件包配置
9
RT-Studio目前只能开发STM32的项目吗?
10
rtt studio 生成hex名字修改
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
USB
DMA
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
FAL
rt-smart
ESP8266
I2C_IIC
WIZnet_W5500
UART
ota在线升级
PWM
cubemx
freemodbus
flash
packages_软件包
BSP
潘多拉开发板_Pandora
定时器
ADC
GD32
flashDB
socket
中断
Debug
编译报错
SFUD
msh
rt_mq_消息队列_msg_queue
keil_MDK
ulog
MicroPython
C++_cpp
本月问答贡献
出出啊
1517
个答案
342
次被采纳
小小李sunny
1443
个答案
289
次被采纳
张世争
805
个答案
174
次被采纳
crystal266
547
个答案
161
次被采纳
whj467467222
1222
个答案
148
次被采纳
本月文章贡献
出出啊
1
篇文章
4
次点赞
小小李sunny
1
篇文章
1
次点赞
张世争
1
篇文章
1
次点赞
crystal266
2
篇文章
2
次点赞
whj467467222
2
篇文章
1
次点赞
回到
顶部
发布
问题
投诉
建议
回到
底部