妥协下的联姻——为rt-thread适配最新k210 kendryte-standalone-sdk的nncase

在上一篇文章中,我们已经成功在maix go上跑起来了rt-thread。可是,rtt官方的bsp只是对kendryte-standalone-sdk v0.5.6及之前的个别版本有支持。而在kendryte最新开发的sdk中,对老sdk中的部分内容做出了较大的改动,并且引入了最新的模型处理程序nncase,以取代之前的kmodel。对于之前的kmodel将不再提供更新支持,全面使用最新的nncase。本文将给大家介绍最新sdk移植的方法以及一些注意事项。

1.编译选项设置

nncase是由c++17编写完成,运用了较多c++17的功能,因此在编译之前首先需要打开工具链对c++17的支持。打开k210文件目录下的rtconfig.py,修改其CXXFLAGS选项如下图:

妥协下的联姻——为rt-thread适配最新k210 kendryte-standalone-sdk的nncase_第1张图片

2.打开rtt的c++支持

  • 在rtt的env工具中,输入menuconfig进入配置页面,在RT-Thread Components->C++ feature选项下找到"Support C++ feature"并选中。

妥协下的联姻——为rt-thread适配最新k210 kendryte-standalone-sdk的nncase_第2张图片

  • RT-Thread中对全局对象构造函数的实现中,在 rt-thread\components\cplusplus 目录下的 crt_init.c 文件中对 C++ 进行了系统初始化, 连接脚本文件 link.lds 为 C++ 全局构造函数的代码分配了段。为了使 C++ 全局对象构造函数链接后能够存放在指定的段中,我们需要修改工程中的链接脚本,打开k210文件目录下的link.lds,对其进行如下修改:

妥协下的联姻——为rt-thread适配最新k210 kendryte-standalone-sdk的nncase_第3张图片

如果想更深入的了解在rtt上应用c++,可以参考这篇文章:RT-Thread--C++应用笔记

3.解决rtt中的libc_signal.c和工具链产生冲突的问题

如果这个时候直接编译,就可能会碰到如下报错:

妥协下的联姻——为rt-thread适配最新k210 kendryte-standalone-sdk的nncase_第4张图片

这个问题貌似是rtt的一个bug,在rtt未来的版本中可能就不会有这个问题了,但如果还有这个错误,那么可以通过以下几个步骤来解决。

  • 打开k210文件路径下的cconfig.h文件,注释掉其中三条语句

妥协下的联姻——为rt-thread适配最新k210 kendryte-standalone-sdk的nncase_第5张图片

  • 打开工具链路径下\RISC-V Embedded GCC\8.3.0-1.1\riscv-none-embed\include\sys中的signal.h,删除其中关于sigval、sigevent、siginfo的定义如下图。删完记得保存。

妥协下的联姻——为rt-thread适配最新k210 kendryte-standalone-sdk的nncase_第6张图片

4.将最新sdk中新增的内容加入工程中

修改rt-thread\bsp\k210\packages\kendryte-sdk-v0.5.5路径下的SConscript文件,将新增的源文件与头文件路径添加至工程中,修改后的文件如下:

from building import *

cwd     = GetCurrentDir()
src     = Split('''
kendryte-standalone-sdk/lib/bsp/entry.c
kendryte-standalone-sdk/lib/bsp/entry_user.c
kendryte-standalone-sdk/lib/bsp/locks.c
kendryte-standalone-sdk/lib/bsp/sleep.c
kendryte-standalone-sdk/lib/drivers/aes.c
kendryte-standalone-sdk/lib/drivers/apu.c
kendryte-standalone-sdk/lib/drivers/clint.c
kendryte-standalone-sdk/lib/drivers/dmac.c
kendryte-standalone-sdk/lib/drivers/dvp.c
kendryte-standalone-sdk/lib/drivers/fft.c
kendryte-standalone-sdk/lib/drivers/fpioa.c
kendryte-standalone-sdk/lib/drivers/gpio.c
kendryte-standalone-sdk/lib/drivers/gpiohs.c
kendryte-standalone-sdk/lib/drivers/i2c.c
kendryte-standalone-sdk/lib/drivers/i2s.c
kendryte-standalone-sdk/lib/drivers/iomem.c
kendryte-standalone-sdk/lib/drivers/kpu.c
kendryte-standalone-sdk/lib/drivers/plic.c
kendryte-standalone-sdk/lib/drivers/pwm.c
kendryte-standalone-sdk/lib/drivers/rtc.c
kendryte-standalone-sdk/lib/drivers/sha256.c
kendryte-standalone-sdk/lib/drivers/spi.c
kendryte-standalone-sdk/lib/drivers/sysctl.c
kendryte-standalone-sdk/lib/drivers/timer.c
kendryte-standalone-sdk/lib/drivers/uart.c
kendryte-standalone-sdk/lib/drivers/uarths.c
kendryte-standalone-sdk/lib/drivers/utils.c
kendryte-standalone-sdk/lib/drivers/wdt.c
kendryte-standalone-sdk/lib/nncase/nncase.cpp
kendryte-standalone-sdk/lib/nncase/runtime/interpreter.cpp
kendryte-standalone-sdk/lib/nncase/runtime/kernel_registry.cpp
kendryte-standalone-sdk/lib/nncase/runtime/cpu/cpu_ops.cpp
kendryte-standalone-sdk/lib/nncase/runtime/k210/k210_ops.cpp
kendryte-standalone-sdk/lib/nncase/runtime/k210/interpreter.cpp
kendryte-standalone-sdk/lib/nncase/runtime/neutral/neutral_ops.cpp
''')
CPPPATH = [cwd + '/kendryte-standalone-sdk/lib/drivers/include', 
cwd + '/kendryte-standalone-sdk/lib/bsp/include',
cwd + '/kendryte-standalone-sdk/lib/utils/include',
cwd + '/kendryte-standalone-sdk/lib/nncase/include',
cwd + '/kendryte-standalone-sdk/lib/nncase/kernels',
cwd + '/kendryte-standalone-sdk/lib/nncase/runtime',
cwd + '/kendryte-standalone-sdk/lib/nncase/targets',
cwd + '/kendryte-standalone-sdk/lib/nncase/runtime/cpu',
cwd + '/kendryte-standalone-sdk/lib/nncase/runtime/k210',
cwd + '/kendryte-standalone-sdk/lib/nncase/runtime/neutral',
cwd + '/kendryte-standalone-sdk/third_party/xtl/include'
]
CPPDEFINES = ['CONFIG_LOG_COLORS', 'CONFIG_LOG_ENABLE', 'CONFIG_LOG_LEVEL=LOG_VERBOSE', 'FPGA_PLL', 'LOG_KERNEL', '__riscv64']

group = DefineGroup('SDK', src, depend = ['PKG_USING_KENDRYTE_SDK'], CPPPATH = CPPPATH, LOCAL_CPPDEFINES = CPPDEFINES)

Return('group')

可以看到,相比原来的文件,添加了不少的内容。

5.对SDK中的部分源码进行修改

5.1动态内存

在k210最新的sdk中,底层的外设驱动包括kpu的代码实现采用了动态内存。为此kendryte特地开发了一个用于管理动态内存的源文件,为\kendryte-standalone-sdk\lib\drivers路径下的iomem.c,该文件实现了动态内存的初始化、申请动态内存、删除动态内存、查询剩余内存空间的功能。这些功能被同目录下的众多其他外设的驱动代码所引用。而rtt本身有动态内存的管理功能,这样一来就会产生冲突,我们需要替换iomem.c中的内容,将rtt的内存管理接口替换上去。

iomem.c中的代码可做如下替换:

#include 
#include 
#include 
#include 
#include "iomem.h"
#include "printf.h"
#include "atomic.h"

#include "rtthread.h"


void iomem_free(void *paddr)
{
    rt_free(paddr); 
}

void *iomem_malloc(uint32_t size)
{
    return rt_malloc(size);
}

uint32_t iomem_unused()
{
    rt_uint32_t total, used, max;

    rt_memory_info(&total, &used, &max);

    return total - used;
}

只要保留iomem_free,iomem_malloc,iomem_unused这三个函数供其他文件调用就可以了。查询剩余内存这部分的内容会和原有bsp下driver目录中的heap.c冲突。可以删去heap.c中查询剩余内存的代码。

5.2调试模式

最新的sdk中还加入了调试功能相关的代码,不过这也和rtt的功能相冲突,同时这部分代码也会因为引用的sdk代码不全(sdk中有部分冗余代码,所以并没有完全加入工程)导致编译报错。在外设驱动uart.c中,我们需要删除以下和调试相关的代码。

妥协下的联姻——为rt-thread适配最新k210 kendryte-standalone-sdk的nncase_第7张图片

5.3 修改nncase target

最新bsp中的nncase有两种工作模式,一种是将运算交给cpu来完成,还有一种是给kpu完成。如果使用kendryte官方的工具进行开发的话会对target进行配置。不过我们如果要用rtthread的话就少了这一过程,需要我们手动添加。我们打开这个路径下的文件。kendryte-standalone-sdk\lib\nncase\include\target_config.h

在其头部添加一个定义即可,如下图:

妥协下的联姻——为rt-thread适配最新k210 kendryte-standalone-sdk的nncase_第8张图片

6.完成

通过以上的操作,包含最新sdk的工程终于可以编译通过了,将代码烧写至开发板中,打开串口终端,就可以看到熟悉的rtt界面了。

妥协下的联姻——为rt-thread适配最新k210 kendryte-standalone-sdk的nncase_第9张图片

后记

经过这么一番操作,可能大家也能看出来为什么叫妥协之作了,我们为了能够将最新的sdk引入到工程中不但修改了sdk的源码,还修改了工具链中代码、cconfig.h中的代码。这些操作很难通过在rtt上提交一个新的bsp实现,有点难登大雅之堂,实在是权宜之计。如果广大网友有什么更好的适配方法,欢迎一起讨论。

 

还不知道怎么编译?查看文章:在sipeed maix go上用上rt-thread以及vs code

你可能感兴趣的:(嵌入式与计算机视觉)