Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
RT-Thread
SPI
SPI + 桌面小时钟遇到的那些坑
发布于 2022-04-15 17:44:45 浏览:1280
订阅该版
[tocm] # 开发SPI + 桌面小时钟遇到的那些坑 - ## 前言 这一周做出来了一个桌面小时钟,跟着rtt官网的教程,很快就完成了使用esp8266获取NTP时间教程。不得不说,rtt的各种软件包真的好用,一步到位。接下来讲一讲开发过程中遇到的问题。 - ## 坑 - 显示图片花屏 如图。 ![花屏.jpg](https://oss-club.rt-thread.org/uploads/20220415/bf9c1dcc93685b2f13a3a3f6a4a59c49.jpg.webp) 一开始,我本来是想让屏幕显示一张图片的大小,但是发现显示出来有差不多2/3的部分花屏,一部分正常显示。上百度查了一下,有人说可能是屏幕硬件问题,但是我的刷屏函数是可以让屏幕正常显示白色的,所以排除硬件问题;而且由于能刷屏,那么应该也不是SPI传输的问题。 抱着试试的心态,我修改了显示范围,使屏幕的显示范围为两张图片的大小,结果如图。 ![h花屏.jpg](https://oss-club.rt-thread.org/uploads/20220415/5f2d0acecdf63b8bc4f1e1da3c5aa470.jpg.webp) 王的发??为什么SPI会传输一堆乱码然后再传数组里的数据??思考了一下,应该是spi在定位或者读取数组数据这个环节出了问题。我想到我的图片数组是单独存放在一个.c文件里的,如果我把它放在传输函数同一文件下,会不会有改变呢?试了一下,没想到。 ![成功显示.jpg](https://oss-club.rt-thread.org/uploads/20220415/3ad632cf95aeffff5d4e85108be2a4d4.jpg.webp) 我佛咯,这都有关系。这个办法虽然能解决问题,但是对于使用240*320屏幕的单片机来说,一张全屏的16位真彩色图片就要一百多KB,实在太浪费空间了。这应该可以采用SD卡+SPI的方式显示来解决。 - 图片斜向显示 如图。 ![斜向显示.jpg](https://oss-club.rt-thread.org/uploads/20220415/6f6c4c787cb073458598f70e2a436c8a.jpg.webp) 本来应该显示一个'0',但是却显示成了这样,明明函数啥的都没改过,为何会显示成斜的呢?想了想,上面那个成功显示的图片,两边都接触到了屏幕的边缘,也就是说全屏。那这两个显示的区别就在于,一个的显示区域固定住了或者说屏幕宽度上限了,而另一个还可以扩展。那会不会是设置显示区域的问题?思来想去,起始位置和结束位置定义错了!佛辣!如果要在横坐标60-90的区域显示,那么横坐标X1应该设置为60,而X2应该设置成89,没想到setaddress函数的参数里真写了60和90。崩贵。 - SPI设备在不同线程里的使用 上面显示图片的例子都是在main函数里完成的,由于要区别裸机开发,就要在创建线程,在线程里编写接下来的步骤。但是在自己创建的线程里使用SPI传输时,却不能正常显示图片,串口也并没有输出调试信息,输入list_device也有spi10(我使用的spi设备)。这是为何?难道不能在不同线程里使用同一个spi设备?在程序中加入几个rt_kprintf语句,确定了程序是在rt_spi_transfer_message_my这个函数里卡住了。(CSDN里大佬修改的spi_dma传输函数) ``` struct rt_spi_message *rt_spi_transfer_message_my(struct rt_spi_device *device, struct rt_spi_message *message, rt_sem_t sem) { rt_err_t result; struct rt_spi_message *index; RT_ASSERT(device != RT_NULL); /* get first message */ index = message; if (index == RT_NULL) return index; result = rt_mutex_take(&(device->bus->lock), RT_WAITING_FOREVER); if (result != RT_EOK) { rt_set_errno(-RT_EBUSY); return index; } /* reset errno */ rt_set_errno(RT_EOK); /* configure SPI bus */ if (device->bus->owner != device) { /* not the same owner as current, re-configure SPI bus */ result = device->bus->ops->configure(device, &device->config); if (result == RT_EOK) { /* set SPI bus owner */ device->bus->owner = device; } else { /* configure SPI bus failed */ rt_set_errno(-RT_EIO); goto __exit; } } /* transmit each SPI message */ while (index != RT_NULL) { /* transmit SPI message */ result = device->bus->ops->xfer_my(device, index, sem); if (result == 0) { rt_set_errno(-RT_EIO); break; } index = index->next; } __exit: /* release bus lock */ rt_mutex_release(&(device->bus->lock)); return index; } ``` 在rtt studio里运行仿真,发现程序运行到这一句时卡住了: ``` result = rt_mutex_take(&(device->bus->lock), RT_WAITING_FOREVER); ``` 单步跳入rt_mutex_take查看,发现spi设备要在不同线程使用,不仅仅是将spi设备挂载到spi总线上那么简单。 我在上一篇文章的代码中写道, ``` rt_spi_take_bus(&spi10); //(关键)使spi10设备获得SPI1总线控制权 ``` 这一步很关键,它获取了spi总线的控制权,实际上是获取spi设备所挂载到的总线上的lock这个互斥锁的值,没有这一步,spi就不能正常使用。而在使用rt_spi_transfer_message_my函数时,会先获取spi设备所挂载到的总线上lock的值,获取过程是: + 获取当前线程的句柄。 ``` /*get current thread */ thread = rt_thread_self(); ``` + 若当前线程是此互斥锁的owner,那么无论lock.value的值是多少,都获取成功。 ``` if (mutex->owner == thread){ if(mutex->hold < RT_MUTEX_HOLD_MAX){ /* it's the same thread */ mutex->hold ++; /*进入到这个if后,直接运行到函数尾*/ } else ..... } ..... return RT_EOK; ``` + 若当前线程非互斥锁的owner,查看lock.value,若value>0,则value--,且设置owner为当前线程,并获取成功。 问题应该很明显了,那就是由于我在main函数里调用了rt_spi_take_bus函数,此时spi总线的lock的值为0,owner为main,而在线程里调用传输函数时,由于lock.value == 0,并且owner也不是该线程,于是程序就一直卡在互斥锁的获取这一步。 解决方法很简单,只需要在main函数结束spi传输的地方加上一句: `rt_spi_release_bus(&spi10);/*使spi10让出spi1总线控制权*/` 然后在线程开始的地方加上: `rt_spi_take_bus(&spi10);` 就可以在线程里正常使用spi设备了。(同理,若要在另一个线程里使用,也要重复上面的步骤) - ## 结尾 这次踩坑令我感到自己还是一个彻头彻尾的小白,不足的地方,不懂的地方还有很多,但好在自己还韧了点,差点还没被打倒,还有一点勇气和毅力debug。希望下次做得更好,能逐步地成长起来。
4
条评论
默认排序
按发布时间排序
登录
注册新账号
关于作者
Budali11
调和 变革
文章
5
回答
1
被采纳
0
关注TA
发私信
相关文章
1
BBB的SPI驱动
2
求个SPI上挂两个或多个设备的使用例子
3
SPI设备有个bug
4
spi flash 的fatfs使用一段时间后读写文件出现故障
5
SPI驱动
6
请教rt_spi_configure函数理解
7
SPI FLASH挂载的问题
8
SPI-FLASH 文件系统 SPIFFS
9
求助一个完整的 spi flash 驱动
10
关于同时使用文件系统与SPI FLASH的问题
推荐文章
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
DMA
USB
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
FAL
rt-smart
I2C_IIC
ESP8266
UART
cubemx
WIZnet_W5500
ota在线升级
PWM
BSP
flash
freemodbus
packages_软件包
潘多拉开发板_Pandora
定时器
ADC
GD32
flashDB
socket
编译报错
中断
Debug
rt_mq_消息队列_msg_queue
keil_MDK
ulog
SFUD
msh
C++_cpp
MicroPython
本月问答贡献
RTT_逍遥
8
个答案
2
次被采纳
三世执戟
7
个答案
1
次被采纳
KunYi
6
个答案
1
次被采纳
winfeng
2
个答案
1
次被采纳
chenyaxing
2
个答案
1
次被采纳
本月文章贡献
出出啊
1
篇文章
4
次点赞
小小李sunny
1
篇文章
1
次点赞
张世争
1
篇文章
3
次点赞
crystal266
2
篇文章
2
次点赞
whj467467222
2
篇文章
2
次点赞
回到
顶部
发布
问题
投诉
建议
回到
底部