Embedded Programming - Assignment:
The objective of this week was to browse through the datasheet of a microcontroller and, based on that information, write and test a program for an embedded system using the microcontroller to interact with local input and/or output devices, as well as to communicate through remote wired or wireless connections.
Microcontroller - Xiao nrf52840 Sense
For my project, I decided to use the XIAO nRF52840 Sense from Seeed Studio mainly because it already includes a built-in gyroscope and accelerometer. This is very convenient for my application, since it allows me to measure motion and orientation directly without needing to add an external IMU module, such as an MPU sensor. By having these sensors integrated into the board, the design becomes more compact, the wiring is simpler, and the overall system is more reliable. It also reduces power consumption and development time, because I can work with the onboard components using the provided libraries instead of configuring additional hardware.
XIAO Pin-out
XIAO Pin Configuration
Below is the detailed pinout table for the XIAO module, describing the function and chip pin mapping used in the project.
| XIAO Pin | Function | Chip Pin | Description |
|---|---|---|---|
| 5V | VBUS | - | Power Input/Output |
| GND | - | - | Ground |
| 3V3 | 3V3_OUT | - | Power Output |
| D0 | Analog | P0.02 | GPIO, ADC |
| D1 | Analog | P0.03 | GPIO, ADC |
| D2 | Analog | P0.28 | GPIO, ADC |
| D3 | Analog | P0.29 | GPIO, ADC |
| D4 | Analog, SDA | P0.04 | GPIO, I2C Data, ADC |
| D5 | Analog, SCL | P0.05 | GPIO, I2C Clock, ADC |
| D6 | TX | P1.11 | GPIO, UART Transmit |
| D7 | RX | P1.12 | GPIO, UART Receive |
| D8 | SPI_SCK | P1.13 | GPIO, SPI Clock |
| D9 | SPI_MISO | P1.14 | GPIO, SPI Data |
| D10 | SPI_MOSI | P1.15 | GPIO, SPI Data |
XIAO Series Specifications Comparison
A detailed comparison of the technical specifications across the Seeed Studio XIAO nRF52840 family.
| Item | XIAO nRF52840 | XIAO nRF52840 Sense | XIAO nRF52840 Plus | XIAO nRF52840 Sense Plus |
|---|---|---|---|---|
| Processor | Nordic nRF52840, ARM® Cortex®-M4 32-bit processor with FPU, 64 MHz | |||
| Wireless | Bluetooth Low Energy 5.4 / Bluetooth Mesh / NFC | |||
| Memory | 256 KB RAM, 1MB Flash, 2MB onboard Flash | |||
| Built-in Sensors | N/A | 6 DOF IMU, PDM Microphone | N/A | 6 DOF IMU, PDM Microphone |
| Interfaces | 1xI2C, 1xUART, 1xSPI | 1xI2C, 2xUART, 2xSPI, 1xI2S | ||
| PWM/Analog Pins | 11 / 6 | 20 / 6 | ||
| Onboard Buttons | Reset Button | |||
| Onboard LEDs | 3-in-one LED / Charge LED | |||
| Programming | Arduino / MicroPython / CircuitPython | |||
Simulation
For this section I used the simulation program Wowki and I used a C++ and a python code, my simulation consists on a led that lights on when it detects a movement range I made a range from 1-100, using the Xiao and a MPU.
Section 1: Library and Hardware Definitions.
This section includes the Wire.h library for I2C communication and defines the I2C address for the MPU6050 (0x68). It also specifies the pins for the LED and the I2C interface (SDA and SCL) assigned to the board.
#include <Wire.h>
#define MPU_ADDR 0x68
#define LED_PIN D4
#define SCL_PIN D5
#define SDA_PIN D6
Section 2: System Setup and Sensor Wake-up.
The setup function configures the LED pin as an output and initializes the Serial communication. It starts the I2C bus with the defined pins and sends a command to register 0x6B to wake up the MPU6050, as it starts in sleep mode by default.
void setup() {
pinMode(LED_PIN, OUTPUT);
Serial.begin(115200);
Wire.begin(SDA_PIN, SCL_PIN);
Wire.beginTransmission(MPU_ADDR);
Wire.write(0x6B);
Wire.endTransmission();
Serial.println("MPU6050 initialized");
}
Section 3: Data Request and Raw Reading.
Inside the loop, the code requests 6 bytes of data starting from register 0x3B (Accelerometer X-axis). It then uses bit-shifting to combine the high and low bytes for each of the three axes (X, Y, and Z) into 16-bit integers.
void loop() {
int16_t accX, accY, accZ;
Wire.beginTransmission(MPU_ADDR);
Wire.write(0x3B);
Wire.endTransmission(false);
Wire.requestFrom(MPU_ADDR, 6, true);
accX = Wire.read() << 8 | Wire.read();
accY = Wire.read() << 8 | Wire.read();
accZ = Wire.read() << 8 | Wire.read();
float ax = (float)accX;
float ay = (float)accY;
float az = (float)accZ;
Section 4: Movement Calculation and Normalization.
The code calculates the magnitude of the acceleration vector using the square root of the sum of squares. This value is constrained and normalized between 16000 and 50000 to generate a movement percentage (0-100%).
float movement = sqrt(ax * ax + ay * ay + az * az);
float minVal = 16000;
float maxVal = 50000;
movement = constrain(movement, minVal, maxVal);
float normalized = (movement - minVal)/(max_val - minVal);
normalized = constrain(normalized, 0.0, 1.0);
int movementPercent = normalized * 100;
Section 5: Output and Threshold Logic. Finally, the movement percentage is printed to the Serial Monitor. If the detected movement exceeds 30%, the LED is turned on (HIGH); otherwise, it is turned off (LOW). A delay of 200ms is added to stabilize the readings.
Serial.print("Movement (%): ");
Serial.println(movementPercent);
if (movementPercent > 30){
digitalWrite(LED_PIN, HIGH);
} else {
digitalWrite(LED_PIN, LOW);
}
delay(200);
}
Section: Video Demonstration. This video shows the real-time interaction between the MPU6050 sensor and the XIAO board. You can observe how the LED triggers when the movement magnitude exceeds the defined threshold.