Single

Openwrt自动识别DFU状态下的STM32并实现自动烧录

前言

DFU状态下的STM32不属于ttyUSB或者ttyACM设备,所以需要用到USB(Universal Serial Bus)的BUS端口,这里记录一下我是如何获取到的BUS口的

准备

我这里用到的设备有
1、BPI-M1+
2、OpenWrt固件(具体配置方法在这里
3、Artec板子(上面有一片STM32F042F6P6和一片ESP32,我们主要是为了给这2个芯片烧写固件)
4、一个hub(想接更多设备可以接更多hub,但是一定要注意供电,一定要买好点的hub,我在这里遇到了很多供电不足的坑)
我这里用到的软件是hotplug,但是由于hotplug默认配置文件只支持ttyACM和ttyUSB设备,所以需要修改默认的配置文件,配置文件分析可以看这里

区分STM32和ESP32

想要知道设备类型,我们需要输出所有变量

[ "if",
    [ "eq", "SUBSYSTEM",
        [ "usb" ]
    ],
    [ "exec", "/root/test" ]
]

上面代码是,识别到了usb设备后,执行/root/test这个脚本
然后需要编辑脚本

vi /root/test

将下面的代码放进去

#!/bin/sh
echo "==========" >> /tmp/env.log
env >> /tmp/env.log
echo "----------" >> /tmp/env.log

重启之后将STM32设置为DFU模式,并插入,查看日志

root@OpenWrt:~# cat /tmp/env.log
==========
DEVNAME=bus/usb/001/005
ACTION=add
SHLVL=1
HOME=/
SEQNUM=1010
BUSNUM=001
MAJOR=189
DEVPATH=/devices/platform/soc@01c00000/1c14000.usb/usb1/1-1/1-1.4
TERM=linux
SUBSYSTEM=usb
PATH=/usr/sbin:/usr/bin:/sbin:/bin
MINOR=4
TYPE=0/0/0
DEVNUM=005
PRODUCT=483/df11/2200
PWD=/
DEVTYPE=usb_device
----------
==========
ACTION=add
SHLVL=1
HOME=/
SEQNUM=1011
DEVPATH=/devices/platform/soc@01c00000/1c14000.usb/usb1/1-1/1-1.4/1-1.4:1.0
TERM=linux
SUBSYSTEM=usb
PATH=/usr/sbin:/usr/bin:/sbin:/bin
MODALIAS=usb:v0483pDF11d2200dc00dsc00dp00icFEisc01ip02in00
TYPE=0/0/0
PRODUCT=483/df11/2200
INTERFACE=254/1/2
PWD=/
DEVTYPE=usb_interface
----------
==========
DEVNAME=bus/usb/001/005
ACTION=bind
SHLVL=1
HOME=/
SEQNUM=1012
BUSNUM=001
MAJOR=189
DEVPATH=/devices/platform/soc@01c00000/1c14000.usb/usb1/1-1/1-1.4
TERM=linux
SUBSYSTEM=usb
PATH=/usr/sbin:/usr/bin:/sbin:/bin
MINOR=4
DRIVER=usb
TYPE=0/0/0
DEVNUM=005
PRODUCT=483/df11/2200
PWD=/
DEVTYPE=usb_device
----------

仔细看会发现,脚本一共触发了三次,根据Tim老师的分析,分别是:1、USB hub插入。2、STM32插入。3、USB hub绑定驱动(由于STM32的DFU设备没有驱动,所以不会触发,如果是CH340这种,还会再触发一次设备驱动绑定)
在这里我们只需加入判断就能识别两种芯片,其中第一个刷的是dfu模式下的STM32,它的PID为df11(PID为固定的,所以可以识别,具体查询地址在这里http://www.linux-usb.org/usb.ids,其中df11代表STM Device in DFU Mode)
输入lsusb命令就能看到PID

Bus 001 Device 012: ID 0483:df11 STMicroelectronics STM Device in DFU Mode

将STM32设置为普通模式,将Artec插入BPI-M1+,得到以下日志:

root@OpenWrt:~# cat env.log
=========
DEVNAME=bus/usb/001/006
ACTION=add
SHLVL=1
HOME=/
SEQNUM=1009
BUSNUM=001
MAJOR=189
DEVPATH=/devices/platform/soc@01c00000/1c14000.usb/usb1/1-1/1-1.4
TERM=linux
SUBSYSTEM=usb
PATH=/usr/sbin:/usr/bin:/sbin:/bin
MINOR=5
TYPE=2/2/0
DEVNUM=006
PRODUCT=20a0/4269/200
PWD=/
DEVTYPE=usb_device
----------
=========
ACTION=add
SHLVL=1
HOME=/
SEQNUM=1010
DEVPATH=/devices/platform/soc@01c00000/1c14000.usb/usb1/1-1/1-1.4/1-1.4:1.0
TERM=linux
SUBSYSTEM=usb
PATH=/usr/sbin:/usr/bin:/sbin:/bin
MODALIAS=usb:v20A0p4269d0200dc02dsc02dp00ic02isc02ip01in00
TYPE=2/2/0
PRODUCT=20a0/4269/200
INTERFACE=2/2/1
PWD=/
DEVTYPE=usb_interface
----------
=========
ACTION=bind
SHLVL=1
HOME=/
SEQNUM=1012
DEVPATH=/devices/platform/soc@01c00000/1c14000.usb/usb1/1-1/1-1.4/1-1.4:1.0
TERM=linux
SUBSYSTEM=usb
PATH=/usr/sbin:/usr/bin:/sbin:/bin
MODALIAS=usb:v20A0p4269d0200dc02dsc02dp00ic02isc02ip01in00
DRIVER=cdc_acm
TYPE=2/2/0
PRODUCT=20a0/4269/200
INTERFACE=2/2/1
PWD=/
DEVTYPE=usb_interface
----------
=========
ACTION=add
SHLVL=1
HOME=/
SEQNUM=1013
DEVPATH=/devices/platform/soc@01c00000/1c14000.usb/usb1/1-1/1-1.4/1-1.4:1.1
TERM=linux
SUBSYSTEM=usb
PATH=/usr/sbin:/usr/bin:/sbin:/bin
MODALIAS=usb:v20A0p4269d0200dc02dsc02dp00ic0Aisc00ip00in01
DRIVER=cdc_acm
TYPE=2/2/0
PRODUCT=20a0/4269/200
INTERFACE=10/0/0
PWD=/
DEVTYPE=usb_interface
----------
=========
ACTION=bind
SHLVL=1
HOME=/
SEQNUM=1014
DEVPATH=/devices/platform/soc@01c00000/1c14000.usb/usb1/1-1/1-1.4/1-1.4:1.1
TERM=linux
SUBSYSTEM=usb
PATH=/usr/sbin:/usr/bin:/sbin:/bin
MODALIAS=usb:v20A0p4269d0200dc02dsc02dp00ic0Aisc00ip00in01
DRIVER=cdc_acm
TYPE=2/2/0
PRODUCT=20a0/4269/200
INTERFACE=10/0/0
PWD=/
DEVTYPE=usb_interface
----------
=========
DEVNAME=bus/usb/001/006
ACTION=bind
SHLVL=1
HOME=/
SEQNUM=1015
BUSNUM=001
MAJOR=189
DEVPATH=/devices/platform/soc@01c00000/1c14000.usb/usb1/1-1/1-1.4
TERM=linux
SUBSYSTEM=usb
PATH=/usr/sbin:/usr/bin:/sbin:/bin
MINOR=5
DRIVER=usb
TYPE=2/2/0
DEVNUM=006
PRODUCT=20a0/4269/200
PWD=/
DEVTYPE=usb_device
----------

可以看到,流程分别为
usb_device add
usb_interface add
usb_interface bind
usb_interface add
usb_interface bind
usb_device bind
想要区分出来,只用识别DRIVER是否为cdc_acm,且usb_interface为add
具体hotplug.json代码如下,在最下面加就行

        [ "if",
                [ "and",
                        [ "eq", "SUBSYSTEM", "usb" ],
                        [ "eq", "ACTION", "add" ],
                        [ "eq", "DEVTYPE", "usb_interface" ],
                        [ "regex", "PRODUCT", "df11" ]
                ],
                [ "exec", "/root/QC/AutoRun", "STM32" ]
        ],
        [ "if",
                [ "and",
                        [ "eq", "SUBSYSTEM", "usb" ],
                        [ "eq", "ACTION", "add" ],
                        [ "eq", "DEVTYPE", "usb_interface" ],
                        [ "regex", "DRIVER", "cdc_acm" ]
                ],
                [ "exec", "/root/QC/AutoRun", "ESP32" ]
        ]
        

将/root/QC/AutoRun脚本改为如下,就能在/root/QC/env.log文件中看到是哪个芯片

root@OpenWrt:~/QC# cat AutoRun
#!/bin/sh
export HOTPLUG_TYPE="$1"
echo $HOTPLUG_TYPE >> /root/QC/env.log

最后将AutoRun改为以下代码

#!/bin/sh
export HOTPLUG_TYPE="$1"
echo $HOTPLUG_TYPE >> /root/QC/env.log
if [ "$HOTPLUG_TYPE" = ESP32 ]
        then
            /root/QC/AutoRun_ESP32
        elif [ "$HOTPLUG_TYPE" = STM32 ]
            /root/QC/AutoRun_STM32
fi

在识别为STM32时运行/root/QC/AutoRun_STM32,在识别为ESP32 时运行/root/QC/AutoRun_ESP32

自动烧录

STM32的dfu固件烧写工具为dfu-util
下面是Tim老师给出的命令

dfu-util -a 0 -R -p 2-1.4.3 -D studuinobit_STM32F042_Flash_20190306.dfu

下面是dfu-util的具体使用方法:

root@OpenWrt:~# dfu-util -h
Usage: dfu-util [options] ...
  -h --help                     Print this help message
  -V --version                  Print the version number
  -v --verbose                  Print verbose debug statements
  -l --list                     List currently attached DFU capable devices
  -e --detach                   Detach currently attached DFU capable devices
  -E --detach-delay seconds     Time to wait before reopening a device after detach
  -d --device <vendor>:<product>[,<vendor_dfu>:<product_dfu>]
                                Specify Vendor/Product ID(s) of DFU device
  -p --path <bus-port. ... .port>       Specify path to DFU device
  -c --cfg <config_nr>          Specify the Configuration of DFU device
  -i --intf <intf_nr>           Specify the DFU Interface number
  -S --serial <serial_string>[,<serial_string_dfu>]
                                Specify Serial String of DFU device
  -a --alt <alt>                Specify the Altsetting of the DFU Interface
                                by name or by number
  -t --transfer-size <size>     Specify the number of bytes per USB Transfer
  -U --upload <file>            Read firmware from device into <file>
  -Z --upload-size <bytes>      Specify the expected upload size in bytes
  -D --download <file>          Write firmware from <file> into device
  -R --reset                    Issue USB Reset signalling once we're finished
  -s --dfuse-address <address>  ST DfuSe mode, specify target address for
                                raw file download or upload. Not applicable for
                                DfuSe file (.dfu) downloads

可见,只用将port识别出来就行,找了一会,发现在 DEVPATH变量中有:

 DEVPATH=/devices/platform/soc@01c00000/1c14000.usb/usb1/1-1/1-1.1/1-1.1:1.0

1-1.1就是我们要提取出来的数字,其中1-1是bus-port,代表1号bus的1号port,后面的.1代表它接的hub的1号口接了一个设备(我在M1+的板子上接了一个hub),我们只需在STM32识别到了之后将port提取出来就行
本来想用正则,而且式子也列出来了(另外强烈推荐球猫给的网站https://regex101.com/)

但是奈何技术不太过关,没找到正则在shell中的使用方法,于是使用了最土的办法,截取:和/两个符号中间的字符,分两步删掉

root@OpenWrt:~# DEVPATH=/devices/platform/soc@01c00000/1c14000.usb/usb1/1-1/1-1.1/1-1.1:1.0
root@OpenWrt:~# b=${DEVPATH##*/} && echo $b
1-1.1:1.0
root@OpenWrt:~# USBBUS=${b%:*} && echo $USBBUS
1-1.1

使用以上方法就能将port识别出来
最后直接替代就好了

dfu-util -a 0 -R -p $USBBUS -D studuinobit_STM32F042_Flash_20190306.dfu

ESP32烧录

ESP32部分就比较简单了,插上之后时ttyACM*,直接在hotplug.json加上以下代码就行

        [ "if",
                [ "and",
                        [ "eq", "SUBSYSTEM",
                                [ "net", "input", "usb", "ieee1394", "block", "atm", "zaptel", "tty", "button" ]
                        ],
                        [ "regex", "DEVNAME",
                                [ "^ttyACM" ]
                        ],
                        [ "eq", "ACTION", "add" ]
                ],
                [ "exec", "/root/QC/AutoRun", "ESP32" ]
        ]

在最后面加了个变量,用来标记ESP32或者STM32,/root/QC/AutoRun脚本中加个判断就能直接用了,$DEVNAME变量就是端口号

参考链接

正则表达式:https://www.runoob.com/regexp/regexp-syntax.html
Shell字符串截取(非常详细):http://c.biancheng.net/view/1120.html
regex101:https://regex101.com/

月球猫以及Tim老师

暂无评论

发表评论