M5UnitUnified 0.6.3 git rev:e38fc73
Loading...
Searching...
No Matches
adapter_i2c.hpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2024 M5Stack Technology CO LTD
3 *
4 * SPDX-License-Identifier: MIT
5 */
10#ifndef M5_UNIT_COMPONENT_ADAPTER_I2C_HPP
11#define M5_UNIT_COMPONENT_ADAPTER_I2C_HPP
12
13#include "adapter_base.hpp"
14#include "pin.hpp"
15#if defined(ESP_PLATFORM) && __has_include(<driver/i2c_master.h>)
16#include <driver/i2c_master.h>
17#elif defined(ESP_PLATFORM)
18#include <driver/i2c.h>
19#endif
20#include <vector>
21
22class TwoWire;
23
24namespace m5 {
25class I2C_Class;
26namespace unit {
27
32class AdapterI2C : public Adapter {
33public:
35 enum class ImplType : uint8_t {
36 Unknown,
37 TwoWire,
38 Bus,
39 I2CClass,
40#if defined(ESP_PLATFORM) && __has_include(<driver/i2c_master.h>)
41 ESPIDFMasterBus,
42#elif defined(ESP_PLATFORM)
43 ESPIDFLegacyBus,
44#endif
45 };
46
47 class I2CImpl : public Adapter::Impl {
48 public:
49 I2CImpl() = default;
50 I2CImpl(const uint8_t addr, const uint32_t clock) : Adapter::Impl(), _addr(addr), _clock(clock)
51 {
52 }
53
54 virtual ~I2CImpl() = default;
55
56 inline uint8_t address() const
57 {
58 return _addr;
59 }
60 inline virtual void setAddress(const uint8_t addr)
61 {
62 _addr = addr;
63 }
64
65 inline uint32_t clock() const
66 {
67 return _clock;
68 }
69
70 inline virtual void setClock(const uint32_t clock)
71 {
72 _clock = clock;
73 }
74
75 //
77 virtual int16_t port() const
78 {
79 return -1;
80 }
81 virtual int16_t scl() const
82 {
83 return -1;
84 }
85 virtual int16_t sda() const
86 {
87 return -1;
88 }
89
90 //
91 virtual bool begin()
92 {
93 return false;
94 }
95 virtual bool end()
96 {
97 return false;
98 }
99 virtual m5::hal::error::error_t wakeup()
100 {
101 return m5::hal::error::error_t::UNKNOWN_ERROR;
102 }
103
104 //
105 virtual I2CImpl* duplicate(const uint8_t addr)
106 {
107 return new I2CImpl(addr, _clock);
108 }
109
111 virtual ImplType implType() const
112 {
113 return ImplType::Unknown;
114 }
115
116 virtual TwoWire* getWire()
117 {
118 return nullptr;
119 }
120 virtual m5::hal::bus::Bus* getBus()
121 {
122 return nullptr;
123 }
124 virtual m5::I2C_Class* getI2CClass()
125 {
126 return nullptr;
127 }
128
129 protected:
130 uint8_t _addr{};
131 uint32_t _clock{100 * 1000U};
132 };
133
134#if defined(ESP_PLATFORM) && __has_include(<driver/i2c_master.h>)
135 class ESPIDFMasterBusImpl : public I2CImpl {
136 public:
137 ESPIDFMasterBusImpl(i2c_master_bus_handle_t bus, const i2c_port_t port, const gpio_num_t sda,
138 const gpio_num_t scl, const uint8_t addr, const uint32_t clock);
139 inline virtual ImplType implType() const override
140 {
141 return ImplType::ESPIDFMasterBus;
142 }
143 inline virtual int16_t port() const override
144 {
145 return _port;
146 }
147 inline virtual int16_t scl() const override
148 {
149 return _scl;
150 }
151 inline virtual int16_t sda() const override
152 {
153 return _sda;
154 }
155 inline virtual void setAddress(const uint8_t addr) override
156 {
157 if (_addr != addr) {
158 end();
159 }
160 I2CImpl::setAddress(addr);
161 }
162 virtual void setClock(const uint32_t clock) override;
163 virtual bool begin() override;
164 virtual bool end() override;
165 virtual I2CImpl* duplicate(const uint8_t addr) override;
166 virtual m5::hal::error::error_t readWithTransaction(uint8_t* data, const size_t len) override;
167 virtual m5::hal::error::error_t writeWithTransaction(const uint8_t* data, const size_t len,
168 const uint32_t stop) override;
169 virtual m5::hal::error::error_t writeWithTransaction(const uint8_t reg, const uint8_t* data, const size_t len,
170 const uint32_t stop) override;
171 virtual m5::hal::error::error_t writeWithTransaction(const uint16_t reg, const uint8_t* data, const size_t len,
172 const uint32_t stop) override;
173 virtual m5::hal::error::error_t generalCall(const uint8_t* data, const size_t len) override;
174 virtual m5::hal::error::error_t wakeup() override;
175
176 protected:
177 m5::hal::error::error_t ensure_device();
178 m5::hal::error::error_t transmit(const uint8_t* data, const size_t len);
179 void set_pending_write(const uint8_t* data, const size_t len);
180
181 private:
182 i2c_master_bus_handle_t _bus{};
183 i2c_master_dev_handle_t _dev{};
184 std::vector<uint8_t> _pending_write{};
185 int16_t _port{-1}, _sda{-1}, _scl{-1};
186 };
187#elif defined(ESP_PLATFORM)
188 class ESPIDFLegacyBusImpl : public I2CImpl {
189 public:
190 ESPIDFLegacyBusImpl(const i2c_port_t port, const gpio_num_t sda, const gpio_num_t scl, const uint8_t addr,
191 const uint32_t clock);
192 inline virtual ImplType implType() const override
193 {
194 return ImplType::ESPIDFLegacyBus;
195 }
196 inline virtual int16_t port() const override
197 {
198 return _port;
199 }
200 inline virtual int16_t scl() const override
201 {
202 return _scl;
203 }
204 inline virtual int16_t sda() const override
205 {
206 return _sda;
207 }
208 inline virtual void setClock(const uint32_t clock) override
209 {
210 if (_clock != clock) {
211 I2CImpl::setClock(clock);
212 apply_clock();
213 }
214 }
215 virtual bool begin() override;
216 virtual bool end() override;
217 virtual I2CImpl* duplicate(const uint8_t addr) override;
218 virtual m5::hal::error::error_t readWithTransaction(uint8_t* data, const size_t len) override;
219 virtual m5::hal::error::error_t writeWithTransaction(const uint8_t* data, const size_t len,
220 const uint32_t stop) override;
221 virtual m5::hal::error::error_t writeWithTransaction(const uint8_t reg, const uint8_t* data, const size_t len,
222 const uint32_t stop) override;
223 virtual m5::hal::error::error_t writeWithTransaction(const uint16_t reg, const uint8_t* data, const size_t len,
224 const uint32_t stop) override;
225 virtual m5::hal::error::error_t generalCall(const uint8_t* data, const size_t len) override;
226 virtual m5::hal::error::error_t wakeup() override;
227
228 protected:
229 // Timing registers for this unit's clock, read back after i2c_param_config (high == 0: not readable)
230 struct timing_t {
231 int high{}, low{};
232 int start_setup{}, start_hold{};
233 int stop_setup{}, stop_hold{};
234 int sample{}, hold{};
235 int timeout{};
236 };
237
238 void apply_clock();
239 void restore_timing() const;
240 m5::hal::error::error_t result_of(const esp_err_t err);
241 m5::hal::error::error_t write_with_transaction(const uint8_t addr, const uint8_t* data, const size_t len,
242 const uint32_t stop);
243
244 private:
245 i2c_port_t _port{I2C_NUM_0};
246 int16_t _sda{-1}, _scl{-1};
247 timing_t _timing{};
248 };
249#endif
250
251 //
252#if defined(ARDUINO)
253 class WireImpl : public I2CImpl {
254 public:
255 WireImpl(TwoWire& wire, const uint8_t addr, const uint32_t clock);
256 inline virtual ImplType implType() const override
257 {
258 return ImplType::TwoWire;
259 }
260 inline virtual TwoWire* getWire() override
261 {
262 return _wire;
263 }
264 inline virtual int16_t port() const override
265 {
266 return _port;
267 }
268 inline virtual int16_t scl() const override
269 {
270 return _scl;
271 }
272 inline virtual int16_t sda() const override
273 {
274 return _sda;
275 }
276 virtual bool begin() override;
277 virtual bool end() override;
278 virtual m5::hal::error::error_t readWithTransaction(uint8_t* data, const size_t len) override;
279 virtual m5::hal::error::error_t writeWithTransaction(const uint8_t* data, const size_t len,
280 const uint32_t stop) override;
281 virtual m5::hal::error::error_t writeWithTransaction(const uint8_t reg, const uint8_t* data, const size_t len,
282 const uint32_t stop) override;
283 virtual m5::hal::error::error_t writeWithTransaction(const uint16_t reg, const uint8_t* data, const size_t len,
284 const uint32_t stop) override;
285 virtual I2CImpl* duplicate(const uint8_t addr) override;
286 virtual m5::hal::error::error_t generalCall(const uint8_t* data, const size_t len) override;
287 virtual m5::hal::error::error_t wakeup() override;
288
289 protected:
290 m5::hal::error::error_t write_with_transaction(const uint8_t addr, const uint8_t* data, const size_t len,
291 const uint32_t stop);
292
293 private:
294 TwoWire* _wire{};
295 int16_t _port{}, _sda{}, _scl{};
296 };
297#endif
298
299 class BusImpl : public I2CImpl {
300 public:
301 BusImpl(m5::hal::bus::Bus* bus, const uint8_t addr, const uint32_t clock);
302 inline virtual ImplType implType() const override
303 {
304 return ImplType::Bus;
305 }
306 inline virtual m5::hal::bus::Bus* getBus() override
307 {
308 return _bus;
309 }
310 inline virtual int16_t scl() const override
311 {
312 return _scl;
313 }
314 inline virtual int16_t sda() const override
315 {
316 return _sda;
317 }
318
319 inline virtual void setAddress(const uint8_t addr) override
320 {
321 I2CImpl::setAddress(addr);
322 _access_cfg.i2c_addr = addr;
323 }
324 inline virtual void setClock(const uint32_t clock) override
325 {
326 I2CImpl::setClock(clock);
327 _access_cfg.freq = clock;
328 }
329 virtual bool begin() override
330 {
331 return true;
332 }
333 virtual bool end() override
334 {
335 return true;
336 }
337 virtual I2CImpl* duplicate(const uint8_t addr) override;
338 virtual m5::hal::error::error_t readWithTransaction(uint8_t* data, const size_t len) override;
339 virtual m5::hal::error::error_t writeWithTransaction(const uint8_t* data, const size_t len,
340 const uint32_t stop) override;
341
342 virtual m5::hal::error::error_t writeWithTransaction(const uint8_t reg, const uint8_t* data, const size_t len,
343 const uint32_t stop) override;
344 virtual m5::hal::error::error_t writeWithTransaction(const uint16_t reg, const uint8_t* data, const size_t len,
345 const uint32_t stop) override;
346 virtual m5::hal::error::error_t generalCall(const uint8_t* data, const size_t len) override;
347 virtual m5::hal::error::error_t wakeup() override;
348
349 protected:
350 m5::hal::error::error_t write_with_transaction(const m5::hal::bus::I2CMasterAccessConfig& cfg,
351 const uint8_t* data, const size_t len, const uint32_t stop);
352
353 private:
354 m5::hal::bus::Bus* _bus{};
355 m5::hal::bus::I2CMasterAccessConfig _access_cfg{};
356 int16_t _sda{-1}, _scl{-1};
357 };
358
359 class I2CClassImpl : public I2CImpl {
360 public:
361 I2CClassImpl(m5::I2C_Class& i2c, const uint8_t addr, const uint32_t clock);
362 inline virtual ImplType implType() const override
363 {
364 return ImplType::I2CClass;
365 }
366 inline virtual m5::I2C_Class* getI2CClass() override
367 {
368 return _i2c;
369 }
370 inline virtual int16_t port() const override
371 {
372 return _port;
373 }
374 inline virtual int16_t scl() const override
375 {
376 return _scl;
377 }
378 inline virtual int16_t sda() const override
379 {
380 return _sda;
381 }
382 virtual bool begin() override;
383 virtual bool end() override;
384 virtual m5::hal::error::error_t readWithTransaction(uint8_t* data, const size_t len) override;
385 virtual m5::hal::error::error_t writeWithTransaction(const uint8_t* data, const size_t len,
386 const uint32_t stop) override;
387 virtual m5::hal::error::error_t writeWithTransaction(const uint8_t reg, const uint8_t* data, const size_t len,
388 const uint32_t stop) override;
389 virtual m5::hal::error::error_t writeWithTransaction(const uint16_t reg, const uint8_t* data, const size_t len,
390 const uint32_t stop) override;
391 virtual I2CImpl* duplicate(const uint8_t addr) override;
392 virtual m5::hal::error::error_t generalCall(const uint8_t* data, const size_t len) override;
393 virtual m5::hal::error::error_t wakeup() override;
394
395 private:
396 m5::I2C_Class* _i2c{};
397 int16_t _port{-1}, _sda{-1}, _scl{-1};
398 bool _in_transaction{false};
399 };
400
401#if defined(ARDUINO)
402 AdapterI2C(TwoWire& wire, uint8_t addr, const uint32_t clock);
403#endif
404 AdapterI2C(m5::hal::bus::Bus* bus, const uint8_t addr, const uint32_t clock);
405 AdapterI2C(m5::I2C_Class& i2c, const uint8_t addr, const uint32_t clock);
406#if defined(ESP_PLATFORM) && __has_include(<driver/i2c_master.h>)
407 AdapterI2C(i2c_master_bus_handle_t bus, const uint8_t addr, const uint32_t clock);
408 AdapterI2C(i2c_master_bus_handle_t bus, const i2c_port_t port, const gpio_num_t sda, const gpio_num_t scl,
409 const uint8_t addr, const uint32_t clock);
410#elif defined(ESP_PLATFORM)
411 AdapterI2C(const i2c_port_t port, const gpio_num_t sda, const gpio_num_t scl, const uint8_t addr,
412 const uint32_t clock);
413#endif
414 AdapterI2C(m5::hal::bus::Bus& bus, const uint8_t addr, const uint32_t clock) : AdapterI2C(&bus, addr, clock)
415 {
416 }
417
418 inline I2CImpl* impl()
419 {
420 return static_cast<I2CImpl*>(_impl.get());
421 }
422 inline const I2CImpl* impl() const
423 {
424 return static_cast<I2CImpl*>(_impl.get());
425 }
426
427 inline uint8_t address() const
428 {
429 return impl()->address();
430 }
431 inline void setAddress(const uint8_t addr)
432 {
433 impl()->setAddress(addr);
434 }
435
436 inline uint32_t clock() const
437 {
438 return impl()->clock();
439 }
440
441 inline void setClock(const uint32_t clock)
442 {
443 impl()->setClock(clock);
444 }
445
447 inline ImplType implType() const
448 {
449 return impl()->implType();
450 }
451
453 inline int16_t port() const
454 {
455 return impl()->port();
456 }
457 inline int16_t scl() const
458 {
459 return impl()->scl();
460 }
461 inline int16_t sda() const
462 {
463 return impl()->sda();
464 }
465
466 virtual Adapter* duplicate(const uint8_t addr) override;
467
472 inline bool begin()
473 {
474 return impl()->begin();
475 }
476 inline bool end()
477 {
478 return impl()->end();
479 }
480 bool pushPin();
481 bool popPin();
483
499 bool releasePins();
504 bool restorePins();
505
506protected:
507 AdapterI2C() : Adapter(Adapter::Type::I2C, new I2CImpl())
508 {
509 }
510
511protected:
512 gpio::pin_backup_t _backupSCL{-1}, _backupSDA{-1};
513};
514
515} // namespace unit
516} // namespace m5
517#endif
Adapter base.
Implementation base class (Pimpl pattern)
Definition adapter_base.hpp:37
Adapter()
Default constructor (creates Unknown type adapter)
Definition adapter_base.hpp:137
Type
Adapter type.
Definition adapter_base.hpp:28
Definition adapter_i2c.hpp:299
virtual ImplType implType() const override
Gets the implementation type.
Definition adapter_i2c.hpp:302
Definition adapter_i2c.hpp:359
virtual ImplType implType() const override
Gets the implementation type.
Definition adapter_i2c.hpp:362
virtual int16_t port() const override
I2C port number, or -1 if unknown.
Definition adapter_i2c.hpp:370
Definition adapter_i2c.hpp:47
virtual int16_t port() const
I2C port number, or -1 if unknown.
Definition adapter_i2c.hpp:77
virtual ImplType implType() const
Gets the implementation type.
Definition adapter_i2c.hpp:111
virtual Adapter * duplicate(const uint8_t addr) override
Create a duplicate adapter with a different address.
Definition adapter_i2c.cpp:1037
ImplType
I2C implementation type.
Definition adapter_i2c.hpp:35
@ I2CClass
m5::I2C_Class (m5gfx::i2c)
@ Bus
M5HAL Bus (including SoftwareI2C)
bool releasePins()
Detach SDA/SCL from the I2C controller and make them GPIO.
Definition adapter_i2c.cpp:1087
bool restorePins()
Reattach SDA/SCL to the I2C controller as they were before releasePins()
Definition adapter_i2c.cpp:1130
ImplType implType() const
Gets the I2C implementation type.
Definition adapter_i2c.hpp:447
int16_t port() const
I2C port number, or -1 if unknown (TwoWire, Bus, or a bus handle added without its port)
Definition adapter_i2c.hpp:453
Top level namespace of M5Stack.
Definition test_helper.hpp:20
Unit-related namespace.
PIN settings save/restore.