diff --git a/libraries/MLC/examples/NiclaVision_DataLogger_FIFO/NiclaVision_DataLogger_FIFO.ino b/libraries/MLC/examples/NiclaVision_DataLogger_FIFO/NiclaVision_DataLogger_FIFO.ino
new file mode 100644
index 000000000..1bd9c917b
--- /dev/null
+++ b/libraries/MLC/examples/NiclaVision_DataLogger_FIFO/NiclaVision_DataLogger_FIFO.ino
@@ -0,0 +1,265 @@
+/*
+ This example exposes the second MB of Nicla Vision flash as a USB disk.
+ The user can interact with this disk as a bidirectional communication with the board
+ For example, the board could save data in a file to be retrieved later with a drag and drop.
+ If the user does a double tap, the firmware goes to datalogger mode (green led on).
+ Now the user can do another double tap to start a recording of the IMU data
+ (green led blinking). With another double tap the recording will be stopped (green led on).
+ Now the user can start/stop other recordings of the IMU data using again the double tap.
+ The log files are saved in flash with an increasing number suffix data_0.txt, data_1.txt, etc.
+ If you want to transfer the log files to the PC, you can reset the board and
+ wait for 10 seconds (blue led blinking).
+*/
+
+#include "PluggableUSBMSD.h"
+#include "QSPIFBlockDevice.h"
+#include "MBRBlockDevice.h"
+#include "FATFileSystem.h"
+#include "LSM6DSOXSensor.h"
+
+#define INT_1 LSM6DS_INT
+#define SENSOR_ODR 104.0f // In Hertz
+#define ACC_FS 2 // In g
+#define GYR_FS 2000 // In dps
+#define MEASUREMENT_TIME_INTERVAL (1000.0f/SENSOR_ODR) // In ms
+#define FIFO_SAMPLE_THRESHOLD 199
+#define FLASH_BUFF_LEN 8192
+
+typedef enum {
+ DATA_STORAGE_STATE,
+ DATA_LOGGER_IDLE_STATE,
+ DATA_LOGGER_RUNNING_STATE
+} demo_state_e;
+
+volatile demo_state_e demo_state = DATA_STORAGE_STATE;
+volatile int mems_event = 0;
+uint32_t file_count = 0;
+unsigned long timestamp_count = 0;
+bool acc_available = false;
+bool gyr_available = false;
+int32_t acc_value[3];
+int32_t gyr_value[3];
+char buff[FLASH_BUFF_LEN];
+uint32_t pos = 0;
+
+QSPIFBlockDevice root(QSPI_SO0, QSPI_SO1, QSPI_SO2, QSPI_SO3, QSPI_SCK, QSPI_CS, QSPIF_POLARITY_MODE_1, 40000000);
+// Partition 1 is allocated to WiFi
+mbed::MBRBlockDevice lsm_data(&root, 2);
+static mbed::FATFileSystem lsm_fs("lsm");
+
+LSM6DSOXSensor AccGyr(&SPI1, PIN_SPI_SS1);
+
+USBMSD MassStorage(&root);
+
+rtos::Thread acquisition_th;
+
+FILE *f = nullptr;
+
+void INT1Event_cb()
+{
+ mems_event = 1;
+}
+
+void USBMSD::begin()
+{
+ int err = lsm_fs.mount(&lsm_data);
+ if (err) {
+ Serial.println("mount failed");
+ err = lsm_fs.reformat(&lsm_data);
+ if (err) {
+ Serial.println("Reformat failed");
+ return;
+ }
+ }
+}
+
+mbed::FATFileSystem &USBMSD::getFileSystem()
+{
+ static mbed::FATFileSystem fs("lsm");
+ return fs;
+}
+
+void led_green_thd()
+{
+ while (1) {
+ if (demo_state == DATA_LOGGER_RUNNING_STATE) {
+ digitalWrite(LEDG, LOW);
+ delay(100);
+ digitalWrite(LEDG, HIGH);
+ delay(100);
+ }
+ }
+}
+
+void Read_FIFO_Data(uint16_t samples_to_read)
+{
+ uint16_t i;
+
+ for (i = 0; i < samples_to_read; i++) {
+ uint8_t tag;
+ // Check the FIFO tag
+ AccGyr.Get_FIFO_Tag(&tag);
+ switch (tag) {
+ // If we have a gyro tag, read the gyro data
+ case LSM6DSOX_GYRO_NC_TAG: {
+ AccGyr.Get_FIFO_G_Axes(gyr_value);
+ gyr_available = true;
+ break;
+ }
+ // If we have an acc tag, read the acc data
+ case LSM6DSOX_XL_NC_TAG: {
+ AccGyr.Get_FIFO_X_Axes(acc_value);
+ acc_available = true;
+ break;
+ }
+ // We can discard other tags
+ default: {
+ break;
+ }
+ }
+ // If we have the measurements of both acc and gyro, we can store them with timestamp
+ if (acc_available && gyr_available) {
+ int num_bytes;
+ num_bytes = snprintf(&buff[pos], (FLASH_BUFF_LEN - pos), "%lu %d %d %d %d %d %d\n", (unsigned long)((float)timestamp_count * MEASUREMENT_TIME_INTERVAL), (int)acc_value[0], (int)acc_value[1], (int)acc_value[2], (int)gyr_value[0], (int)gyr_value[1], (int)gyr_value[2]);
+ pos += num_bytes;
+ timestamp_count++;
+ acc_available = false;
+ gyr_available = false;
+ }
+ }
+ // We can add the termination character to the string, so we are ready to save it in flash
+ buff[pos] = '\0';
+ pos = 0;
+}
+
+void setup()
+{
+ Serial.begin(115200);
+ MassStorage.begin();
+ pinMode(LEDB, OUTPUT);
+ pinMode(LEDG, OUTPUT);
+ digitalWrite(LEDB, HIGH);
+ digitalWrite(LEDG, HIGH);
+
+ // Initialize SPI1 bus.
+ SPI1.begin();
+
+ //Interrupts.
+ attachInterrupt(INT_1, INT1Event_cb, RISING);
+
+ // Initialize IMU.
+ AccGyr.begin();
+ AccGyr.Enable_X();
+ AccGyr.Enable_G();
+ // Configure ODR and FS of the acc and gyro
+ AccGyr.Set_X_ODR(SENSOR_ODR);
+ AccGyr.Set_X_FS(ACC_FS);
+ AccGyr.Set_G_ODR(SENSOR_ODR);
+ AccGyr.Set_G_FS(GYR_FS);
+ // Enable the Double Tap event
+ AccGyr.Enable_Double_Tap_Detection(LSM6DSOX_INT1_PIN);
+ // Configure FIFO BDR for acc and gyro
+ AccGyr.Set_FIFO_X_BDR(SENSOR_ODR);
+ AccGyr.Set_FIFO_G_BDR(SENSOR_ODR);
+ // Start Led blinking thread
+ acquisition_th.start(led_green_thd);
+}
+
+void loop()
+{
+
+ if (mems_event) {
+ mems_event = 0;
+ LSM6DSOX_Event_Status_t status;
+ AccGyr.Get_X_Event_Status(&status);
+ if (status.DoubleTapStatus) {
+ switch (demo_state) {
+ case DATA_STORAGE_STATE: {
+ // Go to DATA_LOGGER_IDLE_STATE state
+ demo_state = DATA_LOGGER_IDLE_STATE;
+ digitalWrite(LEDG, LOW);
+ Serial.println("From DATA_STORAGE_STATE To DATA_LOGGER_IDLE_STATE");
+ break;
+ }
+ case DATA_LOGGER_IDLE_STATE: {
+ char filename[32];
+ // Go to DATA_LOGGER_RUNNING_STATE state
+ snprintf(filename, 32, "/lsm/data_%lu.txt", file_count);
+ Serial.print("Start writing file ");
+ Serial.println(filename);
+ // open a file to write some data
+ // w+ means overwrite, so every time the board is rebooted the file will be overwritten
+ f = fopen(filename, "w+");
+ if (f != nullptr) {
+ // write header
+ fprintf(f, "Timestamp[ms] A_X [mg] A_Y [mg] A_Z [mg] G_X [mdps] G_Y [mdps] G_Z [mdps]\n");
+ fflush(f);
+ Serial.println("From DATA_LOGGER_IDLE_STATE To DATA_LOGGER_RUNNING_STATE");
+ demo_state = DATA_LOGGER_RUNNING_STATE;
+ digitalWrite(LEDG, HIGH);
+ timestamp_count = 0;
+ pos = 0;
+ acc_available = false;
+ gyr_available = false;
+ // Set FIFO in Continuous mode
+ AccGyr.Set_FIFO_Mode(LSM6DSOX_STREAM_MODE);
+ }
+ break;
+ }
+ case DATA_LOGGER_RUNNING_STATE: {
+ // Empty the FIFO
+ uint16_t fifo_samples;
+ AccGyr.Get_FIFO_Num_Samples(&fifo_samples);
+ Read_FIFO_Data(fifo_samples);
+ // Store the string in flash
+ fprintf(f, "%s", buff);
+ fflush(f);
+
+ // Close the log file and increase the counter
+ fclose(f);
+ file_count++;
+ // Set FIFO in Bypass mode
+ AccGyr.Set_FIFO_Mode(LSM6DSOX_BYPASS_MODE);
+ // Go to DATA_LOGGER_IDLE_STATE state
+ demo_state = DATA_LOGGER_IDLE_STATE;
+ // Wait for the led thread ends the blinking
+ delay(250);
+ digitalWrite(LEDG, LOW);
+ Serial.println("From DATA_LOGGER_RUNNING_STATE To DATA_LOGGER_IDLE_STATE");
+ break;
+ }
+ default:
+ Serial.println("Error! Invalid state");
+ }
+ }
+ }
+
+ if (demo_state == DATA_LOGGER_RUNNING_STATE) {
+ uint16_t fifo_samples;
+
+ // Check the number of samples inside FIFO
+ AccGyr.Get_FIFO_Num_Samples(&fifo_samples);
+
+ // If we reach the threshold we can empty the FIFO
+ if (fifo_samples > FIFO_SAMPLE_THRESHOLD) {
+ // Empty the FIFO
+ Read_FIFO_Data(fifo_samples);
+ // Store the string in flash
+ fprintf(f, "%s", buff);
+ fflush(f);
+ }
+ }
+
+ if (demo_state == DATA_STORAGE_STATE && millis() > 10000) {
+ // Disable the sensor and go to Mass Storage mode
+ AccGyr.Disable_Double_Tap_Detection();
+ AccGyr.Disable_X();
+ AccGyr.Disable_G();
+ while (1) {
+ digitalWrite(LEDB, LOW);
+ delay(100);
+ digitalWrite(LEDB, HIGH);
+ delay(100);
+ }
+ }
+}
diff --git a/libraries/MLC/examples/NiclaVision_MLC_Motion_Intensity/NiclaVision_MLC_Motion_Intensity.ino b/libraries/MLC/examples/NiclaVision_MLC_Motion_Intensity/NiclaVision_MLC_Motion_Intensity.ino
new file mode 100644
index 000000000..b865d0068
--- /dev/null
+++ b/libraries/MLC/examples/NiclaVision_MLC_Motion_Intensity/NiclaVision_MLC_Motion_Intensity.ino
@@ -0,0 +1,134 @@
+/*
+ This example shows how to load the MLC bytecode for Motion Intensity on LSM6DSOX
+ of the Arduino Nicla Vision.
+*/
+
+// Includes
+#include "LSM6DSOXSensor.h"
+#include "lsm6dsox_motion_intensity.h"
+
+#define INT_1 LSM6DS_INT
+
+//Interrupts.
+volatile int mems_event = 0;
+
+// Components
+LSM6DSOXSensor AccGyr(&SPI1, PIN_SPI_SS1);
+
+// MLC
+ucf_line_t *ProgramPointer;
+int32_t LineCounter;
+int32_t TotalNumberOfLine;
+
+void INT1Event_cb();
+void printMLCStatus(uint8_t status);
+
+void setup()
+{
+ // Led.
+ pinMode(LEDB, OUTPUT);
+ pinMode(LEDG, OUTPUT);
+ pinMode(LEDR, OUTPUT);
+ digitalWrite(LEDB, HIGH);
+ digitalWrite(LEDG, HIGH);
+ digitalWrite(LEDR, HIGH);
+
+ // Initialize serial for output.
+ Serial.begin(115200);
+
+ // Initialize I2C bus.
+ SPI1.begin();
+
+ AccGyr.begin();
+
+ /* Feed the program to Machine Learning Core */
+ /* Motion Intensity Default program */
+ ProgramPointer = (ucf_line_t *)lsm6dsox_motion_intensity;
+ TotalNumberOfLine = sizeof(lsm6dsox_motion_intensity) / sizeof(ucf_line_t);
+ Serial.println("Motion Intensity for LSM6DSOX MLC");
+ Serial.print("UCF Number Line=");
+ Serial.println(TotalNumberOfLine);
+
+ for (LineCounter = 0; LineCounter < TotalNumberOfLine; LineCounter++) {
+ if (AccGyr.Write_Reg(ProgramPointer[LineCounter].address, ProgramPointer[LineCounter].data)) {
+ Serial.print("Error loading the Program to LSM6DSOX at line: ");
+ Serial.println(LineCounter);
+ while (1) {
+ // Led blinking.
+ digitalWrite(LED_BUILTIN, LOW);
+ delay(250);
+ digitalWrite(LED_BUILTIN, HIGH);
+ delay(250);
+ }
+ }
+ }
+
+ Serial.println("Program loaded inside the LSM6DSOX MLC");
+
+ AccGyr.Enable_X();
+ AccGyr.Set_X_ODR(104.0f);
+ AccGyr.Set_X_FS(2);
+
+ //Interrupts.
+ pinMode(INT_1, INPUT);
+ attachInterrupt(INT_1, INT1Event_cb, RISING);
+}
+
+void loop()
+{
+ if (mems_event) {
+ mems_event = 0;
+ LSM6DSOX_MLC_Status_t status;
+ AccGyr.Get_MLC_Status(&status);
+ if (status.is_mlc1) {
+ uint8_t mlc_out[8];
+ AccGyr.Get_MLC_Output(mlc_out);
+ printMLCStatus(mlc_out[0]);
+ }
+ }
+}
+
+void INT1Event_cb()
+{
+ mems_event = 1;
+}
+
+void printMLCStatus(uint8_t status)
+{
+ switch (status) {
+ case 1:
+ // Reset leds status
+ digitalWrite(LEDB, HIGH);
+ digitalWrite(LEDG, HIGH);
+ digitalWrite(LEDR, HIGH);
+ // LEDB On
+ digitalWrite(LEDB, LOW);
+ Serial.println("Stationary");
+ break;
+ case 4:
+ // Reset leds status
+ digitalWrite(LEDB, HIGH);
+ digitalWrite(LEDG, HIGH);
+ digitalWrite(LEDR, HIGH);
+ // LEDG On
+ digitalWrite(LEDG, LOW);
+ Serial.println("Medium Intensity");
+ break;
+ case 8:
+ // Reset leds status
+ digitalWrite(LEDB, HIGH);
+ digitalWrite(LEDG, HIGH);
+ digitalWrite(LEDR, HIGH);
+ // LEDR On
+ digitalWrite(LEDR, LOW);
+ Serial.println("High Intensity");
+ break;
+ default:
+ // Reset leds status
+ digitalWrite(LEDB, HIGH);
+ digitalWrite(LEDG, HIGH);
+ digitalWrite(LEDR, HIGH);
+ Serial.println("Unknown");
+ break;
+ }
+}
diff --git a/libraries/MLC/examples/NiclaVision_MLC_Motion_Intensity/lsm6dsox_motion_intensity.h b/libraries/MLC/examples/NiclaVision_MLC_Motion_Intensity/lsm6dsox_motion_intensity.h
new file mode 100644
index 000000000..cd669df13
--- /dev/null
+++ b/libraries/MLC/examples/NiclaVision_MLC_Motion_Intensity/lsm6dsox_motion_intensity.h
@@ -0,0 +1,127 @@
+/*
+ ******************************************************************************
+ * @file lsm6dsox_motion_intensity.h
+ * @author Sensors Software Solution Team
+ * @brief This file contains the configuration for lsm6dsox_motion_intensity.
+ *
+ ******************************************************************************
+ * @attention
+ *
+ *
© Copyright (c) 2021 STMicroelectronics.
+ * All rights reserved.
+ *
+ * This software component is licensed by ST under BSD 3-Clause license,
+ * the "License"; You may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at:
+ * opensource.org/licenses/BSD-3-Clause
+ *
+ */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef LSM6DSOX_MOTION_INTENSITY_H
+#define LSM6DSOX_MOTION_INTENSITY_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/* Includes ------------------------------------------------------------------*/
+#include
+#ifndef MEMS_UCF_SHARED_TYPES
+#define MEMS_UCF_SHARED_TYPES
+
+/** Common data block definition **/
+typedef struct {
+ uint8_t address;
+ uint8_t data;
+} ucf_line_t;
+
+#endif /* MEMS_UCF_SHARED_TYPES */
+
+/** Configuration array generated from Unico Tool **/
+const ucf_line_t lsm6dsox_motion_intensity[] = {
+ {.address = 0x10, .data = 0x00,},
+ {.address = 0x11, .data = 0x00,},
+ {.address = 0x01, .data = 0x80,},
+ {.address = 0x04, .data = 0x00,},
+ {.address = 0x05, .data = 0x00,},
+ {.address = 0x17, .data = 0x40,},
+ {.address = 0x02, .data = 0x11,},
+ {.address = 0x08, .data = 0xEA,},
+ {.address = 0x09, .data = 0x46,},
+ {.address = 0x09, .data = 0x03,},
+ {.address = 0x09, .data = 0x50,},
+ {.address = 0x09, .data = 0x03,},
+ {.address = 0x09, .data = 0x00,},
+ {.address = 0x09, .data = 0x00,},
+ {.address = 0x09, .data = 0x0A,},
+ {.address = 0x02, .data = 0x11,},
+ {.address = 0x08, .data = 0xF2,},
+ {.address = 0x09, .data = 0x34,},
+ {.address = 0x02, .data = 0x11,},
+ {.address = 0x08, .data = 0xFA,},
+ {.address = 0x09, .data = 0x3C,},
+ {.address = 0x09, .data = 0x03,},
+ {.address = 0x09, .data = 0x52,},
+ {.address = 0x09, .data = 0x03,},
+ {.address = 0x09, .data = 0x5E,},
+ {.address = 0x09, .data = 0x03,},
+ {.address = 0x02, .data = 0x31,},
+ {.address = 0x08, .data = 0x3C,},
+ {.address = 0x09, .data = 0x3F,},
+ {.address = 0x09, .data = 0x00,},
+ {.address = 0x09, .data = 0x01,},
+ {.address = 0x09, .data = 0x10,},
+ {.address = 0x09, .data = 0x00,},
+ {.address = 0x09, .data = 0x00,},
+ {.address = 0x09, .data = 0x00,},
+ {.address = 0x09, .data = 0x00,},
+ {.address = 0x09, .data = 0x1F,},
+ {.address = 0x09, .data = 0x00,},
+ {.address = 0x02, .data = 0x31,},
+ {.address = 0x08, .data = 0x52,},
+ {.address = 0x09, .data = 0x00,},
+ {.address = 0x09, .data = 0x00,},
+ {.address = 0x09, .data = 0x00,},
+ {.address = 0x09, .data = 0x00,},
+ {.address = 0x09, .data = 0x00,},
+ {.address = 0x09, .data = 0x00,},
+ {.address = 0x09, .data = 0x00,},
+ {.address = 0x09, .data = 0x00,},
+ {.address = 0x09, .data = 0x00,},
+ {.address = 0x09, .data = 0x00,},
+ {.address = 0x09, .data = 0x00,},
+ {.address = 0x01, .data = 0x00,},
+ {.address = 0x01, .data = 0x80,},
+ {.address = 0x17, .data = 0x40,},
+ {.address = 0x02, .data = 0x31,},
+ {.address = 0x08, .data = 0x5E,},
+ {.address = 0x09, .data = 0x00,},
+ {.address = 0x09, .data = 0x2C,},
+ {.address = 0x09, .data = 0x80,},
+ {.address = 0x09, .data = 0xA0,},
+ {.address = 0x09, .data = 0x00,},
+ {.address = 0x09, .data = 0x00,},
+ {.address = 0x09, .data = 0x41,},
+ {.address = 0x09, .data = 0xE0,},
+ {.address = 0x01, .data = 0x80,},
+ {.address = 0x17, .data = 0x00,},
+ {.address = 0x04, .data = 0x00,},
+ {.address = 0x05, .data = 0x10,},
+ {.address = 0x02, .data = 0x01,},
+ {.address = 0x01, .data = 0x00,},
+ {.address = 0x5E, .data = 0x02,},
+ {.address = 0x01, .data = 0x80,},
+ {.address = 0x0D, .data = 0x01,},
+ {.address = 0x60, .data = 0x35,},
+ {.address = 0x01, .data = 0x00,},
+ {.address = 0x10, .data = 0x40,},
+ {.address = 0x11, .data = 0x00,}
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LSM6DSOX_MOTION_INTENSITY_H */
+
diff --git a/libraries/MLC/examples/RP2040_DataLogger_FIFO/RP2040_DataLogger_FIFO.ino b/libraries/MLC/examples/RP2040_DataLogger_FIFO/RP2040_DataLogger_FIFO.ino
new file mode 100644
index 000000000..ce39211bd
--- /dev/null
+++ b/libraries/MLC/examples/RP2040_DataLogger_FIFO/RP2040_DataLogger_FIFO.ino
@@ -0,0 +1,258 @@
+/*
+ This example exposes the first MB of Rp2040 flash as a USB disk.
+ The user can interact with this disk as a bidirectional communication with the board
+ For example, the board could save data in a file to be retrieved later with a drag and drop.
+ If the user does a double tap, the firmware goes to datalogger mode (green led on).
+ Now the user can do another double tap to start a recording of the IMU data
+ (green led blinking). With another double tap the recording will be stopped (green led on).
+ Now the user can start/stop other recordings of the IMU data using again the double tap.
+ The log files are saved in flash with an increasing number suffix data_0.txt, data_1.txt, etc.
+ If you want to transfer the log files to the PC, you can reset the board and
+ wait for 10 seconds (blue led blinking).
+ You can find the video tutorial on LSM6DSOX MLC at: https://docs.arduino.cc/tutorials/nano-rp2040-connect/rp2040-imu-advanced
+*/
+
+#include "PluggableUSBMSD.h"
+#include "FlashIAPBlockDevice.h"
+#include "WiFiNINA.h"
+#include "LSM6DSOXSensor.h"
+
+#define INT_1 INT_IMU
+#define SENSOR_ODR 104.0f // In Hertz
+#define ACC_FS 2 // In g
+#define GYR_FS 2000 // In dps
+#define MEASUREMENT_TIME_INTERVAL (1000.0f/SENSOR_ODR) // In ms
+#define FIFO_SAMPLE_THRESHOLD 199
+#define FLASH_BUFF_LEN 8192
+
+typedef enum {
+ DATA_STORAGE_STATE,
+ DATA_LOGGER_IDLE_STATE,
+ DATA_LOGGER_RUNNING_STATE
+} demo_state_e;
+
+volatile demo_state_e demo_state = DATA_STORAGE_STATE;
+volatile int mems_event = 0;
+uint32_t file_count = 0;
+unsigned long timestamp_count = 0;
+bool acc_available = false;
+bool gyr_available = false;
+int32_t acc_value[3];
+int32_t gyr_value[3];
+char buff[FLASH_BUFF_LEN];
+uint32_t pos = 0;
+
+static FlashIAPBlockDevice bd(XIP_BASE + 0x100000, 0x100000);
+
+LSM6DSOXSensor AccGyr(&Wire, LSM6DSOX_I2C_ADD_L);
+
+USBMSD MassStorage(&bd);
+
+rtos::Thread acquisition_th;
+
+FILE *f = nullptr;
+
+void INT1Event_cb()
+{
+ mems_event = 1;
+}
+
+void USBMSD::begin()
+{
+ int err = getFileSystem().mount(&bd);
+ if (err) {
+ err = getFileSystem().reformat(&bd);
+ }
+}
+
+mbed::FATFileSystem &USBMSD::getFileSystem()
+{
+ static mbed::FATFileSystem fs("fs");
+ return fs;
+}
+
+void led_green_thd()
+{
+ while (1) {
+ if (demo_state == DATA_LOGGER_RUNNING_STATE) {
+ digitalWrite(LEDG, HIGH);
+ delay(100);
+ digitalWrite(LEDG, LOW);
+ delay(100);
+ }
+ }
+}
+
+void Read_FIFO_Data(uint16_t samples_to_read)
+{
+ uint16_t i;
+
+ for (i = 0; i < samples_to_read; i++) {
+ uint8_t tag;
+ // Check the FIFO tag
+ AccGyr.Get_FIFO_Tag(&tag);
+ switch (tag) {
+ // If we have a gyro tag, read the gyro data
+ case LSM6DSOX_GYRO_NC_TAG: {
+ AccGyr.Get_FIFO_G_Axes(gyr_value);
+ gyr_available = true;
+ break;
+ }
+ // If we have an acc tag, read the acc data
+ case LSM6DSOX_XL_NC_TAG: {
+ AccGyr.Get_FIFO_X_Axes(acc_value);
+ acc_available = true;
+ break;
+ }
+ // We can discard other tags
+ default: {
+ break;
+ }
+ }
+ // If we have the measurements of both acc and gyro, we can store them with timestamp
+ if (acc_available && gyr_available) {
+ int num_bytes;
+ num_bytes = snprintf(&buff[pos], (FLASH_BUFF_LEN - pos), "%lu %d %d %d %d %d %d\n", (unsigned long)((float)timestamp_count * MEASUREMENT_TIME_INTERVAL), (int)acc_value[0], (int)acc_value[1], (int)acc_value[2], (int)gyr_value[0], (int)gyr_value[1], (int)gyr_value[2]);
+ pos += num_bytes;
+ timestamp_count++;
+ acc_available = false;
+ gyr_available = false;
+ }
+ }
+ // We can add the termination character to the string, so we are ready to save it in flash
+ buff[pos] = '\0';
+ pos = 0;
+}
+
+void setup()
+{
+ Serial.begin(115200);
+ MassStorage.begin();
+ pinMode(LEDB, OUTPUT);
+ pinMode(LEDG, OUTPUT);
+ digitalWrite(LEDB, LOW);
+ digitalWrite(LEDG, LOW);
+
+ // Initialize I2C bus.
+ Wire.begin();
+ Wire.setClock(400000);
+
+ //Interrupts.
+ attachInterrupt(INT_1, INT1Event_cb, RISING);
+
+ // Initialize IMU.
+ AccGyr.begin();
+ AccGyr.Enable_X();
+ AccGyr.Enable_G();
+ // Configure ODR and FS of the acc and gyro
+ AccGyr.Set_X_ODR(SENSOR_ODR);
+ AccGyr.Set_X_FS(ACC_FS);
+ AccGyr.Set_G_ODR(SENSOR_ODR);
+ AccGyr.Set_G_FS(GYR_FS);
+ // Enable the Double Tap event
+ AccGyr.Enable_Double_Tap_Detection(LSM6DSOX_INT1_PIN);
+ // Configure FIFO BDR for acc and gyro
+ AccGyr.Set_FIFO_X_BDR(SENSOR_ODR);
+ AccGyr.Set_FIFO_G_BDR(SENSOR_ODR);
+ // Start Led blinking thread
+ acquisition_th.start(led_green_thd);
+}
+
+void loop()
+{
+
+ if (mems_event) {
+ mems_event = 0;
+ LSM6DSOX_Event_Status_t status;
+ AccGyr.Get_X_Event_Status(&status);
+ if (status.DoubleTapStatus) {
+ switch (demo_state) {
+ case DATA_STORAGE_STATE: {
+ // Go to DATA_LOGGER_IDLE_STATE state
+ demo_state = DATA_LOGGER_IDLE_STATE;
+ digitalWrite(LEDG, HIGH);
+ Serial.println("From DATA_STORAGE_STATE To DATA_LOGGER_IDLE_STATE");
+ break;
+ }
+ case DATA_LOGGER_IDLE_STATE: {
+ char filename[32];
+ // Go to DATA_LOGGER_RUNNING_STATE state
+ snprintf(filename, 32, "/fs/data_%lu.txt", file_count);
+ Serial.print("Start writing file ");
+ Serial.println(filename);
+ // open a file to write some data
+ // w+ means overwrite, so every time the board is rebooted the file will be overwritten
+ f = fopen(filename, "w+");
+ if (f != nullptr) {
+ // write header
+ fprintf(f, "Timestamp[ms] A_X [mg] A_Y [mg] A_Z [mg] G_X [mdps] G_Y [mdps] G_Z [mdps]\n");
+ fflush(f);
+ Serial.println("From DATA_LOGGER_IDLE_STATE To DATA_LOGGER_RUNNING_STATE");
+ demo_state = DATA_LOGGER_RUNNING_STATE;
+ digitalWrite(LEDG, LOW);
+ timestamp_count = 0;
+ pos = 0;
+ acc_available = false;
+ gyr_available = false;
+ // Set FIFO in Continuous mode
+ AccGyr.Set_FIFO_Mode(LSM6DSOX_STREAM_MODE);
+ }
+ break;
+ }
+ case DATA_LOGGER_RUNNING_STATE: {
+ // Empty the FIFO
+ uint16_t fifo_samples;
+ AccGyr.Get_FIFO_Num_Samples(&fifo_samples);
+ Read_FIFO_Data(fifo_samples);
+ // Store the string in flash
+ fprintf(f, "%s", buff);
+ fflush(f);
+
+ // Close the log file and increase the counter
+ fclose(f);
+ file_count++;
+ // Set FIFO in Bypass mode
+ AccGyr.Set_FIFO_Mode(LSM6DSOX_BYPASS_MODE);
+ // Go to DATA_LOGGER_IDLE_STATE state
+ demo_state = DATA_LOGGER_IDLE_STATE;
+ // Wait for the led thread ends the blinking
+ delay(250);
+ digitalWrite(LEDG, HIGH);
+ Serial.println("From DATA_LOGGER_RUNNING_STATE To DATA_LOGGER_IDLE_STATE");
+ break;
+ }
+ default:
+ Serial.println("Error! Invalid state");
+ }
+ }
+ }
+
+ if (demo_state == DATA_LOGGER_RUNNING_STATE) {
+ uint16_t fifo_samples;
+
+ // Check the number of samples inside FIFO
+ AccGyr.Get_FIFO_Num_Samples(&fifo_samples);
+
+ // If we reach the threshold we can empty the FIFO
+ if (fifo_samples > FIFO_SAMPLE_THRESHOLD) {
+ // Empty the FIFO
+ Read_FIFO_Data(fifo_samples);
+ // Store the string in flash
+ fprintf(f, "%s", buff);
+ fflush(f);
+ }
+ }
+
+ if (demo_state == DATA_STORAGE_STATE && millis() > 10000) {
+ // Disable the sensor and go to Mass Storage mode
+ AccGyr.Disable_Double_Tap_Detection();
+ AccGyr.Disable_X();
+ AccGyr.Disable_G();
+ while (1) {
+ digitalWrite(LEDB, HIGH);
+ delay(100);
+ digitalWrite(LEDB, LOW);
+ delay(100);
+ }
+ }
+}
diff --git a/libraries/MLC/examples/RP2040_MLC_Motion_Intensity/RP2040_MLC_Motion_Intensity.ino b/libraries/MLC/examples/RP2040_MLC_Motion_Intensity/RP2040_MLC_Motion_Intensity.ino
new file mode 100644
index 000000000..6b4f300fa
--- /dev/null
+++ b/libraries/MLC/examples/RP2040_MLC_Motion_Intensity/RP2040_MLC_Motion_Intensity.ino
@@ -0,0 +1,136 @@
+/*
+ This example shows how to load the MLC bytecode for Motion Intensity on LSM6DSOX
+ of the Arduino Nano RP2040 Connect.
+ You can find the video tutorial on LSM6DSOX MLC at: https://docs.arduino.cc/tutorials/nano-rp2040-connect/rp2040-imu-advanced
+*/
+
+// Includes
+#include "WiFiNINA.h"
+#include "LSM6DSOXSensor.h"
+#include "lsm6dsox_motion_intensity.h"
+
+#define INT_1 INT_IMU
+
+//Interrupts.
+volatile int mems_event = 0;
+
+// Components
+LSM6DSOXSensor AccGyr(&Wire, LSM6DSOX_I2C_ADD_L);
+
+// MLC
+ucf_line_t *ProgramPointer;
+int32_t LineCounter;
+int32_t TotalNumberOfLine;
+
+void INT1Event_cb();
+void printMLCStatus(uint8_t status);
+
+void setup()
+{
+ // Led.
+ pinMode(LEDB, OUTPUT);
+ pinMode(LEDG, OUTPUT);
+ pinMode(LEDR, OUTPUT);
+ digitalWrite(LEDB, LOW);
+ digitalWrite(LEDG, LOW);
+ digitalWrite(LEDR, LOW);
+
+ // Initialize serial for output.
+ Serial.begin(115200);
+
+ // Initialize I2C bus.
+ Wire.begin();
+
+ AccGyr.begin();
+
+ /* Feed the program to Machine Learning Core */
+ /* Motion Intensity Default program */
+ ProgramPointer = (ucf_line_t *)lsm6dsox_motion_intensity;
+ TotalNumberOfLine = sizeof(lsm6dsox_motion_intensity) / sizeof(ucf_line_t);
+ Serial.println("Motion Intensity for LSM6DSOX MLC");
+ Serial.print("UCF Number Line=");
+ Serial.println(TotalNumberOfLine);
+
+ for (LineCounter = 0; LineCounter < TotalNumberOfLine; LineCounter++) {
+ if (AccGyr.Write_Reg(ProgramPointer[LineCounter].address, ProgramPointer[LineCounter].data)) {
+ Serial.print("Error loading the Program to LSM6DSOX at line: ");
+ Serial.println(LineCounter);
+ while (1) {
+ // Led blinking.
+ digitalWrite(LED_BUILTIN, HIGH);
+ delay(250);
+ digitalWrite(LED_BUILTIN, LOW);
+ delay(250);
+ }
+ }
+ }
+
+ Serial.println("Program loaded inside the LSM6DSOX MLC");
+
+ AccGyr.Enable_X();
+ AccGyr.Set_X_ODR(104.0f);
+ AccGyr.Set_X_FS(2);
+
+ //Interrupts.
+ pinMode(INT_1, INPUT);
+ attachInterrupt(INT_1, INT1Event_cb, RISING);
+}
+
+void loop()
+{
+ if (mems_event) {
+ mems_event = 0;
+ LSM6DSOX_MLC_Status_t status;
+ AccGyr.Get_MLC_Status(&status);
+ if (status.is_mlc1) {
+ uint8_t mlc_out[8];
+ AccGyr.Get_MLC_Output(mlc_out);
+ printMLCStatus(mlc_out[0]);
+ }
+ }
+}
+
+void INT1Event_cb()
+{
+ mems_event = 1;
+}
+
+void printMLCStatus(uint8_t status)
+{
+ switch (status) {
+ case 1:
+ // Reset leds status
+ digitalWrite(LEDB, LOW);
+ digitalWrite(LEDG, LOW);
+ digitalWrite(LEDR, LOW);
+ // LEDB On
+ digitalWrite(LEDB, HIGH);
+ Serial.println("Stationary");
+ break;
+ case 4:
+ // Reset leds status
+ digitalWrite(LEDB, LOW);
+ digitalWrite(LEDG, LOW);
+ digitalWrite(LEDR, LOW);
+ // LEDG On
+ digitalWrite(LEDG, HIGH);
+ Serial.println("Medium Intensity");
+ break;
+ case 8:
+ // Reset leds status
+ digitalWrite(LEDB, LOW);
+ digitalWrite(LEDG, LOW);
+ digitalWrite(LEDR, LOW);
+ // LEDR On
+ digitalWrite(LEDR, HIGH);
+ Serial.println("High Intensity");
+ break;
+ default:
+ // Reset leds status
+ digitalWrite(LEDB, LOW);
+ digitalWrite(LEDG, LOW);
+ digitalWrite(LEDR, LOW);
+ Serial.println("Unknown");
+ break;
+ }
+}
diff --git a/libraries/MLC/examples/RP2040_MLC_Motion_Intensity/lsm6dsox_motion_intensity.h b/libraries/MLC/examples/RP2040_MLC_Motion_Intensity/lsm6dsox_motion_intensity.h
new file mode 100644
index 000000000..989639411
--- /dev/null
+++ b/libraries/MLC/examples/RP2040_MLC_Motion_Intensity/lsm6dsox_motion_intensity.h
@@ -0,0 +1,128 @@
+/*
+ ******************************************************************************
+ * @file lsm6dsox_motion_intensity.h
+ * @author Sensors Software Solution Team
+ * @brief This file contains the configuration for lsm6dsox_motion_intensity.
+ *
+ ******************************************************************************
+ * @attention
+ *
+ * © Copyright (c) 2021 STMicroelectronics.
+ * All rights reserved.
+ *
+ * This software component is licensed by ST under BSD 3-Clause license,
+ * the "License"; You may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at:
+ * opensource.org/licenses/BSD-3-Clause
+ *
+ */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef LSM6DSOX_MOTION_INTENSITY_H
+#define LSM6DSOX_MOTION_INTENSITY_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/* Includes ------------------------------------------------------------------*/
+#include
+#ifndef MEMS_UCF_SHARED_TYPES
+#define MEMS_UCF_SHARED_TYPES
+
+/** Common data block definition **/
+typedef struct {
+ uint8_t address;
+ uint8_t data;
+} ucf_line_t;
+
+#endif /* MEMS_UCF_SHARED_TYPES */
+
+/** Configuration array generated from Unico Tool **/
+const ucf_line_t lsm6dsox_motion_intensity[] = {
+ {.address = 0x10, .data = 0x00,},
+ {.address = 0x11, .data = 0x00,},
+ {.address = 0x01, .data = 0x80,},
+ {.address = 0x04, .data = 0x00,},
+ {.address = 0x05, .data = 0x00,},
+ {.address = 0x17, .data = 0x40,},
+ {.address = 0x02, .data = 0x11,},
+ {.address = 0x08, .data = 0xEA,},
+ {.address = 0x09, .data = 0x46,},
+ {.address = 0x09, .data = 0x03,},
+ {.address = 0x09, .data = 0x50,},
+ {.address = 0x09, .data = 0x03,},
+ {.address = 0x09, .data = 0x00,},
+ {.address = 0x09, .data = 0x00,},
+ {.address = 0x09, .data = 0x0A,},
+ {.address = 0x02, .data = 0x11,},
+ {.address = 0x08, .data = 0xF2,},
+ {.address = 0x09, .data = 0x34,},
+ {.address = 0x02, .data = 0x11,},
+ {.address = 0x08, .data = 0xFA,},
+ {.address = 0x09, .data = 0x3C,},
+ {.address = 0x09, .data = 0x03,},
+ {.address = 0x09, .data = 0x52,},
+ {.address = 0x09, .data = 0x03,},
+ {.address = 0x09, .data = 0x5E,},
+ {.address = 0x09, .data = 0x03,},
+ {.address = 0x02, .data = 0x31,},
+ {.address = 0x08, .data = 0x3C,},
+ {.address = 0x09, .data = 0x3F,},
+ {.address = 0x09, .data = 0x00,},
+ {.address = 0x09, .data = 0x01,},
+ {.address = 0x09, .data = 0x10,},
+ {.address = 0x09, .data = 0x00,},
+ {.address = 0x09, .data = 0x00,},
+ {.address = 0x09, .data = 0x00,},
+ {.address = 0x09, .data = 0x00,},
+ {.address = 0x09, .data = 0x1F,},
+ {.address = 0x09, .data = 0x00,},
+ {.address = 0x02, .data = 0x31,},
+ {.address = 0x08, .data = 0x52,},
+ {.address = 0x09, .data = 0x00,},
+ {.address = 0x09, .data = 0x00,},
+ {.address = 0x09, .data = 0x00,},
+ {.address = 0x09, .data = 0x00,},
+ {.address = 0x09, .data = 0x00,},
+ {.address = 0x09, .data = 0x00,},
+ {.address = 0x09, .data = 0x00,},
+ {.address = 0x09, .data = 0x00,},
+ {.address = 0x09, .data = 0x00,},
+ {.address = 0x09, .data = 0x00,},
+ {.address = 0x09, .data = 0x00,},
+ {.address = 0x01, .data = 0x00,},
+ {.address = 0x01, .data = 0x80,},
+ {.address = 0x17, .data = 0x40,},
+ {.address = 0x02, .data = 0x31,},
+ {.address = 0x08, .data = 0x5E,},
+ {.address = 0x09, .data = 0x00,},
+ {.address = 0x09, .data = 0x18,},
+ {.address = 0x09, .data = 0x11,},
+ {.address = 0x09, .data = 0xC0,},
+ {.address = 0x09, .data = 0xC8,},
+ {.address = 0x09, .data = 0x32,},
+ {.address = 0x09, .data = 0x84,},
+ {.address = 0x09, .data = 0xE0,},
+ {.address = 0x01, .data = 0x80,},
+ {.address = 0x17, .data = 0x00,},
+ {.address = 0x04, .data = 0x00,},
+ {.address = 0x05, .data = 0x10,},
+ {.address = 0x02, .data = 0x01,},
+ {.address = 0x01, .data = 0x00,},
+ {.address = 0x01, .data = 0x80,},
+ {.address = 0x60, .data = 0x35,},
+ {.address = 0x01, .data = 0x00,},
+ {.address = 0x10, .data = 0x40,},
+ {.address = 0x11, .data = 0x00,},
+ {.address = 0x5E, .data = 0x02,},
+ {.address = 0x01, .data = 0x80,},
+ {.address = 0x0D, .data = 0x01,},
+ {.address = 0x01, .data = 0x00,}
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LSM6DSOX_MOTION_INTENSITY_H */
diff --git a/libraries/MLC/library.properties b/libraries/MLC/library.properties
new file mode 100644
index 000000000..020c1bba6
--- /dev/null
+++ b/libraries/MLC/library.properties
@@ -0,0 +1,10 @@
+name=MLC
+version=1.0
+author=Arduino
+maintainer=Arduino
+sentence=MLC library for LSM6DSOX on Arduino boards
+paragraph=
+category=Other
+url=https://github.com/arduino/ArduinoCore-mbed/tree/master/libraries/MLC
+architectures=mbed,mbed_nano,mbed_nicla
+depends=STM32duino LSM6DSOX, WiFiNINA
diff --git a/libraries/MLC/src/MLC.h b/libraries/MLC/src/MLC.h
new file mode 100644
index 000000000..bd36232ac
--- /dev/null
+++ b/libraries/MLC/src/MLC.h
@@ -0,0 +1 @@
+// Placeholder header to allow showing the example in menu
\ No newline at end of file