博客文章“基于全志A33 spi从机系统实现”写后,有不少网友私信给我,感谢大家的关注,我把一些原则和思路和大家再次交流。
一:spi从机的基本思路
1:必须解决安卓上层发送数据后,不能死等。
2:必须解决从机准备好数据后可以通知主机立即获取数据,否则1就无法满足。
3:必须解决主机数据可以及时发给从机。
参考了nxp的spi从机代码,发现不好移植到全志的代码中(DMA部分没有看懂,1-3是如何解决没有看懂)。我们通过硬件上多加2个GPIO解决1-3问题。
流程如下:从机接收到GPIO-A的中断信号,知道主机请求数据,立即把一个信号写1,安卓上层是在不停读取这个信号量,发现为1后就立即下发spi数据。这个耗时在ms级别。A33的spi的驱动在接收到上层的数据后,把数据存入DMA中(一定要是DMA,否则1无法解决),把GPIO-B拉低,启动spi,退出。主机接收到GPIO-B的中断信号后,就立即读spi。A33在spi DMA结束后,把GPIO-B拉高(利用DMA的callback函数)。
关于如何设置spi为从机,就注意一个地方就好:
/* set master mode */
static void spi_set_master(void __iomem *base_addr)
{
u32 reg_val = readl(base_addr + SPI_GC_REG);
reg_val |= SPI_GC_MODE;
writel(reg_val, base_addr + SPI_GC_REG);
}
我们查看cpu的pdf,就知道如何修改为spi从机:
#ifdef SUPPORT_XC_SLAVE_SPI
/* set master mode */
static void spi_set_master_slave(void __iomem *base_addr)
{
u32 reg_val = readl(base_addr + SPI_GC_REG);
reg_val &= ~SPI_GC_MODE;
reg_val |= SPI_GC_SLAVE_MODE;
writel(reg_val, base_addr + SPI_GC_REG);
}
#endif
对应把驱动中spi_set_master的地方都修改为slave,只要这一步,spi的硬件就设置为从机了。
剩下的,就是细节和测试了。我遇到的问题:
1:发现数据会乱。
查看代码,之前的驱动中是spi主机,因此DMA用的内存在数据传输后就立即free了。而在我的驱动中,应用把spi数据发给驱动后,是保存在DMA中就立即返回,数据实际上是在等待主机读取。看代码,就会发现,这时驱动会把DMA用的内存给free,当然数据就会出错。最简单的处理,就是用一个全局的4096字buff代替每次的内存申请。
2:测试有发现偶尔出现spi数据无法发出:数据为0 .这个原因,我无法分析,最终解决的方法,是每次结束和开始,我都执行一次spi复位。
最后补充一下:就是如果遇到从机spi要求,linux 的spi从机驱动资料确实少,调试也不方便,可能会用大量的时间来测试和修改。我们后来做了一个spi转接板,可以完美解决linuxspi从机的问题。linux的spi还是是主机,你的原spi主机不变,spi转接板是2路spi从机接口。这样,linux的驱动几乎不用修改,当然,gpio还是要的。
我目前在深圳市芯传科技有限公司工作,芯传是一家方案开发公司,主要是基于全志cpu做安卓和linux方面的开发。源码就无法在博客中写出,思路和解决方法供大家参考,如果您的问题还是无法解决,欢迎商务合作。