EVM3
发布于2021年3月中旬
本次发布带来的更新是参照IoT.js框架标准,实现了EVM自己的后端框架。同时,基于这套框架,我们已经移植到硬件开发板上,大家可以克隆仓库到本地,然后部署到开发板中进行实际硬件体验。
本次移植的开发板是博流智能基于BL602核心开发板,基于RISC-V核的低功耗、高可靠Wi-Fi+BLE二合一SoC芯片。内存方面有276KB RAM/128KB ROM。关于该板子的详细介绍请移步:博流智能。
快速上手
1. 克隆仓库
git clone https://gitee.com/scriptiot.com/evm3
git submodule update --init --recursive
2. 编译固件
cd bsp/bouffalolab
./genromap
输出信息:
AR build_out/freertos_riscv_ram/libfreertos_riscv_ram.a
AR build_out/lwip/liblwip.a
LD build_out/app.elf
==========================
Generating BIN File to /home/~/bsp/bouffalolab/build_out/app.bin
Traceback (most recent call last):
File "flash_build.py", line 1396, in <module>
eflash_loader_cfg = os.path.join(app_path, bin_build_out_path, "eflash_loader_cfg.ini")
File "shutil.py", line 245, in copy
File "shutil.py", line 121, in copyfile
FileNotFoundError: [Errno 2] No such file or directory: '/home/~/sdk/bl_iot_sdk/customer_app/app/build_out/eflash_loader_cfg.ini'
[32048] Failed to execute script flash_build
make: *** [/home/~/bsp/bouffalolab/../../sdk/bl_iot_sdk/make_scripts_riscv/project.mk:191:all] 错误 255
当看到
LD build_out/app.elf
==========================
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
命令了,那么在仓库以下路径:
~/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引导下载的状态。
重点是注意以下几个参数设置:
- 串口选择第一个(该开发板有两个串口)
- 波特率设置为2000000(2M)
具体操作方法是:
- 按住BOOTSTRAP键不松手
- 点按RST键
- 松开BOOTSTRAP键
然后在烧录工具点击:Create & Download 按钮
5. 登录开发板
数据线连接电脑,使用串口工具(PuTTY或者MobaXterm)登录开发板,串口工具参数设置如下:
打开串口:
当你看到EVM Logo时说明已经登录开发板并启动了EVM虚拟机。
6. 调试
虚拟机能执行JS脚本,必须要有文件系统支持。对于BL602开发板来说,我们可以将JS脚本所在目录整体写到ROMFS中,具体设置如下:
重点是打开RomFS选项,并且选中目录为仓库的test目录。
案例展示
下面展示解析一个域名的DNS地址:
JS脚本代码如下:
var dns = require('dns');
dns.lookup('www.baidu.com', function(err, ip, family) {
print(ip);
});
打开串口工具连接登录开发板,在EVM虚拟机REPL中输入以下测试命令:
更多更好玩的库等待你探索哦!
如何移植一个驱动或者库
概述
移植一个库,首先要明白这个驱动或者库的输入和输出是什么,天下所有的程序模式都是一个套路,那就是IPO(Input/Process/Output)。
我们要做的是移植工作,所以不需要关心Process,只需要关心Input和Output。
因此,将这个驱动或者库移植到EVM上来时,需要注意的就是要将EVM的参数类型转换成C语言的参数类型,以上,便是移植的主要工作。
实际操作
以下以一个GPIO的驱动库为例,展示移植一个驱动库的过程。
首先,这个库在博流智能SDK以下目录:
~/sdk/bl_iot_sdk/customer_app/sdk_app_gpio
我们先可以抛开EVM,将这个库烧录到开发板中试玩一下:
./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
在体验完库基本使用后,我们可以查看源码:
~/sdk/bl_iot_sdk/customer_app/sdk_app_gpio/sdk_app_gpio/main.c
然后,我们大概了解下EVM模块目录设计:
.
├── iotjs IoT.js模块
│ ├── bouffalolab 博流智能BL602的移植
│ │ ├── evm_main.c 虚拟机入口文件
│ │ ├── evm_module_dns.c DNS模块
│ │ ├── evm_module_fs.c 文件系统模块
│ │ ├── evm_module_gpio.c GPIO模块
│ │ ├── evm_module_http.c HTTP Client模块
│ │ ├── evm_module_net.c SOCKET/TCP模块
│ │ ├── evm_module_timers.c 定时器模块
│ │ └── evm_module_uart.c UART模块
│ ├── bouffalo.mk makefile文件
│ ├── common 通用模块,纯C,与硬件无关的库
│ │ ├── evm_module_assert.c 断言
│ │ ├── evm_module_buffer.c Buffer
│ │ ├── evm_module.c require模块
│ │ ├── evm_module_events.c 事件模块
│ │ ├── evm_module_process.c
│ │ └── SConscript
│ ├── linux linux平台的移植
│ │ ├── evm_main.c 入口函数
│ │ ├── evm_module_adc.c ADC模块
│ │ ├── evm_module_dns.c DNS模块
│ │ ├── evm_module_fs.c 文件系统模块
│ │ ├── evm_module_gpio.c GPIO模块
│ │ ├── evm_module_http.c HTTP Client模块
│ │ ├── evm_module_i2c.c IIC模块
│ │ ├── evm_module_net.c SCOKET/TCP模块
│ │ ├── evm_module_pwm.c PWM模块
│ │ ├── evm_module_spi.c SPI模块
│ │ ├── evm_module_timers.c 定时器模块
│ │ ├── evm_module_uart.c UART模块
│ │ ├── evm_module_udp.c UDP模块
│ │ ├── README.md
│ │ └── SConscript 基于Scons体系的编译
│ ├── rt-thread RT-Thread的移植
│ │ ├── evm_main.c
│ │ ├── evm_module_adc.c
│ │ ├── evm_module_fs.c
│ │ ├── evm_module_gpio.c
│ │ ├── evm_module_http.c
│ │ ├── evm_module_i2c.c
│ │ ├── evm_module_net.c
│ │ ├── evm_module_pwm.c
│ │ ├── evm_module_spi.c
│ │ ├── evm_module_timers.c
│ │ ├── evm_module_uart.c
│ │ ├── evm_module_udp.c
│ │ ├── README.md
│ │ └── SConscript
│ └── zephyr Zephyr的移植
│ └── README.md
└── 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
添加这个模块宏名称。
以上,便会将开发者新增的模块编译进固件中。
最后,打开你的终端,敲:
./genromap
一个新的模块便被编译进虚拟机,接着你可以写JS测试脚本,放在~/test
目录中,在PuTTY中,输入:
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中,请期待!想加入我们一起搞的,加群!加群!加群!