专栏首页程序手艺人[ 物联网篇 ] 11 - NXP i.MX8M Mini 集成Mender OTA解决方案

[ 物联网篇 ] 11 - NXP i.MX8M Mini 集成Mender OTA解决方案

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

本文链接:https://blog.csdn.net/z2066411585/article/details/103023901

i.MX8M Mini OTA方案介绍

参考收集中的资料,介绍SWupdate 和 Mender 的区别,以及应用场景

代码下载
  • 代码下载
repo init -u https://source.codeaurora.org/external/imx/imx-manifest -b imx-linux-sumo -m imx-4.14.98-2.0.0_demo_mender.xml
  • 编译
MACHINE=imx8mmevk DISTRO=fsl-imx-xwayland source ./fsl-setup-mender.sh -b bld-xwayland

bitbake core-image-base
  • 烧录的固件介绍
//升级固件
core-image-base-imx8mmevk-20191111104651.mender 

//烧录固件
core-image-base-imx8mmevk-20191111104651.sdimg
和之前的 core-image-minimal-imx8mmevk-20190521120542.rootfs.sdcard 区别, 这部分了解了很久,走了不少弯路. 

弯路1 : 第一次编译出的固件,没发现可以整体烧录的固件(sdcard) , 发出查找是不是代码出现问题
弯路2:  找到对应的代码, 反复琢磨,最终编译出路的固件烧录成功无法启动

解决方案:最终通过 dd if=core-image-base-imx8mmevk.sdimg  of=/dev/sdc bs=1M && sync 写入sd卡,发现可以成功启动
  • 烧录固件提示
boot_fdt=try
bootcmd=mmc dev ${mmcdev}; if mmc rescan; then if run loadbootscript; then run bootscript; else run mender_setup; if run loadimage; then run mmcboot; run mender_try_to_recover; else run mender_try_to_recover; run netboot; fi; fi; else booti ${loadaddr} - ${fdt_addr}; fi
bootcmd_mfg=run mfgtool_args;if iminfo ${initrd_addr}; then if test ${tee} = yes; then bootm ${tee_addr} ${initrd_addr} ${fdt_addr}; else booti ${loadaddr} ${initrd_addr} ${fdt_addr}; fi; else echo "Run fastboot ..."; fastboot 0; fi;
bootcount=1
bootdelay=2
bootlimit=1
bootscript=echo Running bootscript from mmc ...; source
console=ttymxc1,115200 earlycon=ec_imx6q,0x30890000,115200
emmc_dev=1
ethaddr=00:04:9f:05:d1:93
ethprime=FEC
fastboot_dev=mmc1
fdt_addr=0x43000000
fdt_file=boot/fsl-imx8mm-evk.dtb
fdt_high=0xffffffffffffffff
fdtcontroladdr=bc906500
image=boot/Image
initrd_addr=0x43800000
initrd_high=0xffffffffffffffff
jh_clk= 
jh_mmcboot=mw 0x303d0518 0xff; setenv fdt_file fsl-imx8mm-evk-root.dtb;setenv jh_clk clk_ignore_unused; if run loadimage; then run mmcboot; else run jh_netboot; fi; 
jh_netboot=mw 0x303d0518 0xff; setenv fdt_file fsl-imx8mm-evk-root.dtb; setenv jh_clk clk_ignore_unused; run netboot; 
kboot=booti 
loadaddr=0x40480000
loadbootscript=fatload mmc ${mmcdev}:${mmcpart} ${loadaddr} ${script};
loadfdt=ext4load ${mender_uboot_root} ${fdt_addr} ${fdt_file}
loadimage=ext4load ${mender_uboot_root} ${loadaddr} ${image}
mender_altbootcmd=if test ${mender_boot_part} = 2; then setenv mender_boot_part 3; setenv mender_boot_part_hex 3; else setenv mender_boot_part 2; setenv mender_boot_part_hex 2; fi; setenv upgrade_available 0; saveenv; run mender_setup
mender_boot_kernel_type=booti
mender_boot_part=2
mender_boot_part_hex=2
mender_check_saveenv_canary=1
mender_dtb_name=fsl-imx8mm-evk-inmate.dtb
mender_kernel_name=Image
mender_saveenv_canary=1
mender_setup=if test "${mender_saveenv_canary}" != "1"; then setenv mender_saveenv_canary 1; saveenv; fi; if test "${mender_pre_setup_commands}" != ""; then run mender_pre_setup_commands; fi; setenv mender_kernel_root /dev/mmcblk1p${mender_boot_part}; if test ${mender_boot_part} = 2; then setenv mender_boot_part_name /dev/mmcblk1p2; else setenv mender_boot_part_name /dev/mmcblk1p3; fi; setenv mender_kernel_root_name ${mender_boot_part_name}; setenv mender_uboot_root mmc 0:${mender_boot_part_hex}; setenv mender_uboot_root_name ${mender_boot_part_name}; setenv expand_bootargs "setenv bootargs \\"${bootargs}\\""; run expand_bootargs; setenv expand_bootargs; if test "${mender_post_setup_commands}" != ""; then run mender_post_setup_commands; fi
mender_try_to_recover=if test ${upgrade_available} = 1; then reset; fi
mender_uboot_boot=mmc 0:1
mender_uboot_dev=0
mender_uboot_if=mmc
mfgtool_args=setenv bootargs console=${console},${baudrate} rdinit=/linuxrc clk_ignore_unused 
mmcargs=setenv bootargs ${jh_clk} console=${console} root=${mender_kernel_root}
mmcautodetect=yes
mmcboot=echo Booting from mmc ...; run mmcargs; if test ${boot_fdt} = yes || test ${boot_fdt} = try; then if run loadfdt; then booti ${loadaddr} - ${fdt_addr}; else echo WARN: Cannot load the DT; fi; else echo wait for boot; fi;
mmcdev=1
mmcpart=1
mmcroot=/dev/mmcblk2p2 rootwait rw
netargs=setenv bootargs ${jh_clk} console=${console} root=/dev/nfs ip=dhcp nfsroot=${serverip}:${nfsroot},v3,tcp
netboot=echo Booting from net ...; run netargs;  if test ${ip_dyn} = yes; then setenv get_cmd dhcp; else setenv get_cmd tftp; fi; ${get_cmd} ${loadaddr} ${image}; if test ${boot_fdt} = yes || test ${boot_fdt} = try; then if ${get_cmd} ${fdt_addr} ${fdt_file}; then booti ${loadaddr} - ${fdt_addr}; else echo WARN: Cannot load the DT; fi; else booti; fi;
script=boot.scr
sd_dev=0
soc_type=imx8mm
upgrade_available=0

Environment size: 3925/4091 bytes



Card did not respond to voltage select!
** Bad device mmc 0 **

排查问题定位于

OTA Mender 升级
  • 阅读文档

记录文档中的注意事项

mender -rootfs 与 mender -install 的疑惑? / 只是版本的区别

  • USB升级
fdisk -l 罗列出设备, 

mount /dev/sda1 /mnt  挂载U盘

mender -rootfs  /mnt/core.mender 进行升级
  • 在线升级
1. 配置文件介绍
2. 重点修改TenantToken
  • 升级过程
root@imx8mmevk:~# mender -rootfs /mnt/core.mender        
INFO[0000] Configuration file does not exist: /var/lib/mender/mender.conf  module=config
INFO[0000] Loaded configuration file: /etc/mender/mender.conf  module=config
INFO[0000] Mender running on partition: /dev/mmcblk1p2   module=main
INFO[0000] Start updating from local image file: [/mnt/core.mender]  module=rootfs
Installing update from the artifact of size 51602432
INFO[0000] no public key was provided for authenticating the artifact  module=installer
INFO[0000] opening device /dev/mmcblk1p3 for writing     module=block_device
INFO[0000] partition /dev/mmcblk1p3 size: 218103808      module=block_device
................................   2% 1024 KiB
................................ 
................................  99% 50176 KiB
......INFO[0047] wrote 218103808/218103808 bytes of update to device /dev/mmcblk1p3  module=device
                           100% 50393 KiB
INFO[0056] Enabling partition with new image installed to be a boot candidate: 3  module=device
  • 是否升级成功主要看:
 Kernel command line: console=ttymxc1,115200 earlycon=ec_imx6q,0x30890000,115200 root=/dev/mmcblk1p3
官方提供的mender-demo编译出的可以从SD卡启动, 无法从emmc启动

主要原因在于:

setenv mender_kernel_root /dev/mmcblk1p${mender_boot_part};  //这里参数是写死的

对应的

对应代码中

"setenv mender_kernel_root " MENDER_STORAGE_DEVICE_BASE "${mender_boot_part};

从而找到编译代码中

meta-mender-community/meta-mender-imx/templates/local.conf.append:8:MENDER_STORAGE_DEVICE_imx8mqevk = "/dev/mmcblk1"

修改之后结果发现还是无法启动, 提示:

Fastboot: Normal
Normal Boot
Hit any key to stop autoboot:  0 
switch to partitions #0, OK
mmc1(part 0) is current device
** Unable to read file boot.scr **
Card did not respond to voltage select!
** Bad device mmc 0 **
Booting from net ...
ethernet@30be0000 Waiting for PHY auto negotiation to complete......... TIMEOUT !
Could not initialize PHY ethernet@30be0000
BOOTP broadcast 1
BOOTP broadcast 2
BOOTP broadcast 3
BOOTP broadcast 4
BOOTP broadcast 5

注意到其中的: Card did not respond to voltage select! , ** Bad device mmc 0 ** , 马上根据关键词,定位到源码中相关位置, 查找时候没有重大发现,继续搜索关键词: Booting from net … , 发现:

//代码位置: include/configs/imx8mm_evk.h

   "if run loadimage; then " \
	   "run mmcboot; " \
	   "run mender_try_to_recover; " \
   "else " \
	   "run mender_try_to_recover; " \
	   "run netboot; " \
   "fi; " \
   
	"netboot=echo Booting from net ...; " \ 

应该是启动loadimage失败,导致else走netboot, 继续分析: 

	"loadimage=ext4load ${mender_uboot_root} ${loadaddr} ${image}\0" \  找到对应的环境变量值
    loadimage=ext4load mmc 0:2  0x40480000 boot/Image , 可以分析下ext4load后面字段的意思: 
    
   ext4load mmc 0:2 0x40480000 boot/Image   //从第0个存储设备的第2个分区的boot目录读出Image文件到内存地址0x40008000

 但是根据实际的情况,目前用的是第1个存储设备,第0个设备是SD卡
 
u-boot=> mmc list
FSL_SDHC: 0
FSL_SDHC: 1 (eMMC)


可以在uboot 中运行:  ext4load mmc 0:2  0x40480000 boot/Image 得到结果一样的
Card did not respond to voltage select!
** Bad device mmc 0 ** 

改为第1个存储设备之后, 运行正常
u-boot=> ext4load mmc 1:2  0x40480000 boot/Image 
23163392 bytes read in 448 ms (49.3 MiB/s)

//找到对应的问题,据悉分析在源码中应该怎么改动

include/env_mender.h 中的L91中设置了该变量
"setenv mender_uboot_root " MENDER_UBOOT_STORAGE_INTERFACE " " __stringify(MENDER_UBOOT_STORAGE_DEVICE) ":${mender_boot_part_hex}; " \

其中MENDER_UBOOT_STORAGE_DEVICE主要设置第几个存储设备, 这个宏的值是Yocto编译层面传进来的, 对应于

sources/meta-mender-community/meta-mender-imx/recipes-bsp/u-boot/u-boot-imx_%.bbappend 其中的MENDER_UBOOT_STORAGE_DEVICE_imx8mmevk改为1 

 10 # Set machine-specific variables per the definitions found in include/configs/MACHINE.h
 11 # | VARIABLE                                 | DEFINITION             |
 12 # | MENDER_UBOOT_ENV_STORAGE_DEVICE_OFFSET_1 | CONFIG_ENV_OFFSET      |
 13 # | BOOTENV_SIZE                             | CONFIG_ENV_SIZE        |
 14 # | MENDER_UBOOT_STORAGE_DEVICE              | CONFIG_SYS_MMC_ENV_DEV |
 17 MENDER_UBOOT_STORAGE_DEVICE_imx8mmevk              = "0"
 18 MENDER_UBOOT_ENV_STORAGE_DEVICE_OFFSET_1_imx8mqevk = "0x400000"


修改之后代码编译出错提示: 

include/config_mender.h
72:#  if CONFIG_SYS_MMC_ENV_DEV != MENDER_UBOOT_STORAGE_DEVICE
73:#   error CONFIG_SYS_MMC_ENV_DEV is not the same as MENDER_UBOOT_STORAGE_DEVICE. Either set it to the same value (check for example in the defconfig file), or make sure it is not defined at all. Make sure that: 1) All the instructions at docs.mender.io/devices/integrating-with-u-boot have been followed. 2) All required layers are included in bblayers.conf, including any board specific layers such as meta-mender-<board>

意思是 CONFIG_SYS_MMC_ENV_DEV 相等 MENDER_UBOOT_STORAGE_DEVICE才行,CONFIG_SYS_MMC_ENV_DEV的值位于
 include/configs/imx8mm_evk.h -> #define CONFIG_SYS_MMC_ENV_DEV>->---1   /* USDHC2 */

//修改源码之后,Yocto中编译需要注意一下

bitbake core-image-base -c compile -f

修改之后在此进行编译正常启动
  • 在线Mender部署
参考

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Lua之Date和Time

    Lua标准库中提供了关于时间函数os.time()和os.date(), 不同的是这两个函数引入时区的设置

    程序手艺人
  • Git 提交缺少Change-Id

    Git 提交时时候提示如下:主要提示你的提交缺少了Change-Id,主要之前进行了几次git rebase -i 错删了Change-Id导致的

    程序手艺人
  • [ 物联网篇 ] 20 - aplay Segmentation fault

    程序手艺人
  • Python list初始化

    4、Python的四种数据类型字典、集合、列表、元组,分别用花括号、中括号、小括号表示。如:

    py3study
  • Hike:A Hybrid Human-Machine Method for Entity Alignment

    Zhuang Y,Li G, Zhong Z, et al. Hike: A Hybrid Human-Machine Method for Entity Al...

    企鹅号小编
  • 日常踩坑实录

    最近在抓取了几十万条微博数据,目的是对其进行情感分析,这就需要过滤掉内容中表情等特殊符号。在Google了一圈以后,发现很多方法过滤的效果不好,因此自己记录一下...

    GitOPEN
  • redis高可用模式比较及一致性hash

    Sentinel为Redis提供高可用。利用Sentinel,在无人干预的情况下,可用让Redis服务抵御一定程度的故障。主要发挥以下几个方面的作用:

    开发架构二三事
  • Redis笔记(四):Redis事务支持

    以下是一个事务的例子, 它先以 MULTI 开始一个事务, 然后将多个命令入队到事务中, 最后由 EXEC 命令触发事务, 一并执行事务中的所有命令:

    朝雨忆轻尘
  • Little Tips 记录

    最近在抓取了几十万条微博数据,目的是对其进行情感分析,这就需要过滤掉内容中表情等特殊符号。在Google了一圈以后,发现很多方法过滤的效果不好,因此自己记录一下...

    GitOPEN
  • 从SAP最佳业务实践看企业管理(22)-CRM-案例

    一扫销售跟踪的沉闷 雄伟的帝国蓝十字大楼位于曼哈顿中心。在它的第31层楼上弥漫着一种典型的企业氛围。销售人员脚不沾地地穿行在迷宫般的格子间中,在富丽堂皇的办公室...

    SAP最佳业务实践

扫码关注云+社区

领取腾讯云代金券