3

X-CUBE-AI(TinyML) + Keil

 3 years ago
source link: https://www.taterli.com/7739/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

X-CUBE-AI(TinyML) + Keil

  • TaterLi
  • 2021年4月27日2021年4月27日

到现在已经完成两个实验了,但是都是在编译和测试别人的东西,那如何移植到我们熟悉的IDE,比如古董Keil(其实我也不喜欢,但是Team里都用这个,我也没办法!),所幸X-CUBE-AI能给到很大的帮助.他是STM32CubeMX内的一个组件.但是Cube只能支持M4/M7/M23/M33/M35P/M55等等(最低推荐架构:ARMv7E-M),大尺寸低配MCU不常见,比如STM32F030RB,手动移植即可.

注意:目前支持依然有点问题,模型文件不知道被他转换到哪里去了,不过他能帮忙添加目录结构也是挺好的.

在新建CubeMX工程后选择顶部的Software Pack并添加X-CUBE-AI组件,选择Core以及应用为Not Selected.

从软件中Add Network.

模型还是从这里获取:https://github.com/tensorflow/tensorflow/blob/master/tensorflow/lite/micro/examples/hello_world/train/train_hello_world_model.ipynb,最终要的文件是这个.

从左侧文件浏览中下载他,然后直接在Cube加载并分析.

  • 如果选的是CubeAI框架,那么可以节约很多编译时间.
  • 如果选的是Tensorflow Micro框架,则可以有和TinyML一样的原生开发体验.

然后可以进行验证测试,我是NUCLEO-H723ZG,PD8/PD9作为USART3的Bootloader下载接口,其他的要自行看原理图,编译工程需要不少时间,耐心等等,由于没有配备验证解雇集,所以能跑就不错了.

然后其他按照自己喜欢配置,最后生成工程,最后编译还缺了个文件:

缺了的东西要补上(主要是ST软件开小差忘了复制了吧,如果要提交到Git,最好是包含官方工程的submodule而不是全部打包.),然后重新添加Keil工程里Application/User/X-CUBE-AI/App缺失的syscall文件.

然后micro_error_reporter没有定义,从前面的学习知道,这个其实就应该映射为串口输出.暂时不想实现他就可以在主函数写个dummy函数.

void DebugLog(const char* s){
	__nop();
}

然后C文件还要CPP化,最后把代码移植过去.(完整版请查看:https://gist.github.com/nickfox-taterli/f21dba55a2118a95406547253ff7141a 完成工程:https://github.com/nickfox-taterli/KeilCube_TfMciro)

/* Includes ------------------------------------------------------------------*/
#include "main.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "tensorflow/lite/micro/all_ops_resolver.h"
#include "tensorflow/lite/micro/micro_error_reporter.h"
#include "tensorflow/lite/micro/micro_interpreter.h"
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
#define TFLITE_SCHEMA_VERSION (3)

const int kInferencesPerCycle = 1000;
const float kXrange = 2.f * 3.14159265359f;

// Globals, used for compatibility with Arduino-style sketches.
namespace {
    tflite::ErrorReporter* error_reporter = nullptr;
    const tflite::Model* model = nullptr;
    tflite::MicroInterpreter* interpreter = nullptr;
    TfLiteTensor* input = nullptr;
    TfLiteTensor* output = nullptr;
    int inference_count = 0;

    constexpr int kTensorArenaSize = 2000;
    uint8_t tensor_arena[kTensorArenaSize];
} 
/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */
alignas(8) const unsigned char g_model[] = {
    0x1c, 0x00, 0x00, 0x00, 0x54, 0x46, 0x4c, 0x33, 0x14, 0x00, 0x20, 0x00,
    ....
    0x00, 0x00, 0x00, 0x09};
const int g_model_len = 2488;
/* USER CODE END PV */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
void DebugLog(const char* s){
	__nop();
}

void HandleOutput(tflite::ErrorReporter* error_reporter, float x_value,
                  float y_value) {
  // 从例子中挪过来
}

void setup() {
  // 从例子中挪过来
}

void loop() {
  // 从例子中挪过来
}
/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 2 */
  setup();
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */
		loop();
    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

查看输出.

image-43-1024x572.png

发表评论 取消回复

您的电子邮箱地址不会被公开。 必填项已用*标注

评论

显示名称 *

电子邮箱地址 *

网站网址


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK