在嵌入式系統(tǒng)中差导,串口既可以用于輸出日志進(jìn)行系統(tǒng)調(diào)試,又可以用于短距離低速通信舰始,是一種非常實(shí)用的通信端口第焰。
本文基于RockPI 4A
單板Linux 4.4
內(nèi)核介紹RK3399 UART
功能。
一上枕、UART介紹
UART(Universal Asynchronous Receiver/Transmitter)
:通用異步收發(fā)器咐熙,適用于短距離、低速辨萍、串行和全雙工數(shù)據(jù)傳輸棋恼。
在PC
中,串口一般指COM
口锈玉,即串行通訊端口爪飘。有9個(gè)引腳,使用RS-232
電平拉背。
在嵌入式中师崎,串口一般指UART
口。一般使用3個(gè)引腳椅棺,使用TTL
電平犁罩。
TTL/RS-232/RS-485
是指電平標(biāo)準(zhǔn),差別如下:
電平標(biāo)準(zhǔn) | 邏輯0 | 邏輯1 | 傳輸方式 |
---|---|---|---|
TTL 電平 |
0 ~ 0.4V |
2.4 ~ 5V |
全雙工 |
RS-232 電平 |
3 ~ 15V |
-15 ~ -3V |
全雙工 |
RS-485 電平 |
-6 ~ -2V |
2 ~ 6V |
半雙工(差分傳輸两疚,距離更長(zhǎng)) |
在嵌入式單板調(diào)試時(shí)床估,可以選擇USB轉(zhuǎn)TTL
模塊,實(shí)現(xiàn)PC
和單板之間的串口通訊鬼雀,見(jiàn)下圖:
RK3399 UART
控制器特性:
1顷窒、支持5路串口。
2源哩、支持DMA
或中斷傳輸模式鞋吉。
3、支持2個(gè)64字節(jié)的發(fā)送和接收FIFO
励烦。
4谓着、支持5/6/7/8bit
串行數(shù)據(jù)發(fā)送或接收。
5坛掠、支持啟動(dòng)赊锚、停止和奇偶校驗(yàn)等標(biāo)準(zhǔn)異步通信位治筒。
6、最大可支持到4Mbps
的時(shí)鐘波特率舷蒲。
7耸袜、UART0/3
支持自動(dòng)流控模式。
RK3399 UART
引腳描述見(jiàn)下圖:
二牲平、UART連接
ROCKPi 4A
單板有個(gè)40個(gè)引腳的擴(kuò)展口堤框,引用radxa
圖片,見(jiàn)下圖:
RockPI 4A
單板的UART2
作為調(diào)試串口纵柿,和USB
轉(zhuǎn)TTL
串口的引腳連接方式如下:
RockPI4A單板 | USB轉(zhuǎn)TTL串口 |
---|---|
PIN8(UART2_TXD) | RXD |
PIN9(GND) | GND |
PIN10(UART2_RXD) | TXD |
RockPI 4A
單板的調(diào)試串口配置見(jiàn)下圖:
連接串口時(shí)蜈抓,必須先保證
GND
連接正確,其次查看串口引腳電平是否兼容昂儒,串口參數(shù)配置是否正確沟使,否則容易出現(xiàn)串口不可用或亂碼。
三渊跋、UART配置
以ROCKPI 4A
單板為例腊嗡,介紹RK3399 DTS
中UART
配置。
3.1刹枉、串口別名
普通串口設(shè)備會(huì)根據(jù)dts
中aliases
對(duì)串口進(jìn)行編號(hào)叽唱,將serialx
注冊(cè)成對(duì)應(yīng)的ttySx
設(shè)備。
配置文件:arch/arm64/boot/dts/rockchip/rk3399.dtsi
微宝。
RK3399 DTS
中aliases
定義如下:
aliases {
...
serial0 = &uart0;
serial1 = &uart1;
serial2 = &uart2;
serial3 = &uart3;
serial4 = &uart4;
};
如果將UART4
修改注冊(cè)成ttyS1
,可以進(jìn)行如下修改:
aliases {
...
serial0 = &uart0;
serial1 = &uart4; ## 使用uart4替換uart1
...
serial4 = &uart1;
};
3.2虎眨、串口配置
配置文件:arch/arm64/boot/dts/rockchip/rk3399.dtsi
蟋软。
UART0 dts
配置如下:
uart0: serial@ff180000 {
compatible = "rockchip,rk3399-uart", "snps,dw-apb-uart";
reg = <0x0 0xff180000 0x0 0x100>; ## uart0寄存器地址0xff180000和映射大小0x100
clocks = <&cru SCLK_UART0>, <&cru PCLK_UART0>; ## uart0使用的時(shí)鐘
clock-names = "baudclk", "apb_pclk";
interrupts = <GIC_SPI 99 IRQ_TYPE_LEVEL_HIGH 0>; ## uart0使用SPI中斷,中斷號(hào)131(99+32)嗽桩,沒(méi)有使用DMA模式
reg-shift = <2>; ## 寄存器地址偏移2位岳守,即offset+4
reg-io-width = <4>; ## 寄存器位寬,即32位。
pinctrl-names = "default";
pinctrl-0 = <&uart0_xfer &uart0_cts &uart0_rts>; ## uart0使用流控引腳
status = "disabled"; ## 默認(rèn)關(guān)閉狀態(tài)
};
UART0 pinmux
配置碌冶,其中包括流控引腳cts/rts
湿痢。
uart0 {
uart0_xfer: uart0-xfer {
rockchip,pins =
<2 16 RK_FUNC_1 &pcfg_pull_up>,
<2 17 RK_FUNC_1 &pcfg_pull_none>;
};
uart0_cts: uart0-cts {
rockchip,pins =
<2 18 RK_FUNC_1 &pcfg_pull_none>;
};
uart0_rts: uart0-rts {
rockchip,pins =
<2 19 RK_FUNC_1 &pcfg_pull_none>;
};
};
注:
RK3399 UART0
中斷號(hào)為131。SPI
中斷號(hào)從32開(kāi)始扑庞,dts
中的SPI
中斷號(hào)默認(rèn)從0開(kāi)始譬重,所以UART0
配置的中斷號(hào)為:131-32,即99罐氨。
系統(tǒng)啟動(dòng)后臀规,可查看串口中斷(131和132):
root@xiaotianbsp:/# cat proc/interrupts
CPU0 CPU1 CPU2 CPU3 CPU4 CPU5
14: 0 0 0 0 0 0 GICv3 29 Edge arch_timer
...
35: 16 0 0 0 0 0 GICv3 131 Level serial
...
222: 301 0 0 0 0 0 GICv3 132 Level debug
...
Err: 0
3.3、串口使能
配置文件:arch/arm64/boot/dts/rockchip/rockpi-4-linux.dtsi
栅隐。
UART0 dts
使能配置如下:
&uart0 {
pinctrl-names = "default";
pinctrl-0 = <&uart0_xfer &uart0_cts>;
status = "okay"; ## okay:打開(kāi)串口功能; disabled:關(guān)閉該串口功能塔嬉。
};
&uart2 {
status = "okay"; ## 使能串口2
};
注:
status = "okay"
或"ok"
玩徊,而不能用enable
。
內(nèi)核解析代碼如下:
static bool __of_device_is_available(const struct device_node *device)
{
...
status = __of_get_property(device, "status", &statlen);
...
if (statlen > 0) {
if (!strcmp(status, "okay") || !strcmp(status, "ok"))
return true;
}
return false;
}
3.4谨究、ttyFIQ0
系統(tǒng)使用/dev/ttyFIQ0
作為console
設(shè)備恩袱。
配置文件:arch/arm64/boot/dts/rockchip/rockpi-4-linux.dtsi
,內(nèi)容如下:
fiq_debugger: fiq-debugger {
status = "disabled";
compatible = "rockchip,fiq-debugger";
rockchip,serial-id = <2>; ## 使用串口號(hào)(UART2),修改該屬性的值胶哲,切換串口憎蛤,同時(shí)切換串口的pinmux
rockchip,signal-irq = <182>;
rockchip,wake-irq = <0>;
rockchip,irq-mode-enable = <1>; /* If enable uart uses irq instead of fiq */
rockchip,baudrate = <1500000>; /* Only 115200 and 1500000 */
pinctrl-names = "default";
pinctrl-0 = <&uart2c_xfer>; ## pinmux必須和serial-id對(duì)應(yīng)
};
RockPI 4A
單板使用的Debian
系統(tǒng),在配置文件extlinux.conf
中設(shè)置console
參數(shù)纪吮。
root@xiaotianbsp:/boot/extlinux# cat extlinux.conf
timeout 10
menu title select kernel
label kernel-4.4.154-90-rockchip-ga14f6502e045
kernel /vmlinuz-4.4.154-90-rockchip-ga14f6502e045
devicetreedir /dtbs/4.4.154-90-rockchip-ga14f6502e045
## 使能early printk俩檬,ttyFIQ0做為console設(shè)備,串口波特率1.5M碾盟,8個(gè)數(shù)據(jù)位棚辽,1個(gè)停止位
append earlyprintk console=ttyFIQ0,1500000n8 init=/sbin/init root=PARTUUID=b921b045-1d rw rootwait rootfstype=ext4
系統(tǒng)啟動(dòng)后,可通過(guò)cmdline
查看冰肴。
root@xiaotianbsp:~# cat /proc/cmdline
earlyprintk console=ttyFIQ0,1500000n8 init=/sbin/init root=PARTUUID=b921b045-1d rw rootwait rootfstype=ext4
四屈藐、UART驅(qū)動(dòng)
RK3399 Linux4.4
內(nèi)核UART
驅(qū)動(dòng)采用8250通用驅(qū)動(dòng),類(lèi)型是16550A
熙尉。主要實(shí)現(xiàn)文件:
drivers/tty/serial/8250/8250_dma.c ## UART dma實(shí)現(xiàn)
drivers/tty/serial/8250/8250_dw.c ## Synopsys DesignWare 8250串口驅(qū)動(dòng)
drivers/tty/serial/8250/8250_early.c ## early console實(shí)現(xiàn)
drivers/tty/serial/8250/8250_port.c ## UART端口配置的相關(guān)接口
UART
驅(qū)動(dòng)和調(diào)試后續(xù)介紹联逻。
五、內(nèi)核日志調(diào)試
在嵌入式Linux
系統(tǒng)中检痰,最常見(jiàn)的就是使用串口輸出內(nèi)核日志進(jìn)行功能調(diào)試包归。
5.1、printk
在Linux
內(nèi)核中铅歼,可用函數(shù)printk()
將內(nèi)核信息輸出到內(nèi)核信息緩沖區(qū)中公壤。
內(nèi)核日志輸出分不同的等級(jí),定義文件:include/linux/kern_levels.h
椎椰,包括:
#define LOGLEVEL_EMERG 0 /* system is unusable */
#define LOGLEVEL_ALERT 1 /* action must be taken immediately */
#define LOGLEVEL_CRIT 2 /* critical conditions */
#define LOGLEVEL_ERR 3 /* error conditions */
#define LOGLEVEL_WARNING 4 /* warning conditions */
#define LOGLEVEL_NOTICE 5 /* normal but significant condition */
#define LOGLEVEL_INFO 6 /* informational */
#define LOGLEVEL_DEBUG 7 /* debug-level messages */
除printk()
函數(shù)外厦幅,還可以使用pr_**()
和dev_**()
。
pr_**
定義文件:include/linux/printk.h
慨飘,宏定義如下:
#define pr_emerg(fmt, ...) \
printk(KERN_EMERG pr_fmt(fmt), ##__VA_ARGS__)
#define pr_alert(fmt, ...) \
printk(KERN_ALERT pr_fmt(fmt), ##__VA_ARGS__)
#define pr_crit(fmt, ...) \
printk(KERN_CRIT pr_fmt(fmt), ##__VA_ARGS__)
#define pr_err(fmt, ...) \
printk(KERN_ERR pr_fmt(fmt), ##__VA_ARGS__)
#define pr_warning(fmt, ...) \
printk(KERN_WARNING pr_fmt(fmt), ##__VA_ARGS__)
#define pr_warn pr_warning
#define pr_notice(fmt, ...) \
printk(KERN_NOTICE pr_fmt(fmt), ##__VA_ARGS__)
#define pr_info(fmt, ...) \
printk(KERN_INFO pr_fmt(fmt), ##__VA_ARGS__)
dev_**
定義文件:drivers/base/core.c
确憨,函數(shù)定義如下:
#define define_dev_printk_level(func, kern_level) \
void func(const struct device *dev, const char *fmt, ...) \
{ \
struct va_format vaf; \
va_list args; \
\
va_start(args, fmt); \
\
vaf.fmt = fmt; \
vaf.va = &args; \
\
__dev_printk(kern_level, dev, &vaf); \
\
va_end(args); \
} \
EXPORT_SYMBOL(func);
define_dev_printk_level(dev_emerg, KERN_EMERG);
define_dev_printk_level(dev_alert, KERN_ALERT);
define_dev_printk_level(dev_crit, KERN_CRIT);
define_dev_printk_level(dev_err, KERN_ERR);
define_dev_printk_level(dev_warn, KERN_WARNING);
define_dev_printk_level(dev_notice, KERN_NOTICE);
define_dev_printk_level(_dev_info, KERN_INFO);
5.1.1、日志輸出等級(jí)
通過(guò)修改loglevel
或/proc/sys/kernel/printk
的值可以調(diào)整內(nèi)核日志輸出等級(jí)瓤的。
在系統(tǒng)啟動(dòng)前休弃,通過(guò)配置loglevel
,可以調(diào)整串口日志輸出等堤瘤。
root@xiaotianbsp:~# cat /boot/extlinux/extlinux.conf
...
label kernel-debug
kernel /debug/Image
fdt /debug/rk3399-rock-pi-4a.dtb
## 修改loglevel調(diào)整串口輸出日志等級(jí)
append earlyprintk console=ttyFIQ0,1500000n8 loglevel=4 init=/sbin/init root=PARTUUID=b921b045-1d rw rootwait rootfstype=ext4 no_console_suspend initcall_debug
其他系統(tǒng)(如:Ubuntun玫芦、Buildroot
或Android
),一般在bootargs
中修改loglevel
本辐。
注:
no_console_suspend
用于Linux系統(tǒng)電源管理調(diào)試桥帆,表示系統(tǒng)休眠(suspend)后医增,串口不休眠,仍可輸出老虫。
在系統(tǒng)啟動(dòng)后叶骨,也可動(dòng)態(tài)調(diào)整串口日志輸出等級(jí)。
root@xiaotianbsp:/proc/sys/kernel# cat printk
7 4 1 7
root@xiaotianbsp:/proc/sys/kernel# echo 4 > printk
root@xiaotianbsp:/proc/sys/kernel# cat printk
4 4 1 7
printk
中的數(shù)字對(duì)應(yīng)不同的日志級(jí)別祈匙,只要修改console
口的日志級(jí)別即可忽刽。
int console_printk[4] = {
CONSOLE_LOGLEVEL_DEFAULT, /* console_loglevel */ ## 控制臺(tái)的日志級(jí)別
MESSAGE_LOGLEVEL_DEFAULT, /* default_message_loglevel */ ## 默認(rèn)消息日志級(jí)別
CONSOLE_LOGLEVEL_MIN, /* minimum_console_loglevel */ ## 最小控制臺(tái)日志級(jí)別
CONSOLE_LOGLEVEL_DEFAULT, /* default_console_loglevel */ ## 默認(rèn)控制臺(tái)日志級(jí)別
};
5.1.2、日志時(shí)間戳
在系統(tǒng)啟動(dòng)后夺欲,可以動(dòng)態(tài)調(diào)整內(nèi)核日志時(shí)間戳的顯示跪帝。
## 1.time值為Y,表示顯示時(shí)間戳
root@xiaotianbsp:/# cat /sys/module/printk/parameters/time
Y
## 2.此時(shí)日志顯示有時(shí)間戳
root@xiaotianbsp:/# find . -name time
[ 1719.836194] FAT-fs (sda4): error, invalid access to FAT (entry 0x07b03538)
[ 1719.836874] FAT-fs (sda4): error, invalid access to FAT (entry 0x07b03538)
## 3.設(shè)置time值為N
root@xiaotianbsp:/# echo N > /sys/module/printk/parameters/time
## 4.此時(shí)日志顯示有時(shí)間戳
root@xiaotianbsp:/# find . -name time
FAT-fs (sda4): error, invalid access to FAT (entry 0x07b03538)
FAT-fs (sda4): error, invalid access to FAT (entry 0x07b03538)
5.2些阅、dmesg
在系統(tǒng)啟動(dòng)后伞剑,如果已經(jīng)錯(cuò)過(guò)內(nèi)核啟動(dòng)階段或使用非串口(例:adb/ssh
登錄)連接調(diào)試板,可以使用dmesg
查看內(nèi)核日志市埋。
dmesg
用法如下:
root@xiaotianbsp:/# dmesg -h
Usage:
dmesg [options]
Display or control the kernel ring buffer.
Options:
-C, --clear clear the kernel ring buffer
-c, --read-clear read and clear all messages
-D, --console-off disable printing messages to console
-E, --console-on enable printing messages to console
-F, --file <file> use the file instead of the kernel log buffer
-f, --facility <list> restrict output to defined facilities
-H, --human human readable output
-k, --kernel display kernel messages
-L, --color[=<when>] colorize messages (auto, always or never)
colors are enabled by default
-l, --level <list> restrict output to defined levels
-n, --console-level <level> set level of messages printed to console
-P, --nopager do not pipe output into a pager
-r, --raw print the raw message buffer
-S, --syslog force to use syslog(2) rather than /dev/kmsg
-s, --buffer-size <size> buffer size to query the kernel ring buffer
-u, --userspace display userspace messages
-w, --follow wait for new messages
-x, --decode decode facility and level to readable string
-d, --show-delta show time delta between printed messages
-e, --reltime show local time and time delta in readable format
-T, --ctime show human-readable timestamp (may be inaccurate!)
-t, --notime don't show any timestamp with messages
--time-format <format> show timestamp using the given format:
[delta|reltime|ctime|notime|iso]
Suspending/resume will make ctime and iso timestamps inaccurate.
-h, --help display this help and exit
-V, --version output version information and exit
Supported log facilities:
kern - kernel messages
user - random user-level messages
mail - mail system
daemon - system daemons
auth - security/authorization messages
syslog - messages generated internally by syslogd
lpr - line printer subsystem
news - network news subsystem
Supported log levels (priorities):
emerg - system is unusable
alert - action must be taken immediately
crit - critical conditions
err - error conditions
warn - warning conditions
notice - normal but significant condition
info - informational
debug - debug-level messages
For more details see dmesg(1).
5.2.1黎泣、顯示內(nèi)核日志
root@xiaotianbsp:/# dmesg
[ 0.000000] Booting Linux on physical CPU 0x0
[ 0.000000] Initializing cgroup subsys cpuset
[ 0.000000] Initializing cgroup subsys cpu
[ 0.000000] Initializing cgroup subsys cpuacct
[ 0.000000] Linux version 4.4.154-90-rockchip-ga14f6502e045 (root@2705a206000b) (gcc version 7.3.1 20180425 [linaro-7.3-2018.05 revision d29120a424ecfbc167ef90065c0eeb7f91977701] (Linaro GCC 7.3-2018.05) ) #22 SMP Tue Jul 30 10:32:28 UTC 2019
5.2.2、限制日志輸出等級(jí)
## 僅輸出error信息
root@xiaotianbsp:/# dmesg -l err
[ 2.170152] rockchip-pcie f8000000.pcie: PCIe link training gen1 timeout!
[ 2.175658] rk-vcodec ff650000.vpu_service: could not find power_model node
[ 2.180010] rk-vcodec ff660000.rkvdec: could not find power_model node
[ 2.200359] rockchip-vop ff900000.vop: missing rockchip,grf property
[ 2.201913] rockchip-vop ff8f0000.vop: missing rockchip,grf property
[ 2.203632] i2c i2c-9: of_i2c: modalias failure on /hdmi@ff940000/ports
[ 2.240381] mali ff9a0000.gpu: Failed to get regulator
[ 2.240839] mali ff9a0000.gpu: Power control initialization failed
[ 2.260317] rk_gmac-dwmac fe300000.ethernet: cannot get clock clk_mac_speed
## 同時(shí)輸出error和warning信息
root@xiaotianbsp:/# dmesg -l err,warn
[ 0.000000] rockchip_clk_register_frac_branch: could not find dclk_vop0_frac as parent of dclk_vop0, rate changes may not work
[ 0.000000] rockchip_clk_register_frac_branch: could not find dclk_vop1_frac as parent of dclk_vop1, rate changes may not work
[ 0.000000] rockchip_cpuclk_pre_rate_change: limiting alt-divider 33 to 31
[ 1.589058] thermal thermal_zone1: power_allocator: sustainable_power will be estimated
[ 1.637902] phy phy-ff770000.syscon:usb2-phy@e450.1: Failed to get VBUS supply regulator
[ 1.639962] phy phy-ff770000.syscon:usb2-phy@e460.3: Failed to get VBUS supply regulator
[ 2.170152] rockchip-pcie f8000000.pcie: PCIe link training gen1 timeout!
5.2.3缤谎、查找某條信息
root@xiaotianbsp:~# dmesg | grep rockchip-vop
[ 2.197270] rockchip-vop ff900000.vop: missing rockchip,grf property
[ 2.198853] rockchip-vop ff8f0000.vop: missing rockchip,grf property
root@xiaotianbsp:~# dmesg | grep xiaotianbsp
root@xiaotianbsp:~#
5.2.4抒倚、清空環(huán)形緩沖區(qū)信息
root@xiaotianbsp:/# dmesg -c
[ 0.000000] Booting Linux on physical CPU 0x0
[ 0.000000] Initializing cgroup subsys cpuset
[ 0.000000] Initializing cgroup subsys cpu
[ 0.000000] Initializing cgroup subsys cpuacct
...
root@xiaotianbsp:/# dmesg
root@xiaotianbsp:/#
dmesg
更多用法大家可以自行測(cè)試。
注:轉(zhuǎn)載請(qǐng)注明作者和出處坷澡。