DSP

DSP F2812 SPI调试

2019-07-13 10:29发布

最近需要调试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能否读回来,成功了再测读写   主要这么多了,把握好几个点,就比较简单了,调板子还是很需要耐心的的,多看手册,多思考,这次调试还是很有意义的,早就不用的示波器又用起来了,还是很有用啊,以后还是要多多学习硬件方面的东西