664|2

88

帖子

3

TA的资源

一粒金砂(高级)

楼主
 

[STM32H7R/S]测评 ⑧nano edge ai studio 训练一个模型--上 [复制链接]

本帖最后由 不爱胡萝卜的仓鼠 于 2024-11-12 11:53 编辑

一.nano edge ai studio简介

        nano edge ai studio是ST AI套件中的一个,他的作用就是帮助我们快速训练一个AI模型,并且这个软件现在是免费的,几个月前他还是收费的。但是这个软件有点局限性,他训练的模型只能是传感器的数据,并且是时间序列的(如果你要实现一些例如图像识别的AI模型,那这个软件就不合适了,图像ST有对应的图像套件)

        下图为nano edge ai studio工作流程的见图,一张图就说明了这个工具是如何使用的,我们只需要创建一个工程,然后收集数据,给到软件,软件就会自动分析并帮我们选择一个最佳的模型,对于我们这些没有AI基础的嵌入式工程师简直就是帮助巨大

        nano edge ai studio官网如下:https://stm32ai.st.com/nanoedge-ai/

        具体怎么下载安装我这儿就不赘述了,额外说一下的就是他需要你注册一个ST账号,然后licence会通过邮件发送给你,软件打开后需要用licence注册后才能使用

 

        nano edge ai studio软件主界面如下,软件左上角时这个软件可以支持的4种算法,右边是一些应用的展示,可以为大家提供一些思路

简单给大家讲一下4中算法(可以看一下这个视频在大约23:23左右开始介绍,https://www.bilibili.com/video/BV1EG4y1a7Ji?spm_id_from=333.788.videopod.sections&vd_source=b5472a9f9c8c4560fd993637d3d9cb0f

        AD(异常检测):需要输入正常工作的信号和异常工作的信号给到软件去生成算法,算法就能分辨出机器是否在正常工作。并且这个算法是唯一一个支持在使用过程中自学习的,不同机器不同安装环境下检测到的信号可能会和训练时的样本不一致,这个自学习就可以做到很好的适应性。但是需要我们列举出异常信号给软件去学习

        nC(多分类):给软件多种信号,生成算法,算法就能分辨出当前检测到的信号是之前训练时的哪一种

        1C(单分类):给软件一种信号,生成算法,生成的算法就能分辨出当前时候和之前训练时提供的信号是否一致。对于检测设备是否异常工作的场景,可以只提供正常信号用于学习,不需要提供异常信号,因为异常信号可能有很多种,我们不一定可以一一列举

        E(外推法):这是一种回归算法,可以基于当前检测到的信号预测未来。例如某个设备生命周期内各个时间点的振动信号,然后实际工作是,软件就可以预测,该机器寿命大概还有多久,用于提前检测异常并提示保养或维修。

 

 

二.训练模型

        我这边就训练一个多分类模型,回头我会使用加速度传感器,让模型识别出我现在的动作,例如静止、直线运动、环形运动

        先选择nC

 

2.1 工程设置

接下来就是第一步,工程的一些设置

我们主要关注的就是taget和sensor

其中target我们可以选择ST的开发板、或者MCU信号、或者arduino开发板。我这边因为以前选过H7S的DK板,所以他还有favorite的展示

然后传感器的话有很多,加速度计、电流、磁力、麦克风等等

 

 

我这边使用的ACC,并且选择3轴,最终设置如下

 

2.2 信号采集

        信号采集相关内容已经在上一篇中说过了,这边我就不具体展开了。[STM32H7R/S]测评 ⑦制作一个NANO EDGE AI STUDIO采集数据使用的Data Logger

        我采集了3中信号,停止、画线、画圈。每种都采样100轮

 

2.3 Benchmark

        这里名字叫benchmark,事实上他还干了另外一件事,那就是从众多的算法中,拿着我们给的样本数据,一个一个去试,看那个算法最匹配我们提供的样本

        我们这边创建一个新的benchmark,然后默认的会把3种数据样本都选上,CPU处理器的核也拉满,这样可以算的快一点

然后等待启动计算

计算中,左边有个小的进度指示。右边可以看到总耗时,以及匹配度、RAM占用、Flash占用情况。并得到一个分数

经过大约半个多小时的计算(这个速度还是挺可以的,我这电脑CPU是好多年前的Ryzen 5 1600X),结果如下

2.4 校验

这里我们可以看到刚才软件尝试的所有算法,一共尝试了60种,并找出了里面效果最好的一种

如果你想在电脑上模拟测试这个模型的效果,就可以在这个界面完成,当然不想的话就可以跳过这个界面。这个步骤是可选的

 

首先要准备要用于验证的样本数据,我这儿就偷懒不再拿新的数据了,把之前第二步采样到的数据用一下。回到第二步,点击如图,就可以把整个采样数据下载下来(里面有100条)

然后用notepad++打开,随便选择一条,其他的都删掉

 

回到第四步的界面,选择一种算法,我就选择效果最好的那个

接下来会让我们放入用于测试的样本

把刚才修改过的文件放到circle下面,点击开始

测试结果如下,模型认为这个数据100%是圈,效果很不错

2.5 导出模型

最后一步就是导出模型

下一步ST会做个小小的问卷调查,我就直接跳过了

保存,我们会得到一个压缩包,这个我们待会儿看,因为这个界面还有好东西,一段示例代码


/* =============
    Copyright (c) 2024, STMicroelectronics

    All rights reserved.

    Redistribution and use in source and binary forms, with or without modification, are permitted provided that
    the following conditions are met:

    * Redistributions of source code must retain the above copyright notice, this list of conditions and the
      following disclaimer.

    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
      following disclaimer in the documentation and/or other materials provided with the distribution.

    * Neither the name of the copyright holders nor the names of its contributors may be used to endorse or promote
      products derived from this software without specific prior written permission.

    *THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
    INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER / OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
    WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
    USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.*
*/
/**
  **************************************************************************
  * Demo: NanoEdge AI process to include in main program body
  *
  * @note  This program must be completed and customized by the user
  **************************************************************************
  */

/* Includes --------------------------------------------------------------------*/
#include "NanoEdgeAI.h"
#include "knowledge.h"
/* Private define --------------------------------------------------------------*/
/* Private variables defined by user -------------------------------------------*/
float input_user_buffer[DATA_INPUT_USER * AXIS_NUMBER]; // Buffer of input values
float output_class_buffer[CLASS_NUMBER]; // Buffer of class probabilities
/* Private function prototypes defined by user ---------------------------------*/
/*
 * @brief  Collect data process
 *
 * This function is defined by user, depends on applications and sensors
 *
 * @param sample_buffer: [in, out] buffer of sample values
 * @retval None
 * @note   If AXIS_NUMBER = 3 (cf NanoEdgeAI.h), the buffer must be
 *         ordered as follow:
 *         [x0 y0 z0 x1 y1 z1 ... xn yn zn], where xi, yi and zi
 *         are the values for x, y and z axes, n is equal to
 *         DATA_INPUT_USER (cf NanoEdgeAI.h)
 */
void fill_buffer(float sample_buffer[])
{
	/* USER BEGIN */
	/* USER END */
}
/* -----------------------------------------------------------------------------*/
int main(void)
{
	/* Initialization ------------------------------------------------------------*/
	enum neai_state error_code = neai_classification_init(knowledge);
	if (error_code != NEAI_OK) {
		/* This happens if the knowledge does not correspond to the library or if the library works into a not supported board. */
	}

	/* Classification ------------------------------------------------------------*/
	uint16_t id_class = 0;
	while (1) {
		fill_buffer(input_user_buffer);
		neai_classification(input_user_buffer, output_class_buffer, &id_class);
		/* USER BEGIN */
		/*
		* e.g.: Trigger functions depending on id_class
		* (print output class probabilities using output_class_buffer[],
		* print the name of the identified class using id2class[id_class],
		* blink LED, ring alarm, etc.).
		*/
		/* USER END */
	}
}

通过这段示例代码我们就可以知道,待会儿这个模型我们如何使用,只需要3步,初始化,采样数据,调用检测函数。即可得到检测结果,非常简洁明了,对于完全不了解AI底层算法或者调参的工程师来说,这个真的是太方便好用了,可以帮助我们快速完成项目

 

接下来看看压缩包里有点什么

docs中是一个pdf文档,介绍nanoedge ai还给了一些网址用于学习

emulators中的文件是模拟用的,可以通过命令行做测试,我这儿用不到,就不展示了

.a、.h文件 就是我们回头移植到单片机所需的。

json文件目前没搞明白干嘛的,可能是

 

三.移植算法到开发板上运行

很可惜,本次移植最终是失败率,搞了很久一直无法编译通过。其实移植是很简单的,把.a、.h放到工程中,参照刚才的示例代码调用函数就可以了,但是很可惜学艺不精,cubeide是现学的,有可能是那边没配置到位。也有可能是这个工程有问题,之前就是遇到ld的问题,现在也是卡在ld.exe上。我就把我的操作步骤放一下,工程也放后面,看看有没有懂的大佬给看看

 

工程我就直接用上一篇的datalogger的

 

main.c修改如下

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @File     GPIO/GPIO_IOToggle/Src/main.c
  * @author   MCD Application Team
  * @brief   This example describes how to configure and use GPIOs through
  *          the STM32H7RSxx HAL API.
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2023 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "flash.h"
#include "usart.h"
#include "gpio.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "stdio.h"
#include "iks4a1_motion_sensors.h"
#include "NanoEdgeAI.h"
#include "knowledge.h"
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
typedef struct displayFloatToInt_s {
  int8_t sign; /* 0 means positive, 1 means negative*/
  uint32_t  out_int;
  uint32_t  out_dec;
} displayFloatToInt_t;
/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
#define MAX_BUF_SIZE 256

#define ACC_SAMPLE_MAX 64
#define AXIS  3
/* USER CODE END PD */

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

/* USER CODE END PM */

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

/* USER CODE BEGIN PV */
static uint8_t verbose = 0;  /* Verbose output to UART terminal ON/OFF. */

static IKS4A1_MOTION_SENSOR_Capabilities_t MotionCapabilities[IKS4A1_MOTION_INSTANCES_NBR];

static char dataOut[MAX_BUF_SIZE];

// static int acc_sample_buffer[AXIS * ACC_SAMPLE_MAX] = {0};

float input_user_buffer[DATA_INPUT_USER * AXIS_NUMBER]; // Buffer of input values
float output_class_buffer[CLASS_NUMBER]; // Buffer of class probabilities
/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
/* USER CODE BEGIN PFP */
static void MPU_AdjustRegionAddressSize(uint32_t Address, uint32_t Size, MPU_Region_InitTypeDef* pInit);
static void MPU_Config(void);
/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
int __io_putchar(int ch)
{
    HAL_UART_Transmit(&huart4 , (uint8_t *)&ch, 1, 0xFFFF);
    return ch;
}

static void floatToInt(float in, displayFloatToInt_t *out_value, int32_t dec_prec)
{
  if(in >= 0.0f)
  {
    out_value->sign = 0;
  }else
  {
    out_value->sign = 1;
    in = -in;
  }

  in = in + (0.5f / pow(10, dec_prec));
  out_value->out_int = (int32_t)in;
  in = in - (float)(out_value->out_int);
  out_value->out_dec = (int32_t)trunc(in * pow(10, dec_prec));
}

static void Accelero_Sensor_Handler(uint32_t Instance)
{
//  float odr;
//  int32_t fullScale;
  IKS4A1_MOTION_SENSOR_Axes_t acceleration;
//  displayFloatToInt_t out_value;
//  uint8_t whoami;
  uint16_t i = 0;

  for (i = 0; i < ACC_SAMPLE_MAX;)
  {
    if (0 == IKS4A1_MOTION_SENSOR_GetAxes(Instance, MOTION_ACCELERO, &acceleration))
    {
      input_user_buffer[AXIS * i] = (float)acceleration.x;
      input_user_buffer[(AXIS * i) + 1] = (float)acceleration.y;
      input_user_buffer[(AXIS * i) + 2] = (float)acceleration.z;

      i++;
    }
  }

  // unsigned char data[50] = {0};
  // uint8_t len = 0;
  // for(i = 0; i < ACC_SAMPLE_MAX - 1; i++)
  // {
  //   sprintf(data, "%d,%d,%d,", acc_sample_buffer[i], acc_sample_buffer[i+1], acc_sample_buffer[i+2]);
  //   len = strlen(data);
  //   HAL_UART_Transmit(&huart4, data, len, 0xFFFF);
  // }
  // sprintf(data, "%d,%d,%d", acc_sample_buffer[i], acc_sample_buffer[i+1], acc_sample_buffer[i+2]);
  // len = strlen(data);
  // HAL_UART_Transmit(&huart4, data, len, 0xFFFF);



  // unsigned char data2[] = {"\r\n"};
  // len = strlen(data2);
  // HAL_UART_Transmit(&huart4, data2, len, 0xFFFF);

}

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{

  /* USER CODE BEGIN 1 */
  MPU_Config();
  uint16_t id_class = 0;
  /* USER CODE END 1 */

  /* Enable the CPU Cache */

  /* Enable I-Cache---------------------------------------------------------*/
  SCB_EnableICache();

  /* Enable D-Cache---------------------------------------------------------*/
  SCB_EnableDCache();

  /* MCU Configuration--------------------------------------------------------*/

  /* Update SystemCoreClock variable according to RCC registers values. */
  SystemCoreClockUpdate();

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_UART4_Init();
  MX_FLASH_Init();
  /* USER CODE BEGIN 2 */
  /* ACC传感器初始化 */
  displayFloatToInt_t out_value_odr;
  int i;
  IKS4A1_MOTION_SENSOR_Init(IKS4A1_LSM6DSO16IS_0, MOTION_ACCELERO | MOTION_GYRO);
  unsigned char data[] = "IKS4A1_MOTION_SENSOR_Init ok\r\n";
  HAL_UART_Transmit(&huart4, data, sizeof(data), 0xFFFF);
  // for(i = 0; i < IKS4A1_MOTION_INSTANCES_NBR; i++)
  // {
  //   IKS4A1_MOTION_SENSOR_GetCapabilities(i, &MotionCapabilities[i]);
  //   snprintf(dataOut, MAX_BUF_SIZE,
  //            "\r\nMotion Sensor Instance %d capabilities: \r\n ACCELEROMETER: %d\r\n GYROSCOPE: %d\r\n MAGNETOMETER: %d\r\n LOW POWER: %d\r\n",
  //            i, MotionCapabilities[i].Acc, MotionCapabilities[i].Gyro, MotionCapabilities[i].Magneto, MotionCapabilities[i].LowPower);
  //   printf("%s", dataOut);
  //   floatToInt(MotionCapabilities[i].AccMaxOdr, &out_value_odr, 3);
  //   snprintf(dataOut, MAX_BUF_SIZE, " MAX ACC ODR: %d.%03d Hz, MAX ACC FS: %d\r\n", (int)out_value_odr.out_int,
  //            (int)out_value_odr.out_dec, (int)MotionCapabilities[i].AccMaxFS);
  //   printf("%s", dataOut);
  //   floatToInt(MotionCapabilities[i].GyroMaxOdr, &out_value_odr, 3);
  //   snprintf(dataOut, MAX_BUF_SIZE, " MAX GYRO ODR: %d.%03d Hz, MAX GYRO FS: %d\r\n", (int)out_value_odr.out_int,
  //            (int)out_value_odr.out_dec, (int)MotionCapabilities[i].GyroMaxFS);
  //   printf("%s", dataOut);
  //   floatToInt(MotionCapabilities[i].MagMaxOdr, &out_value_odr, 3);
  //   snprintf(dataOut, MAX_BUF_SIZE, " MAX MAG ODR: %d.%03d Hz, MAX MAG FS: %d\r\n", (int)out_value_odr.out_int,
  //            (int)out_value_odr.out_dec, (int)MotionCapabilities[i].MagMaxFS);
  //   printf("%s", dataOut);
  // }
  enum neai_state error_code = neai_classification_init(knowledge);
	if (error_code != NEAI_OK) {
		/* This happens if the knowledge does not correspond to the library or if the library works into a not supported board. */
	}
  unsigned char data2[] = "neai_classification_init ok\r\n";
  HAL_UART_Transmit(&huart4, data2, sizeof(data2), 0xFFFF);

  /* USER CODE END 2 */

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

    /* USER CODE BEGIN 3 */
  #if 0
    HAL_GPIO_TogglePin(LD1_GPIO_PORT, LD1_Pin);
    /* Insert delay 100 ms */
    HAL_Delay(100);
    HAL_GPIO_TogglePin(LD2_GPIO_PORT, LD2_PIN);
    /* Insert delay 100 ms */
    HAL_Delay(100);
    HAL_GPIO_TogglePin(LD3_GPIO_PORT, LD3_PIN);
    /* Insert delay 100 ms */
    HAL_Delay(100);
    HAL_GPIO_TogglePin(LD4_GPIO_PORT, LD4_PIN);
    /* Insert delay 100 ms */
    HAL_Delay(100);
#endif

#if 0
    unsigned char data[] = "123";
    HAL_UART_Transmit(&huart4, data, sizeof(data), 0xFFFF);

    // printf("666\r\n");
    // float a = 3.14;
    // printf("a = %.2f\r\n", a);
#endif

#if 1
    Accelero_Sensor_Handler(0);
    // HAL_GPIO_TogglePin(LD1_GPIO_PORT, LD1_Pin);
    // HAL_Delay(100);
    neai_classification(input_user_buffer, output_class_buffer, &id_class);
    unsigned char result[50] = {0};
    uint8_t len = 0;
    
    sprintf(result, "id_class = %d", id_class);
    len = strlen(result);
    HAL_UART_Transmit(&huart4, result, len, 0xFFFF);
#endif

  }
  /* USER CODE END 3 */
}

/* USER CODE BEGIN 4 */
/**
  * @brief  This function configures the MPU context of the application.
  * @retval None
  */
static void MPU_Config(void)
{
  MPU_Region_InitTypeDef MPU_InitStruct = {0};
  uint32_t index = MPU_REGION_NUMBER0;
  uint32_t address;
  uint32_t size;

  /* Disable the MPU */
  HAL_MPU_Disable();

  /* Initialize the background region */
  MPU_InitStruct.Enable = MPU_REGION_ENABLE;
  MPU_InitStruct.Number = index;
  MPU_InitStruct.BaseAddress = 0x0;
  MPU_InitStruct.Size = MPU_REGION_SIZE_4GB;
  MPU_InitStruct.SubRegionDisable = 0x87;
  MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
  MPU_InitStruct.AccessPermission = MPU_REGION_NO_ACCESS;
  MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_DISABLE;
  MPU_InitStruct.IsShareable = MPU_ACCESS_SHAREABLE;
  MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE;
  MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE;
  HAL_MPU_ConfigRegion(&MPU_InitStruct);
  index++;

  /* Initialize the region corresponding to external RAM */
#if defined ( __ICCARM__ )
  extern uint32_t __region_EXTRAM_start__;
  extern uint32_t __region_EXTRAM_end__;

  address = (uint32_t)&__region_EXTRAM_start__;
  size = (uint32_t)&__region_EXTRAM_end__ - (uint32_t)&__region_EXTRAM_start__ + 1;

#elif defined (__CC_ARM) || defined(__ARMCC_VERSION)
  extern uint32_t Image$$RW_EXTRAM$$Base;
  extern uint32_t Image$$RW_EXTRAM$$ZI$$Length;
  extern uint32_t Image$$RW_EXTRAM$$Length;

  address = (uint32_t)&Image$$RW_EXTRAM$$Base;
  size  = (uint32_t)&Image$$RW_EXTRAM$$Length + (uint32_t)&Image$$RW_EXTRAM$$ZI$$Length;
#elif defined ( __GNUC__ )
  extern uint32_t __EXTRAM_BEGIN;
  extern uint32_t __EXTRAM_SIZE;
  address = (uint32_t)&__EXTRAM_BEGIN;
  size  = (uint32_t)&__EXTRAM_SIZE;
#else
#error "Compiler toolchain is unsupported"
#endif

  if (size != 0)
  {
    MPU_InitStruct.Enable = MPU_REGION_ENABLE;
    MPU_InitStruct.Number = index;
    MPU_InitStruct.SubRegionDisable = 0u;
    MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL1;
    MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
    MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_DISABLE;
    MPU_InitStruct.IsShareable = MPU_ACCESS_SHAREABLE;
    MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE;
    MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE;
    MPU_AdjustRegionAddressSize(address, size, &MPU_InitStruct);
    HAL_MPU_ConfigRegion(&MPU_InitStruct);
    index++;
  }

  /* Initialize the non cacheable region */
#if defined ( __ICCARM__ )
  /* get the region attribute form the icf file */
  extern uint32_t NONCACHEABLEBUFFER_start;
  extern uint32_t NONCACHEABLEBUFFER_size;

  address = (uint32_t)&NONCACHEABLEBUFFER_start;
  size = (uint32_t)&NONCACHEABLEBUFFER_size;

#elif defined (__CC_ARM) || defined(__ARMCC_VERSION)
  extern uint32_t Image$$RW_NONCACHEABLEBUFFER$$Base;
  extern uint32_t Image$$RW_NONCACHEABLEBUFFER$$Length;
  extern uint32_t Image$$RW_NONCACHEABLEBUFFER$$ZI$$Length;

  address = (uint32_t)&Image$$RW_NONCACHEABLEBUFFER$$Base;
  size  = (uint32_t)&Image$$RW_NONCACHEABLEBUFFER$$Length + (uint32_t)&Image$$RW_NONCACHEABLEBUFFER$$ZI$$Length;
#elif defined ( __GNUC__ )
  extern int __NONCACHEABLEBUFFER_BEGIN;
  extern int __NONCACHEABLEBUFFER_END;

  address = (uint32_t)&__NONCACHEABLEBUFFER_BEGIN;
  size  = (uint32_t)&__NONCACHEABLEBUFFER_END - (uint32_t)&__NONCACHEABLEBUFFER_BEGIN;
#else
#error "Compiler toolchain is unsupported"
#endif

  if (size != 0)
  {
    /* Configure the MPU attributes as Normal Non Cacheable */
    MPU_InitStruct.Enable = MPU_REGION_ENABLE;
    MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
    MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;
    MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;
    MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
    MPU_InitStruct.Number = index;
    MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL1;
    MPU_InitStruct.SubRegionDisable = 0x00;
    MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_DISABLE;
    MPU_AdjustRegionAddressSize(address, size, &MPU_InitStruct);
    HAL_MPU_ConfigRegion(&MPU_InitStruct);
    index++;
  }

  /* Initialize the region corresponding to the execution area
     (external or internal flash or external or internal RAM
     depending on scatter file definition) */
#if defined ( __ICCARM__ )
  extern uint32_t __ICFEDIT_region_ROM_start__;
  extern uint32_t __ICFEDIT_region_ROM_end__;
  address = (uint32_t)&__ICFEDIT_region_ROM_start__;
  size = (uint32_t)&__ICFEDIT_region_ROM_end__ - (uint32_t)&__ICFEDIT_region_ROM_start__ + 1;
#elif defined (__CC_ARM) || defined(__ARMCC_VERSION)
  extern uint32_t Image$$ER_ROM$$Base;
  extern uint32_t Image$$ER_ROM$$Limit;
  address = (uint32_t)&Image$$ER_ROM$$Base;
  size    = (uint32_t)&Image$$ER_ROM$$Limit-(uint32_t)&Image$$ER_ROM$$Base;
#elif defined ( __GNUC__ )
  extern uint32_t __FLASH_BEGIN;
  extern uint32_t __FLASH_SIZE;
  address = (uint32_t)&__FLASH_BEGIN;
  size  = (uint32_t)&__FLASH_SIZE;
#else
#error "Compiler toolchain is unsupported"
#endif

  MPU_InitStruct.Enable = MPU_REGION_ENABLE;
  MPU_InitStruct.Number = index;
  MPU_InitStruct.SubRegionDisable = 0u;
  MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL1;
  MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
  MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;
  MPU_InitStruct.IsShareable = MPU_ACCESS_SHAREABLE;
  MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE;
  MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE;
  MPU_AdjustRegionAddressSize(address, size, &MPU_InitStruct);
  HAL_MPU_ConfigRegion(&MPU_InitStruct);
  index++;

  /* Reset unused MPU regions */
  for(; index < __MPU_REGIONCOUNT ; index++)
  {
    /* All unused regions disabled */
    MPU_InitStruct.Enable = MPU_REGION_DISABLE;
    MPU_InitStruct.Number = index;
    HAL_MPU_ConfigRegion(&MPU_InitStruct);
  }

  /* Enable the MPU */
  HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
}

/**
  * @brief This function adjusts the MPU region Address and Size within an MPU configuration.
  * @param Address memory address
  * @param Size memory size
  * @param pInit pointer to an MPU initialization structure
  * @retval None
  */
static void MPU_AdjustRegionAddressSize(uint32_t Address, uint32_t Size, MPU_Region_InitTypeDef* pInit)
{
  /* Compute the MPU region size */
  pInit->Size = ((31 - __CLZ(Size)) - 1);
  if (Size > (1 << (pInit->Size + 1)))
  {
    pInit->Size++;
  }
  uint32_t Modulo = Address % (1 << (pInit->Size - 1));
  if (0 != Modulo)
  {
    /* Align address with MPU region size considering there is no need to increase the size */
    pInit->BaseAddress = Address - Modulo;
  }
  else
  {
    pInit->BaseAddress = Address;
  }
}
/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  while(1) 
  {
  }
  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
    ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* Infinite loop */
  while (1)
  {
  }
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

 

在工程的文件夹下建一个名字就叫nanoEdgeAi的文件夹(你取别的名字也可以的),把.a、.h放进来

先在工程中添加文件夹

添加文件

添加.h路径

添加库文件路径

添加库文件

rebuild index

编译,得到如下错误

C:/ST/STM32CubeIDE_1.15.0/STM32CubeIDE/plugins/com.st.stm32cube.ide.mcu.externaltools.gnu-tools-for-stm32.12.3.rel1.win32_1.0.100.202403111256/tools/bin/../lib/gcc/arm-none-eabi/12.3.1/../../../../arm-none-eabi/bin/ld.exe: cannot find -l-mcpu=cortex-m7: No such file or directory
collect2.exe: error: ld returned 1 exit status
make: *** [makefile:68: GPIO_IOToggle_Appli.elf] Error 1

-l-mcpu=cortex-m7这玩意儿找不到,这玩意儿我百度找了半天都没搞明白是个什么意思,已经触摸到我的知识盲区了,无奈只能止步于此了

/*****************************************************************************/

2024.11.12补充

移植到开发板失败的问题,已经通过曲线救国的方式解决了,模型成功运行,效果很好,请看“[STM32H7R/S]测评 ⑨nano edge ai studio 训练一个模型--下 https://bbs.eeworld.com.cn/thread-1298763-1-1.html”这篇文章

/****************************************************************************/

 

 

本文的一些文件如下

最终生成的压缩包: libneai_project2024-11-09-15-29-02_2.zip (403.71 KB, 下载次数: 1)
第四步的测试数据: circle_test.csv (834 Bytes, 下载次数: 3)

第二步的三种采样数据:

circle.csv (81.94 KB, 下载次数: 3)
line.csv (75.57 KB, 下载次数: 2)
stop.csv (68.79 KB, 下载次数: 2)
工程: GPIO_IOToggle.rar (22.22 MB, 下载次数: 3)
此帖出自stm32/stm8论坛

最新回复

大佬有检查过MAKEFILE没   详情 回复 发表于 2024-11-10 11:23
点赞(1) 关注
 

回复
举报

166

帖子

1

TA的资源

一粒金砂(高级)

沙发
 

大佬有检查过MAKEFILE没

此帖出自stm32/stm8论坛

点评

我只会一些简单的makefile,这种工程的makefile太复杂了,看不明白不过我已经通过一种曲线救国的方法达到目的了,模型成功在开发板上跑起来了,效果超级好,今晚会更新一篇新的文章  详情 回复 发表于 2024-11-11 09:51
 
个人签名

没用比没有强

 

回复

88

帖子

3

TA的资源

一粒金砂(高级)

板凳
 
电子烂人 发表于 2024-11-10 11:23 大佬有检查过MAKEFILE没

我只会一些简单的makefile,这种工程的makefile太复杂了,看不明白不过我已经通过一种曲线救国的方法达到目的了,模型成功在开发板上跑起来了,效果超级好,今晚会更新一篇新的文章

此帖出自stm32/stm8论坛
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
推荐帖子
自学单片机心得体会

无论是作为一名业余的电子爱好者还是一名电子行业的相关从业人员,掌握单片机技术无疑可以使您如虎添翼,为您的电子小制作或者开 ...

AT91RM9200调试心得

AT91RM9200的资料,分享ING

glibc-2.11-libgcc_eh-1.patch

C运行时库glibc的相关安装包及补丁地址: glibc-2.11.tar.bz2,下载地址为 ftp://ftp.gnu.org/gnu/glibc/glibc-2.11.tar.bz2 ...

一次“血”的教训之Xilinx FPGA菊花链

这篇文章主要是还原一个“事故”现场,具体原因有待进一步分析。 遇难芯片:1片Xilinx FPGA XC5VSX95T、1片PROM XCF32P、2片 ...

SDRAM串口实验之依样画葫芦(verilog)

前一段时间在这里申请了开发板,然后一直没来得及做实验,平时太忙。上周花了一天的时间把别人verilog(最初始是特权)写的SDRAM ...

【求助】平头哥场景化蓝牙Mesh节点烧录遇到的问题和部分解决办法

我想实现一个可以联网的温湿度功能,先解压ble_mesh_gateway_node_sdk到本地硬盘,solutions里正好有一个mesh_temperature_senso ...

X-CAP导致继电器电流尖峰?

下图这个电路,测量最开始的输入端电流和继电器电流,分别是情色和黑色,那个黑色尖峰就是继电器的电流,去掉X-CAP后就没有了, ...

请问我该如何硬件切换电源

我现在驱动电磁阀,需要24V的启动电压,但这个电压的时间不能太长,在启动后马上需要切换到6V来维持,否则电磁阀容易过热损坏, ...

来做个调查呀~~小伙伴们都对什么样的书感兴趣呀??

管管最近正在做书籍调查,来问问小伙伴们都对什么样的书感兴趣呀? 人工智能,深度学习,Python,嵌入式Linux等等... 还 ...

【国产Tang Primer 25K测评】基于E203的扩展外设的简单例子-第一篇硬件层

上一期演示了如何简单移植E203在Tang25K开发板上,这次就简单演示一下如何在E203软核上添加外设,存在一定的问题,就是在地址偏 ...

关闭
站长推荐上一条 1/8 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表