Skip to Content

Getting started with XIAO MG24 Sense

Getting started with XIAO MG24 Sense

The XIAO MG24 Sense is one of the boards in Seeed Studio’s XIAO series, combining a powerful Silicon Labs EFR32MG24 microcontroller with built-in sensors like a microphone and a 6-axis IMU. Thanks to its small form factor, low-power design, and integrated wireless capabilities, it’s a great choice for projects in IoT, sensor fusion, and edge AI.

In this guide, we will walk through the basics of getting started with the XIAO MG24 Sense. We will begin by installing the necessary board core, then run the classic blink example to confirm everything is working. After that, we will explore its defining features: the onboard microphone and the IMU (Inertial Measurement Unit).

Required Parts

You will need a XIAO MG24 Sense board by Seeed Studio and a USB-C cable to program the board and to try out the code examples.

Seeed Studio XIAO MG24 Sense

USB C Cable

Makerguides is a participant in affiliate advertising programs designed to provide a means for sites to earn advertising fees by linking to Amazon, AliExpress, Elecrow, and other sites. As an Affiliate we may earn from qualifying purchases.

The XIAO MG24 Sense

The XIAO MG24 Sense is powered by the Silicon Labs EFR32MG24 system-on-chip, which uses an ARM Cortex-M33 microcontroller running at up to 78 MHz. This gives it plenty of processing capability for general embedded projects while remaining highly energy efficient. A standout feature of this chip is the Matrix-Vector Processor (MVP), a small hardware accelerator that speeds up the mathematical operations required in machine learning. This makes the MG24 Sense particularly well-suited for TinyML applications, such as keyword spotting or motion classification, without draining the battery too quickly.

Components of XIAO MG24 Sense
Components of XIAO MG24 Sense

In terms of memory, the board includes 1.5 MB of flash and 256 kB of RAM built into the microcontroller. On top of that, Seeed Studio has added an external 4 MB SPI flash chip, which is useful for storing larger programs, model data, or even logs. The combination of internal and external memory gives you room to experiment with more complex applications while still working on a small form factor board.

Wireless connectivity is another strength of this device. The MG24 supports Matter over Thread as well as Bluetooth Low Energy 5.3, ensuring compatibility with modern IoT ecosystems and smartphone connectivity. The board also comes with Secure Vault hardware security features, which protect sensitive data like encryption keys and enable secure boot.

Sensors

The “Sense” in the board’s name comes from its onboard sensors. First, there is the LSM6DS3TR-C IMU, a six-axis sensor that combines a three-axis accelerometer with a three-axis gyroscope. This sensor is capable of measuring motion, orientation, steps, and gestures, and it even includes low-power modes for continuous activity detection without heavy energy use. You can find more details in the datasheet linked below:

In addition to the IMU there is the MSM381ACT001 MEMS microphone, which allows you to capture sound. While it is an analog microphone, the microcontroller’s ADC makes it straightforward to sample and process audio, whether for sound detection or voice-triggered interactions. See the datasheet below:

GPIO

For hardware interfacing, the XIAO MG24 Sense exposes 19 general-purpose input/output (GPIO) pins, arranged in the familiar XIAO footprint. These pins can be used for I²C, SPI, UART, and other standard interfaces.

Pinout of XIAO MG24 Sense
Pinout of XIAO MG24 Sense

A user LED and power/charge LED are also present to help with debugging and quick feedback. Uploading code is done via the USB-C connector, which also doubles as a power and charging interface.

Power

Power efficiency is one of the strongest aspects of the XIAO MG24 Sense. In deep sleep modes, the microcontroller can reduce its current consumption to just a couple of microamps, making it ideal for battery-powered projects. The board includes a charging circuit for Li-Po batteries, and it can also measure the battery voltage so your projects can monitor their own power levels. With these features, the MG24 Sense is an excellent choice for long-term, battery-operated IoT nodes.

Battery connector of XIAO MG24 Sense
Battery connector of XIAO MG24 Sense

Size

Despite packing all of these features, the board keeps the classic XIAO form factor at just 21 × 17.8 mm, making it easy to embed in compact projects or wearables. It includes an onboard antenna for wireless communication, so you don’t need any additional modules to get started.

To summarize, the XIAO MG24 Sense combines a powerful and efficient microcontroller, modern wireless connectivity, secure hardware, onboard motion and audio sensors, generous memory, and a battery-friendly design in a very small package.

Technical Specification

FeatureSpecification
ProcessorSilicon Labs EFR32MG24, ARM Cortex-M33, up to 78 MHz
Hardware acceleratorMatrix-Vector Processor (MVP) for ML workloads
Internal memory1536 kB flash, 256 kB RAM
External memory4 MB SPI flash
WirelessMatter (Thread), Bluetooth Low Energy 5.3
SecuritySecure Vault hardware security engine
IMULSM6DS3TR-C, 6-axis accelerometer + gyroscope
MicrophoneMSM381ACT001 analog MEMS microphone
GPIO19 pins (I²C, SPI, UART, GPIO, etc.)
USBUSB-C for programming, power, and charging
Battery featuresOn-board charging circuit, battery voltage monitoring
Power efficiencyUltra-low power, sleep current down to ~1.95 µA
Form factor21 × 17.8 mm, onboard antenna

XIAO MG24 Sense versus XIAO MG24

Seeed Studio offers two closely related versions of this board: the XIAO MG24 and the XIAO MG24 Sense. Both share the same foundation, built around the EFR32MG24 microcontroller with its ARM Cortex-M33 core, Matrix-Vector Processor for machine learning, and support for modern wireless standards like Matter (Thread) and Bluetooth Low Energy 5.3. They also share the same compact XIAO form factor, the same external 4 MB flash, and the same low-power design with an onboard charging circuit for Li-Po batteries.

The main difference comes down to sensing capabilities. The XIAO MG24 Sense integrates two additional onboard sensors: the LSM6DS3TR-C 6-axis IMU and the MSM381ACT001 analog MEMS microphone. These additions allow the Sense edition to detect motion, orientation, and sound out of the box, making it a much stronger option for projects involving gesture recognition, audio input, or sensor fusion. By contrast, the standard XIAO MG24 does not include these sensors, but this also makes it slightly less expensive and a better fit if you only need the microcontroller, wireless features, and I/O pins.

Another small distinction is in the intended use cases. The XIAO MG24 is designed as a general-purpose ultra-low-power IoT board, while the XIAO MG24 Sense is aimed more at edge AI and smart sensing projects where motion and audio play a role. If your project involves things like TinyML keyword spotting, fitness tracking, gesture control, or sound-triggered events, the Sense version will save you the effort of wiring up external sensors. If, however, you want a simple, cost-effective base board for wireless IoT nodes or sensor networks, the non-Sense MG24 might be all you need.

XIAO MG24 versus ESP32

The ESP32 is well-known in the maker community for combining a dual-core (or sometimes single-core, depending on the variant) Xtensa LX6/LX7 processor running at up to 240 MHz with Wi-Fi and Bluetooth connectivity. This makes it especially attractive for projects that require higher raw processing power or internet connectivity via Wi-Fi. The ESP32 also has generous amounts of RAM (often 520 kB SRAM, with external PSRAM available on some modules) and flash memory, making it suitable for applications such as web servers, real-time audio streaming, or complex user interfaces. Its ecosystem is vast, with excellent community support, numerous tutorials, and compatibility with platforms like Arduino, ESP-IDF, and MicroPython.

By contrast, the EFR32MG24 used in the XIAO MG24 focuses on low power consumption, modern wireless standards, and security. It runs at a lower clock speed (up to 78 MHz) and has less RAM, but it includes the Matrix-Vector Processor (MVP) to accelerate machine learning tasks. Instead of Wi-Fi, it supports Matter (Thread) and Bluetooth Low Energy 5.3, both of which are highly relevant for smart home and IoT applications where low power and mesh networking are important. The MG24 also integrates Silicon Labs’ Secure Vault features, offering hardware-level encryption and secure boots.

In short, the ESP32 is better suited for applications where Wi-Fi connectivity, higher processing power, or large amounts of memory are necessary, while the MG24 is designed for battery-powered IoT nodes, sensor devices, and applications requiring strong security and modern wireless standards. Both are supported by Arduino, but the ESP32 benefits from a larger community and ecosystem, while the MG24 is a strong choice for developers interested in Matter, BLE 5.3, and ultra-low-power operation.

Comparison Table

FeatureXIAO MG24 (EFR32MG24)ESP32 (typical variants)
ProcessorARM Cortex-M33, up to 78 MHzXtensa LX6/LX7, single or dual-core, up to 240 MHz
Hardware acceleratorMVP (Matrix-Vector Processor for ML)None (some ESP32 variants include AI/ML co-processors, e.g., ESP32-S3 with vector instructions)
Internal memory1536 kB flash, 256 kB RAM~448–520 kB SRAM, external PSRAM on some modules
External memory4 MB SPI flash (on XIAO board)Typically 4–16 MB flash, optional PSRAM
WirelessMatter (Thread), Bluetooth 5.3Wi-Fi 2.4 GHz, Bluetooth 4.2/5.0 (depending on variant)
SecuritySecure Vault hardware (secure boot, key storage)Secure boot, flash encryption (varies by variant)
EcosystemSupported in Arduino, official Silicon Labs SDKsArduino, ESP-IDF, MicroPython, CircuitPython, large community
Power efficiencyUltra-low power, sleep current in µA rangeLow power modes available, but typically higher current draw
Best suited forLow-power IoT nodes, Matter/Thread devices, BLE applicationsWi-Fi-connected projects, web servers, real-time streaming, general-purpose maker projects

Installing the Core

Before you can start programming the XIAO MG24 or XIAO MG24 Sense with the Arduino IDE, you need to install the board core. But what exactly is a board core?

A core in the Arduino ecosystem is essentially a set of software files that allows the Arduino IDE to understand and communicate with a specific type of microcontroller. It includes the compiler, linker, startup files, libraries, and board definitions needed to build and upload code to that microcontroller. Without a core, the Arduino IDE wouldn’t know how to turn your sketches into machine code that the microcontroller can run.

Add URL to Preferences

The XIAO MG24 uses Silicon Labs’ EFR32MG24 microcontroller, which is not included in the default Arduino installation. To add support for this board, follow these steps.

First, Open the Arduino IDE and go to File → Preferences:

Next, in the Additional Board Manager URLs field, add the URL for the Seeed Studio package. The current URL is:

https://files.seeedstudio.com/arduino/package_seeeduino_boards_index.json

You can add the URL as a text in the edit field. If you already have other URLs listed, separate them with a comma.

Or you click on the icon to the right, which opens a separate editor, where you can add the URL. In the screenshot below you can see, I have already installed the ESP8266 core and the ESP32 core as well:

Install Boards

Then, open the Boards Manager by going to Tools → Board → Boards Manager… and type “MG24” in the search bar. You will see Silicon Labs and a text, listing the supported board. Press the INSTALL button. The screenshot below shows you how this looks after installing the core (the INSTALL button becomes a REMOVE button):

Once installed, select a board from the drop-down selector under the menu bar: In the example below it shows an Arduino Uno as selected board, for instance:

Bord selector

Clicking on the name of the currently selected board (Arduino Uno), will open the board selection dialog. In the search box type “mg24” and select the “Seeed Studio XIAO MG24 (Sense)” as shown below:

If the board is connected to your PC via USB, you should also be able to select the COM port. In the screenshot above this is COM8 but in your case it might be a different COM port.

After installation, the Arduino IDE treats the MG24 just like any other supported board. You can access libraries, use GPIO, I²C, SPI, ADC, and even leverage built-in examples for the board, such as the classic Blink sketch, which we will implement in the next section.

Blink Code

Once the core for the MG24 is installed, let’s test it and see if it actually works. We use the common Blink program for our test. Below is the code:

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

void loop() {
  Serial.println("OFF");
  digitalWrite(LED_BUILTIN, HIGH);  
  delay(1000);                      

  Serial.println("ON");
  digitalWrite(LED_BUILTIN, LOW);   
  delay(1000);   

It blinks the on-board LED every second and also prints the status of the LED to the Serial monitor. Note that the logic is inverted. Writing a HIGH signal to the LED pin causes the LED to be off and vice versa.

Upload the code to your board by pressing the upload icon in the Arduino IDE. Make sure you have the correct board selected (Seeed Studio XIAO MG24):

You should see the following compilation and programming status displayed in the Output terminal. Don’t be deceived by the red color. If you can read “** Programming Finished **” all is good.

Next switch over to the terminal output of the Serial Monitor. You should see a sequence of “ON” and “OFF” statements appearing. At the same time the orange LED of the XIAO MG24 board should be blinking.

If this all works, congratulations, you can now programm your XIAO MG24 Sense ; )

In the next sections we will try out the Inertial Measurement Unit (IMU) and Microphone of the XIAO MG24 Sense.

IMU Code

The following sketch shows how to read motion data from the LSM6DS3, a 6-axis IMU that combines a 3-axis accelerometer and a 3-axis gyroscope.

Before you can run it, you will need to install the Seeed_Arduino_LSM6DS3 Library. Download the library as a .ZIP file from the Github Repo and install it via Sketch → Include Library → Add .ZIP Library …

The example program initializes the sensor, checks for errors, and continuously prints acceleration and gyroscope readings to the serial monitor. Let’s walk through the code step by step.

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

LSM6DS3 myIMU(I2C_MODE, 0x6A);  

void setup() {
  Serial.begin(115200);

  pinMode(PD5, OUTPUT);
  digitalWrite(PD5, HIGH);

  if (myIMU.begin() != 0) {
    Serial.println("Device error");
  } 
}

void loop() {
    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();
    delay(500);
}

Imports

The sketch starts by including two essential libraries. The first is <LSM6DS3.h>, which provides an easy interface to the LSM6DS3 IMU. The second is <Wire.h>, which enables I2C communication between the Arduino and the sensor. Without these, the Arduino cannot talk to the IMU.

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

Objects

After the imports, the sketch creates an object called myIMU from the LSM6DS3 class. The constructor tells the program to use I2C communication and sets the I2C address of the sensor to 0x6A. This address depends on how the sensor’s pins are wired, and it must match the hardware configuration.

LSM6DS3 myIMU(I2C_MODE, 0x6A);

Setup

The setup() function runs once at the beginning. It starts by opening the serial port at 115200 baud so we can view the sensor data in the Arduino IDE’s Serial Monitor.

Serial.begin(115200);

Next, the code configures pin PD5 as an output and sets it to HIGH. This is used to enable the IMU.

pinMode(PD5, OUTPUT);
digitalWrite(PD5, HIGH);

Finally, the sketch initializes the IMU by calling myIMU.begin(). If the function returns a non-zero value, the program prints "Device error" to the Serial Monitor, signaling that the sensor could not be detected or initialized correctly.

if (myIMU.begin() != 0) {
  Serial.println("Device error");
}

Loop

The loop() function runs continuously after setup. Each cycle, the sketch reads acceleration and gyroscope data from the IMU and prints it to the Serial Monitor in a comma-separated format.

The accelerometer readings are taken in the X, Y, and Z directions. Each call to readFloatAccelX(), readFloatAccelY(), and readFloatAccelZ() returns a floating-point value in g’s, which measure acceleration relative to gravity. The second argument 3 tells the Serial Monitor to print three digits after the decimal point.

Serial.print(myIMU.readFloatAccelX(), 3);
Serial.print(',');
Serial.print(myIMU.readFloatAccelY(), 3);
Serial.print(',');
Serial.print(myIMU.readFloatAccelZ(), 3);

Next, the gyroscope values are read in the X, Y, and Z directions. The functions readFloatGyroX(), readFloatGyroY(), and readFloatGyroZ() return angular velocity in degrees per second. Again, the sketch prints each value with three decimal places, separated by commas.

Serial.print(',');
Serial.print(myIMU.readFloatGyroX(), 3);
Serial.print(',');
Serial.print(myIMU.readFloatGyroY(), 3);
Serial.print(',');
Serial.print(myIMU.readFloatGyroZ(), 3);

At the end of each loop, the sketch prints a newline so that each complete set of readings appears on its own line. It then pauses for 500 milliseconds before repeating. This delay keeps the output readable and prevents overwhelming the Serial Monitor.

Serial.println();
delay(500);

If you upload and run this code, you should see a stream of numbers appearing on your Serial Monitor that changes if you move the XIAO MG24 Sense around:

In the next two sections we are going to try out the microphone of the XIAO MG24 Sense, using two different libraries.

Microphone Code with SiliconLabs Library

The following code shows how to capture audio samples from the microphone, calculate the average signal level, and map that level to LED brightness. It uses a callback system to handle microphone data efficiently. Let’s explore the code piece by piece.

#include <SilabsMicrophoneAnalog.h>

#define MIC_DATA_PIN PC9
#define MIC_PWR_PIN PC8
#define NUM_SAMPLES 128
#define MIC_VAL_MIN 735
#define MIC_VAL_MAX 900

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() {
  memcpy(mic_buffer_local, mic_buffer, NUM_SAMPLES * sizeof(uint32_t));
  data_ready_flag = true;
}

void calculate_and_display_voice_level() {
  static uint32_t avg = 0;

  micAnalog.stopSampling();

  uint32_t level = (uint32_t)micAnalog.getAverage(mic_buffer_local, NUM_SAMPLES);
  level = constrain(level, MIC_VAL_MIN, MIC_VAL_MAX);
  avg = (level + avg) / 2;

  int brightness = map(avg, MIC_VAL_MIN, MIC_VAL_MAX, 0, 255);
  analogWrite(LED_BUILTIN, 255 - brightness);
  Serial.println(avg);

  micAnalog.startSampling(mic_samples_ready_cb);
}

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();
  }
}

Imports

The sketch begins by including the SilabsMicrophoneAnalog.h library. This library provides functions to initialize the microphone, start and stop sampling, and process the collected data.

#include <SilabsMicrophoneAnalog.h>

Constants

Next, the program defines several constants. MIC_DATA_PIN and MIC_PWR_PIN specify the pins connected to the microphone’s data and power lines. NUM_SAMPLES determines how many audio samples will be collected at once. MIC_VAL_MIN and MIC_VAL_MAX define the expected range of microphone values for normalization. These limits help filter out unwanted noise and ensure a good LED brightness mapping.

#define MIC_DATA_PIN PC9
#define MIC_PWR_PIN PC8
#define NUM_SAMPLES 128
#define MIC_VAL_MIN 735
#define MIC_VAL_MAX 900

Buffers

Two buffers store the microphone samples. mic_buffer holds raw samples from the microphone, while mic_buffer_local stores a safe copy of those samples for processing. This separation prevents errors if new data arrives while calculations are still in progress.

uint32_t mic_buffer[NUM_SAMPLES];
uint32_t mic_buffer_local[NUM_SAMPLES];

Flags and Objects

The variable data_ready_flag tells the program when a new set of samples is available. It is marked as volatile because it is updated inside an interrupt or callback. The object micAnalog is created from the MicrophoneAnalog class. It takes the microphone’s data and power pins as parameters.

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

Microphone Callback

The function mic_samples_ready_cb() runs automatically whenever the microphone finishes collecting a batch of samples. It copies the contents of mic_buffer into mic_buffer_local and sets data_ready_flag to true, signaling that the data is ready to process.

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

Processing Voice Levels

The function calculate_and_display_voice_level() processes the audio data and updates the LED brightness. First, it stops microphone sampling to avoid interference during calculations. Then it calculates the average signal value using micAnalog.getAverage(). This value is constrained between MIC_VAL_MIN and MIC_VAL_MAX to smooth out extreme spikes.

To make the LED respond more smoothly, the average value is combined with the previous average using a simple filter. The result is mapped from the microphone range to the LED brightness range of 0 to 255. Finally, the LED brightness is set using analogWrite(). A higher sound level makes the LED brighter.

The function also prints the average value to the Serial Monitor and then restarts microphone sampling.

void calculate_and_display_voice_level() {
  static uint32_t avg = 0;

  micAnalog.stopSampling();

  uint32_t level = (uint32_t)micAnalog.getAverage(mic_buffer_local, NUM_SAMPLES);
  level = constrain(level, MIC_VAL_MIN, MIC_VAL_MAX);
  avg = (level + avg) / 2;

  int brightness = map(avg, MIC_VAL_MIN, MIC_VAL_MAX, 0, 255);
  analogWrite(LED_BUILTIN, 255 - brightness);
  Serial.println(avg);

  micAnalog.startSampling(mic_samples_ready_cb);
}

Setup

The setup() function prepares the serial monitor and the LED. It also initializes the microphone with the buffer and number of samples. Once initialized, the sketch starts sampling and prints confirmation messages to the Serial Monitor.

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...");
}

Loop

The loop() function checks if new data is ready. If data_ready_flag is true, it clears the flag and calls calculate_and_display_voice_level(). This ensures that the microphone data is processed only when fresh samples are available.

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

After uploading the code, you should see the brightness of the on-board LED changing depending on the ambient volume levels. The louder the brighter.

Microphone Code with Seeed_Arduino_Mic Library

This sketch initializes a microphone using the Seeed_Arduino_Mic library, collects a fixed number of audio samples, and outputs them as raw data. It demonstrates how to set up microphone parameters, handle callbacks, and process incoming audio data.

You will need to install the Seeed_Arduino_Mic Library, before you can run this code. Download the library as a .ZIP file from the Github Repo and install it via Sketch → Include Library → Add .ZIP Library …

Have a quick look at the complete sketch first and then we will dive into its details:

#include <mic.h>

#define DEBUG 1  // Enable pin pulse during ISR
#define SAMPLES 800

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

MG24_ADC_Class Mic(&mic_config);

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

static void audio_rec_callback(uint16_t *buf, uint32_t buf_len) {
  static uint32_t idx = 0;

  for (uint32_t i = 0; i < buf_len; i++) {
    // Convert 12-bit unsigned ADC value to 16-bit PCM (signed) audio value
    recording_buf[idx++] = buf[i];
    if (idx >= SAMPLES) {
      idx = 0;
      recording = 0;
      record_ready = true;
      break;
    }
  }
}

void setup() {
  Serial.begin(115200);
  Mic.set_callback(audio_rec_callback);

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

void loop() {
  if (record_ready) {
    Serial.println("Finished sampling");
    for (int i = 0; i < SAMPLES; i++) {
      int16_t sample = recording_buf[i];
      Serial.println(sample);
    }
    record_ready = false;
  }
}

Imports

The program begins by including the mic.h header file. This library provides tools to configure and control the microphone hardware on Seeed’s platforms.

#include <mic.h>

Constants

Two constants are defined. The first, DEBUG, allows you to enable pin pulsing during interrupts for debugging. If DEBUG is set to 1, the LED pin toggles every time an interrupt occurs, giving a visual indication of sampling activity. The second constant, SAMPLES, specifies the number of audio samples to record before processing.

#define DEBUG 1  // Enable pin pulse during ISR
#define SAMPLES 800

Microphone Configuration

The microphone is configured using a mic_config_t structure. Here, the microphone is set to use one channel, a sampling rate of 16 kHz, and a buffer size of 1600 samples. The debug_pin is linked to LED_BUILTIN, so the onboard LED toggles during each interrupt if debugging is enabled.

mic_config_t mic_config{
  .channel_cnt = 1,
  .sampling_rate = 16000,
  .buf_size = 1600,
  .debug_pin = LED_BUILTIN
};

The program then creates a microphone object named Mic using the MG24_ADC_Class. This object takes the microphone configuration as input and manages data collection.

MG24_ADC_Class Mic(&mic_config);

Buffers and Flags

The array recording_buf stores the recorded samples, with a size equal to the constant SAMPLES. Two variables manage the recording process: recording tracks recording status, and record_ready signals when the buffer is full and ready for processing. Both are declared volatile because they are modified inside an interrupt callback.

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

Callback

The core of the recording process happens in the audio_rec_callback() function. This callback runs automatically whenever the microphone buffer fills. The function copies audio data from the input buffer into the main recording_buf.

Each raw 12-bit ADC value from the microphone is converted into a signed 16-bit PCM sample. The function keeps track of the current index in the buffer with a static variable idx. When the buffer reaches its maximum size (SAMPLES), the function resets the index, clears the recording flag, and sets record_ready to true so the loop knows data is ready to process.

static void audio_rec_callback(uint16_t *buf, uint32_t buf_len) {
  static uint32_t idx = 0;

  for (uint32_t i = 0; i < buf_len; i++) {
    // Convert 12-bit unsigned ADC value to 16-bit PCM (signed) audio value
    recording_buf[idx++] = buf[i];
    if (idx >= SAMPLES) {
      idx = 0;
      recording = 0;
      record_ready = true;
      break;
    }
  }
}

Setup

Inside setup(), the Serial Monitor is initialized at 115200 baud. The program assigns audio_rec_callback as the function that will handle incoming audio data whenever the microphone collects samples.

The microphone is then started using Mic.begin(). If initialization fails, the program prints an error message and enters an infinite loop. Otherwise, it confirms successful initialization.

void setup() {
  Serial.begin(115200);
  Mic.set_callback(audio_rec_callback);

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

Loop

The loop() function checks whether recording has completed by looking at record_ready. If true, the program prints "Finished sampling" and then iterates through the buffer, printing each recorded audio sample. After printing, it resets record_ready to false so the system can record again.

void loop() {
  if (record_ready) {
    Serial.println("Finished sampling");
    for (int i = 0; i < SAMPLES; i++) {
      int16_t sample = recording_buf[i];
      Serial.println(sample);
    }
    record_ready = false;
  }
}

If you upload this sketch and open the Serial Plotter you will see an audio signal that varies depending on the audio detected by the microphone:

And that’s it! These instructions and code examples should help you to quickly get started with the XIAO MG24 Sense.

Conclusions

In this tutorial you learned how to get started with the XIAO MG24 Sense by Seeed Studio. For additional information have a look at Seeed Studio’s Getting Started Wiki. The code examples in this tutorial are derived from the examples in the Seeed_Arduino_Mic and the Seeed_Arduino_LSM6DS3 Libraries. You will find more code examples there.

With the built-in microphone and the Matrix-Vector Processor (MVP) the XIAO MG24 Sense is especially suited for TinyML applications such as keyword spotting, voice control or sound classification.

An alternative microcontroller is the ESP32 based XIAO-ESP32-S3-Sense – also by Seeed Studio. It also comes with a microphone and while it lacks the IMU it has a camera instead. It can be used for voice applications, see the our Voice control with XIAO-ESP32-S3-Sense and Edge Impulse as well, but consumes more power.

However, if you are interested in object detection the XIAO ESP32 Sense is the better choice due to the built-in camera. Have a look at our Face Detection with XIAO ESP32-S3-Sense and SenseCraft AI and the Edge AI Room Occupancy Sensor with ESP32 and Person Detection tutorials, for details.

If you have any questions feel free to leave them in the comment section.

Happy Tinkering 😉