STM32F1SPI标准接口程序以及模拟SPI标准接口程序讲解
一、SPI标准接口初始化:
1、SPI 内部结构简明图
2、上一篇文章提到,spi标准协议包含4条信号线、时钟相位、时钟极性、数据单字节从高位到低位传输、片选信号可以由软件控制,也可以由硬件控制,依据以上内容初始化SPI标准接口程序如下:
void SPI2_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
SPI_InitTypeDef SPI_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE );
RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE );
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_SetBits(GPIOB,GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15);
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;
SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_InitStructure.SPI_CRCPolynomial = 7;
SPI_Init(SPI2, &SPI_InitStructure);
SPI_Cmd(SPI2, ENABLE);
SPI2_ReadWriteByte(0xff);
}
(1)IO口初始化: 要用 SPI2,第一步就要使能 SPI2 的时钟。其次要设置 SPI2 的相关引脚为复用输出,这样才会连接到 SPI2 上否则这些 IO 口还是默认的状态,也就是标准输入输出口。这里使用的是 PB13、14、15 这 3 个(SCK.、MISO、MOSI,CS 使用软件管理方式),所以设置这三个为复用 IO。 (2)初始化SPI标准接口(结构体): 第一个参数 SPI_Direction 是用来设置 SPI 的通信方式,可以选择为半双工,全双工,以及串行发和串行收方式,这里选择全双工模式 SPI_Direction_2Lines_FullDuplex。 第二个参数 SPI_Mode 用来设置 SPI 的主从模式,这里设置为主机模式 SPI_Mode_Master,当然也可以选择为从机模式 SPI_Mode_Slave。 第三个参数 SPI_DataSiz 为 8 位还是 16 位帧格式选择项,这里是 8 位传输,选择SPI_DataSize_8b。 第四个参数 SPI_CPOL 用来设置时钟极性,设置串行同步时钟的空闲状态为高电平所以选择 SPI_CPOL_High。 第五个参数 SPI_CPHA 用来设置时钟相位,也就是选择在串行同步时钟的第几个跳变沿(上升或下降)数据被采样,可以为第一个或者第二个条边沿采集,这里选择第二个跳变沿,所以选择 SPI_CPHA_2Edge 第六个参数 SPI_NSS 设置 NSS 信号由硬件(NSS 管脚)还是软件控制,这里通过软件控制 NSS 关键,而不是硬件自动控制,所以选择 SPI_NSS_Soft。 第七个参数 SPI_BaudRatePrescaler 很关键,就是设置 SPI 波特率预分频值也就是决定 SPI 的时钟的参数,从不分频道 256 分频 8 个可选值,初始化的时候选择 256 分频值SPI_BaudRatePrescaler_256, 传输速度为 36M/256=140.625KHz。 第八个参数 SPI_FirstBit 设置数据传输顺序是 MSB 位在前还是 LSB 位在前,这里选择SPI_FirstBit_MSB 高位在前。 第九个参数 SPI_CRCPolynomial 是用来设置 CRC 校验多项式,提高通信可靠性,大于 1 即可。 (3)使能 SPI2: 初始化完成之后接下来是要使能 SPI2 通信了,在使能 SPI2 之后,就可以开始 SPI 通讯了。使能 SPI2 的方法是: SPI_Cmd(SPI2, ENABLE); //使能 SPI 外设 (4)启动数据传输: 外设的写操作和读操作是同步完成的。如果只进行写操作,主机只需忽略接收到的字节;反之,若主机要读取从机的一个字节,就必须发送一个空字节来引发从机的传输。 3、标准SPI接口初始化程序写完后,开始写数据传输程序,程序如下:
u8 SPI2_ReadWriteByte(u8 TxData)
{
u8 retry=0;
while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET)
{
retry++;
if(retry>200)return 0;
}
SPI_I2S_SendData(SPI2, TxData);
retry=0;
while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET)
{ retry++;
if(retry>200)return 0;
}
return SPI_I2S_ReceiveData(SPI2);
}
(1)SPI 传输数据: 通信接口需要有发送数据和接受数据的函数,固件库提供的发送数据函数原型为: void SPI_I2S_SendData(SPI_TypeDef* SPIx, uint16_t Data); 往 SPIx 数据寄存器写入数据 Data,从而实现发送。 固件库提供的接受数据函数原型为: uint16_t SPI_I2S_ReceiveData(SPI_TypeDef* SPIx) ; 从 SPIx 数据寄存器读出接受到的数据。 (2)获取SPI 传输状态: SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE); SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE); ***(3)改变SPI 波特率预分频值从而改变数据传输速度的程序如下:***
void SPI2_SetSpeed(u8 SPI_BaudRatePrescaler)
{
assert_param(IS_SPI_BAUDRATE_PRESCALER(SPI_BaudRatePrescaler));
SPI2->CR1&=0XFFC7;
SPI2->CR1|=SPI_BaudRatePrescaler;
SPI_Cmd(SPI2,ENABLE);
}
至此SPI标准接口初始化程序就已完成了
二、STM32模拟SPI标准接口设计思路以及部分程序讲解
1、既然SPI标准协议是用4条信号线,那么首先需要初始化4个引脚,其中MISO引脚要初始化为输入引脚,其他三条信号线SCL,CS,MOSI引脚都初始化为输出引脚。 2、片选信号与时钟极性在初始化时将对应的引脚设置为高电平或低电平就对应不同的模式(所谓的时钟极性也就是在空闲状态下时钟信号的高低电平状态) 3、初始化设置好后就该写读写数据函数了,那么读写数据函数分为两种形式: (1)一种是分开读写,也就是读是一个函数,写是一个函数,分时传输数据,程序如下:
void SPI_WriteByte(uint8_t data)
{
uint8_t i = 0;
uint8_t temp = 0;
for(i=0; i<8; i++) {
temp = ((data&0x80)==0x80)? 1:0;
data = data<<1;
SPI_CLK(0);
SPI_MOSI(temp);
SPI_Delay();
SPI_CLK(1);
SPI_Delay(); }
SPI_CLK(0); }
uint8_t SPI_ReadByte(void) {
uint8_t i = 0;
uint8_t read_data = 0xFF;
for(i=0; i<8; i++) {
read_data = read_data << 1;
SPI_CLK(0);
SPI_Delay();
SPI_CLK(1);
SPI_Delay();
if(SPI_MISO()==1) {
read_data = read_data + 1; } }
SPI_CLK(0);
return read_data;
}
(2)另一种是读写数据是一个函数,同步传输数据,比如在时钟的上升沿是写数据,那么在时钟的下降沿就是读数据,程序如下:
uint8_t SPI_WriteReadByte(uint8_t data)
{
uint8_t i = 0;
uint8_t temp = 0;
uint8_t read_data = 0xFF;
for(i=0;i<8;i++) {
temp = ((data&0x80)==0x80)? 1:0;
data = data<<1;
read_data = read_data<<1;
SPI_CLK(0);
SPI_MOSI(temp);
SPI_Delay();
SPI_CLK(1);
SPI_Delay();
if(SPI_MISO()==1) {
read_data = read_data + 1; } }
SPI_CLK(0);
return read_data;
}
至此SPI标准接口模拟程序就已完成了
三、FLASH 介绍
1、Flash物理特性: 只能写0,不能写1,也就是说,当bit=1时,此bit可以写数据改变这个bit值,当bit=0时,说明此bit有数值了,不能再写了,只能擦除后再写数据。 2、结构组成: W25Q128 将 16M 的容量分为 256 个块(Block),每个块大小为 64K 字节,每个块又分为16 个扇区(Sector),每个扇区 4K 个字节。W25Q128 的最小擦除单位为一个扇区,也就是每次必须擦除 4K 个字节。这样我们需要给 W25Q128 开辟一个至少 4K 的缓存区,这样对 SRAM 要求比较高,要求芯片必须有 4K 以上 SRAM 才能很好的操作。 3、W25Q128 相关指令与函数 (1)初始化片选信号线
void W25QXX_CS(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE );
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_SetBits(GPIOB,GPIO_Pin_12);
}
#define W25QXX_CS PBout(12) //W25QXX的片选信号 (2)读写状态寄存器(0x05,0x01):
u8 W25QXX_ReadSR(void)
{
u8 byte=0;
W25QXX_CS=0;
SPI2_ReadWriteByte(0x05);
byte=SPI2_ReadWriteByte(0Xff);
W25QXX_CS=1;
return byte;
}
void W25QXX_Write_SR(u8 sr)
{
W25QXX_CS=0;
SPI2_ReadWriteByte(0x01);
SPI2_ReadWriteByte(sr);
W25QXX_CS=1;
}
(3)等待空闲,进入掉电模式(0xB9),唤醒flash(0xAB)函数
void W25QXX_Wait_Busy(void)
{
while((W25QXX_ReadSR()&0x01)==0x01);
}
void W25QXX_PowerDown(void)
{
W25QXX_CS=0;
SPI2_ReadWriteByte(W25X_PowerDown);
W25QXX_CS=1;
delay_us(3);
}
void W25QXX_WAKEUP(void)
{
W25QXX_CS=0;
SPI2_ReadWriteByte(W25X_ReleasePowerDown);
W25QXX_CS=1;
delay_us(3);
}
(4)写使能与写禁止(0x06,0x04):
void W25QXX_Write_Enable(void)
{
W25QXX_CS=0;
SPI2_ReadWriteByte(0x06);
W25QXX_CS=1;
}
void W25QXX_Write_Disable(void)
{
W25QXX_CS=0;
SPI2_ReadWriteByte(0x04);
W25QXX_CS=1;
}
(5)读制造商和芯片ID(90h) 先发送命令,再发送24位空字节,再接收16位地址,程序如下:
u16 W25QXX_ReadID(void)
{
u16 Temp = 0;
W25QXX_CS=0;
SPI2_ReadWriteByte(0x90);
SPI2_ReadWriteByte(0x00);
SPI2_ReadWriteByte(0x00);
SPI2_ReadWriteByte(0x00);
Temp|=SPI2_ReadWriteByte(0xFF)<<8;
Temp|=SPI2_ReadWriteByte(0xFF);
W25QXX_CS=1;
return Temp;
}
(6)读数据(0x03): 先发送读命令,再发送24位地址,再读取指定大小的数据,程序如下:
void W25QXX_Read(u8* pBuffer,u32 ReadAddr,u16 NumByteToRead)
{
u16 i;
W25QXX_CS=0;
SPI2_ReadWriteByte(W25X_ReadData);
SPI2_ReadWriteByte((u8)((ReadAddr)>>16));
SPI2_ReadWriteByte((u8)((ReadAddr)>>8));
SPI2_ReadWriteByte((u8)ReadAddr);
for(i=0;i<NumByteToRead;i++)
{
pBuffer[i]=SPI2_ReadWriteByte(0XFF);
}
W25QXX_CS=1;
}
或
void FLASH_BufferRead(uint8_t* pBuffer, uint32_t ReadAddr, uint16_t NumByteToRead)
{
W25_CS_ENABLE();
W25_RW_Byte(W25X_ReadData);
W25_RW_Byte((ReadAddr & 0xFF0000) >> 16);
W25_RW_Byte((ReadAddr& 0xFF00) >> 8);
W25_RW_Byte(ReadAddr & 0xFF);
while (NumByteToRead--) { *pBuffer = W25_RW_Byte(Dummy_Byte);
pBuffer++; }
W25_CS_DISABLE(); }
(7)页写函数(0x02)(只能按页写数据):
void W25QXX_Write_Page(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite)
{
u16 i;
W25QXX_Write_Enable();
W25QXX_CS=0;
SPI2_ReadWriteByte(W25X_PageProgram);
SPI2_ReadWriteByte((u8)((WriteAddr)>>16));
SPI2_ReadWriteByte((u8)((WriteAddr)>>8));
SPI2_ReadWriteByte((u8)WriteAddr);
for(i=0;i<NumByteToWrite;i++)SPI2_ReadWriteByte(pBuffer[i]);
W25QXX_CS=1;
W25QXX_Wait_Busy();
}
或
void FLASH_PageWrite(uint8_t* pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite)
{
Flash_WritenEN();
W25_CS_ENABLE();
W25_RW_Byte(W25X_PageProgram);
W25_RW_Byte((WriteAddr & 0xFF0000) >> 16);
W25_RW_Byte((WriteAddr & 0xFF00) >> 8);
W25_RW_Byte(WriteAddr & 0xFF);
if(NumByteToWrite > SPI_FLASH_PerWritePageSize) {
NumByteToWrite = SPI_FLASH_PerWritePageSize; }
while (NumByteToWrite--) {
W25_RW_Byte(*pBuffer);
pBuffer++; }
W25_CS_DISABLE();
FLASH_WaitForWriteEnd(); }
(8)擦除整个芯片(0xC7),擦除一个扇区(0x20):
void W25QXX_Erase_Chip(void)
{
W25QXX_Write_Enable();
W25QXX_Wait_Busy();
W25QXX_CS=0;
SPI2_ReadWriteByte(W25X_ChipErase);
W25QXX_CS=1;
W25QXX_Wait_Busy();
}
void W25QXX_Erase_Sector(u32 Dst_Addr)
{
printf("fe:%x\r\n",Dst_Addr);
Dst_Addr*=4096;
W25QXX_Write_Enable();
W25QXX_Wait_Busy();
W25QXX_CS=0;
SPI2_ReadWriteByte(W25X_SectorErase);
SPI2_ReadWriteByte((u8)((Dst_Addr)>>16));
SPI2_ReadWriteByte((u8)((Dst_Addr)>>8));
SPI2_ReadWriteByte((u8)Dst_Addr);
W25QXX_CS=1;
W25QXX_Wait_Busy();
}
(9)无检验页写SPI FLASH 函数:
void W25QXX_Write_NoCheck(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite)
{
u16 pageremain;
pageremain=256-WriteAddr%256;
if(NumByteToWrite<=pageremain)pageremain=NumByteToWrite;
while(1)
{
W25QXX_Write_Page(pBuffer,WriteAddr,pageremain);
if(NumByteToWrite==pageremain)break;
else
{
pBuffer+=pageremain;
WriteAddr+=pageremain;
NumByteToWrite-=pageremain;
if(NumByteToWrite>256)pageremain=256;
else pageremain=NumByteToWrite;
}
};
}
(10)检验是否擦除写SPI FLASH 函数:
u8 W25QXX_BUFFER[4096];
void W25QXX_Write(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite)
{
u32 secpos;
u16 secoff;
u16 secremain;
u16 i;
u8 * W25QXX_BUF;
W25QXX_BUF=W25QXX_BUFFER;
secpos=WriteAddr/4096;
secoff=WriteAddr%4096;
secremain=4096-secoff;
if(NumByteToWrite<=secremain)secremain=NumByteToWrite;
while(1)
{
W25QXX_Read(W25QXX_BUF,secpos*4096,4096);
for(i=0;i<secremain;i++)
{
if(W25QXX_BUF[secoff+i]!=0XFF)break;
}
if(i<secremain)
{
W25QXX_Erase_Sector(secpos);
for(i=0;i<secremain;i++)
{
W25QXX_BUF[i+secoff]=pBuffer[i];
}
W25QXX_Write_NoCheck(W25QXX_BUF,secpos*4096,4096);
}else W25QXX_Write_NoCheck(pBuffer,WriteAddr,secremain);
if(NumByteToWrite==secremain)break;
else
{
secpos++;
secoff=0;
pBuffer+=secremain;
WriteAddr+=secremain;
NumByteToWrite-=secremain;
if(NumByteToWrite>4096)secremain=4096;
else secremain=NumByteToWrite;
}
};
}
其他W25Q128FLASH指令请参考flash数据手册
四、完整程序:
(1)spi.h:
#ifndef __SPI_H
#define __SPI_H
#include "sys.h"
void SPI2_Init(void);
void SPI2_SetSpeed(u8 SpeedSet);
u8 SPI2_ReadWriteByte(u8 TxData);
#endif
(2)spi.c
#include "spi.h"
void SPI2_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
SPI_InitTypeDef SPI_InitStructure;
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE );
RCC_APB1PeriphClockCmd( RCC_APB1Periph_SPI2, ENABLE );
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_SetBits(GPIOB,GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15);
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;
SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_InitStructure.SPI_CRCPolynomial = 7;
SPI_Init(SPI2, &SPI_InitStructure);
SPI_Cmd(SPI2, ENABLE);
SPI2_ReadWriteByte(0xff);
}
void SPI2_SetSpeed(u8 SPI_BaudRatePrescaler)
{
assert_param(IS_SPI_BAUDRATE_PRESCALER(SPI_BaudRatePrescaler));
SPI2->CR1&=0XFFC7;
SPI2->CR1|=SPI_BaudRatePrescaler;
SPI_Cmd(SPI2,ENABLE);
}
u8 SPI2_ReadWriteByte(u8 TxData)
{
u8 retry=0;
while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET)
{
retry++;
if(retry>200)return 0;
}
SPI_I2S_SendData(SPI2, TxData);
retry=0;
while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET)
{
retry++;
if(retry>200)return 0;
}
return SPI_I2S_ReceiveData(SPI2);
}
(3)w25qxx.h:
#ifndef __FLASH_H
#define __FLASH_H
#include "sys.h"
#define W25Q80 0XEF13
#define W25Q16 0XEF14
#define W25Q32 0XEF15
#define W25Q64 0XEF16
#define W25Q128 0XEF17
extern u16 W25QXX_TYPE;
#define W25QXX_CS PBout(12)
#define W25X_WriteEnable 0x06
#define W25X_WriteDisable 0x04
#define W25X_ReadStatusReg 0x05
#define W25X_WriteStatusReg 0x01
#define W25X_ReadData 0x03
#define W25X_FastReadData 0x0B
#define W25X_FastReadDual 0x3B
#define W25X_PageProgram 0x02
#define W25X_BlockErase 0xD8
#define W25X_SectorErase 0x20
#define W25X_ChipErase 0xC7
#define W25X_PowerDown 0xB9
#define W25X_ReleasePowerDown 0xAB
#define W25X_DeviceID 0xAB
#define W25X_ManufactDeviceID 0x90
#define W25X_JedecDeviceID 0x9F
void W25QXX_Init(void);
u16 W25QXX_ReadID(void);
u8 W25QXX_ReadSR(void);
void W25QXX_Write_SR(u8 sr);
void W25QXX_Write_Enable(void);
void W25QXX_Write_Disable(void);
void W25QXX_Write_NoCheck(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite);
void W25QXX_Read(u8* pBuffer,u32 ReadAddr,u16 NumByteToRead);
void W25QXX_Write(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite);
void W25QXX_Erase_Chip(void);
void W25QXX_Erase_Sector(u32 Dst_Addr);
void W25QXX_Wait_Busy(void);
void W25QXX_PowerDown(void);
void W25QXX_WAKEUP(void);
#endif
(4)25qxx.c:
#include "w25qxx.h"
#include "spi.h"
#include "delay.h"
#include "usart.h"
u16 W25QXX_TYPE=W25Q128;
void W25QXX_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE );
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_SetBits(GPIOB,GPIO_Pin_12);
W25QXX_CS=1;
SPI2_Init();
SPI2_SetSpeed(SPI_BaudRatePrescaler_2);
W25QXX_TYPE=W25QXX_ReadID();
}
u8 W25QXX_ReadSR(void)
{
u8 byte=0;
W25QXX_CS=0;
SPI2_ReadWriteByte(W25X_ReadStatusReg);
byte=SPI2_ReadWriteByte(0Xff);
W25QXX_CS=1;
return byte;
}
void W25QXX_Write_SR(u8 sr)
{
W25QXX_CS=0;
SPI2_ReadWriteByte(W25X_WriteStatusReg);
SPI2_ReadWriteByte(sr);
W25QXX_CS=1;
}
void W25QXX_Write_Enable(void)
{
W25QXX_CS=0;
SPI2_ReadWriteByte(W25X_WriteEnable);
W25QXX_CS=1;
}
void W25QXX_Write_Disable(void)
{
W25QXX_CS=0;
SPI2_ReadWriteByte(W25X_WriteDisable);
W25QXX_CS=1;
}
u16 W25QXX_ReadID(void)
{
u16 Temp = 0;
W25QXX_CS=0;
SPI2_ReadWriteByte(0x90);
SPI2_ReadWriteByte(0x00);
SPI2_ReadWriteByte(0x00);
SPI2_ReadWriteByte(0x00);
Temp|=SPI2_ReadWriteByte(0xFF)<<8;
Temp|=SPI2_ReadWriteByte(0xFF);
W25QXX_CS=1;
return Temp;
}
void W25QXX_Read(u8* pBuffer,u32 ReadAddr,u16 NumByteToRead)
{
u16 i;
W25QXX_CS=0;
SPI2_ReadWriteByte(W25X_ReadData);
SPI2_ReadWriteByte((u8)((ReadAddr)>>16));
SPI2_ReadWriteByte((u8)((ReadAddr)>>8));
SPI2_ReadWriteByte((u8)ReadAddr);
for(i=0;i<NumByteToRead;i++)
{
pBuffer[i]=SPI2_ReadWriteByte(0XFF);
}
W25QXX_CS=1;
}
void W25QXX_Write_Page(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite)
{
u16 i;
W25QXX_Write_Enable();
W25QXX_CS=0;
SPI2_ReadWriteByte(W25X_PageProgram);
SPI2_ReadWriteByte((u8)((WriteAddr)>>16));
SPI2_ReadWriteByte((u8)((WriteAddr)>>8));
SPI2_ReadWriteByte((u8)WriteAddr);
for(i=0;i<NumByteToWrite;i++)SPI2_ReadWriteByte(pBuffer[i]);
W25QXX_CS=1;
W25QXX_Wait_Busy();
}
void W25QXX_Write_NoCheck(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite)
{
u16 pageremain;
pageremain=256-WriteAddr%256;
if(NumByteToWrite<=pageremain)pageremain=NumByteToWrite;
while(1)
{
W25QXX_Write_Page(pBuffer,WriteAddr,pageremain);
if(NumByteToWrite==pageremain)break;
else
{
pBuffer+=pageremain;
WriteAddr+=pageremain;
NumByteToWrite-=pageremain;
if(NumByteToWrite>256)pageremain=256;
else pageremain=NumByteToWrite;
}
};
}
u8 W25QXX_BUFFER[4096];
void W25QXX_Write(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite)
{
u32 secpos;
u16 secoff;
u16 secremain;
u16 i;
u8 * W25QXX_BUF;
W25QXX_BUF=W25QXX_BUFFER;
secpos=WriteAddr/4096;
secoff=WriteAddr%4096;
secremain=4096-secoff;
if(NumByteToWrite<=secremain)secremain=NumByteToWrite;
while(1)
{
W25QXX_Read(W25QXX_BUF,secpos*4096,4096);
for(i=0;i<secremain;i++)
{
if(W25QXX_BUF[secoff+i]!=0XFF)break;
}
if(i<secremain)
{
W25QXX_Erase_Sector(secpos);
for(i=0;i<secremain;i++)
{
W25QXX_BUF[i+secoff]=pBuffer[i];
}
W25QXX_Write_NoCheck(W25QXX_BUF,secpos*4096,4096);
}else W25QXX_Write_NoCheck(pBuffer,WriteAddr,secremain);
if(NumByteToWrite==secremain)break;
else
{
secpos++;
secoff=0;
pBuffer+=secremain;
WriteAddr+=secremain;
NumByteToWrite-=secremain;
if(NumByteToWrite>4096)secremain=4096;
else secremain=NumByteToWrite;
}
};
}
void W25QXX_Erase_Chip(void)
{
W25QXX_Write_Enable();
W25QXX_Wait_Busy();
W25QXX_CS=0;
SPI2_ReadWriteByte(W25X_ChipErase);
W25QXX_CS=1;
W25QXX_Wait_Busy();
}
void W25QXX_Erase_Sector(u32 Dst_Addr)
{
printf("fe:%x\r\n",Dst_Addr);
Dst_Addr*=4096;
W25QXX_Write_Enable();
W25QXX_Wait_Busy();
W25QXX_CS=0;
SPI2_ReadWriteByte(W25X_SectorErase);
SPI2_ReadWriteByte((u8)((Dst_Addr)>>16));
SPI2_ReadWriteByte((u8)((Dst_Addr)>>8));
SPI2_ReadWriteByte((u8)Dst_Addr);
W25QXX_CS=1;
W25QXX_Wait_Busy();
}
void W25QXX_Wait_Busy(void)
{
while((W25QXX_ReadSR()&0x01)==0x01);
}
void W25QXX_PowerDown(void)
{
W25QXX_CS=0;
SPI2_ReadWriteByte(W25X_PowerDown);
W25QXX_CS=1;
delay_us(3);
}
void W25QXX_WAKEUP(void)
{
W25QXX_CS=0;
SPI2_ReadWriteByte(W25X_ReleasePowerDown);
W25QXX_CS=1;
delay_us(3);
}
|