原博客连接:http://blog.sina.com.cn/s/blog_9fff1f140102wq3m.html
这个项目里面涉及到使用加速度芯片,我们使用了一片目前最低功耗的ADXL362芯片。这类数字传感芯片的主流端口一般是IIC和SPI。IIC相对而言硬件设计较为简单,两线总线可以直接挂载很多芯片,但通信受干扰,容易进入“死锁”状态,需要软件处理。SPI相对而言需要的硬线更多,但不存在出现“死锁”的问题,另外通信速率也更高。
下面是NRF52832的SPI模块结构图。和51422/51822之类相比其主要区别,新增了EasyDMA模块,可以自动读写RAM。也就意味着我们CPU可以一次性配置一整个数据包的传输,然后等着整包数据传输完再处理剩下任务了,无论是低功耗还是降低CPU负荷都有很大帮助。
除此以外还有个比较重要的事情,NRF的MCU有一部分外设是“共享资源”的,他们的配置寄存器的地址也是重合的,不能同时被使能。(其实我觉得根本就是同一个模块的不同模式罢了...)。下图里面可以看出来,片上的SPIM,SPIS,TWI三个模块均是共享同样地址。因此要注意,不能同时使能同一个ID号的外设。也意味着NRF52832事实上只有3个同步串行通信模块,可以被配置为SPI主,SPI从,IIC模式,而不是有9个...
接下来先编写SPI外设的驱动程序。这里我将其封装为4个功能:
1、初始化并开启SPI模块
2、收发数据
3、关闭SPI模块
如图为初始化程序,其主要任务为:初始化SPI模块并使能,创建传输完成的信号量
由于我们经常会在同一个SPI总线上面挂若干芯片,通过片选来分别,分时复用,所以一般都将ss_pin禁用,在更高一层的设备驱动,软件控制GPIO来实现。
另外重点就是字节传输顺序,bit_order,一般都是MSB在前,也遇到过LSB在前的奇葩(某国产芯片),每次都应该仔细核对下。
此外还有CPOL和CPHA也要仔细确认下,这里使用库函数的话,直接采用MODE0/1/2/3来代替。
这里orc是如果数据包长度TX
此外外设库SPI初始化函数nrf_drv_spi_init可以提供一个函数句柄,用做传输完成的回调函数。若不提供的话则后面调用nrf_drv_spi_transfer则会是阻塞的。
如图为SPI读写函数。由于SPI读写是同步的故直接封装成一个函数,且使用RTOS的信号量实现阻塞。
大致任务就是调用nrf_drv_spi_transfer发送,随后等待回调函数里面释放信号量,再返回。
如图为SPI模块关闭函数,主要用于低功耗优化。
如图为SPI的发送完成回调函数,将会在发送完成中断中调用,因此发送信号量时候应该选择FromISR这个API。
接下来可以编写个简单的程序,用ADXL362来进行一番简单测试。一般的,这类芯片皆有一个专门用来识别ID的只读寄存器,可以编写读取这个ID来测试。
这里就读取0x02地址的数据来测试。
首先,在ADXL362的驱动程序里面,封装一个函数__read_char,作用是读取单个字节大小的寄存器的数据。其中输入参量为寄存器地址,返回值为寄存器的值。