当前位置: 首页 > news >正文

Linux SPI子系统跟踪打印

主要跟踪复杂容易出现误解的函数,忽略spi_init()函数,这个函数主要注册bus以及class,基本上不会出错。主要打印查看以下函数:

主机层初始化

#defineSPI_LOG(fmt,...)\printk(KERN_ERR"[SPI-IMX] %s: "fmt"\n",__func__,##__VA_ARGS__)

开始时调用

SPI_LOG("probe start");

从设备树读取cs信息并初始化

ret=of_property_read_u32(np,"fsl,spi-num-chipselects",&num_cs);SPI_LOG("num_cs=%d",num_cs);intcs_gpio=of_get_named_gpio(np,"cs-gpios",i);SPI_LOG("cs[%d]=%d",i,cs_gpio);

查看寄存器的基地址

spi_imx->base=devm_ioremap_resource(&pdev->dev,res);SPI_LOG("base=%p",spi_imx->base);

打印获取到的中断号

irq=platform_get_irq(pdev,0);if(irq<0){ret=irq;gotoout_master_put;}SPI_LOG("irq=%d",irq);

打印SPI时钟

spi_imx->spi_clk=clk_get_rate(spi_imx->clk_per);SPI_LOG("spi_clk=%lu",spi_imx->spi_clk);

打印DMA初始化结果

if((spi_imx->devtype_data==&imx51_ecspi_devtype_data||spi_imx->devtype_data==&imx6ul_ecspi_devtype_data)&&spi_imx_sdma_init(&pdev->dev,spi_imx,master,res))dev_err(&pdev->dev,"dma setup error,use pio instead\n");elseSPI_LOG("spi_imx: dma setup ok");

打印probe结果

SPI_LOG("probed successfully");

编译后结果

可以看出probe成功初始化。
除此以外,probe函数中还进行了bitbang的初始化以及控制器向核心层设备的注册
在核心层的注册函数中加入

of_register_spi_devices(master);SPI_CORE_LOG("devcice registered\n");

可以看到成功创建了设备:

这样总线上就已经挂载了主机设备,现在来看看用户驱动如何通过总线与主机设备匹配上的。

用户驱动注册

当用户驱动调用spi_register_driver()注册到内核时,总线核心代码会遍历挂在 SPI 总线上的所有设备,并调用这个函数来判断设备和驱动是否匹配

这里使用insmod注册驱动,可以发现

用户驱动注册后,APP便要调用write和read函数来操作,这个操作都是通过同步传输实现的。
同时注意到,linux内核初始化时

说明设备被添加到总线上时,也会与编译进入内核的驱动进行匹配。

同步通信

根据代码分析spi_sync函数最终会调用__spi_sync函数
首先绑定完成量

然后会在__spi_queued_transfer中将message加入队列尾部

随后,调用__spi_pump_messages来调用底层硬件来发送,注意到这里的bool类型 is kworker为false,通过看注释发现其取消了使用线程来发送,这是为了节省上下文切换的空间,如果是异步的话就是会调用线程

需要注意的是,sync和async都会调用这个函数,唯一的区别是,这个函数sync是自己调用的,为了节约时间,将任务分配给了kworker去做,而async全部都交给kworker去执行。

在__spi_pump_messages中插入

可以注意到,在sync中,并没有代码发送信号量完成,这时我们要观察硬件代码,通过代码分析,实际上spi-imx只提供了xfer函数,主要发送还是有bitbang框架实现,所以在bitbang框架中加入





可以看到最后bitbang还调用了spi.c中的函数,用来发送完成量,在完成量函数中也加入消息完成log,接下来我们来看主机层主要实现的函数

在函数中加入log

只有数据量大的时候才会用DMA

最后会调用push来推送数据,并等待xfer_done完成量,在push中加入以下log


这里的xfer_done完成量会在中断中调用,同时,中断还会接收消息


![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/78cfd731baf2428989eeb49933f9bb56.png
可以发现代码确实如分析所反应的一样,通过pump来调用bitbangbitbang调用transfer,然后调用push,最后引起主机层中断,在中断中处理读取数据,并发送完成xfer_done标志,当bitbang完成后,就会发送完成complete标志给sync函数,最终完成一次同步信息传输,同时调用kworker来清理,同时上面的ASYNC标识后面会解释。

可以看出上文中并没有使用到kworker,因为sync为了避免上下文切换直接发送了消息,接下来将驱动中的sync替换为async,并进行分析:

异步通信


这里之前分析sync的时候已经查看过了,唯一不同的是这里会将pump_messages加入kworker中驱动

这里的pump_messages被绑定为如下函数,可以看出这个函数我们之前在SYNC中就被调用过了,但是当时其并没有输入true

在这里加入kwoker清空的情况

后面的过程就与SYNC相似了,直接用之前写好的log

将驱动中的读取SYNC换成ASYNC,结果为

staticvoidicm20608_spi_complete(void*arg){structcompletion*done=arg;complete(done);}staticinticm20608_read_regs(structicm20608_dev*dev,u8 reg,void*buf,intlen){intret;unsignedchartxdata[1];unsignedchar*rxdata;structspi_messagem;structspi_transfert;structspi_device*spi=(structspi_device*)dev->private_data;DECLARE_COMPLETION_ONSTACK(done);rxdata=kzalloc(len+1,GFP_KERNEL);if(!rxdata)return-ENOMEM;txdata[0]=reg|0x80;memset(&t,0,sizeof(t));t.tx_buf=txdata;t.rx_buf=rxdata;t.len=len+1;spi_message_init(&m);spi_message_add_tail(&t,&m);m.complete=icm20608_spi_complete;m.context=&done;ret=spi_async(spi,&m);if(ret)gotoout;wait_for_completion(&done);memcpy(buf,rxdata+1,len);out:kfree(rxdata);returnret;}



可以看出除了开始化过程其他与SYNC一致。

http://www.cnnetsun.cn/news/1506604.html

相关文章:

  • 零基础入门:OpenClaw+GLM-4.7-Flash首个自动化任务实战
  • SetDPI:解决多显示器DPI缩放不一致的精准控制方案
  • 5步掌握抖音音乐批量下载:douyin-downloader高效使用指南
  • OpenClaw+百川2-13B:小型工作室内容创作自动化解决方案
  • Pixel Fashion Atelier部署教程:Kubernetes集群中水平扩展像素锻造服务
  • OpenClaw定时任务:百川2-13B实现每日早报自动生成与发送
  • 【Java】UTF-8变长编码及其3字节存储奥秘
  • 零代码玩转OpenClaw:百川2-13B-4bits量化模型自动化办公入门
  • 嵌入式硬件第五弹——ARM(2)
  • OpenClaw语音交互扩展:nanobot镜像接入Whisper实现语音控制
  • 跨端 UI 设计统一:多平台的视觉和谐
  • OpenClaw跨平台实战:Windows到Mac的Qwen3-32B配置迁移
  • 南医三院脊柱骨折诊疗:微创技术与专科方案解析
  • 废弃电脑改造计划:OpenClaw+GLM-4-7-Flash搭建24/7自动化终端
  • window环境使用git-filter-repo
  • OpenClaw+GLM-4.7-Flash:自动化社交媒体管理
  • 200KB轻量级HTML编辑器:KindEditor如何让网页内容创作变得简单高效?
  • Simple Runtime Window Editor:突破窗口分辨率限制的技术实现与应用指南
  • 4太5也5与4y
  • macOS Ventura 13命令行自动化管理:定时开机与关机高效攻略
  • 在QEMU中定制AST2600设备:从Machine定义到硬件模拟实战
  • 如何高效使用LeaguePrank:英雄联盟个性化展示的终极指南 [特殊字符]
  • 跨平台文件同步:OpenClaw+Qwen3.5-9B智能处理NAS文档归类
  • 横向对比:@zxing/library vs html5-qrcode,你的Web扫码方案该选谁?
  • [FLAC无损下载]技术突破:网易云音乐资源高效获取的架构解析与工程实践
  • OpenClaw多模型切换实战:百川2-13B-4bits与Qwen3-32B混合调用策略
  • 【工程心法】砸碎 Keil 的黑盒枷锁!告别 IDE 农耕时代,用 CMake + GCC 构筑嵌入式工业级自动化构建矩阵
  • OpenClaw学习助手实战:Qwen3.5-9B自动整理PDF笔记与生成思维导图
  • [LangGraph编译原理]从“状态图(StateGraph)”到“Actor模型(Pregel)”的转变
  • 4步焕新计划:老旧Mac设备升级macOS全攻略