Navigation

    • Register
    • Login
    • Search
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    1. Home
    2. liangdi
    3. Best
    L
    • Profile
    • Following
    • Followers
    • Topics
    • Posts
    • Best
    • Groups

    Best posts made by liangdi

    • RE: 「RVBoards-哪吒」D1 Debian系统镜像和安装方法

      后面会发布针对 dd 等普通烧录工具的 img

      posted in RVBoards系列(RISC-V SoC Board)
      L
      liangdi
    • [Happy Hacking Nezha Board] 开始裸奔吧,少年
      每一个程序员都有一个 OS 梦!
                        - Liangdi
      

      前言

      我属于提前批拿到哪吒开发板的,兴奋之余开始研究如何去运行自己的裸机程序,美其名曰:操作系统.

      和 mcu 不一样, sbc 级别的 cpu 跑起来要复杂的多,不过好在系统级别的领域,不同的软件分工明确, 我们的裸机程序作为 kernel 部分,等着被引导就好.

      尽管 sbc 的系统很复杂, 不过要跑起我们的小小的代码,我们刚开始关心的东西不必要很多.

      走出第一步,才能看到后面的广阔天空.

      由于没有自己的 OS , 这里用 rt-thread 的 rt-smart 来作为实验验证对象.

      uboot

      和我们接触的第一个对象就是 uboot , uboot 是哪吒开发板的 bootloader,所以我们要和他搞好关系,了解他,才能让他帮我们完成 kernel 的引导.

      哪吒开发板的引导路径大致是这样: BROOM -> spl -> uboot -> [nand | mmc]

      通过简单的把玩,发现以下规律, BROOM 中的一级 bootloader 会检测 mmc 和 nand 设备, 如果存在 mmc 设备就会 load mmc boot 分区中的 spl 继续工作, nand 同理.

      开发板上有 256MB 的 nand flash, 可以有足够的空间存放我们的程序了, 所以就不考虑 mmc 了.

      哪吒的 uboot 和 nand

      开发板,接上串口工具,上电,串口中就可以看到系统启动信息了, 如果你什么都不操作就会进入 tina 环境了, 所以开机的时候,连按 s 键盘(和 PC 开机按 F2或者 F10 一样吧) 就可以进入 uboot 环境

      如下界面:

      先用 mtdparts 查看 nand 信息

      mdtparts default
      mtdparts
      # 输出如下:
      device nand0 <nand>, # parts = 4
       #: name                size            offset          mask_flags
       0: boot0               0x00100000      0x00000000      1
       1: uboot               0x00300000      0x00100000      1
       2: secure_storage      0x00100000      0x00400000      1
       3: sys                 0x0fb00000      0x00500000      0
      
      active partition: nand0,0 - (boot0) 0x00100000 @ 0x00000000
      
      defaults:
      mtdids  : nand0=nand
      mtdparts: mtdparts=nand:[email protected](boot0)ro,[email protected](uboot)ro,[email protected](secure_storage)ro,-(sys)
      

      从上面可以看到, nand 有四个分区, 前面两个 bootloader , 第三 secure_storage 和我们也没有什么关系, 第四个分区 sys 就是保存用户 os 的地方, 目前就是 tina linux 系统.

      查看一下 sys 中的信息

      ubi part sys
      ubi info l
      # 输出如下:
      Volume information dump:
              vol_id          0
              reserved_pebs   1
              alignment       1
              data_pad        0
              vol_type        4
              name_len        3
              usable_leb_size 258048
              used_ebs        1
              used_bytes      258048
              last_eb_bytes   258048
              corrupted       0
              upd_marker      0
              name            mbr
      Volume information dump:
              vol_id          1
              reserved_pebs   1
              alignment       1
              data_pad        0
              vol_type        3
              name_len        13
              usable_leb_size 258048
              used_ebs        1
              used_bytes      258048
              last_eb_bytes   258048
              corrupted       0
              upd_marker      0
              name            boot-resource
      Volume information dump:
              vol_id          2
              reserved_pebs   1
              alignment       1
              data_pad        0
              vol_type        3
              name_len        3
              usable_leb_size 258048
              used_ebs        1
              used_bytes      258048
              last_eb_bytes   258048
              corrupted       0
              upd_marker      0
              name            env
      Volume information dump:
              vol_id          3
              reserved_pebs   1
              alignment       1
              data_pad        0
              vol_type        3
              name_len        10
              usable_leb_size 258048
              used_ebs        1
              used_bytes      258048
              last_eb_bytes   258048
              corrupted       0
              upd_marker      0
              name            env-redund
      Volume information dump:
              vol_id          4
              reserved_pebs   29
              alignment       1
              data_pad        0
              vol_type        3
              name_len        4
              usable_leb_size 258048
              used_ebs        29
              used_bytes      7483392
              last_eb_bytes   258048
              corrupted       0
              upd_marker      0
              name            boot
      ...
      

      我们看到了一些熟悉的信息,系统镜像的分区表, 就是 tina sdk 打包出来的产物.

      那么 uboot 如何引导 nand 中的系统的呢?
      使用 printenv 查看一下 uboot 的环境变量,下面列出重要的部分:

      boot_normal=sunxi_flash read 45000000 ${boot_partition};bootm 45000000
      boot_partition=boot
      bootcmd=run setargs_nand_ubi boot_normal
      
      [email protected]_0:[email protected]_1:[email protected]_2:[email protected]_3:[email protected]_4:[email protected]_5:[email protected]_6:[email protected]_7:[email protected]_8:
      root_partition=rootfs
      
      setargs_nand_ubi=setenv bootargs ubi.mtd=${mtd_name} ubi.block=0,${root_partition} earlyprintk=${earlyprintk} clk_ignore_unused initcall_debug=${initcall_debug} console=${console} loglevel=${loglevel} root=${nand_root} rootfstype=${rootfstype} init=${init} partitions=${partitions} cma=${cma} snum=${snum} mac_addr=${mac} wifi_mac=${wifi_mac} bt_mac=${bt_mac} specialstr=${specialstr} gpt=1
      ubi_attach_mtdnum=3
      

      就以上这几行就可以了, 对我们来说关键作用的只有前 3 行.
      bootcmd 这个是 uboot 启动时候执行的变量, 内容是 run setargs_nand_ubi 和 boot_normal

      其中 setargs_nand_ubi 是设置 bootargs 的, 是 Linux 关心的东西.
      我们主要看 boot_normal

      boot_normal 大致含义是 flash 工具读取 ${boot_partition}(解析后是 boot) 位置的数据到内存 0x45000000 的位置, 然后 bootm 引导 0x45000000 位置的内核.

      所以,简单的方法就是我们把我们自己的 OS 程序,写入到 nand 中 boot 分区的位置,理论上就可以了.

      构建 nand 和引导自己的系统

      起初本来想用 xboot 的 xfel 工具将数据写入 nand, 然后发现没有实现,所以先跳过, 等后续支持了就会更方便了.

      tina sdk 中 device/config/chips/d1/configs/nezha_min/sys_partition.fex 这个文件是 pack 的配置信息 , 根据文件知道 pack 命令会把 boot.img 打包到 nand 的 boot 分区, 这个就是我们所要的,所以最简单的方法就是把我们自己的 bin 文件替换调 boot.img , 然后 tina sdk 中执行pack ,生成的产物tina_d1-nezha_min_uart0.img中就包含了我们的代码了.

      然后用全志的工具,将 tina_d1-nezha_min_uart0.img 烧录到哪吒主板上.第一步就完成了.

      这样就可以正常引导了么? 答案是否定的.

      在前面 uboot 的引导指令用的是 bootm 45000000, bootm 是引导 linux kernel 的,包含了引导协议的一些东西, 我们作为一个裸机程序,我们可以使用 uboot 的 go 命令之间跳转到 0x45000000处运行, 将 boot_normal 改为 sunxi_flash read 45000000 ${boot_partition};go 45000000 即可, 但是目前 tina 默认的 uboot 没有编译 go 指令, 进入 lichee/brandy-2.0/u-boot-2018 目录, 执行 make menuconfig, 然后在 Command line interface --> Boot commands 中选中 go 指令,保存后,重新编译, 在打包一次就可以了.

      tina uboot 默认的环境变量信息在文件 device/config/chips/d1/configs/nezha/env.cfg 里面,可以将 boot_normal 改好后再编译,就不用在 uboot 交互界面中修改环境变量了.

      上电

      d1-rt-smart.png
      bingo!

      少年, 下一步就开始在哪吒上运行你的 Dreeam OS 吧!

      最后的补充注意事项: RISC-V 芯片运行在 SBI 环境, S Mode 下,所以如果裸机程序 M 模式的代码是无法正常运行的.

      posted in RVBoards系列(RISC-V SoC Board)
      L
      liangdi
    • 用 Rust 探索 RISC-V 主板 D1 之 GPIO

      gpio 是单片机或者单板机和外部硬件沟通的桥梁,通过它可以控制外部硬件,可以建立通讯,可以获取传感器数据等

      D1 开发板和树莓派一样,对外引出了 40pin 引脚, 这些引脚包含3.3v,5v供电, GND , 以及几个未使用(NC)引脚, 然后就是我们要讲到的 GPIO 引脚.

      辅助利器

      开发 gpio 应用离不开几个利器

      1. 原理图

      全志已经开放原理图下载, 下载地址: https://developer.allwinnertech.com/downloads/resources/24

      根据原理图,我们可以看到 40pin 引脚与之对应的芯片端口
      IO 原理图

      这里要说明 D1 板子用 PCF8574 扩展了 8 个 IO 分别是 PP0-PP7 ,其他引出的 IO 来至 D1 这颗芯片, 并且由于 IO 端口不足, 40 Pin 里面物理 32pin 和 38pin 为未启用(NC), 树莓派中是两个 GPIO 端口
      io-expand.png

      IO 扩展

      2. debugfs

      第二个利器就是 debugfs Wiki: Debugfs

      debugfs 传承了 Linux 一切皆文件的理念,把内核更多信息通过文件系统展现给开发者,这里当然就包括了我们要的 gpio 信息

      debugfs 默认挂载在 /sys/kernel/debug , 如果没有挂载,可以执行 mount -t debugfs none /sys/kernel/debug 挂载

      在 /sys/kernel/debug 目录下有个 gpio 文件

      gpiochip0: GPIOs 0-223, parent: platform/2000000.pinctrl, 2000000.pinctrl:
       gpio-115 (                    |usb1-vbus           ) out lo 
       gpio-116 (                    |otg_det             ) in  lo 
       gpio-117 (                    |otg_id              ) in  hi 
       gpio-144 (                    |phy-rst             ) out hi 
       gpio-166 (                    |cd                  ) in  hi IRQ 
       gpio-202 (                    |wlan_hostwake       ) in  hi 
       gpio-204 (                    |wlan_regon          ) out lo 
       gpio-208 (                    |bt_wake             ) out lo 
       gpio-209 (                    |bt_hostwake         ) in  hi 
       gpio-210 (                    |bt_rst              ) out lo 
      
      gpiochip1: GPIOs 2020-2027, parent: i2c/2-0038, pcf8574, can sleep:
      
      

      里面内容显示了,板子上有两部分 gpio 组成,第一部分(gpiochip0)有 0-223 ,共224 个 gpio 端口,来自 D1 芯片, 第二部分(gpiochip1) 2020-2027 , 共8个 gpio 端口来自 PCF8574, 并且 8574 是通过 i2c 连接的 , 同时又显示了gpiochip0 中已经做了配置的 GPIO 接口

      D1 芯片中的 gpio 信息可以在 /sys/kernel/debug/pinctrl/2000000.pinctrl/pins 找到编号和芯片引脚名称(PA1,PB2等)的对应关系

      registered pins: 88
      pin 32 (PB0) 
      pin 33 (PB1) 
      pin 34 (PB2) 
      pin 35 (PB3) 
      pin 36 (PB4) 
      pin 37 (PB5) 
      pin 38 (PB6) 
      pin 39 (PB7) 
      pin 40 (PB8) 
      pin 41 (PB9) 
      pin 42 (PB10) 
      pin 43 (PB11) 
      pin 44 (PB12) 
      pin 64 (PC0) 
      pin 65 (PC1) 
      pin 66 (PC2) 
      pin 67 (PC3) 
      ...
      

      3. sysfs

      sysfs 和 debugfs 一样,通过文件系统,用户不仅可以查看信息,还可以操作硬件.

      在 /sys/class/gpio 目录下有四个文件,分别是 export,gpiochip0 ,gpiochip2020,unexport

      其中 gpiochip0,gpiochip2020 链接的是芯片两个gpio主控

      export 和 unexport 用来控制 gpio 的开启与关闭

      # 启用 2020 号 gpio 端口, 根据上面的信息,可以知道 2020 对应扩展 IO PP0 , 也就是 40pin 引脚中的 GPIO8
      echo 2020 > export 
      
      # 执行完 echo 2020 > export  后, 会在 /sys/class/gpio 中创建一个目录 /sys/class/gpio/gpio202 , 在这个目录里面就可以设置 gpio 的in 和 out 以及读取或者输出高低电平
      
      cd /sys/class/gpio/gpio2020
      # 设置为输出
      echo out > direction 
      # 设置高电平
      echo 1 > value
      # 设置低电平
      echo 0 > value
      
      # 执行代码后, 如果接了 LED 灯, 灯就会亮了又灭了
      
      

      Rust 在 gpio 方面的支持情况

      rust 有以下一些 crate

      1. linux-embedded-hal

      Implementation of the embedded-hal traits for Linux devices

      2. gpio-cdev

      基于 GPIO character device ABI 的库

      3. sysfs-gpio

      基于 sysfs 操作 gpio 的库, 原理如上面手动操作 sysfs 是一样的

      4. gpio-utils

      操作 gpio 的小工具程序, 基于 sysfs_gpio

      Rust Demo (使用cdev-gpio)

      • list gpios
      extern crate gpio_cdev;
      
      use gpio_cdev::*;
      
      fn main() {
          let  chip_iterator = match chips() {
              Ok(chips) => chips,
              Err(e) => {
                  println!("Failed to get chip iterator: {:?}", e);
                  return;
              }
          };
      
          for chip in chip_iterator {
              let chip = match chip {
                  Ok(chip) => chip,
                  Err(err) =>  panic!("Failed to open the chip: {:?}", err)
              };
                  println!(
                      "GPIO chip: {}, \"{}\", \"{}\", {} GPIO Lines",
                      chip.path().to_string_lossy(),
                      chip.name(),
                      chip.label(),
                      chip.num_lines()
                  );
                  for line in chip.lines() {
                      match line.info() {
                          Ok(info) => {
                              let mut flags = vec![];
      
                              if info.is_kernel() {
                                  flags.push("kernel");
                              }
      
                              if info.direction() == LineDirection::Out {
                                  flags.push("output");
                              }
      
                              if info.is_active_low() {
                                  flags.push("active-low");
                              }
                              if info.is_open_drain() {
                                  flags.push("open-drain");
                              }
                              if info.is_open_source() {
                                  flags.push("open-source");
                              }
      
                              let usage = if !flags.is_empty() {
                                  format!("[{}]", flags.join(" "))
                              } else {
                                  "".to_owned()
                              };
      
                              println!(
                                  "\tline {lineno:>3}: {name} {consumer} {usage}",
                                  lineno = info.line().offset(),
                                  name = info.name().unwrap_or("unused"),
                                  consumer = info.consumer().unwrap_or("unused"),
                                  usage = usage,
                              );
                          }
                          Err(e) => println!("\tError getting line info: {:?}", e),
                      }
                  }
                  println!();
          }
      }
      
      

      cdev-gpio 的接口中, 通过 chips() 获取 gpio控制器列表, D1 中的/dev/gpiochip0 和 /dev/gpiochip1

      每个 chip 中有 lines 列表,就是控制器下的 gpio 列表 line 就是 gpio 对象, 可以 进行 set_value , get_value ,以及设定输入输出等操作

      总体来说, Linux 对 gpio 封装已经很简单, rust 在这方面支持也比较完善. 后续文章还有 i2c, spi , uart 等方面的操作,欢迎关注,欢迎拍砖.

      posted in RVBoards系列(RISC-V SoC Board)
      L
      liangdi
    • [Happy Hacking Nezha Board] 小孩子才做选择,我全都要 BOOT

      乘胜追击

      前面完成引导 rt-smart 后, 开始继续其他功能的研究.

      常规我们使用 raspberry pi 以及其他 Linux 系统的时候, 一般我们的 kernel 等信息都是放在 /boot 目录下的,大多数会格式化成独立的一个分区.

      那么我们就照着这个方向去改造哪吒板子, 目前已经初见成效了, 我做了一个 demo 的 image , 供大家测试, 后续 RVBoards 会发布正式的 Debian 版本.

      • 下载地址: d1-multi-kernel

      说明

      镜像前面几个 1-3 分区是全志的预留的几个分区,占用空间很间,这里不去动他.

      第 4 分区是 vfat 格式的 boot 分区, kernel 和 dtbo 等文件存放在这里面

      demo 镜像 boot 分区文件说明

      • overlay : 存放 dtb overlay 文件
      • boot_debian.img debian 内核
      • boot_tina.img tina 内核
      • config.txt 引导配置文件
      • rt-smart rt-smart 执行程序

      config.txt 配置说明

      配置示例

      # mode 
      # 0 boot bare metal bin
      # 1 boot linux kernel
      mode=1
      bin=rt-smart
      kernel=boot_debian.img
      
      # dtb overlay
      # load overlay/${dtoverlay}.dtbo
      dtoverlay=test-overlay
      
      # uboot vars
      # for debian
      mmc_root=/dev/mmcblk0p6
      # for tina
      #mmc_root=/dev/mmcblk0p5
      

      详细说明

      • mode:

        配置引导模式 0 为引导二进制程序 1 为引导linux 内核 (目前这个版本的 内核文件需要使用 mkbootimage 打包生成,就是 tina sdk 中 pack 命令生成的 boot.img 文化)

      • bin

        mode=0 的时候引导的文件

      • kernel

        mode=1 的时候引导的文件

      • dtoverlay

        dtb overlay 配置, 将会加载 overlay/${dtoverlay}.dtbo 这个文件,后续将会支持多个文件加载

      • mmc_root

        这个是作为 bootargs 中 root 参数传递给内核的,告诉内核 root 在什么分区,默认是 /dev/mmcblk0p5 , demo 镜像中有多个内核,多个 rootfs ,所以需要配置一下.

      • 注意

        • 配置项"="两边不能有空格
        • config.txt 是作为 uboot 的环境变量加载的,可以配置其他变量覆盖 uboot 内部的变量

      原理

      主要就是利用 uboot 的 fatload 这个指令,从 mmc 中 vfat 文件系统中加载指定文件到内存中使用.

      用到相关的指令 fatload, env import ,fdt 等

      核心配置

      # demo 镜像中的 
      bootcmd=run boot_check setargs_mmc boot_mmc
      # 其中 setargs_mmc 是全志默认的,设置 mmc 加载的 bootrags 的指令
      
      # boot_check 检测 mmc 是否启用,然后加载 config.txt 文件,再加载 dtbo 文件
      boot_check=run card_init;mmcinfo;mmc part;fatload mmc ${mmc_dev}:${mmc_boot_part} 47000000 config.txt;env import -t 47000000 ${filesize}; test -n "$dtoverlay" && fatload mmc ${mmc_dev}:${mmc_boot_part} 48000000 overlay/${dtoverlay}.dtbo; fdt apply 48000000
      
      # boot_mmc 就是根据 mode 引导不同系统了
      boot_mmc=if test ${mode} -eq 0; then fatload mmc ${mmc_dev}:${mmc_boot_part} 45000000 ${bin}; go 45000000; else fatload mmc ${mmc_dev}:${mmc_boot_part} 45000000 ${kernel}; bootm 45000000; fi
      
      

      原理和实现其实很简单, 后续还可以继续改进,支持多个 dtbo 加载, tftp 加载(方便快速调试) 等等.

      后记

      完成多系统引导就这么简单了, 后续文章我会再写一个 dtb overlay 的 demo.
      注意事项: demo 镜像中, debain 的 rootfs 大小太小,更大空间,需要自行处理一下.

      posted in RVBoards系列(RISC-V SoC Board)
      L
      liangdi
    • 「RVBoards-哪吒」开启 SSH 和 VNC 远程访问,摆脱烦人的鼠标键盘显示器

      单板机,上手比较烦人的就是要准备配套的鼠标键盘以及显示器,通过 SSH 或者 VNC 就可以在自己电脑上远程进行操作,更加方便.

      准备材料

      • 哪吒开发板 (RVBoards Debian 系统)
      • 串口调试线
      • 网络已经联通(联网不在这里讨论,可以另外写一篇文章了)

      开启 SSH

      系统默认配置禁用了 root 远程 ssh 登陆, 如果是普通权限用户没有这个问题.

      • 开启 root ssh 远程登陆

        编辑 /etc/ssh/sshd_config

        将 #PermitRootLogin without-password 修改为 PermitRootLogin yes

        systemctl restart sshd 重启 ssh 服务即可

      • ssh 访问

        使用 ssh [email protected] 就可以登陆访问了,默认密码是 rvboards

        使用 ssh-copy-id [email protected] 可以设置公钥访问,省掉密码输入

      开启 VNC 服务

      Linux 上有很多 vnc 服务程序,这里我们选择 tigervnc

      • 安装软件
      apt update
      apt install tigervnc-standalone-server -y
      
      • tigervnc server 常规使用方法

        启动服务: vncserver -localhost no -display :1

        上述命令启动 vncserver 并且使用 :1 编号的显示器, :0 默认被启动的 xserver使用了, -localhost no 表示可以远程访问

        第一次启用的时候会提示输入密码, 建议使用和 root 一样的密码,便于记忆, 同时可以配置使用 linux 系统认证, 这个哪吒玩家可以自己去查看相关资料.

        查看服务: vncserver -list

        TigerVNC server sessions:
          X DISPLAY #	RFB PORT #	PROCESS ID	SERVER
          :1         	5901      	647       	Xtigervnc
        

        停止服务 vncserver -kill

        vncserver -kill :1 
        # 结束 :1 display 的 vnc 服务
        

        配置分辨率, 使用 -geometry 1280x800 参数

        目前哪吒支持的分辨率

         1920x1080     60.00  
         1600x1200     60.00  
         1680x1050     60.00  
         1400x1050     60.00  
         1360x768      60.00  
         1280x1024     60.00  
         1280x960      60.00  
         1280x720      60.00  
         1024x768      60.00  
         800x600       60.00  
         640x480       60.00  
        
        
      • 配置 VNC server 开机启动

        开机启动最简单的方式是在 /etc/rc.local 中加入启动脚本,以下是示例

        echo "start vnc server"
        export HOME=/root
        /usr/bin/vncserver -localhost no -display :1 -geometry 1280x800
        echo "vnc server started"
        # 这里需要先配置 HOME 环境变量, vncserver 需要
        
        
      • VNC 远程连接
        VNC 有很多客户端, ReadVNC 的 VNC Viewer 推荐一下,并且有 Chrome 的插件, 输入ip和端口号就可以连接了,密码就是初次启动 vncserver 配置的密码

      vnc-login.png

      vnc-viewer.png

      总结

      linux 生态下, 远程访问是比较容易的, SBC 级别的设备,大多比较精简,需要自己去安装配置,借此文抛砖引玉,欢迎一起交流.

      吐槽一下目前系统层面对 D1 的显示驱动优化的比较差, 性能弱,使用 VNC 操作 gui 大大提升用户体验.

      posted in RVBoards系列(RISC-V SoC Board)
      L
      liangdi