STM32F030 HAL库硬件SPI操作W25Q16存储芯片(二)
上篇文章介绍了W25Q16芯片的一些基本信息,这篇主要介绍编程操作。
/*封装读写操作
SPI 读写一个字节
//TxData:要写入的字节
//返回值:读取到的字节
*/
uint8_t SPI_ReadWriteByte(uint8_t TxData)
{
uint8_t Rxdata;
HAL_SPI_TransmitReceive(&hspi2, &TxData, &Rxdata, 1, 1000);
return Rxdata; //返回收到的数据
}
/********************************************************************* :
BIT: 7 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
**********************************************************************/
uint8_t SPI_W25X_ReadSR(void)
{
uint8_t byte = 0;
W25_CS_L; /*enable chip selection*/
SPI_ReadWriteByte(W25X_ReadStatusReg); /*send read status register command */
byte = SPI_ReadWriteByte(0Xff); /*read one byte */
W25_CS_H; /*disable chip selection*/
return byte;
}
void SPI_W25X_Write_SR(uint8_t sr)
{
W25_CS_L; /*enable chip selection*/
SPI_ReadWriteByte(W25X_WriteStatusReg); /*send write status register command */
SPI_ReadWriteByte(sr); /*write one byte*/
W25_CS_H; /*disable chip selection*/
}
void SPI_W25X_Write_Enable(void)
{
W25_CS_L; /*enable chip selection*/
SPI_ReadWriteByte(W25X_WriteEnable); /*send write enable*/
W25_CS_H; /*disable chip selection*/
}
uint16_t SPI_W25X_ReadID(void)
{
uint16_t Temp = 0;
W25_CS_L; /*enable chip selection*/
SPI_ReadWriteByte(W25X_ManufactDeviceID);
SPI_ReadWriteByte(0x00);
SPI_ReadWriteByte(0x00);
SPI_ReadWriteByte(0x00);
Temp |= SPI_ReadWriteByte(0xFF) << 8;
Temp |= SPI_ReadWriteByte(0xFF);
W25_CS_H;
return Temp;
}
void SPI_W25X_Read(uint8_t *pBuffer, uint32_t ReadAddr, uint16_t NumByteToRead)
{
uint16_t i;
W25_CS_L;
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);
}
W25_CS_H;
}
uint8_t SPI_W25X_Read_onebyte(unsigned int ReadAddr)
{
uint8_t tmp;
W25_CS_L;
SPI_ReadWriteByte(W25X_ReadData);
SPI_ReadWriteByte((uint8_t)((ReadAddr) >> 16));
SPI_ReadWriteByte((uint8_t)((ReadAddr) >> 8));
SPI_ReadWriteByte((uint8_t)ReadAddr);
tmp = SPI_ReadWriteByte(0XFF);
W25_CS_H;
return tmp;
}
//等待空闲
void SPI_W25X_Wait_Busy(void)
{
uint16_t uErrTime;
while ((SPI_W25X_ReadSR() & 0x01) == 0x01) // 等待BUSY位清空
{
uErrTime++;
if(uErrTime > 500)
{
break;
}
}
}
//-----------------------------------------------------------------------------
//擦除整个芯片
//整片擦除时间:
//W25X16:25s
//W25X32:40s
//W25X64:40s
//等待时间超长...
void SPI_W25X_Erase_Chip(void)
{
SPI_W25X_Write_Enable(); //SET WEL
SPI_W25X_Wait_Busy();
W25_CS_L; //使能片选
SPI_ReadWriteByte(W25X_ChipErase); //发送片擦除命令
W25_CS_H; //关闭片选
SPI_W25X_Wait_Busy(); //等待芯片擦除结束
}
//-----------------------------------------------------------------------------
//擦除一个扇区
//Dst_Addr:扇区地址 0~511 for w25x16
//擦除一个山区的最少时间:150ms
void SPI_W25X_Erase_Sector(uint32_t Dst_Addr)
{
Dst_Addr *= 4096;
SPI_W25X_Write_Enable(); //SET WEL
SPI_W25X_Wait_Busy();
W25_CS_L; //使能片选
SPI_ReadWriteByte(W25X_SectorErase); //发送扇区擦除指令
SPI_ReadWriteByte((uint8_t)((Dst_Addr) >> 16)); //发送24bit地址
SPI_ReadWriteByte((uint8_t)((Dst_Addr) >> 8));
SPI_ReadWriteByte((uint8_t)Dst_Addr);
W25_CS_H; //关闭片选
SPI_W25X_Wait_Busy(); //等待擦除完成
}
//-----------------------------------------------------------------------------
//在一页(0~65535)内写入少于256个字节的数据
//从指定地址开始写入最大256字节的数据
//pBuffer:数据存储区地址
//WriteAddr:写入区首地址
//NumByteToWrite:待写入的字节数(最大256,且不得超过本页的剩余字节数)
void SPI_W25X_Write_Page(uint8_t *pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite)
{
uint16_t i;
SPI_W25X_Write_Enable(); //使能片选
W25_CS_L;
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]);
}
W25_CS_H; //关闭片选
SPI_W25X_Wait_Busy(); //等待写入结束
}
//-----------------------------------------------------------------------------
//无检验写SPI FLASH
//必须确保所写的地址范围内的数据全部为0XFF,否则在非0XFF处写入的数据将失败!
//具有自动换页功能
//在指定地址开始写入指定长度的数据,但是要确保地址不越界!
//pBuffer:数据存储区
//WriteAddr:开始写入的地址(24bit)
//NumByteToWrite:要写入的字节数(最大65535)
//CHECK OK
void SPI_W25X_Write_NoCheck(uint8_t *pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite)
{
uint16_t pageremain;
pageremain = 256 - WriteAddr % 256;
if (NumByteToWrite <= pageremain)
pageremain = NumByteToWrite; //不大于256字节
while (1)
{
SPI_W25X_Write_Page(pBuffer, WriteAddr, pageremain);
if (NumByteToWrite == pageremain)
break; //写入结束
else
{
pBuffer += pageremain;
WriteAddr += pageremain;
NumByteToWrite -= pageremain; //减去已经写入的字节
if (NumByteToWrite > 256)
pageremain = 256;
else
pageremain = NumByteToWrite; //不够256个字节
}
}
}
//-----------------------------------------------------------------------------
//写W25X
//在指定地址开始写入指定长度的数据
//pBuffer:数据存储区
//WriteAddr:开始写入的地址(24bit)
//NumByteToWrite:要写入的字节数(最大65535)
uint8_t W25X_BUF[4096];
void SPI_W25X_Write(uint8_t *pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite)
{
uint32_t secpos;
uint16_t secoff;
uint16_t secremain;
uint16_t i;
secpos = WriteAddr / 4096; //扇区地址
secoff = WriteAddr % 4096; //在扇区内的偏移
secremain = 4096 - secoff; //扇区剩余空间
if (NumByteToWrite <= secremain)
secremain = NumByteToWrite; //不大于4096字节
while (1)
{
SPI_W25X_Read(W25X_BUF, secpos * 4096, 4096); //读该扇区
for (i = 0; i < secremain; i++) //校验
{
if (W25X_BUF[secoff + i] != 0XFF)
break; //需要擦除
}
if (i < secremain) //需要擦除
{
SPI_W25X_Erase_Sector(secpos); //擦除该扇区
for (i = 0; i < secremain; i++) //复制
{
W25X_BUF[i + secoff] = pBuffer[i];
}
SPI_W25X_Write_NoCheck(W25X_BUF, secpos * 4096, 4096); //写扇区
}
else
SPI_W25X_Write_NoCheck(pBuffer, WriteAddr, secremain); //已经擦除,直接写入剩余扇区
if (NumByteToWrite == secremain)
break; //写入完成
else //写入未完
{
secpos++; //扇区地址增1
secoff = 0; //偏移位置为0
pBuffer += secremain;
WriteAddr += secremain;
NumByteToWrite -= secremain;
if (NumByteToWrite > 4096)
secremain = 4096; //下一扇区仍不够
else
secremain = NumByteToWrite; //下一扇区可以写完
}
}
}
//-----------------------------------------------------------------------------
//进入掉电模式
void SPI_W25X_PowerDown(void)
{
W25_CS_L; //使能片选
SPI_ReadWriteByte(W25X_PowerDown); //发送掉电命令
W25_CS_H; //关闭片选
Delay_ms(3); //等待TPD
}
//-----------------------------------------------------------------------------
//唤醒
void SPI_W25X_WAKEUP(void)
{
W25_CS_L; //使能片选
SPI_ReadWriteByte(W25X_ReleasePowerDown); // send W25X_PowerDown command 0xAB
W25_CS_H; //关闭片选
Delay_ms(3); //等待TRES1
}
以下链接为STM32Cube 配置测试完的完成工程文档,芯片为STM32F030 硬件SPI读写W25Q16,使用HAL库编写,有需要的朋友可点击链接下载!
(43条消息) 基于STM32CubeMX-STM32F030HAL库对W25Q16读写操作-C文档类资源-CSDN文库
STM32F030 HAL库硬件SPI操作W25Q16存储芯片(二)相关推荐
- STM32F030 HAL库硬件SPI操作W25Q16存储芯片(一)
芯片:华邦W25Q16JV W25Q16JV (16m位)串行闪存为有限空间.引脚和电源的系统提供了存储解决方案.25Q系列提供了超越普通串行闪存设备的灵活性和性能.它们非常适合代码跟踪到RAM,直接 ...
- STM32CubeMX | 基于STM32使用HAL库硬件SPI驱动WK2124一拖四SPI转四路串口芯片
STM32CubeMX | 基于STM32使用HAL库硬件SPI驱动WK2124一拖四SPI转四路串口芯片 STM32基础工程生成 首先使用STM32CUBEMX生成STM32的基础工程,配置时钟到7 ...
- 单片机:STM32F4x HAL库软硬SPI驱动ST7735s 1.8寸LCD屏幕
单片机:STM32F4x HAL库软硬SPI驱动ST7735s 1.8寸LCD屏幕 说明:此篇为学习记录.可能存在错误或者不足.如有问题请指出. 硬件环境 主控芯片:STM32F411CEU6 主控开 ...
- LSM6DS3TR-C姿态传感器的使用(二)---HAL库硬件IIC和官方例程
上篇记录了,利用模拟IIC读取LSM6DS3TR数据,这篇记录利用硬件IIC和LSM6DS3TR官方例程,读取加速计.陀螺仪.温度数据,并利用加速计数据装换成角度. 官网例程写的很好,有兴趣的网友可以 ...
- 简单的记录一下使用HAL库的SPI外挂W25Q32
简单的记录一下使用HAL库的SPI外挂W25Q32 抽筋了,想记录一下. cubeMX配置SPI CS脚 spi.h 里添加 #define FLASH_ID 0XEF14//指令表#define W ...
- HAL库硬件IIC_MPU6050_DMP移植
HAL库硬件IIC_MPU6050_DMP移植 一.CUBEMX基本配置 本篇博客只介绍如何在HAL库进行移植代码,所以只开启了一些必要的端口:I2C1,USART1,另外介绍一下本文基于芯片ST ...
- STM32 HAL库 STM32CubeMX -- SPI
文章目录 一.SPI 协议简介 SPI 物理层 SPI 协议层 二.SPI 的架构 三.通讯过程 四.STM32Cube MX配置 五.SPI HAL库函数 一.SPI 协议简介 SPI (Seria ...
- STM8L151 使用硬件SPI驱动W25Q16 Flash
SPI:有四根线的串行通信协议,允许与其他设备以半.全双工.同步.串行方式通信. MISO:主模式输入.从模式输出线 MOSI:主模式输出.从模式输入线 CLK:时钟线 NSS:从设备选择引脚,主设备 ...
- STM32 (基于HAL库) 硬件IIC读写任意AT24CXX芯片
HAL任意AT24Cxx芯片读写: 原理我就不讲了,直接实操: 一.配置 1.使用STM32CUBEMX进行引脚配置,IIC配置如下: 2.利用串口进行数据查看,串口配置如下: 3.时钟我们选择最高7 ...
最新文章
- iOS-仿膜拜贴纸滚动(物理仿真)
- js 阻断网页选中和右键
- 数据库系统概论:第七章 数据库设计
- SpringCloud入门之Maven系统安装及配置
- Python+matplotlib绘制函数曲线查找函数极值
- Python爬虫之Cookie和Session(转载)
- netbeans使用教程
- Ubuntu上安装visual studio code
- MapReduce环境准备
- 刘宇凡:一棵树给我的真理
- 无限循环小数四则运算_无限循环小数不能进行四则运算
- 电子技术基础(三)__电感的感抗_无功功率和电容的容抗_无功功率
- 输出所有3位数的水仙花数,例:153=1的3次方+5的3次方+3的3次方 谭浩强《c语言程序设计》第五章第八题
- 【模型】【课程笔记】01+02+03 金融风险管理导论
- 第一章:计算机硬件知识
- C++定义结构体大小根堆的方法
- 移动聊天工具Kakao要开网络银行 牌照有望下月到手
- 做程序员,就是修自己的佛,渡众生的苦--看看散文缓缓心情吧
- etry error, curr request is null
- 手机QQ安卓版下载【正式版】