【罗马不起多】D1h开发板评测

D1h开发板评测

百问网D1h双屏异显开发套件是采用全志科技首款RISC-V处理器D1-H,该芯片是基于RISC-V指令集的芯片,集成了阿里平头哥64位C906核心,支持RVV,1GHz+主频,可支持Linux、RTOS等系统。同时支持最高4K的H.265/H.264解码,内置一颗HiFi4 DSP,最高可外接2GB DDR3,可以应用于智慧城市、智能汽车、智能商显、智能家电、智能办公和科研教育等多个领域。

本次板子采用的主控芯片是全志D1H

这里我们先快速的安装SDK

快速使用Tina-SDK 指南

  • Tina-SDK开发HOST主机环境主要基于ubuntu-16.04及以上系统,其它系统暂未做过验证,请尽量使用 ubuntu-18.04。

获取配套开发文档

Tina-SDK提供的配套开发资料非常丰富,有驱动开发有组件开发等,大家可以直接点击下方的链接进行下载。

获取Tina-SDK源码

网盘获取

  • 由于整个Tina-SDK V2.0工程比较大,所以我们单独将其分卷压缩存放至 网盘内,可以点击此 传输链接获取:文件下载-奶牛快传 Download |CowTransfer

  • 下载成功后,需要先拷贝到 Ubuntu系统目录下,请尽量准备足够的硬盘存储空间,建议至少保留 100G以上剩余空间。

  • 之后进入到 ubuntu系统目录下 执行解压缩命令cat tina-d1-h.tar.gz.* | tar zvx等待解压缩完成。

  • 解压缩完成后,我们就可以开始配置HOST主机环境了

全志客户服务获取

配置主机环境

ubuntu-16.04

安装命令:

sudo apt-get update
sudo apt-get 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

ubuntu-18.04

安装命令:

sudo apt-get update
sudo apt-get 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
sudo apt-get install libc6:i386 libstdc++6:i386 lib32ncurses5 lib32z1

配置&编译

1.进入获取完成的Tina-SDK V2.0目录下,执行 cd tina-d1-h/即可进入目录内。 2. 首先执行 source build/envsetup.sh 命令设置环境变量等待配置完成。会提示 Setup env done! Please run lunch next. 此段命令。 3. 选择你要编译的目标方案配置名称,比如输入 lunch d1-h_nezha-tina说明指定编译d1-h tina方案,当然也可以输入 lunch命令显示所有的方案,在弹出的对话框中输入你要编译的方案序号。 4. 配置好方案名称后,就可以执行 make命令来开始编译了,整个编译过程比较漫长,可以加上 *-JN *参数来加速编译,这里N指的是CPU的个数一般可以以 CPU个数 x 线程数 进行指定。 5. 编译完成后,相应的文件会输出到 **/out/d1_nezha-tina/ 目录下,之后我们继续执行 pack打包命令,来进行打包操作。

book@100ask:~$ cd tina-d1-h/
book@100ask:~/tina-d1-h$ source build/envsetup.sh
Setup env done! Please run lunch next.
book@100ask:~/tina-d1-h$ lunch
 
You're building on Linux
 
Lunch menu... pick a combo:
     1. d1-h_nezha_min-tina
     2. d1-h_nezha-tina
     3. d1s_nezha-tina
 
Which would you like?: 2============================================TINA_BUILD_TOP=/home/book/tina-d1-hTINA_TARGET_ARCH=riscvTARGET_PRODUCT=d1-h_nezhaTARGET_PLATFORM=d1-hTARGET_BOARD=d1-h-nezhaTARGET_PLAN=nezhaTARGET_BUILD_VARIANT=tinaTARGET_BUILD_TYPE=releaseTARGET_KERNEL_VERSION=5.4TARGET_UBOOT=u-boot-2018TARGET_CHIP=sun20iw1p1============================================
no buildserver to clean[1] 20070
book@100ask:~/tina-d1-h$ make -j16

如上示例,我进入 tina-d1-h 目录 之后使用lunch命令 显示所有的支持方案,选中 第二个 d1-h_nezha-tina 之后 执行 make -j16开始编译,这里给大家提醒一下 我们的 东山哪吒STU 开发板支持 方案1. d1-h_nezha_min-tina 方案2. d1-h_nezha-tina

打包&烧写

编译完成后,我们就可以执行 pack命令,将编译好的固件打包成一个 img 文件,用于后续烧写操作,固件路径在 /out/d1_nezha-tina/tina_d1-nezha_uart0.img 以 方案名称_串口节点.img 进行命名。 最后我们就可以参考页面左侧 快速开始 内 烧写 全志原厂 系统的说明文档进行烧写操作啦。

获取交叉编译工具链

Tina-SDK可以使用专门的配套教程编译工具链 单独编译组件,编译内核驱动 或者 编写相应的应用程序,可以直接点击链接进行下载。

下载成功后,拷贝到ubuntu系统内,执行 tar -xvf riscv64-glibc-gcc-thead_20200702.tar.xz进行解压缩,等待解压缩完成后,可以执行如下命令设置环境变量,比如解压到 家目录下 也就是/home/book目录。则单独执行tar -xvf riscv64-glibc-gcc-thead_20200702.tar.xz -C ~。 之后执行如下命令在终端下执行环境变量,再设计之前需要您确认没有设置其它的环境变量。

book@100ask:~$ export ARCH=riscv
book@100ask:~$ export CROSS_COMPILE=riscv64-unknown-linux-gnu-
book@100ask:~$ export PATH=$PATH:/home/book/riscv64-glibc-gcc-thead_20200702/bin
到了这里我们就可以获得烧录的镜像
烧录的镜像名字叫做tina_d1-h-nezha_uart0.img

烧写固件至TF卡

我们提供的系统镜像有多种不同的镜像类型,主要以全志原厂Tina-SDK构建出来的系统,和使用Buildroot构建出来的两种不同类型的系统镜像。本文先以介绍全志原厂Tina-SDK构建出来的系统进行演示,后续在提供Buildroot构建出来的系统烧写步骤。

准备工作

  1. 东山哪吒STU开发板主板 x1

  2. TF卡读卡器 x1

  3. 8GB以上的 micro TF卡 x1

  4. 全志原厂Tina-SDK烧写所用的烧录工具:点击下载:文件下载-奶牛快传 Download |CowTransfer

  5. SDcard专用格式化工具:点击下载: 文件下载-奶牛快传 Download |CowTransfer

烧录Tina-SDK镜像

  1. 下载需要的镜像文件:点此传输链接:文件下载-奶牛快传 Download |CowTransfer 。下载任意镜像,然后参考下面步骤进行烧写。

  2. 使用 SD Card Formatter.exe格式化插入的 Micro TF卡。

打开原厂专用烧录工具,参考下图进行烧写操作。 打开烧录软件 PhoenixCard,选择烧录的固件,将内存卡通过读卡器插入电脑中

并不能保证每台电脑和每个人的内存卡都是可以烧录的,烧录失败的话建议购买官方的镜像卡。 等待提示烧录结束,之后拔下卡 插入到 东山哪吒STU背面TF卡卡槽内,按下进去,继续进行如下步骤 启动开发板进入系统。

· 如果需要自行从头编译构建 全志原厂Tina-SDK V2.0系统,请移步至左侧 Tina-SDK V2.0开发指南页面。

上电启动系统

1. 连接串口线

将配套的TypeC线一段连接至开发板的串口/供电接口,另一端连接至电脑USB接口,连接成功后板载的红色电源灯会亮起。 默认情况下系统会自动安装串口设备驱动,如果没有自动安装,可以使用驱动精灵来自动安装。

· 对于Windows系统 此时Windows设备管理器 在 端口(COM和LPT) 处会多出一个串口设备,一般是以 USB-Enhanced-SERIAL CH9102开头,您需要留意一下后面的具体COM编号,用于后续连接使用。

如上图,COM号是96,我们接下来连接所使用的串口号就是96。

· 对于Linux系统 可以查看是否多出一个/dev/tty<> 设备,一般情况设备节点为 /dev/ttyACM0 。 !

2. 打开串口控制台

获取串口工具

使用Putty或者MobaXterm等串口工具来开发板设备。

· 其中putty工具可以访问页面 PuTTY: a free SSH and Telnet client 来获取。

· MobaXterm可以通过访问页面 https://mobaxterm.mobatek.net/ 获取 (推荐使用)。

使用putty登录串口

使用Mobaxterm登录串口

打开MobaXterm,点击左上角的“Session”,在弹出的界面选中“Serial”,如下图所示选择端口号(前面设备管理器显示的端口号COM21)、波特率(Speed 115200)、流控(Flow Control: none),最后点击“OK”即可。步骤如下图所示。 注意:流控(Flow Control)一定要选择none,否则你将无法在MobaXterm中向串口输入数据

3. 进入系统shell

使用串口工具成功打开串口后,可以直接按下 Enter 键 进入shell,当然您也可以按下板子上的 Reset复位键,来查看完整的系统信息。

这里之后我们就可以进行开发了

由于WIFI的引脚在原理图中又改变

所以我们要调用WIFI的话就需要在设备树里面进行修改

设备树在这个路进里面

这个时候我们需要对引脚进行修改

修改这个引脚设置之后我们需要在MAKE MENUCONFIG中修改XR829-40M为XR829就能启动WIFI设备

这个设备可以看到WIFI WLANO

这个时候就可以证明我们配置成功了

wifi_scan_results_test

wifi_connect_ap_test ESP8266 12345678

然后通过这两个指令就可以连接WIFI

这样我们就能连接WIFI了

音乐播放我们可以采用aplay指令

amixe -Dhw:audiocodec cset name=‘LINEOUT Switch’ 1

指令我们可以用喇叭播放

然后这样就能播放音乐了

HDMI视频播放我们先进行HDMI显示

cd /sys/kernel/debug/dispdbg && echo disp0 > name; echo switch1 > command;

echo 4 10 0 0 0x4 0x101 0 0 0 8 > param; echo 1 > start;

视频播放的格式采用的是.mkv

这个是启动的图片

我们是在UBOOT的开机图片里面设备

读取红外的遥控的按键值

clip_image030

在设备树中启动红外接收引脚

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <linux/input.h>

int main(int argc, char *argv[])
{
  struct input_event in_ev = {0};

  int fd = -1;

  /* 校验传参 */

  if (2 != argc) {
    fprintf(stderr, "usage: %s <input-dev>\n", argv[0]);
    exit(-1);
  }

  /* 打开文件 */

  if (0 > (fd = open(argv[1], O_RDONLY))) {
    perror("open error");
    exit(-1);
  }

  for ( ; ; ) {
    /* 循环读取数据 */
    if (sizeof(struct input_event) !=
      read(fd, &in_ev, sizeof(struct input_event))) {
      perror("read error");
      exit(-1);
    }
      
    printf("type:%d code:%d value:%d\n",in_ev.type, in_ev.code, in_ev.value);
  }

}

这个是一个读取红外按键值的函数

clip_image032

由图中可知

获取的红外的按键值是69

#include "lvgl/lvgl.h"
#include "lvgl/demos/lv_demos.h"
#include "lv_drivers/display/fbdev.h"
#include "lv_drivers/indev/evdev.h"
#include <unistd.h>
#include <pthread.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <linux/input.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/time.h>

#define DISP_BUF_SIZE (600 * 1024)

LV_IMG_DECLARE(lvgl_img1); 
LV_IMG_DECLARE(lvgl_img2); 
LV_IMG_DECLARE(lvgl_img3); 
LV_IMG_DECLARE(lvgl_img4); 

int main(int argc, char *argv[])
{
  struct input_event in_ev = {0};
  int fd = -1;
    
  /* 校验传参 */
  if (2 != argc) {
    fprintf(stderr, "usage: %s <input-dev>\n", argv[0]);
    exit(-1);
  }

  /* 打开文件 */
  if (0 > (fd = open(argv[1], O_RDONLY))) {
    perror("open error");
    exit(-1);
  }
  /*LittlevGL init*/
  lv_init();
    
  /*Linux frame buffer device init*/
  fbdev_init();
    
  /*A small buffer for LittlevGL to draw the screen's content*/
  static lv_color_t buf1[DISP_BUF_SIZE];
  static lv_color_t buf2[DISP_BUF_SIZE];
    
  /*Initialize a descriptor for the buffer*/
  static lv_disp_draw_buf_t disp_buf;
  lv_disp_draw_buf_init(&disp_buf, buf1, buf2, DISP_BUF_SIZE);
    
  /*Initialize and register a display driver*/
  static lv_disp_drv_t disp_drv;
  lv_disp_drv_init(&disp_drv);
  disp_drv.draw_buf  = &disp_buf;
  disp_drv.flush_cb  = fbdev_flush;
  disp_drv.hor_res  = 250;
  disp_drv.ver_res  = 250;
  lv_disp_drv_register(&disp_drv);
  evdev_init();
  static lv_indev_drv_t indev_drv_1;
    
  lv_indev_drv_init(&indev_drv_1); /*Basic initialization*/
  indev_drv_1.type = LV_INDEV_TYPE_POINTER;
    
  /*This function will be called periodically (by the library) to get the mouse position and state*/
  indev_drv_1.read_cb = evdev_read;
  lv_indev_t *mouse_indev = lv_indev_drv_register(&indev_drv_1);
  /*Set a cursor for the mouse*/
  //LV_IMG_DECLARE(mouse_cursor_icon)
  //lv_obj_t * cursor_obj = lv_img_create(lv_scr_act()); /*Create an image object for the cursor */
  //lv_img_set_src(cursor_obj, &mouse_cursor_icon);      /*Set the image source*/
  //lv_indev_set_cursor(mouse_indev, cursor_obj);       /*Connect the image object to the driver*/
   lv_obj_t *img;
    
  /*Create a Demo*/
  //lv_demo_widgets();
  img = lv_img_create(lv_scr_act());                               /* 创建图片部件 */
  lv_img_set_src(img, &lvgl_img1);                                 /* 设置图片源 */
  lv_obj_align(img, LV_ALIGN_TOP_LEFT,0, 0);                  /* 设置图片位置 */
  lv_obj_update_layout(img);                                   /* 更新图片参数 */
  img = lv_img_create(lv_scr_act());                               /* 创建图片部件 */
  lv_img_set_src(img, &lvgl_img2);                                 /* 设置图片源 */
  lv_obj_align(img, LV_ALIGN_TOP_LEFT,0, 0);                  /* 设置图片位置 */
  lv_obj_update_layout(img);                                   /* 更新图片参数 */
  img = lv_img_create(lv_scr_act());                               /* 创建图片部件 */
  lv_img_set_src(img, &lvgl_img3);                                 /* 设置图片源 */
  lv_obj_align(img, LV_ALIGN_TOP_LEFT,0, 0);                  /* 设置图片位置 */
  lv_obj_update_layout(img);   
  img = lv_img_create(lv_scr_act());                               /* 创建图片部件 */
  lv_img_set_src(img, &lvgl_img4);                                 /* 设置图片源 */
  lv_obj_align(img, LV_ALIGN_TOP_LEFT,0, 0);                  /* 设置图片位置 */
  lv_obj_update_layout(img);                                  /* 更新图片参数 */
  /*Handle LitlevGL tasks (tickless mode)*/

  while(1) {
   if (sizeof(struct input_event) !=
      read(fd, &in_ev, sizeof(struct input_event))) {
      perror("read error");
      exit(-1);
    }

    if(in_ev.type == 4 &&  in_ev.code==4)
    {
      if(in_ev.value == 0x18){
          img = lv_img_create(lv_scr_act());                               /* 创建图片部件 */
          lv_img_set_src(img, &lvgl_img1);                                 /* 设置图片源 */
          lv_obj_align(img, LV_ALIGN_TOP_LEFT,0, 0);                  /* 设置图片位置 */
          lv_obj_update_layout(img);                                   /* 更新图片参数 */
      }

      if(in_ev.value == 0x52){
          img = lv_img_create(lv_scr_act());                               /* 创建图片部件 */
          lv_img_set_src(img, &lvgl_img2);                                 /* 设置图片源 */
          lv_obj_align(img, LV_ALIGN_TOP_LEFT,0, 0);                  /* 设置图片位置 */
          lv_obj_update_layout(img);                                   /* 更新图片参数 */
      }

      if(in_ev.value == 0x08){
          img = lv_img_create(lv_scr_act());                               /* 创建图片部件 */
          lv_img_set_src(img, &lvgl_img3);                                 /* 设置图片源 */
          lv_obj_align(img, LV_ALIGN_TOP_LEFT,0, 0);                  /* 设置图片位置 */
          lv_obj_update_layout(img);                                   /* 更新图片参数 */
      }

       if(in_ev.value == 0x5a){
          img = lv_img_create(lv_scr_act());                               /* 创建图片部件 */
          lv_img_set_src(img, &lvgl_img4);                                 /* 设置图片源 */
          lv_obj_align(img, LV_ALIGN_TOP_LEFT,0, 0);                  /* 设置图片位置 */
          lv_obj_update_layout(img);                                   /* 更新图片参数 */
      } 
    }
    lv_timer_handler();
    usleep(5000);
  }
  return 0;
}

/*Set in lv_conf.h as `LV_TICK_CUSTOM_SYS_TIME_EXPR`*/
uint32_t custom_tick_get(void)
{

  static uint64_t start_ms = 0;

  if(start_ms == 0) {
    struct timeval tv_start;
    gettimeofday(&tv_start, NULL);
    start_ms = (tv_start.tv_sec * 1000000 + tv_start.tv_usec) / 1000;
  }
  struct timeval tv_now;
  gettimeofday(&tv_now, NULL);
  uint64_t now_ms;
  now_ms = (tv_now.tv_sec * 1000000 + tv_now.tv_usec) / 1000;
  uint32_t time_ms = now_ms - start_ms;
  return time_ms;
}

然后我们在LVGL函数中就可以用红外控制了