本文将介绍如何为APM32F407IG芯片移植轻量级AI推理框架——TinyMaix,并在开发板上运行TinyMaix的手写数字识别示例。本文将首先介绍TinyMaix是什么,以及APM32F407IG芯片的主要参数。然后,介绍如何为APM32F407IG芯片创建一个支持基于SysTick计时,以及printf输出到UART的Keil项目。接着,介绍如何将TinyMaix项目核心框架和手写数字识别示例源码添加到支持SysTick计时和printf输出的Keil项目中。最后,介绍如何将编译好的二进制程序下载到APM32F407IG Tiny开发板上,并运行手写数字识别示例程序。 一、背景介绍开始之前,首先介绍一下轻量级AI推理框架——TinyMaix,以及本次使用活动的APM32F407IG Tiny Board的主控芯片APM32F407IGT6。 1.1 TinyMaix框架简介TinyMaix是国内sipeed团队开发一个轻量级AI推理框架,官方介绍如下: TinyMaix 是面向单片机的超轻量级的神经网络推理库,即 TinyML 推理库,可以让你在任意单片机上运行轻量级深度学习模型。
根据官方介绍,在仅有2K RAM的 Arduino UNO(ATmega328, 32KB Flash, 2KB RAM) 上,都可以基于 TinyMaix 进行手写数字识别。对,你没有看错,2K RAM + 32K Flash的设备上都可以使用TinyMaix进行手写数字识别!TinyMaix官网提供了详细介绍,可以在本文末尾的参考链接中找到。 TinyMaix项目源码时以 Apache-2.0协议开源的, GitHub代码仓:https://github.com/sipeed/tinymaix TinyMaix项目源代码仓中,包含了TinyMaix核心框架代码、示例程序、常用模型、测试图片、文档等内容。 1.2 TinyMaix上层APITinyMaix框架对上层应用程序提供的核心API主要位于代码仓的tinymaix.h文件中,核心API如下: /******************************* MODEL FUNCTION ************************************/
tm_err_t tm_load (tm_mdl_t* mdl, const uint8_t* bin, uint8_t*buf, tm_cb_t cb, tm_mat_t* in); //load model
void tm_unload(tm_mdl_t* mdl); //remove model
tm_err_t tm_preprocess(tm_mdl_t* mdl, tm_pp_t pp_type, tm_mat_t* in, tm_mat_t* out); //preprocess input data
tm_err_t tm_run (tm_mdl_t* mdl, tm_mat_t* in, tm_mat_t* out); //run model
/******************************* UTILS FUNCTION ************************************/
uint8_t TM_WEAK tm_fp32to8(float fp32);
float TM_WEAK tm_fp8to32(uint8_t fp8);
/******************************* STAT FUNCTION ************************************/
#if TM_ENABLE_STAT
tm_err_t tm_stat(tm_mdlbin_t* mdl); //stat model
#endif主要分为三类: 模型函数,包括模型加载、卸载、预处理、推理; 工具函数,包含FP32和uint8的互转; 统计函数,用于输出模型中间层信息;
这里的模型,通常是预训练模型经过脚本转换生成的TinyMaix格式的模型; 1.3 TinyMaix底层依赖TinyMaix可以简单理解为一个矩阵和向量计算库,目前已支持如下几种计算硬件: #define TM_ARCH_CPU (0) //default, pure cpu compute
#define TM_ARCH_ARM_SIMD (1) //ARM Cortex M4/M7, etc.
#define TM_ARCH_ARM_NEON (2) //ARM Cortex A7, etc.
#define TM_ARCH_ARM_MVEI (3) //ARMv8.1: M55, etc.
#define TM_ARCH_RV32P (4) //T-head E907, etc.
#define TM_ARCH_RV64V (5) //T-head C906,C910, etc.
#define TM_ARCH_CSKYV2 (6) //cskyv2 with dsp core
#define TM_ARCH_X86_SSE2 (7) //x86 sse2对于ARM-Cortex系列MCU,可以支持纯CPU计算和SIMD计算。其中CPU计算部分无特殊依赖(计算代码均使用标准C实现)。SIMD部分,部分计算代码使用了C语言内嵌汇编实现,需要CPU支持相应的汇编指令,才可以正常编译、运行。 TinyMaix的示例代码依赖于精准计时和打印输出能力,具体是项目的tm_port.h中的几个宏定义: #define TM_GET_US() ((uint32_t)((uint64_t)clock()*1000000/CLOCKS_PER_SEC))
#define TM_DBGT_INIT() uint32_t _start,_finish;float _time;_start=TM_GET_US();
#define TM_DBGT_START() _start=TM_GET_US();
#define TM_DBGT(x) {_finish=TM_GET_US();\
_time = (float)(_finish-_start)/1000.0;\
TM_PRINTF("===%s use %.3f ms\n", (x), _time);\
_start=TM_GET_US();}1.4 APM32F407IGT6芯片简介本次试用的APM32F407IG Tiny Board,主控芯片是APM32F407IGT6,它的主要参数为: TinyMaix的手写数字识别示例,在32KB Flash 2KB RAM的Arduino UNO R3上都可以运行。 在我们这次试用的主角APM32F407IG Tiny Board上运行是完全没有任何压力的。 开发板正面特写,可以看到主控芯片型号为APM32F407IGT6: 二、开发环境搭建2.1 下载APM32F407资料极海官网APM32F07资料下载页: APM32F405/407 (geehy.com) 必须下载的文件包括: APM32F405xG 407xExG数据手册 APM32F4xxx用户手册 APM32F407IG Tiny 原理图 APM32F4xx_SDK APM32F4xx_DFP Pack
具体下载链接,参见本文末尾的参考链接部分。 2.2 安装Keil MDKARM官网Keil MDK安装包下载页面(需要填写问卷): https://www.keil.com/download/product/ 填写完问卷之后,可以看到,最新版本5.38a安装包文件下载页面: 这里的安装包文件的链接可以直接复制: https://www.keil.com/fid/g6daezwlgtwj1wzt54w1lz01v1lvsy2w9vmud1/files/eval/mdk538a.exe MD5: 6792e5e0c0b5207b4db8339e043d7461 PS: 使用下载工具下载完成后,记得验证一下MD5值。 Keil本身的安装没啥难度,一路下一步就好了,这里不再详细介绍。 2.3 安装ARM Compiler 5APM32F4xx_SDK需要ARM Compiler 5才可以顺利编译,用Keil MDK较新版本默认附带ARM Compiler 6无法正常编译。因此,需要下载ARM Compiler 5。 ARM Compiler下载页面为: https://developer.arm.com/documentation/ka005198/latest 可以看到ARM Compiler 5最后一个版本是:5.06 update 7 (build 960) 点击中间的ACOMP5蓝色链接,可以跳转到该版本编译器的下载页面(需要注册登录): 这里下载下方的Win32版本即可。 ARM Compiler下载页面的文件链接是动态生成的,无法直接复制出来。 我用某雷下载之后,转存了一个云盘链接,方便国内用户下载: 链接:https://pan.xunlei.com/s/VN_A6-Wskfwt4IYWpJLHgsGkA1?pwd=h23k#MD5: 56a3c52585e7ce4d95fc75ae6ff6b9df 2.4 安装APM32F4xx支持包Keil MDK APM32F4系列MCU支持包: https://www.geehy.com/uploads/tool/Geehy.APM32F4xx_DFP.1.0.3.pack 下载完成后,双击安装即可(PS:成功安装Keil MDK之后,.pack文件会自动关联到Keil)。 到这里,基础开发环境已经搭建完成了。 三、运行SysTick示例程序现在,我们需要为APM32F407IGT6芯片创建一个同时支持SysTick计时和printf输出的Keil项目。 3.1 下载APM32F4xx_SDK首先,从极海官网上下载APM32F4xx_SDK,解压后可以在它的 Examples 子目录下找到 SysTick和USART示例,如下图所示: 3.2 编译SysTick示例程序接着,打开SysTick目录下,SysTick_TimeBase\Project\MDK 子目录中的 SysTick_TimeBase.uvprojx 文件,可以看到该示例参与编译的源代码文件: 按F7键,进行编译,编译成功可以看到Build Output输出如下: 3.3 修改调试器设置接下来,将APM32F407 Tiny开发板通过USB Type-C线连接到电脑。注意,开发板注意接在调试的USB口上。 按照如下步骤修改调试器设置: PS:这里SW Device中已经成功识别到了ARM CoreSight SW-DP,说明调试和MCU之间通信正常。 查阅数据手册,这里参数都是正确的,不需要修改。 为了方便调试,建议将这里的Rest and Run勾选上,如下图所示: 勾选之后,记得点OK保存。 3.4 下载和运行SysTick示例程序完成上述调试设置之后,就可以按F8或Download按钮开始下载成了。Download按钮,位置如下图所示: 开始下载后,Build Output窗口将会显示下载进度,下载成功后可以看到: 其中,Application running … 是勾选了Reset and Run才会有的。 如果没有意外,将会看到开发板上的LED灯已经开始闪烁了: 3.5 分析SysTick示例程序主要代码我们继续看Project视图下的文件: 其中,各源码目录中的对应作用分别为: 接下来,看下main.c中的主要代码: 可以看到这里是一个点灯的代码,其中while循环调用了另外两个函数: 这个while循环,就是闪灯不断LED2和LED,再延时一秒。 另外,还可以看到上面的截图中: 除此之外,main.c文件中还有如下代码: 通过注释,可以知道,这个函数实现了printf到串口的重定向。 3.6 查看SysTick示例程序的串口输出前面分析知道,SysTick示例程序的main函数中初始化了USART1,并且有一行字符串打印,另外还实现了printf到串口的重定向。因此,如果没有什么意外的话,我们应该可以通过USART1看到这一行打印的输出。 接下来,查阅原理图的APM32-Link部分: 可以看到,APM32-Link预留了USART1的跳线。 然而不幸的是: 没有跳线帽简单,从其他板子上扣下来一对就行了。而APM32-Link连接到PC之后没有识别到串口设备,可能原因有两个: 通过极海官网查阅APM32F103C8T6参数发现,它是支持USBD功能的,理论上可以实现USB转UART功能。那这里PC没有识别到串口设备的原因就是——APM32-Link固件暂时还不支持USB转UART。 查阅极海官网APM32-Link介绍信息,发现确实如此,没有找到对USB转UART功能的说明。 所以,需要外接一个USB转UART用来查看串口输出,连接如下图: 其中, 开发板的U2TX,连接到USB转串口的RX 开发板的U2RX,连接到USB转串口的TX
接着,USB转串口和调试器插上PC,打开MobaXterm,设置如下参数: 打开新的会话之后,按下开发板的RESET按键,将会看到: 成功接收到了printf打印的字符串! 继续查阅原理图的USART1_TX和USART1_RX标号部分: 可以看到, USART1_TX,对应PA9 USART1_RX,对应PA10
这也项目代码能够对应起来: 在Keil中一路查看: 找到的Board_APM32F407_MINI.h文件,在Keil的Project视图也可以看到: 该文件的完整路径为:APM32F407\APM32F4xx_SDK_v1.3\Boards\Board_APM32F407_MINI\inc\Board_APM32F407_MINI.h 我们试用的是APM32F407_Tiny开发板,实际上不应该用这个文件。但因为两个板子的串口配置代码是一样的,所以只使用串口输出的话,不修改也并不会影响串口输出。 两个开发板对应的头文件的主要差异在于,按键相关的宏定义不一样: 如果想要修改为方法是,在Options for Target ‘APM32F407’窗口的C/C++标签页中: 将APM32F407_MINI宏修改为APM32F407_TINY。 修改之后,main.c中的也要响应修改: APM_MINI_COMInit 替换为 APM_TINY_COMInit APM_MINI_LEDInit 替换为 APM_TINY_LEDInit APM_MINI_LEDToggle 替换为 APM_TINY_LEDToggle
四、移植TinyMaix核心库和手写数字识别示例简单起见,接下来我们不再新建Keil项目,而是直接将TinyMaix核心库和手写数字识别示例代码拷贝到SysTick示例目录中(虽然这么做不太规范)。 4.1 下载TinyMaix源码到本地首先,使用 git 命令下载TinyMaix最新源码: git clone https://github.com/sipeed/tinymaix.git4.2 拷贝TinyMaix源码到Keil项目目录接着,在SysTick示例的SysTick_TimeBase目录下,创建TinyMaix目录: 将TinyMaix源码的examples、include、src目录,拷贝到刚刚创建的TinyMaix目录中: 另外,创建tools目录,并将tools目录下的tmdl目录拷贝过去;拷贝的exmaples中包含了多个示例,可以把不需要的删除掉,只保留mnist目录,即手写数字识别示例。 4.3 将TinyMaix源文件添加到Keil项目中首先,在Keil的Project视图右击APM32F407,选择Manage Project Items: 接着,在弹出的Manage Project Items窗口中,进行如下两步骤操作: 然后,点击Add Files,在弹出的文件添加界面中,依次添加刚刚拷贝过来的TinyMaix目录src目录和examples/mnist目录下的.c文件到项目中: 添加完成后,点击OK确认。 4.4 解决Keil项目的编译问题完成上述修改后,直接编译,将会报错: 首先,按照如下步骤,添加必要的include搜索路径: 在Project视图右键APM32F407,选择”Options for Target ‘APM32F407’“,如下图所示: 在弹出的Options for Target ‘APM32F407’窗口中,点击C/C++标签页,如图下图所示: 在C/C++标签页,点击Include Paths右侧的”…”按钮,会弹出Folder Setup界面,如下图所示: 在Folder Setup界面中,分别点击如下两处,选择目录进行添加: 在弹出的文件夹选择界面中,选择拷贝的TinyMaix的include目录,选择之后,如下图所示:
此时,再次编译项目,报错已经不一样了: 这里报错说,找不到”sys/time.h“文件。 直接双击error信息行,主编辑器区可以看到tm_port.h文件对应位置: 回顾开头1.4节,这里就是TinyMaix依赖的几个计时宏。 将其修改为: 接下来编译,遇到如下错误: 需要打开GNU扩展选项: 再次编译,报链接错误: 这两个连接错误说有两个main函数定义。 找到手写数字识别的main.c,将其中的main函数重命名为mnist_main: 再次编译,报错如下: 这次说,SysTick_Get没有定义。 打开Application下的main.c,Ctrl+F搜索TimingDelay: 找到如下引用: 将其全部替换掉为SysTickCount: 然后,修改main.c中的SysTick_Delay_ms和TimingDelay_Decrement函数,并新增SysTick_Get函数: 再次编译,终于成功了: 4.5 调用mnist示例程序接下来,在main.c文件的main函数中添加两行代码: 记得保存Ctrl+S。 然后重新编译、下载,下载完成后,自动开始运行,可以看到串口输出: 运行报错了。 这里是因为,TinyMaix需要试用malloc申请内存,APM32F407的SysTick示例程序默认的堆大小配置不够。 需要修改 startup_apm32f40x.s 文件: 将其中的Heap_Size修改为0x1000(4096),默认的是0x200(512) 再次重新编译、下载、运行,串口可以看到: 这次成功运行了,耗时4毫秒,识别了手写数字2。 原始图片数据为: 可以看出来,识别结果是正确的。 PS:看了一下字数统计四千多字了,有点肝。 好了,本文就到这里了,感谢阅读。 五、参考链接APM32F405xG 407xExG数据手册: https://www.geehy.com/uploads/tool/APM32F405xG 407xExG数据手册 V1.5.pdf APM32F4xxx用户手册: https://www.geehy.com/uploads/tool/APM32F4xxx用户手册 V2.0.pdf APM32F407IG Tiny 原理图: https://www.geehy.com/uploads/tool/APM32F407IG TinyBoard.zip APM32F4xx_SDK: https://www.geehy.com/uploads/tool/APM32F4xx_SDK_v1.3.zip APM32F4xx_DFP Pack: https://www.geehy.com/uploads/tool/Geehy.APM32F4xx_DFP.1.0.3.pack
|