### Basic Display Example Source: https://github.com/m5stack/m5unified/blob/master/README.md Demonstrates printing text to the display. Ensure M5GFX is installed. ```cpp // Basic display example // See examples/Basic/Displays/Displays.ino ``` -------------------------------- ### Touch Event Handling Example Source: https://github.com/m5stack/m5unified/blob/master/README.md Reacts to touch events on the screen. Consult the Touch example sketch. ```cpp // Touch event example // See examples/Basic/Touch/Touch.ino ``` -------------------------------- ### IMU Sensor Data Example Source: https://github.com/m5stack/m5unified/blob/master/README.md Demonstrates reading data from the accelerometer, gyroscope, and magnetometer. Check the IMU example. ```cpp // IMU sensor data example // See examples/Basic/Imu/Imu.ino ``` -------------------------------- ### Combined Functionality Demonstration Source: https://github.com/m5stack/m5unified/blob/master/README.md A comprehensive example showcasing multiple M5Unified features in a single sketch. Located in HowToUse.ino. ```cpp // Combined demonstration example // See examples/Basic/HowToUse/HowToUse.ino ``` -------------------------------- ### Microphone Recording and Playback Example Source: https://github.com/m5stack/m5unified/blob/master/README.md Records a short audio clip using the microphone and plays it back through the speaker. Refer to the Microphone example. ```cpp // Microphone recording and playback example // See examples/Basic/Microphone/Microphone.ino ``` -------------------------------- ### RTC and WiFi Time Synchronization Example Source: https://github.com/m5stack/m5unified/blob/master/README.md Connects to an Internet time server via WiFi to set the real-time clock. See the RTC example. ```cpp // RTC and WiFi time sync example // See examples/Basic/Rtc/Rtc.ino ``` -------------------------------- ### Button Press Detection Example Source: https://github.com/m5stack/m5unified/blob/master/README.md Detects and responds to button presses. Refer to the Button example sketch. ```cpp // Button detection example // See examples/Basic/Button/Button.ino ``` -------------------------------- ### Speaker Audio Playback Example Source: https://github.com/m5stack/m5unified/blob/master/README.md Plays wave audio through the built-in speakers or compatible accessories. Check the Speaker example. ```cpp // Speaker audio playback example // See examples/Basic/Speaker/Speaker.ino ``` -------------------------------- ### Advanced Audio and Bluetooth Examples Source: https://github.com/m5stack/m5unified/blob/master/README.md Explore advanced functionalities like playing audio over Bluetooth and MP3 decoding. These are found in the Advanced folder. ```cpp // Advanced audio and Bluetooth examples // See examples/Advanced/ ``` -------------------------------- ### M5Unified Logging System Source: https://context7.com/m5stack/m5unified/llms.txt Utilize M5Unified's logging system for structured output with source information. Configure log levels for different targets, enable/disable colored output, and set up custom log callbacks. Includes examples for error, warning, info, debug, and verbose levels, as well as direct printf-style output and hex dumps. ```cpp #include void setup(void) { M5.begin(); // Log macros with source information M5_LOGE("Error message: %d", 42); // Error level M5_LOGW("Warning message"); // Warning level M5_LOGI("Info message"); // Info level M5_LOGD("Debug message"); // Debug level M5_LOGV("Verbose message"); // Verbose level // Output: [123456][E][file.cpp:10] setup(): Error message: 42 // Direct log output (ignores log level) M5.Log.printf("Formatted output: %d\n", 100); M5.Log.print("Simple text"); M5.Log.println("Text with newline"); M5.Log.println(); // Set log levels for different targets M5.Log.setLogLevel(m5::log_target_serial, ESP_LOG_DEBUG); M5.Log.setLogLevel(m5::log_target_display, ESP_LOG_INFO); M5.Log.setLogLevel(m5::log_target_callback, ESP_LOG_WARN); // Enable/disable colored output M5.Log.setEnableColor(m5::log_target_serial, true); M5.Log.setEnableColor(m5::log_target_display, false); // Set log display M5.setLogDisplayIndex(0); // Show logs on display 0 M5.Log.setDisplay(&M5.Display); // Custom log callback M5.Log.setCallback([](esp_log_level_t level, bool use_color, const char* text) { // Custom handling of log messages Serial.printf("[CUSTOM] %s", text); }); // Hex dump uint8_t data[] = {0x01, 0x02, 0x03, 0x04}; M5.Log.dump(data, sizeof(data), ESP_LOG_INFO); } void loop(void) { static int counter = 0; M5_LOGI("Loop iteration: %d", counter++); M5.delay(1000); } ``` -------------------------------- ### Initialize M5Unified with Custom Configuration Source: https://context7.com/m5stack/m5unified/llms.txt Initializes all hardware components with customizable options. Pass a configuration object to `M5.begin()` to enable specific features like serial baud rate, display clearing, power output, internal/external peripherals, LED brightness, and speaker/display configurations. Detects the board type at runtime. ```cpp #include void setup(void) { auto cfg = M5.config(); // Serial configuration (Arduino only) cfg.serial_baudrate = 115200; // 0 to disable Serial // Display options cfg.clear_display = true; // Clear screen on startup // Power options cfg.output_power = true; // Enable 5V output to external ports // Internal peripherals cfg.internal_imu = true; // Enable internal IMU cfg.internal_rtc = true; // Enable internal RTC cfg.internal_spk = true; // Enable internal speaker cfg.internal_mic = true; // Enable internal microphone // External peripherals cfg.external_imu = false; // Enable Unit IMU cfg.external_rtc = false; // Enable Unit RTC // System LED brightness (0=off, 255=max) cfg.led_brightness = 64; // External speaker configuration cfg.external_speaker.hat_spk = true; // HAT SPK cfg.external_speaker.hat_spk2 = true; // HAT SPK2 cfg.external_speaker.atomic_spk = true; // ATOMIC SPK cfg.external_speaker.atomic_echo = true; // ATOMIC ECHO BASE // External display configuration cfg.external_display.module_display = true; // Module Display cfg.external_display.atom_display = true; // ATOM Display cfg.external_display.unit_oled = true; // Unit OLED cfg.external_display.unit_lcd = true; // Unit LCD M5.begin(cfg); // Get detected board type switch (M5.getBoard()) { case m5::board_t::board_M5Stack: Serial.println("M5Stack"); break; case m5::board_t::board_M5StackCore2: Serial.println("Core2"); break; case m5::board_t::board_M5StickC: Serial.println("StickC"); break; case m5::board_t::board_M5AtomS3: Serial.println("ATOMS3"); break; default: Serial.println("Unknown"); break; } } void loop(void) { M5.update(); // Required for button/touch state updates M5.delay(10); } ``` -------------------------------- ### ESP-IDF M5Unified Integration Source: https://context7.com/m5stack/m5unified/llms.txt This snippet demonstrates how to integrate M5Unified with the ESP-IDF framework. It includes the necessary includes, M5.begin() and M5.update() calls within a task, and the ESP-IDF entry point 'app_main'. Ensure you provide your own main task for ESP-IDF projects. ```cpp #include void setup(void) { M5.begin(); M5.Display.println("ESP-IDF example"); } void loop(void) { M5.update(); M5.delay(10); } // ESP-IDF entry point #if !defined(ARDUINO) && defined(ESP_PLATFORM) extern "C" { void loopTask(void*) { setup(); for (;;) { loop(); } vTaskDelete(NULL); } void app_main() { xTaskCreatePinnedToCore(loopTask, "loopTask", 8192, NULL, 1, NULL, 1); } } #endif ``` -------------------------------- ### Handle Touch Screen Input with M5Unified Source: https://context7.com/m5stack/m5unified/llms.txt This snippet demonstrates how to detect touch events like press, release, click, hold, drag, and flick on devices with touchscreens. Configure touch thresholds for hold and flick detection. Supports multi-touch up to 5 points. ```cpp #include void setup(void) { M5.begin(); M5.Display.setTextSize(2); // Configure touch settings M5.Touch.setHoldThresh(500); // Hold detection time in ms M5.Touch.setFlickThresh(8); // Flick detection distance } void loop(void) { M5.delay(1); M5.update(); auto count = M5.Touch.getCount(); // Number of touch points if (count == 0) return; // Get touch detail for first touch point auto t = M5.Touch.getDetail(0); // Touch state detection if (t.wasPressed()) { M5.Display.printf("Touch at (%d, %d)\n", t.x, t.y); } if (t.wasReleased()) { M5.Display.println("Touch released"); } if (t.wasClicked()) { M5.Display.printf("Clicked at (%d, %d)\n", t.x, t.y); } // Hold detection if (t.wasHold()) { M5.Display.println("Hold started"); } if (t.isHolding()) { M5.Display.printf("Holding at (%d, %d)\n", t.x, t.y); } // Drag detection if (t.wasDragStart()) { M5.Display.println("Drag started"); } if (t.isDragging()) { int dx = t.deltaX(); // Movement since last frame int dy = t.deltaY(); M5.Display.printf("Dragging: dx=%d, dy=%d\n", dx, dy); } if (t.wasDragged()) { M5.Display.println("Drag ended"); } // Flick detection if (t.wasFlickStart()) { M5.Display.println("Flick started"); } if (t.wasFlicked()) { int distX = t.distanceX(); // Total distance from start int distY = t.distanceY(); M5.Display.printf("Flicked: distX=%d, distY=%d\n", distX, distY); } // Multi-touch support (up to 5 points) for (size_t i = 0; i < count; ++i) { auto touch = M5.Touch.getDetail(i); M5.Display.printf("Point %d: (%d, %d)\n", i, touch.x, touch.y); } } ``` -------------------------------- ### Configure and Use RTC Source: https://context7.com/m5stack/m5unified/llms.txt Initializes the RTC, sets date and time directly or via NTP synchronization, and retrieves current date/time information. Supports setting and clearing alarms and timers. ```cpp #include #include void setup(void) { auto cfg = M5.config(); cfg.internal_rtc = true; // Enable internal RTC cfg.external_rtc = true; // Enable external Unit RTC M5.begin(cfg); if (!M5.Rtc.isEnabled()) { Serial.println("RTC not found"); return; } // Set date and time directly // Format: {{ year, month, day }, { hour, minute, second }} M5.Rtc.setDateTime({{ 2024, 6, 15 }, { 14, 30, 0 }}); // Set date only m5::rtc_date_t date = { 2024, 6, 15, 6 }; // year, month, day, weekDay (0=Sun) M5.Rtc.setDate(&date); // Set time only m5::rtc_time_t time = { 14, 30, 0 }; // hours, minutes, seconds M5.Rtc.setTime(&time); // Synchronize with NTP (requires WiFi) WiFi.begin("SSID", "PASSWORD"); while (WiFi.status() != WL_CONNECTED) { delay(500); } configTzTime("JST-9", "pool.ntp.org"); delay(2000); // Set RTC from system time time_t t = time(nullptr); M5.Rtc.setDateTime(gmtime(&t)); // Set system time from RTC M5.Rtc.setSystemTimeFromRtc(); } void loop(void) { // Get current date and time auto dt = M5.Rtc.getDateTime(); Serial.printf("%04d/%02d/%02d %02d:%02d:%02d\n", dt.date.year, dt.date.month, dt.date.date, dt.time.hours, dt.time.minutes, dt.time.seconds); // Get date only auto date = M5.Rtc.getDate(); Serial.printf("Date: %04d/%02d/%02d\n", date.year, date.month, date.date); // Get time only auto time = M5.Rtc.getTime(); Serial.printf("Time: %02d:%02d:%02d\n", time.hours, time.minutes, time.seconds); // Set alarm IRQ m5::rtc_time_t alarm_time = { 7, 0, 0 }; // 7:00:00 M5.Rtc.setAlarmIRQ(alarm_time); // Set timer IRQ (milliseconds) M5.Rtc.setTimerIRQ(5000); // 5 seconds // Check and clear IRQ if (M5.Rtc.getIRQstatus()) { Serial.println("RTC alarm triggered"); M5.Rtc.clearIRQ(); } // Disable IRQ M5.Rtc.disableIRQ(); M5.delay(1000); } ``` -------------------------------- ### M5Unified Microphone Audio Recording Source: https://context7.com/m5stack/m5unified/llms.txt Shows how to record audio using the M5Mic class, including setting up the microphone, recording in 16-bit or 8-bit format, configuring sample rate and noise filter, and checking recording status. Note that Speaker and Mic cannot be used simultaneously. ```cpp #include static constexpr size_t RECORD_LENGTH = 16000; // 1 second at 16kHz static int16_t rec_buffer[RECORD_LENGTH]; void setup(void) { M5.begin(); M5.Display.println("Recording..."); // Note: Speaker and Mic cannot be used simultaneously // Turn off speaker before recording M5.Speaker.end(); M5.Mic.begin(); } void loop(void) { M5.update(); if (M5.Mic.isEnabled()) { // Record audio (16-bit, 16kHz, mono) if (M5.Mic.record(rec_buffer, RECORD_LENGTH, 16000, false)) { M5.Display.println("Recording in progress..."); } // Check recording status // Returns: 0=not recording, 1=recording (queue has room), 2=recording (queue full) size_t status = M5.Mic.isRecording(); // Alternative: record 8-bit audio // uint8_t rec_buffer_8bit[RECORD_LENGTH]; // M5.Mic.record(rec_buffer_8bit, RECORD_LENGTH, 16000, false); // Set sample rate M5.Mic.setSampleRate(16000); // Configure noise filter (via config) auto cfg = M5.Mic.config(); cfg.noise_filter_level = 64; // 0-255 (0 = off) M5.Mic.config(cfg); } // Playback recorded audio if (M5.BtnA.wasClicked()) { // Wait for recording to complete while (M5.Mic.isRecording()) { M5.delay(1); } // Switch to speaker mode M5.Mic.end(); M5.Speaker.begin(); M5.Speaker.setVolume(255); // Play recorded audio M5.Speaker.playRaw(rec_buffer, RECORD_LENGTH, 16000, false); while (M5.Speaker.isPlaying()) { M5.delay(1); } // Switch back to microphone mode M5.Speaker.end(); M5.Mic.begin(); } } ``` -------------------------------- ### Initialize and Read IMU Data Source: https://context7.com/m5stack/m5unified/llms.txt Initializes the IMU, checks its type, loads calibration data, and reads accelerometer, gyroscope, and magnetometer data. Calibration can be saved or cleared using buttons. ```cpp #include void setup(void) { auto cfg = M5.config(); cfg.internal_imu = true; // Enable internal IMU // cfg.external_imu = true; // Enable external Unit IMU M5.begin(cfg); // Check IMU type auto imu_type = M5.Imu.getType(); switch (imu_type) { case m5::imu_none: Serial.println("No IMU"); break; case m5::imu_mpu6886: Serial.println("MPU6886"); break; case m5::imu_mpu9250: Serial.println("MPU9250"); break; case m5::imu_bmi270: Serial.println("BMI270"); break; case m5::imu_sh200q: Serial.println("SH200Q"); break; default: Serial.println("Unknown IMU"); break; } // Load calibration data from NVS if (!M5.Imu.loadOffsetFromNVS()) { Serial.println("No calibration data found"); } // Set calibration strength (0=off, 1-255=strength) // Arguments: accel_strength, gyro_strength, mag_strength M5.Imu.setCalibration(64, 64, 64); } void loop(void) { // Update IMU values auto updated = M5.Imu.update(); if (updated) { // Get all IMU data at once auto data = M5.Imu.getImuData(); // Accelerometer (in G) float ax = data.accel.x; float ay = data.accel.y; float az = data.accel.z; Serial.printf("Accel: X=%.2f Y=%.2f Z=%.2f G\n", ax, ay, az); // Gyroscope (in degrees/second) float gx = data.gyro.x; float gy = data.gyro.y; float gz = data.gyro.z; Serial.printf("Gyro: X=%.2f Y=%.2f Z=%.2f dps\n", gx, gy, gz); // Magnetometer (if available) float mx = data.mag.x; float my = data.mag.y; float mz = data.mag.z; Serial.printf("Mag: X=%.2f Y=%.2f Z=%.2f\n", mx, my, mz); // Alternative: get individual sensor values float accel_x, accel_y, accel_z; M5.Imu.getAccel(&accel_x, &accel_y, &accel_z); float gyro_x, gyro_y, gyro_z; M5.Imu.getGyro(&gyro_x, &gyro_y, &gyro_z); float mag_x, mag_y, mag_z; M5.Imu.getMag(&mag_x, &mag_y, &mag_z); float temperature; M5.Imu.getTemp(&temperature); } M5.update(); // Save calibration to NVS on button press if (M5.BtnA.wasClicked()) { M5.Imu.saveOffsetToNVS(); Serial.println("Calibration saved"); } // Clear calibration data if (M5.BtnB.wasClicked()) { M5.Imu.clearOffsetData(); Serial.println("Calibration cleared"); } M5.delay(10); } ``` -------------------------------- ### Basic Display Operations with M5Unified Source: https://context7.com/m5stack/m5unified/llms.txt Performs basic display operations using the unified `M5.Display` object (M5GFX). Supports auto-rotation, backlight control, EPD modes, text rendering, shape drawing, and accessing multiple displays. Use `M5.Displays(index)` for devices with multiple displays. ```cpp #include void setup(void) { M5.begin(); // Auto-rotate to landscape if needed if (M5.Display.width() < M5.Display.height()) { M5.Display.setRotation(M5.Display.getRotation() ^ 1); } // Set backlight brightness (0-255) for LCD displays M5.Display.setBrightness(128); // Set EPD mode for e-paper displays M5.Display.setEpdMode(epd_mode_t::epd_fastest); // fastest but low quality // M5.Display.setEpdMode(epd_mode_t::epd_quality); // slow but high quality // Basic drawing operations M5.Display.fillScreen(TFT_BLACK); M5.Display.setTextSize(2); M5.Display.setTextColor(TFT_WHITE, TFT_BLACK); M5.Display.setCursor(0, 0); M5.Display.println("Hello M5Stack!"); // Draw shapes M5.Display.drawRect(10, 50, 100, 60, TFT_RED); M5.Display.fillCircle(160, 80, 30, TFT_GREEN); M5.Display.drawLine(0, 0, M5.Display.width(), M5.Display.height(), TFT_BLUE); // Multiple displays support size_t display_count = M5.getDisplayCount(); for (int i = 0; i < display_count; ++i) { M5.Displays(i).startWrite(); M5.Displays(i).fillScreen(TFT_BLACK); M5.Displays(i).printf("Display %d\n", i); M5.Displays(i).endWrite(); } // Set primary display by type M5.setPrimaryDisplayType({ m5::board_t::board_M5ModuleDisplay, m5::board_t::board_M5AtomDisplay, }); } ``` -------------------------------- ### M5Unified Speaker Audio Playback Source: https://context7.com/m5stack/m5unified/llms.txt Demonstrates various audio playback methods using the M5Speaker class, including tone generation, raw audio data playback (8-bit and 16-bit), and WAV file playback. Also covers volume control and playback status checks. ```cpp #include // Sample 8-bit WAV data (would normally be loaded from file) extern const uint8_t sample_wav[]; extern const size_t sample_wav_len; void setup(void) { M5.begin(); if (M5.Speaker.isEnabled()) { // Set master volume (0-255) M5.Speaker.setVolume(128); // Play a simple tone // tone(frequency_hz, duration_ms, channel, stop_current) M5.Speaker.tone(440, 500); // 440Hz for 500ms while (M5.Speaker.isPlaying()) { M5.delay(1); } // Play another tone on a specific channel M5.Speaker.tone(880, 300, 0, true); // Channel 0, stop current while (M5.Speaker.isPlaying()) { M5.delay(1); } // Play raw audio data (signed 8-bit) // playRaw(data, length, sample_rate, stereo, repeat, channel, stop_current) M5.Speaker.playRaw((const int8_t*)sample_wav, sample_wav_len, 44100, false, 1, -1, false); // Play raw audio data (unsigned 8-bit) M5.Speaker.playRaw((const uint8_t*)sample_wav, sample_wav_len, 44100); // Play raw audio data (16-bit) // M5.Speaker.playRaw((const int16_t*)sample_wav16, sample_wav16_len, 44100); // Play WAV file (with header) // M5.Speaker.playWav(wav_data, wav_data_len, 1); // repeat once // Set channel volume (0-255) M5.Speaker.setChannelVolume(0, 200); M5.Speaker.setAllChannelVolume(128); // Stop playback M5.Speaker.stop(); // Stop all channels M5.Speaker.stop(0); // Stop specific channel // Check playback status if (M5.Speaker.isPlaying()) { Serial.println("Playing audio"); } size_t playing = M5.Speaker.isPlaying(0); // Check specific channel // Returns: 0=not playing, 1=playing (queue has room), 2=playing (queue full) size_t channels = M5.Speaker.getPlayingChannels(); Serial.printf("%d channels playing\n", channels); } } void loop(void) { M5.update(); } ``` -------------------------------- ### Include M5Unified Library Source: https://github.com/m5stack/m5unified/blob/master/README.md Include the M5Unified library in your Arduino sketch to access its functionalities. ```cpp #include "M5Unified.h" ``` -------------------------------- ### Control Power States and Battery Source: https://context7.com/m5stack/m5unified/llms.txt Manage external port power, USB output, LED brightness, and monitor battery status including level, voltage, current, and charging state. Configure battery charging parameters and control the vibration motor. ```cpp #include void setup(void) { M5.begin(); // Enable/disable external port power M5.Power.setExtOutput(true); // Enable/disable USB port output (CoreS3) M5.Power.setUsbOutput(true); // Control power LED M5.Power.setLed(128); // 0=off, 255=max brightness // Battery management int level = M5.Power.getBatteryLevel(); // 0-100% Serial.printf("Battery: %d%%\n", level); int voltage = M5.Power.getBatteryVoltage(); // in mV Serial.printf("Voltage: %d mV\n", voltage); int current = M5.Power.getBatteryCurrent(); // in mA (+=charging, -=discharging) Serial.printf("Current: %d mA\n", current); // Check charging status auto charging = M5.Power.isCharging(); switch (charging) { case m5::Power_Class::is_charging: Serial.println("Charging"); break; case m5::Power_Class::is_discharging: Serial.println("Discharging"); break; case m5::Power_Class::charge_unknown: Serial.println("Unknown"); break; } // Configure charging M5.Power.setBatteryCharge(true); M5.Power.setChargeCurrent(500); // mA M5.Power.setChargeVoltage(4200); // mV // Vibration motor (if available) M5.Power.setVibration(128); // 0=stop, 1-255=strength M5.delay(200); M5.Power.setVibration(0); } void loop(void) { M5.update(); // Power button state (for devices with AXP192/AXP2101) uint8_t key = M5.Power.getKeyState(); // 0=none, 1=long press, 2=short click, 3=both if (key) { Serial.printf("Power key: %d\n", key); } // Power off if (M5.BtnA.wasHold()) { M5.Power.powerOff(); } // Deep sleep with timer wakeup if (M5.BtnB.wasClicked()) { M5.Power.deepSleep(10 * 1000000); // 10 seconds in microseconds } // Light sleep if (M5.BtnC.wasClicked()) { M5.Power.lightSleep(5 * 1000000); // 5 seconds } // Timer sleep with RTC wakeup // M5.Power.timerSleep(30); // Wake up in 30 seconds M5.delay(100); } ``` -------------------------------- ### Detect Button States with M5Unified Source: https://context7.com/m5stack/m5unified/llms.txt Use this snippet to detect various states of physical buttons like pressed, released, clicked, and held. Ensure M5.update() is called in the loop to refresh button states. Available buttons depend on the M5 device. ```cpp #include void setup(void) { M5.begin(); M5.Display.setTextSize(2); M5.Display.println("Press buttons!"); } void loop(void) { M5.delay(1); M5.update(); // Must call to update button states // Button state detection if (M5.BtnA.wasPressed()) { M5.Display.println("BtnA pressed"); } if (M5.BtnA.wasReleased()) { M5.Display.println("BtnA released"); } if (M5.BtnA.wasClicked()) { M5.Display.println("BtnA clicked"); } if (M5.BtnA.wasHold()) { M5.Display.println("BtnA held"); } // Check for double-click or multi-click if (M5.BtnA.wasDecideClickCount()) { int count = M5.BtnA.getClickCount(); M5.Display.printf("Clicked %d times\n", count); } // Check if button is currently pressed if (M5.BtnA.isPressed()) { M5.Display.println("BtnA is being pressed"); } if (M5.BtnA.isHolding()) { M5.Display.println("BtnA is being held"); } // Press duration check if (M5.BtnA.pressedFor(1000)) { M5.Display.println("BtnA pressed for 1 second"); } // Configure thresholds M5.BtnA.setDebounceThresh(10); // Debounce time in ms M5.BtnA.setHoldThresh(500); // Hold detection time in ms // Power button (available on Core2, StickC, CoreInk, etc.) if (M5.BtnPWR.wasClicked()) { M5.Display.println("Power button clicked"); } } ``` -------------------------------- ### I2C Bus Access and Scanning Source: https://context7.com/m5stack/m5unified/llms.txt Access internal and external I2C buses provided by M5Unified. Includes a function to scan the external I2C bus for connected devices and demonstrates reading data from an I2C device. Also shows how to retrieve the GPIO pin assignments for the I2C bus. ```cpp #include void setup(void) { M5.begin(); // Internal I2C bus (for built-in devices) // M5.In_I2C // External I2C bus (Port A) // M5.Ex_I2C // Scan for I2C devices on external bus Serial.println("Scanning I2C bus..."); for (uint8_t addr = 1; addr < 127; addr++) { M5.Ex_I2C.beginTransmission(addr); if (M5.Ex_I2C.endTransmission() == 0) { Serial.printf("Device found at 0x%02X\n", addr); } } // Read from I2C device uint8_t reg = 0x00; uint8_t data[2]; M5.Ex_I2C.beginTransmission(0x50); M5.Ex_I2C.write(reg); M5.Ex_I2C.endTransmission(false); M5.Ex_I2C.requestFrom(0x50, 2); data[0] = M5.Ex_I2C.read(); data[1] = M5.Ex_I2C.read(); // Get GPIO pin assignments int sda_pin = M5.getPin(m5::port_a_sda); int scl_pin = M5.getPin(m5::port_a_scl); Serial.printf("Port A: SDA=%d, SCL=%d\n", sda_pin, scl_pin); } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.