Skip to content

Commit 3632ef0

Browse files
committed
Add I2C_Class adapter support for M5Unified internal I2C bus
1 parent f799507 commit 3632ef0

6 files changed

Lines changed: 280 additions & 0 deletions

File tree

src/M5UnitComponent.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,15 @@ bool Component::assign(TwoWire& wire)
150150
return false;
151151
}
152152

153+
bool Component::assign(m5::I2C_Class& i2c)
154+
{
155+
if (canAccessI2C() && _addr) {
156+
_adapter = std::make_shared<AdapterI2C>(i2c, _addr, _component_cfg.clock);
157+
return static_cast<bool>(_adapter);
158+
}
159+
return false;
160+
}
161+
153162
bool Component::assign(const int8_t rx_pin, const int8_t tx_pin)
154163
{
155164
if (canAccessGPIO()) {

src/M5UnitComponent.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ class SPIClass;
2525
struct SPISettings;
2626

2727
namespace m5 {
28+
class I2C_Class;
2829
namespace unit {
2930

3031
class UnitUnified;
@@ -226,6 +227,8 @@ class Component {
226227
virtual bool assign(m5::hal::bus::Bus* bus);
227228
/*! @brief Assgin TwoWire */
228229
virtual bool assign(TwoWire& wire);
230+
/*! @brief Assign I2C_Class */
231+
virtual bool assign(m5::I2C_Class& i2c);
229232
/*! @brief Assgin GPIO */
230233
virtual bool assign(const int8_t rx_pin, const int8_t tx_pin);
231234
/*! @brief Assgin UART */

src/M5UnitUnified.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,25 @@ bool UnitUnified::add(Component& u, TwoWire& wire)
5757
return false;
5858
}
5959

60+
bool UnitUnified::add(Component& u, m5::I2C_Class& i2c)
61+
{
62+
if (u.isRegistered()) {
63+
M5_LIB_LOGW("Already added");
64+
return false;
65+
}
66+
67+
M5_LIB_LOGD("Add [%s] addr:%02x children:%zu", u.deviceName(), u.address(), u.childrenSize());
68+
69+
u._manager = this;
70+
if (u.assign(i2c)) {
71+
u._order = ++_registerCount;
72+
_units.emplace_back(&u);
73+
return add_children(u);
74+
}
75+
M5_LIB_LOGE("Failed to assign %s:%u", u.deviceName(), u.canAccessI2C());
76+
return false;
77+
}
78+
6079
bool UnitUnified::add(Component& u, const int8_t rx_pin, const int8_t tx_pin)
6180
{
6281
if (u.isRegistered()) {

src/M5UnitUnified.hpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ struct SPISettings;
3535
@brief Top level namespace of M5stack
3636
*/
3737
namespace m5 {
38+
class I2C_Class;
3839
/*!
3940
@namespace unit
4041
@brief Unit-related namespace
@@ -104,6 +105,13 @@ class UnitUnified {
104105
@return True if successful
105106
*/
106107
bool add(Component& u, m5::hal::bus::Bus* bus);
108+
/*!
109+
@brief Adding unit to be managed (I2C_Class)
110+
@param u Unit Component
111+
@param i2c I2C_Class to be used (e.g. M5.In_I2C)
112+
@return True if successful
113+
*/
114+
bool add(Component& u, m5::I2C_Class& i2c);
107115
///@}
108116

109117
//! @brief Begin of all units under management

src/m5_unit_component/adapter_i2c.cpp

Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@
1717
#include <soc/gpio_struct.h>
1818
#include <soc/gpio_sig_map.h>
1919
#include <cassert>
20+
#if __has_include(<utility/I2C_Class.hpp>)
21+
#include <utility/I2C_Class.hpp>
22+
#define M5_UNITUNIFIED_ADAPTER_HAS_M5_I2C_CLASS
23+
#endif
2024

2125
#if defined(ARDUINO)
2226

@@ -325,6 +329,193 @@ m5::hal::error::error_t AdapterI2C::BusImpl::write_with_transaction(const m5::ha
325329
return m5::hal::error::error_t::INVALID_ARGUMENT;
326330
}
327331

332+
// Impl for I2C_Class
333+
#if defined(M5_UNITUNIFIED_ADAPTER_HAS_M5_I2C_CLASS)
334+
335+
AdapterI2C::I2CClassImpl::I2CClassImpl(m5::I2C_Class& i2c, const uint8_t addr, const uint32_t clock)
336+
: AdapterI2C::I2CImpl(addr, clock), _i2c(&i2c)
337+
{
338+
_sda = _i2c->getSDA();
339+
_scl = _i2c->getSCL();
340+
M5_LIB_LOGI("I2C_Class SDA:%d, SCL:%d", _sda, _scl);
341+
}
342+
343+
bool AdapterI2C::I2CClassImpl::begin()
344+
{
345+
return true; // Already initialized by M5Unified
346+
}
347+
348+
bool AdapterI2C::I2CClassImpl::end()
349+
{
350+
return true; // Managed by M5Unified
351+
}
352+
353+
m5::hal::error::error_t AdapterI2C::I2CClassImpl::readWithTransaction(uint8_t* data, const size_t len)
354+
{
355+
assert(_addr);
356+
if (!data) {
357+
return m5::hal::error::error_t::INVALID_ARGUMENT;
358+
}
359+
bool started = _in_transaction ? _i2c->restart(_addr, true, _clock) : _i2c->start(_addr, true, _clock);
360+
if (!started) {
361+
_in_transaction = false;
362+
return m5::hal::error::error_t::I2C_BUS_ERROR;
363+
}
364+
bool ok = _i2c->read(data, len, true);
365+
_i2c->stop();
366+
_in_transaction = false;
367+
return ok ? m5::hal::error::error_t::OK : m5::hal::error::error_t::I2C_BUS_ERROR;
368+
}
369+
370+
m5::hal::error::error_t AdapterI2C::I2CClassImpl::writeWithTransaction(const uint8_t* data, const size_t len,
371+
const uint32_t stop)
372+
{
373+
assert(_addr);
374+
bool started = _in_transaction ? _i2c->restart(_addr, false, _clock) : _i2c->start(_addr, false, _clock);
375+
if (!started) {
376+
_in_transaction = false;
377+
return m5::hal::error::error_t::I2C_BUS_ERROR;
378+
}
379+
bool ok = true;
380+
if (data && len) {
381+
ok = _i2c->write(data, len);
382+
}
383+
if (stop || !ok) {
384+
_i2c->stop();
385+
_in_transaction = false;
386+
} else {
387+
_in_transaction = true;
388+
}
389+
return ok ? m5::hal::error::error_t::OK : m5::hal::error::error_t::I2C_BUS_ERROR;
390+
}
391+
392+
m5::hal::error::error_t AdapterI2C::I2CClassImpl::writeWithTransaction(const uint8_t reg, const uint8_t* data,
393+
const size_t len, const uint32_t stop)
394+
{
395+
assert(_addr);
396+
bool started = _in_transaction ? _i2c->restart(_addr, false, _clock) : _i2c->start(_addr, false, _clock);
397+
if (!started) {
398+
_in_transaction = false;
399+
return m5::hal::error::error_t::I2C_BUS_ERROR;
400+
}
401+
bool ok = _i2c->write(reg);
402+
if (ok && data && len) {
403+
ok = _i2c->write(data, len);
404+
}
405+
if (stop || !ok) {
406+
_i2c->stop();
407+
_in_transaction = false;
408+
} else {
409+
_in_transaction = true;
410+
}
411+
return ok ? m5::hal::error::error_t::OK : m5::hal::error::error_t::I2C_BUS_ERROR;
412+
}
413+
414+
m5::hal::error::error_t AdapterI2C::I2CClassImpl::writeWithTransaction(const uint16_t reg, const uint8_t* data,
415+
const size_t len, const uint32_t stop)
416+
{
417+
assert(_addr);
418+
m5::types::big_uint16_t r(reg);
419+
bool started = _in_transaction ? _i2c->restart(_addr, false, _clock) : _i2c->start(_addr, false, _clock);
420+
if (!started) {
421+
_in_transaction = false;
422+
return m5::hal::error::error_t::I2C_BUS_ERROR;
423+
}
424+
bool ok = _i2c->write(r.data(), r.size());
425+
if (ok && data && len) {
426+
ok = _i2c->write(data, len);
427+
}
428+
if (stop || !ok) {
429+
_i2c->stop();
430+
_in_transaction = false;
431+
} else {
432+
_in_transaction = true;
433+
}
434+
return ok ? m5::hal::error::error_t::OK : m5::hal::error::error_t::I2C_BUS_ERROR;
435+
}
436+
437+
AdapterI2C::I2CImpl* AdapterI2C::I2CClassImpl::duplicate(const uint8_t addr)
438+
{
439+
return new I2CClassImpl(*_i2c, addr, _clock);
440+
}
441+
442+
m5::hal::error::error_t AdapterI2C::I2CClassImpl::generalCall(const uint8_t* data, const size_t len)
443+
{
444+
bool ok = _i2c->start(0x00, false, _clock);
445+
if (ok && data && len) {
446+
ok = _i2c->write(data, len);
447+
}
448+
_i2c->stop();
449+
_in_transaction = false;
450+
return ok ? m5::hal::error::error_t::OK : m5::hal::error::error_t::I2C_BUS_ERROR;
451+
}
452+
453+
m5::hal::error::error_t AdapterI2C::I2CClassImpl::wakeup()
454+
{
455+
bool ok = _i2c->start(_addr, false, _clock);
456+
_i2c->stop();
457+
_in_transaction = false;
458+
return ok ? m5::hal::error::error_t::OK : m5::hal::error::error_t::I2C_BUS_ERROR;
459+
}
460+
461+
#else
462+
// Stub when I2C_Class is not available
463+
AdapterI2C::I2CClassImpl::I2CClassImpl(m5::I2C_Class& i2c, const uint8_t addr, const uint32_t clock)
464+
: AdapterI2C::I2CImpl(addr, clock)
465+
{
466+
(void)i2c;
467+
M5_LIB_LOGE("I2C_Class not available");
468+
}
469+
470+
bool AdapterI2C::I2CClassImpl::begin()
471+
{
472+
return false;
473+
}
474+
475+
bool AdapterI2C::I2CClassImpl::end()
476+
{
477+
return false;
478+
}
479+
480+
m5::hal::error::error_t AdapterI2C::I2CClassImpl::readWithTransaction(uint8_t*, const size_t)
481+
{
482+
return m5::hal::error::error_t::UNKNOWN_ERROR;
483+
}
484+
485+
m5::hal::error::error_t AdapterI2C::I2CClassImpl::writeWithTransaction(const uint8_t*, const size_t, const uint32_t)
486+
{
487+
return m5::hal::error::error_t::UNKNOWN_ERROR;
488+
}
489+
490+
m5::hal::error::error_t AdapterI2C::I2CClassImpl::writeWithTransaction(const uint8_t, const uint8_t*, const size_t,
491+
const uint32_t)
492+
{
493+
return m5::hal::error::error_t::UNKNOWN_ERROR;
494+
}
495+
496+
m5::hal::error::error_t AdapterI2C::I2CClassImpl::writeWithTransaction(const uint16_t, const uint8_t*, const size_t,
497+
const uint32_t)
498+
{
499+
return m5::hal::error::error_t::UNKNOWN_ERROR;
500+
}
501+
502+
AdapterI2C::I2CImpl* AdapterI2C::I2CClassImpl::duplicate(const uint8_t addr)
503+
{
504+
return new I2CImpl(addr, _clock);
505+
}
506+
507+
m5::hal::error::error_t AdapterI2C::I2CClassImpl::generalCall(const uint8_t*, const size_t)
508+
{
509+
return m5::hal::error::error_t::UNKNOWN_ERROR;
510+
}
511+
512+
m5::hal::error::error_t AdapterI2C::I2CClassImpl::wakeup()
513+
{
514+
return m5::hal::error::error_t::UNKNOWN_ERROR;
515+
}
516+
517+
#endif
518+
328519
// Adapter
329520
#if defined(ARDUINO)
330521
AdapterI2C::AdapterI2C(TwoWire& wire, const uint8_t addr, const uint32_t clock)
@@ -351,6 +542,24 @@ AdapterI2C::AdapterI2C(m5::hal::bus::Bus* bus, const uint8_t addr, const uint32_
351542
assert(_impl);
352543
}
353544

545+
#if defined(M5_UNITUNIFIED_ADAPTER_HAS_M5_I2C_CLASS)
546+
AdapterI2C::AdapterI2C(m5::I2C_Class& i2c, const uint8_t addr, const uint32_t clock)
547+
: Adapter(Adapter::Type::I2C, new AdapterI2C::I2CClassImpl(i2c, addr, clock))
548+
{
549+
assert(_impl);
550+
}
551+
#else
552+
#pragma message "Not support I2C_Class"
553+
AdapterI2C::AdapterI2C(m5::I2C_Class& i2c, const uint8_t addr, const uint32_t clock) : Adapter()
554+
{
555+
(void)i2c;
556+
(void)addr;
557+
(void)clock;
558+
assert(_impl);
559+
M5_LIB_LOGE("Not support I2C_Class");
560+
}
561+
#endif
562+
354563
Adapter* AdapterI2C::duplicate(const uint8_t addr)
355564
{
356565
auto ptr = new AdapterI2C();

src/m5_unit_component/adapter_i2c.hpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
class TwoWire;
1717

1818
namespace m5 {
19+
class I2C_Class;
1920
namespace unit {
2021

2122
/*!
@@ -187,10 +188,41 @@ class AdapterI2C : public Adapter {
187188
int16_t _sda{-1}, _scl{-1};
188189
};
189190

191+
class I2CClassImpl : public I2CImpl {
192+
public:
193+
I2CClassImpl(m5::I2C_Class& i2c, const uint8_t addr, const uint32_t clock);
194+
inline virtual int16_t scl() const override
195+
{
196+
return _scl;
197+
}
198+
inline virtual int16_t sda() const override
199+
{
200+
return _sda;
201+
}
202+
virtual bool begin() override;
203+
virtual bool end() override;
204+
virtual m5::hal::error::error_t readWithTransaction(uint8_t* data, const size_t len) override;
205+
virtual m5::hal::error::error_t writeWithTransaction(const uint8_t* data, const size_t len,
206+
const uint32_t stop) override;
207+
virtual m5::hal::error::error_t writeWithTransaction(const uint8_t reg, const uint8_t* data, const size_t len,
208+
const uint32_t stop) override;
209+
virtual m5::hal::error::error_t writeWithTransaction(const uint16_t reg, const uint8_t* data, const size_t len,
210+
const uint32_t stop) override;
211+
virtual I2CImpl* duplicate(const uint8_t addr) override;
212+
virtual m5::hal::error::error_t generalCall(const uint8_t* data, const size_t len) override;
213+
virtual m5::hal::error::error_t wakeup() override;
214+
215+
private:
216+
m5::I2C_Class* _i2c{};
217+
int16_t _sda{-1}, _scl{-1};
218+
bool _in_transaction{false};
219+
};
220+
190221
#if defined(ARDUINO)
191222
AdapterI2C(TwoWire& wire, uint8_t addr, const uint32_t clock);
192223
#endif
193224
AdapterI2C(m5::hal::bus::Bus* bus, const uint8_t addr, const uint32_t clock);
225+
AdapterI2C(m5::I2C_Class& i2c, const uint8_t addr, const uint32_t clock);
194226
AdapterI2C(m5::hal::bus::Bus& bus, const uint8_t addr, const uint32_t clock) : AdapterI2C(&bus, addr, clock)
195227
{
196228
}

0 commit comments

Comments
 (0)