软件开发指导 ============= .. include:: /docs/COMMON/MYZR-RK3588-EK360开发环境搭建手册.rst Linux源码编译 -------------- 编译环境要求 ~~~~~~~~~~~~~ 1. 编译主机需在ubuntu系统中进行,且版本需Ubuntu 20.04以上,笔者主机系统为Ubuntu 20.04 2. 主机需可连接外网,因为编译系统过程需要下载某些文件。 下载源码包 ~~~~~~~~~~~ 1. 下载rk3588源码包,路径为:3.软件资料-->3.1源码-->rk3588-linux.tar.xz 2. 创建编译目录: .. code-block:: shell mkdir -p ~/my-work/RK3588/02_sources/ 3. 把源码放到刚创建的目录中,并进行解压: .. code-block:: shell tar xvf rk3588-linux.tar.xz -C ~/my-work/RK3588/02_sources/ 依赖安装 ~~~~~~~~~ | 首次编译可能需要安装某些依赖,下面给出主机可能需要安装的某些依赖: .. code-block:: shell sudo apt-get install uuid uuid-dev zlib1g-dev liblz-dev liblzo2-2 liblzo2-dev lzop \ git curl u-boot-tools mtd-utils openjdk-8-jdk device-tree-compiler \ gdisk m4 zlib1g-dev git gnupg flex bison gperf libsdl1.2-dev libesd-java \ squashfs-tools build-essential zip curl libncurses5-dev zlib1g-dev pngcrush schedtool \ libxml2 libxml2-utils xsltproc lzop libc6-dev schedtool g++-multilib lib32z1-dev \ lib32ncurses-dev lib32readline-dev gcc-multilib libswitch-perl libssl-dev unzip \ zip liblz4-tool git ssh make gcc libssl-dev liblz4-tool vim expect \ g++ patchelf chrpath gawk texinfo chrpath diffstat binfmt-support \ qemu-user-static live-build bison flex fakeroot cmake gcc-multilib g++-multilib \ unzip device-tree-compiler python3-pip libncurses5-dev rsync subversion python-protobuf \ sed make binutils build-essential gcc g++ wget python-is-python2 libncurses5 bzr cvs git mercurial \ patch gzip bzip2 perl tar cpio unzip rsync file bc wget qemu-user-static live-build android-sdk-libsparse-utils android-sdk-ext4-utils -y libicu-dev 整体编译 ~~~~~~~~~~ 1. 运行整体编译(编译时间较长),输入如下命令: buildroot ^^^^^^^^^^^ .. code-block:: shell ./build.sh buildroot_update ubuntu20 ^^^^^^^^^^ .. code-block:: shell ./build.sh ubuntu20_update ubuntu22 ^^^^^^^^^^ .. code-block:: shell ./build.sh ubuntu22_update debian11 ^^^^^^^^^^ .. code-block:: shell ./build.sh debian11_update debian12 ^^^^^^^^^^ .. code-block:: shell ./build.sh debian12_update 2. 编译成功后在rockdev/目录下可看到相关镜像,其中update.img是所有镜像的集合 单独编译uboot ~~~~~~~~~~~~~~~ 1. 编译前可先清除生成文件 .. code-block:: shell cd u-boot/ make clean 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 单独编译rootfs ~~~~~~~~~~~~~~~ | 在SDK主目录下输入如下命令: buildroot ^^^^^^^^^^^ .. code-block:: shell ./build.sh rootfs ubantu20 ^^^^^^^^^^ .. code-block:: shell ./build.sh ubuntu20 ubantu22 ^^^^^^^^^^ .. code-block:: shell ./build.sh ubuntu22 debian11 ^^^^^^^^^^ .. code-block:: shell ./build.sh debian11 debian12 ^^^^^^^^^^ .. code-block:: shell ./build.sh debian12 打包固件 ~~~~~~~~~ | 在SDK主目录下输入如下命令: .. code-block:: shell ./mkfirmware.sh 打包update.img ~~~~~~~~~~~~~~~~ 1. 在rockdev将镜像打包成update.img 2. 在SDK主目录下输入如下命令: .. code-block:: shell ./build.sh updateimg | 完成上述操作后可按照刷机手册重新刷机 | 最后提示用户应该重新刷机测试 安卓源码编译 ------------- 编译环境要求 ~~~~~~~~~~~~~ 1. 编译主机需在linux环境中进行,推荐主机系统为Ubuntu 20.04 2. 主机需可连接外网,因为编译系统过程需要下载某些文件。 下载源码包 ~~~~~~~~~~~ 1. 网盘目录下,下载源码包 MYZR-RK3588-EK360_Android12_20260108.tar.bz2(请将网盘内分卷文件下载后合并可以得到该压缩包) 2. 创建编译目录: .. code-block:: shell mkdir ~/my-work/rk3588/05_android -p 3. 把源码放到此目录中,并进行解压: .. code-block:: shell tar xvf MYZR-RK3588-EK360_Android12_20260108.tar.bz2 -C ~/my-work/rk3588/05_android/ 配置编译环境 ~~~~~~~~~~~~~ 1. 每次打开一个新的终端,都需要进行一个环境配置 2. 进入3588-android12目录 3. 输入如下命令配置java环境: .. code-block:: shell source javaenv.sh 4. 输入如下命令配置编译环境: .. code-block:: shell source build/envsetup.sh 5. 输入如下命令配置平台环境: .. code-block:: shell lunch myzr_rk3588-userdebug 整体编译 ~~~~~~~~~~ 1. 整体编译将整个android系统,包括kernel、uboot、android、recovery。 2. 输入如下命令: .. code-block:: shell ./build.sh -AUCKu 3. 编译时间较长,本人使用16线程主机编译需要4个小时时间(仅作参考!) 4. 成功编译后在rockdev/Image-myzr_rk3588/目录下可看到相关镜像,其中update.img是所有镜像的集合。 单独编译 uboot ~~~~~~~~~~~~~~~~ 1. 编译前可先清除生成文件 .. code-block:: shell cd u-boot/ make clean 2. 回到SDK主目录,并进行uboot单独编译 .. code-block:: shell cd ../ ./build.sh -U 单独编译 Kernel ~~~~~~~~~~~~~~~~ 1. 编译前可先清除生成文件 .. code-block:: shell cd kernel/ make clean 2. 回到SDK主目录,并进行kernel单独编译 .. code-block:: shell cd ../ ./build.sh -CKA 单独编译 android ~~~~~~~~~~~~~~~~~~ 1. 在SDK主目录下 .. code-block:: shell ./build.sh -A 打包update.img ~~~~~~~~~~~~~~~~ 1. 在rockdev将镜像打包成update.img 2. 在SDK主目录下 .. code-block:: shell ./build.sh -u 开发指导 --------- U-Boot 板级文件 ~~~~~~~~~~~~~~~~ - u-boot 板级文件位置:board/myzr/myzr_rk3588 - u-boot 板级配置文件:include/configs/myzr_rk3588.h - u-boot 极级编译配置文件:configs/myzr_rk3588_defconfig Linux 内核板级文件 ~~~~~~~~~~~~~~~~~~ - 内核板级编译配置文件:arch/arm64/configs/myzr_linux_defconfig - 内核板级设备树文件:arch/arm64/boot/dts/rockchip/myzr-*.dts* - 内核开发参考手册:网盘中《*Reference Manual*.pdf》 Ethernet ~~~~~~~~~~ | 开发板有俩个网口:J13、J14,以J13说明,J14同理 | 俩个网口都支持连接外网。 1. dts 配置 | 1.1 公共的配置 | kernel/arch/arm64/boot/dts/rockchip/rk3588.dtsi .. code-block:: shell gmac0: ethernet@fe1b0000 { compatible = "rockchip,rk3588-gmac", "snps,dwmac-4.20a"; reg = <0x0 0xfe1b0000 0x0 0x10000>; interrupts = , ; interrupt-names = "macirq", "eth_wake_irq"; rockchip,grf = <&sys_grf>; rockchip,php_grf = <&php_grf>; clocks = <&cru CLK_GMAC_125M>, <&cru CLK_GMAC_50M>, <&cru PCLK_GMAC0>, <&cru ACLK_GMAC0>, <&cru CLK_GMAC0_PTP_REF>; clock-names = "stmmaceth", "clk_mac_ref", "pclk_mac", "aclk_mac", "ptp_ref"; resets = <&cru SRST_A_GMAC0>; reset-names = "stmmaceth"; power-domains = <&power RK3588_PD_GMAC>; 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>; status = "disabled"; mdio0: mdio { compatible = "snps,dwmac-mdio"; #address-cells = <0x1>; #size-cells = <0x0>; }; | 1.2 板级的配置 | kernel/arch/arm64/boot/dts/rockchip/myzr-rk3588-linux.dts .. code-block:: shell //有线网卡配置 &gmac0 { /* Use rgmii-rxid mode to disable rx delay inside Soc */ phy-mode = "rgmii-rxid"; clock_in_out = "output"; snps,reset-active-low; /* Reset time is 20ms, 100ms for rtl8211f */ snps,reset-delays-us = <0 20000 100000>; pinctrl-names = "default"; pinctrl-0 = <&gmac0_miim &gmac0_tx_bus2 &gmac0_rx_bus2 &gmac0_rgmii_clk &gmac0_rgmii_bus>; tx_delay = <0x44>; /* rx_delay = <0x4f>; */ phy-handle = <&rgmii_phy0>; status = "okay"; }; 2. 网口没有自动获取ip | 等待或者电脑网络适配器能上网的网口关掉共享给以太网网口并重新开启共享,再重启板子便能自动获取ip。 RTC 使用 ~~~~~~~~~~ 1. 简介 | MYZR-RK3588-EK360开发板采用HYM8563作为RTC(Real Time Clock),HYM8563是一款低功耗CMOS实时时钟/日历芯片,它提供一个可编程的时钟输出,一个中断 输出和一个掉电检测器,所有的地址和数据都通过I2C总线接口串行传递。最大总线速度为 400Kbits/s,每次读写数据后,内嵌的字地址寄存器会自动递增 - 可计时基于 32.768kHz 晶体的秒,分,小时,星期,天,月和年 - 宽工作电压范围:1.0~5.5V - 低休眠电流:典型值为 0.25μA(VDD =3.0V, TA =25°C) - 内部集成振荡电容 - 漏极开路中断引脚 2. RTC驱动 | 驱动参考:kernel/drivers/rtc/rtc-hym8563.c 3. 接口使用 | Linux 提供了三种用户空间调用接口。在 MYZR-RK3588-EK360开发板中对应的路径为: - SYSFS接口:/sys/class/rtc/rtc0/ - PROCFS接口: /proc/driver/rtc - IOCTL接口: /dev/rtc0 4. SYSFS接口 | 可以直接使用 cat 和 echo 操作 /sys/class/rtc/rtc0/ 下面的接口。 | 比如查看当前 RTC 的日期和时间: .. code-block:: shell root@root:/# date -s "2025-05-7 10:00:00" Wed May 7 10:00:00 UTC 2025 root@root:/# cat /sys/class/rtc/rtc0/time 10:00:24 5. PROCFS 接口 | 打印 RTC 相关的信息: .. code-block:: shell root@root:/# cat /proc/driver/rtc rtc_time : 10:03:19 rtc_date : 2025-05-07 alrm_time : 10:04:00 alrm_date : 2025-05-07 alarm_IRQ : no alrm_pending : no update IRQ enabled : no periodic IRQ enabled : no periodic IRQ frequency : 1 max user IRQ frequency : 64 24hr : yes 6. IOCTL接口 | 可以使用 ioctl 控制 /dev/rtc0。 | 详细使用说明请参考文档 kernel/Documentation/admin-guide/rtc.rst 。 7. FAQs | Q1: 开发板上电后时间不同步? | A1: 检查一下 RTC 电池是否正确接入。 GPIO ~~~~~~ 1. 简介 | GPIO,全称 General-Purpose Input/Output(通用输入输出),是一种软件运行期间能够动态配置和控制的通用引脚。 所有的 GPIO 在上电后的初始状态都是输入模式,可以通过软件设为上拉或下拉,也可以设置为中断脚,驱动强度都是可编程的,其核心是填充 GPIO bank 的方法和参数,并调用 gpiochip_add 注册到内核中。 2. GPIO引脚计算 | RK3588 有 6 组 GPIO bank:GPIO0~GPIO5,每组又以 A0~A7, B0~B7, C0~C7, D0~D7 作为编号区分,常用以下公式计算引脚: | GPIO pin脚计算公式:pin = bank * 32 + number | GPIO 小组编号计算公式:number = group * 8 + X | 下面演示GPIO2_C4 pin脚计算方法: | bank = 2; //GPIO2_C4 => 2, bank ∈ [0,5] | group = 2; //GPIO2_C4 => 2, group ∈ {(A=0), (B=1), (C=2), (D=3)} | X = 0; //GPIO2_C4 => 4, X ∈ [0,7] | number = group * 8 + X = 2 * 8 + 4 = 20 | pin = bank*32 + number= 2 * 32 + 20 = 56; | GPIO2_C4 对应的设备树属性描述为:<&gpio2 20 GPIO_ACTIVE_HIGH>,由kerne/include/dt-bindings/pinctrl/rockchip.h的宏定义可知,也可以将GPIO2_C4描述为<&gpio2 RK_PC4 GPIO_ACTIVE_HIGH>。 .. code-block:: shell #define RK_PA0 0 #define RK_PA1 1 #define RK_PA2 2 #define RK_PA3 3 #define RK_PA4 4 #define RK_PA5 5 #define RK_PA6 6 #define RK_PA7 7 #define RK_PB0 8 ... | 当GPIO2_C4脚没有被其它外设复用时, 我们可以通过export导出该引脚去使用 3. 中断 .. code-block:: shell interrupt-parent = <&gpio0>; interrupts = ; | IRQ_TYPE_LEVEL_LOW 表示中断由低电平触发,当该引脚接收到低电平信号时可以触发中断函数。 这里还可以配置成如下: | IRQ_TYPE_NONE //默认值,无定义中断触发类型 | IRQ_TYPE_EDGE_RISING //上升沿触发 | IRQ_TYPE_EDGE_FALLING //下降沿触发 | IRQ_TYPE_EDGE_BOTH //上升沿和下降沿都触发 | IRQ_TYPE_LEVEL_HIGH //高电平触发 | IRQ_TYPE_LEVEL_LOW //低电平触发 4. 复用 | 该案例仅供参考,最终以实际硬件接口为准 | GPIO 口除了通用输入输出、中断功能外,还可能有其它复用功能,以GPIO2_C4为例,就有如下几个功能: | 若要改变gpio的复用,可以通过rk3588-linux\kernel\arch\arm64\boot\dts\rockchip\rk3588-vccio3-pinctrl.dtsi | 输入4 RK_PA3去查找节点,引用并配置 .. code-block:: shell /omit-if-no-ref/ uart0m2_xfer: uart0m2-xfer { rockchip,pins = /* uart0_rx_m2 */ <4 RK_PA4 10 &pcfg_pull_up>, /* uart0_tx_m2 */ <4 RK_PA3 10 &pcfg_pull_up>; }; //485 &uart0 { status = "okay"; pinctrl-names = "default"; pinctrl-0 = <&uart0m2_xfer>; }; 5. GPIO 调试接口 | Debugfs 文件系统目的是为开发人员提供更多内核数据,方便调试。 这里 GPIO 的调试也可以用 Debugfs 文件系统,获得更多的内核信息。GPIO 在 Debugfs 文件系统中的接口为 /sys/kernel/debug/gpio,可以这样读取该接口的信息: .. code-block:: shell root@topeet:/# cat sys/kernel/debug/gpio gpiochip0: GPIOs 0-31, parent: platform/fd8a0000.gpio, gpio0: gpio-15 ( |vcc-3v3-sd-s0-regula) out lo gpiochip1: GPIOs 32-63, parent: platform/fec20000.gpio, gpio1: gpio-43 ( |vcc3v3-lcd0-n ) out hi gpio-52 ( |hp-det ) in hi ACTIVE LOW gpio-61 ( |hdmirx-det ) in hi ACTIVE LOW gpiochip2: GPIOs 64-95, parent: platform/fec30000.gpio, gpio2: ... 485 ~~~~~ DTS配置 ^^^^^^^^^^ | 文件路径kernel/arch/arm64/boot/dts/rockchip/myzr-rk3588-linux.dts .. code-block:: shell //485 &uart0 { status = "okay"; pinctrl-names = "default"; pinctrl-0 = <&uart0m2_xfer>; }; | 配置好串口后,硬件接口对应软件上的节点为: .. code-block:: shell UART0: /dev/ttyS0 CAN ~~~~~ 1. CAN 简介 | CAN(Controller Area Network)总线,即控制器局域网总线,是一种有效支持分布式控制或实时控制的串行通信网络。CAN总线是一种在汽车上广泛采用的总线协议,被设计作为汽车环境中的微控制器通讯。 如果想了解更多的内容可以参考CAN应用报告 2. DTS 节点配置 - 公共配置 kernel/arch/arm64/boot/dts/rockchip/rk3588s.dtsi .. code-block:: shell can1: can@fea60000 { compatible = "rockchip,can-2.0"; reg = <0x0 0xfea60000 0x0 0x1000>; interrupts = ; clocks = <&cru CLK_CAN1>, <&cru PCLK_CAN1>; clock-names = "baudclk", "apb_pclk"; resets = <&cru SRST_CAN1>, <&cru SRST_P_CAN1>; reset-names = "can", "can-apb"; pinctrl-names = "default"; pinctrl-0 = <&can1m0_pins>; tx-fifo-depth = <1>; rx-fifo-depth = <6>; status = "disabled"; }; - 板级配置 arch/arm64/boot/dts/rockchip/myzr-rk3588-linux.dts .. code-block:: shell //can &can1 { status = "okay"; compatible = "rockchip,can-2.0"; //使用can pinctrl-0 = <&can1m1_pins>; assigned-clocks = <&cru CLK_CAN1>; assigned-clock-rates = <100000000>; }; 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, 杜邦线是否松动或者接反。 HDMI ~~~~~~ 1. HDMI接口的配置 | 硬件上有两个 HDMI 显示输出接口。 | 打开HDMI接口如下所示: - /rk3588-linux/kernel/arch/arm64/boot/dts/rockchip/myzr-screen-lcds.dts .. code-block:: shell //#define LCD_TYPE_MIPI0 //VP2 //#define LCD_TYPE_LVDS_10_1_1280x800_GT911 //VP2 //#define LCD_TYPE_LVDS_10_1_1280x800_GT9271 //VP2 //#define LCD_TYPE_LVDS_10_1_1024x600_GT911 //VP2 //#define LCD_TYPE_LVDS_7_0 //VP2 #define LCD_TYPE_HDMI1 //VP1 #define LCD_TYPE_HDMI0 //VP0 //#define LCD_TYPE_TYPEC_DP //VP1 //#define LCD_TYPE_MIPI1 //VP3 | 如果将两个 HDMI 接口同时接上屏幕,默认会双屏同显。 | 1.1. 软件配置 .. code-block:: shell #if defined(LCD_TYPE_HDMI0) //打开 hdmi0 的 硬件 phy &hdptxphy_hdmi0 { status = "okay"; }; //使能HDMI0 &hdmi0 { enable-gpios = <&gpio4 RK_PB1 GPIO_ACTIVE_HIGH>; status = "okay"; }; //配置HDMI0到VP0上面 &hdmi0_in_vp0 { status = "okay"; }; //打开HDMI0 声音 &hdmi0_sound { status = "okay"; }; //配置HDMI0上面显示开机logo &route_hdmi0 { status = "okay"; }; #endif .. code-block:: shell #if defined(LCD_TYPE_HDMI1) //使能HDMI1 &hdptxphy_hdmi1 { status = "okay"; }; &hdmi1 { enable-gpios = <&gpio4 RK_PA2 GPIO_ACTIVE_HIGH>; status = "okay"; }; //配置HDMI1到VP1上面 &hdmi1_in_vp1 { status = "okay"; }; //打开HDMI1 声音 &hdmi1_sound { status = "okay"; }; //配置HDMI1上面显示开机logo &route_hdmi1 { status = "okay"; }; #endif Watchdog ~~~~~~~~~~ 1. 简介 | 看门狗(watchdog)实际是一个定时器,启动之后会开始计时。系统或者软件需要在规定时间内与看门狗通信(俗称喂狗)重置计时,如此反复下去,以此来确定系统和软件正常运行。 | 如果规定时间内没有喂狗,看门狗超时,说明系统或应用陷入循环、卡死,此时看门狗会发出复位信号让主控复位,脱离卡死。 2. DTS配置 | MYZR-RK3588-EK360的 watchdog 的 DTS 节点在 kernel/arch/arm64/boot/dts/rockchip/rk3588s.dtsi 文件中定义,如下所示: .. code-block:: shell wdt: watchdog@feaf0000 { compatible = "snps,dw-wdt"; reg = <0x0 0xfeaf0000 0x0 0x100>; clocks = <&cru TCLK_WDT0>, <&cru PCLK_WDT0>; clock-names = "tclk", "pclk"; interrupts = ; status = "okay"; }; | watchdog 的驱动文件为 kernel/drivers/watchdog/dw_wdt.c。