您尚未登录。

楼主 #1 2019-11-19 14:57:00

kernelpanic
会员
注册时间: 2019-11-08
已发帖子: 20
积分: 20

OrangePi zero 最小软件系统构建过程记录

一下是我最近摸索构建一个最简单用于 OrangePi zero 的系统的过程,笔记是我从自己 OneNote 复制的,图片丢失,语言表述,格式等恐存在问题,见谅。
也算踩了很多的坑,有些问题比较奇葩,网上搜索,qq群请教无果,最后也在本论坛上得到了帮助: https://whycan.cn/t_3243.html#p27998
也就把自己记录分享出来。
   
        1. 大致流程
        a. u-boot 编译,启用 ethernet 以太网,烧写到 sd 卡,验证 网络能用
        b. 编译内核生成 zImage 和 dtb,放在开发机上的 tftp 目录, u-boot 端通过 tftp 下载内核和dt,并启动内核
        c. 有了 u-boot 和 内核,还需要构建根文件系统 -- rootfs,使用 buildroot 构建, 并部署到开发机的 nfs 目录,避免重复插拔 sd 卡;u-boot 启动内核并通过 bootargs 传递 cmd line 给内核,内核通过nfs挂载rootfs。
        d. 验证系统可用性
        e. 烧写到 sd 卡
    2. u-boot
        a. 源码
        opz 和 友善 nanopi duo 都是用 h2+,orangepi 技术支持太糟糕,所以采用友善 nanopi h3 的源码:
         git clone https://github.com/friendlyarm/u-boot.git -b sunxi-v2017.x --depth 1
        参考: http://wiki.friendlyarm.com/wiki/index.php/Building_U-boot_and_Linux_for_H5/H3/H2%2B
       
        b. 配置编译
            i. 默认配置
                1) make ARCH=arm nanopi_h3_defconfig
                2) configs/ 下有几个 h2+ soc 相关的
                    a) orangepi_zero_defconfig  是 orangepi zero 的配置
                    b) nanopi_h3_defconfig 是 nanopi h3 的配置,但是兼容 h2+
            虽然我板子是 orangepi zero,但是这份源码是 友善修改过适配 h3 的,所以选择 nanopi_h3_defconfig 作为初始配置
            ii. u-boot bootcmd 设置,bootcmd value :
            fatload mmc 0:1 ${scriptaddr} boot.scr; source ${scriptaddr}
           
           
           
            这个 bootcmd 命令会在 u-boot 指定 boot 命令时执行,或者自动加载时执行(倒计时之后)
            它做的事:
                1) 从 mmc 0:1 分区,也就是 sd 卡 fat 分区(boot) 加载 boot.scr 文件到 内存,地址由环境变量 scriptaddr 决定
                2) 执行boot.scr 脚本
                3) boot.scr 后面我们会看到,它就是加载内核的
                4) 所以,u-boot 能够移到内核,这一个命令起到了关键的作用
           
            编译为 boot.scr
            mkimage -C none -A arm -T script -d boot.cmd boot.scr
           
            iii. 配置以太网卡
                1) > Device Drivers > Network device support
                Allwinner Sun8i Ethernet MAC support  打勾
            iv. 选择 u-boot dts 文件:不能使用 nanopi 的因为板级外设不同
            Device Tree Control-> sun8i-h2-plus-orangepi-zero  注意不需要后缀
            v. 保存配置文件
            make ARCH=arm savedefconfig
            会生成 defconfig 文件
            mv defconfig configs/opz_defconfig
            vi. 编写编译脚本 rebuild.sh
            #!/bin/sh
            time make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- 2>&1 | tee build.log
            vii. 编译 ./rebuild.h
            viii. 生成 
            u-boot-sunxi-with-spl.bin
        c. 烧写 u-boot
            i. 把 sd 读卡器接入 vmware 虚拟机
            ii. 烧写u-boot 镜像 
            ls /dev/sd*  查看sd卡的磁盘标号 一般是 sdb,sdb1,sdb2
            dd if=u-boot-sunxi-with-spl.bin of=/dev/sdb bs=1024 seek=8
sync && eject /dev/sdb
        d. 上电测试
            i. 串口插上,查看日志
           
           
            ii. 验证网卡
                1) 插入网线到路由器 路由器网段 192.168.1.1/24
                2) 设置关闭自动加载 setenv autoload no  (不然dhcp会触发自动从tftp 加载,但是我们还没配置)
                3) dhcp  正常的话,会输出 bound to ip地址的日志
                4) ping 192.168.1.1  会显示 host is alive
    3. tftp 配置
        a. tftp 是 u-boot 支持的网络文件共享方式,用于从另一个PC下载文件
        b. 配置 ubuntu 运行 tftp 服务端
            i. vmware 里的 ubuntu 增加桥接网络 —— 虚拟机接入路由器,拥有独立ip,开发板才能通过ip地址访问到
            ii. 安装配置 tftp 服务  https://www.davidsudjiman.info/2006/03/27/installing-and-setting-tftpd-in-ubuntu/
                1) sudo apt-get install xinetd tftpd tftp
                2) 创建配置文件  /etc/xinetd.d/tftp
                service tftp
                {
                protocol        = udp
                port            = 69
                socket_type     = dgram
                wait            = yes
                user            = nobody
                server          = /usr/sbin/in.tftpd
                server_args     = /tftpboot
                disable         = no
                }
                3) 创建共享目录  /tftpboot
                $ sudo mkdir /tftpboot
                $ sudo chmod -R 777 /tftpboot
                $ sudo chown -R nobody /tftpboot
                4) 启动服务
                $ sudo /etc/init.d/xinetd start
                5) 在 /tftpboot 放置测试文件
                touch /tftpboot/hello
        c. 在 u-boot 命令行,测试 tftp
            i. 服务端地址环境变量设置
            setenv serverip 192.168.1.76
            ii. tftp 0x41000000 hello
            日志显示下载到文件
    4. linux 内核
        a. 源码
        opz 和 友善 nanopi duo 都是用 h2+,orangepi 技术支持太糟糕,所以采用友善 nanopi h3 的源码:
         git clone https://github.com/friendlyarm/linux.git -b sunxi-4.14.y --depth 1
        参考: http://wiki.friendlyarm.com/wiki/index.php/Building_U-boot_and_Linux_for_H5/H3/H2%2B
        源码版本比荔枝派源码更新
        b. 选择基础配置
            i. 只有 sunxi_defconfig 可选
            make  ARCH=arm sunxi_defconfig
        c. 配置内核
            make  ARCH=arm menuconfig
            i. System Type
           
           
            ii. Device Drivers > Network device support > Ethernet driver support
           
            为什么全志的网卡跟 ST 是关联的?
           
            iii. File Systems > Network File Systems
            使能 nfs
           
           
        d. 保存配置
        make ARCH=arm savedefconfig
        mv defconfig arch/arm/configs/opz_defconfig
       
        e. 创建编译脚本, 编译完成,拷贝镜像文件到 result_image/ 目录,方便导出
        #!/bin/sh
        make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j16 &&\
        make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j16 INSTALL_MOD_PATH=out modules &&\
        make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j16 INSTALL_MOD_PATH=out modules_install &&\
        mkdir ./result_image -p  &&\
        cp arch/arm/boot/zImage ./result_image &&\
        cp arch/arm/boot/dts/sun8i-h2-plus-orangepi-zero.dtb ./result_image/opz.dtb
        f. 编译
         ./rebuild.sh
        g. 在 result_image/ 生成了 zImage 和 opz.dtb, dtb 复制的是orangepi-zeror 的与开发板对应
        h. 测试 uboot tftp 加载内核
            i. u-boot 正常的启动流程
                1) boot.cmd 会被编译成 boot.scr,存放在sd 卡 boot 分区里
                2) u-boot 环境变量 bootcmd,上一节提到的,它的作用就是去sd卡上加载 boot.scr 并执行
               
               
                3) boot.cmd -> boot.scr
                #boot.scr 
                setenv bootargs console=ttyS0,115200 panic=5 rootwait root=/dev/mmcblk2p2 rootfstype=ext4 earlyprintk rw
                load mmc 0:1 0x41000000 zImage
                load mmc 0:1 0x41800000 opz.dtb
                bootz 0x41000000 - 0x41800000
                第一行设置的是 bootargs 环境变量,是传递给内核的参数
                第二行从mmc0 分区1 也就是 mmcblk0p1 加载 zImage 文件到内存 0x41000000 地址处,也就是把zImage 从 sd卡 boot 分区拷贝到内存
                第三行把 opz.dtb 加载到内存 0x41800000 地址处
                第四行,跳转到 0x41000000 运行内核,也就是启动 linux 内核, u-boot 会把 bootargs 的值传给内核
               
               
                mkimage -C none -A arm -T script -d boot.cmd boot.scr
               
            ii. 改用 tftp 启动
            上面我们摸清了 u-boot 从sd卡的引导内核的流程,下面我用 tftp 的方式来代替
                1) 设置 bootargs
                原来 bootargs 是在 boot.scr 脚本里设置的,当然我们也可以通过 tftp 加载 boot.scr;不过,这种情况,直接设置 bootargs 环境变量即可:
                => setenv bootargs console=ttyS0,115200 panic=5 rootwait root=/dev/mmcblk2p2 rootfstype=ext4 earlyprintk rw
                => saveenv
                # 没有改变,只是手动设定,并保存
                2) 设置 bootcmd 环境变量
                我们不需要 boot.scr 了,所以,bootcmd 可以直接代替 boot.scr 的功能
                => setenv bootcmd
                        tftp 0x41000000 zImage; tftp 0x41800000 opz.dtb; bootz 0x41000000 - 0x41800000
                => saveenv
                    1) 加载 zImage, 从 serverip:/tftpboot/ 下载 zImage
                    2) 加载 dtb, 从 serverip:/tftpboot/ 下载 opz.dtb
                    3) 启动内核
                3) 启动,执行boot 命令,则会执行 bootcmd 并, 传递 bootargs
                boot
                4) linux 下 tftp命令 : tftp 192.169.1.76 -g -r zImage -l zImage
    5. 根文件系统 —— 使用 buildroot 构建根文件系统
        a. buildroot 源码
        https://buildroot.org/download.html
        https://buildroot.org/downloads/buildroot-2019.02.7.tar.gz
        git clone git://git.buildroot.net/buildroot  -b 2019.02.x
        buildroot 不光可以构建根文件系统,还可以连内核,uboot 一键构建,最主要是用来把系统依赖的软件包打包进去根文件系统
        b. 配置
        make ARCH=arm menuconfig
            i. Target options
           
           
            ii. Toolchain
               
                1) 使用外部工具链: buildroot 可以支持内建交叉工具链(连工具链都给你准备好了 ?),但是我们这里使用跟编译u-boot 和 内核相同的外部工具链就可以
                2) Custom toolchain 自定义的工具链
                3) 工具链路径   /opt/gcc-linaro-6.3.1-2017.05-x86_64_arm-linux-gnueabihf/
                4) 工具链前缀  arm-linux-gnueabihf
                5) 工具链 gcc 版本  6.x   查看工具链目录就知道
                6) 头文件版本,查看
                cat /opt/gcc-linaro-6.3.1-2017.05-x86_64_arm-linux-gnueabihf/arm-linux-gnueabihf/libc/usr/include/linux/version.h
                #define LINUX_VERSION_CODE 263680
                #define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
               
               
                版本号为 4.6
               
            iii. System Configuration
           
       
            i. Kernel 和 Bootloader 都不选,因为我们自己编译
            ii. Target package 需要根据实际需要选择要打包进入根文件系统的依赖,这个阶段可以不过多配置
        c. 编译
        make
       
        d. 经过漫长的编译时间,生成 output/images/rootfs.tar

    6. 网络挂载根文件系统 NFS
        a. NFS 服务端配置
            i. 服务端ip地址是 192.168.1.76
            ii. 安装软件
            sudo apt-get install nfs-kernel-server
            iii. 配置目录: 配置要服务的目录
            sudo vi /etc/exports
            /nfs/rootfs *(rw,sync,no_root_squash,no_subtree_check) 
            iv. 启动服务
            sudo service nfs-kernel-server restart
            v. 检测是否 exported
           
            sudo showmount -e
            以上,把 /nfs/rootfs 作为 nfs 目录共享到网络上
           
            vi. 解压根文件系统镜像 到 /nfs/rootfs
                1) 上面一节我们得到了 rootfs.tar
                2) 创建目录 sudo mkdir /nfs/rootfs
                3) 解压 rootfs.tar 到 nfs/rootfs 目录
                sudo tar xvf rootfs.tar -C /nfs/rootfs
                4) 注意要 sudo,因为根文件系统里用户是 root
            vii. 至此,我们准备好了 NFS 服务端
           
        b. u-boot NFS 测试
        在 u-boot 命令行
        => nfs 0x41000000 192.168.1.76:/helloworld.out
        若 nfs 服务通畅,日志会显示下载成功
           
       
        c. 挂载根文件系统到 NFS
        要让内核启动后把 NFS 作为 根文件系统挂载,需要在 bootargs 指定正确的参数
        setenv bootargs noinitrd console=ttyS0,115200 panic=5 rootwait ip=192.168.1.172:192.168.1.76:192.168.1.1:255.255.255.0:opz:::192.168.1.1 
        nfsroot=192.168.1.76:/nfs/rootfs,nfsvers=3,tcp   
        root=/dev/nfs rw loglevel=7 earlyprintk  init=/sbin/init
        以上,bootargs 指定了  根文件系统是 nfs 类型, nfsroot 设置了 服务器的地址,nfsvers 指定协议版本
        版本非常重要,大部分教程都没有说版本,但是在我的环境里没有指定 nfsvers 确实是挂载不上去的。
        详细说明参考:nfs 启动的说明:  https://www.kernel.org/doc/Documentation/filesystems/nfs/nfsroot.txt
        d. 挂载成功,系统启动
           
        e. 以上,通过tftp和nfs网络手段,验证了 u-boot,内核, 根文件系统可以正常工作,就可以烧写到 sd 卡。
        NFS 可以减少我们频繁插拔操作sd卡的次数,提供 根文件系统构建过程的调试效率
        tftp 可以提高内核替换验证速度
    7. 烧写 sd 卡
        a. u-boot 烧写
            i. 把 sd 读卡器接入 vmware 虚拟机
            ii. 烧写u-boot 镜像 
            ls /dev/sd*  查看sd卡的磁盘标号 一般是 sdb,sdb1,sdb2
            dd if=u-boot-sunxi-with-spl.bin of=/dev/sdb bs=1024 seek=8
sync && eject /dev/sdb
           
        b. 分区
            i. sd 分区格式化的说明文档: https://linux-sunxi.org/Bootable_SD_card
                1) 为全志芯片定制的 u-boot,对 mmc 有如下要求:
               
                2) 8KB 偏移处,存储 u-boot-spl
                3) 大部分分区工具从 1MB 开始第一个分区,u-boot 可以使用 前1MB 的空间。
                8KB 偏移是全志 SOC BROM 检测的,它会检查 8KB 偏移处是否有 eGON/TOC0 头部签名
                40KB 偏移是 U-Boot proper 默认定义的位置,可以通过修改 CONFIS_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR 配置
                新的全志SOC 如 H2+, 如果检测不到 8KB 偏移的签名,就会从 128KB 加载 SPL,响应的 U-Boot proper 偏移需要修改。
                u-boot 被分为两部分:SPL 和 U-Boot proper,我们编译得到的 u-boot-sunxi-with-spl.bin 已经打包了这两部分。烧写进 8KB 偏移时,两部分都烧写了。
               
               
            ii. sd 卡通过读卡器接入 ubuntu 系统
                1) 查看sd卡设备号 blkid
               
                2) 定义shell 变量
                export card=/dev/sdb
                export p=""
               
            iii. 烧写 u-boot
                1) 清空前1MB,为u-boot 烧写做准备
                dd if=/dev/zero of=${card} bs=1M count=1
                2) 烧写 u-boot
                dd if=u-boot-sunxi-with-spl.bin of=${card} bs=1024 seek=8
               
            iv. 创建分区
                1) 如果分区被挂载中,需要 umount
                sudo umount /media/panic/linux/
                2) fdisk /dev/sdb
            n: 新建
            p 主分区
            交互式创建分区
           
            分区代号表:
               
           
            v. 调整分区格式
            sudo mkfs.vfat  /dev/sdb1
            sudo mkfs.ext4  /dev/sdb2
           
            遇到一个问题,格式化之后,fdisk 里,l 命令查看分区表,发现 第一个分区也是 linux,不知是否格式化失败
            $ sudo mkfs.vfat /dev/sdb1
            mkfs.fat 3.0.26 (2014-03-07)
           
            $ sudo fdisk -l /dev/sdb
           
            Disk /dev/sdb: 3904 MB, 3904897024 bytes
            121 heads, 62 sectors/track, 1016 cylinders, total 7626752 sectors
            Units = sectors of 1 * 512 = 512 bytes
            Sector size (logical/physical): 512 bytes / 512 bytes
            I/O size (minimum/optimal): 512 bytes / 512 bytes
            Disk identifier: 0xed2d5f33
           
               Device Boot      Start         End      Blocks   Id  System
            /dev/sdb1            4096       69631       32768   83  Linux
            /dev/sdb2           69632     7626751     3778560   83  Linux
           
            mkfs.msdos, mkfs.ntfs 都是显示 一样的结果
               
               
                但是从上图可以看出,实际文件格式是 fat,因为用 fat 命令可以读取到文件
               
            vi. 查看分区列表
        c. 挂载 sd 分区
       
        d. 内核 zImage, dtb, boot.scr 拷贝
            i. boot.cmd
            setenv bootargs console=ttyS0,115200 panic=5 rootwait root=/dev/mmcblk0p2 earlyprintk rw
            load mmc 0:1 0x41000000 zImage
            load mmc 0:1 0x41800000 opz.dtb
            bootz 0x41000000 - 0x41800000
            由于粗心,bootargs 里多写了 一个 console=tty0 导致内核启动之后,日志打印不出来以为没启动,怀疑式根文件系统的问题,
            因为 nfs 挂载可以成功,恰恰式因为 nfs 的 bootargs 没多写 console
            ii. boot.scr
            mkimage -C none -A arm -T script -d boot.cmd boot.scr
            iii. zImage , dtb 拷贝到 sd 卡 boot 分区
            iv. bootcmd 环境变量
            v. tftp 0x43100000 boot-mmc.scr; source 0x43100000
        e. 根文件系统拷贝
            i. 把sd卡第二分区挂载到 pc上
            sudo mount /dev/sdb2 /mnt
            (ubuntu 桌面系统会自动挂载到 /media/panic/XXX )
            ii. 解压跟文件系统
            sudo tar xvf rootfs.tar -C /nfs/rootfs
           
            iii. 遇到的问题
                1) boot 分区 fat 格式有问题,
                    1) ubuntu fdisk -l 显示boot分区为 linux 格式,而 gparted 显示 fat16
                    2) 从 boot 分区加载 zImage , 运行不起来,同一个 zImage 放在网络或者 linux 分区加载,都可以成功
                    3) 讲boot 分区格式化为 ext4, 可以正常加载linux
                mkfs.vfat /dev/sdb1  之后,fdisk -l 查看到的 分区,仍然识别为 linux,但 gparted 却可以是被为 fat16, windows 也可以识别。
                but 在 u-boot 里,虽然加载到 zImage ,但是启动不起来 到 starting kernel 就停了。于是我把boot分区格式化为 ext4, 内核起得来了
                2) 根文件系统,nfs 可以正常,但是放在 sd 卡上就不正常了
                [    2.352629] mmc3: new high speed SDIO card at address 0001
                [    2.359692] random: fast init done
                [    2.365871] EXT4-fs (mmcblk2p2): mounted filesystem with ordered data mode. Opts: (null)
                [    2.374086] VFS: Mounted root (ext4 filesystem) on device 179:2.
                [    2.381915] devtmpfs: mounted
                [    2.387054] Freeing unused kernel memory: 2048K
                [    2.495571] EXT4-fs (mmcblk2p2): re-mounted. Opts: data=ordered
                [    2.676719] random: dd: uninitialized urandom read (512 bytes read)
                [    2.834544] Generic PHY stmmac-0:01: attached PHY driver [Generic PHY] (mii_bus:phy_addr=stmmac-0:01, irq=POLL)
                [    2.846970] dwmac-sun8i 1c30000.ethernet eth0: No MAC Management Counters available
                [    2.854702] dwmac-sun8i 1c30000.ethernet eth0: PTP not supported by HW
                [    2.861597] IPv6: ADDRCONF(NETDEV_UP): eth0: link is not ready
                [    5.978730] dwmac-sun8i 1c30000.ethernet eth0: Link is Up - 100Mbps/Full - flow control rx/tx
                [    5.987345] IPv6: ADDRCONF(NETDEV_CHANGE): eth0: link becomes ready
                改了 bootargs,去掉多余的 console 字段之后,终于正常。
                3) mount /dev/mmcblk2p1 /mnt 挂载问题
           
                # mount /dev/mmcblk2p1 /mnt
                [  167.579602] FAT-fs (mmcblk2p1): IO charset ascii not found
                [  167.591458] FAT-fs (mmcblk2p1): Volume was not properly unmounted. Some data may be corrupt. Please run fsck
                虽然有警告,但是可以挂载
                要内核配置为支持 fat 文件系统 File systems-> ms dos blablabla -> *
            iv. 恢复 u-boot bootcmd 默认引导
            setenv bootcmd "load mmc 0:1 ${scriptaddr} boot.scr; source ${scriptaddr}"
            fatload 改为 load , load 支持其他格式文件系统
            v. 调试技巧
                1) 从 tftp 加载 boot.scr,并启动
                setenv bootcmd "tftp ${scriptaddr} boot.scr; source ${scriptaddr}"
                saveenv
                boot
                2) 从 tftp 更新 zImage
                setenv bootcmd "tftp ${scriptaddr} boot.scr; source ${scriptaddr}"
                setenv serverip 192.168.1.76
                setenv ipaddr 192.168.1.172
                tftp 命令需要先设置好ip
                3) 在linux系统里从 tftp 下载文件
                tftp -g -r boot-mmc.scr 192.168.1.76
   
    8. 内核模块拷贝进入根文件系统
        a. 内核编译生成目录
            i. 编译模块
            make ARCH=arm modules
            ii. 安装模块  INSTALL_MOD_PATH 指定安装的目录,我们安装到源码目录下
            make INSTALL_MOD_PATH=out modules_install
            iii. 得到 out/lib/modules/4.14.111-g08b7e83/
        b. 拷贝
        一般编译的是时候,文件系统没有挂载到主机上,所以需要多一步
        把 p2 挂载到 /mnt,再把上一步生成的目录拷贝到目标根文件系统上。
        sudo mkdir -p /mnt/lib/modules/$VERSION/ &&\
        sudo cp modules/* /mnt/lib/modules/$VERSION -r &&\
        $VERSION 是目标内核的版本号 通过 uname -r 查看
        c. 疑问
            i. 文件夹的名字需要改么,生成的 modules 带后缀
            https://unix.stackexchange.com/questions/231500/difference-between-lib-module-uname-r-and-sys-module
            -需要相同
            ii. 内核模块安装错误
            appledisplay: version magic '4.14.111-g08b7e83 SMP mod_unload ARMv7 p2v8 ' should be '4.14.111-g25f7b00-dirty SMP mod_unload ARMv7 p2v8 '
            编译版本和运行版本不是一样的
            http://billauer.co.il/blog/2013/10/version-magic-insmod-modprobe-force/
                1) include/generated/utsrelease.h  里记录了自动生成的版本号
                2) include/linux/vermagic.h 决定了随机的版本号
                3) 编译菜单 General setup -> Automatically append version information to version string 去勾选,会去掉 版本后面的随机串,但是最后有个加号
                4) 加号来源是版本控制系统,当前版本处于改动中就会自动附上+ http://smilejay.com/2012/07/kernel-version-plus-sign/
            iii. 内核如何决定是否使用 这些模块,开机使用还是需要手动
            应该是在内核使用到相应的功能时,会自动去查找安装

最近编辑记录 kernelpanic (2019-11-19 15:03:22)

离线

#2 2019-11-19 14:59:24

晕哥
管理员
注册时间: 2017-09-06
已发帖子: 9,348
积分: 9202

Re: OrangePi zero 最小软件系统构建过程记录

感谢分享, 有空我也照着你的步奏一步一步跑起来。





离线

楼主 #3 2019-11-19 16:27:49

kernelpanic
会员
注册时间: 2019-11-08
已发帖子: 20
积分: 20

Re: OrangePi zero 最小软件系统构建过程记录

晕哥 说:

感谢分享, 有空我也照着你的步奏一步一步跑起来。


好的,大佬。
我想知道为什么你有那么多的时间,为什么俺觉得老是没时间用

离线

#4 2019-11-19 16:33:00

晕哥
管理员
注册时间: 2017-09-06
已发帖子: 9,348
积分: 9202

Re: OrangePi zero 最小软件系统构建过程记录

时间就像海绵里面的水,挤一挤总是有的。





离线

页脚

工信部备案:粤ICP备20025096号 Powered by FluxBB

感谢为中文互联网持续输出优质内容的各位老铁们。 QQ: 516333132, 微信(wechat): whycan_cn (哇酷网/挖坑网/填坑网) service@whycan.cn