Linux 下离线烧写 SPI 闪存

手上的嵌入式设备一多,尤其是路由器一多,就会发现时不时的要用到 SPI Flash 编程器。然而,市售的 SPI NOR Flash 编程器虽然价格已经非常便宜,但是速度不算给力,而且都是基于私有协议的,完全不能在 Linux 下用。虽然可以开虚拟机,但是咱还是希望方便点,不是吗?

好在后来无意中发现了 coreboot (原 LinuxBIOS )项目开发的 flashrom 工具居然带有离线编程功能,除了支持一票比较贵的专用编程器/基于 FTDIxxxxH 的编程器外,还支持一种叫做 serprog 的协议,可以通过串口操作单片机来给 SPI 闪存编程。这样一来就方便了。flashrom 的 wiki 里给了基于 Arduino 的 serprog 的固件源码,其实就是为 ATMEGA 系列 AVR 单片机设计的。

既然手头有片 ATMEGA8L ,那么就开始吧。首先布下板子。电路很简单。

main

由于 ATMEGA8L 似乎有频率上的限制,这里用了 12MHz 的晶体。实际上有 ATMEGA88A 的话可以用 16MHz 的晶体。

P1120707

在面包板上测试成功。

P1120726

固化到万用板上。顺便吐个槽,双面万用板真是闹眼子啊,正面背面都被过孔连在一起了还能叫双面么?!

用法也很简单,首先你的机器上要安装有 flashrom 。Ubuntu 的软件库里自带了:

sudo apt-get install flashrom

但是官方 SVN 仓库里的版本更新一些,而且支持 serprog 的 spispeed 选项。不怕麻烦的最好自己编译一下:

svn co svn://flashrom.org/flashrom/trunk flashrom
cd flashrom
make
sudo make install

连接一个 USB to UART bridge ,装上 SPI 闪存,接上电脑,输入以下命令:

flashrom -p serprog:dev=/dev/ttyUSB0:2000000 -r somefile.bin
flashrom -p serprog:dev=/dev/ttyUSB0:2000000 -E
flashrom -p serprog:dev=/dev/ttyUSB0:2000000 -w somefile.bin

即可读/擦/写 SPI Flash 。写入的时候会自动查空、擦除、写入和校验。

当然,就像 wiki 里说的那样,这个简陋的编程器也有诸多问题:

  • AVR 的 5V 工作电压导致其 IO 电平和 3.3V 的闪存不兼容;
  • 速度慢( UART 只有 2Mbps ,最快 250KB/s );
  • 诸多涉及到 UART 的麻烦,如波特率、转换器和连接等。

考虑到手头上的 STM32F103C8T6 核心板也是个闲得没事干的便宜货,而且还带了硬件 USB2.0 FullSpeed 接口,而且 ST 还有 USB 虚拟串口的例程,不如拉出来溜溜干点活。

STM32F103R8T6 有以下优点:

  • 是最容易买到的 STM32F103 系列里最小的一款,而且也最便宜;
  • 最高 36MHz 的 SPI 接口;
  • 多通道 DMA 引擎;
  • 硬件 USB 2.0 FullSpeed 控制器;
  • 片上 20KB RAM 和 128KB Flash ,足够实现虚拟串口模拟;
  • 有虚拟串口模拟就意味着不需要硬件 UART ,不需要转换器,不需要杜邦线,不需要设置波特率,不会被 UART 掐住速度和稳定性;
  • 90DMIPS 的运算速度是编程器性能的有力保证;
  • 纯天然的 3.3V I/O ,和 SPI Flash 的电气兼容性好。

经过一个星期的折腾,我终于得到了基于 STM32 的 serprog 的第一个可用版本。我把它叫作 serprog-stm32vcp 。这时它只有 200KB/s 到 300KB/s 的读取速度。

P1120840

最初的硬件是用一块带 USB 的核心板配合面包板完成的。核心板是淘宝上买的,回流焊接的,价格不到 ¥30 。

接下来,我做了一系列优化,包括尽量成块地传送数据,提供 SPI 时钟设定以便更快地操作闪存,使代码在 SRAM 中执行以避免片上 Flash 的等待造成性能上的影响等等。此时 serprog-stm32vcp 的读取速度已经有 500KB/s 左右了。后来我就想,既然 STM32 带了 DMA 引擎,何必不利用一下呢?只可惜网上找的 DMA 例子都极具误导性,折腾了一整天总算搞定了,于是有了第二个版本的 serprog-stm32vcp 固件。此时 serprog-stm32vcp 的读取已经高达 850KB/s ,接近 USB2.0 FullSpeed 的极限了( 12Mbps )。

P1130038

随后,有了一个固化的版本。这个板子也是淘宝上买的,也是回流焊接的,可能是最有用的 STM32 核心板了吧,价格 ¥35 。

P1130040

以及……一些对付贴片芯片的专业好帮手——弹跳座。

我觉得开个专业修砖头的店问题不大了。

偷懒的同学,这里有编译好的固件,以及 github 上的仓库

用法很简单,和基于 AVR 的 serprog 基本相同,只不过在最新的 flashrom 里可以加上 spispeed 参数:

flashrom -p serprog:dev=/dev/ttyACM0:4000000,spispeed=36000000 -r somefile.bin
flashrom -p serprog:dev=/dev/ttyACM0:4000000,spispeed=36000000 -E
flashrom -p serprog:dev=/dev/ttyACM0:4000000,spispeed=36000000 -w somefile.bin

ttyACM0 后面的 4000000 是波特率,因为这个编程器并没有用到任何物理上的 UART 所以可以随便填,只要你的系统允许既可,不会影响速度。影响速度的是后面的 spispeed 参数。

最后给点性能测试的结果:

闪存型号 闪存容量 读取速度 写入速度 擦除时间 CH341A 参考速度
EN25F16 2048 KiB 855.5 KiB/s 118.2 KiB/s 20.4 秒
MX25L3205D 4096 KiB 795.3 KiB/s 136.2 KiB/s 62.2 秒 117.0 KiB/s
MX25L6445E 8192 KiB 803.3 KiB/s 144.6 KiB/s 93.9 秒 117.0 KiB/s
MX25L12845E 16384 KiB 797.7 KiB/s 146.8 KiB/s 224.7 秒 18.2 KiB/s

注:CH341A 的参考速度为经销商或网友给出,未注明读取或写入,但是根据使用经验来说应该是读取。flashrom 对 MX25L12845E 的支持状态为“ UNTESTED ”。

今后的速度测试会在仓库里的 PERFORMANCE 文件里更新。


附:某种 CH341A 编程器的照片

P1120845

P1120844

P1120846

P1120847

P1120848

顺便拆了锁紧座,看看里面啥结构。锁紧座这个东西还真是鸡肋。

《Linux 下离线烧写 SPI 闪存》上的93个想法

  1. 真是个好东东,前几天为了写SPI,做了4个编程器,目前只有2个成功,一个是AVR EJTAG-ICE固件的,另一个是USBASP硬件+BRSPI固件,两个都是V-USB模拟,都超级慢,读一个2Mb居然要好几分钟……

  2. 请教一下,我有CH341的编程器
    对你的这个编程器也感兴趣。请问电路板在什么地方可以买到
    另外,这个编程器对有加密区域的SPI flash支持吗
    最大支持多大的flash。淘宝上有点店里出售的ch341编程器支持32M(256mbit)

    1. 做这个玩意主要是配合 Linux 下的 flashrom 的。不过现在 Windows 版的 flashrom 也支持 serprog 了,所以问题应该不大。

      flashrom 的闪存支持列表见 http://www.flashrom.org/Supported_hardware#Supported_chips

      里面列举的 3.3V 的 SPI 闪存都支持,不过目前没做 256Mbit 的支持——其 serprog 协议用的仍然是 24 位地址,目前其开发者正打算将其扩展到 32bit 。

      至于板子,在淘宝搜 STM32F103 ,价格 25-40 间带 USB 的基本都能用,注意看下别买 USB 只能供电或者做 ISP 的板子就行。弹跳座也有不少便宜的,但是图中三个座子加起来比板子本身贵多了。

  3. 我下载了一个windows版本的flashrom。我用的是stm32.已经安装好了windows下面的驱动。但是不知道windows版本的flash应该怎么使用?

    1. Windows 下可能还需要 ST 的 VCP 驱动,另外只有最近的 flashrom 才对 Windows 有比较好的支持。在命令提示符里运行,语法估计跟 Linux 上的会有不同,可能需要把 /dev/ttyACM0 换成 COMx 之类的。

      1. C:\flashrom-0.9.6.1-r1705-mingw>flashrom -p serprog:dev=COM8:4000000,spispeed=36
        000000 -r 2.bin
        flashrom v0.9.6.1-r1704 on Windows 6.1 (x86)
        flashrom is free software, get the source code at http://www.flashrom.org

        Calibrating delay loop… OK.
        Warning: given baudrate 4000000 rounded down to 115200.

        这是我的命令运行结果。为什么波特率会被限制在115200呢?我装的是VCP的驱动。命令是无尽的等待,没有任何反应

  4. 用的你预编译的固件 http://dword1511.info/dword/projects/serprog-stm32vcp/prebuilt/20130331.hex 写入到stm32f103c8t6的开发板里面了。
    把开发板的usb接到windows主机,然后在设备管理器里面能看到 flashrom.org serprog-STM32VCP 字样。
    然后按照这里 http://flashrom.org/Windows 用 libusb-win32 驱动起来了, 也编译了windows下的flashrom。
    之后应该怎么使用呢,用libusb驱动的没有串口设备,应当使用的设备名是什么呢?
    用stm的vcp倒是能驱动,但是使用的时候速度比较慢。

    多谢

    1. 不好意思,本来是打算在 Linux 下用的,所以对 Windows 下的情况不清楚。在“ Making libusb-based driver for your device ”这一步的时候插上并选择了 stm32vcp 吗?

        1. 刚刚看了一下,serprog 似乎是不需要这个驱动的,只需要串口驱动就够了。可以试试指定 SPI 时钟频率: serprog:dev=[/dev/device]:[baud],spispeed=36M

          另外你用的闪存和得到的速度大概是多少?

          1. 都弄好了,在windows下加上spispeed=36M读写速度差不多你是给你值的一半吧 MX25L3205D 。很不多了。多谢博主

  5. 冒昧的问下如果用 gd32f103ret6 配合 12Mhz的晶振的板子, 怎么改程序呢。 我只改了
    FLASH_SIZE = 512K
    SRAM_SIZE = 64K
    但是插上USB不识别。 多谢

      1. usb识别了,原来我这个板子需要某个GPIO去上拉,很奇怪为什么不直接焊上上拉。 看到你重开了个新版的程序,那个对GD32支持的怎么样了呢?

      2. 你那个新版的支持GD32的程序,我改成用SPI2能读取到flash型号, 但是无法读取flash内容。Reading flash… 这里卡着不动, 而且没有建立读取的文件。

        我改动的方式如下。
        spi.c spi_setup函数开头增加 rcc_periph_clock_enable(RCC_GPIOB);

        替换 spi.c spi.h 中的SPI1为SPI2 GPIOA 为 GPIOB

        擦除操作有进度,但非常非常慢。
        请问是有哪里改的不对么, 多谢

  6. gd32烧写20151226.hex。用xtw100的驱动改了设备vid和pid可以驱动,但烧写软件不识别,可能和id有关。

      1. 您好,我现在用您的固件在gd上跑过,实际上用是可以用。
        后来为了方便,我把用您的源代码(github上的老项目)重新建了个工程,修改了下能在spi2接口下也能用,然后无论在spi1或者spi2下(实验环境都是gd的片子,72mhz,flash用的MX25L3206E,windows),重新新建工程中,对spi和dma的配置都没有改动,vcp部分用了正点原子的枚举初始化,数据发送的endp1还是用您的代码,但是在大量的实验下有一些组实验会出现断流的现象,用bushuond看,主机发送了命令(0x13),没回复,就直接卡死在那了,单片机控制的指示忙的led灯也熄灭了,然后那次就失败了,只能关了重来。这个问题好像在提高spi速度后会有所缓解,但是还是会出现。因为对您的固件实验的次数也只有几次,暂未在您的固件上遇到这问题,所以还是不太具体清楚问题点具体在哪里,遂来请教。还有一个问题也想请教您就是,您在配置spi时用的是sck空闲是为低,第一上升沿采样,而大部分历程(包括st的demo中)都用了sck空闲是为高,第二上升沿采样,在您的配置的情况下能用,但是按大部分历程的方式就不能用,也想请问下原因是啥,谢谢。代码在这里https://github.com/posystorage/serprog-stm32-gd32

  7. 请问你那个最新的stm32-vserprog项目里电路图上那些分立元件的参数都应该取多少?我想做一个,但是(当年就没学好的)电路知识已经全还给老师了,悲催……

  8. 楼主,你这个stm32-vserprog-v3的板子没有厂家生产销售吗?我最近想通过手机借助otg以及你这个编程器来测试看能不能用手机来给spi闪存烧录固件,但苦于没有搞到称心的编程器而没有继续折腾下去。。。

  9. 我预编译好的安卓手机端可用的上位机程序到时候用QQ发给你
    支持otg功能的手机应该可以识别usb-cdc设备以及你这款编程器

  10. 哇,大佬是武汉的?我是在武汉软件工程职业学院读书,现在暑假在黄石这边社区实习,9月份开学时可以面基不?2333

        1. 谢谢你编译的安卓版本flashrom
          已经用安卓4.4的手机 otg测试flashrom刷写
          没有任何问题
          我买的淘宝最便宜的基础开发版stm32f103c8t6
          电路无需改动 飞线四根数据线 一根地线 三根3.3v 焊接一个插座 哈哈 从此安卓手机行天下编程器了
          多谢了 也要感谢楼主的好项目
          另外我焊接flash 的时候把WP 写保护引脚悬空了 貌似能用

  11. 我发现一个问题,就是楼主画的那个stm32-vserprog-v3的板子的pcb文件里没有标明主控芯片的脚位信息和焊接时的方向。。。

  12. 今天一上手就废了块板子和一份元器件,c8t6的引脚上全是焊锡,没有风枪,能安全取下来的希望不大。。。

  13. win10装了stm-vcp驱动后插上编程器,设备管理器没有显示相关设备?换句话问,这个编程器不支持windows吗?

  14. R1:标识102 参数1k
    R2:标识223 参数22
    R3:标识152 参数1k5
    R4:标识223 参数22
    R5:标识103 参数10k
    R6:标识102 参数1k
    R7:标识103 参数10k
    R8:标识102 参数1k
    R9:标识102 参数1k

    F1:标识2 参数200mA
    F2:标识2 参数200mA

    C1:0.1u
    C2: 0.1u
    C3: 0.1u
    C4: 22p
    C5: 22p
    C6: 10u
    C7: 0.1u
    C8: 0.1u
    C9: 10u
    C10: 0.1u

          1. 除了R2和R4要换成22欧的标识为220的贴片电阻之外还有什么其他地方需做更改呀?

      1. 搞得想放弃了,烧了几百块钱,好不容易搞出来了两个编程器,到头来各种问题用不了。。

        1. 推荐你直接买10块钱的bluepill然后pullup改1.5k(r10),安装Linux主流发行版,按照作者的方法直接串口烧录或者自己用stlink v2烧录器编译一个stlink程序烧写也一样。
          另外感谢作者,项目很棒很实用~

          1. 全部改好了之后如何使用这个bluepill板子连接闪存呢?具体的连线方法能否不啬赐教,谢谢!

        2. 其实,用1元pos机也可以搞定,连线非常简单,就四根数据线,两根电源线而已,推荐你上数码之家,去年就已经有成熟的固件和电路了。。。

  15. 感谢博主分享这个好项目,与之前那个项目相比,这个版本速度稍有提升,但是稳定性不行,经常擦除完busy灯熄灭就没反应了,插拔后再刷一次才行。看了项目里的说明,可能是flashrom版本太老的缘故(测试用的096,097版本),flashrom1.0编译了几次都出错,不知道博主能否帮忙编译一个,谢谢!

  16. 这个编程器是不是非得接个spi闪存上去,再连上电脑才能被识别出来呀?我手边没有任何可以用来测试的spi闪存和外设,每次接到自己win10电脑上去时都没有任何动静,也装了stm32f-vcp驱动,不甘心。。。

  17. 非常不错,用10多元钱的stm32做了一个一次成功。
    测试环境win7_x64+VirtualBox(ubuntu 18.04_64),使用USB xHCI模式。
    为什么用xHCI 因为我测试过在其它项目中使用xHCI 模式比EHCI的通讯速度快不少。
    测试芯片winbond 25Q32FVSIG (4MBye),下面的结果是多次测试取的平均值:
    读:6.255秒 657KByte/s ,擦除 45.69s ,写50.10s 81.74KByte/s

  18. 补充下:
    linux下的版本是flashrom1.2,自己静态编译的版本i386版本
    (我发现在ub 16.04下动态编译的版本在ub18.04下尽然不能用)就索性编译了一个i386的静态flashrom。
    下载地址:
    http://lzdz.f3322.net:81/serprog-stm32vcp/flashrom1.2_i386_static.tar.gz

    同样stm32flash也编译了一个,下载地址:
    http://lzdz.f3322.net:81/serprog-stm32vcp/stm32flash_i386_static.tar.gz

    windows 下也测试成功了,但是安装那个stm vcp费了点功夫,
    看了帖子http://www.openedv.com/forum.php?mod=viewthread&tid=72803
    才解决了stm vcp安装后驱动出现感叹号的问题
    下载地址:
    http://lzdz.f3322.net:81/serprog-stm32vcp/stm_vcp_usb缺少的文件.zip
    stm_vcp1.4下载地址:
    http://lzdz.f3322.net:81/serprog-stm32vcp/stm_VCP_1.4.zip
    stm_vcp1.5下载地址:
    http://lzdz.f3322.net:81/serprog-stm32vcp/stm_vcp_1.5_en.stsw-stm32102.zip
    当然不会少了flashrom(别人编译的,版本1.1)下载地址:
    http://lzdz.f3322.net:81/serprog-stm32vcp/flashrom_win v1.1.zip
    使用方法-p serprog:dev=comX:115200,spispeed=36000000

    但是我不知道怎么在win7 下计算时间,谁有办法,望告知

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据