内核SPI Slave软件简介
SPI主从之间传输通常遵循特定协议,如SPI Nor 兼容 JEDEC SDFP 协议,瑞芯微RK SPI slave 作为设备端传输也应遵循特定的协议,由于协议无范式,所以RK提供自定义的传输协议和设备驱动以供客户参考。
Linux SPI slave驱动框架限制:使用传输队列,虽然队列唤醒后的线程优先级较高,但受调度影响不能完全保证实时性。
瑞芯微RK SPI slavemode限制:每次传输需重新发起SPI控制器配置,因此为确保SPImaster能够获知RK SPI slave完成传输配置从而发起数据传输,RKSPIslave端需增加side-band信号做ready状态位。
本文基于
触觉智能RK3506星闪开发板
演示SPI Slave从设备开发,其配套RK3506核心板(3核A7+M0多核异构),100%全国产,峰值功耗低至0.65W。
瑞芯微RK SPI slave 传输协议
数据传输要求指定ready-gpios来通知SPI master分为5个部分:
(1)Slave 主动发起 spi_syncstep(2)Slave ready,使能 GPIO_SlV_READY 信号(3)master 确认 Slave ready 后发起传输(4)Slave 接收来自 master 发出的足够的 clk 后完成传输(5)Slave idle,释放 GPIO_SlV_READY 信号

、
包括ctrl packet:2B cmd,2B addr(RK slave 定义的 application buffer 偏移地址),4B data(通常用于指定之后 data 包的传输长度)和data packet。
ctrl 传输(仅包含 1 ctrl packet),以及data 传输(包含1 ctrl packet 和 1 data packet 的两笔 SPI 传输)。
驱动源码:
drivers/spi/spidev-rkslv.c drivers/spi/spidev-rkmst.c
源码简介:
static int spidev_rkslv_ctrl_receiver_thread(void *p) //建立线 程,线程内重复发起传输 { while (1) spidev_rkslv_xfer(spidev); drivers/spi/spidev-rkmst.c: 实现业务 } static int spidev_rkslv_xfer(struct spidev_rkslv_data *spidev) //传输入口 { spidev_slv_read(spidev, spidev->ctrlbuf, SPI_OBJ_CTRL_MSG_SIZE); //1 ctrl packet,获取并解析传输类型 switch (ctrl->cmd) { //1 data packet,根据传输类型,定义 data packet 并完成收发 case SPI_OBJ_CTRL_CMD_INIT: /* to-do */ case SPI_OBJ_CTRL_CMD_READ: /* to-do */ case SPI_OBJ_CTRL_CMD_WRITE: /* to-do */ case SPI_OBJ_CTRL_CMD_DUPLEX: /* to-do */ } } static const struct file_operations spidev_rkslv_misc_fops = {} //注册 misc device 测试接口
drivers/spi/spidev-rkmst.c说明:
static int spidev_rkmst_xfer(struct spidev_rkmst_data *spidev, void *tx, void *rx, u16 addr, u32 len) //传输入口 { spidev_rkmst_ctrl(spidev, cmd, addr, len); //1 ctrl packet,定义传输类型 switch (cmd) { //1 data packet,根据传输类型,定义 data packet 并完成收发 case SPI_OBJ_CTRL_CMD_READ: /* to-do */ case SPI_OBJ_CTRL_CMD_WRITE: /* to-do */ case SPI_OBJ_CTRL_CMD_DUPLEX: /* to-do */ } } static const struct file_operations spidev_rkmst_misc_fops = {} //注册 misc device 测试接口

SPI Slave 测试设备配置
echo cmd addr length > /dev/spidev_rkmst_misc
说明:cmd :支持 read/write/duplex;addr:为对端 slave application buffer 偏移,单位 Bytes,仅支持 10 进制输入;length:为 data packet 长度,单位 Bytes,仅支持 10 进制输入;
实例如下:
echo write 128 128 > /dev/spidev_rkmst_misc echo read 128 128 > /dev/spidev_rkmst_misc echo duplex 128 128 > /dev/spidev_rkmst_misc
echo autotest length loops compare > /dev/spidev_rkmst_misc
说明:autotest:固定输入,先测试全双工数据传输,再测试读写数据传输,并输出速率结果;测试默认使用对端 slave application buffer 偏移地址 0;
length:为 data packet 长度,单位 Bytes,仅支持 10 进制输入;loops:设定压测循环次数;
compare:1 - 开启数据校验;0 - 关闭数据校验(支持特定场景,如持续输出数据进行信号测试);
实例如下:
echo autotest 1024 64 1 > /dev/spidev_rkmst_misc
echo appmem 0 256 > ./dev/spidev_rkslv_misc #打印 application buffer 数据 echo verbose 1 > ./dev/spidev_rkslv_misc #开启传输传输过程 debug log,echo verbose 0 关闭打印
SPI Slave常见问题
调试前确认驱动有跑起来;确保 SPI 4个引脚的IOMUX配置无误;
确认TX 引脚有正常的波形,CLK有正常的 CLOCK 信号,CS信号有拉低;
如果clk频率较高,可以考虑提高驱动强度来改善信号;
如何简单判断SPI DMA 是否使能,串口打印如无以下关键字,则DMA 使能成功:
[ 0.457137] Failed to request TX DMA channel [ 0.457237] Failed to request RX DMA channel
对于 SPI io 速率较高的情形,正常 SPI mode 可能依旧无法匹配外接器件输出延时,RK SPI master read 可能无法采到有效数据,需要启用 SPI rsd 逻辑来延迟采样时钟。
(1)默认传输模式
master mode 支持 IRQ、DMA 和 CPU 传输,slave mode 支持 IRQ 和 DMA 传输,默认都为 IRQ/DMA 组合传输方式:
当传输长度 < fifo 深度时,使用 IRQ 传输,默认使用 4.19 及以上内核版本的SOC,fifo 深度为64;
当传输长度 >= fifo 深度时,使用DMA传输;
(2)修改传输模式
master mode支持:
默认IRQ/DMA 组合传输方式;
参考 ”关闭 DMA 支持,仅支持 IRQ 传输;“ 说明,关闭 DMA,配置后仅支持IRQ 传输;
参考”rockchip,poll-only“ 说明,配置后仅支持CPU传输;
slave mode 不支持修改传输模式。
(3)IRQ传输特性
当数据 < fifo 深度时,一次传触发 1 个中断,当数据 >= fifo 深度且使用 IRQ 传输时,fifo 水线设置为半 fifo,通常为 32 item,一次传输大致上触发 items / 32 次中断。
(4)DMA 传输特性
不触发 spi 控制器中断,使用 DMA 传输 finished call back 回调
通常 SPI 传输速率慢、IO 高负载下 CPU 占用率高的原因是因为:SPI 传输粒度小,且传输次数多,频繁发起传输从而涉及较多的调度。建议优化方向:
1. 开启 auto runtime,延时设置为 500ms,具体值以实测为准,修改点为 dts 节点添加rockchip,autosuspend-delay-ms 属性;
2. 降低 CPU 负载:改用 IRQ 传输,相对 DMA 可能会有优势,补丁参考 “改为 IRQ 传输” 小节;
3. 降低 CPU 负载:如为 DMA 传输,可修改 TX DMA 水线来降低 CPU 在 DMA 回调函数中等待 fifo传输完成的时间,补丁参考 “修改 SPI 水线。
全部0条评论
快来发表一下你的评论吧 !