uboot读取adc,通过cmdline传给kernel解析数值,不同硬件模块进行处理

uboot读取adc,通过cmdline传给kernel解析数值,不同硬件模块进行处理

  1. uboot开发,要想读取adc在哪个时间点读取以及如何传给cmdline,需要清楚2点,
    1. uboot启动得大致流程及相关启动功能,uboot各个硬件模块得接口,
    2. cmdline如何去设置

uboo开发具体如下:

1.uboot启动流程:

start.s

// 汇编环境

=> IRQ/FIQ/lowlevel/vbar/errata/cp15/gic // ARM架构相关的lowlevel初始化

=> _main

=> stack // 准备好C环境需要的栈

// 【第一阶段】C环境初始化,发起一系列的函数调用

=> board_init_f: init_sequence_f[]

initf_malloc

arch_cpu_init // 【SoC的lowlevel初始化】

serial_init // 串口初始化

dram_init // 【获取ddr容量信息】

reserve_mmu // 从ddr末尾开始往低地址reserve内存

reserve_video

reserve_uboot内存布局

U-Boot 由前级 Loader 加载到 CONFIG_SYS_TEXT_BASE 地址,初始化时会探明当前系统的总内存容

量,32位平台上认为最大4GB可用(但是不影响内核对容量的识别),64位平台上认为所有内存都可

用。然后通过一系列reserve_xxx() 接口从内存末尾往前预留需要的内存,最后把自己relocate到某段

reserve的空间上。内存整体使用布局如下,以ARM64为例(常规情况):

reserve_malloc

reserve_global_data

reserve_fdt

reserve_stacks

dram_init_banksize

sysmem_init

setup_reloc // 确定U-Boot自身要reloc的地址

// 汇编环境

=> relocate_code // 汇编实现U-Boot代码的relocation

// 【第二阶段】C环境初始化,发起一系列的函数调用

=> board_init_r: init_sequence_r[]

initr_caches // 使能MMU和I/Dcache

initr_malloc

bidram_initr

sysmem_initr

initr_of_live // 初始化of_live

initr_dm // 初始化dm框架

board_init // 【平台初始化,最核心部分】

board_debug_uart_init // 串口iomux、clk配置

init_kernel_dtb // 【切到kernel dtb】!

clks_probe // 初始化系统频率

regulators_enable_boot_on // 初始化系统电源

io_domain_init // io-domain初始化

set_armclk_rate // __weak,ARM提频(平台有需求才实现)

dvfs_init // 宽温芯片的调频调压

rk_board_init // __weak,由各个具体平台进行实现

console_init_r

board_late_init // 【平台late初始化】

rockchip_set_ethaddr // 设置mac地址

rockchip_set_serialno // 设置serialno

setup_boot_mode // 解析"reboot xxx"命令、

// 识别按键和loader烧写模式、

recovery

charge_display // U-Boot充电

rockchip_show_logo // 显示开机logo

soc_clk_dump // 打印clk tree

rk_board_late_init // __weak,由各个具体平台进行实现

run_main_loop // 【进入命令行模式,或执行启动命令】

2.通过流程知道,我们大概是要在哪里去加这个adc读取及设置cmdline。起码不能再adc驱动接口之前去处理,我们放在board_init里,追一下代码流程即可

这里我在这里添加如下:

u-boot/common/android_bootloader.c

android_get_dtbo函数(因为这个函数里有处理第一个cmdline字符串),具体debug追代码即可

uboot读取adc,通过cmdline传给kernel解析数值,不同硬件模块进行处理_第1张图片

3.知道在哪里添加接口及设置cmdline,我们需要知道如何获取到adc得值,uboot中有封装了寄存器接口,我们之间调接口即可

当然提前得分析驱动及找到相关接口:

首先得知道uboot2017已经实现了kernel同理设备配合驱动得架构

DM (Driver Model) 是 U-Boot 标准的 device-driver 开发模型,跟 kernel 的 device-driver 模型非常类似。v2017版本也遵循 DM 框架开发各功能模块。建议读者先阅读DM文档,了解DM架构原理和实现。

查看./doc/driver-model/README.txt说明

Terminology

-----------

Uclass - a group of devices which operate in the same way. A uclass provides

a way of accessing individual devices within the group, but always

using the same interface. For example a GPIO uclass provides

operations for get/set value. An I2C uclass may have 10 I2C ports,

4 with one driver, and 6 with another.

Driver - some code which talks to a peripheral and presents a higher-level

interface to it.

Device - an instance of a driver, tied to a particular port or peripheral.

简要概括:

uclass:设备驱动模型

driver: 驱动

device:设备

这个时候我们可以去查看dts,找到saradc的硬件定义,然后去找到相关驱动,这里不细说,驱动路径:

u-boot/drivers/adc

uboot读取adc,通过cmdline传给kernel解析数值,不同硬件模块进行处理_第2张图片

查看相关代码即可分析出,我们要获取adc值得接口。

uboot读取adc,通过cmdline传给kernel解析数值,不同硬件模块进行处理_第3张图片

具体使用,传参,你可以搜索是否有样例,也可以分析源码。

4.cmdline如何更新及生效。百度即可知道使用 env_update接口。使用得顺序就是你上传字符串先后得顺序

二、kernel解析cmdline

关于kernel解析,我踩了坑,这里详细说一下,

刚开始我想通过一些字符串得接口,自己去解析出一长串中,我需要得数据,发现会遇到很多问题。

比如:

storagemedia=emmc androidboot.storagemedia=emmc androidboot.mode=normal androidboot.dtb_idx=0 adc_val=20 androidboot.dtbo_idx=0 androidboot.verifiedbootstate=orange androidboot.serialno=11213335POT447000006 console=ttyFIQ0 firmware_class.path=/vendor/etc/firmware init=/init rootwait ro loop.max_part=7 androidboot.console=ttyFIQ0 androidboot.wificountrycode=CN androidboot.hardware=rk30board androidboot.boot_devices=fe2e0000.mmc androidboot.selinux=permissive buildvariant=userdebug earlycon=uart8250,mmio32,0xfeb50000 irqchip.gicv3_pseudo_nmi=0

我获取到这串字符按,然后解析出adc_val=20中得20,其中20是变有可能是100,有可能是1000,字符长度不定。所以很难做到。

通过查找资料,百度等,换了另一种办法通过__setup(xx,xx)去获取我上传得字符串得变量

开发如下:

1.首先kernel已经做了cmdline得解析,start_kernel中setup_arch中解析tags获取cmdline,拷贝到boot_command_line中。我们接着往下看start_kernel。

start_kernel中setup_arch中解析tags获取cmdline,拷贝到boot_command_line中。我们接着往下看start_kernel。调用setup_command_line,

将cmdline拷贝2份,放在saved_command_line static_command_line。

总结下kernel的参数解析:

(1)kernel编译链接,利用.__param .init.setup段将kernel所需参数(driver及通用)和对应处理函数的映射表(obs_kernel_param  kernel_param结构体)存放起来。

(2)Kernel启动,do_early_param处理kernel早期使用的参数(如earlyprintk earlycon)

(3)parse_args对cmdline每个参数都遍历__param .init.setup进行匹配,匹配成功,则调用对应处理函数进行参数值的解析和设置。

总结来说,内核有解析cmdline得源码,它解析出来得数据会存在一个地方,而且cmdline整个字符串,也存在了一个全局指针里。

对于各个内核驱动模块来说,我们可以拿这个全局指针获取到cmdline,然后去解析出你自己需要得字符串数据,又或者是之间使用__setup,

这里我们使用(3)得方法,写一个函数,之间获取到相应字符串得数据,如下:

uboot读取adc,通过cmdline传给kernel解析数值,不同硬件模块进行处理_第4张图片

这样我们就可以再各个内核模块中获取到adc值,进而去判断硬件版本,然后去设置相应得功能

三、在设置不同功能的时候,又会遇到很多坑,涉及到dts得处理。所以最好是能存几份dts,然后根据adc去判断取那份dts,在接下来得文档里说明

你可能感兴趣的:(单片机,c语言,嵌入式硬件)