原创 物联网行业中Nor Flash的软件设计分享_GD35Q20的软件设计方案

2024-9-30 12:31 48 0 分类: 物联网


01

概述


GD25Q32是一种常见的串行闪存器件,它采用SPI(Serial Peripheral Interface)接口协议,具有高速读写和擦除功能,可用于存储和读取数据。GD25Q32芯片容量为32 Mbit(4 MB),其中名称后的数字代表不同的容量选项。不同的型号和容量选项可以满足不同应用的需求,通常被用于嵌入式设备、存储设备、路由器等高性能电子设备中。

GD25Q32闪存芯片的内存分配是按照扇区(Sector)和块(Block)进行的,每个扇区的大小为4KB,每个块包含16个扇区,即一个块的大小为64KB。


02

物理特性


可以将 1 写成 0,但是不能将 0 写成 1,要想将 0 写成 1,必须进行擦除操作。如果要改变数据,就需要先擦除后写数据。

如果想要修改小于扇区大小的数据,需要将整个扇区的数据,在内存中进行备份,然后修改内存中的数据,再将数据写回到原扇区位置。因此,驱动要达到支持自动完成这个过程,用户可以使用驱动修改任意位置的数据。


03

引脚定义和描述



04

命令概览



05

组件的使用


1 Gitee链接地址

Demo位于amaziot_bloom_os_sdk\sample\3rd\2.0_GD25Q20C

Gitee源码地址:https://gitee.com/ning./hongdou

Github源码地址:https://github.com/ayumid/hongdou

编译指令:.\build.bat -l .\amaziot_bloom_os_sdk\sample\3rd\2.0_GD25Q20C

2 组件功能介绍

实现软件模拟SPI,驱动GD25Q20芯片,实现数据存储

3 代码讲解

1 drv_gd25q20_delay_us

功能:该函数用于,延时。

参数:

参数

释义

count

死循环次数

返回值:无

示例:

C
//初始化i2c总线
ret = drv_xl9535_i2c_init();

2 drv_gd25q20_gpio_set

功能:该函数用于,模拟SPI设置IO输出电平。

参数:

参数

释义

num

引脚号

val

0 低电平,1 高电平

返回值:0 成功,-1 失败

示例:

C
drv_gd25q20_gpio_set(DRV_GD25Q20_SPI_CS, DRV_GD25Q20_GPIO_LOW);

3 drv_gd25q20_byte_wr

功能:该函数用于,SPI写读一个字节 mode3。

参数:

参数

释义

byte

发送数据

返回值:flash返回数据

示例:

C
drv_gd25q20_byte_wr(DRV_GD25Q20_DUMMY_BYTE);

4 drv_gd25q20_byte_rd

功能:该函数用于,SPI只读一个字节。

参数:无

返回值:flash返回数据

示例:

C
drv_gd25q20_byte_rd(DRV_GD25Q20_DUMMY_BYTE);

5 drv_gd25q20_busy_wait

功能:该函数用于,GD25Q20 忙等待。

参数:无

返回值:无

示例:

C
while(drv_gd25q20_read_reg1() & BIT_BUSY);

6 drv_gd25q20_read_reg1

功能:该函数用于,读reg1。

参数:无

返回值:无

示例:

C
while(drv_gd25q20_read_reg1() & BIT_BUSY);

7 drv_gd25q20_read_identification

功能:该函数用于,读 GD25Q20 JEDEC_ID(制造商、类型、容量)。

参数:无

返回值:无

示例:

C
sample_gd25q20_uart_printf("identification is 0x%X, Device id is 0x%X, Manufacturer Device ID is 0x%X",
drv_gd25q20_read_identification(), drv_gd25q20_read_device_id(), drv_gd25q20_read_manufacturer_id());

8 drv_gd25q20_read_manufacturer_id

功能:该函数用于,读 GD25Q20 制造商 ID。

参数:无

返回值:无

示例:

C
sample_gd25q20_uart_printf("identification is 0x%X, Device id is 0x%X, Manufacturer Device ID is 0x%X",
drv_gd25q20_read_identification(), drv_gd25q20_read_device_id(), drv_gd25q20_read_manufacturer_id());

9 drv_gd25q20_read_device_id

功能:该函数用于,读 GD25Q20 设备 ID。

参数:无

返回值:无

示例:

C
sample_gd25q20_uart_printf("identification is 0x%X, Device id is 0x%X, Manufacturer Device ID is 0x%X",
drv_gd25q20_read_identification(), drv_gd25q20_read_device_id(), drv_gd25q20_read_manufacturer_id());

10 drv_gd25q20_write_enable

功能:该函数用于,写使能。

参数:无

返回值:无

示例:

C
sample_gd25q20_uart_printf("identification is 0x%X, Device id is 0x%X, Manufacturer Device ID is 0x%X",
drv_gd25q20_read_identification(), drv_gd25q20_read_device_id(), drv_gd25q20_read_manufacturer_id());

11 drv_gd25q20_write_disable

功能:该函数用于,写失能。

参数:无

返回值:无

示例:

C

12 drv_gd25q20_write_page

功能:该函数用于,页编程(调用本函数写入数据前需要先擦除扇区)。

参数:

参数

释义

pbuf

数据

addr

地址

len

长度

返回值:无

示例:

C
drv_gd25q20_write_page(pbuf, addr, pageremain);

13 drv_gd25q20_read

功能:该函数用于,读闪存数据。

参数:

参数

释义

pbuf

数据

addr

地址

len

长度

返回值:无

示例:

C
drv_gd25q20_read((UINT8*)rx_buff1, 8181, strlen(tx_buff1));

14 drv_gd25q20_sector_erase

功能:该函数用于,扇区擦除。

参数:

参数

释义

addr

地址

返回值:无

示例:

C
drv_gd25q20_sector_erase(secpos * DRV_GD25Q20_SOCTOR_SIZE);

15 drv_gd25q20_chip_rease

功能:该函数用于,FLASH整片擦除(为了安全起见,若要调用,请先调用 drv_gd25q20_write_enable 函数)。

参数:无

返回值:无

示例:

C

16 drv_gd25q20_powr_down

功能:该函数用于,掉电。

参数:无

返回值:无

示例:

C

17 drv_gd25q20_release_powr_down

功能:该函数用于,读闪存数据。

参数:

参数

释义

pbuf

数据

addr

地址

len

长度

返回值:无

示例:

C
drv_gd25q20_read((UINT8*)rx_buff1, 8181, strlen(tx_buff1));

18 drv_gd25q20_write_nocheck

功能:该函数用于,写数据。

参数:

参数

释义

pbuf

数据

addr

地址

len

长度

返回值:无

示例:

C
drv_gd25q20_write_nocheck(gd25q20_buffer, secpos * DRV_GD25Q20_SOCTOR_SIZE, DRV_GD25Q20_SOCTOR_SIZE);

19 drv_gd25q20_write

功能:该函数用于,写闪存数据,可以使任意地址。

参数:

参数

释义

pbuf

数据

addr

地址

len

长度

返回值:无

示例:

C
drv_gd25q20_write((UINT8*)tx_buff1, 8181, strlen(tx_buff1));

20 drv_gd25q20_init

功能:该函数用于,写数据。

参数:无

返回值:无

示例:

C
drv_gd25q20_init();

4 Demo实战

4.1 概述

上电后,按下按键,串口会打印出按下了哪一个按键

4.2 测试

测试步骤:

  • 参考编译教程,和文档开头的编译指令,进行编译
  • 按照编译教程选择对应的选项
  • 烧录

4.3 宏定义介绍

  • sample_gd25q20_uart_printf

输出日志到DEBUG 串口,日志比较少,可以输出到这个串口,如果日志比较多,需要输出到usb口,以免不必要的问题出现

  • sample_gd25q20_catstudio_printf

输出日志到USB 串口,使用catstudio查看,catstudio查看日志需要更新对应版本mdb.txt文件,软件打开filtter过滤日志,只查看用户输出的日志

  • SAMPLE_GD25Q20_STACK_SIZE

栈空间宏定义

4.4 全局变量介绍

  • sample_gd25q20_task_ref

任务指针

4.5 函数介绍

  • Phase1Inits_enter

底层初始化,本例空

  • Phase1Inits_exit

底层初始化,本例空

  • Phase2Inits_enter

底层初始化,本例空

  • Phase2Inits_exit

创建主任务,初始化INT 引脚

代码片段:

C
void Phase2Inits_exit(void)
{
int ret;

sample_gd25q20_task_stack = malloc(SAMPLE_GD25Q20_STACK_SIZE);

ret = OSATaskCreate(&sample_gd25q20_task_ref, sample_gd25q20_task_stack, SAMPLE_GD25Q20_STACK_SIZE, 88, "sample_gd25q20_task", sample_gd25q20_task, NULL);
ASSERT(ret == OS_SUCCESS);
}

  • _task

主任务,代码发分为两部分,一部分是发送不定长数据;另一部分是上电后等待其它模块发送的数据,收到后打印到串口。

代码片段:

C
static void sample_gd25q20_task(void *ptr)
{
int ret = 0;
uint32_t identification = 0;
// unsigned char writeBuf[30] = {0};
// unsigned char readBuf[30] = {0};

// ret = ql_spi_init(QL_SPI_PORT0, QL_SPI_MODE3, QL_SPI_CLK_812_5KHZ);
// sample_gd25q20_catstudio_printf("ql_spi_init ret %d", ret);

drv_gd25q20_init();

identification = drv_gd25q20_read_identification();
sample_gd25q20_uart_printf("identification is 0x%X, Device id is 0x%X, Manufacturer Device ID is 0x%X",
drv_gd25q20_read_identification(), drv_gd25q20_read_device_id(), drv_gd25q20_read_manufacturer_id());

// while(1)
// {
// drv_gd25q20_gpio_set(DRV_GD25Q20_SPI_CS, 0);
// sample_gd25q20_uart_printf("low");
// OSATaskSleep(5*200);
// drv_gd25q20_gpio_set(DRV_GD25Q20_SPI_CS, 1);
// sample_gd25q20_uart_printf("high");
// OSATaskSleep(5*200);
// }
if(identification != RDID)
{
/* 读取错误处理 */
sample_gd25q20_uart_printf("SPI read-write Error, please check the connection between MCU and SPI Flash\n");
}
else
{
//读取成功处理
char tx_buff1[64] = "abcdefghigklmnopqrstuvwxyz0123456789";
char rx_buff1[64] = {0};
char tx_buff2[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ9876543210";
char rx_buff2[64] = {0};
int i = 0;
//测试跨sector写,并且读出数据,写两次,第二次保留第一次部分数据,证明数据擦除,写入正常
drv_gd25q20_write((UINT8*)tx_buff1, 8181, strlen(tx_buff1));//从8181地址开始写数据,需要写第二和第三个扇区
drv_gd25q20_read((UINT8*)rx_buff1, 8181, strlen(tx_buff1));
sample_gd25q20_uart_printf("read flash:%s", rx_buff1);

if(!strncmp(tx_buff1, rx_buff1, strlen(tx_buff1)))
{
sample_gd25q20_uart_printf("SPI read-write succeed 1");
}
//验证驱动擦除扇区时,可以保留之前有效内容
drv_gd25q20_write((UINT8*)tx_buff2, 8186, strlen(tx_buff2));//从8186地址开始写数据,需要写第二和第三个扇区,同时不能擦掉8181 - 8186的5字节数据
drv_gd25q20_read((UINT8*)rx_buff2, 8181, strlen(tx_buff2) + 5);
sample_gd25q20_uart_printf("read flash:%s", rx_buff2);

if(!strncmp(rx_buff2, "abcdeABCDEFGHIJKLMNOPQRSTUVWXYZ9876543210", strlen("abcdeABCDEFGHIJKLMNOPQRSTUVWXYZ9876543210")))
{
sample_gd25q20_uart_printf("SPI read-write succeed 2");
}
}

while (1)
{
// memset(writeBuf, 0x00, sizeof(writeBuf));
// memset(readBuf, 0x00, sizeof(readBuf));

// writeBuf[0] = 0x9F;

// ret = ql_spi_write_read(QL_SPI_PORT0, readBuf, writeBuf, 1);
// sample_gd25q20_catstudio_printf("ql_spi_write_read ret %d, readBuf %02X,%02X,%02X\n", ret, readBuf[0], readBuf[1], readBuf[2]);
// ret = ql_spi_write(QL_SPI_PORT0, writeBuf, 1);
// sample_gd25q20_catstudio_printf("ql_spi_write_read ret %d, readBuf %02X\n", ret, writeBuf[0]);
// ret = ql_spi_read(QL_SPI_PORT0, readBuf, 3);
// sample_gd25q20_catstudio_printf("ql_spi_write_read ret %d, readBuf %02X,%02X,%02X\n", ret, readBuf[0], readBuf[1], readBuf[2]);
OSATaskSleep(5 * 200);
}
}

4.6 固件

点击下载 Lora Demo固件

注:本文部分内容来源于网络,如有侵权,请及时联系我们。

本文章源自奇迹物联开源的物联网应用知识库Cellular IoT Wiki,更多技术干货欢迎关注收藏Wiki:Cellular IoT Wiki 知识库(https://rckrv97mzx.feishu.cn/wiki/wikcnBvAC9WOkEYG5CLqGwm6PHf)

文章评论0条评论)

登录后参与讨论
我要评论
0
0
关闭 站长推荐上一条 /2 下一条