Uart Subsystem

Reference https://www.kernel.org/doc/Documentation/serial/driver Introduction 波特率 115200,bps 每秒传输的 bit 数。 每一位 1/115200 秒,传输 1byte 需要 10 位(start, data, stop),那么每秒能传 11520byte。 115200,8n1。8:data,n:校验位不用,1:停止位。 TTY 体系中设备节点的差别 不关心终端是真实的还是虚拟的,都可以通过/dev/tty 找到当前终端。 /dev/console 内核的打印信息可以通过 cmdline 来选择打印到哪个设备。 console=ttyS0 console=tty console=ttyS0 时,/dev/console 就是 ttyS0 console=ttyN 时,/dev/console 就是/dev/ttyN console=tty 时,/dev/console 就是前台程序的虚拟终端 console=tty0 时,/dev/console 就是前台程序的虚拟终端 console 有多个取值时,使用最后一个取值来判断。 /dev/tty 和/dev/tty0 区别 /dev/tty表示当前进程的控制终端,也就是当前进程与用户交互的终端。 /dev/tty0则是当前所使用虚拟终端的一个别名 Linux 串口应用编程 https://digilander.libero.it/robang/rubrica/serial.htm struct termios options; open("/dev/ttyS1", O_RDWR | O_NOCTTY | O_NDELAY)// O_NOCTTY: 不用作控制终端 O_NDELAY: 使 I/O 变成非阻塞模式 fcntl(fd, F_SETFL, 0): //读数据时,没有数据则阻塞等待 fcntl(fd, F_SETFL, FNDELAY): //读数据时不等待,没有数据就返回 0 /* c_cflag: Control Options */ options....

2023-05-15 · 5 min

GPIO Subsystem

Kernel doc: General Purpose Input/Output (GPIO) GPIO Driver Interface Controller Drivers: gpio_chip struct gpio_chip 抽象 gpio controller。 gpiochip_add_data() or devm_gpiochip_add_data()接口用来注册 gpio controller。 gpiochip_remove()释放 gpio controller。 gpiochip_is_request()在 gpio controller driver 中用于检测某个 gpio 是否被其他 chip 占用,没占用返回 NULL,占用返回 request 时传入的 string。 GPIO electrical configuration gpio_chip 的.set_config回调用于设置: Debouncing Single-ended modes (open drain/open source) Pull up and pull down resistor enablement 这些属性可以在 dts 中指定,include/dt-bindings/gpio/gpio.h GPIO_PUSH_PULL GPIO_LINE_OPEN_SOURCE GPIO_OPEN_DRAIN … 可以设置为gpiochip_generic_config()会调用到pinctrl_gpio_set_config()-> ops->pin_config_set GPIO drivers providing IRQs gpiod_to_irq(); // 传入 gpio_desc,返回 gpio 的 irq number(软件映射的,不是 irq hw id) gpio_chip_hwgpio(); gc->to_irq(); rts_gpio_to_irq(); irq_linear_revmap(); Cascaded GPIO irqchips CHAINED CASCADED GPIO IRQCHIPS:挺多 soc 上是这种做法, 打开CONFIG_GPIOLIB_IRQCHIP设置 girq->parent_handler。 gpio controller 注册过程中通过irq_set_chained_handler设置中断处理函数, 因此在中断处理函数中需要 chained_irq_enter,chained_irq_exit。 相当于级联中断处理器的做法。 static irqreturn_t foo_gpio_irq(int irq, void *data) /// 中断处理函数 chained_irq_enter(....

2023-05-12 · 2 min

CMA&DMA

Reserved-memory 参考:http://www.wowotech.net/memory_management/cma.html https://xilinx-wiki.atlassian.net/wiki/spaces/A/pages/18841683/Linux+Reserved+Memory?view=blog /Documentation/devicetree/bindings/reserved-memory/reserved-memory.txt 定义了 no-map 属性的,不会自动映射到虚拟地址,需要自行在 driver 中映射。 // dts reserved: buffer@0x38000000 { no-map; reg = <0x38000000 0x08000000>; }; /* Get reserved memory region from Device-tree */ np = of_parse_phandle(dev->of_node, "memory-region", 0); rc = of_address_to_resource(np, 0, &r); lp->paddr = r.start; lp->vaddr = memremap(r.start, resource_size(&r), MEMREMAP_WB); 定义"shared-dma-pool" 就可以创建 DMA memory pool,使用 DMA engine API 了。of_reserved_mem_device_init 中会帮我们创建映射。(DMA 在 of_reserved_mem_device_init 阶段会进行 memremap 同上,这个 remap 不是直接映射的方式)。 // dts reserved: buffer@0 { compatible = "shared-dma-pool"; no-map; reg = <0x0 0x70000000 0x0 0x10000000>; }; /* Initialize reserved memory resources */ rc = of_reserved_mem_device_init(dev); /* Allocate memory */ dma_set_coherent_mask(dev, 0xFFFFFFFF); lp->vaddr = dma_alloc_coherent(dev, ALLOC_SIZE, &lp->paddr, GFP_KERNEL); log:...

2023-05-10 · 4 min

Pinctrl Subsystem

Consumer APIs: bool pinctrl_gpio_can_use_line(unsigned gpio); int pinctrl_gpio_request(unsigned gpio); void pinctrl_gpio_free(unsigned gpio); int pinctrl_gpio_direction_input(unsigned gpio); int pinctrl_gpio_direction_output(unsigned gpio); int pinctrl_gpio_set_config(unsigned gpio, unsigned long config); pinctrl_gpio_can_use_line: 如果 dts 没有定义 gpio-ranges-group-names, 将 gpio index 映射到 pin index, 总是返回 true。\ 统一驱动设备模型会处理 pin control: platform_driver_register() driver_register(); bus_add_driver(); driver_attach(); __driver_attach(); device_driver_attach(drv, dev); driver_probe_device(drv, dev); really_probe(dev, drv); really_probe(struct device *dev, struct device_driver *drv) pinctrl_bind_pins(dev); devm_pinctrl_get(dev); pinctrl_lookup_state(dev->pins->p, PINCTRL_STATE_DEFAULT); pinctrl_lookup_state(dev->pins->p, PINCTRL_STATE_INIT); pinctrl_select_state(dev->pins->p, dev->pins->default_state); Provider Debug files /sys/kernel/debug/pinctrl Reference https://docs.kernel.org/driver-api/pin-control.html

2023-05-10 · 1 min

GDB

Stepping step(s)/stepi(si) + <n>: 执行 n 行 c/assembly 代码, 会跳进函数。 next(n)/nexti(ni) + <n>: 执行 n 行 c/assembly 代码,不会跳进函数。 Running run/r: run code 直到遇到 breakpoint。程序跑完接着 run 会 restart 程序。 continue/c: 继续执行。 finish: run code 直到当前函数 return。 advance <location>: run code 直到指令到达。和设置 breakpoint 然后 Breakpoints break <location>: 设置断点,location 可以是内存地址"*0x7c00"或者名称"mon_backtrace", "monitor.c:71" break <location> if <condition>: 只有 condition 满足的时候才会 break。 cond <number> <condition>: 给某个断点增加 condition。 info breakpoints/b: 查看断点 delete <n>: 删除编号为 n 的断点 Watchpoints watch <expression>: 表达式值发生改变时,会停止执行指令。...

2023-05-08 · 2 min

Time Subsystem

CONFIG_GENERIC_CLOCKEVENTS:新的时间子系统 以下选项三选一: CONFIG_HZ_PERIODIC:无论何时,都启用用周期性的tick,即便是在系统idle的时候。 CONFIG_NO_HZ_IDLE:在系统idle的时候,停掉周期性tick。会同时enable NO_HZ_COMMON。 CONFIG_NO_HZ_FULL:即便在非idle的状态下,也就是说cpu上还运行在task,也可能会停掉tick。会同时enable NO_HZ_COMMON。 CONFIG_HIGH_RES_TIMERS:高精度timer。 如果配置了高精度timer,或者配置了NO_HZ_COMMON的选项,那么一定需要配置CONFIG_TICK_ONESHOT,表示系统支持支持one-shot类型的tick device。 sysfs接口 cd /sys/bus/clocksource/devices/clocksource0 cat current_clocksource: 查看当前的clocksource cat available_clocksource: 查看可用的clocksource echo xxx > current_clocksource: 设置clocksource cd /sys/bus/clockevents/devices/clockevent0 cat current_device: 查看当前的clockevent Clocksource Clockevent

2023-05-08 · 1 min

Interrupt Subsystem

IRQ domain http://www.wowotech.net/linux_kenrel/irq-domain.html 1. 向系统注册 irq domain interrupt controller 初始化的过程中,注册 irq domain irq_domain_add_linear(struct device_node *of_node, unsigned int size, const struct irq_domain_ops *ops, void *host_data) 2. 为 irq domain 创建映射 在各个硬件外设的驱动初始化过程中,创建 HW interrupt ID 和 IRQ number 的映射关系。 方法 1:irq_create_mapping(struct irq_domain *host, irq_hw_number_t hwirq); 比如drivers/clocksource/timer-riscv.c中irq_create_mapping(domain, RV_IRQ_TIMER);直接将 hw id(RV_IRQ_TIMER)传入, 创建 hw id 和 irq number 的映射。 irq_create_mapping(domain, hwirq); irq_create_mapping_affinity(); irq_domain_alloc_descs(); // 创建hw id和irq number的映射 irq_domain_associate(); domain->ops->map(); //调用到interrupt controller的map函数 方法 2:irq_of_parse_and_map. 需要在设备树中指定 hw id。...

2023-05-08 · 3 min

U-Boot启动流程

Uboot编译流程 https://blog.csdn.net/ooonebook/article/details/53000893 编译生成的文件: 具体可以参考Uboot Makefile u-boot Makefile u-boot.cfg: $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.autoconf $(@) cfg: u-boot.cfg prepare2: prepare3 outputmakefile cfg prepare1: prepare2$(version_h) $(timestamp_h) $(dt_h) $(env_h) include/config/auto.conf archprepare: prepare1 scripts_basic prepare0: archprepare prepare:prepare0 scripts: scripts_basic scripts_dtc include/config/auto.conf $(u-boot-dirs): prepare scripts $(sort $(u-boot-init) $(u-boot-main)): $(u-boot-dirs) u-boot-init := $(head-y) u-boot-main := $(libs-y) u-boot-keep-syms-lto := keep-syms-lto.o u-boot.lds: $(LDSCRIPT) prepare u-boot: $(u-boot-init) $(u-boot-main) $(u-boot-keep-syms-lto) u-boot.lds u-boot-dtb.bin: u-boot-nodtb.bin dts/dt.dtb u-boot-nodtb.bin: u-boot dts/dt.dtb: u-boot u-boot.srec: u-boot u-boot.bin: u-boot-dtb.bin u-boot.sym: u-boot System....

2023-04-19 · 4 min

I2C Subsystem

用户层测试指令 # 检测当前系统有几组i2c总线 i2cdetect -l # 查看i2c-0接口上的设备 i2cdetect -y -a 0 # Force scanning of non-regular addresses i2cdetect -y -r 0 # 读取指定设备的全部寄存器的值 i2cdump -f -y 0 0x68 # 读取指定i2c设备的某个寄存器的值,如下读取i2c-0地址为0x68器件中的0x01寄存器 i2cget -f -y 0 0x68 0x01 # 写入指定i2c设备的某个寄存器的值,如下写入i2c-0地址为0x68器件中的0x01寄存器值为0x6f i2cset -f -y 0 0x68 0x01 0x6f # 写入i2c-0地址为0x50的eeprom,从偏移为0x64地址读8个byte。 i2ctransfer -f -y 0 w1@0x50 0x64 r8 I2C 基础知识 写操作 主芯片要发出一个start信号 然后发出一个设备地址(用来确定是往哪一个芯片写数据),方向(读/写,0表示写,1表示读) 从设备回应(用来确定这个设备是否存在),然后就可以传输数据 主设备发送一个字节数据给从设备,并等待回应 每传输一字节数据,接收方要有一个回应信号(确定数据是否接受完成),然后再传输下一个数据。 数据发送完之后,主芯片就会发送一个停止信号。 下图:白色背景表示"主→从",灰色背景表示"从→主" 读操作 I2C信号 I2C协议中数据传输的单位是字节,也就是8位。但是要用到9个时钟:前面8个时钟用来传输8数据,第9个时钟用来传输回应信号。传输时,先传输最高位(MSB)。 开始信号(S):SCL为高电平时,SDA山高电平向低电平跳变,开始传送数据。 结束信号(P):SCL为高电平时,SDA由低电平向高电平跳变,结束传送数据。 响应信号(ACK):接收器在接收到8位数据后,在第9个时钟周期,拉低SDA SDA上传输的数据必须在SCL为高电平期间保持稳定,SDA上的数据只能在SCL为低电平期间变化 I2C协议信号如下:...

2023-04-13 · 4 min

Buildroot

Buildroot User Manual https://buildroot.org/downloads/manual/manual.html https://www.cnblogs.com/fuzidage/p/12049442.html Chapter 4 Buildroot quick start make menuconfig make make menuconfig 进入选择菜单,可以选择编译 kernel, bootloader, rootfs。 编译完成后内容会放到output目录下,其中: image: 包括 kernel image, bootloader and root filesystem images build: host: staging: 软链接,指向/host/<toolchain>/sysroot target: 就是目标板的文件系统,和 staging 相比,developing files(header, etc.)被省略了,binaries are stripped, 去除了 debug info。 PARTⅡ User Guide Chapter 6 Buildroot configuration 6.1 Cross-compilation toolchain Buildroot 提供两种 toolchain: internal toolchain backend, Buildroot toolchain in menuconfig. external toolchain backend. External toolchain in menuconfig....

2023-04-13 · 10 min