LicheePI Zero 上电后进入到 u-boot 导致启动失败的解决方法

文章讲述了在LicheePIZero核心板上,由于连接RS232转换器导致设备上电后自动进入u-boot状态而非操作系统。通过排查,发现问题出在u-boot的自动启动逻辑接收到键盘输入后终止,通过修改u-boot代码解决了该问题,确保了正常启动流程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

故障描述

LicheePI Zero 核心板,配备 32M SPI-NOR-Flash,Console口 UART0 通过 RS232 接口芯片连接到上位机(如下图)。在测试中发现在设备上电后等待很久都不能 ping 通设备,使用 RS232 转 TTL 电缆连接上位机,打入回车键,发现是 u-boot 的提示符 ==>,说明设备自动进入到了u-boot 状态,导致启动失败。

使用上位机通过Console手动输入 boot 命令,可正常启动。正常启动后,执行操作系统的 reboot 指令,主板可以正常启动,不会进入到 u-boot。而拔出上位机电缆,断电后重新上电时,复现进入到 u-boot 的故障。

相同的主板,如果不接 RS232 转换芯片时,不会出现进入到 u-boot 的情况。

分析和测试

根据上述比较,猜测问题可能出在 RS232 转换接口上。如果不接上位机电缆,上电时,U5 的13/14 脚均为低电平。如果连接了上位机电缆,U5 的对应管脚会被正确地上拉/下拉。考虑到这一点,基本可以确定是 u-boot 扫描到了Console 口有“按键”输入,从而终止自动启动(autoboot)。

打开 VS Code,全局搜索“Hit any key to stop autoboot:”,最终定位到 .../u-boot/common/autoboot.c 的 __abortboot(int) 函数。通过分析代码,得知 __abortboot 的算法:当捕捉到任何一个按键输入时,即终止 boot,进入到 u-boot 命令行环境。

解决方法

找到了可能的原因,将这一部分的代码修改成如下内容。

static int __abortboot(int bootdelay)
{
	int abort = 0;
	unsigned long ts;

	int gotc = 0;

#ifdef CONFIG_MENUPROMPT
	printf(CONFIG_MENUPROMPT);
#else
	printf("Hit any key to stop autoboot: %2d ", bootdelay);
#endif

	/*
	 * Check if key already pressed
	 */
	if (tstc())
	{				  /* we got a key press	*/
					  /* Test gotc == RETURN_KEY || gotc == SPACE_BAR
						 If true, set abort = 1; others let abort alone.
					   */

#if (0)
		(void)getc(); /* consume input	*/
		puts("\b\b\b 0");
		abort = 1; /* don't auto boot	*/
#else
		gotc = getc(); /* save key pressed */
#if (1)
		printf("We catched key press as: %02X\r\n", gotc);
#endif
		if (gotc == 0x0D || gotc == 0x20)
		{
			/*puts("\b\b\b 0");*/ /* Clear counting down number and filled with 0 */
			abort = 1;			  /* Set abort boot flag */
		}
#endif
	}

	while ((bootdelay > 0) && (!abort))
	{
		--bootdelay;
		/* delay 1000 ms */
		ts = get_timer(0);
		do
		{
			if (tstc())
			{				   /* we got a key press	*/
#if (0)
				abort = 1;	   /* don't auto boot	*/
				bootdelay = 0; /* no more delay	*/
#ifdef CONFIG_MENUKEY
				menukey = getc();
#else
				(void)getc(); /* consume input	*/
#endif
#else
#ifdef CONFIG_MENUKEY
				menukey = getc();
				if (menukey == 0x0D || menukey == 0x20)
				{
					abort = 1;	   /* don't auto boot	*/
					bootdelay = 0; /* no more delay	*/
				}
#else
				gotc = getc(); /* consume input	*/
#if (1)
				printf("We catched key press as: %02X\r\n", gotc);
#endif
				if (gotc == 0x0D || gotc == 0x20)
				{
					abort = 1;	   /* don't auto boot	*/
					bootdelay = 0; /* no more delay	*/
				}
#endif
#endif
				break;
			}

			udelay(10000);
		} while (!abort && get_timer(ts) < 1000);

		printf("\b\b\b%2d ", bootdelay);
	}

	putc('\n');

	return abort;
}

#if(0) 块中的代码是原有的代码,#else中的代码是修改后的代码。主要思路:

  1. 第一次捕获按键输入时,判断是否为回车键(0x0D)或者空格键(0x20),如果是回车键或者空格键,才设置abort标志。
  2. 循环捕获按键输入时,也做上述同样的判断,符合条件时才设置abort标志。
  3. gotc变量保存getc()的结果。
  4. if(1) printf("We catched key press as: %02X\r\n", gotc); #endif 块纯粹为测试保留,可以设置为 if(0)。
  5. 尽量保留原有的 CONFIG_xxx条件。

使用

make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- clean

make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j16

将 u-boot-sunxi-with-spl.bin 文件拷贝到 buildroot 目录,重建整个 flashimg.bin,通过上位机烧录到Flash中,等待主板正常启动一次。然后断电,拆掉上位机电缆。连接好主板的以太网口,在上位机上 ping 主板。将主板上电。一开始是 ping 不通的(还没启动完成),等待大约10秒钟后,上位机可以 ping 通主板,这时执行

telnet 192.168.0.xxx(主板的IP地址)

可以正常登录。说明故障得以解决。

反复断电/上电大约 100次,没有捕捉到主板“误入”u-boot的情况。

参考链接

  1. 上电偶发停留在uboot中问题分析_一直在uboot_roostnew的博客-优快云博客-

感谢 roostnew 的思路,本文对如何修改 u-boot 的代码补充了一下。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

硬核老骆

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值