Linux启动流程
固化代码启动,根据指定引脚的电平,确认从emmc或SD卡启动
拷贝uboot到内存中
uboot初始化始终、内存、网络等
根据cmdline,加载启动kernel,加载驱动模块
加载rootfs到内存
启动应用
uboot
命令:printenv、setenv、saveenv
参数:bootargs、cmdline、ip等,可直接修改代码
启动:tftpboot 0xXXXXX uImage直接下载到内存;fastboot flash XXX 下载到emmc,再从emmc加载到内存
kernel
.config文件
make menuconfig图形化配置(修改.config的CONFIG-XXX)
内核添加菜单选项Kconfig、Makefile
uImage = zImage + dtb
编译:make uImage
设备树
arch/arm/boot/dts
查看treedevices/bingding下的说明实例
#include文件
子节点:标签:name@地址
引用:追加属性
常用属性:compatible、address、reg、status
属性值:string、
查找属性:of_find_node_by_XXX
获取属性:of_operation_read_string
pintrl子系统:引脚、电气属性
编译:make dtb
驱动
模块加载:module_init
模块卸载:module_exit
__init、__exit:放到代码段
命令:insmod、rmmode、modprobe(自动添加依赖)
模块传参:module_param
模块导出方法:EXPORT_SYMBOL
字符设备
注册:
自动申请设备号:alloc_chrdev_region
手动:MKDEV、register_region
初始化:cdev_init
添加到内核:cdev_add
申请设备节点:class_create、device_create
释放:
device_destroy
class_destroy
cdev_del
unregister_chrdev_region
实现file_operation:owner、open/release、read/write
查看:cat /proc/devices、cat /dev/XXX
设备总线
设备和驱动分离,设备和驱动挂载到总线,通过匹配拿到信息
platform_get_resource
device:
platform_device
注册platform_device_register
bus_add_driver
driver_attach
匹配platcform_match:先和设备树匹配,不行再和id_table
绑定driver_probe_device
driver:
platform_driver
注册platform_driver_register
platform_device_add
device_add
device_attach
匹配platcform_match:先和设备树匹配,不行再和id_table
绑定driver_probe_device
gpio:gpio_request、gpio_free
中断:request_irq、free_irq
中断处理下半部:处理耗时操作,使用tasklet或workqueue,在上半部中调用task_schedule或schedule_work
定时器
竞争:互斥锁mutex、自旋锁spin、原子操作atomic
总线
UART:同步串行,1帧1字节
I2C:同步半双工,从器件地址,寄存器地址、方向,i2cdetect、i2cget、i2cget,一个总线一个adapter
SPI:同步全双工
CAN:CANID 仲裁
实战
1.修改设备树
pintrl配置时钟/数据/使能/片选/中断线
配置寄存器、中断号、PWM、时钟、屏参等
2.内核开启外设驱动、开启总线
EMMC:SDIO(8条数据线);总线:i2C;内核:SDMMC Controller
LCD:设备树:bitwidth(RGB565、RGB888)、背光(开启PWM、时钟)、修改水平像素/垂直像素等屏参;内核:LCDC(输出RGB信号)
HDMI:芯片sii9022将RGB信号转成HDMI信号;总线:i2c
触摸:中断/复位引脚;总线:i2c;内核:GT911、input子系统
音频:总线:i2c/sai;内核:cs42l51
蓝牙:总线:UART;内核:AP6236
WIFI:总线:SDIO;
CAN:内核开启CAN总线,socket