Navigation

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

    liangdi

    @liangdi

    8
    Reputation
    12
    Posts
    11
    Profile views
    1
    Followers
    0
    Following
    Joined Last Online

    liangdi Follow

    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

    Latest posts made by liangdi

    • [Happy Hacking Nezha Board] 掌握 Device Tree Oerlay 的魔法

      Device Tree 是目前嵌入式 Linux 系统最常用的设备解耦工具, 所以要玩转嵌入式 Linux , 这个东西必须掌握.

      DTB, DTS , DTSI?

      在 tina sdk 代码中, 有 board.dts , sun20iw1p1.dtsi 这些文件, 这些就是 device tree 的源文件,或者说描述文件.

      dts 通过 dtc 这个编译器可以编译成 dtb 以及后面我们要用到的 dtbo(dtb overlay) , 它们是二进制文件, Linux 和 uboot 可以使用.

      DTC

      Device Tree Compiler , dts 的编译工具, Linux 下面可以使用包管理工具按照

      # redora
      sudo dnf install dtc
      
      # ubuntu
      
      sudo apt install device-tree-compiler
      
      

      windows 参考(未验证):
      https://github.com/lbmeng/dtc

      dtb overlay 示例代码

      在之前给出的 demo 镜像中, pwm7 这个设备的驱动部分在 dts 中被注释了, 所以我们尝试用 dtb overlay 给他弄回来.

      dtbo 的编译只要 dtc 就可以, 但是我们会看到 dtsi 中有 c 语言的 #include 宏,所以还会用到 c编译根据展开宏,如果没有 #include ,就不需要.

      使用 #include 宏展开示例, include 里面都是 dt-bindings 目录下的文件,该目录在 tina 中的位置是: lichee/linux-5.4/include , 你要展开需要将 lichee/linux-5.4/include/dt-bindings 拷贝到 dts 目录中来

      cpp -nostdinc -I. -undef -x assembler-with-cpp board.dts > board-with-include.dts
      
      

      执行后, board-with-include.dts 就是 include 展开后的代码.

      pwm7-overlay.dts 示例代码

      /dts-v1/;
      /plugin/;
      
      / {
          [email protected] {
          target-path = "/soc/[email protected]";
              __overlay__ {
                   pwm7_pin_a: [email protected] {
                      pins = "PD22";
                      function = "pwm7";
                      drive-strength = <10>;
                      bias-pull-up;
                  };
      
                  pwm7_pin_b: [email protected] {
                      pins = "PD22";
                      function = "gpio_in";
                  };
              };
          };
      
          [email protected] {
              target-path = "/soc/[email protected]";
             
              __overlay__ {
                  pinctrl-names = "active", "sleep";
                  pinctrl-0 = <&pwm7_pin_a>;
                  pinctrl-1 = <&pwm7_pin_b>;
                  status = "okay";
              };
          };
      
      };
      

      头部是作为一个 overlay 的描述, 和 dts 相比多了 /plugin/; 这个节点

      /dts-v1/;
      /plugin/;
      

      后面同样有个 / 根节点, 然后需要覆盖的地方用 [email protected] 作为节点名称

      fragment 里面 target-path 为需要覆盖的节点路径, 也可以用 target 使用的是引用.

      后面 overlay 里面就是需要覆盖的属性.

      编译

      dtc -I dts -O dtb -o ./pwm7-overlay.dtbo ./pwm7-overlay.dts
      

      这样得到的 pwm7-overlay.dtbo 文件就是我们所要的. 可以用
      fdtdump ./pwm7-overlay.dtbo 查看结果

      测试

      一个测试程序 (pwm.sh, 来自 RVBoards) 和蜂鸣器扩展版

      #!/bin/bash
      #pwm 节点
      pwmnode=pwm$1
      #输出提示pwm$1 通道
      echo  /sys/class/pwm/pwmchip0/${pwmnode}
      #申请pwm$1 通道
      echo $1 > /sys/class/pwm/pwmchip0/export
      #指定pwm$1 通道的频率
      echo $2 > /sys/class/pwm/pwmchip0/${pwmnode}/period
      #指定pwm$1 通道的占空比
      echo $3 > /sys/class/pwm/pwmchip0/${pwmnode}/duty_cycle
      #使能pwm$1 通道 
      echo 1 > /sys/class/pwm/pwmchip0/${pwmnode}/enable
      #使能pwm$1 通道 工作时间10s
      sleep 10
      #失能pwm$1 通道 
      echo 0 > /sys/class/pwm/pwmchip0/${pwmnode}/enable
      #等待pwm$1 通道 关闭
      sleep 1
      #注销pwm$1 通道
      echo $1 > /sys/class/pwm/pwmchip0/unexport
      

      在没有配置 dtb overlay 的系统中执行

      # 设置 7 号 pwm 引脚数据
      ./pwm.sh 7 300000 150000
      

      会出现错误

      然后将 pwm7-overlay.dtbo 复制到 boot 分区的 overlay 目录下, 在编辑 config.txt 添加配置
      dtoverlay=pwm7-overlay , 配置中不需要加 .dtbo, 系统会自动添加.

      重启后, 在执行
      ./pwm.sh 7 300000 150000 , 蜂鸣器就会响了.

      如果没有蜂鸣器扩展版,可以查看 /sys/class/pwm/ 里面的内容,进行前后对比,也会发现 dtb overlay 生效了.

      后记

      dtb 以及相关技术需要去掌握,掌握了就可以把开发板玩的更溜了, 如果你去使用各种大的扩展板, 基本都会涉及到 dtb overlay.

      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
    • RE: [Happy Hacking Nezha Board] 开始裸奔吧,少年

      rt-smart 代码: https://gitlab.eduxiji.net/lizhirui/project325618-83178.git
      用 riscv64-unknown-elf 的工具链就可以

      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
    • D1 tina Docker 编译环境制作和使用

      d1 的 tina 环境由于工具链比较老旧, 很多开发者的机器上的环境没法正常使用
      所以,我写一篇使用 Docker 编译 tina 的文章,继续抛砖引玉,欢迎交流.
      PS: 还是希望全志官方升级一下工具链版本

      准备工作

      • 安装好 docker , 执行 docker info 可以查看是否安装正常
      • 下载好 tina sdk 的代码, 参考: tina sdk 下载

      使用 Docker 编译

      # 假设下载的 tina-sdk 目录是 /opt/tina-sdk
      # 执行如下 docker 命令
      docker run  -v /opt/tina-sdk:/sdk -it liangdi/d1-tina-build-env /bin/bash
      # 第一次执行的时候,需要下载镜像,会耗时比较久一点
      # 执行完上面 docker 命令后, 会将本机 /opt/tina-sdk 映射到 docker 中的 /sdk 下,就可以在 docker 中编译 tina 了
      cd /sdk
      source ./build/envsetup.sh
      # 选择编译内容
      lunch
      
      # 需要设置 FORCE_UNSAFE_CONFIGURE 变量解决 root 检测, 后面 -jx  x为配置编译线程数量,可以根据 cpu 数量来配置
      make FORCE_UNSAFE_CONFIGURE=1 -j8
      # 备注: 第一次编译,会编译一批 host 的依赖比较慢,但是编译一次后,下次重新编译就会跳过了,速度会快很多
      
      # 打包
      pack
      
      
      

      以上就可以正常编译 d1 的 tina 了, 编译完成后, 在本机 tina-sdk 目录下的 out 目录中就可以看到编译产物了, 采用路径映射的方式,本机更新代码后,再运行 docker , docker 里面就是最新的代码

      附上 Dockerfile

      # D1 tina build env
      
      FROM ubuntu:14.04
      RUN apt update
      RUN apt install build-essential subversion git-core libncurses5-dev zlib1g-dev gawk flex quilt libssl-dev xsltproc libxml-parser-perl mercurial bzr ecj cvs unzip lib32z1 lib32z1-dev lib32stdc++6 libstdc++6 -y
      RUN apt install bc busybox wget -y
      

      可以自行修改构建, 完善这个 docker

      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
    • RE: 「RVBoards-哪吒」D1 Debian系统镜像和安装方法

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

      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
    • RE: 「RVBoards-哪吒」D1 Debian系统镜像和安装方法

      @王哥 在 「RVBoards-哪吒」Allwinner D1 Debian系统镜像和安装方法 中说:

      07e82d95f363afa8079047a197620511

      是的 我已经下载 :blush:

      posted in RVBoards系列(RISC-V SoC Board)
      L
      liangdi
    • RE: 「RVBoards-哪吒」D1 Debian系统镜像和安装方法

      目前第一轮测试下来反馈一下:
      测试环境无网络.

      1. 无 lsusb 命令, 这个对硬件使用来说挺重要的
      2. WIFI 设备无法使用
      • 无 iw* 相关iang命令
      • connmanctl 无法正常操作 wifi 设备
      1. 蓝牙无法正常使用
      • hcitool dev 无法找到设备
      1. 烧录系统的改进(这个应该在官方计划中)
      posted in RVBoards系列(RISC-V SoC Board)
      L
      liangdi