Skip to content

Commit 27ac3e4

Browse files
committed
Add legacy I2C driver fallback to wiring helpers for IDF 5.0/5.1
1 parent c24d960 commit 27ac3e4

1 file changed

Lines changed: 57 additions & 0 deletions

File tree

src/wiring/m5_unit_unified_wiring.hpp

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,13 @@
3838
#include <SPI.h>
3939
#include <HardwareSerial.h>
4040
#else // ESP-IDF native
41+
// driver/i2c_master.h (new I2C master driver) exists only on IDF >= 5.2. On IDF 5.0/5.1 fall back to
42+
// the legacy driver/i2c.h so the I2C wiring helpers keep working across the whole IDF >= 5.0 range.
43+
#if __has_include(<driver/i2c_master.h>)
4144
#include <driver/i2c_master.h>
45+
#else
46+
#include <driver/i2c.h>
47+
#endif
4248
#include <driver/uart.h>
4349
#include <driver/spi_master.h>
4450
#include <hal/gpio_types.h>
@@ -571,10 +577,12 @@ constexpr size_t kUARTPortCacheSize = 4;
571577
constexpr size_t kSPIHostCacheSize = 2; // SPI2_HOST / SPI3_HOST
572578
constexpr size_t kSPIDevCacheSize = 4;
573579

580+
#if __has_include(<driver/i2c_master.h>)
574581
struct I2CCacheEntry {
575582
uint32_t key;
576583
i2c_master_bus_handle_t handle;
577584
};
585+
#endif
578586

579587
struct UARTCacheEntry {
580588
uint32_t key;
@@ -591,6 +599,7 @@ struct SPIDevEntry {
591599
spi_device_handle_t handle;
592600
};
593601

602+
#if __has_include(<driver/i2c_master.h>)
594603
//! @brief Get or create an I2C master bus, cached by {port, sda, scl}.
595604
inline i2c_master_bus_handle_t ensureI2CBus(const i2c_port_t port, const gpio_num_t sda, const gpio_num_t scl,
596605
const uint32_t /*clock - not used to key, single bus per pins*/)
@@ -629,6 +638,39 @@ inline i2c_master_bus_handle_t ensureI2CBus(const i2c_port_t port, const gpio_nu
629638
cache[count].key = key;
630639
return cache[count++].handle;
631640
}
641+
#else // legacy driver/i2c.h (IDF 5.0 / 5.1)
642+
//! @brief Install the legacy I2C master driver once per {port, sda, scl}; cached so re-adds are no-ops.
643+
inline bool ensureI2CLegacyDriver(const i2c_port_t port, const gpio_num_t sda, const gpio_num_t scl,
644+
const uint32_t clock)
645+
{
646+
const uint32_t key = (static_cast<uint32_t>(static_cast<uint8_t>(port)) << 24) |
647+
(static_cast<uint32_t>(static_cast<uint8_t>(sda)) << 16) |
648+
(static_cast<uint32_t>(static_cast<uint8_t>(scl)) << 8);
649+
static uint32_t cache[kI2CBusCacheSize]{};
650+
static size_t count{};
651+
for (size_t i = 0; i < count; ++i) {
652+
if (cache[i] == key) return true;
653+
}
654+
if (count >= kI2CBusCacheSize) {
655+
M5_LIB_LOGE("wiring: I2C bus cache full (max %zu)", kI2CBusCacheSize);
656+
return false;
657+
}
658+
i2c_config_t conf{};
659+
conf.mode = I2C_MODE_MASTER;
660+
conf.sda_io_num = sda;
661+
conf.scl_io_num = scl;
662+
conf.sda_pullup_en = true;
663+
conf.scl_pullup_en = true;
664+
conf.master.clk_speed = clock;
665+
if (i2c_param_config(port, &conf) != ESP_OK ||
666+
i2c_driver_install(port, I2C_MODE_MASTER, 0, 0, 0) != ESP_OK) {
667+
M5_LIB_LOGE("wiring: legacy i2c driver install failed port=%d sda=%d scl=%d", (int)port, (int)sda, (int)scl);
668+
return false;
669+
}
670+
cache[count++] = key;
671+
return true;
672+
}
673+
#endif
632674

633675
//! @brief Get or install a UART port, cached by {port, rx, tx}.
634676
inline uart_port_t ensureUARTPort(const uart_port_t port, const gpio_num_t rx, const gpio_num_t tx, const uint32_t baud,
@@ -727,15 +769,18 @@ inline spi_device_handle_t ensureSPIDevice(const spi_host_device_t host, const g
727769

728770
} // namespace detail
729771

772+
#if __has_include(<driver/i2c_master.h>)
730773
/*!
731774
@brief Get or create an I2C master bus handle (cached by {port, sda, scl})
732775
@note Intended for unit-specific wiring in M5Unit-* libraries; examples should use addI2C() instead.
776+
@note Available only on IDF >= 5.2 (new I2C master driver). On IDF 5.0/5.1 use addI2C() instead.
733777
*/
734778
inline i2c_master_bus_handle_t i2cBusHandle(const i2c_port_t port, const gpio_num_t sda, const gpio_num_t scl,
735779
const uint32_t clock = 100000)
736780
{
737781
return detail::ensureI2CBus(port, sda, scl, clock);
738782
}
783+
#endif
739784

740785
/*!
741786
@brief Get or install a UART port (cached by {port, rx, tx})
@@ -793,9 +838,16 @@ inline bool addI2C(UnitUnified& units, Component& unit, const uint32_t clock = 1
793838
return i2cClass(units, unit, M5.In_I2C);
794839
} else {
795840
// Core / Stick / S3 etc: M5Unified does not call Wire.begin(), so install ourselves
841+
#if __has_include(<driver/i2c_master.h>)
796842
auto bus = i2cBusHandle(I2C_NUM_0, (gpio_num_t)pins.sda, (gpio_num_t)pins.scl, clock);
797843
if (!bus) return false;
798844
return units.add(unit, bus);
845+
#else // legacy driver (IDF 5.0 / 5.1): install legacy driver, then add by port
846+
if (!detail::ensureI2CLegacyDriver(I2C_NUM_0, (gpio_num_t)pins.sda, (gpio_num_t)pins.scl, clock)) {
847+
return false;
848+
}
849+
return units.add(unit, I2C_NUM_0, (gpio_num_t)pins.sda, (gpio_num_t)pins.scl);
850+
#endif
799851
}
800852
case I2CPins::Backend::ExI2C:
801853
// NanoC6 / NanoH2: M5Unified manages Ex_I2C -> borrow
@@ -863,9 +915,14 @@ inline bool addHatI2C(UnitUnified& units, Component& unit, const uint32_t clock
863915
}
864916
M5_LIB_LOGI("wiring(ESP-IDF): addHatI2C port=%d sda=%d scl=%d clock=%u", (int)port, (int)p.sda, (int)p.scl,
865917
(unsigned)clock);
918+
#if __has_include(<driver/i2c_master.h>)
866919
auto bus = i2cBusHandle(port, (gpio_num_t)p.sda, (gpio_num_t)p.scl, clock);
867920
if (!bus) return false;
868921
return units.add(unit, bus);
922+
#else // legacy driver (IDF 5.0 / 5.1)
923+
if (!detail::ensureI2CLegacyDriver(port, (gpio_num_t)p.sda, (gpio_num_t)p.scl, clock)) return false;
924+
return units.add(unit, port, (gpio_num_t)p.sda, (gpio_num_t)p.scl);
925+
#endif
869926
}
870927

871928
//! @brief Add a unit on the board's Hat GPIO header (ESP-IDF native)

0 commit comments

Comments
 (0)