如何在嵌入式Linux(ARM)中读取/写入通过SPI连接的Flash?

问题描述 投票:0回答:7

我正在使用 Yocto 和 meta-atmel 构建嵌入式 Linux(4.4.19)。我的板上有一个通过 SPI 连接的 Flash。 我尝试了几种方法来写它。但他们都失败了。 如何读取/写入数据?

一些信息:

闪存类型 4Mbit:
s25fl164k (http://www.farnell.com/datasheets/1756778.pdf)

通过设备树包含:

    spi1: spi@f8008000 {
        cs-gpios = <&pioC 25 GPIO_ACTIVE_HIGH>;
        status = "okay";

        m25p80@0 {
            compatible = "spansion,s25fl164k";
            spi-max-frequency = <50000000>;
            reg = <0>;
        };
    };

内核配置:

  • MTD 设备已激活
  • SPI 激活
  • SPI 设备驱动程序已激活

dmesg
启动时打印:

[    2.630000] Creating 8 MTD partitions on "atmel_nand":
[    2.640000] 0x000000000000-0x000000040000 : "bootstrap"
[    2.640000] 0x000000040000-0x0000000c0000 : "uboot"
[    2.650000] 0x0000000c0000-0x000000100000 : "env"
[    2.660000] 0x000000100000-0x000000140000 : "env_redundant"
[    2.660000] 0x000000140000-0x000000180000 : "spare"
[    2.670000] 0x000000180000-0x000000200000 : "dtb"
[    2.670000] 0x000000200000-0x000000800000 : "kernel"
[    2.680000] 0x000000800000-0x000010000000 : "rootfs"
[    2.690000] atmel_spi f0004000.spi: version: 0x213
[    2.690000] atmel_spi f0004000.spi: DMA TX channel not available, SPI unable to use DMA
[    2.700000] atmel_spi f0004000.spi: Atmel SPI Controller using PIO only
[    2.700000] atmel_spi f0004000.spi: Atmel SPI Controller at 0xf0004000 (irq 25)
[    2.710000] m25p80 spi32766.0: at25df321a (4096 Kbytes)

fdisk
打印(看
mtdblock8
):

root@sama5d3xek:~# fdisk -l
Disk /dev/ram0: 8 MiB, 8388608 bytes, 16384 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 4096 bytes
I/O size (minimum/optimal): 4096 bytes / 4096 bytes


Disk /dev/ram1: 8 MiB, 8388608 bytes, 16384 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 4096 bytes
I/O size (minimum/optimal): 4096 bytes / 4096 bytes


Disk /dev/ram2: 8 MiB, 8388608 bytes, 16384 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 4096 bytes
I/O size (minimum/optimal): 4096 bytes / 4096 bytes


Disk /dev/ram3: 8 MiB, 8388608 bytes, 16384 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 4096 bytes
I/O size (minimum/optimal): 4096 bytes / 4096 bytes


Disk /dev/mtdblock0: 256 KiB, 262144 bytes, 512 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes


Disk /dev/mtdblock1: 512 KiB, 524288 bytes, 1024 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes


Disk /dev/mtdblock2: 256 KiB, 262144 bytes, 512 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes


Disk /dev/mtdblock3: 256 KiB, 262144 bytes, 512 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes


Disk /dev/mtdblock4: 256 KiB, 262144 bytes, 512 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes


Disk /dev/mtdblock5: 512 KiB, 524288 bytes, 1024 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes


Disk /dev/mtdblock6: 6 MiB, 6291456 bytes, 12288 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes


Disk /dev/mtdblock7: 248 MiB, 260046848 bytes, 507904 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes


Disk /dev/mtdblock8: 4 MiB, 4194304 bytes, 8192 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes


Disk /dev/mmcblk0: 7.4 GiB, 7985954816 bytes, 15597568 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x00000000

Device         Boot Start      End  Sectors  Size Id Type
/dev/mmcblk0p1       8192 15597567 15589376  7.4G  b W95 FAT32

阅读/写作测试:

cat /dev/mtdblock8
echo "hello" > /dev/mtdblock8
cat /dev/mtdblock8

我没有得到任何结果/错误。

安装:

mkdir /tmp/abc
mount -t jffs2 /dev/mtdblock8 /tmp/abc
mount: /dev/mtdblock8: can't read superblock

有什么想法吗?

我喜欢做演示。假设在 SPI 闪存的位置 12345 上写入“hello Linux”。

linux linux-kernel embedded-linux kernel-module flash-memory
7个回答
3
投票

可能设备已被 U-Boot 锁定,并且内核的 m25p80 驱动程序中未实现 ioctl UNLOCK。我以前见过,请参阅erasing-flash-nor-ioctlmemunlock-return-status


2
投票

您可以使用内存技术设备(MTD)子系统对闪存分区进行擦除/写入/读取操作。 在您的情况下,SPI闪存已安装到mtdblock8。使用以下命令查看所有现有分区

cat /proc/mtd

要写入 mtd 设备,请使用 nandwrite 命令。可以与 busybox 一起使用。

安装尝试

mount -t jffs2 /dev/block/mtdblock8 /tmp/abc

MTD详细信息: http://free-electrons.com/blog/managing-flash-storage-with-linux/

mtd utils 的详细信息: http://processors.wiki.ti.com/index.php/Mtdutils


2
投票

所以,让我们一步一步来。您的 SPI NOR 闪存在设备树中进行了描述,看来您已成功正确配置内核(即添加相关驱动程序)。您的日志证实了这一点:

[    2.710000] m25p80 spi32766.0: at25df321a (4096 Kbytes)

/dev/mtd8 似乎也是与该设备关联的 MTD 设备(根据您的大小分析)。您应该能够通过检查 /sys/class/mtd 来确认它。

现在,为了对设备进行编程,您需要 1) 擦除要写入的扇区,2) 写入这些扇区,最后读回并确认。 要写入,您可以使用 write() 系统调用(即

cat somefile > /dev/mtd8
)。要擦除,您需要一个 ioctl 系统调用,即
flash_erase
命令。

MTD网站有一些相关信息:

http://www.linux-mtd.infradead.org/index.html

hashdefine 回复中提到的 Free-Electrons 帖子也很好。


2
投票

我的设备树表文件中有错误。 spi1、图像传感器接口(isi1) 和i2c(i2c1) 使用相同的引脚。编译内核+ dts 时没有显示错误。 一般来说,fdisk + mtd_debug 的组合对于检查底层驱动程序和硬件非常有用。就我而言,SAMA5D35 + 自己的主板@ dts:

ahb {
    apb {
        spi1: spi@f8008000 {
            cs-gpios = <&pioC 25 GPIO_ACTIVE_LOW>;
            status = "okay";
            m25p80@0 {
                compatible = "spansion,s25fl132k", "jedec,spi-nor";
                spi-max-frequency = <108000000>;
                reg = <0>;
                m25p,fast-read;
            };
        };

        // conflicts with spi1 
        i2c1: i2c@f0018000 {
            status = "disabled";
        };
        // confilcts with spi1 (pin PC27 periph B TWCK1 pin, conflicts with SPI1_NPCS2, ISI_D10)
        isi: isi@f0034000 {
            status = "disabled";
        };
};

现在可以正常使用了


1
投票

您可以使用mtd_debug命令工具。使用此工具可以测试一个字节的读/写。这对于定位问题非常方便。


0
投票

你可以尝试降低时钟频率,这解决了我使用SPI FLASH的问题:

spi-max-frequency = <10000000>

0
投票

你说你想写入你的SPI FLASH设备

[    2.630000] Creating 8 MTD partitions on "atmel_nand":
[    2.640000] 0x000000000000-0x000000040000 : "bootstrap"
[    2.640000] 0x000000040000-0x0000000c0000 : "uboot"
[    2.650000] 0x0000000c0000-0x000000100000 : "env"
[    2.660000] 0x000000100000-0x000000140000 : "env_redundant"
[    2.660000] 0x000000140000-0x000000180000 : "spare"
[    2.670000] 0x000000180000-0x000000200000 : "dtb"
[    2.670000] 0x000000200000-0x000000800000 : "kernel"
[    2.680000] 0x000000800000-0x000010000000 : "rootfs"

cat /dev/mtdblock8
echo "hello" > /dev/mtdblock8
cat /dev/mtdblock8

但是那8个MTD分区是NAND FLASH,而你的

m25c80
是SPI NOR FLASH

© www.soinside.com 2019 - 2024. All rights reserved.