非常幸运,在海思SDK的 drv.tgz\drv\extdrv\ssp-st7789
中正好有源码,连芯片型号都一样,基于这个代码做一些简单修改就能用 。
经过我的一番修改,实际测试下来发现这个ko模块的性能比linux内核spi的性能有一点点提升,延时从1.656us降低到了1.6us以内,基本等于没有优化,这里就不放截图了 。
这个代码就比较简单,读起来也不费劲,大概看了一下还是能找到一点优化的地方,注意看spi_write_XXbyte
这几个函数,这几个函数内都有这样的代码
spi_enable();ssp_writew(SSP_DR,spi_data);ret = hi_spi_check_timeout();if(ret != 0){printk("spi_send timeout\n");}spi_disable();
在前面的代码中设置过CS片选信号由spi使能信号控制,也就是说,这段代码每次写一个字节都要拉一次CS信号,效率比较低,我将 spi_enable 和 spi_disable 提出来后再次进行测试,速度确实有一定提升,但提升幅度仍然不大,只有大概几百ns的水平,优化效果仍然不理想 。
这段代码只剩下两个函数了,ssp_writew 是写寄存器,根本不能优化,只能想办法优化 hi_spi_check_timeout,来看一下这个函数的实现
static int hi_spi_check_timeout(void){unsigned int value =https://www.huyubaike.com/biancheng/0;unsigned int tmp = 0;while (1){ssp_readw(SSP_SR,value);if ((value & SPI_SR_TFE) && (!(value & SPI_SR_BSY))){break;}if (tmp++ > MAX_WAIT){printk("spi transfer wait timeout!\n");return -1;}udelay(1);}return 0;}
逻辑非常简单,不停地读取发送FIFO空和SPI忙的标志位,延时1us继续读,直到发送完成且SPI空闲 。看到这个 udelay(1) 你现在的想法肯定和我当时的想法一样:第一次读取发现寄存器没有置位,延时1us,第二次读取寄存器置位,退出循环,现在的发送间隔是1.6us,去掉这个延时尽快读取寄存器,应该直接能优化到0.6us以内 。
想得美!实际测试去掉这个 udelay(1) 以后优化效果确实挺明显的,延时直接缩短到 1.2us 左右,但是这个延时还是太长了 。
现在再来看这个函数,就剩一个读寄存器了,为了保证可靠传输,读标志位肯定不能去掉,这已经最简单了,还能怎么优化呢?我们重新梳理一下:去掉 udelay(1) 后间隔缩短到 1.2us 左右,说明这里循环读了很多次寄存器,不然怎么还有这么长的延时?那要不就加打印看看这里到底循环读取了几次?来来来,竞猜一下这里到底循环了几次?十次以内?百次以内?还是千次以内?答案是一次!没错只有一次!
1次这个答案可以说即在意料之外也在意料之中 。说它在意料之外是因为读写寄存器这种操作是非常快的,一般而言几个cpu时钟就能完成,但这里读一个寄存器却花费了 1.2us 。说它在意料之内是因为这些物理寄存器都是通过硬件置位的,以发送 FIFO 为空标志为例,当 SPI 发送完成瞬间它就会被硬件置位,这一点在任何一款单片机上都可以验证,实际操作一下就会发现类似的寄存器是瞬间被置位的 。pl022 应该是非常成熟的 SPI 控制器,我觉得芯片设计人员不会范发送 FIFO 为空后很长时间才设置标志位这种低级错误 。
接下赖重点思考这个问题:为什么 ssp_readw(SSP_SR,value) 这样一个简单的读寄存器操作要 1.2us 之久?(目前我测试 ssp_writew 写一个寄存器大概在 100ns 以内,ssp_readw 读一个寄存器大概在 1us 左右)这个问题无论是百度还是谷歌我找了很久都没有找到确切答案,如果有知道的大佬非常欢迎指导!!!不白嫖知识,私信发红包 。下面是我个人的推测,虽然是推测,但我觉得这就是正确答案,仅供参考:
linux 不同于单片机裸机程序那样可以直接访问寄存器,如果需要读写物理寄存器,在内核态使用
经验总结扩展阅读
- 基于vite3+tauri模拟QQ登录切换窗体|Tauri自定义拖拽|最小/大/关闭
- 痞子衡嵌入式:i.MXRT中FlexSPI外设不常用的读选通采样时钟源 - loopbackFromSckPad
- 基于tauri+vue3.x多开窗口|Tauri创建多窗体实践
- 提高工作效率的神器:基于前端表格实现Chrome Excel扩展插件
- 基于雪花算法的增强版ID生成器
- 基于QT和C++实现的翻金币游戏
- Mysql单表访问方法,索引合并,多表连接原理,基于规则的优化,子查询优化
- 基于tauri打造的HTTP API客户端工具-CyberAPI
- 基于纯前端类Excel表格控件实现在线损益表应用
- 知识图谱实体对齐2:基于GNN嵌入的方法