W25Q128芯片的SPI驱动程序

1、四个文件

//SPI底层初始化控制
bsp_spi_hw.h
bsp_spi_hw.c
//W25Qxx NorFlash驱动
bsp_w25qxx.h
bsp_w25qxx.c

2、bsp_spi_hw.h文件

主要是用户配置、根据不同的接线对驱动进行配置,考虑到移植性,只需要修改用户配置这几个宏即可。
#ifndef __BSP_SPI_HW_H_
#define __BSP_SPI_HW_H_
#include "main.h"/*用户配置*/
#define SPI_SC_GPIOTYPE   GPIOB
#define SPI_SC_PIN        GPIO_PIN_14#define SPI_CLK_GPIOTYPE  GPIOB
#define SPI_CLK_PIN       GPIO_PIN_3#define SPI_MISO_GPIOTYPE GPIOB
#define SPI_MISO_PIN      GPIO_PIN_4#define SPI_MOSI_GPIOTYPE GPIOB
#define SPI_MOSI_PIN      GPIO_PIN_5#define SPIx SPI1
#define SPI_WAIT_TIME_OUT 0x0FFFvoid BSP_SPIx_Init(void);
void BSP_SPIx_WaitReady(void);
void BSP_SPIx_Select(void);
void BSP_SPIx_DisSelect(void);
unsigned char BSP_SPIx_WriteReadByte(unsigned char TxData);
void BSP_SPIx_SetSpeed(unsigned char SPI_BaudRatePrescaler);#endif

3、bsp_spi_hw.c文件

SPI初始化配置、我是在STM32F4板子进行测试的,使用的hal库,方便移植到其他系列MCU上,毕竟也是这几年ST主推hal库的原因,便于移植。
1、初始化SPI
void BSP_SPIx_Init(void) 2、 SPI引脚初始化、该函数在HAL库为弱定义、需要用户自己实现函数体、HAL_SPI_Init函数中会调用到
void HAL_SPI_MspInit(SPI_HandleTypeDef *hspi)3、设置SPI时钟分频系数(设置完成之后一定再使能下SPI才能生效)
void BSP_SPIx_SetSpeed(unsigned char SPI_BaudRatePrescaler)4、片选使能、设置CS输出为低电平、
void BSP_SPIx_Select(void)5、片选失能、设置CS输出为高电平
void BSP_SPIx_DisSelect(void)6、SPI收发数据函数
SPI通信的两个设备实际上是两个双向的移位寄存器在时钟信号的控制交换数据、发送一个byte数据、同时也会接收到一个byte数据。
unsigned char BSP_SPIx_WriteReadByte(unsigned char TxData)
#include "bsp_spi_hw.h"SPI_HandleTypeDef SPI1_Handler;   //SPI1句柄
uint8_t TxData = 0xFF;
uint8_t RxData = 0;//SPI初始化
void BSP_SPIx_Init(void)
{//SPI1初始化SPI1_Handler.Instance = SPIx;SPI1_Handler.Init.Mode = SPI_MODE_MASTER;    //主SPI1_Handler.Init.Direction = SPI_DIRECTION_2LINES;  //双线模式SPI1_Handler.Init.DataSize = SPI_DATASIZE_8BIT;      //8位数据SPI1_Handler.Init.NSS = SPI_NSS_SOFT;    //软件控制SSSPI1_Handler.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_256;  //256分频SPI1_Handler.Init.FirstBit = SPI_FIRSTBIT_MSB;  //发送MSBSPI1_Handler.Init.CLKPolarity = SPI_POLARITY_LOW;     //时钟极性0SPI1_Handler.Init.CLKPhase = SPI_PHASE_1EDGE;         //时钟相位0SPI1_Handler.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;  //硬件CRC失能SPI1_Handler.Init.TIMode = SPI_TIMODE_DISABLE; //关闭IT模式HAL_SPI_Init(&SPI1_Handler);//使能SPI1__HAL_SPI_ENABLE(&SPI1_Handler);//开启SPI传输HAL_SPI_TransmitReceive(&SPI1_Handler,&TxData,&RxData,1,SPI_WAIT_TIME_OUT);
}//GPIO引脚初始化
//PB3 - SPI1_SCK
//PB4 - SPI1_MISO
//PB5 - SPI1_MOSI
void HAL_SPI_MspInit(SPI_HandleTypeDef *hspi)
{if(SPIx == hspi->Instance){GPIO_InitTypeDef GPIO_InitStructer;//使能GPIO时钟、SPI1时钟__HAL_RCC_GPIOB_CLK_ENABLE();__HAL_RCC_SPI1_CLK_ENABLE();//初始化GPIOGPIO_InitStructer.Mode = GPIO_MODE_AF_PP;GPIO_InitStructer.Pin = SPI_CLK_PIN|SPI_MISO_PIN|SPI_MOSI_PIN;GPIO_InitStructer.Pull = GPIO_PULLUP;GPIO_InitStructer.Speed = GPIO_SPEED_FAST;GPIO_InitStructer.Alternate = GPIO_AF5_SPI1;HAL_GPIO_Init(SPI_CLK_GPIOTYPE,&GPIO_InitStructer);//初始化CSGPIO_InitStructer.Mode = GPIO_MODE_OUTPUT_PP;GPIO_InitStructer.Pin = SPI_SC_PIN;GPIO_InitStructer.Speed = GPIO_SPEED_FAST;GPIO_InitStructer.Pull = GPIO_PULLUP;HAL_GPIO_Init(SPI_SC_GPIOTYPE,&GPIO_InitStructer);//CS线初始化拉高HAL_GPIO_WritePin(SPI_SC_GPIOTYPE,SPI_SC_PIN,GPIO_PIN_SET);}
}//设置SPI时钟频率
void BSP_SPIx_SetSpeed(unsigned char SPI_BaudRatePrescaler)
{assert_param(IS_SPI_BAUDRATE_PRESCALER(SPI_BaudRatePrescaler)); //判断有效性SPIx->CR1&=0XFFC7; //位3-5清零,用来设置波特率SPIx->CR1|=SPI_BaudRatePrescaler;   //设置SPI1速度 __HAL_SPI_ENABLE(&SPI1_Handler);
}//等待SPI空闲
void BSP_SPIx_WaitReady(void)
{RxData = 0;HAL_SPI_TransmitReceive(&SPI1_Handler,&TxData,&RxData,1,SPI_WAIT_TIME_OUT);if(0xFF == RxData){return;}
}//片选使能
void BSP_SPIx_Select(void)
{//片选线拉低HAL_GPIO_WritePin(GPIOB,GPIO_PIN_14,GPIO_PIN_RESET);
}//片选失能
void BSP_SPIx_DisSelect(void)
{//片选线拉高HAL_GPIO_WritePin(GPIOB,GPIO_PIN_14,GPIO_PIN_SET);
}//读写一个字节数据
unsigned char BSP_SPIx_WriteReadByte(unsigned char TxData)
{unsigned char RxData = 0;HAL_SPI_TransmitReceive(&SPI1_Handler,&TxData,&RxData,1,SPI_WAIT_TIME_OUT);return RxData;
}

4、bsp_w25qxx.h

#ifndef __BSP_W25QXX_H_
#define __BSP_W25QXX_H_#include"main.h"#define FLASH_SECTOR_SIZE 4096     //扇区大小4KB
#define FLASH_PAGE_SIZE   256      //页大小256byte
#define FLASH_TIME_OUT    0x7FFF//芯片ID
#define W25Q08  0xEF13
#define W25Q16  0xEF14
#define W25Q32  0xEF15
#define W25Q64  0xEF16
#define W25Q128 0xEF17
#define W25Q256 0xEF18enum
{S_ERROR,S_OK,
};//状态寄存器ID
typedef enum emNorFlashReg_ID
{W25Qxx_STA_REG_1 = 1,W25Qxx_STA_REG_2,W25Qxx_STA_REG_3,W25Qxx_STA_REG_MAX,
}emNorFlashReg_ID;//芯片类型枚举
typedef enum emNorFlashTypeId
{NorFlash_W25Q80 = 0,NorFlash_W25Q16,NorFlash_W25Q32,NorFlash_W25Q64,NorFlash_W25Q128,NorFlash_W25Q256,NorFlash_ID_MAX,
}emNorFlashTypeId;//输入参数
typedef struct tagNorFlashInPara
{unsigned long timeout;
}tagNorFlashInPara;//输入函数
typedef struct tagNorFlashInFun
{void (*SPI_Init)(void);void (*SPI_Select)(void);void (*SPI_DisSelect)(void);void (*SPI_SetSpeed)(unsigned char speed);unsigned char (*SPI_WriteReadByte)(unsigned char tx_data);}tagNorFlashInFun;//输出参数
typedef struct tagNorFlashOutPara
{unsigned long totalsize;     //芯片总容量unsigned long sectorcount;   //扇区个数unsigned long sectorsize;    //扇区大小unsigned long blocksize;     //块大小unsigned short dev_id;       //芯片型号}tagNorFlashOutPara;//私有成员
typedef struct tagNorFlashPrv
{uint8_t debug_err;uint8_t DataBuff[FLASH_SECTOR_SIZE];   //4K的数据缓冲区
}tagNorFlashPrv;//NorFlash控制块
typedef struct tagNorFlashCB
{tagNorFlashInPara  InPara;tagNorFlashInFun   InFun;tagNorFlashOutPara OutPara;tagNorFlashPrv     Prv;
}tagNorFlashCB;/*-----------------------接口函数----------------------------*/
unsigned short NorFlash_GetVersion(void);
unsigned char  NorFlash_DeInit(tagNorFlashCB *cb);
unsigned char  NorFlash_InitInPara(tagNorFlashCB *cb, unsigned long timeout);
unsigned char  NorFlash_InitInFun(tagNorFlashCB *cb,void *Init(void),void *Select(void),void *DisSelect(void),void *SetSpeed(unsigned char),unsigned char *WriteReadByte(unsigned char *));unsigned char NorFlash_Init(tagNorFlashCB *cb);
unsigned char NorFlash_SoftReset(tagNorFlashCB *cb);
unsigned short NorFlash_DevId(tagNorFlashCB *cb);
unsigned char NorFlash_Write_Enable(tagNorFlashCB *cb);
unsigned char NorFlash_Write_Disable(tagNorFlashCB *cb);
unsigned char NorFlash_Wait_Busy(tagNorFlashCB *cb);
unsigned char NorFlash_Erase_Sec(tagNorFlashCB *cb, unsigned short sec_id);
unsigned char NorFlash_Erase_Chip(tagNorFlashCB *cb);
unsigned char NorFlash_Read_Regs(tagNorFlashCB *cb, emNorFlashReg_ID reg_id);
unsigned char NorFlash_Wirte_Regs(tagNorFlashCB *cb, emNorFlashReg_ID reg_id,unsigned char reg_val);
unsigned char NorFlash_ReadData(tagNorFlashCB *cb,unsigned char *pbuffer,unsigned long  r_addr,unsigned short r_len);
unsigned char NorFlash_Write_Page(tagNorFlashCB *cb,unsigned char *pbuffer,unsigned long  w_addr,unsigned short w_len);
unsigned char NorFlash_Write_Pages(tagNorFlashCB *cb,unsigned char *pbuffer,unsigned long  w_addr,unsigned short w_len);
unsigned char NorFlash_Wirte(tagNorFlashCB *cb,unsigned char *pbuffer,unsigned long w_addr,unsigned short w_len);
#endif

5、bsp_w25qxx.c

#include "bsp_w25qxx.h"//模块版本
#define NorFlash_Version  0x100//指令集
#define W25Qxx_READ_DEV_ID    0x90     //读设备ID
#define W25Qxx_READ_DATA      0x03     //读数据#define W25Qxx_WRITE_ENABLE   0x06     //写使能
#define W25Qxx_WRITE_DISABLE  0x04     //写失能#define W25Qxx_ERASE_SEC      0x20     //擦除扇区 4KB
#define W25Qxx_ERASE_BK32     0x52     //擦除块 32KB
#define W25Qxx_ERASE_BK64     0xD8     //擦除块 64KB#define W25Qxx_PAGE_PROGRAM   0x02     //页编程 页大小为256#define W25Qxx_Read_StaReg1   0x05     //读状态寄存器1
#define W25Qxx_Read_StaReg2   0x35     //读状态寄存器2
#define W25Qxx_Read_StaReg3   0x15     //读状态寄存器3#define W25Qxx_Write_StaReg1  0x01     //写状态寄存器1 写状态寄存器中指定的位
#define W25Qxx_Write_StaReg2  0x31     //写状态寄存器2
#define W25Qxx_Write_StaReg3  0x11     //写状态寄存器3#define W25Qxx_Erase_Chip1    0xC7     //全片擦除指令1
#define W25Qxx_Erase_Chip2    0x60     //全片擦除指令2#define W25Qxx_Reset_Enable   0x66     //芯片复位使能
#define W25Qxx_Reset_Cmd      0x99     //芯片复位指令//芯片对应的设备ID
const unsigned short NorFlashDevID[NorFlash_ID_MAX] =
{0xEF13,   //W25Q800xEF14,   //W25Q160xEF15,   //W25Q320xEF16,   //W25Q640xEF17,   //W25Q1280xEF18,   //W25Q256
};//芯片容量对照表
const unsigned long NorFlashTotalSizeTable[NorFlash_ID_MAX] =
{8*1024*1024,    //W25Q802*1024*1024,    //W25Q164*1024*1024,    //W25Q328*1024*1024,    //W25Q6416*1024*1024,   //W25Q12832*1024*1024,   //W25Q256
};//获取模块版本
unsigned short NorFlash_GetVersion(void)
{return NorFlash_Version;
}//控制块DeInit
unsigned char  NorFlash_DeInit(tagNorFlashCB *cb)
{if(cb){#if 0cb->InFun.SPI_Init = (void)(*0)(void);cb->InFun.SPI_Select = (void)(*0)(void);cb->InFun.SPI_DisSelect = (void)(*0)(void);cb->InFun.SPI_SetSpeed = (void)(*0)(unsigned char);cb->InFun.SPI_WriteReadByte = (unsigned char)(*0)(unsigned char);#endifcb->InPara.timeout = 0;return S_OK;     }return S_ERROR;
}//初始化输入参数
unsigned char  NorFlash_InitInPara(tagNorFlashCB *cb, unsigned long timeout)
{if(cb){cb->InPara.timeout = timeout;return S_OK;}return S_ERROR;
}//初始化输入函数
unsigned char  NorFlash_InitInFun(tagNorFlashCB *cb,void *Init(void),void *Select(void),void *DisSelect(void),void *SetSpeed(unsigned char),unsigned char *WriteReadByte(unsigned char *))
{if(cb){cb->InFun.SPI_Init = Init;cb->InFun.SPI_Select = Select;cb->InFun.SPI_DisSelect = DisSelect;cb->InFun.SPI_SetSpeed = SetSpeed;cb->InFun.SPI_WriteReadByte = WriteReadByte;return S_OK;}return S_ERROR;
}//初始化W25Qxx
unsigned char NorFlash_Init(tagNorFlashCB *cb)
{unsigned char i;if(cb){//初始化SPIif(cb->InFun.SPI_Init){cb->InFun.SPI_Init();}else{return S_ERROR;}//软件复位芯片//NorFlash_SoftReset(cb);//读取芯片的厂家IDcb->OutPara.dev_id = NorFlash_DevId(cb);//识别芯片for(i = 0; i < NorFlash_ID_MAX; i++){if(cb->OutPara.dev_id == NorFlashDevID[i]){cb->OutPara.totalsize = NorFlashTotalSizeTable[i];cb->OutPara.sectorcount = cb->OutPara.totalsize/FLASH_SECTOR_SIZE;cb->OutPara.sectorsize = FLASH_SECTOR_SIZE;cb->OutPara.blocksize = 16;}}return S_OK;}return S_ERROR;
}//芯片软件复位
unsigned char NorFlash_SoftReset(tagNorFlashCB *cb)
{if(cb){if(cb->InFun.SPI_Select){cb->InFun.SPI_Select();}else{return S_ERROR;}if(cb->InFun.SPI_WriteReadByte){cb->InFun.SPI_WriteReadByte(W25Qxx_Reset_Enable);cb->InFun.SPI_WriteReadByte(W25Qxx_Reset_Cmd);}else{return S_ERROR;}if(cb->InFun.SPI_DisSelect){cb->InFun.SPI_DisSelect();}else{return S_ERROR;}//应该需要等待复位完成、50usreturn S_OK;}return S_ERROR;
}//读取设备id
unsigned short NorFlash_DevId(tagNorFlashCB *cb)
{unsigned short dev_id = 0;if(cb){if(cb->InFun.SPI_Select){cb->InFun.SPI_Select();}else{return S_ERROR;}if(cb->InFun.SPI_WriteReadByte){cb->InFun.SPI_WriteReadByte(W25Qxx_READ_DEV_ID);cb->InFun.SPI_WriteReadByte(0x00);cb->InFun.SPI_WriteReadByte(0x00);cb->InFun.SPI_WriteReadByte(0x00);dev_id |= cb->InFun.SPI_WriteReadByte(0xFF) << 8;dev_id |= cb->InFun.SPI_WriteReadByte(0xFF);}if(cb->InFun.SPI_DisSelect){cb->InFun.SPI_DisSelect();}else{return S_ERROR;}return dev_id;}return S_ERROR;
}//写使能
unsigned char NorFlash_Write_Enable(tagNorFlashCB *cb)
{if(cb){if(cb->InFun.SPI_Select){cb->InFun.SPI_Select();}else{return S_ERROR;}if(cb->InFun.SPI_WriteReadByte){cb->InFun.SPI_WriteReadByte(W25Qxx_WRITE_ENABLE);}else{return S_ERROR;}if(cb->InFun.SPI_DisSelect){cb->InFun.SPI_DisSelect();}else{return S_ERROR;}return S_OK;}return S_ERROR;
}//写禁止
unsigned char NorFlash_Write_Disable(tagNorFlashCB *cb)
{if(cb){if(cb->InFun.SPI_Select){cb->InFun.SPI_Select();}else{return S_ERROR;}if(cb->InFun.SPI_WriteReadByte){cb->InFun.SPI_WriteReadByte(W25Qxx_WRITE_DISABLE);}else{return S_ERROR;}if(cb->InFun.SPI_DisSelect){cb->InFun.SPI_DisSelect();}else{return S_ERROR;}return S_OK;}return S_ERROR;
}   //待等芯片空闲
unsigned char NorFlash_Wait_Busy(tagNorFlashCB *cb)
{unsigned long timeout = 0;if(cb){while(NorFlash_Read_Regs(cb,W25Qxx_STA_REG_1)&0x01){timeout++;if(timeout > FLASH_TIME_OUT){break;}}if(timeout <= FLASH_TIME_OUT){return S_OK;}else{return S_ERROR;}}return S_ERROR;
}//擦除扇区
unsigned char NorFlash_Erase_Sec(tagNorFlashCB *cb, unsigned short sec_id)
{unsigned long sec_addr = 0;if(cb){//扇区id有效性检查if(sec_id > cb->OutPara.totalsize/FLASH_SECTOR_SIZE){return S_ERROR;}//等待芯片空闲NorFlash_Wait_Busy(cb);//写使能NorFlash_Write_Enable(cb);if(cb->InFun.SPI_Select){cb->InFun.SPI_Select();}else{return S_ERROR;}//扇区的序号转化为扇区地址sec_addr = sec_id * FLASH_SECTOR_SIZE;if(cb->InFun.SPI_WriteReadByte){cb->InFun.SPI_WriteReadByte(W25Qxx_ERASE_SEC);cb->InFun.SPI_WriteReadByte((unsigned char)((sec_addr)>>16));cb->InFun.SPI_WriteReadByte((unsigned char)((sec_addr)>>8));cb->InFun.SPI_WriteReadByte((unsigned char)(sec_addr));}if(cb->InFun.SPI_DisSelect){cb->InFun.SPI_DisSelect();}else{return S_ERROR;}//等待芯片空闲NorFlash_Wait_Busy(cb);return S_OK;}return S_ERROR;
}//全片擦除、花费时钟较长
unsigned char NorFlash_Erase_Chip(tagNorFlashCB *cb)
{if(cb){//等待芯片空闲NorFlash_Wait_Busy(cb);//先写使能NorFlash_Write_Enable(cb);//片选if(cb->InFun.SPI_Select){cb->InFun.SPI_Select();}else{return S_ERROR;}//发送全片擦除指令if(cb->InFun.SPI_WriteReadByte){cb->InFun.SPI_WriteReadByte(W25Qxx_Erase_Chip1);}else{return S_ERROR;}//取消片选if(cb->InFun.SPI_DisSelect){cb->InFun.SPI_DisSelect();}else{return S_ERROR;}//等待擦操作完成、这里需要下、死等可能导致看门狗复位、//有操作系统的话使用可以使用OS的延迟、让出CPU、防止看门狗复位//我这里使用的FreeRTOS//vTaskDelay(5000);  //延迟5swhile(NorFlash_Read_Regs(cb,1)&0x1);return S_OK;}return S_ERROR;
}//读取状态寄存器的值
unsigned char NorFlash_Read_Regs(tagNorFlashCB *cb, emNorFlashReg_ID reg_id)
{if(reg_id >= W25Qxx_STA_REG_MAX){return S_ERROR;}unsigned char reg_val = 0;if(cb){if(cb->InFun.SPI_Select){cb->InFun.SPI_Select();}else{return S_ERROR;}if(cb->InFun.SPI_WriteReadByte){if(W25Qxx_STA_REG_1 == reg_id){cb->InFun.SPI_WriteReadByte(W25Qxx_Read_StaReg1);}else if(W25Qxx_STA_REG_2 == reg_id){cb->InFun.SPI_WriteReadByte(W25Qxx_Read_StaReg2);}else{cb->InFun.SPI_WriteReadByte(W25Qxx_Read_StaReg3);}reg_val = cb->InFun.SPI_WriteReadByte(0xFF);}else{return S_ERROR;}if(cb->InFun.SPI_DisSelect){cb->InFun.SPI_DisSelect();}else{return S_ERROR;}return reg_val;}return S_ERROR;
}//读取指定地址数据
unsigned char NorFlash_ReadData(tagNorFlashCB *cb,unsigned char *pbuffer,unsigned long  r_addr,unsigned short r_len)
{if((pbuffer == (void*)0)||(r_addr + r_len) > cb->OutPara.totalsize){return S_ERROR;}unsigned short i;if(cb){if(cb->InFun.SPI_Select){cb->InFun.SPI_Select();}else{return S_ERROR;}if(cb->InFun.SPI_WriteReadByte){cb->InFun.SPI_WriteReadByte(W25Qxx_READ_DATA);cb->InFun.SPI_WriteReadByte((unsigned char)(r_addr>>16));cb->InFun.SPI_WriteReadByte((unsigned char)(r_addr>>8));cb->InFun.SPI_WriteReadByte((unsigned char)(r_addr));//读取数据for(i = 0; i < r_len; i++){pbuffer[i] = cb->InFun.SPI_WriteReadByte(0xFF);}}else{return S_ERROR;}if(cb->InFun.SPI_DisSelect){cb->InFun.SPI_DisSelect();}else{return S_ERROR;}return S_OK;}return S_ERROR;
}//页编程 256个字节
unsigned char NorFlash_Write_Page(tagNorFlashCB *cb,unsigned char *pbuffer,unsigned long  w_addr,unsigned short w_len)
{if((pbuffer == (void*)0)||(w_addr + w_len) > cb->OutPara.totalsize|| w_len > FLASH_PAGE_SIZE)   //页大小256字节{return S_ERROR;}unsigned short i;if(cb){//需先写使能NorFlash_Write_Enable(cb);//片选if(cb->InFun.SPI_Select){cb->InFun.SPI_Select();}else{return S_ERROR;}if(cb->InFun.SPI_WriteReadByte){cb->InFun.SPI_WriteReadByte(W25Qxx_PAGE_PROGRAM);  //发送02功能码cb->InFun.SPI_WriteReadByte((unsigned char)(w_addr>>16));  //24位写地址cb->InFun.SPI_WriteReadByte((unsigned char)(w_addr>>8));  cb->InFun.SPI_WriteReadByte((unsigned char)(w_addr));  //发送数据for(i = 0; i < w_len; i++){cb->InFun.SPI_WriteReadByte(pbuffer[i]);  }}else{return S_ERROR;}if(cb->InFun.SPI_DisSelect){cb->InFun.SPI_DisSelect();}else{return S_ERROR;}//等待数据写入完成NorFlash_Wait_Busy(cb);return S_OK;}return S_ERROR;
}//写多页操作
unsigned char NorFlash_Write_Pages(tagNorFlashCB *cb,unsigned char *pbuffer,unsigned long  w_addr,unsigned short w_len)
{if((pbuffer == (void*)0)||(w_addr + w_len) >= cb->OutPara.totalsize){return S_ERROR;}unsigned short page_remain = 0;page_remain = FLASH_PAGE_SIZE - w_addr%FLASH_PAGE_SIZE;//判断该页的剩余空间是否可以写完if(page_remain >= w_len){page_remain = w_len;}while(1){NorFlash_Write_Page(cb,pbuffer,w_addr,page_remain);if(page_remain == w_len){break;}else{pbuffer += page_remain;w_addr += page_remain;w_len -= page_remain;if(w_len > FLASH_PAGE_SIZE){page_remain = FLASH_PAGE_SIZE;}else{page_remain = w_len;}}}return S_OK;
}//写数据 - 有检查是否擦除
unsigned char NorFlash_Wirte(tagNorFlashCB *cb,unsigned char *pbuffer,unsigned long w_addr,unsigned short w_len)
{if((pbuffer == (void*)0)||(w_addr + w_len > cb->OutPara.totalsize)){return S_ERROR;}unsigned short i;unsigned short erase_flag = 0;unsigned short sec_id, sec_offset, sec_remain;//计算当前写入的扇区信息sec_id = w_addr/FLASH_SECTOR_SIZE;sec_offset = w_addr%FLASH_SECTOR_SIZE;sec_remain = FLASH_SECTOR_SIZE - sec_offset;//判断剩余空间是否可以写完成if(sec_remain >= w_len){sec_remain = w_len;}while(1){//将当前扇区里面的内容全部读出来NorFlash_ReadData(cb,cb->Prv.DataBuff,sec_id*FLASH_SECTOR_SIZE,FLASH_SECTOR_SIZE);//判断是否需要擦除for(i = sec_offset; i < FLASH_SECTOR_SIZE; i++){if(cb->Prv.DataBuff[i] != 0xFF){erase_flag = 1;break;}erase_flag = 0;}//擦除扇区if(1 == erase_flag){NorFlash_Erase_Sec(cb,sec_id);}//拷贝数据for(i = 0; i < sec_remain; i++){cb->Prv.DataBuff[i+sec_offset] = pbuffer[i];}//写入数据NorFlash_Write_Pages(cb,cb->Prv.DataBuff,sec_id*FLASH_SECTOR_SIZE, FLASH_SECTOR_SIZE);//判断本次是否写完成if(sec_remain == w_len){break;}else{//这里已经页对齐了sec_id++;sec_offset = 0;pbuffer += sec_remain;w_addr += sec_remain;w_len -= sec_remain;if(w_len > FLASH_SECTOR_SIZE){sec_remain = FLASH_SECTOR_SIZE;}else{sec_remain = w_len;}}}return S_OK;
}

6、使用举例

已经在STMF4、W25Q128 norFlash测试ok
其他平台暂未测试、请注意。


static uint16_t dev_id = 0;
uint8_t WBuffer[] = "hello world!";
uint8_t RBuffer[100];
tagNorFlashCB NorFlashcb;  //定义NorFlash控制块
void Flash_Test_Task(void *Para)
{   tagNorFlashCB *pcb = &NorFlashcb;NorFlash_DeInit(pcb);//初始化控制块中输入函数、挂SPI接口NorFlash_InitInFun(pcb,  BSP_SPIx_Init,BSP_SPIx_Select,BSP_SPIx_DisSelect,BSP_SPIx_SetSpeed,BSP_SPIx_WriteReadByte);//初始化控制输入参数、超时时间NorFlash_InitInPara(pcb,0x7FFF);//初始化W25Qx128芯片、读写芯片设备号NorFlash_Init(pcb);while(1){memset(RBuffer,0,100);//写操作NorFlash_Wirte(pcb,WBuffer,12000,sizeof(WBuffer));vTaskDelay(1000);        //读操作NorFlash_ReadData(pcb,RBuffer,12000,sizeof(WBuffer));vTaskDelay(1000);}
}

W25Q128芯片的SPI驱动设计相关推荐

  1. 钜泉光电ATT7053C芯片STM32 SPI驱动

    一.硬件(低速)光耦隔离,测试速率40Kbps较稳定,80Kbps不稳定. 二.MX软件SPI配置 SPI读函数 void Read_ATT7053_B( uint8_t addr, uint8_t ...

  2. spi 协议驱动设计

    spi 协议驱动设计 MISO– Master Input Slave Output,主设备数据输入,从设备数据输出. MOSI– Master Output Slave Input,主设备数据输出, ...

  3. 基于ART-PI SPI驱动W25Q128

    吐槽和避坑 弄spi弄了一天,使用的开发板是art-pi家的h750,本来准备直接用rt-thread studio生成的,但是不知道怎么回事配置出的工程文件都有问题,不是线程运行不了就是缺少定义,所 ...

  4. ESP32系列:三线SPI硬件设计及程序驱动设计(SPI FLASH为例)

    (1)三线SPI硬件设计 首先,ESP32是支持三线制和四线制的,三线制为半双工通信,四线制为全双工通信.如果你们用的芯片不支持三线制,就不要再折腾了,支不支持三线制,看芯片的datasheet.如图 ...

  5. STM32CubeMX | 基于STM32使用HAL库硬件SPI驱动WK2124一拖四SPI转四路串口芯片

    STM32CubeMX | 基于STM32使用HAL库硬件SPI驱动WK2124一拖四SPI转四路串口芯片 STM32基础工程生成 首先使用STM32CUBEMX生成STM32的基础工程,配置时钟到7 ...

  6. AT32F437VM SPI驱动AT7456E OSD芯片

    上篇文章讲了BF固件中关于OSD的代码部分,今天来看一下硬件部分. 使用AT的芯片配置SPI和OSD芯片通讯. 先配置一下AT32F437的时钟: /************************* ...

  7. 基于MM32SPIN360C芯片的低压无刷电机设计 电机开发板驱动有感 BLDC 的操作方法

    近年来,无刷直流电动机在众多领域中得到广泛应用.无论是电动汽车.家用电器,还是工业控制和医疗器械都有它的身影.无刷直流电动机之所以如此广受青睐,除了保持了有刷直流电动机优越的启动性能和调速性能外,其最 ...

  8. Linux驱动修炼之道-SPI驱动框架源码分析(上)

    Linux驱动修炼之道-SPI驱动框架源码分析(上)   SPI协议是一种同步的串行数据连接标准,由摩托罗拉公司命名,可工作于全双工模式.相关通讯设备可工作于m/s模式.主设备发起数据帧,允许多个从设 ...

  9. 线性序列机与串行接口ADC驱动设计与验证

    线性序列机与串行接口ADC驱动设计与验证 ADC128S022 型 ADC 内部工作原理 在 AC620 开发板上使用的模数转换器为逐次逼近型的低功耗芯片 ADC128S022,其具有 8 通道以及 ...

  10. (38)FPGA数码管驱动设计(第8天)

    (38)FPGA数码管驱动设计(第8天) 1 文章目录 1)文章目录 2)FPGA初级课程介绍 3)FPGA初级课程架构 4)FPGA数码管驱动设计(第8天) 5)技术交流 6)参考资料 2 FPGA ...

最新文章

  1. FCKeditor在线文本编辑器初级应用
  2. layout_gravity 和 gravity
  3. Linux之JDK安装
  4. 锅巴文件共享软件地址和说明
  5. model.evaluate 输出出一大串 ======================
  6. 《数据结构与算法分析:Java语言描述》.pdf
  7. android开发连接手机usb调试模式,安卓手机usb调试在哪里 安卓手机usb调试模式设置教程...
  8. iptables 报错 MASQUERADE':No such file or directory
  9. RL(Chapter 5): Monte Carlo Methods (MC) (蒙特卡洛方法)
  10. speedoffice文档中怎么删除页眉页脚
  11. 基于android7.1+msm8937充电学习---概述(1)
  12. C#实现简单点餐系统(winform框架)
  13. 纹理压缩(二) ETC格式
  14. Linux监控平台搭建Zabbix(资源)
  15. ES6将对象中同一类相加
  16. 微信pc支付 java_微信小程序+微信支付+java后台(springboot)使用的是微信官方支付SDK(附代码)...
  17. 智能机器人Cleverbot是怎样炼成的?
  18. 信息学奥赛入门资源推荐
  19. 汉诺塔(java版)
  20. python初识(三)

热门文章

  1. 奉劝各位学弟学妹们,该打造你的技术影响力了!
  2. ISACA最新白皮书助力企业了解中国《个人信息保护法》
  3. 仙剑缘_仙剑缘手游下载-仙剑缘最新版-仙剑缘手机版_易玩网
  4. 川大网页多媒体设计【李天翼班】资料整理
  5. 解决Unable to find a single main class from the following candidates
  6. 用 Python 给自己的头像加一个小国旗或者小月饼
  7. Windows系统下Android DNK r5环境配置和开发(二)
  8. zotero自定义导出参考文献bib格式
  9. 【考研】计算机考研复试之智力题测试
  10. 从冬奥会看中国科技:全民感谢的高速摄像机,有何玄机?