EVM3

发布于2021年3月中旬

本次发布带来的更新是参照IoT.js框架标准,实现了EVM自己的后端框架。同时,基于这套框架,我们已经移植到硬件开发板上,大家可以克隆仓库到本地,然后部署到开发板中进行实际硬件体验。

本次移植的开发板是博流智能基于BL602核心开发板,基于RISC-V核的低功耗、高可靠Wi-Fi+BLE二合一SoC芯片。内存方面有276KB RAM/128KB ROM。关于该板子的详细介绍请移步:博流智能

BL602

快速上手

1. 克隆仓库

  1. git clone https://gitee.com/scriptiot.com/evm3
  2. git submodule update --init --recursive

2. 编译固件

  1. cd bsp/bouffalolab
  2. ./genromap

输出信息:

  1. AR build_out/freertos_riscv_ram/libfreertos_riscv_ram.a
  2. AR build_out/lwip/liblwip.a
  3. LD build_out/app.elf
  4. ==========================
  5. Generating BIN File to /home/~/bsp/bouffalolab/build_out/app.bin
  6. Traceback (most recent call last):
  7. File "flash_build.py", line 1396, in <module>
  8. eflash_loader_cfg = os.path.join(app_path, bin_build_out_path, "eflash_loader_cfg.ini")
  9. File "shutil.py", line 245, in copy
  10. File "shutil.py", line 121, in copyfile
  11. FileNotFoundError: [Errno 2] No such file or directory: '/home/~/sdk/bl_iot_sdk/customer_app/app/build_out/eflash_loader_cfg.ini'
  12. [32048] Failed to execute script flash_build
  13. make: *** [/home/~/bsp/bouffalolab/../../sdk/bl_iot_sdk/make_scripts_riscv/project.mk:191all] 错误 255

当看到

  1. LD build_out/app.elf
  2. ==========================
  3. Generating BIN File to /home/~/bsp/bouffalolab/build_out/app.bin

说明已经编译成功,下面几行是找不到eflash loader的配置文件,无法将零散的bin进行打包,打包的文件主要用于ota,和把所有bin合并成一个2M的bin。总之,这不影响我们最终烧录进板子。

3. 下载烧写工具

Windows

Windows烧录工具在本仓库的子仓库中,如果你已经执行过克隆仓库中的git submodule update --init --recursive命令了,那么在仓库以下路径:

  1. ~/sdk/bl_iot_sdk/tools/flash_tool/BLDevCube.exe

Linux

如果你使用的是Ubuntu/Deepin/UOS等Linux操作系统,请移步:https://dev.bouffalolab.com/download

MacOS

请移步博流智能开发者中心下载:https://dev.bouffalolab.com/download

4. 设置参数

参照博流智能官方开发者使用手册:https://bouffalolab.github.io/bl_iot_sdk/

其中,你当前需要浏览BLFlashEnv工具的使用:https://bouffalolab.github.io/bl_iot_sdk/Developer_Environment/BLFlashEnv/BLFlashEnv.html

注意

官方文档描述的步骤:将板子的BOOT引脚保持高电平,并且使得芯片复位,使其处于UART引导下载的状态。

重点是注意以下几个参数设置:

  1. 串口选择第一个(该开发板有两个串口)
  2. 波特率设置为2000000(2M)

具体操作方法是:

  1. 按住BOOTSTRAP键不松手
  2. 点按RST键
  3. 松开BOOTSTRAP键

然后在烧录工具点击:Create & Download 按钮

5. 登录开发板

数据线连接电脑,使用串口工具(PuTTY或者MobaXterm)登录开发板,串口工具参数设置如下:

PuTTY

打开串口:

EVM

当你看到EVM Logo时说明已经登录开发板并启动了EVM虚拟机。

6. 调试

虚拟机能执行JS脚本,必须要有文件系统支持。对于BL602开发板来说,我们可以将JS脚本所在目录整体写到ROMFS中,具体设置如下:

RomFS

重点是打开RomFS选项,并且选中目录为仓库的test目录。

案例展示

下面展示解析一个域名的DNS地址:

JS脚本代码如下:

  1. var dns = require('dns');
  2. dns.lookup('www.baidu.com', function(err, ip, family) {
  3. print(ip);
  4. });

打开串口工具连接登录开发板,在EVM虚拟机REPL中输入以下测试命令:

DNS

更多更好玩的库等待你探索哦!

如何移植一个驱动或者库

概述

移植一个库,首先要明白这个驱动或者库的输入和输出是什么,天下所有的程序模式都是一个套路,那就是IPO(Input/Process/Output)。

我们要做的是移植工作,所以不需要关心Process,只需要关心Input和Output。

因此,将这个驱动或者库移植到EVM上来时,需要注意的就是要将EVM的参数类型转换成C语言的参数类型,以上,便是移植的主要工作。

实际操作

以下以一个GPIO的驱动库为例,展示移植一个驱动库的过程。

首先,这个库在博流智能SDK以下目录:

  1. ~/sdk/bl_iot_sdk/customer_app/sdk_app_gpio

我们先可以抛开EVM,将这个库烧录到开发板中试玩一下:

  1. ./genromap

最终生成的二进制文件在~/sdk/bl_iot_sdk/customer_app/sdk_app_gpio/build_out/sdk_app_gpio.bin

然后在烧录工具中,将Firmware Bin设为这个sdk_app_gpio.bin文件,烧录即可,具体使用请参考官方文档:https://bouffalolab.github.io/bl_iot_sdk/Examples/demo_peripherals_gpio/GPIO.html

在体验完库基本使用后,我们可以查看源码:

  1. ~/sdk/bl_iot_sdk/customer_app/sdk_app_gpio/sdk_app_gpio/main.c

然后,我们大概了解下EVM模块目录设计:

  1. .
  2. ├── iotjs IoT.js模块
  3. ├── bouffalolab 博流智能BL602的移植
  4. ├── evm_main.c 虚拟机入口文件
  5. ├── evm_module_dns.c DNS模块
  6. ├── evm_module_fs.c 文件系统模块
  7. ├── evm_module_gpio.c GPIO模块
  8. ├── evm_module_http.c HTTP Client模块
  9. ├── evm_module_net.c SOCKET/TCP模块
  10. ├── evm_module_timers.c 定时器模块
  11. └── evm_module_uart.c UART模块
  12. ├── bouffalo.mk makefile文件
  13. ├── common 通用模块,纯C,与硬件无关的库
  14. ├── evm_module_assert.c 断言
  15. ├── evm_module_buffer.c Buffer
  16. ├── evm_module.c require模块
  17. ├── evm_module_events.c 事件模块
  18. ├── evm_module_process.c
  19. └── SConscript
  20. ├── linux linux平台的移植
  21. ├── evm_main.c 入口函数
  22. ├── evm_module_adc.c ADC模块
  23. ├── evm_module_dns.c DNS模块
  24. ├── evm_module_fs.c 文件系统模块
  25. ├── evm_module_gpio.c GPIO模块
  26. ├── evm_module_http.c HTTP Client模块
  27. ├── evm_module_i2c.c IIC模块
  28. ├── evm_module_net.c SCOKET/TCP模块
  29. ├── evm_module_pwm.c PWM模块
  30. ├── evm_module_spi.c SPI模块
  31. ├── evm_module_timers.c 定时器模块
  32. ├── evm_module_uart.c UART模块
  33. ├── evm_module_udp.c UDP模块
  34. ├── README.md
  35. └── SConscript 基于Scons体系的编译
  36. ├── rt-thread RT-Thread的移植
  37. ├── evm_main.c
  38. ├── evm_module_adc.c
  39. ├── evm_module_fs.c
  40. ├── evm_module_gpio.c
  41. ├── evm_module_http.c
  42. ├── evm_module_i2c.c
  43. ├── evm_module_net.c
  44. ├── evm_module_pwm.c
  45. ├── evm_module_spi.c
  46. ├── evm_module_timers.c
  47. ├── evm_module_uart.c
  48. ├── evm_module_udp.c
  49. ├── README.md
  50. └── SConscript
  51. └── zephyr Zephyr的移植
  52. └── README.md
  53. └── mpy MicroPython的兼容

因此,我们在博流移植一个模块,源文件应该存放在~/modules/iotjs/bouffalolab中,并且源文件名以evm_module_xxx为前缀命名。然后参考博流官方例程和IoT.js官方API标准来封装模块:

IoT.js官方API手册:https://github.com/jerryscript-project/iotjs/blob/master/docs/api/IoT.js-API-reference.md

在完成API移植后,设置一个宏来控制是否需要编译该模块,具体操作步骤如下:

一、在~/modules/iotjs/bouffalolab/evm_main.c根据这个宏,来初始化该模块,代码都是模板式的,找个空位置复制一段,将宏替换为你命名的宏以及模块入口函数名修改为你命名的函数名;

二、在~/module/iotjs/bouffalolab.mk变量COMPONENT_SRCS添加上这个模块的文件名;

三、在~/include/evm_module.h中添加一个宏。

四、在~/bsp/bouffalolab/makefile添加这个模块宏名称。

以上,便会将开发者新增的模块编译进固件中。

最后,打开你的终端,敲:

  1. ./genromap

一个新的模块便被编译进虚拟机,接着你可以写JS测试脚本,放在~/test目录中,在PuTTY中,输入:

  1. runsccript("test_xxx.js")

虚拟机便会加载执行这个脚本文件。

以上,便是移植一个模块的过程。

当然,GPIO库比较简单,基本就是一些参数类型转换。复杂一点的比如HTTP客户端库,涉及到网络请求和多线程处理,这个稍微就麻烦点。开发者感兴趣可以自行阅读HTTP库的源码,了解和学习一个复杂的库又该如何处理。其实大同小异。

如何移植一个新的开发板或者RTOS

首先,目前EVM并不支持裸跑在开发板中,所有库均依赖操作系统的实现,因此移植一个开发板首先要确定这个开发板已经有操作系统支持,最好是官方已经一直好的操作系统,并且附带大量使用DEMo。

所以,移植到一个开发板就是移植到一个操作系统上,EVM目前版本并不直接运行在硬件上。

移植到RTOS

BL602开发板入口函数是bfl_main,所以,EVM肯定是在这个入口函数里面启动。再看EVM入口函数,在~/modules/iotjs/bouffalolab/evm_main.c中的evm_main中,那么我们能否直接在bfl_main调用evm_main函数呢?

答案是不能的,尤其是RTOS(当前BL602开发板移植的是FreeRTOS),直接调用会阻塞,导致后面代码无法执行。因此需要启动一个线程启动调用evm_main

最终代码请参考~/bsp/bouffalolab/app/main.c中。

但是在正式调用evm_main之前,我们还需要将当前操作系统几个必要API注册到EVM虚拟机中,需要修改~/modules/iotjs/evm_main.c,具体有以下几个方法需要注册:

  • int fs_open(char *name, int mode);
  • void fs_close(int fd);
  • int fs_size(int fd);
  • int fs_read(int fd, char *buf, int len);
  • int fs_write(int fd, char *buf, int len);
  • void *vm_malloc(int size);
  • void vm_free(void *mem);

此外,我们还可以根据实际需求修改虚拟机自身的堆栈大小,配置文件在~/include/evm_module.h中,堆栈的宏如下:

  • EVM_HEAP_SIZE
  • EVM_STACK_SIZE

以上,便是移植一个RTOS的步骤。

EVM即将移植到下一款开发板ESP32中,请期待!想加入我们一起搞的,加群!加群!加群!