This post was last edited by Hamster who doesn't like carrots on 2024-10-20 18:16
This article is a preliminary preparation for playing with NanoEdge AI Studio. This software is a software that allows users to train models by themselves, and can implement anomaly detection, outlier detection, classification, and regression libraries. We will introduce the specific details in the subsequent specific articles.
The training model needs sample data input. I plan to use accelerometer data to recognize certain actions. I happen to have an X-NUCLEO-IKS4A1 development board with an accelerometer, so I will port the relevant content of this development board to it today.
1. Install the X-NUCLEO-IKS4A1 development board
The X-NUCLEO-IKS4A1 development board uses the Arduino interface. You can plug it directly into the development board and use it. It is very convenient. The configuration jumper caps on the development board are as shown in the figure. The default jumper caps are used.
2.cubemx configuration
The project will use the previous one, and we will continue to modify it
First, make sure that the IIC interface used on the Arduino interface corresponds to the two GPIOs used on the board. After looking at the documentation, the PB6 and PB9 used
First open the flash (because it cannot be opened without opening IIC, cubemx has corresponding prompts)
Then we turn on IIC and configure the pins correctly
IIC speed changed to fast mode
IIC is now open and completed
Next, add the mems plug-in, find X-CUBE-MEMS1 in "Middleware and Software Packs", click it and a pop-up window will appear, select X-NUCLEO-IKS4A1 (I have already installed the corresponding package)
Then turn on the X-CUBE-MEMS1 and pair it with the IIC you actually use.
This configuration is OK, and the project can be generated.
3. Code modification
Refer to the demo source code of U575 matching X-NUCLEO-IKS4A1, modify main.c, I only initialize LSM6DSO16IS, and then read its ACC data. The main.c code is as follows
/* USER CODE BEGIN Header */
/**
******************************************************************************
* [url=home.php?mod=space&uid=1307177]@File[/url] GPIO/GPIO_IOToggle/Src/main.c
* [url=home.php?mod=space&uid=1315547]@author[/url] MCD Application Team
* [url=home.php?mod=space&uid=159083]@brief[/url] 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"
/* 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
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
static uint8_t verbose = 1; /* Verbose output to UART terminal ON/OFF. */
static IKS4A1_MOTION_SENSOR_Capabilities_t MotionCapabilities[IKS4A1_MOTION_INSTANCES_NBR];
static char dataOut[MAX_BUF_SIZE];
/* 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;
snprintf(dataOut, MAX_BUF_SIZE, "\r\nMotion sensor instance %d:", (int)Instance);
printf("%s", dataOut);
if (IKS4A1_MOTION_SENSOR_GetAxes(Instance, MOTION_ACCELERO, &acceleration))
{
snprintf(dataOut, MAX_BUF_SIZE, "\r\nACC[%d]: Error\r\n", (int)Instance);
}
else
{
snprintf(dataOut, MAX_BUF_SIZE, "\r\nACC_X[%d]: %d, ACC_Y[%d]: %d, ACC_Z[%d]: %d\r\n", (int)Instance,
(int)acceleration.x, (int)Instance, (int)acceleration.y, (int)Instance, (int)acceleration.z);
}
printf("%s", dataOut);
if (verbose == 1)
{
if (IKS4A1_MOTION_SENSOR_ReadID(Instance, &whoami))
{
snprintf(dataOut, MAX_BUF_SIZE, "WHOAMI[%d]: Error\r\n", (int)Instance);
}
else
{
snprintf(dataOut, MAX_BUF_SIZE, "WHOAMI[%d]: 0x%x\r\n", (int)Instance, (int)whoami);
}
printf("%s", dataOut);
if (IKS4A1_MOTION_SENSOR_GetOutputDataRate(Instance, MOTION_ACCELERO, &odr))
{
snprintf(dataOut, MAX_BUF_SIZE, "ODR[%d]: ERROR\r\n", (int)Instance);
}
else
{
floatToInt(odr, &out_value, 3);
snprintf(dataOut, MAX_BUF_SIZE, "ODR[%d]: %d.%03d Hz\r\n", (int)Instance, (int)out_value.out_int,
(int)out_value.out_dec);
}
printf("%s", dataOut);
if (IKS4A1_MOTION_SENSOR_GetFullScale(Instance, MOTION_ACCELERO, &fullScale))
{
snprintf(dataOut, MAX_BUF_SIZE, "FS[%d]: ERROR\r\n", (int)Instance);
}
else
{
snprintf(dataOut, MAX_BUF_SIZE, "FS[%d]: %d g\r\n", (int)Instance, (int)fullScale);
}
printf("%s", dataOut);
}
}
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
MPU_Config();
/* 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);
printf("IKS4A1_MOTION_SENSOR_Init ok\r\n");
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);
}
/* 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 0
snprintf(dataOut, MAX_BUF_SIZE, "\r\n__________________________________________________________________________\r\n");
printf("%s", dataOut);
for(i = 0; i < IKS4A1_MOTION_INSTANCES_NBR; i++)
{
if(MotionCapabilities[i].Acc)
{
Accelero_Sensor_Handler(i);
}
// if(MotionCapabilities[i].Gyro)
// {
// Gyro_Sensor_Handler(i);
// }
// if(MotionCapabilities[i].Magneto)
// {
// Magneto_Sensor_Handler(i);
// }
}
HAL_Delay( 1000 );
#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 */
Turn off other motion sensors in the .h file of IKS4A1 configuration
That's it, the ACC data is read successfully