目录
上篇写了具体的SPI通信原理
SPI工作原理
1.硬件上为4根线。
2.主机和从机都有一个串行移位寄存器,主机通过向它的SPI串行寄存器写入一个字节来发起一次传输。
3.串行移位寄存器通过MOSI信号线将字节传送给从机,从机也将自己的串行移位寄存器中的内容通过MISO信号线返回给主机。这样,两个移位寄存器中的内容就被交换。
4.外设的写操作和读操作是同步完成的。如果只进行写操作,主机只需忽略接收到的字节;反之,若主机要读取从机的个字节,就必须发送一个空字节来引发从机的传输。
SPI引脚配置
SPI相关库函数
void SPI_I2S_Delnit(SPI_TypeDef* SPIx); //复位函数
void SPI_Init(SPI_TypeDef* SPIx, SPI_InitTypeDef* SPI_InitStruct); //SPI初始化函数
void SPI_Cmd(SPI_TypeDef* SPIx, FunctionalState NewState); //SPI使能函数
woid SPI_I2S_ITConfig(SPI_TypeDef* SPlx, uint8_t SPI_I2S_IT, FunctionalState NewState);//中断配置函数
void SPI_I2S_DMACmd(SPI_TypeDef* SPIx, uint16_t SPI_I2S_DMAReq, FunctionalState NewState);//DMA配置
void SPI_I2S SendData(SPI_TypeDef* SPlx, uint16_t Data); //发送数据
uint16_t SPI_I2S_ReceiveData(SPI_TypeDef* SPlx);//接受数据
void SPI_DataSizeConfig(SPI_TypeDef* SPIx, uint16_t SPI_DataSize);//SPI数据配置
FlagStatus SPI_I2S_GetFlagStatus(SPI_TypeDef* SPlx, uint16_t SPI_I2S_FLAG);//获取标志位
void SPI_I2S_ClearFlag(SPI_TypeDef* SPlx, uint16_t SPI_I2S_FLAG);//清除标志
ITStatus SPI_I2S_GetITStatus(SPI_TypeDef* SPlx, uint8_t SPI_I2S_IT);//获取中断状态
void SPI_I2S_ClearlTPendingBit(SPI_TypeDef* SPlx, uint8_t SPI_I2S_IT);//清除中断状态标志
程序配置过程
1.配置相关引脚的复用功能,使能SPlx时钟
void GPIO Init(GPIO_TypeDef* GPIOx, GPIO InitTypeDef* GPIO_InitStruct);
2.初始化SPIx,设置SPIx工作模式
void SPI_Init(SPL TypeDef* SPIx, SPI Init TypeDef* SPL InitStruct);
3.使能SPIx
void SPI Cmd(SPI TypeDef* SPIx, FunctionalState NewState);
4.SPI传输数据
void SPI_I2S_SendData(SPITypeDef* SPIx, uint16 Data);
uint16 SPI_I2S_ReceiveData(SPI TypeDef* SPlx);
5.查看SPI传输状态
SPI_I2S_GetFlagStatus(SPI2, SPI_2S FLAGRXNE);
W25Q128硬件连接图
W25Q128(W25Q64)将16M(8M)的容量分为256(128)个块(Block)每个块大小为64K字节,每个块又分为16个扇区(Sector),每个扇区4K个字节。W25Qxx的最小擦除单位为一个扇区,也就是每次必须擦除4K个字节。这样我们需要给W25Qxx开辟一个至少4K的缓存区,这样对SRAM要求比较高,要求芯片必须有4K以上SRAM才能很好的操作。
实验源码
/**
******************************************************************************
* @file : user_rcc_config.c
* @brief : V1.00
******************************************************************************
* @attention
*
******************************************************************************
*/
/* Include 包含---------------------------------------------------------------*/
#include "user_rcc_config.h"
/* Typedef 类型----------------------------------------------------------------*/
/* Define 定义----------------------------------------------------------------*/
/* Macro 宏------------------------------------------------------------------*/
/* Variables 变量--------------------------------------------------------------*/
/* Constants 常量--------------------------------------------------------------*/
/* Function 函数--------------------------------------------------------------*/
/*!
\brief RCC配置
\param[in] none
\param[out] none
\retval none
*/
void Rcc_config(void)
{
/*使能GPIOA时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
/*使能UART1时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
/*使能GPIOB时钟*/
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE );
/*SPI2时钟使能*/
RCC_APB1PeriphClockCmd( RCC_APB1Periph_SPI2, ENABLE );
}
/************************************************************** END OF FILE ****/
/**
******************************************************************************
* @file : user_gpio.c
* @brief : V1.00
******************************************************************************
* @attention
*
******************************************************************************
*/
/* Include 包含---------------------------------------------------------------*/
#include "user_gpio.h"
/* Typedef 类型----------------------------------------------------------------*/
/* Define 定义----------------------------------------------------------------*/
/* Macro 宏------------------------------------------------------------------*/
/* Variables 变量--------------------------------------------------------------*/
/* Constants 常量--------------------------------------------------------------*/
/* Function 函数--------------------------------------------------------------*/
/*!
\brief GPIO初始化函数
\param[in] none
\param[out] none
\retval none
*/
void Gpio_Init(void)
{
/*GPIO结构体*/
GPIO_InitTypeDef GPIO_InitTypeDefstruct;
/*UART1发送引脚配置*/
GPIO_InitTypeDefstruct.GPIO_Mode = GPIO_Mode_AF_PP;//推挽复用输出
GPIO_InitTypeDefstruct.GPIO_Pin = GPIO_Pin_9;
GPIO_InitTypeDefstruct.GPIO_Speed = GPIO_Speed_10MHz;
/*写入结构体到GPIOA*/
GPIO_Init(GPIOA,&GPIO_InitTypeDefstruct);
/*UART1接收引脚配置*/
GPIO_InitTypeDefstruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
GPIO_InitTypeDefstruct.GPIO_Pin = GPIO_Pin_10;
GPIO_InitTypeDefstruct.GPIO_Speed = GPIO_Speed_10MHz;
/*写入结构体到GPIOA*/
GPIO_Init(GPIOA,&GPIO_InitTypeDefstruct);
/*配置SPI 13 时钟 14 MISO 15 MOSI*/
GPIO_InitTypeDefstruct.GPIO_Pin = GPIO_Pin_12| GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
GPIO_InitTypeDefstruct.GPIO_Mode = GPIO_Mode_AF_PP; //PB12/13/14/15复用推挽输出 MISO推挽也正常
GPIO_InitTypeDefstruct.GPIO_Speed = GPIO_Speed_50MHz;
/*写入结构体到GPIOB*/
GPIO_Init(GPIOB,&GPIO_InitTypeDefstruct);
/*配置SPI 12 CS*/
GPIO_InitTypeDefstruct.GPIO_Pin = GPIO_Pin_12;
GPIO_InitTypeDefstruct.GPIO_Mode = GPIO_Mode_Out_PP; //PB12
GPIO_InitTypeDefstruct.GPIO_Speed = GPIO_Speed_50MHz;
/*写入结构体到GPIOB*/
GPIO_Init(GPIOB,&GPIO_InitTypeDefstruct);
/*高电平*/
GPIO_SetBits(GPIOB,GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15);
}
/************************************************************** END OF FILE ****/
/**
******************************************************************************
* @file : user_uart.c
* @brief : V1.00
******************************************************************************
* @attention
*
******************************************************************************
*/
/* Include 包含---------------------------------------------------------------*/
#include "user_uart.h"
/* Typedef 类型----------------------------------------------------------------*/
/* Define 定义----------------------------------------------------------------*/
/* Macro 宏------------------------------------------------------------------*/
/* Variables 变量--------------------------------------------------------------*/
extern uint16_t USART_RX_STA;
extern uint8_t USART_RX_BUF[200];
/* Constants 常量--------------------------------------------------------------*/
/* Function 函数--------------------------------------------------------------*/
#if 1
#pragma import(__use_no_semihosting)
/*实现Printf代码*/
struct __FILE
{
int handle;
};
FILE __stdout;
void _sys_exit(int x)
{
x = x;
}
//重定义fputc函数
int fputc(int ch, FILE *f)
{
while((USART1->SR&0X40)==0);//循环发送,直到发送完毕
USART1->DR = (u8) ch;
return ch;
}
#endif
/*!
\brief UART1初始化
\param[in] none
\param[out] none
\retval none
*/
void Uart1_Init(u32 bound)
{
/*UART结构体*/
USART_InitTypeDef USART_InitTypeDefstruct;
/*UART结构体配置*/
USART_InitTypeDefstruct.USART_BaudRate = bound; //波特率
USART_InitTypeDefstruct.USART_HardwareFlowControl =USART_HardwareFlowControl_None; //不使用硬件流
USART_InitTypeDefstruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;//发送接收使能
USART_InitTypeDefstruct.USART_Parity = USART_Parity_No; //不使用奇偶校验
USART_InitTypeDefstruct.USART_StopBits = USART_StopBits_1; //1个停止位
USART_InitTypeDefstruct.USART_WordLength = USART_WordLength_8b; //8个数据位
/*写入USART1*/
USART_Init(USART1,&USART_InitTypeDefstruct);
/*使能串口1*/
USART_Cmd(USART1,ENABLE);
}
/*!
\brief UART1中断服务函数
\param[in] none
\param[out] none
\retval none
*/
void USART1_IRQHandler(void)
{
}
/************************************************************** END OF FILE ****/
/**
******************************************************************************
* @file : user_spi.c
* @brief : V1.00
******************************************************************************
* @attention
*
******************************************************************************
*/
/* Include 包含---------------------------------------------------------------*/
#include "user_spi.h"
/* Typedef 类型----------------------------------------------------------------*/
/* Define 定义----------------------------------------------------------------*/
/* Macro 宏------------------------------------------------------------------*/
/* Variables 变量--------------------------------------------------------------*/
/* Constants 常量--------------------------------------------------------------*/
/* Function 函数--------------------------------------------------------------*/
/*!
\brief 设置SPI通信速度
\param[in] none
\param[in] none
\retval none
*/
void SPI2_SetSpeed(uint8_t SPI_BaudRatePrescaler)
{
/*断言库函数里的*/
assert_param(IS_SPI_BAUDRATE_PRESCALER(SPI_BaudRatePrescaler));
/*清除第bit3、4、5位可以进库函数去看分频具体数值,分频就是操作 3 4 5bit位*/
SPI2->CR1&=0XFFC7;
/*设置SPI2速度*/
SPI2->CR1|=SPI_BaudRatePrescaler;
/*重新使能SPI*/
SPI_Cmd(SPI2,ENABLE);
}
/*!
\brief 读写函数,SPI因为2个位移寄存器相连写一个字节的时候会返回上一次接受到的字节
\param[in] 发送数据
\param[in] none
\retval 读取的字节
*/
uint8_t SPI2_ReadWriteByte(uint8_t TxData)
{
/*等待超时时间*/
uint8_t retry=0;
/*检查指定的SPI标志位设置与否:发送缓存空标志位*/
while(SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET)
{
retry++;
if(retry>200)
{
return 0;
}
}
/*通过外设SPI2发送一个数据*/
SPI_I2S_SendData(SPI2, TxData);
/*等待超时时间*/
retry=0;
/*检查指定的SPI标志位设置与否:接受缓存非空标志位*/
while(SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET)
{
retry++;
if(retry>200)
{
return 0;
}
}
/*返回通过SPIx最近接收的数据*/
return SPI_I2S_ReceiveData(SPI2);
}
/*!
\brief SPI初始化
\param[in] none
\param[out] none
\retval none
*/
void Spi_Init(void)
{
/*SPI结构体*/
SPI_InitTypeDef SPI_InitStructure;
/*SPI配置*/
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; //SPI设置为双线双向全双工
SPI_InitStructure.SPI_Mode = SPI_Mode_Master; //设置为主SPI
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;//SPI发送接收8位帧结构
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;//APB1(36M)/256
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //数据传输从MSB(高)位开始
SPI_InitStructure.SPI_CRCPolynomial = 7; //CRC值计算的多项式
SPI_Init(SPI2, &SPI_InitStructure); //写入SPI2里面
/*使能SPI外设*/
SPI_Cmd(SPI2, ENABLE);
/*主机和从机都有一个串行移位寄存器,主机通过向它的SPI串行寄存器写入一个字节来发起一次传输*/
SPI2_ReadWriteByte(0xFF);
}
/************************************************************** END OF FILE ****/
/**
******************************************************************************
* @file : user_w25q128.h
* @brief : V1.00
******************************************************************************
* @attention
*
******************************************************************************
*/
/* Define to prevent recursive incluson---------------------------------------*/
#ifndef _USER_W25Q128_H__
#define _USER_W25Q128_H__
/* Include 包含---------------------------------------------------------------*/
#include "stm32f10x.h"
#include "user_spi.h"
#include "user_uart.h"
/* Typedef 类型----------------------------------------------------------------*/
/* Define 定义----------------------------------------------------------------*/
/* Macro 宏------------------------------------------------------------------*/
//指令表数据手册上的
#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
//IO口操作宏定义
#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2))
#define MEM_ADDR(addr) *((volatile unsigned long *)(addr))
#define BIT_ADDR(addr, bitnum) MEM_ADDR(BITBAND(addr, bitnum))
//IO口地址映射
#define GPIOA_ODR_Addr (GPIOA_BASE+12) //0x4001080C
#define GPIOB_ODR_Addr (GPIOB_BASE+12) //0x40010C0C
#define GPIOC_ODR_Addr (GPIOC_BASE+12) //0x4001100C
#define GPIOD_ODR_Addr (GPIOD_BASE+12) //0x4001140C
#define GPIOE_ODR_Addr (GPIOE_BASE+12) //0x4001180C
#define GPIOF_ODR_Addr (GPIOF_BASE+12) //0x40011A0C
#define GPIOG_ODR_Addr (GPIOG_BASE+12) //0x40011E0C
#define GPIOA_IDR_Addr (GPIOA_BASE+8) //0x40010808
#define GPIOB_IDR_Addr (GPIOB_BASE+8) //0x40010C08
#define GPIOC_IDR_Addr (GPIOC_BASE+8) //0x40011008
#define GPIOD_IDR_Addr (GPIOD_BASE+8) //0x40011408
#define GPIOE_IDR_Addr (GPIOE_BASE+8) //0x40011808
#define GPIOF_IDR_Addr (GPIOF_BASE+8) //0x40011A08
#define GPIOG_IDR_Addr (GPIOG_BASE+8) //0x40011E08
//片选引脚
#define W25Q128_CS BIT_ADDR(GPIOB_ODR_Addr,12) //W25QXX的片选信号 1取消片选 0 选中
/* Variables 变量--------------------------------------------------------------*/
/* Constants 常量--------------------------------------------------------------*/
/* Function 函数--------------------------------------------------------------*/
uint16_t W25Q128_ReadID(void); //读取FLASH ID
void W25Q128_Read(uint8_t* pBuffer,uint32_t ReadAddr,uint16_t NumByteToRead); //读取flash
void W25Q128_Write(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite);//写入flash
void W25Q128_Init(void); //初始化
#endif
/************************************************************** END OF FILE ****/
/**
******************************************************************************
* @file : user_w25q128.c
* @brief : V1.00
******************************************************************************
* @attention
*
******************************************************************************
*/
/* Include 包含---------------------------------------------------------------*/
#include "user_w25q128.h"
/* Typedef 类型----------------------------------------------------------------*/
/* Define 定义----------------------------------------------------------------*/
/* Macro 宏------------------------------------------------------------------*/
/* Variables 变量--------------------------------------------------------------*/
/*中转变量发现有其他值的全部取出来,然后擦除一个扇区在写回去*/
uint8_t W25Q128_BUFFER[4096];
/* Constants 常量--------------------------------------------------------------*/
/* Function 函数--------------------------------------------------------------*/
/*!
\brief W25Q128初始化
\param[in] none
\param[in] none
\retval none
*/
void W25Q128_Init(void)
{
/*W25Q128不片选*/
W25Q128_CS=1;
/*初始化SPI*/
Spi_Init();
/*//设置为36/2=18M时钟,高速模式*/
SPI2_SetSpeed(SPI_BaudRatePrescaler_2);
}
/*!
BIT7 6 5 4 3 2 1 0
SPR RV TB BP2 BP1 BP0 WEL BUSY
SPR:默认0,状态寄存器保护位,配合WP使用
TB,BP2,BP1,BP0:FLASH区域写保护设置
WEL:写使能锁定
BUSY:忙标记位(1,忙;0,空闲)
默认:0x00
\brief 读取W25Q128状态寄存器
\param[in] none
\param[in] none
\retval none
*/
uint8_t W25Q128_ReadSR(void)
{
/*接收数据变量*/
uint8_t byte=0;
/*选中片选*/
W25Q128_CS=0;
/*发送读取状态命令,同时会返回一个无用字节*/
SPI2_ReadWriteByte(W25X_ReadStatusReg);
/*写一个无用字节,返回状态寄存器值*/
byte=SPI2_ReadWriteByte(0XFF);
/*取消片选*/
W25Q128_CS=1;
/*返回状态*/
return byte;
}
/*! SPR,TB,BP2,BP1,BP0(bit 7,5,4,3,2)可以写
\brief 写W25Q128状态寄存器
\param[in] none
\param[in] none
\retval none
*/
void W25Q128_Write_SR(uint8_t sr)
{
/*选中片选*/
W25Q128_CS=0;
/*发送写取状态寄存器命令*/
SPI2_ReadWriteByte(W25X_WriteStatusReg);
/*写入一个字节*/
SPI2_ReadWriteByte(sr);
/*取消片选*/
W25Q128_CS=1;
}
/*!
\brief 写W25Q128使能
\param[in] none
\param[in] none
\retval none
*/
void W25Q128_Write_Enable(void)
{
/*选中片选*/
W25Q128_CS=0;
/*发送写使能命令*/
SPI2_ReadWriteByte(W25X_WriteEnable);
/*取消片选*/
W25Q128_CS=1;
}
/*!
\brief 写W25Q128禁止
\param[in] none
\param[in] none
\retval none
*/
void W25Q128_Write_Disable(void)
{
/*选中片选*/
W25Q128_CS=0;
/*发送写禁止指令*/
SPI2_ReadWriteByte(W25X_WriteDisable);
/*取消片选*/
W25Q128_CS=1;
}
/*!
\brief 读取ID
\param[in] none
\param[in] none
\retval 0XEF17,表示芯片型号为W25Q128
*/
uint16_t W25Q128_ReadID(void)
{
/*ID返回变量*/
uint16_t Temp = 0;
/*选中片选*/
W25Q128_CS=0;
/*发送读取ID命令*/
SPI2_ReadWriteByte(W25X_ManufactDeviceID);
/*发送24bit位的地址*/
SPI2_ReadWriteByte(0x00);
SPI2_ReadWriteByte(0x00);
SPI2_ReadWriteByte(0x00);
/*发无用字节,接收ID*/
Temp|=SPI2_ReadWriteByte(0xFF)<<8;
Temp|=SPI2_ReadWriteByte(0xFF);
/*取消片选*/
W25Q128_CS=1;
/*返回ID*/
return Temp;
}
/*!
\brief 擦除一个扇区
\param[in] none
\param[in] none
\retval none
*/
void W25Q128_Erase_Sector(u32 Dst_Addr)
{
/*一个扇区是4096个字节*/
Dst_Addr*=4096;
/*写使能*/
W25Q128_Write_Enable();
/*等待BUSY位清空*/
while((W25Q128_ReadSR()&0x01)==0x01);
/*选中片选*/
W25Q128_CS=0;
/*发送扇区擦除指令*/
SPI2_ReadWriteByte(W25X_SectorErase);
/*发送24bit地址*/
SPI2_ReadWriteByte((u8)((Dst_Addr)>>16));
SPI2_ReadWriteByte((u8)((Dst_Addr)>>8));
SPI2_ReadWriteByte((u8)Dst_Addr);
/*取消片选*/
W25Q128_CS=1;
/*等待擦除完成*/
while((W25Q128_ReadSR()&0x01)==0x01);
}
/*!
\brief 擦除整个芯片
\param[in] none
\param[in] none
\retval none
*/
void W25Q128_Erase_Chip(void)
{
/*写使能*/
W25Q128_Write_Enable();
/*等待BUSY位清空*/
while((W25Q128_ReadSR()&0x01)==0x01);
/*选中片选*/
W25Q128_CS=0;
/*发送片擦除命令*/
SPI2_ReadWriteByte(W25X_ChipErase);
/*取消片选*/
W25Q128_CS=1;
/*等待擦除完成*/
while((W25Q128_ReadSR()&0x01)==0x01);
}
/*!
\brief 读取函数
\param[in] 读取BUFF
\param[in] 要读取的地址(24bit)
\param[in] 要读取的数量(65535字节最大)
\retval none
*/
void W25Q128_Read(uint8_t* pBuffer,uint32_t ReadAddr,uint16_t NumByteToRead)
{
uint16_t i;
/*选中片选*/
W25Q128_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);
}
/*取消片选*/
W25Q128_CS=1;
}
/*!
\brief 写一页256个字节
\param[in] 写BUFF
\param[in] 要写的地址(24bit)
\param[in] 要写的数量(256字节最大)
\retval none
*/
void W25Q128_Write_Page(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite)
{
u16 i;
/*写使能*/
W25Q128_Write_Enable();
/*选中片选*/
W25Q128_CS=0;
/*发送写页命令*/
SPI2_ReadWriteByte(W25X_PageProgram);
/*发送24bit地址*/
SPI2_ReadWriteByte((u8)((WriteAddr)>>16));
SPI2_ReadWriteByte((u8)((WriteAddr)>>8));
SPI2_ReadWriteByte((u8)WriteAddr);
/*开始循环写数*/
for(i=0;i<NumByteToWrite;i++){
SPI2_ReadWriteByte(pBuffer[i]);
}
/*取消片选*/
W25Q128_CS=1;
/*等待擦除完成*/
while((W25Q128_ReadSR()&0x01)==0x01);
}
/*!
\brief 检查是否一页当中有存其他值,可以换页
\param[in] 写BUFF
\param[in] 要写的地址(24bit)
\param[in] 要写的数量(256字节最大)
\retval none
*/
void W25Q128_Write_NoCheck(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite)
{
u16 pageremain;
/*单页剩余的字节数*/
pageremain=256-WriteAddr%256;
/*不大于256个字节*/
if(NumByteToWrite<=pageremain)pageremain=NumByteToWrite;
while(1)
{ /*写一页256个字节*/
W25Q128_Write_Page(pBuffer,WriteAddr,pageremain);
if(NumByteToWrite==pageremain)
{ /*写入结束*/
break;
}
else //NumByteToWrite>pageremain
{
pBuffer+=pageremain;
WriteAddr+=pageremain;
/*减去已经写入了的字节数*/
NumByteToWrite-=pageremain;
/*一次可以写入256个字节*/
if(NumByteToWrite>256)
{
pageremain=256;
}
else
{ /*不够256个字节了*/
pageremain=NumByteToWrite;
}
}
}
}
/*!
\brief 写数据
\param[in] 写BUFF
\param[in] 要写的地址(24bit)
\param[in] 要写的数量(65535字节最大)
\retval none
*/
void W25Q128_Write(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite)
{
u32 secpos;
u16 secoff;
u16 secremain;
u16 i;
u8 * W25QXX_BUF;
W25QXX_BUF=W25Q128_BUFFER;
/*扇区地址*/
secpos=WriteAddr/4096;
/*在扇区内的偏移*/
secoff=WriteAddr%4096;
/*扇区剩余空间大小*/
secremain=4096-secoff;
/*不大于4096个字节*/
if(NumByteToWrite<=secremain)secremain=NumByteToWrite;
while(1)
{ /*读出整个扇区的内容*/
W25Q128_Read(W25QXX_BUF,secpos*4096,4096);
/*校验数据*/
for(i=0;i<secremain;i++)
{
if(W25QXX_BUF[secoff+i]!=0XFF)
{
/*需要擦除 */
break;
}
}
/*//需要擦除 */
if(i<secremain)
{
/*擦除这个扇区*/
W25Q128_Erase_Sector(secpos);
/*复制*/
for(i=0;i<secremain;i++)
{
W25QXX_BUF[i+secoff]=pBuffer[i];
}
/*写入整个扇区*/
W25Q128_Write_NoCheck(W25QXX_BUF,secpos*4096,4096);//
}else
{ /*写已经擦除了的,直接写入扇区剩余区间*/
W25Q128_Write_NoCheck(pBuffer,WriteAddr,secremain);
}
if(NumByteToWrite==secremain)
{ /*写入结束了*/
break;
}
else/*写入未结束*/
{ /*扇区地址增1*/
secpos++;
/*偏移位置为0*/
secoff=0;
/*指针偏移*/
pBuffer+=secremain;
/*写地址偏移*/
WriteAddr+=secremain;
/*字节数递减*/
NumByteToWrite-=secremain;
/*下一个扇区还是写不完*/
if(NumByteToWrite>4096)
{
secremain=4096;
}
else
{ /*下一个扇区可以写完了*/
secremain=NumByteToWrite;
}
}
};
}
/************************************************************** END OF FILE ****/
/**
******************************************************************************
* @file : user_mian.h
* @brief : V1.00
******************************************************************************
* @attention
*
******************************************************************************
*/
/* Include 包含---------------------------------------------------------------*/
#include "stm32f10x.h"
#include <stdbool.h>
#include "user_gpio.h"
#include "user_delay.h"
#include "user_rcc_config.h"
#include "user_uart.h"
#include "user_w25q128.h"
/* Typedef 类型----------------------------------------------------------------*/
/* Define 定义----------------------------------------------------------------*/
/* Macro 宏------------------------------------------------------------------*/
#define SIZE sizeof(TEXT_Buffer)
/* Variables 变量--------------------------------------------------------------*/
const uint8_t TEXT_Buffer[]={"SPI TEST AAAAAAAAA"};
/* Constants 常量--------------------------------------------------------------*/
/* Function 函数--------------------------------------------------------------*/
int main(void)
{
/*ID变量*/
uint16_t id;
/*flash大小16M字节*/
uint32_t FLASH_SIZE = 128*1024*1024;
/*读出数组*/
uint8_t datatemp[SIZE];
/*打印变量*/
uint16_t i;
/*配置系统中断分组为2位抢占2位响应*/
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
/*延时函数初始化*/
delay_init();
/*RCC配置*/
Rcc_config();
/*GPIO初始化*/
Gpio_Init();
/*USART1初始化*/
Uart1_Init(9600);
/*W25Q128初始化*/
W25Q128_Init();
/*死循环*/
while(1){
id = W25Q128_ReadID();
if(id == 0X5217)
{
printf("W25Q128\r\n");
}
/*从倒数第200个地址处开始,写入SIZE长度的数据*/
W25Q128_Write((uint8_t*)TEXT_Buffer,FLASH_SIZE-200,SIZE);
/*从倒数第100个地址处开始,读出SIZE个字节*/
W25Q128_Read(datatemp,FLASH_SIZE-200,SIZE);
for(i = 0; i < SIZE; i++)
{
printf("%c",datatemp[i]);
}
printf("\r\n");
delay_ms(1000);
}
}
/************************************************************** END OF FILE ****/