又见炊烟升起

导航

=嵌入式开发中的一句话备忘 - 嵌入式linux(非安卓)

>uboot

//uboot编译时,help帮助为了详细,需要把单板配置头文件(比如include/configs/imx8qm_mek_android_auto.h)的这个配置 不要 #undef:
#undef CONFIG_SYS_LONGHELP

嵌入式linux

//cmdline的配置 如

console=hvc0  vmalloc=400M  DFTC_IVI_CONFIG=01_0x2000000000000000 DFTC_IC_CONFIG=01_0x2000000000000000

可以通过__setup 来获取,类似M57项目的如下:

  __setup("DFTC_IVI_CONFIG=",  guest_get_ivi_config);

//从对方IP地址接收文件
tftp -gr 文件名 对方IP地址

//向对方IP地址发送文件
tftp -pr 文件名 对方IP地址
//常用添加打印:
printk("nisy_%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
查询内核打印的配置:
cat /proc/sys/kernel/printk
关闭打印:
echo 0 > /proc/sys/kernel/printk
打开所有打印:
echo 8 > /proc/sys/kernel/printk
//查看运行中Linux的内核配置选项
zcat /proc/config.gz
需要开启内核配置项CONFIG_IKCONFIG才会生成这个文件
//强制关闭串口打印:
echo 0 > /proc/sys/kernel/printk
//DTC除了可以编译.dts文件以外,其实也可以“反汇编”.dtb文件为.dts文件,其指令格式为:
dtc -I dtb -O dts -o xxx.dts arch/arm/boot/dts/xxx.dtb
用这种方式把树莓派的设备树“还原”出来。

//Linux kernal的文档使用rst结构化文本编写,阅读kernal\msm-4.1.4\README文档可知,可以通过

make htmldocs

生成可读的html,不过也可以直接在
https://www.kernel.org/doc/html/latest/index.html#
就能搜索。
//打印编译fail的某个.c文件的完整编译命令,内核原始makefile有v=1来开启,也可以在直接篡改一下:
原始:

# Use 'make V=1' to see the full commands

ifeq ("$(origin V)", "command line")
  KBUILD_VERBOSE = $(V)
endif
ifndef KBUILD_VERBOSE
  KBUILD_VERBOSE = 0
endif

修改后:

# Use 'make V=1' to see the full commands

ifeq ("$(origin V)", "command line")
  KBUILD_VERBOSE = 1
endif
ifndef KBUILD_VERBOSE
  KBUILD_VERBOSE = 1
endif

// 对于某些定位问题的时候需要时间戳,可以使用 ts命令 在每一行行首增加了时间戳。下面给出另一个例子:

$ ls -l | ts
Aug 21 13:34:25 total 120
Aug 21 13:34:25 drwxr-xr-x 2 sk users 12288 Aug 20 20:05 Desktop
Aug 21 13:34:25 drwxr-xr-x 2 sk users 4096 Aug 10 18:44 Documents
Aug 21 13:34:25 drwxr-xr-x 24 sk users 12288 Aug 21 13:06 Downloads
[...]

--- 来自文章 (https://linux.cn/article-9962-1.html 《一套有用的 Unix 实用程序 》)
类似地,可以用sudo execsnoop |ts
来记录函数调用的时间戳。
//
Q:linux下有多套gcc版本,如何手工切换需要的版本?
A:使用 update-alternatives 选择某个版本的gcc:
往系统添加一个 arm-linux-guneabi-gcc-5 的链接配置并设置优先级。

$ sudo update-alternatives --install /usr/bin/arm-linux-gnueabi-gcc arm-linux-gnueabi-gcc /usr/bin/arm-linux-gnueabi-gcc-5 5

接下来往系统添加一个 arm-linux-guneabi-gcc-7 的链接配置并设置优先级。

$ sudo update-alternatives --install /usr/bin/arm-linux-gnueabi-gcc arm-linux-gnueabi-gcc /usr/bin/arm-linux-gnueabi-gcc-7 7

使用 update-alternatives 命令来选择一个配置。

$ sudo update-alternatives --config arm-linux-gnueabi-gcc

然后可以看到arm-linux-gnueabi-gcc 指向的是/etc/alternatives/ 的一个自己选择的版本号的gcc

ls -al /usr/bin/arm-linux-gnueabi-gcc
lrwxrwxrwx 1 root root 39 7月 13 2020 /usr/bin/arm-linux-gnueabi-gcc -> /etc/alternatives/arm-linux-gnueabi-gcc-5

//i2ctools软件中的工具 i2ctransfer 和 i2cdump 都可以读芯片的寄存器,命令稍不同,如下:
注意i2cdetect 扫描到只是说明设备树中有这个设备,实际可能这个芯片根本没有贴片.

# i2cdetect -y -a 9
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- 2c -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- 41 42 43 44 45 -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- UU -- -- -- -- --
70: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --

可以看到bus=9下面有6a,41~45,2c这几个i2c设备.

i2cdump -f -y 9 0x6a
No size specified (using byte-data access)
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f    0123456789abcdef
00: ef 00 00 01 00 00 90 51 2d d4 ff e4 91 f3 50 0b    ?..?..?Q-?.???P?
10: 00 00 f3 0f e4 9b 00 01 00 00 60 00 f4 ff 40 02    ..????.?..`.?.@?
20: 55 00 0f 00 00 00 00 bf 00 00 00 00 00 00 00 00    U.?....?........
30: fa 45 99 99 b6 00 00 00 00 00 00 2e 24 54 c8 22    ?E???.......$T?"
40: 5a 10 00 a0 00 00 55 ff ef 0f ff 00 00 00 05 00    Z?.?..U.??....?.
50: 00 00 05 00 00 00 05 00 00 00 05 90 51 2d 00 00    ..?...?...??Q-..
60: 45 ff 1f 00 00 12 96 00 50 b0 00 00 00 00 00 00    E.?..??.P?......
70: f0 3f 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ??..............
80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
mek_8q_raite:/ #
mek_8q_raite:/ #
mek_8q_raite:/ # i2ctransfer -f -y 9 w1@0x6a 0x0 r2
0xef 0x00
mek_8q_raite:/ # 
mek_8q_raite:/ # i2ctransfer -f -y 9 w1@0x6a 0x2 r2
0x00 0x01
mek_8q_raite:/ # i2ctransfer -f -y 9 w1@0x6a 0x4 r2
0x00 0x00
mek_8q_raite:/ # i2ctransfer -f -y 9 w1@0x6a 0x6 r2
0x90 0x51
mek_8q_raite:/ # i2ctransfer -f -y 9 w1@0x6a 0x8 r2
0x2d 0xd4
mek_8q_raite:/ # 
mek_8q_raite:/ #
mek_8q_raite:/ # i2ctransfer -f -y 9 w1@0x6a 0x0 r16
0xef 0x00 0x00 0x01 0x00 0x00 0x90 0x51 0x2d 0xd4 0xff 0xe4 0x91 0xf3 0x50 0x0b


1|mek_8q_raite:/ # i2cget -f -y 9 0x6a 0   //读寄存器0#
0xef
mek_8q_raite:/ # i2cget -f -y 9 0x6a 1   //读寄存器1#
0x00
mek_8q_raite:/ # i2cset -f -y 9 0x6a 1 4   //写寄存器1#
mek_8q_raite:/ # i2cget -f -y 9 0x6a 1   //读寄存器1#
0x04

注意:i2cdump/i2cget 读寄存器只能输入1byte地址,返回1到多字节结果;如果需要输入地址为2byte,则只能使用 i2ctransfer ,比如读max96722的ID寄存器:

console:/ # i2ctransfer -f -y 2 w2@0x29 0x00 0x0d r1 (输入地址2byte=0x000d,返回值1byte)
0xa1 //正确返回,地址为0x000d

console:/ # i2cget -f -y 2 0x29 0x0d
0x00 //错误返回,地址当做0x0d

//从i2c 4号总线0x38设备的0x3a01寄存器开始读16个字节的数据,w2:表示寄存器0x3a01的长度为2个字节
i2ctransfer -y -f 4 w2@0x38 0x3a 0x01 r16
向i2c 4号总线0x38设备的0x3a01寄存器写0x10,w3:表示寄存器0x3a01和写入值0x10的长度为3字节
i2ctransfer -y -f 4 w3@0x38 0x3a 0x01 0x10
//截屏: 截取fb1界面到sdcard,文件名为fb1.png
screencap -d /dev/graphics/fb1 sdcard/fb1.png

//使用文件系统节点来操作时,需要注意有可能设备树的修改导致节点路径变更了,比如:
原始:
/sys/devices/platform/58226000.i2c/i2c-9/9-006a/max9286_reset
删除了i2c 一个bus后,变成
/sys/devices/platform/58226000.i2c/i2c-8/8-006a/max9286_reset
可能造成上层找不到文件节点,导致功能异常.
上层使用节点,最好使用find 先搜到节点路径,用搜索结果再去操作.

//python循环打印max96722(bus2,addr=0x29)的寄存器的值:

import os
import time

a=0
os.system('adb root')
os.system('adb remount')    

s_hex=""

while a < 255:
    b='adb shell i2ctransfer -f -y 2 w2@0x29 0x00 '
    b += s_hex + hex(a)
    b +=' r1'
    os.system(b)
    a+=1

//dos的命令每隔5秒周期性操作adb shell "factory_test -s fan_switch on" 的参考脚本:

@echo off
adb root
for /l %%i in (1,0,1) do adb shell "factory_test -s fan_switch on" &&choice /T 1 /C ync /CS /D y /n
pause

//打印结构体的内容,使用 print_hex_dump(),类似:

    print_hex_dump(KERN_NOTICE,"" ,DUMP_PREFIX_OFFSET ,16,1,sd,sizeof(struct v4l2_subdev),true);      

//CPU异常占用分析:

  • 使用 top -H -p pid号 确认当前进程所有线程CPU占用
  • 使用 ps -AT -O psr | grep cpu占用异常pid 确认线程状态以及所运行的cpu

//如果下电/上电正常,但是reboot不正常,请检查芯片的上电流程的下电部分,是否时间太少.

skill

打印函数执行时间

举例:

int vb2_ioctl_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
{
   struct video_device *vdev = video_devdata(file);
    int val = 0;

#ifdef FEATURE_DONGFENG_DEBUG
    u64 start_time, end_time ;
    u64 diff = 0;
    
    start_time = ktime_get_real_ns();
    udelay(10); //延时10us,因为2次调用ktime_get_real_ns()有可能因为调度或者中断,导致后一次的值反而小,所以这里人为在第一次取时间戳后加一个短延时
#endif

   if (vb2_queue_is_busy(vdev, file))
   {
        return -EBUSY;
   }
    
   val = vb2_dqbuf(vdev->queue, p, file->f_flags & O_NONBLOCK);

#ifdef FEATURE_DONGFENG_DEBUG
    {
        end_time = ktime_get_real_ns();
        diff = end_time - start_time;
        diff =(u32) diff /(u32) 1000UL;
    }
    if(diff > 30000)
    {
        printk("df_dqbuf:%c-%llu us\n",vdev->name[8] , diff);
    }
#endif
   return val;
}

visual studio code 中过滤内核代码的无关部分

比如 kernel-4.14.code-workspace 文件:

{
	"folders": [
		{
			"path": "."
		}
	],
	"settings": {
		"search.exclude": {
			"arch/alpha"      :true,
			"arch/m68k"      :true,
			"arch/arc"      :true,
			"arch/arm"      :true,
			"arch/blackfin"      :true,
			"arch/c6x"      :true,
			"arch/cris"      :true,
			"arch/frv"      :true,
			"arch/h8300"      :true,
			"arch/hexagon"      :true,
			"arch/ia64"      :true,
			"arch/m32r"      :true,
			"arch/metag"      :true,
			"arch/microblaze"      :true,
			"arch/mn10300"      :true,
			"arch/nios2"      :true,
			"arch/mips"      :true,
			"arch/openrisc"      :true,
			"arch/parisc"      :true,
			"arch/powerpc"      :true,
			"arch/s390"      :true,
			"arch/score"      :true,
			"arch/sh"      :true,
			"arch/sparc"      :true,
			"arch/tile"      :true,
			"arch/um"      :true,
			"arch/unicore32"      :true,
			"arch/x86"      :true,
			"arch/xtensa"      :true,
            "arch/arm64/boot/dts/actions"      :true,
            "arch/arm64/boot/dts/allwinner"      :true,
            "arch/arm64/boot/dts/amd"      :true,
            "arch/arm64/boot/dts/apm"      :true,
            "arch/arm64/boot/dts/broadcom"      :true,
            "arch/arm64/boot/dts/exynos"      :true,
            "arch/arm64/boot/dts/hisilicon"      :true,
            "arch/arm64/boot/dts/qcom"      :true,
            "arch/arm64/boot/dts/renesas"      :true,
            "arch/arm64/boot/dts/socionext"      :true,
            "arch/arm64/boot/dts/xilinx"      :true,
            "arch/arm64/boot/dts/al"      :true,
            "arch/arm64/boot/dts/altera"      :true,
            "arch/arm64/boot/dts/amlogic"      :true,
            "arch/arm64/boot/dts/arm"      :true,
            "arch/arm64/boot/dts/cavium"      :true,
            "arch/arm64/boot/dts/freescale"      :true,
            "arch/arm64/boot/dts/lg"      :true,
            "arch/arm64/boot/dts/marvell"      :true,
            "arch/arm64/boot/dts/nvidia"      :true,
            "arch/arm64/boot/dts/realtek"      :true,
            "arch/arm64/boot/dts/rockchip"      :true,
		},
		"files.exclude": {
			"arch/alpha"      :true,
			"arch/m68k"      :true,
			"arch/arc"      :true,
			"arch/arm"      :true,
			"arch/blackfin"      :true,
			"arch/c6x"      :true,
			"arch/cris"      :true,
			"arch/frv"      :true,
			"arch/h8300"      :true,
			"arch/hexagon"      :true,
			"arch/ia64"      :true,
			"arch/m32r"      :true,
			"arch/metag"      :true,
			"arch/microblaze"      :true,
			"arch/mn10300"      :true,
			"arch/nios2"      :true,
			"arch/mips"      :true,
			"arch/openrisc"      :true,
			"arch/parisc"      :true,
			"arch/powerpc"      :true,
			"arch/s390"      :true,
			"arch/score"      :true,
			"arch/sh"      :true,
			"arch/sparc"      :true,
			"arch/tile"      :true,
			"arch/um"      :true,
			"arch/unicore32"      :true,
			"arch/x86"      :true,
			"arch/xtensa"      :true,
            "arch/arm64/boot/dts/actions"      :true,
            "arch/arm64/boot/dts/allwinner"      :true,
            "arch/arm64/boot/dts/amd"      :true,
            "arch/arm64/boot/dts/apm"      :true,
            "arch/arm64/boot/dts/broadcom"      :true,
            "arch/arm64/boot/dts/exynos"      :true,
            "arch/arm64/boot/dts/hisilicon"      :true,
            "arch/arm64/boot/dts/qcom"      :true,
            "arch/arm64/boot/dts/renesas"      :true,
            "arch/arm64/boot/dts/socionext"      :true,
            "arch/arm64/boot/dts/xilinx"      :true,
            "arch/arm64/boot/dts/al"      :true,
            "arch/arm64/boot/dts/altera"      :true,
            "arch/arm64/boot/dts/amlogic"      :true,
            "arch/arm64/boot/dts/arm"      :true,
            "arch/arm64/boot/dts/cavium"      :true,
            "arch/arm64/boot/dts/freescale"      :true,
            "arch/arm64/boot/dts/lg"      :true,
		}
	}
}

//在Linux系统内部,可以通过查看配置文档来获取内核编译的开关信息。这些配置文档通常位于/boot/config-$(uname -r)或/proc/config.gz。

  1. cat /boot/config-$(uname -r)命令可以查看当前正在运行的内核配置。
  2. zcat /proc/config.gz命令可以查看压缩的内核配置文档。请注意,在内核编译时增减相应的选项才会生成该文档,因此如果系统中没有该文档,可能无法获取内核编译的开关信息。

posted on 2021-07-18 10:18  ni_sy  阅读(69)  评论(0编辑  收藏  举报