之前使用STM32驱动W25Q128,驱动程序用的是github上下载的一个W25QXX的文件,对该系列的芯片通用。
现在使用NIOS II软核为控制核心,添加了SPI外设,配置其实很简单:
添加后,BSP内部会提供一个写好的SPI函数,实现SPI数据的收发,但是使用过程中需要注意一些问题。
第一个要注意的问题是SPI的收发函数。
uint8_t W25qxx_Spi(uint8_t Data)
{
uint8_t ret;
HAL_SPI_TransmitReceive(&_W25QXX_SPI,&Data,&ret,1,100);
return ret;
}
这个函数是在STM32环境下使用的,没有任何问题。关键在于这个函数:
HAL_SPI_TransmitReceive(&_W25QXX_SPI,&Data,&ret,1,100);
注意看它的参数,它是同时进行SPI数据的发送和接收,在发送Data里面的数据的同时,也会把收到的数据存入ret。并不是先把Data里面的数据发出去,然后在进行接收操作。
而NIOS II的BSP里面提供的函数如下:
int alt_avalon_spi_command(alt_u32 base, alt_u32 slave,
alt_u32 write_length, const alt_u8 * write_data,
alt_u32 read_length, alt_u8 * read_data,
alt_u32 flags)
这个函数会先发送指定数量的数据,然后接收指定数量的数据,和STM32的函数是不一样的。并非无法实现STM32的效果,而是官方只提供了这一个函数,所以要想办法自己修改。
另一个要注意的地方也和这个函数有关系。实际应用中,使用STM32的SPI外设时,通常是不用硬件的NSS片选信号的,而是自己定义一个GPIO,用来做片选。用到W25QXX的驱动里,效果是这样:
void W25qxx_ReadUniqID(void)
{
HAL_GPIO_WritePin(_W25QXX_CS_GPIO,_W25QXX_CS_PIN,GPIO_PIN_RESET);
W25qxx_Spi(0x4B);
for(uint8_t i=0;i<4;i++)
W25qxx_Spi(W25QXX_DUMMY_BYTE);
for(uint8_t i=0;i<8;i++)
w25qxx.UniqID[i] = W25qxx_Spi(W25QXX_DUMMY_BYTE);
HAL_GPIO_WritePin(_W25QXX_CS_GPIO,_W25QXX_CS_PIN,GPIO_PIN_SET);
}
如上,不管什么操作,先开片选,然后各种读写,然后关片选。
而NIOS II官方提供的这个SPI函数,把片选写在了里面。每调用一次,函数内部就会执行打开片选、关闭片选的操作。而要实现一些比较复杂的操作时,需要反复读写,中间是不能关闭片选的,一旦关掉,操作就被中断了。这就是导致读写失败的主要原因。
因此也要注意这个地方,解决方法很简单,注释掉里面的开关片选就行了,在外面自己宏定义一个开片选、一个关片选即可。
大致就这些,只讲了原理,没提供源码,打完收工。