gd32读写w25q128
时间: 2025-01-08 13:24:19 浏览: 1
### GD32微控制器对W25Q128闪存芯片进行读写操作
#### 芯片简介
W25Q128是一款由华邦电子生产的串行NOR Flash存储器,具有128 Mbit(16 MB)的存储容量[^4]。此款存储器被划分为多个可编程页面和扇区,支持多种擦除方式以及高速SPI接口。
#### SPI初始化与配置
为了实现GD32微控制器与W25Q128之间的通信,需先完成SPI模块的相关设置。这通常涉及选择合适的GPIO引脚作为SPI信号线,并设定相应的参数如波特率、工作模式等。对于GD32F407而言,其硬件SPI外设可以直接用于连接到W25Q128设备。
```c
#include "gd32f4xx.h"
// 定义SPI端口及相关引脚
#define SPIx SPI1
#define SPI_CLK RCC_APB2Periph_SPI1
#define SPI_GPIO_PORT GPIOA
#define SPI_SCK_PIN GPIO_Pin_5
#define SPI_MISO_PIN GPIO_Pin_6
#define SPI_MOSI_PIN GPIO_Pin_7
#define SPI_NSS_PIN GPIO_Pin_4
void spi_init(void){
// 配置SPI时钟源及时钟使能
rcu_periph_clock_enable(RCU_AF);
rcu_periph_clock_enable(SPI_CLK);
// 初始化SPI相关的GPIO引脚
gpio_init(SPI_GPIO_PORT, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, SPI_SCK_PIN | SPI_MOSI_PIN);
gpio_init(SPI_GPIO_PORT, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, SPI_MISO_PIN);
// 设置NSS管脚为推挽输出模式
gpio_bit_reset(GPIOA,SPI_NSS_PIN);
gpio_mode_set(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, SPI_NSS_PIN);
gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, SPI_NSS_PIN);
// 配置SPI功能结构体变量并调用函数初始化SPI外设
struct spi_configuration spi_conf;
spi_i2s_deinit(SPIx);
spi_struct_para_init(&spi_conf);
spi_conf.trans_mode = SPI_TRANSMODE_FULLDUPLEX;
spi_conf.device_mode = SPI_MASTER;
spi_conf.frame_size = SPI_FRAMESIZE_8BIT;
spi_conf.direction = SPI_DIRECTION_2LINES;
spi_conf.nss = SPI_NSS_SOFT;
spi_conf.clock_polarity_phase = SPI_CK_PL_LOW_PH_1EDGE;
spi_conf.prescale = SPI_PSC_256;
spi_init(SPIx,&spi_conf);
}
```
#### 命令帧格式与基本操作
##### 写入保护解除 (Write Enable)
在执行任何修改内存的操作之前,必须向W25Q128发送`WRITE ENABLE`命令来解锁写入权限:
```c
static void w25q128_write_enable(void){
uint8_t cmd[] = {CMD_WREN}; // CMD_WREN定义为0x06
// 下拉CS低电平启动传输过程
gpio_bit_reset(GPIOA,SPI_NSS_PIN);
// 发送指令给flash
while(spi_i2s_flag_get(SPIx, SPI_FLAG_TXE) == RESET);
spi_i2s_data_transmit(SPIx,*cmd++);
// 等待传输结束再释放CS回到高阻态
while(spi_i2s_flag_get(SPIx, SPI_FLAG_BSY));
gpio_bit_set(GPIOA,SPI_NSS_PIN);
}
```
##### 状态寄存器查询 (Read Status Register)
通过发送特定命令获取当前的状态信息可以帮助确认某些条件是否满足,比如是否有未处理的数据等待写入:
```c
uint8_t w25q128_read_status_register(void){
uint8_t status=0;
uint8_t cmd[] = {CMD_RDSR};
gpio_bit_reset(GPIOA,SPI_NSS_PIN);
while(spi_i2s_flag_get(SPIx, SPI_FLAG_TXE)==RESET);
spi_i2s_data_transmit(SPIx,*cmd++);
while(spi_i2s_flag_get(SPIx, SPI_FLAG_RXNE)==RESET);
status=(uint8_t)(spi_i2s_data_receive(SPIx));
gpio_bit_set(GPIOA,SPI_NSS_PIN);
return status;
}
```
##### 数据读取 (Read Data)
当需要从指定位置开始读取一定长度的内容时,则要构建包含起始地址在内的完整请求序列并向目标器件发出:
```c
void w25q128_read(uint32_t addr,uint8_t *data,uint16_t length){
uint8_t cmd[4];
cmd[0]=CMD_READ_DATA;// CMD_READ_DATA定义为0x03
cmd[1]=(addr>>16)&0xFF;
cmd[2]=(addr>>8)&0xFF;
cmd[3]=addr&0xFF;
gpio_bit_reset(GPIOA,SPI_NSS_PIN);
for(int i=0;i<4;i++){
while(spi_i2s_flag_get(SPIx, SPI_FLAG_TXE)==RESET);
spi_i2s_data_transmit(SPIx,cmd[i]);
}
for(int j=0;j<length;j++){
while(spi_i2s_flag_get(SPIx, SPI_FLAG_RXNE)==RESET);
data[j]=(uint8_t)(spi_i2s_data_receive(SPIx));
}
gpio_bit_set(GPIOA,SPI_NSS_PIN);
}
```
##### 扇区擦除 (Sector Erase)
如果想要清除某个区域内的所有数据以便后续重新写入新的内容,可以通过发送对应的擦除命令来进行批量删除动作:
```c
void w25q128_sector_erase(uint32_t sector_addr){
uint8_t cmd[4];
cmd[0]=CMD_SECTOR_ERASE; // CMD_SECTOR_ERASE定义为0x20
cmd[1]=(sector_addr>>16)&0xFF;
cmd[2]=(sector_addr>>8)&0xFF;
cmd[3]=sector_addr&0xFF;
w25q128_write_enable();
gpio_bit_reset(GPIOA,SPI_NSS_PIN);
for(int i=0;i<4;i++){
while(spi_i2s_flag_get(SPIx, SPI_FLAG_TXE)==RESET);
spi_i2s_data_transmit(SPIx,cmd[i]);
}
gpio_bit_set(GPIOA,SPI_NSS_PIN);
// Wait until the operation is complete.
do{
delay_ms(10);
}while(w25q128_read_status_register() & STATUS_REG_WIP);
}
```
以上代码片段展示了如何利用GD32平台上的SPI接口控制W25Q128闪存芯片的一些基础交互逻辑,包括但不限于启用写入许可、检查状态寄存器值、按地址范围读回数据以及实施整块扇区级别的清零操作。实际应用中可能还需要考虑更多细节问题,例如错误检测机制的设计或是针对不同应用场景优化性能等方面的工作。
阅读全文