本帖最后由 不爱胡萝卜的仓鼠 于 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”这篇文章
/****************************************************************************/
本文的一些文件如下
第二步的三种采样数据: