Skip to main content

Usage of Seeed Studio XIAO MG24 Sense built-in Sensor

XIAO MG24 Sense IMU

Overview of Built-in Sensors

6-Axis IMU (Inertial Measurement Unit) Sensors like the LSM6DS3TR-C integrate accelerometers and gyroscopes to measure the motion and orientation of an object in three-dimensional space. Specifically, the LSM6DS3TR-C has the following features:

Accelerometer function:

  • Measures the acceleration of an object along the X, Y, and Z axes. It is able to sense object motion (e.g., rest, acceleration, deceleration) and tilt changes (e.g., angle of the object).
  • It can be used to detect gait, position changes, vibrations, etc.

Gyroscope function (Gyroscope):

  • Measures the angular velocity of an object around the X, Y, and Z axes, i.e., the rotation of the object.
  • Can be used to detect rotation, rate of rotation, and change in direction.
  • The X-axis angle ( Roll ) is the angle in the direction of rotation around the X-axis.
  • The Y-axis angle ( Pitch ) is the angle in the direction of rotation around the Y-axis.
  • The Z-axis angle ( Yaw ) is the angle in the direction of rotation around the Z-axis.

Software Preparation

Click on the github download link to drive the six-axis sensor.

Code Implementation


#include <LSM6DS3.h>
#include <Wire.h>

//Create a instance of class LSM6DS3
LSM6DS3 myIMU(I2C_MODE, 0x6A); //I2C device address 0x6A
float aX, aY, aZ, gX, gY, gZ;
const float accelerationThreshold = 2.5; // threshold of significant in G's
const int numSamples = 119;
int samplesRead = numSamples;

void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
while (!Serial);

pinMode(PD5,OUTPUT);
digitalWrite(PD5,HIGH);
//Call .begin() to configure the IMUs
if (myIMU.begin() != 0) {
Serial.println("Device error");
} else {
Serial.println("aX,aY,aZ,gX,gY,gZ");
}
}

void loop() {
// wait for significant motion
while (samplesRead == numSamples) {
// read the acceleration data
aX = myIMU.readFloatAccelX();
aY = myIMU.readFloatAccelY();
aZ = myIMU.readFloatAccelZ();

// sum up the absolutes
float aSum = fabs(aX) + fabs(aY) + fabs(aZ);

// check if it's above the threshold
if (aSum >= accelerationThreshold) {
// reset the sample read count
samplesRead = 0;
break;
}
}

// check if the all the required samples have been read since
// the last time the significant motion was detected
while (samplesRead < numSamples) {
// check if both new acceleration and gyroscope data is
// available
// read the acceleration and gyroscope data

samplesRead++;

// print the data in CSV format
Serial.print(myIMU.readFloatAccelX(), 3);
Serial.print(',');
Serial.print(myIMU.readFloatAccelY(), 3);
Serial.print(',');
Serial.print(myIMU.readFloatAccelZ(), 3);
Serial.print(',');
Serial.print(myIMU.readFloatGyroX(), 3);
Serial.print(',');
Serial.print(myIMU.readFloatGyroY(), 3);
Serial.print(',');
Serial.print(myIMU.readFloatGyroZ(), 3);
Serial.println();

if (samplesRead == numSamples) {
// add an empty line if it's the last sample
Serial.println();
}
}
}
tip

Due to the update of the LSM6DS3 library, if you have previously added this library to the user, you will need to re-download version 2.0.4 or higher and add the ZIP file to the Arduino.

Function Overview

  • Include Libraries

      #include <LSM6DS3.h> 
    #include <Wire.h>
    • Includes the library for communicating with the LSM6DS3 sensor.
    • Includes the library for I2C communication.
  • Create Sensor Instance

    • LSM6DS3 myIMU(I2C_MODE, 0x6A) Creates an instance of the LSM6DS3 class for the IMU sensor, specifying I2C communication mode and the device address 0x6A.
  • Variables and Constants

    • float aX, aY, aZ, gX, gY, gZ: Variables to store accelerometer and gyroscope data.
    • const float accelerationThreshold = 2.5: The threshold value in G's for detecting significant motion.
    • const int numSamples = 119: The number of samples to collect after detecting significant motion.
    • int samplesRead = numSamples: Initializes the sample counter to the total number of samples, indicating no data has been collected yet.
  • Basic Settings

      pinMode(PD5,OUTPUT);
    digitalWrite(PD5,HIGH);
    • Turn on the gyro enable pin.
  • Data Processing

    aX = myIMU.readFloatAccelX();:
    aY = myIMU.readFloatAccelY();:
    aZ = myIMU.readFloatAccelZ();:
    float aSum = fabs(aX) + fabs(aY) + fabs(aZ);
    • Reads the acceleration along X.
    • Reads the acceleration along Y.
    • Reads the acceleration along Z.
    • Calculate the sum of the absolute values of the acceleration data,fabs()Returns the absolute value.
      // check if it's above the threshold
    if (aSum >= accelerationThreshold) {
    // reset the sample read count
    samplesRead = 0;
    break;
    }
    • If the sum of the absolute acceleration values is greater than or equal to the set threshold, reset the sample count samplesRead to 0 and exit the loop.
  • Check Data

    while (samplesRead < numSamples) {
    samplesRead++;
    .
    .
    .
    .
    .
    if (samplesRead == numSamples) {
    // add an empty line if it's the last sample
    Serial.println();
    }
    }
    • Go to another loop and check if the required number of samples have been read.
    • Increase the count of samplesRead.
    • If all samples have been read, print a blank line to separate the data output.

Results Chart

Greater

If you want more sample code , Please Click : "File" -> Example -> Seeed Arduino LSM6DS3"

XIAO MG24 Sense Microphone(Seeed Studio Demo)

Overview of Built-in Sensors

Microphone Sensorlike the MSM381ACT001 is a MEMS (Micro-Electro-Mechanical Systems) microphone designed to capture audio signals with high sensitivity and low noise. Specifically, the MSM381ACT001 has the following features:

Microphone Function:

  • Captures sound waves and converts them into electrical signals, enabling the detection of audio input in various environments.
  • It features a wide frequency response range, typically from 20 Hz to 20 kHz, suitable for a variety of audio applications, including voice recognition and music playback.

Key Features

  • High Sensitivity: Capable of detecting faint sounds, making it ideal for applications requiring precise audio capture.
  • Low Noise: Designed to provide a high signal-to-noise ratio (SNR), ensuring clear audio output even in noisy environments.
  • Compact Size: MEMS technology allows for a small form factor, facilitating easy integration into portable devices like smartphones and wearables.
  • Digital Output: Offers digital signal output options (e.g., I2S), simplifying the interface with digital signal processors (DSPs) and microcontrollers.

Software Preparation

Click on the github download link to drive the microphone sensor.

tip

Currently we need to manually modify the replacement file, the subsequent direct download library can be used, please wait for our wiki update.

Changing the file path

  • /Users/yourname/Library/Arduino15/packages/SiliconLabs/hardware/silabs/2.2.0/variants/xiao_mg24/ble_silabs/

Code Implementation

#include <mic.h>
#if defined(WIO_TERMINAL)
#include "processing/filters.h"
#endif

// Settings
#if defined(WIO_TERMINAL)
#define DEBUG 1 // Enable pin pulse during ISR
#define SAMPLES 16000*3
#elif defined(ARDUINO_ARCH_NRF52840)
#define DEBUG 1 // Enable pin pulse during ISR
#define SAMPLES 800
#elif defined(ARDUINO_SILABS)
#define DEBUG 1 // Enable pin pulse during ISR
#define SAMPLES 800
#endif

mic_config_t mic_config{
.channel_cnt = 1,
.sampling_rate = 16000,
.buf_size = 1600,
#if defined(WIO_TERMINAL)
.debug_pin = 1 // Toggles each DAC ISR (if DEBUG is set to 1)
#elif defined(ARDUINO_ARCH_NRF52840)
.debug_pin = LED_BUILTIN // Toggles each DAC ISR (if DEBUG is set to 1)
#elif defined(ARDUINO_SILABS)
.debug_pin = LED_BUILTIN // Toggles each DAC ISR (if DEBUG is set to 1)
#endif
};

#if defined(WIO_TERMINAL)
DMA_ADC_Class Mic(&mic_config);
#elif defined(ARDUINO_ARCH_NRF52840)
NRF52840_ADC_Class Mic(&mic_config);
#elif defined(ARDUINO_SILABS)
MG24_ADC_Class Mic(&mic_config);
#endif

int16_t recording_buf[SAMPLES];
volatile uint8_t recording = 0;
volatile static bool record_ready = false;

#if defined(WIO_TERMINAL)
FilterBuHp filter;
#endif

void setup() {

Serial.begin(115200);
while (!Serial) {delay(10);}

#if defined(WIO_TERMINAL)
pinMode(WIO_KEY_A, INPUT_PULLUP);
#endif

Mic.set_callback(audio_rec_callback);

if (!Mic.begin()) {
Serial.println("Mic initialization failed");
while (1);
}

Serial.println("Mic initialization done.");

}

void loop() {

#if defined(WIO_TERMINAL)
if (digitalRead(WIO_KEY_A) == LOW && !recording) {

Serial.println("Starting sampling");
recording = 1;
record_ready = false;
}
#endif

#if defined(WIO_TERMINAL)
if (!recording && record_ready)
#elif defined(ARDUINO_ARCH_NRF52840) || defined(ARDUINO_SILABS)
if (record_ready)
#endif
{
Serial.println("Finished sampling");

for (int i = 0; i < SAMPLES; i++) {

//int16_t sample = filter.step(recording_buf[i]);
int16_t sample = recording_buf[i];
Serial.println(sample);
}

record_ready = false;
}
}

static void audio_rec_callback(uint16_t *buf, uint32_t buf_len) {

static uint32_t idx = 0;
// Copy samples from DMA buffer to inference buffer
#if defined(WIO_TERMINAL)
if (recording)
#endif
{
for (uint32_t i = 0; i < buf_len; i++) {

// Convert 12-bit unsigned ADC value to 16-bit PCM (signed) audio value
#if defined(WIO_TERMINAL)
recording_buf[idx++] = filter.step((int16_t)(buf[i] - 1024) * 16);
//recording_buf[idx++] = (int16_t)(buf[i] - 1024) * 16;
#elif defined(ARDUINO_ARCH_NRF52840) || defined(ARDUINO_SILABS)
recording_buf[idx++] = buf[i];
#endif

if (idx >= SAMPLES){
idx = 0;
recording = 0;
record_ready = true;
break;
}
}
}

}

Function Overview

Microphone Configuration

mic_config_t mic_config{
.channel_cnt = 1,
.sampling_rate = 16000,
.buf_size = 1600,
#if defined(WIO_TERMINAL)
.debug_pin = 1
#elif defined(ARDUINO_ARCH_NRF52840)
.debug_pin = LED_BUILTIN
#elif defined(ARDUINO_SILABS)
.debug_pin = LED_BUILTIN
#endif
};
  • mic_config_t: Defines a microphone configuration structure.
  • channel_cnt: set to 1 for mono.
  • sampling_rate: Set to 16000 Hz for sampling frequency.
  • buf_size: set to 1600 for buffer size.
  • ebug_pin: set debug pin according to platform, used for signal indication during debugging.

Microphone instantiation

#if defined(WIO_TERMINAL)
DMA_ADC_Class Mic(&mic_config);
#elif defined(ARDUINO_ARCH_NRF52840)
NRF52840_ADC_Class Mic(&mic_config);
#elif defined(ARDUINO_SILABS)
MG24_ADC_Class Mic(&mic_config);
#endif
  • Conditional compilation: create the appropriate microphone class instances for different platforms, using the previously defined configuration.

Recording buffers and flags

int16_t recording_buf[SAMPLES];
volatile uint8_t recording = 0;
volatile static bool record_ready = false;
  • recording_buf: Define an array of SAMPLES to store recording samples.
  • recording: a volatile variable that marks whether recording is currently in progress to prevent compiler optimization.
  • record_ready: a volatile static variable that indicates if the recording is complete and ready for further processing.

Filter Example (for WIO Terminal)

#if defined(WIO_TERMINAL)
FilterBuHp filter;
#endif
  • If on the WIO Terminal, create an instance of a high-pass filter for filter processing.

setup

void setup() {
Serial.begin(115200);
while (!Serial) {delay(10);}

#if defined(WIO_TERMINAL)
pinMode(WIO_KEY_A, INPUT_PULLUP);
#endif

Mic.set_callback(audio_rec_callback);

if (!Mic.begin()) {
Serial.println("Mic initialization failed");
while (1);
}

Serial.println("Mic initialization done.");
}

-Initialize Serial Port: Start serial communication at 115200 baud rate and wait for the serial port to be ready.

  • Set Pin Mode: On WIO Terminal, set the key pins to input pull-up mode.
  • Set callback function: call Mic.set_callback(audio_rec_callback) to specify the callback function when recording audio.
  • Initialize the microphone: call Mic.begin(), if the initialization fails, print an error message and enter a dead loop.

loop

void loop() { 
#if defined(WIO_TERMINAL)
if (digitalRead(WIO_KEY_A) == LOW && !recording) {
Serial.println("Starting sampling");
recording = 1;
record_ready = false;
}
#endif

#if defined(WIO_TERMINAL)
if (!recording && record_ready)
#elif defined(ARDUINO_ARCH_NRF52840) || defined(ARDUINO_SILABS)
if (record_ready)
#endif
{
Serial.println("Finished sampling");

for (int i = 0; i < SAMPLES; i++) {
int16_t sample = recording_buf[i];
Serial.println(sample);
}

record_ready = false;
}
}
  • Detect Key: On the WIO Terminal, starts recording when it detects that a key has been pressed and is not recording.
  • Finished sampling:Prints “Finished sampling” if not recording and record_ready is set to true.
  • Iterates through the recording buffer and prints each sample value.

Audio recording callback function

static void audio_rec_callback(uint16_t *buf, uint32_t buf_len) {
static uint32_t idx = 0;
#if defined(WIO_TERMINAL)
if (recording)
#endif
{
for (uint32_t i = 0; i < buf_len; i++) {
#if defined(WIO_TERMINAL)
recording_buf[idx++] = filter.step((int16_t)(buf[i] - 1024) * 16);
#elif defined(ARDUINO_ARCH_NRF52840) || defined(ARDUINO_SILABS)
recording_buf[idx++] = buf[i];
#endif

if (idx >= SAMPLES){
idx = 0;
recording = 0;
record_ready = true;
break;
}
}
}
}
  • Callback function: called during audio recording, responsible for copying samples from the DMA buffer to the recording buffer.
  • Conditional Compilation: Processes the input using filters if on the WIO Terminal.
  • Converts 12-bit unsigned ADC values to 16-bit PCM (signed) audio values.
  • Sample Fill: copies samples into recording_buf and updates index idx.
  • Finish recording: if the number of filled samples reaches SAMPLES, resets the index, marks the end of recording and sets record_ready to true.

Results Chart

Here is the waveform of the recognized sound, when you blow, you can clearly see that the waveform oscillation amplitude becomes bigger.

Greater

If you want more sample code , Please Click : -> "Example -> Seeed Arduino Mic"

XIAO MG24 Sense Microphone(Silicon Labs Demo)

Software Preparation

tip

The current version requires users to install the library manually. It is planned that this functionality will be integrated directly into the new version, so that users can find the application in the sample programs through the automatic update function.

Replace the duplicate files in the 2.2.0 directory by following the file instructions in the image below

Code Implementation

/*
Analog microphone volume example

The example showcases the usage of analog MEMS microphones and dims the
on-board LED based on the microphone's input volume.
This example is compatible with all Silicon Labs Arduino boards, however
it requires an analog microphone on-board or connected to the specified pin.

Author: Áron Gyapjas (Silicon Labs)
*/

#include <SilabsMicrophoneAnalog.h>

// This configuration is for the MSM381ACT001 microphone on the Seeed Studio XIAO MG24
// Change it according to your hardware
#define MIC_DATA_PIN PC9
#define MIC_PWR_PIN PC8
#define NUM_SAMPLES 128
#define MIC_VALUE_MIN 735
#define MIC_VALUE_MAX 900

// Buffers for storing samples
uint32_t mic_buffer[NUM_SAMPLES];
uint32_t mic_buffer_local[NUM_SAMPLES];

volatile bool data_ready_flag = false;
MicrophoneAnalog micAnalog(MIC_DATA_PIN, MIC_PWR_PIN);
void mic_samples_ready_cb();
void calculate_and_display_voice_level();

void setup()
{
Serial.begin(115200);
pinMode(LED_BUILTIN, OUTPUT);

micAnalog.begin(mic_buffer, NUM_SAMPLES);
Serial.println("Microphone initialized...");

micAnalog.startSampling(mic_samples_ready_cb);
Serial.println("Sampling started...");
}

void loop()
{
if (data_ready_flag) {
data_ready_flag = false;
calculate_and_display_voice_level();
}
}

// Called when the requested amount of samples are available from the microphone
void mic_samples_ready_cb()
{
// Copy data to the local buffer in order to prevent it from overwriting
memcpy(mic_buffer_local, mic_buffer, NUM_SAMPLES * sizeof(uint32_t));
data_ready_flag = true;
}

void calculate_and_display_voice_level() {
// Rolling average for smoothing the voice level
static uint32_t rolling_average = 0u;

// Stop sampling in order to prevent overwriting the current data
micAnalog.stopSampling();

// Get the average of the sampled values
uint32_t voice_level = (uint32_t)micAnalog.getAverage(mic_buffer_local, NUM_SAMPLES);
// Adjust the voice level relative to minimum/maximum of the microphone's output
voice_level = constrain(voice_level, MIC_VALUE_MIN, MIC_VALUE_MAX);
// Calculate the rolling average
rolling_average = (voice_level + rolling_average) / 2;

// Map the current average level to brightness
int brightness = map(rolling_average, MIC_VALUE_MIN, MIC_VALUE_MAX, 0, 255);
if (LED_BUILTIN_ACTIVE == LOW) {
analogWrite(LED_BUILTIN, 255 - brightness);
} else {
analogWrite(LED_BUILTIN, brightness);
}
// Print the average voice level (you can use the Serial Plotter to view this value on a graph)
Serial.println(rolling_average);

// Restart sampling
micAnalog.startSampling(mic_samples_ready_cb);
}

Function Overview

Header file introduction

#include <SilabsMicrophoneAnalog.h>
  • Includes the SilabsMicrophoneAnalog.h header file, which contains the necessary library functions and definitions for using the analog microphone.

Hardware configuration

#define MIC_DATA_PIN  PC9
#define MIC_PWR_PIN PC8
#define NUM_SAMPLES 128
#define MIC_VALUE_MIN 735
#define MIC_VALUE_MAX 900
  • MIC_DATA_PIN: Defines the microphone data pin as PC9.

  • MIC_PWR_PIN: Defines the microphone power pin as PC8.

  • NUM_SAMPLES: Defines the number of samples per sampling as 128.

  • MIC_VALUE_MIN and MIC_VALUE_MAX: Define the minimum and maximum range of the microphone output.

Buffer Definition

uint32_t mic_buffer[NUM_SAMPLES];
uint32_t mic_buffer_local[NUM_SAMPLES];
  • mic_buffer: Used to store raw sample data collected from the microphone.

  • mic_buffer_local: Used to temporarily store sample data to prevent overwriting.

Flags and object definitions

volatile bool data_ready_flag = false;
MicrophoneAnalog micAnalog(MIC_DATA_PIN, MIC_PWR_PIN);
  • data_ready_flag: A flag to indicate whether new sample data is ready.

  • micAnalog: Creates a MicrophoneAnalog object to control the microphone.

Callback Function Declaration

void mic_samples_ready_cb();
void calculate_and_display_voice_level();
  • mic_samples_ready_cb(): A callback function called when sampling is complete.

  • calculate_and_display_voice_level(): A function to calculate the volume and control the LED brightness.

setup() function

void setup()
{
Serial.begin(115200);
pinMode(LED_BUILTIN, OUTPUT);

micAnalog.begin(mic_buffer, NUM_SAMPLES);
Serial.println("Microphone initialized...");

micAnalog.startSampling(mic_samples_ready_cb);
Serial.println("Sampling started...");
}
  • Initializes serial communication with a baud rate of 115200.

  • Sets the onboard LED pin to output mode.

  • Initializes the microphone and specifies the sample buffer.

  • Starts sampling and sets the callback function for when sampling is complete.

loop()function

void loop()
{
if (data_ready_flag) {
data_ready_flag = false;
calculate_and_display_voice_level();
}
}
  • Checks if data_ready_flag is true, indicating that new data is ready.

  • If new data is available, calls the calculate_and_display_voice_level() function to process the data.


void mic_samples_ready_cb()
{
memcpy(mic_buffer_local, mic_buffer, NUM_SAMPLES * sizeof(uint32_t));
data_ready_flag = true;
}

Copies sample data from mic_buffer to mic_buffer_local to prevent overwriting.

Sets data_ready_flag to true to indicate that new data is ready.


void calculate_and_display_voice_level() {
static uint32_t rolling_average = 0u;

micAnalog.stopSampling();

uint32_t voice_level = (uint32_t)micAnalog.getAverage(mic_buffer_local, NUM_SAMPLES);
voice_level = constrain(voice_level, MIC_VALUE_MIN, MIC_VALUE_MAX);
rolling_average = (voice_level + rolling_average) / 2;

int brightness = map(rolling_average, MIC_VALUE_MIN, MIC_VALUE_MAX, 0, 255);
if (LED_BUILTIN_ACTIVE == LOW) {
analogWrite(LED_BUILTIN, 255 - brightness);
} else {
analogWrite(LED_BUILTIN, brightness);
}
Serial.println(rolling_average);

micAnalog.startSampling(mic_samples_ready_cb);
}
  • Stops sampling to prevent data overwriting.

  • Calculates the average of the sample data and constrains it between MIC_VALUE_MIN and MIC_VALUE_MAX.

  • Calculates a rolling average to smooth out volume changes.

  • Maps the rolling average to the LED brightness range (0 to 255) and adjusts the LED brightness.

  • Outputs the rolling average via serial for observing volume changes.

  • Restarts sampling to collect new audio data.

Results Chart

When we blow into the microphone, we can see that the led on top will lighten and darken with the sound.

Greater

If you want more sample code , Please Click : -> "Example -> SilabsMicrophoneAnalog -> MicrophoneVolume"

Resources

For Seeed Studio XIAO MG24 Sense

Tech Support & Product Discussion

Thank you for choosing our products! We are here to provide you with different support to ensure that your experience with our products is as smooth as possible. We offer several communication channels to cater to different preferences and needs.

Loading Comments...