SPI NOR FLASH驱动
合集下载
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
104
.bus_num
= 2,
105
.chip_select
= 1,
106 }
107 };
/*.modalias 字段
*/
/* SPI 通信最大频率
*/
/* SPI 总线编号
*/
/* 片选信号
*/
通过 spi_register_board_info(spi_board_info, ARRAY_SIZE(spi_board_info))函数注册设 备。
spidev_spi_driver 结构体
spidev_spi_driver 如程序清单 1.20 所示。
程序清单 1.4 spidev_spi_driver 结构体
static struct spi_driver spidev_spi_driver = {
.driver = {
.name =
"spi-led",
static int __devinit spidev_probe(struct spi_device *spi) {
int i, status = -1; spi_led = spi; struct device *dev; dev_t devno;
devno = MKDEV(0, 0);
/* create spi device. */
status = device_create_file(dev, &led_device_attrs[i]); if(status != 0){
printk("creat file failed.\n"); goto file_err; } }
gpio117_setting();
/* 创建控制数码管设备的文件 */
dev = device_create(spiled_class, NULL, devno,NULL, "led");
/* 创建 led 设备
*/
if(dev == NULL){ printk("device create failed.\n"); return status;
} /* create device files,led and value. */ for (i = 0; i<2; i++){
程序清单 1.7num_store()函数
static ssize_t num_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
int buf_len = strlen(buf);
char first_char = *buf; if(buf_len > 5 || first_char == '-'){
/* 判断输入的字符串是否合法
*/
printk("Please echo a number 0~9999\n");
return size;
}else{ __g_status = 1; num_process(buf); schedule_delayed_work(&led_work, (1/1000)*HZ);
当 spi_board_info 中的.modalias 字段与 spidev_spi_driver 中.name 字段相匹配,则自动调 用 spidev_probe()函数。
spidev_probe()函数的实现 spidev_probe()函数如程序清单 1.21 所示。
程序清单 1.5 spidev_probe()函数
文件 num 的权限为 0Байду номын сангаас44,文件的读函数设置为 NULL,当用户在系统中执行“echo 1 >num”时,文件写函数 num_store()自动调用,通过 SPI 数据线传输数码管要显示的数值 ‘1’。文件 shutdown 用于熄灭数码管。
函数 num_store()的实现如程序清单 1.23 所示。
现在内核中添加少量代码,完成 spi_board_info 信息初始化,然后再编写一个独立的驱 动文件,实现对 7 段数码管的控制。
1. spi_board_info 在<arch/arm/mach-mx28/mx28evk.c>中添加 spi-led 的 spi_board_info,如程序清单 1.17 所示。
(1) 在 SCK 引脚输入信号的上升沿,在 SI 引脚输入的数据被送入 QA 的第 1 级移位寄 存器,QA 移位寄存器原有的值移入 QB 移位寄存器,QB 移位寄存器原有的值移 入 QC 移位寄存器,以此类推;
(2) 在 RCK 引脚输入信号的上升沿,移位寄存器中的数据被送入锁存器; (3) 若 OE 引脚输入低电平,则锁存器的值将在 QA~QH 引脚输出。 在 AP-283Demo 板上,MCU 的 SPI 接口控制 2 片 74HC595 带锁存的移位寄存器驱动 2 个共阴式的 LN3461BS 数码管,其中 U4 控制 8 位数据管的段选位,U6 控制 4 位数码管的 片选位,也就是说只要给数码管的段选位输送低电平,给数码管的片选位输送高电平,即可 点亮数码管。 MCU 作为主机通过 SPI 总线发送数据,74HC595 作为从机接收数据,采用级联的方式 对 2 片 74HC595 进行操作,其数据的传递方式如下:
EPC-283 主板插上 AP-283Demo 板后,SPI 连接到主板的 SPI3,所以结构体中的 bus_num 设置为 2。
2. 修改 spi_master 片选
i.MX28x 处理器的 SPI 3 控制器带 1 路片选,而 7 段数码管的驱动电路并没有使用 SPI 总线的片选;为了不影响系统原有的 SPI 总线,可为系统增加 1 路片选。修改<drivers/spi /spi_mxs.c>文件,将注册 spi_master 的片选数量修改为 2:
AP-283Demo 基础扩展板提供了 1 路 SPI 接口数码管,电路原理图如图 1.3 所示。
图 1.1 SPI 数码管电路原理图
在 74HC595 芯片中,如果要将 8 位串行输入数据并行输出到 QA、QB、QC、QD、QE、 QF、QG、QH,则需要满足以下条件:
首先必须保证在 driver name
*/
©2017 Guangzhou ZHIYUAN Electronics Stock Co., Ltd. 文章源自广州致远电子有限公司,转载或引用请注明出处
3
广州致远电子有限公司
嵌入式-ARM 工控机
.owner = THIS_MODULE, }, .probe = spidev_probe, .remove = __devexit_p(spidev_remove), };
int status;
spiled_class = class_create(THIS_MODULE, "spiled");
/* 创建类
*/
if (IS_ERR(spiled_class)) {
return PTR_ERR(spiled_class);
}
status = spi_register_driver(&spidev_spi_driver); if (status < 0) {
模块的出口函数如程序清单 1.19 所示。
程序清单 1.3 spidev_exit()函数
/* module exit.*/
static void __exit spidev_exit(void)
{ __g_status = 0; mdelay(10);
/* 工作队列退出标志
*/
/* 延时确保工作队列退出 */
/* 申请 gpio117
*/
printk("spi led create.\r\n"); return status; file_err: device_destroy(spileu ZHIYUAN Electronics Stock Co., Ltd. 文章源自广州致远电子有限公司,转载或引用请注明出处
spi_unregister_driver(&spidev_spi_driver);
class_destroy(spiled_class);
}
module_exit(spidev_exit);
当模块驱动被卸载的时候,自动调用模块的出口函数 spidev_exit(),模块出口函数用于 注销在模块入口函数中注册的设备。
class_destroy(spiled_class); }
/* 注册 spi 总线驱动
*/
INIT_DELAYED_WORK(&led_work, led_worker);
/* 初始化工作队列
*/
return status;
}
module_init(spidev_init);
当向系统加载驱动模块的时候,自动调用模块的入口函数 spidev_init(),此函数主要完 成向系统注册 spi 的设备类、注册 spi 总线驱动和初始化工作队列。
广州致远电子有限公司
嵌入式-ARM 工控机
第1章 SPI NOR FLASH 驱动
在《上册》的“特殊硬件接口编程”一章,提供了一个通过 SPI 接口驱动 7 段数码管的 范例,这里将重新实现这个驱动,只不过是换成内核态实现。将 4 个 7 段数码管作为一个字 符设备,实现多位数字显示。 1.1.1 电路原理
/* device attribute,used to create attribute files.*/ static struct device_attribute led_device_attrs[] = {
__ATTR(num, 0644, NULL, num_store), __ATTR(shutdown, 0644, NULL, shutdown_store), };
(3) 当数据移位完成后,在 RCK 产生一个上升沿将移位寄存器中的数据移位到锁存器; (4) 由于 OE 为低电平,锁存器的数据送到 U4、U6 的 QA~QH 数据引脚上。 其中 U4、U6 的 RCK 引脚连接到 i.MX283 处理器的 GPIO3.21(编号 117)引脚。
1.1.2 驱动实现
程序清单 1.1 spidev 的 spi_board_info
72 static struct spi_board_info spi_board_info[] __initdata = {
……
101 {
102
.modalias
= "spi-led",
103
.max_speed_hz = 20000000,
模块的入口v_init()函数
©2017 Guangzhou ZHIYUAN Electronics Stock Co., Ltd. 文章源自广州致远电子有限公司,转载或引用请注明出处
2
广州致远电子有限公司
嵌入式-ARM 工控机
/* module entry.*/ static int __init spidev_init(void) {
(1) 发送 8 位“段选”数据,且u ZHIYUAN Electronics Stock Co., Ltd. 文章源自广州致远电子有限公司,转载或引用请注明出处
1
广州致远电子有限公司
嵌入式-ARM 工控机
(2) 紧接再发送“片选”数据时,刚才发送的“段选”数据将通过级联方式移位到 U4 的移位寄存器中,后发送的“片选”数据则被保存在 U6 的移位寄存器中;
4
广州致远电子有限公司
嵌入式-ARM 工控机
return status; }
spidev_probe()函数主要用于创建 led 类设备,创建两个控制 SPI 数码管属性的文件 num、 shutdown 和申请 gpio117。
设备属性文件 设备属性文件的配置如程序清单 1.22 所示。
程序清单 1.6 属性文件配置
master->num_chipselect = 2;
重新编译内核,并把新内核固化进 NANDFLASH 中。 3. spi_led_driver.c 驱动模块 创建 spi_led_driver.c 驱动文件,编写 SPI 数码管的驱动程序,并编写 Makefile 文件,实 现模块编译,最终将驱动以模块动态插入内核。 模块入口和出口函数