- 学习目标
- 学习内容
- ifndef BSPW25Q64_H
- define BSPW25Q64_H
- include “gd32f4xx.h”
- include “SPI.h”
- define W25Q_CS_PORT_RCU RCU_GPIOF
- define W25Q_CS_PORT GPIOF
- define W25Q_CS_PIN GPIO_PIN_6
- define W25Q_CS_SELECT() gpio_bit_write(W25Q_CS_PORT, W25Q_CS_PIN, RESET)
- define W25Q_CS_UNSELECT() gpio_bit_write(W25Q_CS_PORT, W25Q_CS_PIN, SET)
- define W25Q_SPI_RD_WR(data) SPI4_read_write(data)
- endif
学习目标
- 掌握w25q128的移植
- 熟悉驱动开发学习方式
学习内容
原理图
W25Q128介绍
W25Q128是一种常见的串行闪存器件,它采用SPI(Serial Peripheral Interface)接口协议,具有高速读写和擦除功能,可用于存储和读取数据。W25Q128芯片容量为128 M-bit(16 M-byte),其中名称后的数字代表不同的容量选项。不同的型号和容量选项可以满足不同应用的需求,比如W25Q16、W25Q32、W25Q128等。通常被用于嵌入式设备、存储设备、路由器等高性能电子设备中。
W25Q128闪存芯片的内存分配是按照扇区(Sector)和块(Block)进行的,每个扇区的大小为4KB,每个块包含16个扇区,即一个块的大小为64KB。
实现参考
https://lceda001.feishu.cn/wiki/Yl6mwgNQiiwolrkqBbscxk45nFb封装改造
官方示例中,耦合太强,进行一些修改,修改后如下: ```cifndef BSPW25Q64_H
define BSPW25Q64_H
include “gd32f4xx.h”
include “SPI.h”
define W25Q_CS_PORT_RCU RCU_GPIOF
define W25Q_CS_PORT GPIOF
define W25Q_CS_PIN GPIO_PIN_6
define W25Q_CS_SELECT() gpio_bit_write(W25Q_CS_PORT, W25Q_CS_PIN, RESET)
define W25Q_CS_UNSELECT() gpio_bit_write(W25Q_CS_PORT, W25Q_CS_PIN, SET)
define W25Q_SPI_RD_WR(data) SPI4_read_write(data)
void W25Q64_init(void); uint16_t W25Q64_readID(void); void W25Q64_write(uint8_t buffer, uint32_t addr, uint16_t numbyte); void W25Q64_read(uint8_t buffer,uint32_t read_addr,uint16_t read_length) ;
endif
```c#include "bsp_w25q64.h"void W25Q64_init(void){//开启CS引脚时钟rcu_periph_clock_enable(W25Q_CS_PORT_RCU);//配置CS引脚模式gpio_mode_set(W25Q_CS_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP, W25Q_CS_PIN);//配置CS输出模式gpio_output_options_set(W25Q_CS_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, W25Q_CS_PIN);//W25Q64不选中W25Q_CS_UNSELECT();}/******************************************************************* 函 数 名 称:spi_read_write_byte* 函 数 说 明:硬件SPI的读写* 函 数 形 参:dat=发送的数据* 函 数 返 回:读取到的数据* 作 者:LC* 备 注:无******************************************************************/static uint8_t spi_read_write_byte(uint8_t dat){return W25Q_SPI_RD_WR(dat);}/******************************************************************* 函 数 名 称:W25Q64_readID* 函 数 说 明:读取W25Q64的厂商ID和设备ID* 函 数 形 参:无* 函 数 返 回:设备正常返回EF16* 作 者:LC* 备 注:无******************************************************************/uint16_t W25Q64_readID(void){uint16_t temp = 0;gpio_bit_write(GPIOF, GPIO_PIN_6, RESET);spi_read_write_byte(0x90);//发送读取ID命令spi_read_write_byte(0x00);spi_read_write_byte(0x00);spi_read_write_byte(0x00);//接收数据temp |= spi_read_write_byte(0xFF)<<8;temp |= spi_read_write_byte(0xFF);gpio_bit_write(GPIOF, GPIO_PIN_6, SET);return temp;}/*********************************************************** 函 数 名 称:W25Q64_wait_busy* 函 数 功 能:判断W25Q64是否忙* 传 入 参 数:无* 函 数 返 回:无* 作 者:LC* 备 注:无**********************************************************/static void W25Q64_wait_busy(void){unsigned char byte = 0;do{gpio_bit_write(GPIOF, GPIO_PIN_6, RESET);spi_read_write_byte(0x05);byte = spi_read_write_byte(0Xff);gpio_bit_write(GPIOF, GPIO_PIN_6, SET);}while( ( byte & 0x01 ) == 1 );}/*********************************************************** 函 数 名 称:W25Q64_write_enable* 函 数 功 能:发送写使能* 传 入 参 数:无* 函 数 返 回:无* 作 者:LC* 备 注:无**********************************************************/void W25Q64_write_enable(void){W25Q_CS_SELECT();spi_read_write_byte(0x06);W25Q_CS_UNSELECT();}/*********************************************************** 函 数 名 称:W25Q64_erase_sector* 函 数 功 能:擦除一个扇区* 传 入 参 数:addr=擦除的扇区号* 函 数 返 回:无* 作 者:LC* 备 注:addr=擦除的扇区号,范围=0~15**********************************************************/void W25Q64_erase_sector(uint32_t addr){addr *= 4096;W25Q64_write_enable(); //写使能W25Q64_wait_busy(); //判断忙gpio_bit_write(GPIOF, GPIO_PIN_6, RESET);spi_read_write_byte(0x20);spi_read_write_byte((uint8_t)((addr)>>16));spi_read_write_byte((uint8_t)((addr)>>8));spi_read_write_byte((uint8_t)addr);gpio_bit_write(GPIOF, GPIO_PIN_6, SET);//等待擦除完成W25Q64_wait_busy();}/*********************************************************** 函 数 名 称:W25Q64_write* 函 数 功 能:写数据到W25Q64进行保存* 传 入 参 数:buffer=写入的数据内容 addr=写入地址 numbyte=写入数据的长度* 函 数 返 回:无* 作 者:LC* 备 注:无**********************************************************/void W25Q64_write(uint8_t* buffer, uint32_t addr, uint16_t numbyte){ //0x02e21unsigned int i = 0;W25Q64_erase_sector(addr/4096);//擦除扇区数据W25Q64_write_enable();//写使能W25Q64_wait_busy(); //忙检测//写入数据W25Q_CS_SELECT();spi_read_write_byte(0x02);spi_read_write_byte((uint8_t)((addr)>>16));spi_read_write_byte((uint8_t)((addr)>>8));spi_read_write_byte((uint8_t)addr);for(i=0;i<numbyte;i++){spi_read_write_byte(buffer[i]);}W25Q_CS_UNSELECT();W25Q64_wait_busy(); //忙检测}/*********************************************************** 函 数 名 称:W25Q64_read* 函 数 功 能:读取W25Q64的数据* 传 入 参 数:buffer=读出数据的保存地址 read_addr=读取地址 read_length=读去长度* 函 数 返 回:无* 作 者:LC* 备 注:无**********************************************************/void W25Q64_read(uint8_t* buffer,uint32_t read_addr,uint16_t read_length){uint16_t i;W25Q_CS_SELECT();spi_read_write_byte(0x03);spi_read_write_byte((uint8_t)((read_addr)>>16));spi_read_write_byte((uint8_t)((read_addr)>>8));spi_read_write_byte((uint8_t)read_addr);for(i=0;i<read_length;i++){buffer[i]= spi_read_write_byte(0XFF);}W25Q_CS_UNSELECT();}
测试逻辑如下:
#include "gd32f4xx.h"#include "systick.h"#include <stdio.h>#include "main.h"#include "Usart0.h"#include "SPI.h"#include "bsp_w25q64.h"#include "string.h"uint8_t cnt = 0;void Usart0_on_recv(uint8_t* data, uint32_t len) {printf("recv: %X\r\n", data[0]);if(data[0] == 0x00) {printf("ID = %X\r\n",W25Q64_readID());} else if(data[0] == 0x01) {char buff[128];sprintf(buff, "hello: %d", cnt++);printf("write: %s (%d)\r\n", buff, strlen(buff));W25Q64_write((uint8_t*)buff, 0, strlen(buff));} else if(data[0] == 0x02) {uint8_t buff[128];W25Q64_read(buff, 0, 16);printf("read: %s (%d)\r\n", (char*)buff, strlen((char*)buff));}}int main(void){systick_config();Usart0_init();SPI_init();W25Q64_init();while(1){}}
练习题
- 实现GD32平台w25q128的驱动移植
- 实现STM32平台w25q128的驱动移植
