第十六期 U-Boot TTL串口输出原理分析《路由器就是开发板》

本文详细分析了U-Boot中TTL串口输出的实现过程,从初始化函数出发,逐步深入到寄存器操作层面,揭示了底层应用如何通过函数调用将信息输出到屏幕。

        这一期我们来分析一下U-Boot中TTL串口输出是怎么实现的,我们带着这个疑问来分析U-Boot的源文件。
        TTL的电气原理是这样的:发送数据时,CPU将并行数据写入UART,UART按照一定的格式在一根电线上串行发出;接收数据时,UART检测另一根电线上的信号,串行收集然后放在缓冲区中,CPU即可读取UART获得这些数据。UART之间以全双工方式传输数据,最精确的连线方法只有3根电线:TXD用于发送数据,RXD用于接收数据,GND用于给双发提供参考电平,连线如下:


那么在U-Boot软件结构上是如何将信息输出的呢,我们来分析一下源文件。首先说一下我们的分析思路,因为我们现在已经可以通过TTL输出信息到屏幕,疑问点是这个功能是如何实现的,所以这是一个逆向的过程,我们要通过最终的实现一级一级的向上追溯。
在U-Boot初始化过程中会打印出很多信息,那么我们就从初始化的函数board_init_r()开始分析,./lib_mips/board.c文件中第1109行,细看board_init_r()函数会发现,终端输出直接调用printf()函数,跳转到printf()函数的定义处:
void printf (const char *fmt, ...)
{
	va_list args;
	uint i;
	char printbuffer[CFG_PBSIZE];

	va_start (args, fmt);

	/* For this to work, printbuffer must be larger than
	 * anything we ever want to print.
	 */
	i = vsprintf (printbuffer, fmt, args);
	va_end (args);

	/* Print the string */
	puts (printbuffer);
}
可见是一个可变参数的函数,关键点是调用了puts()函数来进行输出,再跳转到puts()函数
void puts (const char *s)
{
	DECLARE_GLOBAL_DATA_PTR;

#ifdef CONFIG_SILENT_CONSOLE
	if (gd->flags & GD_FLG_SILENT)
		return;
#endif

	if (gd->flags & GD_FLG_DEVINIT) {
		/* Send to the standard output */
		fputs (stdout, s);
	} else {
		/* Send directly to the handler */
		serial_puts (s);
	}
}
到这里产生了分支,通过条件判断调用了fputs (stdout, s)和serial_puts (s)来实现输出功能,这里限于篇幅的原因,我们选择跟踪serial_puts()函数,有兴趣的读者可以尝试跟踪一下fputs()函数,它的实现是比较复杂的,涉及到了U-Boot的全局变量和设备模型,但在RT3052的SOC实现里fputs()函数最终还是通过调用serial_puts()函数来实现的,所以我们直接跟进serial_puts ()函数,定义在./board/rt2880/serial.c第332行:
void
serial_puts (const char *s)
{
	while (*s) {
		serial_putc (*s++);
	}
}
可以看出,serial_puts()就是serial_putc()的循环,以一个字符为单位,再跟进serial_putc() :
void serial_putc (const char c)
{
	/* wait for room in the tx FIFO on UART */
	while ((LSR(CFG_RT2880_CONSOLE) & LSR_TEMT) == 0);

	TBR(CFG_RT2880_CONSOLE) = c;

	/* If \n, also do \r */
	if (c == '\n')
		serial_putc ('\r');
}
这个参数用到了很多带参数的宏,比如:
TBR(CFG_RT2880_CONSOLE) = c;
其中TBR在./board/rt2880/serial.h第40行定义
 #define TBR(x)		__REG(RT2880_UART_CFG_BASE+(x)+RT2880_UART_TBR_OFFSET)
#define RT2880_UART_CFG_BASE (RT2880_CHIP_REG_CFG_BASE)
#define RT2880_CHIP_REG_CFG_BASE	(RALINK_SYSCTL_BASE)
#define RALINK_SYSCTL_BASE		0xB0000000
#define RT2880_UART_TBR_OFFSET	0x04
#  define __REG(x)	(*((volatile u32 *)io_p2v(x)))
#define CFG_RT2880_CONSOLE	RT2880_UART2   /* we use UART Lite for console */
#define RT2880_UART2	0x0C00  /* UART Lite */
经过以上分析可以将 TBR(CFG_RT2880_CONSOLE) = c; 拓展成 (*((volatile u32 *)(0xB0000000+0x0C00+0x04))) = c;即向地址为(0xB0000000+0x0C00+0x04)的寄存器内写入变量c的数据;
这是我们打开RT3052的DataSheet查找UART相关的寄存器信息可以看到:

这个寄存器的地址名称是TBR(Transmit Buffer Register),也就是发送缓冲器,只要将8位的数据也就是字符的ASCII码写入这个寄存器,在下一个传输周期就会将数据通过UART发送出去。
到这里我们初步的探索了TTL是怎样输出数据的,主要是要理解封装这个概念,能够领悟硬件的寄存器操作是怎样一层一层的封装,最后通过函数的方式提供给上层模块调用。其实驱动程序就是实现这样的功能,比如我们在windows下编程对硬件的控制往往都是厂商提供的SDK,我们只是进行调用就能控制硬件,其实追溯到底层原理是同样的,都是对寄存器的读写操作。记得当年学VHDL设计时的层级模型 开关级<--逻辑门级<--寄存器传输级<--算法级<--系统级,这里我们会发现在分析向U-Boot这样的底层应用很多情况下就是在分析算法级是怎样转换为寄存器传输级的。
U-Boot的硬件模型很多都是从linux的driver model里移植过来的,所以尝试去理解U-Boot的driver组织架构可以为分析linux内核奠定很好的基础,所以如果你有时间有兴趣,建议你更深层次的分析U-Boot的net,flash,usb模块相应的实现原理。
----------------------------------------------------
SDK下载地址:   https://github.com/aggresss/RFDemo

<think> 首先,用户的问题是:“我想了解使用开发板串行口烧录固件的相关信息 请问开发板通过串行口烧录固件的方法和注意事项”。用户提供了几个引用,但明确指出这些引用仅供参考,并不是用户真正的需求,我必须更多地参考用户上一次的问题和我的回答。 回顾系统指令:我必须使用中文回答;确保行内数学表达式使用$...$;独立公式使用$$...$$;LaTeX语法正确;生成相关问题;在回答中引用的段落末尾自然地添加引用标识。 用户的问题是关于开发板通过串行口烧录固件的方法和注意事项。引用中提到了固件的定义、开发板启动方式的设置、以及ESP8266的硬件参数和固件烧录。 关键点是用户提到“尽可能多的参考用户上一次的问题和你的回答”,但在这个对话中,这是第一次交互,没有上一次的问题或我的回答。所以,我应该专注于当前问题。 结构化回答: 1. **引言**:简要介绍固件烧录的重要性,并参考引用内容。 2. **方法**:详细描述通过串行口烧录固件的步骤。 3. **注意事项**:列出烧录时的关键注意事项。 4. **相关问题**:根据系统指令,生成相关问题。 引用标识:在回答中自然地添加引用标识。引用有[^1]、[^2]、[^3],所以我应该在使用这些内容时添加标识。 从引用中提取相关信息: - [^1]:固件是嵌入式系统的关键组成部分。 - [^2]:设置启动方式、断电拨动、上电后查看打印信息。 - [^3]:固件提供基本操作功能,如启动、关机、控制设备。 用户的具体问题是串行口烧录固件的方法和注意事项。引用[2]提到超级终端和启动设置,这可能涉及串行口,因为它说“在超级终端上看到”。 开发板通过串行口烧录固件的通用方法: - 通常使用UART串口连接电脑。 - 需要使用烧录工具,如esptool用于ESP8266。 - 步骤包括:连接串口线、设置波特率、使用烧录软件发送固件文件。 注意事项: - 确保正确的启动模式(如BOOT引脚设置)。 - 避免断电或中断烧录过程。 - 检查串口驱动和连接稳定性。 既然用户提到ESP8266在引用[3],我应该专注于那种开发板,但用户问题是通用的“开发板”,所以保持一般性。 生成相关问题:在回答末尾,添加“相关问题”部分,列出2-3个相关问题。 最终回答结构: 1. **介绍固件烧录**:简述固件的作用,参考[^1]和[^3]。 2. **方法步骤**:一步步描述烧录过程。 3. **注意事项**:列表形式。 4. **相关问题**:生成相关问题。 确保语言中文。 </think> ### 开发板通过串行口烧录固件的方法和注意事项 开发板通过串行口(通常是UART接口)烧录固件是一种常见且成本较低的固件更新方式,特别适用于嵌入式系统开发。固件作为硬件设备的底层软件,控制着设备的启动、输入输出管理、存储器操作等功能[^1][^3]。以下我将基于您的问题,详细解释烧录方法和关键注意事项。内容基于通用开发板(如ESP8266系列)的实践,参考了相关硬件参数和烧录流程[^2][^3]。 #### 1. **烧录固件的方法** 烧录过程主要通过串行口连接开发板和电脑,使用烧录工具软件完成。以下是通用步骤(以ESP8266开发板为例,其他开发板类似,但具体工具可能不同): - **步骤1: 准备硬件和软件** - **连接开发板**:使用USB-TTL串口转换器(如CH340或CP2102芯片)连接开发板的串行口(TX/RX引脚)到电脑的USB端口。确保开发板电源断电后连接[^2]。 - **设置串口参数**:在电脑上安装串口驱动程序(如CP210x驱动),并记录串口号(例如COM3或/dev/ttyUSB0)。默认波特率通常为115200 bps,但需参考开发板文档确认。 - **安装烧录工具**:下载并安装烧录软件,如`esptool`(用于ESP8266/ESP32)或`STM32CubeProgrammer`(用于STM32系列)。可以通过Python安装:`pip install esptool`。 - **获取固件文件**:从设备厂商或开源社区下载固件文件(通常为`.bin`格式),并保存在电脑易访问的位置。 - **步骤2: 配置开发板启动模式** - **断电设置启动方式**:在烧录前,开发板必须切换到烧录模式(例如通过BOOT引脚或拨码开关设置为“串行下载”模式)。参考开发板手册具体设置: - 例如,对于NAND FLASH启动的开发板,需将BOOT引脚接地或设为低电平[^2]。 - **重要操作**:设置时务必先给开发板断电,完成后重新上电。如果设置正确,开发板会进入烧录状态(LED指示灯可能闪烁)。 - **步骤3: 执行烧录操作** - **使用烧录工具**:打开命令行或终端,运行烧录命令。以ESP8266为例: ```bash esptool.py --port COM3 --baud 115200 write_flash 0x00000 firmware.bin ``` - `--port`:替换为实际串口号(如COM3或/dev/ttyUSB0)。 - `--baud`:波特率,默认为115200,但可调整以匹配开发板要求。 - `write_flash`:指定写入操作,`0x00000`是固件起始地址(需查阅固件文档)。 - **监控进度**:烧录过程中,工具会显示进度条和日志。完成后,提示“Write Completed”或类似消息。 - **验证烧录**:断开开发板电源,切换回正常启动模式(如EMMC或NAND启动)[^2]。重新上电后,使用串口调试工具(如PuTTY或Arduino IDE的串口监视器)连接到开发板。如果烧录成功,启动时会显示打印信息(如Bootloader日志或控制台提示符),敲回车可进入交互界面[^2]。 #### 2. **烧录注意事项** 烧录固件时需谨慎,以避免损坏硬件或固件。以下是关键注意事项: - **硬件安全**: - **确保稳定电源**:烧录过程中开发板电源必须稳定,避免中途断电,否则可能导致固件损坏或Flash存储器锁死[^2]。建议使用外部电源而非USB供电。 - **正确连接引脚**:串行口TX/RX引脚必须交叉连接(开发板TX接转换器RX,开发板RX接转换器TX)。错误连线会导致通信失败。 - **静电防护**:操作时穿戴防静电手环,尤其在干燥环境中,防止ESD损坏敏感元件。 - **软件和配置**: - **确认波特率和地址**:波特率不匹配(如使用9600 bps而非115200)或固件地址错误会导致烧录失败。务必参考开发板数据手册[^3]。 - **避免冲突**:确保串口未被其他程序占用(如关闭串口监视器后再烧录)。 - **固件兼容性**:下载的固件版本必须与开发板硬件匹配(如ESP8266 12F需使用特定固件尺寸),否则设备可能无法启动[^3]。 - **操作流程**: - **先设置后上电**:严格按照“断电→设置启动模式→上电→烧录”的顺序操作。跳步可能使开发板无法进入烧录状态[^2]。 - **测试启动**:烧录完成后,通过串口工具检查启动日志。如果无输出或报错(如“Boot Failed”),需重新检查设置和固件。 - **备份原始固件**:首次烧录前,建议先读取并备份原有固件:`esptool.py read_flash 0x00000 0x100000 backup.bin`(地址和大小根据Flash容量调整)。 - **通用建议**: - **使用可靠工具**:优先选择官方推荐的烧录软件,避免第三方工具导致兼容性问题。 - **环境因素**:在低干扰环境中操作,远离WiFi路由器等电磁源,以防串口通信中断。 - **文档查阅**:始终参考开发板的具体文档,因为不同厂商(如STMicroelectronics或Espressif)的细节可能有差异[^3]。 通过以上方法,您可以高效且安全地完成固件烧录。如果在实际操作中遇到问题,建议提供开发板型号和具体错误日志,以便进一步分析
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值