赞
踩
在使用nordic52832的SPI外设对外部Flash进行读写操作时,发现读出来的数据与写进去的数据不一致。
先看一下读写一个字节的错误示范:
- static uint8_t spi_tx[256],spi_rx[256],;
-
- static bool gSpiDone = false;//spi传输完成标志
-
- /**
- @brief SPI传输完成时的回调函数
- */
-
- static void spiCallbackFunc(nrf_drv_spi_evt_t const *pEvent, void *arg)
-
- {
-
- gSpiDone = true;
-
- }
-
- static uint8_t SpiReadStatusReg(void)
-
- {
-
- spi_tx[0] =0x05;//状态寄存器地址
-
- gSpiDone=false;
-
- //注意这个错误示范中发送和接受的都是1个字节
-
- nrf_drv_spi_transfer(&spi_flash, spi_tx, 1, spi_rx, 1);
-
- while(!gSpiDone);//等待传输完成
-
- return spi_rx[0];
-
- }
通过上面的函数读出来的值总是零,实际上是SPI的时序搞错了,我们来重新补习SPI时序相关的知识。
下面是通过逻辑分析仪捕获的读取外部flash器件ID的正常时序图:
先拉低片选信号CS,再发送命令0XAB,再发送三个字节的dummy。读取第四个字节数据,数据就是device ID。最后拉高CS,结束一次操作。注意时钟信号总共有5个字节周期!由于SPI是全双工工作,主机发送数据的同时,也会收到从机的数据,但因为主机没有发送完成,收到的从机数据都是无效的。因此上面的SpiWriteReadByte函数需要改成如下:
- static uint8_t SpiReadStatusReg(void)
-
- {
-
- spi_tx[0] =0x05;//状态寄存器地址
-
- spi_tx[1] =0xFF;//发送的第二个字节是无效数据,目的是提供时序以接受从机的数据
-
- gSpiDone=false;
-
- //注意这个正确示范中发送和接受的都是2个字节
-
- nrf_drv_spi_transfer(&spi_flash, spi_tx, 2, spi_rx, 2);
-
- while(!gSpiDone);//等待传输完成
-
- return spi_rx[1];//返回的第一个字节是无效数据,第二个字节才是有效数据
-
- }
改完之后读写正常,问题解决。
另外,针对52832的SPI库函数,需要注意的是52832的nrf_drv_spi_transfer函数限制了每次读写不能超过251字节(因为nrf_drv_spi_transfer传输数据长度的类型是uint8,1字节命令+3字节地址+251字节数据=255),所以要特殊处理一下。读可以任意地址读,写不能跨页写,正常一页256字节每次都需要分成251+5两次写。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。