软件开发指导 ============= 源码编译 --------- 编译环境要求 ~~~~~~~~~~~~~ 1. 编译主机需在ubuntu系统中进行,且版本需Ubuntu 20.04以上,笔者主机系统为Ubuntu 20.04 2. 主机需可连接外网,因为编译系统过程需要下载某些文件。 下载源码包 ~~~~~~~~~~~ 1. 下载rk3506源码包,路径为:3.软件资料-->3.1源码-->rk3506-buildroot-20250606.tar.xz 2. 创建编译目录: .. code-block:: shell mkdir -p ~/my-work/RK3506/02_sources/ 3. 把源码放到刚创建的目录中,并进行解压: .. code-block:: shell tar xvf rk3506-buildroot-20250606.tar.xz -C ~/my-work/RK3506/02_sources/ 依赖安装 ~~~~~~~~~ | 首次编译可能需要安装某些依赖,下面给出主机可能需要安装的某些依赖: .. code-block:: shell sudo dpkg --add-architecture i386 sudo apt-get install git bc bison build-essential curl flex g++-multilib gcc-multilib gnupg gperf imagemagick lib32ncurses5-dev lib32readline-dev lib32z1-dev liblz4-tool libncurses5-dev libsdl1.2-dev libssl-dev libxml2 libxml2-utils lzop pngcrush rsync schedtool squashfs-tools xsltproc yasm zip \ zlib1g-dev device-tree-compiler expect g++ patchelf gawk texinfo chrpath diffstat binfmt-support qemu-user-static live-build fakeroot cmake ssh make gcc g++ unzip ncurses-dev python3-pip libncurses5 libc6:i386 genext2fs \ u-boot-tools mtools parted libudev-dev libusb-1.0-0-dev autoconf autotools-dev libsigsegv2 m4 intltool libdrm-dev sed binutils wget libglib2.0-dev libgtk2.0-dev libglade2-dev cvs mercurial gcc-arm-none-eabi gcc-arm-linux-gnueabi openjdk-8-jdk subversion asciidoc w3m dblatex graphviz device-tree-compiler flex bison openssl libssl-dev unzip git-lfs ccache libelf-dev default-jdk mtd-utils scons SDK配置加载 ~~~~~~~~~~~~~ | 首次编译需要加载SDK配置文件,进入rk3506_sdk目录,输入如下命令加载配置文件: .. code-block:: shell ./build.sh buildroot-config 整体编译 ~~~~~~~~~~ 1. 运行整体编译(编译时间较长),输入如下命令: .. code-block:: shell ./build.sh 2. 编译成功后在rockdev/目录下可看到相关镜像,其中update.img是所有镜像的集合 单独编译uboot ~~~~~~~~~~~~~~~ 1. 编译前可先清除生成文件 .. code-block:: shell cd u-boot/ make clean 2. 2.回到SDK主目录,并进行uboot单独编译 .. code-block:: shell cd ../ ./build.sh uboot 单独编译Kernel ~~~~~~~~~~~~~~~ 1. 编译前可先清除生成文件 .. code-block:: shell cd kernel/ make clean 2. 回到SDK主目录,并进行kernel单独编译 .. code-block:: shell cd ../ ./build.sh kernel 单独编译recovery ~~~~~~~~~~~~~~~~~ | 在SDK主目录下输入如下命令: .. code-block:: shell ./build.sh recovery 单独编译buildroot ~~~~~~~~~~~~~~~~~~ | 在SDK主目录下输入如下命令: .. code-block:: shell ./build.sh rootfs 打包固件 ~~~~~~~~~ | 在SDK主目录下输入如下命令: .. code-block:: shell ./build.sh firmware 打包update.img ~~~~~~~~~~~~~~~~ 1. 在SDK下的output/update/Image目录里可以看到打包好的镜像update.img 2. 在SDK主目录下输入如下命令: .. code-block:: shell ./build.sh updateimg | 完成上述操作后可按照刷机手册重新刷机 | 最后提示用户应该重新刷机测试 开发指导 --------- UBOOT板级文件 ~~~~~~~~~~~~~~~ | U-boot板级文件:u-boot/board/rockchip/myzr_rk3506 | U-boot板级配置文件:include/configs/myzr_rk3506.h | U-boot板级编译配置文件:configs/myzr_rk3506_defconfig Linux内核板级文件 ~~~~~~~~~~~~~~~~~~ | 内核板级编译配置文件:kernel-6.1/arch/arm/configs/rk3506_defconfig | 内核板级设备树文件:kernel-6.1/arch/arm/boot/dts/rockchip/myzr-rk3506-\*.dts GPIO ~~~~~~ 1. 简介 | GPIO是General Purpose I/O的缩写,即通用输入输出端口,简单来说就是MCU/CPU可控制的引脚, 这些引脚通常有多种功能,最基本的是高低电平输入检测和输出,部分引脚还会与主控器的片上外设绑定, 如作为串口、I2C、网络、电压检测的通讯引脚。Linux提供了GPIO子系统驱动框架,使用该驱动框架即可灵活地控制板子上的GPIO。 2. 引脚命名规则 | RK3562的GPIO分为4组(GPIO0~GPIO3),每组又以 A0~A7, B0~B7, C0~C7, D0~D7 作为编号区分。例如 - GPIO0_C2表示第0组(GPIO0)的C组第2个引脚。 - GPIO3_B5表示第3组(GPIO3)的B组第5个引脚。 3. GPIO引脚编号的计算公式 | bank:GPIO组号(0~3)。 | group:字母对应的组内序号(A=0,B=1,C=2,D=3)。 | X:组内具体编号(0~7)。 | number:组内编号,通过以下公式计算: | GPIO 小组编号计算公式:number = group * 8 + X | GPIO pin 编号计算公式:pin = bank * 32 + number | 下面演示GPIO0_C2 pin脚计算方法: | bank = 4 (GPIO4)。 | group = 1(B组对应1)。 | X = 5 (B5的5)。 | number = group * 8 + X = 2 * 8 + 2 = 18。 | pin = bank*32 + number= 0 * 32 + 18 = 18。 4. 通过/sys/class/gpio目录控制GPIO .. code-block:: shell | 在Linux中,最常见的读写GPIO方式就是用GPIO sysfs interface, 是通过操作 /sys/class/gpio 目录下的 export 、 unexport 、gpio{N}/direction, gpio{N} /value (用实际引脚号替代{N})等文件实现的,经常出现shell脚本里面。 | echo 18 > /sys/class/gpio/export #使能引脚GPIO0_C2 | echo out > gpio18/direction # 设置引脚为输出模式 | echo 1 > gpio18/value # 设置引脚为高电平 | cat /sys/class/gpio/gpio18/value # 读取引脚的值 | echo 18 > /sys/class/gpio/unexport # 释放GPIO | 注意事项:部分GPIO无法导出可能被复用为其他功能(如UART、I2C),需通过设备树确认实际用途。 UART ~~~~~~ 1. 设备树配置 .. code-block:: shell &uart3 { status = "okay"; pinctrl-names = "default"; pinctrl-0 = <&rm_io14_uart3_tx &rm_io15_uart3_rx>; }; | pinctrl-0 = <&rm_io14_uart3_tx &rm_io15_uart3_rx>;的作用,绑定UART3的TX/RX引脚到rm_io14,15复用组。 | uart3m0_xfer在rk3506-pinctrl-rmio.dtsi中已定义: .. code-block:: shell rm_io14_uart3_tx: rm-io14-uart3-tx { rockchip,pins = <0 RK_PB6 20 &pcfg_pull_none>; }; rm_io15_uart3_rx: rm-io15-uart3-rx { rockchip,pins = <0 RK_PB7 21 &pcfg_pull_up>; }; | 设备树配置好之后,UART3在系统中注册为/dev/ttyS3,可通过ls /dev/ttyS*验证。 2. 调试工具 | 将uart3的rx tx短接,利用文件系统内放置的测试文件进行收发测试: .. code-block:: shell =====> Input: # /myzr_test/uart/serial_test.out /dev/ttyS3 "myzr" =====> Output: Starting send data...finish Starting receive data: ASCII: 0x6d Character: m ASCII: 0x79 Character: y ASCII: 0x7a Character: z ASCII: 0x72 Character: r ASCII: 0x0 Character: CAN ~~~~~~ 1. CAN 简介 | CAN(Controller Area Network)总线,即控制器局域网总线,是一种有效支持分布式控制或实时控制的串行通信网络。CAN总线是一种在汽车上广泛采用的总线协议,被设计作为汽车环境中的微控制器通讯。 如果想了解更多的内容可以参考CAN应用报告 2. DTS 节点配置 - 公共配置 kernel/arch/arm/boot/dts/rk3506.dtsi .. code-block:: shell can0: can@ff320000 { compatible = "rockchip,rk3506-canfd", "rockchip,rk3576-canfd"; reg = <0xff320000 0x1000>; interrupts = ; clocks = <&cru CLK_CAN0>, <&cru HCLK_CAN0>; clock-names = "baudclk", "apb_pclk"; resets = <&cru SRST_CAN0>, <&cru SRST_H_CAN0>; reset-names = "can", "can-apb"; status = "disabled"; }; - 板级配置 arch/arm/boot/dts/rockchip/myzr-rk3506-ek200.dts .. code-block:: shell &can0 { status = "okay"; assigned-clocks = <&cru CLK_CAN0>; assigned-clock-rates = <200000000>; pinctrl-names = "default"; pinctrl-0 = <&rm_io19_can0_tx &rm_io20_can0_rx>; }; **CAN通信测试** | 使用 candump 和 cansend 工具进行收发报文测试即可, | #在收发端关闭can0设备 | ip link set can0 down | #在收发端设置比特率为250Kbps | ip link set can0 type can bitrate 250000 dbitrate 1000000 fd on | #在收发端打开can0设备 | ip link set can0 up | #在接收端执行candump,阻塞等待报文 | candump can0 | #在发送端执行cansend,发送报文 | cansend can0 123#1122334455667788 3. 更多指令 .. code-block:: shell 1、 ip link set canX down //关闭can设备; 2、 ip link set canX up //开启can设备; 3、 ip -details link show canX //显示can设备详细信息; 4、 candump canX //接收can总线发来数据; 5、 ifconfig canX down //关闭can设备,以便配置; 6、 ip link set canX up type can bitrate 250000 //设置can波特率 7、 conconfig canX bitrate + 波特率; 8、 canconfig canX start //启动can设备; 9、 canconfig canX ctrlmode loopback on //回环测试; 10、canconfig canX restart // 重启can设备; 11、canconfig canX stop //停止can设备; 12、canecho canX //查看can设备总线状态; 13、cansend canX --identifier=ID+数据 //发送数据; 14、candump canX --filter=ID:mask //使用滤波器接收ID匹配的数据 4. 报文发送后很久才接收到,或者接收不到。 | 检查总线 CAN_H 和 CAN_L, 杜邦线是否松动或者接反。 Ethernet ~~~~~~~~~~ | 开发板有俩个网口:J14、J15,以J14说明,J15同理 | 俩个网口都支持连接外网。 1. dts 配置 | 1.1 公共的配置 | kernel-6.1/arch/arm/boot/dts/rockchip/rk3506.dtsi .. code-block:: shell gmac0: ethernet@ff4c8000 { compatible = "rockchip,rk3506-gmac", "snps,dwmac-4.20a"; reg = <0xff4c8000 0x2000>; interrupts = , ; interrupt-names = "macirq", "eth_wake_irq"; rockchip,grf = <&grf>; clocks = <&cru CLK_MAC0>, <&cru CLK_MAC0_PTP>, <&cru PCLK_MAC0>, <&cru ACLK_MAC0>; clock-names = "stmmaceth", "ptp_ref", "pclk_mac", "aclk_mac"; resets = <&cru SRST_A_MAC0>; reset-names = "stmmaceth"; snps,mixed-burst; snps,tso; snps,axi-config = <&gmac0_stmmac_axi_setup>; snps,mtl-rx-config = <&gmac0_mtl_rx_setup>; snps,mtl-tx-config = <&gmac0_mtl_tx_setup>; phy-mode = "rmii"; status = "disabled"; mdio0: mdio { compatible = "snps,dwmac-mdio"; #address-cells = <0x1>; #size-cells = <0x0>; }; gmac0_stmmac_axi_setup: stmmac-axi-config { snps,wr_osr_lmt = <4>; snps,rd_osr_lmt = <8>; snps,blen = <0 0 0 0 16 8 4>; }; gmac0_mtl_rx_setup: rx-queues-config { snps,rx-queues-to-use = <1>; queue0 { status = "okay"; }; }; gmac0_mtl_tx_setup: tx-queues-config { snps,tx-queues-to-use = <1>; queue0 { status = "okay"; }; }; }; | 1.2 板级的配置 | kernel-6.1/arch/arm/boot/dts/rockchip/myzr-gmac0-100m.dtsi .. code-block:: shell &gmac0 { status = "okay"; phy-mode = "rmii"; clock_in_out = "output"; snps,reset-gpio = <&nca9555_gpio IO_00 GPIO_ACTIVE_LOW>; snps,reset-active-low; snps,reset-delays-us = <0 10000 100000>; compatible = "rockchip,rk3506-gmac", "snps,dwmac-4.20a"; tx_delay = <0x1a>; rx_delay = <0x21>; phy-handle = <&rmii_phy0>; pinctrl-names = "default"; pinctrl-0 = <ð_rmii0_miim_pins ð_rmii0_tx_bus2_pins ð_rmii0_rx_bus2_pins ð_rmii0_clk_pins>; }; 2. 网口没有自动获取ip | 等待或者电脑网络适配器能上网的网口关掉共享给以太网网口并重新开启共享,再重启板子便能自动获取ip。 I2C ~~~~~ 1. I2C 子系统架构概述 | 在 RK3506 平台中,I2C 控制器基于标准 Linux I2C 框架实现,其核心分为硬件抽象层(适配器驱动)和设备驱动层。硬件层通过 i2c_adapter 抽象 I2C 总线控制器,设备层通过 i2c_client 描述从机设备,两者通过 i2c_driver 实现驱动逻辑。RK3562 的 I2C 控制器支持多主模式、时钟分频(最高 400kHz)及中断/DMA 传输,其物理层遵循开漏输出特性,通过 GPIO 复用实现 SCL/SDA 信号。 2. I2C设备树配置 | 以I2C1上挂载gt9触摸芯片为例,打开myzr-lcd-mipi-7-1024-600.dtsi进行配置 .. code-block:: shell &i2c2 { status = "okay"; pinctrl-names = "default"; goodix_ts: goodix_ts@5d { compatible = "goodix,gt9xx"; reg = <0x5d>; gtp_resolution_x = <1024>; gtp_resolution_y = <600>; gtp_int_tarigger = <1>; gtp_change_x2y = <0>; gtp_overturn_x = <0>; gtp_overturn_y = <0>; gtp_send_cfg = <1>; gtp_touch_wakeup = <1>; goodix_rst_gpio = <&gpio0 RK_PA7 GPIO_ACTIVE_HIGH>; goodix_irq_gpio = <&gpio0 RK_PA6 IRQ_TYPE_EDGE_FALLING>; goodix,cfg-group0 = [ //old touch ... ]; goodix,cfg-group5 = [ //new touch ... ]; }; }; | 在该节点中, 内核通过compatible字符串匹配驱动。例如,驱动代码中gt9xx.c需定义相同的 of_device_id 表: .. code-block:: shell static struct of_device_id goodix_ts_dt_ids[] = { { .compatible = "goodix,gt9xx" }, { } }; | 设备在 I2C 总线上的地址(0x5d),驱动通过 i2c_client 结构体获取reg地址。而pinctrl-\*引用 touch_gpio 节点来配置 GPIO 的复用功能和电气属性。 | 驱动与设备树匹配,compatible 值与驱动匹配时,内核调用 .probe() 函数,在probe函数中驱动将会从设备树获取配置包括引脚配置,芯片型号等信息。 | 当设备在i2c上注册成功,利用指令: | i2cdetect -y 1 | 可以看到i2c1上地址5d出现字母“UU”,代表该设备在i2c上成功挂载。