<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Core S3 I2C Issue: SCL is held low on the bus]]></title><description><![CDATA[<p dir="auto">Hi, I'm new to M5Stack. I have a Core S3, Unit CO2L, PaHub, and Unit LIGHT.</p>
<p dir="auto">Last week, I had a working setup for this in ESPHome. For some reason now, when I start the device it's unable to communicate over the Port A I2C bus assigned to GPIO pins 1 and 2. Whether I have the PaHub or the CO2L plugged directly into Port A, I get the following error about "SCL is held low on the bus."</p>
<pre><code>[07:19:11][C][i2c.idf:083]: I2C Bus:
[07:19:11][C][i2c.idf:084]:   SDA Pin: GPIO2
[07:19:11][C][i2c.idf:084]:   SCL Pin: GPIO1
[07:19:11][C][i2c.idf:084]:   Frequency: 50000 Hz
[07:19:11][C][i2c.idf:097]:   Recovery: failed, SCL is held low on the bus
[07:19:11][I][i2c.idf:104]: Results from bus scan:
[07:19:11][I][i2c.idf:106]: Found no devices
[07:19:11][C][i2c.idf:083]: I2C Bus:
[07:19:11][C][i2c.idf:084]:   SDA Pin: GPIO12
[07:19:11][C][i2c.idf:084]:   SCL Pin: GPIO11
[07:19:11][C][i2c.idf:084]:   Frequency: 50000 Hz
[07:19:11][C][i2c.idf:094]:   Recovery: bus successfully recovered
[07:19:11][I][i2c.idf:104]: Results from bus scan:
[07:19:11][I][i2c.idf:110]: Found device at address 0x34
[07:19:11][I][i2c.idf:110]: Found device at address 0x40
[07:19:11][I][i2c.idf:110]: Found device at address 0x51
[07:19:11][I][i2c.idf:110]: Found device at address 0x58
[07:19:11][I][i2c.idf:110]: Found device at address 0x69
</code></pre>
<p dir="auto">You can see here, I had two I2C bus configured, the internal sub on GPIO 11 and 12, and the external bus on GPIO 1 and 2:</p>
<pre><code>i2c:
  - id: i2c_port_a
    sda: GPIO2
    scl: GPIO1
    scan: true
  - id: i2c_internal
    sda: GPIO12
    scl: GPIO11
    scan: true

sensor:
  - platform: scd4x
    i2c_id: i2c_port_a
    id: scd41_sensor
    automatic_self_calibration: false
    co2:
      name: "CO2"
      id: co2_sensor
      unit_of_measurement: "ppm"
      accuracy_decimals: 0
    temperature:
      name: "Temperature"
      id: temperature_sensor
      unit_of_measurement: "°C"
      accuracy_decimals: 1
    humidity:
      name: "Humidity"
      id: humidity_sensor
      unit_of_measurement: "%"
      accuracy_decimals: 1
    update_interval: 5s
</code></pre>
<p dir="auto">I had a more complex configuration, but I have removed it down to the bare essentials after this issue began. I haven't done any soldering or even opened the device. Everything I find about this error has related to physical hardware issues folks typically caused while integrating custom hardware. But I haven't done anything like this.</p>
<p dir="auto">I have tried plugging in the PaHub and the CO2L and in both cases I see this issue. I have tried power cycling the device, etc.</p>
]]></description><link>https://community.m5stack.com/topic/7681/core-s3-i2c-issue-scl-is-held-low-on-the-bus</link><generator>RSS for Node</generator><lastBuildDate>Wed, 29 Apr 2026 15:09:13 GMT</lastBuildDate><atom:link href="https://community.m5stack.com/topic/7681.rss" rel="self" type="application/rss+xml"/><pubDate>Mon, 14 Jul 2025 12:39:57 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to Core S3 I2C Issue: SCL is held low on the bus on Tue, 15 Jul 2025 13:20:26 GMT]]></title><description><![CDATA[<p dir="auto"><a class="plugin-mentions-user plugin-mentions-a" href="/user/hacxx" aria-label="Profile: hacxx">@<bdi>hacxx</bdi></a> I was able to work out the problem. I implemented changes to the m5stack board_m5cores3 component which makes it enable the correct AXP2101 power management for I2C for the Port A Grove port when using USB-C power.</p>
<p dir="auto">My issue was when using the device with the DIN base and the battery on and a sensor (CO2L) plugged into the Grove Port A (I2C), the device would be working. But if I disconnect USB-C from my computer and switch off the DIN base power, then switch the DIN base back on and plug USB-C back in (simulating a complete power outage of mains and battery) the device would boot loop with the message about SDA being held low.</p>
<p dir="auto">The only way for me to get out of the loop is to unplug the CO2L from Port A. Then the device would boot on its next attempt and the I2C port recovery would be successful. Finally, I could plugin the CO2L, reset using the button, and everything would work again.</p>
<p dir="auto">The issue was I needed to call <code>M5.Power.setExtOutput</code> during setup() of the <code>BoardM5CoreS3</code> class from the <a href="https://github.com/m5stack/M5CoreS3-Esphome" target="_blank" rel="noopener noreferrer nofollow ugc">https://github.com/m5stack/M5CoreS3-Esphome</a> repo's components.</p>
<pre><code class="language-cpp">void BoardM5CoreS3::setup() {
  M5.begin();

  ESP_LOGI(TAG, "Enabling 5V power output on the external ports");
  M5.Power.setExtOutput(true);

  ESP_LOGI(TAG, "Turning off display panel backlight");
  M5.Display.setBrightness(0);
}
</code></pre>
<p dir="auto">I implemented this in a <a href="https://github.com/terpasaurus-midwest/esphome-fork/blob/m5cores3/my_components/board_m5cores3/board_m5cores3.cpp#L25" target="_blank" rel="noopener noreferrer nofollow ugc">custom component</a> which I then add as an external_component to my ESPHome config. I added additional functionality in a <a href="https://github.com/terpasaurus-midwest/esphome-fork/tree/m5cores3/my_components/m5cores3_power" target="_blank" rel="noopener noreferrer nofollow ugc">separate component</a>, to expose the AXP2101 battery level, charging status, etc. I also <a href="https://github.com/terpasaurus-midwest/esphome-fork/blob/m5cores3/my_components/m5cores3_power/automations.py" target="_blank" rel="noopener noreferrer nofollow ugc">added an automation</a> action to allow printing out debug state info from the AXP2101, to help with debugging the IRQ and other power management concerns.</p>
<p dir="auto">In my ESPHome config it looks like this now and the CO2L sensor works reliably now without the controller going into boot-loops from various power loss/power source change scenarios:</p>
<pre><code class="language-yaml">esphome:
  name: ${hostname}
  friendly_name: ${friendlyname}
  platformio_options:
    board_build.flash_mode: dio
    board_build.mcu: esp32s3
    board_build.f_cpu: 240000000L
  libraries:
    - m5stack/M5Unified

external_components:
  - source:
      type: git
      url: https://github.com/terpasaurus-midwest/esphome-fork
      ref: m5cores3
      path: my_components
    refresh: 2min
    components: [m5cores3_power, board_m5cores3]

board_m5cores3:
  id: m5_board

m5cores3_power:
  id: m5_power
  battery_sensor:
    name: "Battery Level"
    id: battery_level
  battery_present_sensor:
    name: "Battery Present"
    id: battery_present
  battery_charging_sensor:
    name: "Battery Charging"
    id: battery_charging
</code></pre>
]]></description><link>https://community.m5stack.com/post/29498</link><guid isPermaLink="true">https://community.m5stack.com/post/29498</guid><dc:creator><![CDATA[terpasaurus]]></dc:creator><pubDate>Tue, 15 Jul 2025 13:20:26 GMT</pubDate></item><item><title><![CDATA[Reply to Core S3 I2C Issue: SCL is held low on the bus on Tue, 15 Jul 2025 07:44:11 GMT]]></title><description><![CDATA[<p dir="auto">It sounds like the SCL line on GPIO1 is stuck low, causing the bus to hang. Since your internal I2C on GPIO11/12 works fine, this suggests a hardware issue on Port A or interference on those pins. Double-check for any accidental shorts, damaged cables, or faulty devices connected to Port A. Also, try disconnecting all devices from Port A and test again. If the problem persists, it might be a hardware fault on the Core S3 board’s GPIO1 pin. Consider testing with a different device or contacting M5Stack support for hardware diagnostics.</p>
]]></description><link>https://community.m5stack.com/post/29494</link><guid isPermaLink="true">https://community.m5stack.com/post/29494</guid><dc:creator><![CDATA[hacxx]]></dc:creator><pubDate>Tue, 15 Jul 2025 07:44:11 GMT</pubDate></item><item><title><![CDATA[Reply to Core S3 I2C Issue: SCL is held low on the bus on Tue, 15 Jul 2025 03:51:55 GMT]]></title><description><![CDATA[<p dir="auto">For the person who finds this later from a web search, I figured out an explanation. By default, the pins for the external I2C bus (GPIO1 and GPIO2) are not put into a usable power state. As the error message above states, the SDA pin has a low power signal being held which prevents other things from using this bus to communicate.</p>
<p dir="auto">The simplest way for me to ensure the pins (and other things) are initialized is to import the <code>m5stack/M5Unified</code> library from PlatformIO, and the external component <code>board_m5cores3</code> from <a href="https://github.com/m5stack/M5CoreS3-Esphome" target="_blank" rel="noopener noreferrer nofollow ugc">https://github.com/m5stack/M5CoreS3-Esphome</a>, then declare <code>board_m5cores3:</code> in the ESPHome YAML config:</p>
<pre><code class="language-yaml">esphome:
  name: ${hostname}
  friendly_name: ${friendlyname}
  platformio_options:
    board_build.flash_mode: dio
    board_build.mcu: esp32s3
    board_build.f_cpu: 240000000L
  libraries:
    - m5stack/M5Unified

external_components:
  - source:
      type: git
      url: https://github.com/m5stack/M5CoreS3-Esphome
    refresh: 0s
    components: [board_m5cores3]

board_m5cores3:
</code></pre>
<p dir="auto">This results in <code>M5.begin()</code> being called. The <code>M5</code> namespace on which it's calling <code>begin()</code>  is provided by the <code>m5stack/M5Unified</code> C++ library. This ensures physical buttons and hardware are initialized properly for this particular board.</p>
<p dir="auto">The <code>begin</code> method <a href="https://github.com/m5stack/M5Unified/blob/bf322a062657aae49b2a93e2ca87351769f7b440/src/M5Unified.hpp#L325-L346" target="_blank" rel="noopener noreferrer nofollow ugc">is defined here</a>. On L349-343:</p>
<pre><code class="language-cpp">auto board = _check_boardtype(Display.getBoard());
if (board == board_t::board_unknown) { board = cfg.fallback_board; }
_board = board;
_setup_pinmap(board);
_setup_i2c(board);
</code></pre>
<p dir="auto">That call <code>_setup_i2c</code> is <a href="https://github.com/m5stack/M5Unified/blob/bf322a062657aae49b2a93e2ca87351769f7b440/src/utility/I2C_Class.hpp#L17-L33" target="_blank" rel="noopener noreferrer nofollow ugc">calling this</a> and <a href="https://github.com/m5stack/M5Unified/blob/bf322a062657aae49b2a93e2ca87351769f7b440/src/utility/I2C_Class.cpp#L13-L25" target="_blank" rel="noopener noreferrer nofollow ugc">this from deeper within</a> the M5Unified's I2C library. That seems to cause SDA to not be held in LOW state.</p>
]]></description><link>https://community.m5stack.com/post/29491</link><guid isPermaLink="true">https://community.m5stack.com/post/29491</guid><dc:creator><![CDATA[terpasaurus]]></dc:creator><pubDate>Tue, 15 Jul 2025 03:51:55 GMT</pubDate></item></channel></rss>