前言

环境介绍:

1.编译环境

Ubuntu 18.04.5 LTS

2.SDK

orangepi Linux 5.4 SDK

3.uboot

v2020.04

一、现象

根据《OrangePi_PCPlus_H3_用户手册_v3.1.pdf》5. Linux 5.4 SDK使用说明编译好镜像文件,将Linux 镜像烧写到 tf卡,启动板卡 ,uboot按空格键停留再uboot,保存环境变量,打印如下:

U-Boot 2020.04-orangepi (Jan 02 2021 - 19:58:40 +0800) Allwinner TechnologyCPU:   Allwinner H3 (SUN8I 1680)
Model: Xunlong Orange Pi PC Plus
DRAM:  1 GiB
MMC:   Device 'mmc@1c11000': seq 1 is in use by 'mmc@1c10000'
mmc@1c0f000: 0, mmc@1c10000: 2, mmc@1c11000: 1
Loading Environment from FAT... Unable to use mmc 1:1... In:    serial
Out:   serial
Err:   serial
Net:   phy interface0
eth0: ethernet@1c30000
230456 bytes read in 14 ms (15.7 MiB/s)
starting USB...
Bus usb@1c1a000: USB EHCI 1.00
Bus usb@1c1a400: USB OHCI 1.0
Bus usb@1c1b000: USB EHCI 1.00
Bus usb@1c1b400: USB OHCI 1.0
Bus usb@1c1c000: USB EHCI 1.00
Bus usb@1c1c400: USB OHCI 1.0
Bus usb@1c1d000: USB EHCI 1.00
Bus usb@1c1d400: USB OHCI 1.0
scanning bus usb@1c1a000 for devices... 1 USB Device(s) found
scanning bus usb@1c1a400 for devices... 1 USB Device(s) found
scanning bus usb@1c1b000 for devices... 1 USB Device(s) found
scanning bus usb@1c1b400 for devices... 1 USB Device(s) found
scanning bus usb@1c1c000 for devices... 1 USB Device(s) found
scanning bus usb@1c1c400 for devices... 1 USB Device(s) found
scanning bus usb@1c1d000 for devices... 1 USB Device(s) found
scanning bus usb@1c1d400 for devices... 1 USB Device(s) foundscanning usb for storage devices... 0 Storage Device(s) found
Autoboot in 1 seconds, press <Space> to stop
=>
=> saveenv
Saving Environment to FAT... Unable to use mmc 1:1... Failed (1)

无法保存环境变量,并且在前面加载环境变量的时候也出现了同样的打印信息,无法使用mmc 1:1

Unable to use mmc 1:1... Failed (1)

二、问题定位

直接在uboot搜索“Unable to use”

检索发现打印信息出自
env/fat.c
总共有两个函数有该打印信息

2.1 env_fat_load(void)

static int env_fat_load(void)
{ALLOC_CACHE_ALIGN_BUFFER(char, buf, CONFIG_ENV_SIZE);struct blk_desc *dev_desc = NULL;disk_partition_t info;int dev, part;int err;#ifdef CONFIG_MMCif (!strcmp(CONFIG_ENV_FAT_INTERFACE, "mmc"))mmc_initialize(NULL);
#endifpart = blk_get_device_part_str(CONFIG_ENV_FAT_INTERFACE,CONFIG_ENV_FAT_DEVICE_AND_PART,&dev_desc, &info, 1);if (part < 0)goto err_env_relocate;dev = dev_desc->devnum;if (fat_set_blk_dev(dev_desc, &info) != 0) {/** This printf is embedded in the messages from env_save that* will calling it. The missing \n is intentional.*/printf("Unable to use %s %d:%d... ",CONFIG_ENV_FAT_INTERFACE, dev, part);goto err_env_relocate;}err = file_fat_read(CONFIG_ENV_FAT_FILE, buf, CONFIG_ENV_SIZE);if (err == -1) {/** This printf is embedded in the messages from env_save that* will calling it. The missing \n is intentional.*/printf("Unable to read \"%s\" from %s%d:%d... ",CONFIG_ENV_FAT_FILE, CONFIG_ENV_FAT_INTERFACE, dev, part);goto err_env_relocate;}return env_import(buf, 1);err_env_relocate:env_set_default(NULL, 0);return -EIO;
}

2.2 env_fat_save(void)

static int env_fat_save(void)
{env_t __aligned(ARCH_DMA_MINALIGN) env_new;struct blk_desc *dev_desc = NULL;disk_partition_t info;int dev, part;int err;loff_t size;err = env_export(&env_new);if (err)return err;part = blk_get_device_part_str(CONFIG_ENV_FAT_INTERFACE,CONFIG_ENV_FAT_DEVICE_AND_PART,&dev_desc, &info, 1);if (part < 0)return 1;dev = dev_desc->devnum;if (fat_set_blk_dev(dev_desc, &info) != 0) {/** This printf is embedded in the messages from env_save that* will calling it. The missing \n is intentional.*/printf("Unable to use %s %d:%d... ",CONFIG_ENV_FAT_INTERFACE, dev, part);return 1;}err = file_fat_write(CONFIG_ENV_FAT_FILE, (void *)&env_new, 0, sizeof(env_t),&size);if (err == -1) {/** This printf is embedded in the messages from env_save that* will calling it. The missing \n is intentional.*/printf("Unable to write \"%s\" from %s%d:%d... ",CONFIG_ENV_FAT_FILE, CONFIG_ENV_FAT_INTERFACE, dev, part);return 1;}return 0;
}

从函数名判断
env_fat_save是保存环境变量时调用
env_fat_load是uboot一开始加载环境变量时调用
但都集中与下面这函数

if (fat_set_blk_dev(dev_desc, &info) != 0) {/** This printf is embedded in the messages from env_save that* will calling it. The missing \n is intentional.*/printf("Unable to use %s %d:%d... ",CONFIG_ENV_FAT_INTERFACE, dev, part);return 1;
}

其中fat_set_blk_dev定义在
fs/fat/fat.c

int fat_set_blk_dev(struct blk_desc *dev_desc, disk_partition_t *info)
{ALLOC_CACHE_ALIGN_BUFFER(unsigned char, buffer, dev_desc->blksz);cur_dev = dev_desc;cur_part_info = *info;/* Make sure it has a valid FAT header */if (disk_read(0, 1, buffer) != 1) {cur_dev = NULL;return -1;}/* Check if it's actually a DOS volume */if (memcmp(buffer + DOS_BOOT_MAGIC_OFFSET, "\x55\xAA", 2)) {cur_dev = NULL;return -1;}/* Check for FAT12/FAT16/FAT32 filesystem */if (!memcmp(buffer + DOS_FS_TYPE_OFFSET, "FAT", 3))return 0;if (!memcmp(buffer + DOS_FS32_TYPE_OFFSET, "FAT32", 5))return 0;cur_dev = NULL;return -1;
}

2.3 疑点1

该函数作用是检查tf卡分区以及文件类型的,ps具体不是很懂哈~
从打印情况来看,估计采用推荐的格式化工具格式化tf卡出了问题。

2.4 疑点2

uboot打印的"mmc 1:1…"到底啥意思?
打印的源码如下:

printf("Unable to use %s %d:%d... ",CONFIG_ENV_FAT_INTERFACE, dev, part);

CONFIG_ENV_FAT_INTERFACE 为mmc 定义如下,可以理解为环境变量的接口,也就是环境变量的存储介质。

include/generated/autoconf.h
#define CONFIG_ENV_FAT_INTERFACE "mmc"

dev则为h3 mmc的设备号。
h3总共有三个mmc接口,如下是《Allwinner_H3_Datasheet_v1.2.pdf》找到的。

与uboot一开始打印的信息可以对应上

mmc@1c0f000: 0, mmc@1c10000: 2, mmc@1c11000: 1

其实uboot打印的序号、地址与规格书是有出入的,这里不做深入研究,与我们现在的问题解决关系不大。ps之前就是以为有关系,花了好大力气研究这里,白白浪费时间 -_-!
orangepi pc plus mmc接口硬件设计如下
sd/mmc0→tf卡
sd/mmc1→wifi
sd/mmc2→emmc
part是对应的存储介质内部的分区。
由上可知前面的打印意思是mmc 1设备的分区1无法使用。

三、问题解决

我们先从上面的疑点1入手~

3.1 解疑点1

如下是采用可视化分区工具gparted查看装有系统tf卡的分区情况
这工具挺好用的,适合小白可通过sudo apt install gparted安装。

tf卡只做了一个分区sdb1,并且格式化为ext4,分区1里面存放的就是启动系统。

其中boot里面存放的就是linux kernel编译好的镜像,还有启动参数boot.scr。

那么有人会问uboot存放在哪呢?
其实是是放在tf卡前面未分配的4MB里面,这里不细说。

额。。。以上有点扯远了。
其实问题就出在分区1格式化为ext4!
因为前面uboot的fat_set_blk_dev函数会检查分区格式是否为FAT/FAT32。虽然h3启动对分区格式无要求,能正常加载到想要的数据就行,但不正确的格式影响uboot环境变量加载、保存。
解决方法查看我另外一篇文章。

3.2 解疑点2

以上就算格式化正确了,还是无法解决环境变量问题。
因这个版本uboot存在问题,默认是从mmc 1分区1加载、保存环境变量。
根据前面的推断mmc 1并非tf卡,在加上打印信息与Datasheet有出入,做如下推断:
打印的mmc 1 对应地址是mmc@1c11000,而该地址在Datasheet对应的是mmc2,实际硬件接的emmc。也就是不管插不插卡,默认都是从emmc加载、保存环境变量。
要做的就是修改从tf卡加载、保存环境变量。
下面这个函数的CONFIG_ENV_FAT_DEVICE_AND_PART,就是导致默认从mmc1加载环境变量的。

part = blk_get_device_part_str(CONFIG_ENV_FAT_INTERFACE,CONFIG_ENV_FAT_DEVICE_AND_PART,&dev_desc, &info, 1);

该宏定义在:include/generated/autoconf.h

#define CONFIG_ENV_FAT_DEVICE_AND_PART "1:auto"

是env/Kconfig通过MMC_SUNXI_SLOT_EXTRA的不同值自动生成的。

config ENV_FAT_DEVICE_AND_PARTstring "Device and partition for where to store the environemt in FAT"depends on ENV_IS_IN_FATdefault "0:1" if TI_COMMON_CMD_OPTIONSdefault "0:auto" if ARCH_ZYNQMPdefault "0:auto" if ARCH_SUNXI && MMC_SUNXI_SLOT_EXTRA = -1default "1:auto" if ARCH_SUNXI && MMC_SUNXI_SLOT_EXTRA != -1default "0" if ARCH_AT91

而MMC_SUNXI_SLOT_EXTRA则定义在configs/orangepi_pc_plus_defconfig

CONFIG_MMC_SUNXI_SLOT_EXTRA=2

这定义估计是单板支持2个启动mmc设备。
查看orangepi pc(无emmc)的配置文件orangepi_pc_defconfig,则没有该参数。采用该配置文件编译之后CONFIG_ENV_FAT_DEVICE_AND_PART如下:

#define CONFIG_ENV_FAT_DEVICE_AND_PART "0:auto"

试着把orangepi_pc_plus_defconfig的CONFIG_MMC_SUNXI_SLOT_EXTRA屏蔽掉,
编译之后值同上。
最终效果见这两篇博文
香橙派orangepi pc plus h3 启动tf卡制作

香橙派orangepi pc plus h3 uboot保存环境变量失败解决——Unable to use mmc 1:1... Failed (1)相关推荐

  1. 香橙派orangepi pc plus h3 启动tf卡制作

    前言 环境介绍: 1.编译环境 Ubuntu 18.04.5 LTS 2.SDK orangepi Linux 5.4 SDK 3.uboot v2020.04 参考说明: Bootable SD c ...

  2. 香橙派orangepi查看 GPIO当前状态方法: 安装wiringOP

    树莓派orangepi查看GPIO当前状态 方法:安装GPIO库接口wiringpid,而香橙派orangepi跟树莓派的方法不一样,是用wiringOP, 而wiringOP是从wiringpi改造 ...

  3. 如何修改uboot的环境变量env的值来指定uImage的名字

    今天继续玩基于uboot的nfs.昨天总算是基本搞清了make zImage和make uImage的区别,那么今天就来实际编译几个玩一玩. 不过,在利用mkimage工具对zImage镜像文件加工完 ...

  4. 从bootm 命令讲起/U-boot的环境变量: bootcmd 和bootargs

    从bootm 命令讲起 1 找到linux的内核入口 Bootm命令通过读取uImage的头部0×40字节的信息,将uImage定位到正确的地址,同时找到linux的内核入口地址. 这个地方就涉及到u ...

  5. uboot的环境变量

    注:本文是学习朱老师课程整理的笔记,基于uboot-1.3.4和s5pc11x分析. 环境变量的作用 可以不用修改uboot的源代码,而是通过修改环境变量来影响uboot运行时的一些数据和特性.譬如说 ...

  6. uboot之环境变量

    一.环境变量基础知识 1.环境变量的作用 环境变量的最大作用就是在我们不需要改变源代码的情况下,改变程序的执行情况.比如我们的bootdelay时间,通过修改对应的环境变量的值,就可以改变uboot开 ...

  7. uboot中环境变量的加载、写入过程详解

    1.uboot启动中环境变量的加载 1.1.uboot加载环境变量流程分析 (1)首先使用默认的环境变量default_environment[]: (2)然后加载SD卡中env分区的环境变量,校验读 ...

  8. uboot中环境变量的实现

    1.环境变量介绍 uboot中环境变量的作用类似于全局变量,需要某个环境变量的值时调用getenv函数就可以得到.环境变量会指导程序的运行,不必修改代码重新编译,通过修改环境变量就可以改变uboot的 ...

  9. uboot默认环境变量修改

    uboot的默认环境变量决定了系统是通过何种方式启动的,对于定制化的嵌入式系统,uboot的定制化修改也是必要的. uboot有两种修改方式: 1.直接修改源码或者修改uboot配置 2.在uboot ...

最新文章

  1. 詹森不等式_注意詹森差距
  2. 剑指 Offer 68 - II. (二叉树)二叉树的最近公共祖先
  3. 新版 Edge 浏览器 Logo 曝光:形状相同,但为黄色背景
  4. git 应用 cherry-pick
  5. python怎么把变量付给数组_使用Python将数组的元素导出到变量中(unpacking)
  6. apache安装步骤(redhat)
  7. bootice安装grub2-00 到硬盘或者U盘mbr
  8. malloc函数和free函数的使用方法解析
  9. 计算机教育硕士专业代码,硕士专业代码查询
  10. 行为识别:行人跌倒检测(含源码)
  11. 有感:一名大学毕业生的反思:轰动中国万言帖 最露骨大学生活
  12. Report Services RDL报告服务器的一些经验
  13. 基于C语言的Q格式使用详解
  14. ListView的增删改查(实战)
  15. 【随笔】编程能力和程序员
  16. Vmware Esxi在线管理虚拟机
  17. 宝塔Linux面板安装教程(+Mysql)
  18. 【Redis笔记】发布与订阅
  19. DBeaver(数据库管理软件) v22.0.1 使用安装教程
  20. 阿里云服务器上安装Mysql 服务

热门文章

  1. Windows 7 / 便笺快捷键——让Win7便笺拥有格式
  2. java中将word流化,Microsoft Word - 2015最新java面试题.doc
  3. AI换声,只需5秒音源,这个网络就能实时“克隆”你的声音
  4. 基于GAE搭建Gtalk群
  5. 录屏软件Kap使用经验分享
  6. python flag用法_花了一晚上时间,终于把Python的基本用法归纳好了!
  7. matlab 图上写数字,图像的数字表示和读写操作(MATLAB)
  8. 全网谁家热干面销量最高?教你用Python轻松获取
  9. pyqt label改变文字_制作布条缝制可爱潮流文字图片的PS教程
  10. 数据库查询优化的方式