[单片机芯片] 【CH32F207VCT6】开发例程+09硬件SPI驱动存储芯片

[复制链接]
173|0
聪聪哥哥 发表于 2025-8-31 10:12 | 显示全部楼层 |阅读模式
一:W25Q64芯片介绍:
 W25Q64 是一款常见的串行 Flash 存储器芯片,由华邦(Winbond)公司生产。它的存储容量为 64Mbit(8MB),采用 SPI(串行外设接口)进行通信,常用于嵌入式系统中存储代码或数据。
1.2 参数特性:
   存储容量:64Mbit(相当于8MByte)可以存储大量数据
   接口:采用 SPI接口
   工作电压范围:2.7V~3.6V,典型 3.3V供电设备
    擦除功能:支持扇区、块和整个芯片擦除功能,4KB、32KB、64KB 和整个芯片的擦除操作工作温度范围:-40°C~+85°C的温度范围

    W25Q64 存储容量:8MB 分为128个块
    1页=256字节(Byte)
    1扇区=16页=16*256字节(Byte)=4096Byte/1024=4KB
    1块=16扇区=16*16*256字节(Byte)=65536Byte/1024=64KB
    则128块=128*16*16*256字节(Byte)=8388608 Byte/
二:W25Q64操作注意事项:
W25Q64 的基本操作遵循 SPI 协议,一般流程是:片选拉低 → 发送命令字 → 发送地址(如需)→ 交换数据 → 片选拉高。
2.1:写使能(Write Enable, 06h):在执行任何编程或擦除操作前,必须先发送写使能指令。该指令会将状态寄存器中的写使能锁存(WEL)
2.2:页编程(Page Program, 02h):向指定地址写入数据。一次最多写入256字节(一页),且不能跨页写入。如果写入数据地址会跨页,超出页首地址部分会从当前页的开头覆写8。写入前必须确保目标区域已被擦除。
2.3:扇区擦除(Sector Erase, 20h):擦除指定4KB扇区。擦除操作会将所有位变为1。擦除前需写使能。
2.4:块擦除(Block Erase):提供32KB (52h) 和64KB (D8h) 块擦除选项。
2.5:芯片擦除(Chip Erase, C7h / 60h):擦除整个芯片。谨慎使用。
2.6:读数据(Read Data, 03h):从指定地址开始读取数据。读取操作没有页的限制8。
2.7:读状态寄存器(Read Status Register, 05h):主要用于检查 BUSY 位(S0)和 WEL 位(S1)。在编程、擦除或写状态寄存器期间,BUSY位会置1,此时芯片仅响应读状态寄存器和擦除暂停等少数指令。
读设备ID:如 Read JEDEC ID (9Fh) 可用于识别器件。

三:这里我所使用的是SPI1驱动存储芯片
CH32F207 硬件SPI的时序图如下所示:
08-3.png
3.1 SPI的初始化:
  1. void SPI_Flash_Init( void )
  2. {
  3.     GPIO_InitTypeDef GPIO_InitStructure = {0};
  4.     SPI_InitTypeDef  SPI_InitStructure = {0};

  5.     RCC_APB2PeriphClockCmd(        RCC_APB2Periph_GPIOA | RCC_APB2Periph_SPI1, ENABLE );

  6.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
  7.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  8.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  9.     GPIO_Init( GPIOA, &GPIO_InitStructure );
  10.     GPIO_SetBits( GPIOA, GPIO_Pin_2 );

  11.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
  12.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  13.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  14.     GPIO_Init( GPIOA, &GPIO_InitStructure );

  15.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
  16.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  17.     GPIO_Init( GPIOA, &GPIO_InitStructure );

  18.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
  19.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  20.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  21.     GPIO_Init( GPIOA, &GPIO_InitStructure );

  22.     SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
  23.     SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
  24.     SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
  25.     SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;
  26.     SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
  27.     SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
  28.     SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;
  29.     SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
  30.     SPI_InitStructure.SPI_CRCPolynomial = 7;
  31.     SPI_Init( SPI1, &SPI_InitStructure );

  32.     SPI_Cmd( SPI1, ENABLE );
  33. }
这里需要注意下:SPI通信中的时钟极性(CPOL)和时钟相位(CPHA)是两个关键参数。它们定义了时钟信号在空闲状态下的电平和数据采样的时机。当时是利用硬件的SPI读取两个芯片,一个是存储芯片(W25Q64),一个是AD芯片(CS5530),由于这个两个芯片的时序不一致,一个是在上升沿读取数据,另外一个是在下降沿读取数据,当时也是调试好久才发现,时序不一致,当初也是刚毕业不久,也没有太多的工作经验,还以为是芯片损坏,现在想起来还是真的小白了。后来工作时间久了才发现,影响SPI通讯不正常的原因有很多,需要注意硬件连接、通信协议与时序、数据传输等方面。
3.2 硬件SPI发送字节的函数如下所示:
  1. u8 SPI1_ReadWriteByte( u8 TxData )
  2. {
  3.     u8 i = 0;
  4.     while( SPI_I2S_GetFlagStatus( SPI1, SPI_I2S_FLAG_TXE ) == RESET );
  5.     SPI_I2S_SendData( SPI1, TxData );
  6.     i = 0;
  7.     while( SPI_I2S_GetFlagStatus( SPI1, SPI_I2S_FLAG_RXNE ) == RESET );
  8.     return SPI_I2S_ReceiveData( SPI1 );
  9. }
3.3 写入一页的函数如下:
  1. void W25QXX_Write_Page(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite)
  2. {
  3.         uint16_t i;  
  4.     W25QXX_Write_Enable();                  //SET WEL
  5.           FLASH_CS_LOW() ;                             //使能器件   
  6.     SPI1_ReadWriteByte(W25X_PageProgram);   //发送写页命令   
  7.     SPI1_ReadWriteByte((uint8_t)((WriteAddr)>>16)); //发送24bit地址   
  8.     SPI1_ReadWriteByte((uint8_t)((WriteAddr)>>8));   
  9.     SPI1_ReadWriteByte((uint8_t)WriteAddr);   
  10.     for(i=0;i<NumByteToWrite;i++)SPI1_ReadWriteByte(pBuffer[i]);//循环写数  
  11.                 FLASH_CS_HIGH();;                                    //取消片选
  12.           W25QXX_Wait_Busy();                                           //等待写入结束
  13. }
写入时候的注意事项:
1.每次写入操作前都必须进行写使能指令
2.由于 FLASH 存储器的特性决定了我们再写入数据时候,首先需要擦除数据,否则会导致数据存储错乱,芯片的特性决定只能由1写成0,而不能由0写成1,所以在写入新数据时候,务必擦除
3.擦除必须以最小擦除单元进行,也就是最少要进行一个扇区大小 4KB 的擦除4.写入数据都是先放到 256 字节的页缓存区,然后再转移到 FLASH 内,由于页缓冲区大小限制,所以每次最多写入一页的数据,超过页尾位置的数据会回到页首覆盖写入
5.在执行写入和擦除操作后,芯片会进入忙状态,这时不能进行读写操作,可以通过查看状态寄存器的 BUSY 位来判断芯片是否退出忙状态
3.4 读取一页的函数如下所示:
  1. void W25QXX_Read(uint8_t* pBuffer,uint32_t ReadAddr,uint16_t NumByteToRead)   
  2. {
  3.         uint16_t i;                                                                                       
  4.         FLASH_CS_LOW() ;                           //使能器件   
  5.     SPI1_ReadWriteByte(W25X_ReadData);      //发送读取命令  
  6.     if(W25QXX_TYPE==W25Q256)                //如果是W25Q256的话地址为4字节的,要发送最高8位
  7.     {
  8.         SPI1_ReadWriteByte((uint8_t)((ReadAddr)>>24));   
  9.     }
  10.     SPI1_ReadWriteByte((uint8_t)((ReadAddr)>>16));   //发送24bit地址   
  11.     SPI1_ReadWriteByte((uint8_t)((ReadAddr)>>8));   
  12.     SPI1_ReadWriteByte((uint8_t)ReadAddr);   
  13.     for(i=0;i<NumByteToRead;i++)
  14.         {
  15.         pBuffer[i]=SPI1_ReadWriteByte(0XFF);    //循环读数  
  16.     }
  17.                 FLASH_CS_HIGH();;                                                           
  18. }
四:测试读写函数如下所示:
  1. void Test_SPI_Funtion(void)
  2. {
  3.    WriteBuffer24C02[0]= 0xFA ;
  4.    WriteBuffer24C02[1]= 0xFB ;
  5.    WriteBuffer24C02[2]= 0xFC ;
  6.    WriteBuffer24C02[3]= 0x05 ;
  7.    WriteBuffer24C02[4]= 0xC0 ;
  8.    WriteBuffer24C02[5]= 0x01 ;
  9.    WriteBuffer24C02[6]= 0x02 ;
  10.    W25QXX_Write(&WriteBuffer24C02[0],0,7);
  11.    Delay_Us(50);
  12.     W25QXX_Read(&ReadBuffer24C02[0],0,7) ;
五:实物测试如下所示:
09-1.jpg

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

本版积分规则

100

主题

252

帖子

1

粉丝
快速回复 在线客服 返回列表 返回顶部