OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 5200|回复: 1

我的W25Q128能正确读出ID,但是擦除flash以后,读出的数据不是0XFF,而是各种值

[复制链接]

3

主题

8

帖子

0

精华

初级会员

Rank: 2

积分
75
金钱
75
注册时间
2019-5-1
在线时间
16 小时
发表于 2022-8-2 10:13:59 | 显示全部楼层 |阅读模式
奇怪的是,我用官方历程也不能正确读出写入W25Q128里面的数据,不知道是不是flash坏了,还是其他问题。
这是W25Q128.c文件:
  1. #include "flash.h"
  2. #include "spi.h"
  3. #include "SysTick.h"
  4. #include "usart.h"


  5. u16 W25QXX_TYPE=W25Q128;        //默认是W25Q128

  6. static volatile uint32_t SPITimeout = SPIT_FLAG_TIMEOUT;


  7. //4Kbytes为一个Sector
  8. //16个扇区为1个Block
  9. //W25Q128
  10. //容量为16M字节,共有128个Block,4096个Sector
  11.                                                                                                          
  12. //初始化SPI FLASH的IO口
  13. void W25QXX_Init(void)
  14. {
  15.   GPIO_InitTypeDef  GPIO_InitStructure;

  16.   RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);//使能GPIOB时钟
  17.   RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG, ENABLE);//使能GPIOG时钟

  18.           //GPIOB14
  19.   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14;//PB14
  20.   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//输出
  21.   GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
  22.   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
  23.   GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
  24.   GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化

  25.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;//PG7
  26.   GPIO_Init(GPIOG, &GPIO_InitStructure);//初始化

  27.         GPIO_SetBits(GPIOG,GPIO_Pin_7);//PG7输出1,防止NRF干扰SPI FLASH的通信
  28.         W25QXX_CS=1;                        //SPI FLASH不选中
  29.         SPI1_Init();                                           //初始化SPI
  30.         SPI1_SetSpeed(SPI_BaudRatePrescaler_4);                //设置为21M时钟
  31.         W25QXX_TYPE=W25QXX_ReadID();        //读取FLASH ID.
  32. }  

  33. //读取W25QXX的状态寄存器
  34. //BIT7  6   5   4   3   2   1   0
  35. //SPR   RV  TB BP2 BP1 BP0 WEL BUSY
  36. //SPR:默认0,状态寄存器保护位,配合WP使用
  37. //TB,BP2,BP1,BP0:FLASH区域写保护设置
  38. //WEL:写使能锁定
  39. //BUSY:忙标记位(1,忙;0,空闲)
  40. //默认:0x00
  41. u8 W25QXX_ReadSR(void)   
  42. {  
  43.         u8 byte=0;   
  44.         W25QXX_CS=0;                               //使能器件   
  45.         SPI1_ReadWriteByte(W25X_ReadStatusReg);    //发送读取状态寄存器命令  

  46.   SPITimeout = SPIT_FLAG_TIMEOUT;
  47.        
  48.         while(1)
  49.         {
  50.                 byte =  SPI1_ReadWriteByte(0xFF);
  51.                 if((byte & 0x01) == 0 )    //如果条件成立,说明为空闲状态
  52.                     break;
  53.                 if((SPITimeout--) == 0)      //SPITimeout为0,表示已近检测SPITimeout次都仍为busy,跳出循环
  54.           {
  55.                    SPI_TIMEOUT_UserCallback(3);
  56.                    break;
  57.                 }       
  58.         }
  59.        
  60.         W25QXX_CS=1;                               //取消片选
  61.        
  62.         return byte;   
  63. }
  64. //写W25QXX状态寄存器
  65. //只有SPR,TB,BP2,BP1,BP0(bit 7,5,4,3,2)可以写!!!
  66. void W25QXX_Write_SR(u8 sr)   
  67. {   
  68.         W25QXX_CS=0;                              //使能器件   
  69.         SPI1_ReadWriteByte(W25X_WriteStatusReg);  //发送写取状态寄存器命令   
  70.         SPI1_ReadWriteByte(sr);                   //写入一个字节  
  71.         W25QXX_CS=1;                              //取消片选                  
  72. }   
  73. //W25QXX写使能           等待知道空闲状态
  74. //将WEL置位   
  75. void W25QXX_Write_Enable(void)   
  76. {
  77.         W25QXX_CS=0;                              //使能器件   
  78.   SPI1_ReadWriteByte(W25X_WriteEnable);   //发送写使能
  79.         W25QXX_CS=1;                              //取消片选                  
  80. }
  81. //W25QXX写禁止       
  82. //将WEL清零  
  83. void W25QXX_Write_Disable(void)   
  84. {  
  85.         W25QXX_CS=0;                             //使能器件   
  86.     SPI1_ReadWriteByte(W25X_WriteDisable); //发送写禁止指令   
  87.         W25QXX_CS=1;                             //取消片选                  
  88. }                
  89. //读取芯片ID
  90. //返回值如下:                                  
  91. //0XEF13,表示芯片型号为W25Q80  
  92. //0XEF14,表示芯片型号为W25Q16   
  93. //0XEF15,表示芯片型号为W25Q32  
  94. //0XEF16,表示芯片型号为W25Q64
  95. //0XEF17,表示芯片型号为W25Q128           
  96. u16 W25QXX_ReadID(void)
  97. {
  98.         u16 Temp = 0;          
  99.         W25QXX_CS=0;                                    
  100.         SPI1_ReadWriteByte(0x90);//发送读取ID命令            
  101.         SPI1_ReadWriteByte(0x00);             
  102.         SPI1_ReadWriteByte(0x00);             
  103.         SPI1_ReadWriteByte(0x00);                                    
  104.         Temp|=SPI1_ReadWriteByte(0xFF)<<8;  
  105.         Temp|=SPI1_ReadWriteByte(0xFF);         
  106.         W25QXX_CS=1;                                    
  107.         return Temp;
  108. }                       
  109. //读取SPI FLASH  
  110. //在指定地址开始读取指定长度的数据
  111. //pBuffer:数据存储区
  112. //ReadAddr:开始读取的地址(24bit)
  113. //NumByteToRead:要读取的字节数(最大65535)
  114. void W25QXX_Read(u8* buf,u32 ReadAddr,u16 NumByteToRead)   
  115. {
  116.         u16 i;                                                                                       
  117.         W25QXX_CS=0;                            //使能器件   
  118.   SPI1_ReadWriteByte(W25X_ReadData);         //发送读取命令   
  119.   SPI1_ReadWriteByte((u8)((ReadAddr)>>16));  //发送24bit地址   
  120.   SPI1_ReadWriteByte((u8)((ReadAddr)>>8));   
  121.   SPI1_ReadWriteByte((u8)ReadAddr);   
  122.   for(i=0;i<NumByteToRead;i++)
  123.         {
  124.        *buf=SPI1_ReadWriteByte(0XFF);   //循环读数
  125.         buf++;               
  126.   }
  127.         W25QXX_CS=1;                                                   
  128. }  
  129. //SPI在一页(0~65535)内写入少于256个字节的数据
  130. //在指定地址开始写入最大256字节的数据
  131. //pBuffer:数据存储区
  132. //WriteAddr:开始写入的地址(24bit)
  133. //NumByteToWrite:要写入的字节数(最大256),该数不应该超过该页的剩余字节数!!!         
  134. void W25QXX_Write_Page(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite)
  135. {
  136.         u16 i;  
  137.     W25QXX_Write_Enable();                  //SET WEL
  138.         W25QXX_CS=0;                            //使能器件   
  139.     SPI1_ReadWriteByte(W25X_PageProgram);      //发送写页命令   
  140.     SPI1_ReadWriteByte((u8)((WriteAddr)>>16)); //发送24bit地址   
  141.     SPI1_ReadWriteByte((u8)((WriteAddr)>>8));   
  142.     SPI1_ReadWriteByte((u8)WriteAddr);   
  143.     for(i=0;i<NumByteToWrite;i++)SPI1_ReadWriteByte(pBuffer[i]);//循环写数  
  144.         W25QXX_CS=1;                            //取消片选
  145.         W25QXX_Wait_Busy();                                           //等待写入结束
  146. }
  147. //无检验写SPI FLASH
  148. //必须确保所写的地址范围内的数据全部为0XFF,否则在非0XFF处写入的数据将失败!
  149. //具有自动换页功能
  150. //在指定地址开始写入指定长度的数据,但是要确保地址不越界!
  151. //pBuffer:数据存储区
  152. //WriteAddr:开始写入的地址(24bit)
  153. //NumByteToWrite:要写入的字节数(最大65535)
  154. //CHECK OK
  155. void W25QXX_Write_NoCheck(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite)   
  156. {                                           
  157.         u16 pageremain;          
  158.         pageremain=256-WriteAddr%256; //单页剩余的字节数                             
  159.         if(NumByteToWrite<=pageremain)pageremain=NumByteToWrite;//不大于256个字节
  160.         while(1)
  161.         {          
  162.                 W25QXX_Write_Page(pBuffer,WriteAddr,pageremain);
  163.                 if(NumByteToWrite==pageremain)break;//写入结束了
  164.                  else //NumByteToWrite>pageremain
  165.                 {
  166.                         pBuffer+=pageremain;
  167.                         WriteAddr+=pageremain;       

  168.                         NumByteToWrite-=pageremain;                          //减去已经写入了的字节数
  169.                         if(NumByteToWrite>256)pageremain=256; //一次可以写入256个字节
  170.                         else pageremain=NumByteToWrite;           //不够256个字节了
  171.                 }
  172.         };            
  173. }
  174. //写SPI FLASH  
  175. //在指定地址开始写入指定长度的数据
  176. //该函数带擦除操作!
  177. //pBuffer:数据存储区
  178. //WriteAddr:开始写入的地址(24bit)                                               
  179. //NumByteToWrite:要写入的字节数(最大65535)   
  180. u8 W25QXX_BUFFER[4096];                 
  181. void W25QXX_Write(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite)   
  182. {
  183.         u32 secpos;
  184.         u16 secoff;
  185.         u16 secremain;          
  186.         u16 i;   
  187.         u8 * W25QXX_BUF;          
  188.            W25QXX_BUF=W25QXX_BUFFER;             
  189.         secpos=WriteAddr/4096;//扇区地址  
  190.         secoff=WriteAddr%4096;//在扇区内的偏移
  191.         secremain=4096-secoff;//扇区剩余空间大小   
  192. //         printf("ad:%X,nb:%X\r\n",WriteAddr,NumByteToWrite);//测试用
  193.         if(NumByteToWrite<=secremain)secremain=NumByteToWrite;//不大于4096个字节
  194.         while(1)
  195.         {       
  196.                 W25QXX_Read(W25QXX_BUF,secpos*4096,4096);//读出整个扇区的内容
  197.                 for(i=0;i<secremain;i++)//校验数据
  198.                 {
  199.                         if(W25QXX_BUF[secoff+i]!=0XFF)break;//需要擦除            
  200.                 }
  201.                 if(i<secremain)//需要擦除
  202.                 {
  203.                         W25QXX_Erase_Sector(secpos);//擦除这个扇区
  204.                         for(i=0;i<secremain;i++)           //复制
  205.                         {
  206.                                 W25QXX_BUF[i+secoff]=pBuffer[i];          
  207.                         }
  208.                         W25QXX_Write_NoCheck(W25QXX_BUF,secpos*4096,4096);//写入整个扇区  

  209.                 }else W25QXX_Write_NoCheck(pBuffer,WriteAddr,secremain);//写已经擦除了的,直接写入扇区剩余区间.                                   
  210.                 if(NumByteToWrite==secremain)break;//写入结束了
  211.                 else//写入未结束
  212.                 {
  213.                         secpos++;//扇区地址增1
  214.                         secoff=0;//偏移位置为0          

  215.                            pBuffer+=secremain;  //指针偏移
  216.                         WriteAddr+=secremain;//写地址偏移          
  217.                            NumByteToWrite-=secremain;                                //字节数递减
  218.                         if(NumByteToWrite>4096)secremain=4096;        //下一个扇区还是写不完
  219.                         else secremain=NumByteToWrite;                        //下一个扇区可以写完了
  220.                 }         
  221.         };         
  222. }
  223. //擦除整个芯片                  
  224. //等待时间超长...
  225. void W25QXX_Erase_Chip(void)   
  226. {                                   
  227.     W25QXX_Write_Enable();                  //SET WEL
  228.     W25QXX_Wait_Busy();   
  229.           W25QXX_CS=0;                            //使能器件   
  230.     SPI1_ReadWriteByte(W25X_ChipErase);        //发送片擦除命令  
  231.         W25QXX_CS=1;                            //取消片选                  
  232.         W25QXX_Wait_Busy();                                      //等待芯片擦除结束
  233. }   
  234. //擦除一个扇区
  235. //Dst_Addr:扇区地址 根据实际容量设置
  236. //擦除一个山区的最少时间:150ms
  237. void W25QXX_Erase_Sector(u32 Dst_Addr)   
  238. {  
  239.         //监视falsh擦除情况,测试用   
  240.         printf("擦除的扇区地址为:%x\r\n",Dst_Addr);          
  241.         Dst_Addr*=4096;
  242.   W25QXX_Write_Enable();                  //SET WEL          
  243.   W25QXX_Wait_Busy();   
  244.   W25QXX_CS=0;                            //使能器件   
  245.   SPI1_ReadWriteByte(W25X_SectorErase);      //发送扇区擦除指令
  246.   SPI1_ReadWriteByte((u8)((Dst_Addr)>>16));  //发送24bit地址   
  247.   SPI1_ReadWriteByte((u8)((Dst_Addr)>>8));   
  248.   SPI1_ReadWriteByte((u8)Dst_Addr);  
  249.         W25QXX_CS=1;                            //取消片选                  
  250.   W25QXX_Wait_Busy();                                      //等待擦除完成
  251.   printf("falsh擦除ok!\r\n");    //测试用
  252. }  
  253. //等待空闲
  254. void W25QXX_Wait_Busy(void)   
  255. {   
  256.         while((W25QXX_ReadSR()&0x01)==0x01);   // 等待BUSY位清空
  257. }





  258. //进入掉电模式
  259. void W25QXX_PowerDown(void)   
  260. {
  261.           W25QXX_CS=0;                            //使能器件   
  262.     SPI1_ReadWriteByte(W25X_PowerDown);        //发送掉电命令  
  263.         W25QXX_CS=1;                            //取消片选                  
  264.     delay_us(3);                               //等待TPD  
  265. }   
  266. //唤醒
  267. void W25QXX_WAKEUP(void)   
  268. {  
  269.           W25QXX_CS=0;                            //使能器件   
  270.     SPI1_ReadWriteByte(W25X_ReleasePowerDown);   //  send W25X_PowerDown command 0xAB   
  271.         W25QXX_CS=1;                            //取消片选                  
  272.     delay_us(3);                               //等待TRES1
  273. }   




复制代码
这是W25Q128.h文件:
  1. #ifndef _flash_H
  2. #define _flash_H

  3. #include "system.h"

  4. //W25X系列/Q系列芯片列表          
  5. //W25Q80  ID  0XEF13
  6. //W25Q16  ID  0XEF14
  7. //W25Q32  ID  0XEF15
  8. //W25Q64  ID  0XEF16       
  9. //W25Q128 ID  0XEF17       
  10. #define W25Q80         0XEF13        
  11. #define W25Q16         0XEF14
  12. #define W25Q32         0XEF15
  13. #define W25Q64         0XEF16
  14. #define W25Q128        0XEF17

  15. #define NM25Q80         0X5213
  16. #define NM25Q16         0X5214
  17. #define NM25Q32         0X5215
  18. #define NM25Q64         0X5216
  19. #define NM25Q128        0X5217
  20. #define NM25Q256         0X5218

  21. extern u16 W25QXX_TYPE;                                        //定义W25QXX芯片型号                  

  22. #define        W25QXX_CS                 PBout(14)                  //W25QXX的片选信号

  23. //////////////////////////////////////////////////////////////////////////////////
  24. //指令表
  25. #define W25X_WriteEnable                0x06
  26. #define W25X_WriteDisable                0x04
  27. #define W25X_ReadStatusReg                0x05
  28. #define W25X_WriteStatusReg                0x01
  29. #define W25X_ReadData                        0x03
  30. #define W25X_FastReadData                0x0B
  31. #define W25X_FastReadDual                0x3B
  32. #define W25X_PageProgram                0x02
  33. #define W25X_BlockErase                        0xD8
  34. #define W25X_SectorErase                0x20
  35. #define W25X_ChipErase                        0xC7
  36. #define W25X_PowerDown                        0xB9
  37. #define W25X_ReleasePowerDown        0xAB
  38. #define W25X_DeviceID                        0xAB
  39. #define W25X_ManufactDeviceID        0x90
  40. #define W25X_JedecDeviceID                0x9F

  41. void W25QXX_Init(void);
  42. u16  W25QXX_ReadID(void);                              //读取FLASH ID
  43. u8         W25QXX_ReadSR(void);                        //读取状态寄存器
  44. void W25QXX_Write_SR(u8 sr);                          //写状态寄存器
  45. void W25QXX_Write_Enable(void);                  //写使能
  46. void W25QXX_Write_Disable(void);                //写保护
  47. void W25QXX_Write_NoCheck(u8* buf,u32 WriteAddr,u16 NumByteToWrite);
  48. void W25QXX_Read(u8* pBuffer,u32 ReadAddr,u16 NumByteToRead);   //读取flash
  49. void W25QXX_Write(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite);//写入flash
  50. void W25QXX_Erase_Chip(void);                      //整片擦除
  51. void W25QXX_Erase_Sector(u32 Dst_Addr);        //扇区擦除
  52. void W25QXX_Wait_Busy(void);                   //等待空闲
  53. void W25QXX_PowerDown(void);                //进入掉电模式
  54. void W25QXX_WAKEUP(void);                                //唤醒
  55. #endif


复制代码
这是spi.c文件:
  1. #include "spi.h"
  2. #include "usart.h"

  3. /*
  4. 1.初始化相关引脚及SPI工作模式
  5. 2.编写基本的读写单个字节的流程函数
  6. 3.利用2的函数来组成各种命令
  7. 4.利用命令读写FLASH并校验数据
  8. */
  9. static volatile uint32_t SPITimeout = SPIT_FLAG_TIMEOUT;
  10.        
  11. void SPI1_Init(void)
  12. {         
  13.   GPIO_InitTypeDef  GPIO_InitStructure;
  14.   SPI_InitTypeDef  SPI_InitStructure;
  15.        
  16.   RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);//使能GPIOB时钟
  17.   RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);//使能SPI1时钟

  18.   //GPIOFB3,4,5初始化设置
  19.   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5;//PB3~5复用功能输出       
  20.   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用功能
  21.   GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
  22.   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
  23.   GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
  24.   GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化
  25.        
  26.         GPIO_PinAFConfig(GPIOB,GPIO_PinSource3,GPIO_AF_SPI1); //PB3复用为 SPI1
  27.         GPIO_PinAFConfig(GPIOB,GPIO_PinSource4,GPIO_AF_SPI1); //PB4复用为 SPI1
  28.         GPIO_PinAFConfig(GPIOB,GPIO_PinSource5,GPIO_AF_SPI1); //PB5复用为 SPI1

  29.         //这里只针对SPI口初始化
  30.         RCC_APB2PeriphResetCmd(RCC_APB2Periph_SPI1,ENABLE);//复位SPI1
  31.         RCC_APB2PeriphResetCmd(RCC_APB2Periph_SPI1,DISABLE);//停止复位SPI1

  32.         SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;  //设置SPI单向或者双向的数据模式:SPI设置为双线双向全双工
  33.         SPI_InitStructure.SPI_Mode = SPI_Mode_Master;                //设置SPI工作模式:设置为主SPI
  34.         SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;                //设置SPI的数据大小:SPI发送接收8位帧结构
  35.         SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;                //串行同步时钟的空闲状态为高电平
  36.         SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;        //串行同步时钟的第二个跳变沿(上升或下降)数据被采样
  37.         SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;                //NSS信号由硬件(NSS管脚)还是软件(使用SSI位)管理:内部NSS信号有SSI位控制
  38.         SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;                //定义波特率预分频的值:波特率预分频值为256
  39.         SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;        //指定数据传输从MSB位还是LSB位开始:数据传输从MSB位开始
  40.         SPI_InitStructure.SPI_CRCPolynomial = 7;        //CRC值计算的多项式
  41.         SPI_Init(SPI1, &SPI_InitStructure);  //根据SPI_InitStruct中指定的参数初始化外设SPIx寄存器

  42.         SPI_Cmd(SPI1, ENABLE); //使能SPI外设

  43.         SPI1_ReadWriteByte(0xff);//启动传输                 
  44. }   
  45. //SPI1速度设置函数
  46. //SPI速度=fAPB2/分频系数
  47. //[url=home.php?mod=space&uid=203608]@Ref[/url] SPI_BaudRate_Prescaler:SPI_BaudRatePrescaler_2~SPI_BaudRatePrescaler_256  
  48. //fAPB2时钟一般为84Mhz:
  49. void SPI1_SetSpeed(u8 SPI_BaudRatePrescaler)
  50. {
  51.   assert_param(IS_SPI_BAUDRATE_PRESCALER(SPI_BaudRatePrescaler));//判断有效性
  52.         SPI1->CR1&=0XFFC7;//位3-5清零,用来设置波特率
  53.         SPI1->CR1|=SPI_BaudRatePrescaler;        //设置SPI1速度
  54.         SPI_Cmd(SPI1,ENABLE); //使能SPI1
  55. }
  56. //SPI1 读写一个字节
  57. //TxData:要写入的字节
  58. //返回值:读取到的字节
  59. u8 SPI1_ReadWriteByte(u8 TxData)
  60. {                                          
  61.   
  62.   while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET)     //等待发送区空  (等待TXE)
  63.         {               
  64.                         if((SPITimeout --) == 0)   
  65.                                   return SPI_TIMEOUT_UserCallback(1);
  66.         }
  67.        
  68.         SPI_I2S_SendData(SPI1, TxData); //通过外设SPIx发送一个byte  数据
  69.        
  70.         SPITimeout =         SPIT_FLAG_TIMEOUT;
  71.   while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET)   //等待接收完一个byte  
  72.   {
  73.                         if((SPITimeout --) == 0)   
  74.                                         return SPI_TIMEOUT_UserCallback(2);
  75.         }

  76.         return SPI_I2S_ReceiveData(SPI1); //返回通过SPIx最近接收的数据       
  77.                     
  78. }



  79. uint32_t SPI_TIMEOUT_UserCallback(uint8_t errorCode)
  80. {
  81.                 switch(errorCode)
  82.                 {
  83.                   case 1 : printf("SPI等待发送区一直不为空!errorCode = %d",errorCode); break;
  84.                   case 2 : printf("SPI等待发送区一直为空!  errorCode = %d",errorCode); break;
  85.                   case 3 : printf("W25QXX写使能失败!      errorCode = %d",errorCode); break;
  86.                   default: printf("SPI错误"); break;       
  87.                 }
  88.                
  89.           return 0;
  90. }






复制代码
这是spi.h文件:
  1. #ifndef _spi_H
  2. #define _spi_H


  3. #include "system.h"

  4. #define  SPIT_FLAG_TIMEOUT   ((uint32_t)0x1000)
  5. //#define SPI_LONG_TIMEOUT  ()



  6. u8 SPI1_ReadWriteByte(u8 TxData);
  7. void SPI1_SetSpeed(u8 SPI_BaudRatePrescaler);
  8. void SPI1_Init(void);

  9. uint32_t SPI_TIMEOUT_UserCallback(uint8_t errorCode);
  10. #endif
复制代码

这是main.c文件:
  1. #include "system.h"
  2. #include "led.h"
  3. #include "SysTick.h"
  4. #include "tftlcd.h"
  5. #include "usart.h"
  6. #include "spi.h"
  7. #include "flash.h"
  8. #include "key.h"

  9. //要写入到W25Q16的字符串数组
  10. const u8 TEXT_Buffer[] = {"SPI TEST"};
  11. #define SIZE sizeof(TEXT_Buffer)


  12. u8 read_buf111[4096] = {0};

  13. int main()
  14. {
  15.         u16 itime = 0;              //必须初始化为0
  16.         u8  key   = 0;
  17.         u8 lcd_id[12];             //存放LCD ID字符串
  18.        
  19.         u32 imun = 0;
  20.        
  21.         u32 FLASH_SIZE;
  22.         u16 id = 0;
  23.         u8 datatemp[SIZE];
  24.        
  25.         SysTick_Init(168);         //系统时钟168M
  26.         NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
  27.         USART1_Init(115200);
  28.        
  29.         LCD_Init();
  30.   LED_Init();
  31.         KEY_Init();
  32.         W25QXX_Init();
  33.         POINT_COLOR = RED;        //画笔颜色: 红色
  34.         sprintf((char*)lcd_id,"LCD ID:%04X",lcddev.id);//将LCD ID打印到lcd_id数组。       
  35.         LCD_ShowString(30,50,210,16,16,"Explorer STM32F4");
  36.         LCD_ShowString(30,70,200,16,16,"Sunny!");
  37.         LCD_ShowString(30,90,200,16,16,"ATOM@ALIENTEK");
  38.         LCD_ShowString(30,110,200,16,16,lcd_id);              //显示LCD ID

  39.         while(1)       
  40.         {
  41.                   id = W25QXX_ReadID();
  42.                         printf("W25Q128 = OX%X\r\n",id);
  43.                   if(id == W25Q128 || id == NM25Q128)  break;                  
  44.             LCD_ShowString(30,150,200,16,16,"W25Q128 Check Failed!");
  45.                         delay_ms(500);       
  46.             LCD_ShowString(30,150,200,16,16,"Please Check!");
  47.                         delay_ms(500);
  48.                         led2 =  !led2;
  49.         }
  50.         LCD_ShowString(30,150,200,16,16,"W25Q128 Ready!");
  51.         FLASH_SIZE= 16*1024*1024;       //FLASH 大小为16字节
  52.         POINT_COLOR = BLUE;             //设置字体为蓝色
  53.        
  54.        
  55.         W25QXX_Erase_Sector(0);
  56.        
  57.         W25QXX_Read(read_buf111,0,4096);
  58.        
  59.         for(imun = 0; imun < 4096; imun++)
  60.         {
  61.                   //若不等于oxff,说明擦除不成功
  62.             if(read_buf111[imun] != 0XFF)
  63.                         {
  64.                                  printf("擦除校验失败\r\n");
  65.                         }
  66.        
  67.         }
  68.         printf("擦除校验完成\r\n");
  69.        
  70.         while(1)
  71.         {
  72.                   
  73.             key = KEY_Scan(0);
  74.                   if(key == K_LEFT)  //K_UP按下,写下W25Q128
  75.                         {
  76.                                  LCD_Fill(0,170,239,319,WHITE);   //清除半屏
  77.                LCD_ShowString(30,170,200,16,16,"Start Write W25Q128...");
  78.                                  W25QXX_Write((u8*)TEXT_Buffer,FLASH_SIZE - 100, SIZE);    //
  79.                LCD_ShowString(30,190,200,16,16,"W25Q128 Write Finished!");   //提示传送完成       
  80.                         //         while(K_LEFT == KEY_Scan(0));
  81.                         }
  82.                         if(key==K_RIGHT)//K_DOWN按下,读取字符串并显示
  83.                  {
  84.                            LCD_Fill(0,170,239,319,WHITE);   //清除半屏
  85.                            LCD_ShowString(30,170,200,16,16,"Start Read W25Q128.... ");
  86.                            W25QXX_Read(datatemp,FLASH_SIZE-100,SIZE);                                        //从倒数第100个地址处开始,读出SIZE个字节
  87.                            LCD_ShowString(30,190,200,16,16,"The Data Readed Is:");        //提示传送完成
  88.                            LCD_ShowString(30,210,220,16,16,datatemp);                                        //显示读到的字符串
  89.                            printf("datatemp = %s",datatemp);

  90.                          //  while(K_RIGHT == KEY_Scan(0));

  91.                  }
  92.            itime++;
  93.                  delay_ms(10);
  94.                  if(itime == 20)
  95.                  {
  96.                      led1 = !led1;   //提示系统正在运行
  97.                      itime = 0;
  98.                  }       
  99.         }                       
  100. }
  101.        
  102.        
  103.        

复制代码




正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

0

主题

9

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
385
金钱
385
注册时间
2018-5-29
在线时间
103 小时
发表于 2022-8-3 14:37:36 | 显示全部楼层
强烈建议更换一下芯片试试,这么长谁能帮你仔细看呢,需要自己去找。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-5-3 10:51

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表