Linux下使用MTD驱动操作M25P80与W25闪存芯片 (linux mtd m25p80 w25)

随着智能设备的普及,嵌入式系统的需求越来越高。在嵌入式系统中,闪存芯片是最常用的存储设备之一。闪存芯片不仅可以存储数据,还可以用于引导程序和存储操作系统镜像等功能。在Linux系统中,MTD(Memory Technology Devices)子系统提供了一组操作和管理闪存芯片的API和工具。本文将介绍如何使用MTD驱动操作M25P80和W25闪存芯片。

一、M25P80与W25闪存芯片介绍

M25P80和W25是两种型号的SPI(Serial Peripheral Interface)闪存芯片,具有以下特点:

1. 容量大:M25P80和W25的容量分别为8MB和4MB,可以满足大多数嵌入式系统的存储需求。

2. 接口简单:SPI接口是一种四线串行接口,只需要四根线即可实现读写操作。

3. 速度快:SPI接口的时钟频率可以高达几十MHz,可以提高读写速度。

二、MTD驱动介绍

MTD(Memory Technology Devices)是Linux内核提供的一组操作和管理闪存芯片的API和工具。它通过驱动程序将闪存芯片映射到内存空间,提供了一个类似于文件系统的接口,可以方便地对闪存芯片进行读写操作。

MTD驱动由三部分组成:核心驱动(mtdcore)、设备驱动和机制驱动。核心驱动负责管理和分配闪存芯片的设备号和分区,设备驱动提供对特定型号闪存芯片的访问接口,机制驱动提供特定的垃圾回收和解决坏块的算法。MTD驱动的整体架构如下图所示:

![MTD架构图](https://s3.amazonaws.com/eda-tools/MTD.png)

三、M25P80和W25芯片操作

1. M25P80操作

首先需要编写一个设备驱动程序,用于实现对M25P80芯片的访问。以下是一个简单的设备驱动程序示例:

“`

#include

#include

#include

static struct mtd_info *m25p80_mtd;

static int __init m25p80_init(void)

{

void __iomem *addr;

int err;

addr = ioremap(0x80000000, 0x1000000);

m25p80_mtd = mtd_create_device(NULL, “m25p80”, 0x1000000, NULL);

if (IS_ERR(m25p80_mtd)) {

err = PTR_ERR(m25p80_mtd);

goto out_iounmap;

}

m25p80_mtd->priv = addr;

m25p80_mtd->read = m25p80_read;

m25p80_mtd->write = m25p80_write;

err = add_mtd_device(m25p80_mtd);

if (err)

goto out_mtd_destroy;

return 0;

out_mtd_destroy:

mtd_destroy_device(m25p80_mtd);

out_iounmap:

iounmap(addr);

return err;

}

static void __exit m25p80_exit(void)

{

del_mtd_device(m25p80_mtd);

mtd_destroy_device(m25p80_mtd);

}

static int m25p80_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)

{

void __iomem *addr = mtd->priv;

memcpy_fromio(buf, addr + from, len);

*retlen = len;

return 0;

}

static int m25p80_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf)

{

void __iomem *addr = mtd->priv;

memcpy_toio(addr + to, buf, len);

*retlen = len;

return 0;

}

module_init(m25p80_init);

module_exit(m25p80_exit);

MODULE_LICENSE(“GPL”);

“`

以上代码实现了对M25P80芯片的读写操作。在初始化函数中,首先调用`ioremap`函数将闪存芯片的物理地址映射到内核地址空间上,然后调用`mtd_create_device`函数创建一个名为”m25p80″的MTD设备,并且注册了MTD设备的读写函数。这样就可以把闪存芯片映射到内存空间中,以文件系统的方式进行访问。

2. W25操作

以下是一个W25芯片的设备驱动程序示例:

“`

#include

#include

#include

static struct spi_nor *w25_nor;

static int __init w25_init(void)

{

struct spi_master *master;

struct spi_device *spi;

struct device *dev;

int err;

master = spi_busnum_to_master(0);

if (!master)

return -ENODEV;

spi = spi_alloc_device(master);

if (!spi)

return -ENOMEM;

spi->bits_per_word = 8;

spi->max_speed_hz = 5000000;

spi->mode = SPI_MODE_0;

err = spi_setup(spi);

if (err) {

spi_free_device(spi);

return err;

}

w25_nor = spi_nor_get_flash_info(spi, NULL);

if (IS_ERR(w25_nor)) {

err = PTR_ERR(w25_nor);

spi_free_device(spi);

return err;

}

w25_nor->controller.priv = spi;

dev = &spi->dev;

dev_set_drvdata(dev, w25_nor);

err = mtd_device_register(&w25_nor->mtd, NULL, 0);

if (err) {

spi_nor_put(w25_nor);

spi_free_device(spi);

}

return err;

}

static void __exit w25_exit(void)

{

mtd_device_unregister(&w25_nor->mtd);

spi_nor_put(w25_nor);

}

module_init(w25_init);

module_exit(w25_exit);

MODULE_LICENSE(“GPL”);

“`

与M25P80驱动程序不同的是,W25驱动程序使用了SPI-NOR闪存控制器。在初始化函数中,首先通过`spi_busnum_to_master`函数获取到SPI总线,然后调用`spi_alloc_device`函数分配一个SPI设备,并设置其相关参数。接着调用`spi_setup`函数配置SPI设备,并通过`spi_nor_get_flash_info`函数获取到W25芯片的信息。`spi_nor_get_flash_info`函数调用了闪存控制器的`read_id`函数,从闪存芯片中读取信息,并填充到`spi_nor`结构体中。最后调用`mtd_device_register`函数注册MTD设备。在注册时,使用了`spi_nor`结构体中mtd成员,mtd成员包含了MTD设备的大小、擦除和读写函数等信息。

四、


数据运维技术 » Linux下使用MTD驱动操作M25P80与W25闪存芯片 (linux mtd m25p80 w25)