M5UnitUnified 0.5.5 git rev:bf711f3
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 //
76 virtual int16_t scl() const
77 {
78 return -1;
79 }
80 virtual int16_t sda() const
81 {
82 return -1;
83 }
84
85 //
86 virtual bool begin()
87 {
88 return false;
89 }
90 virtual bool end()
91 {
92 return false;
93 }
94 virtual m5::hal::error::error_t wakeup()
95 {
96 return m5::hal::error::error_t::UNKNOWN_ERROR;
97 }
98
99 //
100 virtual I2CImpl* duplicate(const uint8_t addr)
101 {
102 return new I2CImpl(addr, _clock);
103 }
104
106 virtual ImplType implType() const
107 {
108 return ImplType::Unknown;
109 }
110
111 virtual TwoWire* getWire()
112 {
113 return nullptr;
114 }
115 virtual m5::hal::bus::Bus* getBus()
116 {
117 return nullptr;
118 }
119 virtual m5::I2C_Class* getI2CClass()
120 {
121 return nullptr;
122 }
123
124 protected:
125 uint8_t _addr{};
126 uint32_t _clock{100 * 1000U};
127 };
128
129#if defined(ESP_PLATFORM) && __has_include(<driver/i2c_master.h>)
130 class ESPIDFMasterBusImpl : public I2CImpl {
131 public:
132 ESPIDFMasterBusImpl(i2c_master_bus_handle_t bus, const uint8_t addr, const uint32_t clock);
133 inline virtual ImplType implType() const override
134 {
135 return ImplType::ESPIDFMasterBus;
136 }
137 inline virtual void setAddress(const uint8_t addr) override
138 {
139 if (_addr != addr) {
140 end();
141 }
142 I2CImpl::setAddress(addr);
143 }
144 inline virtual void setClock(const uint32_t clock) override
145 {
146 if (_clock != clock) {
147 end();
148 }
149 I2CImpl::setClock(clock);
150 }
151 virtual bool begin() override;
152 virtual bool end() override;
153 virtual I2CImpl* duplicate(const uint8_t addr) override;
154 virtual m5::hal::error::error_t readWithTransaction(uint8_t* data, const size_t len) override;
155 virtual m5::hal::error::error_t writeWithTransaction(const uint8_t* data, const size_t len,
156 const uint32_t stop) override;
157 virtual m5::hal::error::error_t writeWithTransaction(const uint8_t reg, const uint8_t* data, const size_t len,
158 const uint32_t stop) override;
159 virtual m5::hal::error::error_t writeWithTransaction(const uint16_t reg, const uint8_t* data, const size_t len,
160 const uint32_t stop) override;
161 virtual m5::hal::error::error_t generalCall(const uint8_t* data, const size_t len) override;
162 virtual m5::hal::error::error_t wakeup() override;
163
164 protected:
165 m5::hal::error::error_t ensure_device();
166 m5::hal::error::error_t transmit(const uint8_t* data, const size_t len);
167 void set_pending_write(const uint8_t* data, const size_t len);
168
169 private:
170 i2c_master_bus_handle_t _bus{};
171 i2c_master_dev_handle_t _dev{};
172 std::vector<uint8_t> _pending_write{};
173 };
174#elif defined(ESP_PLATFORM)
175 class ESPIDFLegacyBusImpl : public I2CImpl {
176 public:
177 ESPIDFLegacyBusImpl(const i2c_port_t port, const gpio_num_t sda, const gpio_num_t scl, const uint8_t addr,
178 const uint32_t clock);
179 inline virtual ImplType implType() const override
180 {
181 return ImplType::ESPIDFLegacyBus;
182 }
183 inline virtual int16_t scl() const override
184 {
185 return _scl;
186 }
187 inline virtual int16_t sda() const override
188 {
189 return _sda;
190 }
191 inline virtual void setClock(const uint32_t clock) override
192 {
193 if (_clock != clock) {
194 I2CImpl::setClock(clock);
195 apply_clock();
196 }
197 }
198 virtual bool begin() override;
199 virtual bool end() override;
200 virtual I2CImpl* duplicate(const uint8_t addr) override;
201 virtual m5::hal::error::error_t readWithTransaction(uint8_t* data, const size_t len) override;
202 virtual m5::hal::error::error_t writeWithTransaction(const uint8_t* data, const size_t len,
203 const uint32_t stop) override;
204 virtual m5::hal::error::error_t writeWithTransaction(const uint8_t reg, const uint8_t* data, const size_t len,
205 const uint32_t stop) override;
206 virtual m5::hal::error::error_t writeWithTransaction(const uint16_t reg, const uint8_t* data, const size_t len,
207 const uint32_t stop) override;
208 virtual m5::hal::error::error_t generalCall(const uint8_t* data, const size_t len) override;
209 virtual m5::hal::error::error_t wakeup() override;
210
211 protected:
212 void apply_clock();
213 m5::hal::error::error_t write_with_transaction(const uint8_t addr, const uint8_t* data, const size_t len,
214 const uint32_t stop);
215
216 private:
217 i2c_port_t _port{I2C_NUM_0};
218 int16_t _sda{-1}, _scl{-1};
219 int _high{0}, _low{0};
220 };
221#endif
222
223 //
224#if defined(ARDUINO)
225 class WireImpl : public I2CImpl {
226 public:
227 WireImpl(TwoWire& wire, const uint8_t addr, const uint32_t clock);
228 inline virtual ImplType implType() const override
229 {
230 return ImplType::TwoWire;
231 }
232 inline virtual TwoWire* getWire() override
233 {
234 return _wire;
235 }
236 inline virtual int16_t scl() const override
237 {
238 return _scl;
239 }
240 inline virtual int16_t sda() const override
241 {
242 return _sda;
243 }
244 virtual bool begin() override;
245 virtual bool end() override;
246 virtual m5::hal::error::error_t readWithTransaction(uint8_t* data, const size_t len) override;
247 virtual m5::hal::error::error_t writeWithTransaction(const uint8_t* data, const size_t len,
248 const uint32_t stop) override;
249 virtual m5::hal::error::error_t writeWithTransaction(const uint8_t reg, const uint8_t* data, const size_t len,
250 const uint32_t stop) override;
251 virtual m5::hal::error::error_t writeWithTransaction(const uint16_t reg, const uint8_t* data, const size_t len,
252 const uint32_t stop) override;
253 virtual I2CImpl* duplicate(const uint8_t addr) override;
254 virtual m5::hal::error::error_t generalCall(const uint8_t* data, const size_t len) override;
255 virtual m5::hal::error::error_t wakeup() override;
256
257 protected:
258 m5::hal::error::error_t write_with_transaction(const uint8_t addr, const uint8_t* data, const size_t len,
259 const uint32_t stop);
260
261 private:
262 TwoWire* _wire{};
263 int16_t _sda{}, _scl{};
264 };
265#endif
266
267 class BusImpl : public I2CImpl {
268 public:
269 BusImpl(m5::hal::bus::Bus* bus, const uint8_t addr, const uint32_t clock);
270 inline virtual ImplType implType() const override
271 {
272 return ImplType::Bus;
273 }
274 inline virtual m5::hal::bus::Bus* getBus() override
275 {
276 return _bus;
277 }
278 inline virtual int16_t scl() const override
279 {
280 return _scl;
281 }
282 inline virtual int16_t sda() const override
283 {
284 return _sda;
285 }
286
287 inline virtual void setAddress(const uint8_t addr) override
288 {
289 I2CImpl::setAddress(addr);
290 _access_cfg.i2c_addr = addr;
291 }
292 inline virtual void setClock(const uint32_t clock) override
293 {
294 I2CImpl::setClock(clock);
295 _access_cfg.freq = clock;
296 }
297 virtual bool begin() override
298 {
299 return true;
300 }
301 virtual bool end() override
302 {
303 return true;
304 }
305 virtual I2CImpl* duplicate(const uint8_t addr) override;
306 virtual m5::hal::error::error_t readWithTransaction(uint8_t* data, const size_t len) override;
307 virtual m5::hal::error::error_t writeWithTransaction(const uint8_t* data, const size_t len,
308 const uint32_t stop) override;
309
310 virtual m5::hal::error::error_t writeWithTransaction(const uint8_t reg, const uint8_t* data, const size_t len,
311 const uint32_t stop) override;
312 virtual m5::hal::error::error_t writeWithTransaction(const uint16_t reg, const uint8_t* data, const size_t len,
313 const uint32_t stop) override;
314 virtual m5::hal::error::error_t generalCall(const uint8_t* data, const size_t len) override;
315 virtual m5::hal::error::error_t wakeup() override;
316
317 protected:
318 m5::hal::error::error_t write_with_transaction(const m5::hal::bus::I2CMasterAccessConfig& cfg,
319 const uint8_t* data, const size_t len, const uint32_t stop);
320
321 private:
322 m5::hal::bus::Bus* _bus{};
323 m5::hal::bus::I2CMasterAccessConfig _access_cfg{};
324 int16_t _sda{-1}, _scl{-1};
325 };
326
327 class I2CClassImpl : public I2CImpl {
328 public:
329 I2CClassImpl(m5::I2C_Class& i2c, const uint8_t addr, const uint32_t clock);
330 inline virtual ImplType implType() const override
331 {
332 return ImplType::I2CClass;
333 }
334 inline virtual m5::I2C_Class* getI2CClass() override
335 {
336 return _i2c;
337 }
338 inline virtual int16_t scl() const override
339 {
340 return _scl;
341 }
342 inline virtual int16_t sda() const override
343 {
344 return _sda;
345 }
346 virtual bool begin() override;
347 virtual bool end() override;
348 virtual m5::hal::error::error_t readWithTransaction(uint8_t* data, const size_t len) override;
349 virtual m5::hal::error::error_t writeWithTransaction(const uint8_t* data, const size_t len,
350 const uint32_t stop) override;
351 virtual m5::hal::error::error_t writeWithTransaction(const uint8_t reg, const uint8_t* data, const size_t len,
352 const uint32_t stop) override;
353 virtual m5::hal::error::error_t writeWithTransaction(const uint16_t reg, const uint8_t* data, const size_t len,
354 const uint32_t stop) override;
355 virtual I2CImpl* duplicate(const uint8_t addr) override;
356 virtual m5::hal::error::error_t generalCall(const uint8_t* data, const size_t len) override;
357 virtual m5::hal::error::error_t wakeup() override;
358
359 private:
360 m5::I2C_Class* _i2c{};
361 int16_t _sda{-1}, _scl{-1};
362 bool _in_transaction{false};
363 };
364
365#if defined(ARDUINO)
366 AdapterI2C(TwoWire& wire, uint8_t addr, const uint32_t clock);
367#endif
368 AdapterI2C(m5::hal::bus::Bus* bus, const uint8_t addr, const uint32_t clock);
369 AdapterI2C(m5::I2C_Class& i2c, const uint8_t addr, const uint32_t clock);
370#if defined(ESP_PLATFORM) && __has_include(<driver/i2c_master.h>)
371 AdapterI2C(i2c_master_bus_handle_t bus, const uint8_t addr, const uint32_t clock);
372#elif defined(ESP_PLATFORM)
373 AdapterI2C(const i2c_port_t port, const gpio_num_t sda, const gpio_num_t scl, const uint8_t addr,
374 const uint32_t clock);
375#endif
376 AdapterI2C(m5::hal::bus::Bus& bus, const uint8_t addr, const uint32_t clock) : AdapterI2C(&bus, addr, clock)
377 {
378 }
379
380 inline I2CImpl* impl()
381 {
382 return static_cast<I2CImpl*>(_impl.get());
383 }
384 inline const I2CImpl* impl() const
385 {
386 return static_cast<I2CImpl*>(_impl.get());
387 }
388
389 inline uint8_t address() const
390 {
391 return impl()->address();
392 }
393 inline void setAddress(const uint8_t addr)
394 {
395 impl()->setAddress(addr);
396 }
397
398 inline uint32_t clock() const
399 {
400 return impl()->clock();
401 }
402
403 inline void setClock(const uint32_t clock)
404 {
405 impl()->setClock(clock);
406 }
407
409 inline ImplType implType() const
410 {
411 return impl()->implType();
412 }
413
414 inline int16_t scl() const
415 {
416 return impl()->scl();
417 }
418 inline int16_t sda() const
419 {
420 return impl()->sda();
421 }
422
423 virtual Adapter* duplicate(const uint8_t addr) override;
424
429 inline bool begin()
430 {
431 return impl()->begin();
432 }
433 inline bool end()
434 {
435 return impl()->end();
436 }
437 bool pushPin();
438 bool popPin();
440
441protected:
442 AdapterI2C() : Adapter(Adapter::Type::I2C, new I2CImpl())
443 {
444 }
445
446protected:
447 gpio::pin_backup_t _backupSCL{-1}, _backupSDA{-1};
448};
449
450} // namespace unit
451} // namespace m5
452#endif
Adapter base.
Implementation base class (Pimpl pattern)
Definition adapter_base.hpp:37
Adapter()
Default constructor (creates Unknown type adapter)
Definition adapter_base.hpp:133
Type
Adapter type.
Definition adapter_base.hpp:28
Definition adapter_i2c.hpp:267
virtual ImplType implType() const override
Gets the implementation type.
Definition adapter_i2c.hpp:270
Definition adapter_i2c.hpp:327
virtual ImplType implType() const override
Gets the implementation type.
Definition adapter_i2c.hpp:330
Definition adapter_i2c.hpp:47
virtual ImplType implType() const
Gets the implementation type.
Definition adapter_i2c.hpp:106
virtual Adapter * duplicate(const uint8_t addr) override
Create a duplicate adapter with a different address.
Definition adapter_i2c.cpp:925
ImplType
I2C implementation type.
Definition adapter_i2c.hpp:35
@ I2CClass
m5::I2C_Class (m5gfx::i2c)
@ Bus
M5HAL Bus (including SoftwareI2C)
ImplType implType() const
Gets the I2C implementation type.
Definition adapter_i2c.hpp:409
Top level namespace of M5Stack.
Definition test_helper.hpp:20
Unit-related namespace.
PIN settings save/restore.