尧图精选

SPI读取W25Q64硬件驱动(HAL库)

🕒 发布时间:2026/10/2 2:18:52 📁 来源:尧图网络
CubeMx配置CSS片选选中时为低电平;MISO主机输入从机输出,上拉输入模式;MOSI主机输出从机输出,推挽输出模式;SCK时钟线。选用SPI1PB0作为片选线全双工主机模式配置如图:串口用来检测打印输出。全双工主机模式进行通信。MSB高位优先传输一次传输8bitNSS 片选信号类型为软件控制。设置波特率以及CPOL和CPHA的值规则如下CPOL:SPI 空闲时SCK是高电平还是低电平为0时为低电平;CPHA:在SCK的第几个边沿采样数据?可以设置为Edge1/2。所以有4种情况:W25Q64支持Mode0/3目前采用Mode0PB0接片选默认高电平。CPOLCPHA备注Mode 001Edge空闲为低电平上升沿采样Mode 102Edge空闲为低电平下降沿采样Mode 211Edge空闲为高电平下降沿采样Mode 312Edge空闲为高电平上升沿采样flash写入读取规则flash的写入和读取 写入时必须先写使能 每个数据只能从1变为0不能从0变为1。所以一般发送垃圾数据都发0XFF(什么都不改变 写入数据前必须擦除擦除后数据全为1最小单位是扇区4KB 连续写入多字节最多写入一页的数据 写入操作完成后芯片进入忙状态 读取: 不能在忙状态时读取。 地址格式[ 1 byte 指令码 ] [ 3 byte 地址 ] [ N byte 数据 ] 读取/写入发送指令然后发送24位地址然后读或者写数据片选线拉低后才能进行通信在 SPI Flash 中不仅是片选也是“帧开始/结束”的标志比如下面测试通信的代码要按照起始条件SS被选中高电平转低电平;交换一个字节模式0SCK空闲低电平第一个边沿采样移入移位寄存器第二个边沿从移位寄存器移出数据结束条件SS低电平转高电平。的格式。硬件驱动函数(SPI读取W25Q64)地址格式地址格式首位不用23位有效表示8M字节 0 0000000 00000000 00000000 如下 0 0000000 0000 0000 00000000 127个块(7bit) 16个扇区(4bit) 16个页(4bit) 每页256B(8bit)一次通信必须是完整的CS拉低、拉高中间不能插入别的事务。写使能/** * retval 帧开始/起始信号拉低片选线 */ void MySPI_Start(void) { //拉低片选线 PB0 HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET); } /** * retval 帧结束信号拉高片选线 */ void MySPI_Stop(void) { HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET); } /** * retval 写使能发送写使能指令表示要进行写入 */ void W25Q64_WriteEnable(void) {//写使能 uint8_t write_enable 0x06; MySPI_Start(); HAL_SPI_Transmit(hspi1, write_enable, 1, 10); MySPI_Stop(); }等待空闲/** * retval 状态寄存器1的bit0位是busy位为1时表示忙,为0时表示空闲 * */ void W25Q64_WaitBusy(void) { uint8_t cmd 0x05;//读状态寄存器1指令 uint8_t status; MySPI_Start(); HAL_SPI_Transmit(hspi1, cmd, 1, 100);//第0位是忙为 do { HAL_SPI_Receive(hspi1, status, 1, 100); }while ((status 0x01) 0x01); MySPI_Stop(); }获取设备ID/** * * param MID 制造商ID * param DID 设备ID * retval 获取设备ID,直接用三个uint8_t类型保存可以串口发送 */ void W25Q64_GetID(uint8_t* MID,uint8_t* DID1,uint8_t* DID2) { uint8_t cmd 0x9F; uint8_t id[3]; MySPI_Start(); HAL_SPI_Transmit(hspi1, cmd, 1, 100); HAL_SPI_Receive(hspi1, id, 3, 100); *MID id[0]; *DID1 id[1]; *DID2 id[2]; MySPI_Stop(); }页编程页编程顺序为写使能事务 → 页编程事务 → 等待空闲事务。WaitBusy 必须在页编程事务的CS拉高之后独立进行不能穿插在页编程事务的Start和Stop之间。页编程地址0x000FF100倒数第三位是页地址相当于对第1页进行编程。/** * * param Address 页编程的地址24bit * param DataArr 写入数据的起始地址 * param Count 写入数据的数目最多可以写入256个B * */ void W25Q64_PageProgram(uint32_t Address,uint8_t* DataArr,uint16_t Count) { //写使能 W25Q64_WriteEnable(); MySPI_Start(); //发送指令 uint8_t cmd 0x02; HAL_SPI_Transmit(hspi1, cmd, 1, 100); //发送24位地址 uint8_t address_buffer[3]; address_buffer[0] (uint8_t)(Address 16) 0xFF; address_buffer[1] (uint8_t)(Address 8) 0xFF; address_buffer[2] Address 0xFF; HAL_SPI_Transmit(hspi1, address_buffer, 3, 100); //循环发送Count个数据 HAL_SPI_Transmit(hspi1, DataArr, Count, 100); //等待空闲写入操作会置忙读取不会但空闲才能读取 W25Q64_WaitBusy(); MySPI_Stop(); }扇区擦除按扇区擦除对于24位地址0x000FF000后两位是256个页倒数第三位是页地址第四第五位是扇区所以相当于擦除第FF个扇区。/** * * param Address 要擦除的地址按扇区擦除4KB) */ void W25Q64_SectorEarse(uint32_t Address) { //一次SPI事务中CS不能中途释放。 W25Q64_WriteEnable(); MySPI_Start();//擦除就是全置1 //发送指令 uint8_t sector_erase_4KB 0x20; HAL_SPI_Transmit(hspi1, sector_erase_4KB, 1, 100); //提供地址 uint8_t address_buffer[3]; address_buffer[0] (uint8_t)(Address 16) 0xFF;//高8位 右移16bit address_buffer[1] (uint8_t)(Address 8) 0xFF;//中间8位 address_buffer[2] Address 0xFF;//低8位 //擦除 HAL_SPI_Transmit(hspi1, address_buffer, 3, 100); MySPI_Stop(); //等待擦除完毕/解除忙状态 W25Q64_WaitBusy(); }读数据/** * * param Address 24位地址 * param DataArr 存放读取的数据 * param Count 数据个数 * */ void W25Q64_ReadData(uint32_t Address,uint8_t* DataArr,uint32_t Count) { //等待忙状态取消 W25Q64_WaitBusy(); MySPI_Start(); //指令 uint8_t cmd 0x03; HAL_SPI_Transmit(hspi1, cmd, 1, 100); //地址 uint8_t address_buffer[3]; address_buffer[0] (uint8_t)(Address 16) 0xFF; address_buffer[1] (uint8_t)(Address 8) 0xFF; address_buffer[2] Address 0xFF; HAL_SPI_Transmit(hspi1, address_buffer, 3, 100); //接收数据 HAL_SPI_Receive(hspi1, DataArr, Count, 100); MySPI_Stop(); }
上一篇/下一篇内容由系统自动关联 返回资讯列表 →