STM32使用HAL库模拟SPI方式驱动W25Q128存芯片
- 1、模拟SPI方式的IO配置
- 2、位带操作宏定义
- 3、HAL库的延时函数
- 4、W25QXX代码实现
~~~~~~~~ 代码已经实际测试通过,可直接使用,注意一点就是IO口的配置方式要跟我一样,还有一点就是W25Q128的HOLD和WP引脚我是直接通过IO的方式控制的,你也可以直接将这两个引脚接到3.3V,这样的话就可以不使用单片机的IO口控制了,节省单片机IO。
1、模拟SPI方式的IO配置
2、位带操作宏定义
#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))
#define GPIOA_ODR_Addr (GPIOA_BASE+12)
#define GPIOB_ODR_Addr (GPIOB_BASE+12)
#define GPIOC_ODR_Addr (GPIOC_BASE+12)
#define GPIOD_ODR_Addr (GPIOD_BASE+12)
#define GPIOE_ODR_Addr (GPIOE_BASE+12)
#define GPIOF_ODR_Addr (GPIOF_BASE+12)
#define GPIOG_ODR_Addr (GPIOG_BASE+12)
#define GPIOA_IDR_Addr (GPIOA_BASE+8)
#define GPIOB_IDR_Addr (GPIOB_BASE+8)
#define GPIOC_IDR_Addr (GPIOC_BASE+8)
#define GPIOD_IDR_Addr (GPIOD_BASE+8)
#define GPIOE_IDR_Addr (GPIOE_BASE+8)
#define GPIOF_IDR_Addr (GPIOF_BASE+8)
#define GPIOG_IDR_Addr (GPIOG_BASE+8)
#define PAout(n) BIT_ADDR(GPIOA_ODR_Addr,n)
#define PAin(n) BIT_ADDR(GPIOA_IDR_Addr,n)
#define PBout(n) BIT_ADDR(GPIOB_ODR_Addr,n)
#define PBin(n) BIT_ADDR(GPIOB_IDR_Addr,n)
#define PCout(n) BIT_ADDR(GPIOC_ODR_Addr,n)
#define PCin(n) BIT_ADDR(GPIOC_IDR_Addr,n)
#define PDout(n) BIT_ADDR(GPIOD_ODR_Addr,n)
#define PDin(n) BIT_ADDR(GPIOD_IDR_Addr,n)
#define PEout(n) BIT_ADDR(GPIOE_ODR_Addr,n)
#define PEin(n) BIT_ADDR(GPIOE_IDR_Addr,n)
#define PFout(n) BIT_ADDR(GPIOF_ODR_Addr,n)
#define PFin(n) BIT_ADDR(GPIOF_IDR_Addr,n)
#define PGout(n) BIT_ADDR(GPIOG_ODR_Addr,n)
#define PGin(n) BIT_ADDR(GPIOG_IDR_Addr,n)
3、HAL库的延时函数
void delay_us(uint32_t us)
{
uint32_t delay = (HAL_RCC_GetHCLKFreq() / 4000000 * us);
while (delay--)
{
;
}
}
void delay_ms(uint32_t nms)
{
HAL_Delay(nms);
}
4、W25QXX代码实现
头文件
#ifndef __W25QXX_H
#define __W25QXX_H
#include "main.h"
#define W25Q80 0XEF13
#define W25Q16 0XEF14
#define W25Q32 0XEF15
#define W25Q64 0XEF16
#define W25Q128 0XEF17
extern uint16_t W25QXX_TYPE;
#define W25QXX_CS PCout(13)
#define W25QXX_SCK PCout(14)
#define W25QXX_MISO PAin(6)
#define W25QXX_MOSI PCout(15)
#define W25QXX_WP PBout(13)
#define W25QXX_HOLD PBout(14)
#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);
uint16_t W25QXX_ReadID(void);
uint8_t W25QXX_ReadSR(void);
void W25QXX_Write_SR(uint8_t sr);
void W25QXX_Write_Enable(void);
void W25QXX_Write_Disable(void);
void W25QXX_Write_NoCheck(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite);
void W25QXX_Read(uint8_t* pBuffer,uint32_t ReadAddr,uint16_t NumByteToRead);
void W25QXX_Write(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite);
void W25QXX_Erase_Chip(void);
void W25QXX_Erase_Sector(uint32_t Dst_Addr);
void W25QXX_Wait_Busy(void);
void W25QXX_PowerDown(void);
void W25QXX_WAKEUP(void);
#endif
源文件
#include
#include "delay.h"
#include "w25qxx.h"
uint16_t W25QXX_TYPE = 0;
static uint8_t SPI_ReadWriteByte(uint8_t TxData)
{
int i = 0;
uint8_t RxData = 0;
W25QXX_SCK = 0;
for(i = 7; i >= 0; i--)
{
W25QXX_SCK = 0;
if(TxData & (1 << i))
{
W25QXX_MOSI = 1;
}
else
{
W25QXX_MOSI = 0;
}
delay_us(1);
W25QXX_SCK = 1;
RxData <<= 1;
RxData |= W25QXX_MISO;
delay_us(1);
}
W25QXX_SCK = 0;
return RxData;
}
void W25QXX_Init(void)
{
W25QXX_WP = 1;
W25QXX_HOLD = 1;
W25QXX_CS = 0;
SPI_ReadWriteByte(0XFF);
W25QXX_CS = 1;
W25QXX_SCK = 0;
W25QXX_TYPE=W25QXX_ReadID();
}
uint8_t W25QXX_ReadSR(void)
{
uint8_t byte=0;
W25QXX_CS=0;
SPI_ReadWriteByte(W25X_ReadStatusReg);
byte=SPI_ReadWriteByte(0Xff);
W25QXX_CS=1;
return byte;
}
void W25QXX_Write_SR(uint8_t sr)
{
W25QXX_CS=0;
SPI_ReadWriteByte(W25X_WriteStatusReg);
SPI_ReadWriteByte(sr);
W25QXX_CS=1;
}
void W25QXX_Write_Enable(void)
{
W25QXX_CS=0;
SPI_ReadWriteByte(W25X_WriteEnable);
W25QXX_CS=1;
}
void W25QXX_Write_Disable(void)
{
W25QXX_CS=0;
SPI_ReadWriteByte(W25X_WriteDisable);
W25QXX_CS=1;
}
uint16_t W25QXX_ReadID(void)
{
uint16_t Temp = 0;
W25QXX_CS=0;
SPI_ReadWriteByte(0x90);
SPI_ReadWriteByte(0x00);
SPI_ReadWriteByte(0x00);
SPI_ReadWriteByte(0x00);
Temp|=SPI_ReadWriteByte(0xFF)<<8;
Temp|=SPI_ReadWriteByte(0xFF);
W25QXX_CS=1;
return Temp;
}
void W25QXX_Read(uint8_t* pBuffer,uint32_t ReadAddr,uint16_t NumByteToRead)
{
uint16_t i;
W25QXX_CS=0;
SPI_ReadWriteByte(W25X_ReadData);
SPI_ReadWriteByte((uint8_t)((ReadAddr)>>16));
SPI_ReadWriteByte((uint8_t)((ReadAddr)>>8));
SPI_ReadWriteByte((uint8_t)ReadAddr);
for(i=0; i<NumByteToRead; i++)
{
pBuffer[i]=SPI_ReadWriteByte(0XFF);
}
W25QXX_CS=1;
}
void W25QXX_Write_Page(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite)
{
uint16_t i;
W25QXX_Write_Enable();
W25QXX_CS=0;
SPI_ReadWriteByte(W25X_PageProgram);
SPI_ReadWriteByte((uint8_t)((WriteAddr)>>16));
SPI_ReadWriteByte((uint8_t)((WriteAddr)>>8));
SPI_ReadWriteByte((uint8_t)WriteAddr);
for(i=0; i<NumByteToWrite; i++)SPI_ReadWriteByte(pBuffer[i]);
W25QXX_CS=1;
W25QXX_Wait_Busy();
}
void W25QXX_Write_NoCheck(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite)
{
uint16_t 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;
}
};
}
uint8_t W25QXX_BUFFER[4096];
void W25QXX_Write(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite)
{
uint32_t secpos;
uint16_t secoff;
uint16_t secremain;
uint16_t i;
uint8_t * 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;
SPI_ReadWriteByte(W25X_ChipErase);
W25QXX_CS=1;
W25QXX_Wait_Busy();
}
void W25QXX_Erase_Sector(uint32_t Dst_Addr)
{
Dst_Addr*=4096;
W25QXX_Write_Enable();
W25QXX_Wait_Busy();
W25QXX_CS=0;
SPI_ReadWriteByte(W25X_SectorErase);
SPI_ReadWriteByte((uint8_t)((Dst_Addr)>>16));
SPI_ReadWriteByte((uint8_t)((Dst_Addr)>>8));
SPI_ReadWriteByte((uint8_t)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;
SPI_ReadWriteByte(W25X_PowerDown);
W25QXX_CS=1;
delay_us(3);
}
void W25QXX_WAKEUP(void)
{
W25QXX_CS=0;
SPI_ReadWriteByte(W25X_ReleasePowerDown);
W25QXX_CS=1;
delay_us(3);
}