赞
踩
W25X是一系列SPI接口Flash芯片的简称,它采用SPI接口和CPU通信,本文使用的W25Q32BV容量为32M,具体特性如下:
该芯片最大支持104MHz的时钟,供电电压范围在2.7~3.6V,SPI的片选信号CS低有效,在操作芯片的时候,
需要将/WP和/HOLD管脚接电源。
发送地址或数据到设备时,MOSI管脚数据采样在CLK的上升沿,从芯片读数据或者状态时,MISO管脚数据采样在CLK
的下降沿,所以在设置SPI的工作模式时,必须设置为MODE0或者MODE3,本文设置为MODE3。
W25Q32BV总共有16384页(page),每页有256bytes,每次最大可以编程一页。在擦除上,可以一次擦除
4KB、32KB、64KB,或者擦除整个芯片。整个芯片的存储空间如下图:
W25Q32BV存储空间分为sector和block。一个sector共有4KB,一个block共有32KB。一个sector存储空间如下图:
本文共支持四种擦除方式,分别如下:
1) cmd = 0x20,sector擦除,一次可以擦除4KB。芯片共有1024个sector。
2) cmd = 0x52,半个block擦除,一次可以擦除32KB。芯片共有128个半block。
3) cmd = 0xd8,block擦除,一次可以擦除64KB。芯片共有64个block。
4) cmd = 0xC7,芯片擦除,擦除整个芯片。
W25Q32BV共有两个字节的状态寄存器,我们需要关心的就是BIT0和BIT1。
BIT0:busy flag,1:busy,0:free。
BIT1:write enable latch,1:write enable,0:write disable。
在操作W25Q32BV时,如果是写数据到芯片,则每写一个字节,都需要读取一个数据。
在从芯片接收数据时,首先往芯片写一个字节的0xff,然后就是需要读取的数据。
在系统启动的时候,首先会对设备信息进行注册,见《Linux spi驱动分析(一)----总线驱动》中的3.1,所以编写w25q的设备
驱动程序时,首先需要对设备信息进行注册,具体内容如下:
点击(此处)折叠或打开
首先我们从设备注册开始,程序如下:
点击(此处)折叠或打开
由于W25Q32BV使用SPI接口,所以将其注册为SPI驱动,接下来看下探测函数w25q_probe,程序如下:
点击(此处)折叠或打开
说明:
1) 首先申请设备驱动结构体。
2) 调用spi_setup(spi)函数对设备信息初始化。
3) 初始化设备驱动结构体成员变量。
4) 创建/dev目录下操作文件,操作函数集为w25q_fops。
5) 将设备驱动结构体中的链表插入本文件全局链表w25q_device_list中,以便在函数操作集的open函数中找到设备驱动结构体。
remove函数是探测函数的相反过程,具体程序如下:
点击(此处)折叠或打开
操作函数集结构体具体内容如下:
点击(此处)折叠或打开
接下来我们一一讲述。
首先看下open函数w25q_open,具体程序如下:
点击(此处)折叠或打开
说明:
1) 通过container_of找到在探测函数w25q_probe中定义的设备驱动结构体。
2) 测试并且设置忙标志,如果测试忙,直接忙退出。
3) 将找到的设备驱动结构体指针指向file->private_data,在函数操作集的其他函数中就可以使用设备驱动结构体了。
接下来看下写函数w25q_write(),程序如下:
点击(此处)折叠或打开
说明:
1) 写函数首先申请两段内存,第一段内存用于存储从应用层复制来的待写数据,最大为4KB。第二段内存用于存储每次
往W25Q32BV写的数据。由于W25Q32BV每次最大能写256bytes,所以page_num = 256,加上4是由于每次
传输时,需要在最前面加上一个字节的命令和三个字节的地址。
2) 获取本次可以传输的最大数据长度。
3) 设置好传输的cmd和起始地址,然后进入while循环。
4) 在while循环中,获取本次可以传输的最大长度,最长为256bytes,然后将其拷贝到buf中,加上4的目的是因为buf
的前四个字节需要放置命令和地址。
5) 调用w25q_write_date(w25q)函数实现数据传输。
6) 更新变量,为下一次传输做好准备。
w25q_write_date(w25q)函数具体内容如下:
点击(此处)折叠或打开
说明:
1) 在调用w25q_write_date(w25q)函数之前,需要首先设置好w25q->cmd, w25q->len(tx date len),
w25q->addr和w25q->buf(date)变量。
2) 设置芯片状态寄存器,使其可写。
3) 等待芯片不忙。
4) 读取芯片状态寄存器,查看其是否可写。
5) 配置发送buf,调用spi_sync(w25q->spi, &message);函数实现写数据。
6) 等待芯片不忙,退出。
接下来看下函数操作集中的ioctl函数,程序如下:
点击(此处)折叠或打开
说明:
1) 目前共支持5个命令,包括sector擦除,half block擦除,block擦除,芯片擦除和读取芯片ID。
2) 前三种擦除方式共用一个函数w25q_erase(w25q, get_value, cmd);,程序如下:
点击(此处)折叠或打开
说明:
1) 首先根据不同的擦除方式,设置命令和地址两个变量。
2) 调用w25q_write_date(w25q);函数实现数据传输。
芯片擦除函数w25q_chip_erase()如下:
点击(此处)折叠或打开
读取设备ID函数w25q_read_id()如下:
点击(此处)折叠或打开
说明:
1) 首先设置好变量,申请内存
2) 调用w25q_read_data()函数实现读取数据。
w25q_read_data函数如下:
点击(此处)折叠或打开
说明:
1) 在从芯片读取数据时的格式为:首先发送一个字节命令+三个字节读取地址,然后就可以接收数据了。
2) 第一个for循环发送的是命令和地址,第二个for循环是接收数据。
3) 调用此函数之前,需要设置好w25q->cmd, w25q->len(receive len),w25q->buf(kzalloc receive)和w25q->addr。
接下来看下函数操作集中的读数据函数w25q_read(),程序如下:
点击(此处)折叠或打开
说明:
1) 此函数需要申请两段内存空间,第一段用于存放从W25Q32BV接收到的数据,第二段用于存放每次接收的数据。
2) 设置好变量后,调用w25q_read_data(w25q)读取数据。
3) 读取完成后,将读取到的数据拷贝到应用层。
应用层测试程序如下:
点击(此处)折叠或打开
说明:
1) 首先从终端接收命令内容。
2) 比较命令,然后进入不同的处理流程。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。