最近需要调试f2812 的Spi,我的spi口接的是flash,型号是S25FL016A,以前没摸过DSP,看了一个星期F2812的资料,然后开始调试,用的软件调试工具是CCStudio v3.3,编译加在线调试,网上调试f2812 spi的资料也有一些,大多是spi连eeprom和ADS的,应该是大同小异,查看了一些资料后,边写边移植,代码不多,很快就写完了,但spi一直不通,读写flash老是失败,整了一个多星期,总算调通了,下面是我觉得需要注意的地方(我没有用中断模式,也没有开启fifo)。
首先是初始化:
1.GpioMuxRegs.GPFMUX.all = 0x003F; 很多人都是这样初始化的,GPFMUX是控制寄存器,最后四位置1就是把CPU的这四个管脚配成spi功能,分别是MOSI(主输出从输入),MISO(主输入从输出),SCK(时钟),STE(片选),配成spi模式后,只要往SPITXBUF寄存器写数,时钟就会自动发起,片选自动选中(STE拉低),数据也自动传送,这就是我遇到的主要问题了,由于不通,我用示波器量了一下波形,发现发完一个字节后STE就自动拉高了,而这对于该flash读写是绝对不允许的,比如我要读一个地址的数据,发一个字节读命令,三个字节地址,然后准备读数,在这期间STE必须一直是低电平,如果中间拉高了,该读命令就结束了,我也不知道为什么2812发完一个自节就STE自动拉高了,很奇怪,后来我这样解决的,把STE设成gpio模式,方向设为输出(如下)
GpioMuxRegs.GPFMUX.all = 0x0037;
GpioMuxRegs.GPFDIR.all |= 0x0008;
这样我就可以用软件随便控制片选信号了。
还有更有意思的,把四个管脚全设成gpio模式,那么时钟也要用软件模拟的,这样需要一位一位发,稍微麻烦点,我没试过。
SpiaRegs.SPICCR.all=0x0047; 最后四位设成0111,表示每次数据传输位数为8位;关闭自回还模式
需要注意相位和极性的设置,由SPICCR.bit6(POLARITY) 和SPICTl.bit3(PHASE)控制
当SPICCR.bit6 = 1 SPICTl.bit3 = 0 下跳沿发数上跳沿收数
当SPICCR.bit6 = 0 SPICTl.bit3 = 1 在第一个高电平的前半个周期和紧接着的下跳沿发数,上跳沿收数
还有两种极性和相位设置就不介绍了,手册里讲这个flash是在上跳沿时收数,所以我上面讲的两种模式都是可以的(我自己做过实验,确实可以,大部分资料只讲了一种)
SpiaRegs.SPICTL.all=0x0006; //配成主模式,禁止发送功能,禁止中断
SpiaRegs.SPISTS.all=0x0000; //所有状态位清零
SpiaRegs.SPIBRR=0x001F; //设置波特率,波特率计算公式手册上有,BRR的值作是为除数,所以BBR的值设的越大,波特率越小,注意波特率不能太大,大到超过flash的范围那肯定工作就不正常了
SpiaRegs.SPICCR.all=SpiaRegs.SPICCR.all|0x0080; //软复位
2.再讲一下读写函数(注意SPIRXBUF和 SPITXBUF都是16位的)
unsigned short SPI_read_8()
{
unsigned short mytemp = 0x1111; //随便附一个值,这个无所谓,我自己调试用的
SpiaRegs.SPITXBUF=0xffff; //为了启动时钟,要发一个无效数
while((SpiaRegs.SPISTS.all&0x0040) != 0x0040) ; //判断是否发完
mytemp = SpiaRegs.SPIRXBUF;
return (mytemp & 0x00ff); //这个和前面的SPICCR后四位有关,因为设的是1次传输8位,注意收数时是右对齐的,即后面8位才是真正想要的数据
}
void SPI_send_8(unsigned short a)
{
SpiaRegs.SPITXBUF=a; //写到发送寄存器,
while((SpiaRegs.SPISTS.all&0x0040) != 0x0040) ; //判断是否发完
SpiaRegs.SPIRXBUF=SpiaRegs.SPIRXBUF; //发完后读一下接收寄存器,以便清除中断标志位
}
3.最后讲一下flash操作时序,命令主要有读写擦,注意写之前必须全擦一下,否则写不进去,只说一下如何写吧
char Read_RDSR(void) // 读状态函数
{
unsigned short read_data;
GpioDataRegs.GPFDAT.bit.GPIOF3 = 0; //拉低STE,使能flash,每个命令之前都别忘了这一步
SPI_send_8(RDSR); //发命令,手册里都有每个命令的解释
read_data=SPI_read_8(); //读状态数据
GpioDataRegs.GPFDAT.bit.GPIOF3 = 1; //拉高STE,操作完手动拉高,命令才能完全执行
return(read_data);
}
//下面是写的过程
while((temp = Read_RDSR())&0x01); //判断设备是否空闲
EALLOW;GpioDataRegs.GPFDAT.bit.GPIOF3 = 0; EDIS;
SPI_send_8(WREN); //写操作前别忘了写使能
EALLOW;GpioDataRegs.GPFDAT.bit.GPIOF3 = 1; EDIS;
while((temp = Read_RDSR())&0x01); //判断设备是否空闲
EALLOW;GpioDataRegs.GPFDAT.bit.GPIOF3 = 0; EDIS;
SPI_send_8(WRITE); //发送写命令,这里也需要注意,写命令是0x02,而这里WRITE宏定义的值是0x0200,
也是因为每次发8位,发的时候是左对齐的,即实际上只有高八位发出去了,后面的地址数据都是如此
SPI_send_8(0x0000); //发送三个字节写地址
SPI_send_8(0xF000);
SPI_send_8(0x0000);
for(i = 0; i< 10; i++)
SPI_send_8(0xEE00); //要写的数据
EALLOW;GpioDataRegs.GPFDAT.bit.GPIOF3 = 1; EDIS;
刚开始调试的时候可以发个最简单的RDID命令,看设备ID能否读回来,成功了再测读写
主要这么多了,把握好几个点,就比较简单了,调板子还是很需要耐心的的,多看手册,多思考,这次调试还是很有意义的,早就不用的示波器又用起来了,还是很有用啊,以后还是要多多学习硬件方面的东西