uTL
micro Template library
i2c_bb.h
Go to the documentation of this file.
1 
22 #ifndef __utl_com_i2c_bb_h__
23 #define __utl_com_i2c_bb_h__
24 
25 #include <utl/core/impl.h>
26 #include <utl/core/crtp.h>
27 #include <utl/com/i2c.h>
28 
29 
30 namespace utl {
31 
38 
46  template <typename impl_t>
47  class i2c_bb_i : public i2c_i<i2c_bb_i<impl_t>> {
48  _CRTP_IMPL(impl_t);
50 
51  public:
53  using Sequence = typename i2c_i<type>::Sequence;
55  enum class SDAMode {
56  INPUT =0,
57  OUTPUT
58  };
59 
63  protected:
66  ~i2c_bb_i () noexcept = default;
68  i2c_bb_i (uint32_t clk) noexcept
69  : usec_ {1000000/(2*clk)} { }
71 
78  private:
85  bool SDA (SDAMode mode, bool st) { return impl().SDA (mode, st); }
86  void SCL (uint8_t st) { impl().SCL (st); }
87  void delay (uint32_t usec) { impl().delay(usec); }
88 
93  private:
95  uint32_t _clock () const { return 1000000/(2*usec_); }
96  void _clock (uint32_t c) { usec_ = 1000000/(2*c); }
97 
98  void _start ();
99  void _stop ();
100  byte_t _rx_data (bool ack, Sequence seq);
101  bool _tx_data (byte_t byte, Sequence seq);
102  uint32_t usec_;
103  };
105 
106  /*
107  * ============= User functions ================
108  */
114  template <typename impl_t>
116  //Initially set pins
117  SDA (SDAMode::OUTPUT, 1);
118  SCL (1);
119  delay (usec_);
120  SDA (SDAMode::OUTPUT, 0);
121  delay (usec_);
122  SCL (0); //Clear Clock
123  }
124 
130  template <typename impl_t>
132  //Stop bit Operation
133  SDA (SDAMode::OUTPUT, 0);
134  SCL (0);
135  SCL (1);
136  delay (usec_);
137  SDA (SDAMode::OUTPUT, 1);
138  delay (usec_);
139  }
140 
153  template <typename impl_t>
155  byte_t byte {0};
156  //Initial conditions
157  SCL (0);
158  SDA (SDAMode::INPUT, 0);
159 
160  if (seq == Sequence::BYTE || seq == Sequence::BYTEnACK) {
161  // read 8 data bits
162  for (int i=8 ; i!=0 ; --i) {
163  byte <<= 1;
164  SCL (1);
165  delay (usec_);
166  byte |= SDA (SDAMode::INPUT, 0);
167  SCL (0);
168  delay (usec_);
169  }
170  }
171  if (seq == Sequence::ACK || seq == Sequence::BYTEnACK) {
172  SDA (SDAMode::OUTPUT, !ack); //Send (or not) ACK bit
173  SCL (1);
174  delay (usec_);
175  SCL (0); // Keep the bus busy
176  SDA (SDAMode::OUTPUT, 0);
177  }
178  return byte;
179  }
180 
193  template <typename impl_t>
195  bool ack {false};
196  //Initial conditions
197  SCL (0);
198  SDA (SDAMode::OUTPUT, 0);
199 
200  if (seq == Sequence::BYTE || seq == Sequence::BYTEnACK) {
201  //Send 8 bit data
202  for (int i=8 ; i!=0 ; --i) {
203  //Send MSB
204  SDA (SDAMode::OUTPUT, byte & 0x80);
205  byte <<= 1;
206  SCL (1);
207  delay (usec_);
208  SCL (0);
209  delay (usec_);
210  }
211  }
212  if (seq == Sequence::ACK || seq == Sequence::BYTEnACK) {
213  // Get ACK
214  SDA (SDAMode::INPUT, 0);
215  SCL (1);
216  delay (usec_);
217  ack = !SDA (SDAMode::INPUT, 0);
218  SCL (0); // Keep the bus busy
219  delay (usec_);
220  SDA (SDAMode::OUTPUT, 0);
221  }
222  return ack;
223  }
224 
225 
233  template<>
234  class i2c_bb_i<virtual_tag> : public i2c_i<virtual_tag> {
235  public:
239  enum class SDAMode {
240  INPUT =0,
241  OUTPUT
242  };
243 
247  protected:
250  i2c_bb_i (uint32_t clk) noexcept
251  : usec_ {1000000/(2*clk)} { }
253  virtual ~i2c_bb_i () noexcept = default;
255 
259  private:
266  virtual bool SDA (SDAMode mode, bool st) =0;
267  virtual void SCL (bool st) =0;
268  virtual void delay (uint32_t usec) =0;
269 
274  private:
276  uint32_t _clock () const final { return 1000000/(2*usec_); }
277  void _clock (uint32_t c) final { usec_ = 1000000/(2*c); }
278 
279  void _start () final;
280  void _stop () final;
281  byte_t _rx_data (bool ack, Sequence seq) final;
282  bool _tx_data (byte_t byte, Sequence seq) final;
284  uint32_t usec_;
286  };
287 
293  void i2c_bb_i<virtual_tag>::_start (void) {
294  //Initially set pins
295  SDA (SDAMode::OUTPUT, 1);
296  SCL (1);
297  delay (usec_);
298  SDA (SDAMode::OUTPUT, 0);
299  delay (usec_);
300  SCL (0); //Clear Clock
301  }
302 
309  //Stop bit Operation
310  SDA (SDAMode::OUTPUT, 0);
311  SCL (0);
312  SCL (1);
313  delay (usec_);
314  SDA (SDAMode::OUTPUT, 1);
315  delay (usec_);
316  }
317 
331  byte_t byte {0};
332  //Initial conditions
333  SCL (0);
334  SDA (SDAMode::INPUT, 0);
335 
336  if (seq == Sequence::BYTE || seq == Sequence::BYTEnACK) {
337  // read 8 data bits
338  for (int i=8 ; i!=0 ; --i) {
339  byte <<= 1;
340  SCL (1);
341  delay (usec_);
342  byte |= SDA (SDAMode::INPUT, 0);
343  SCL (0);
344  delay (usec_);
345  }
346  }
347  if (seq == Sequence::ACK || seq == Sequence::BYTEnACK) {
348  SDA (SDAMode::OUTPUT, !ack); //Send (or not) ACK bit
349  SCL (1);
350  delay (usec_);
351  SCL (0); // Keep the bus busy
352  SDA (SDAMode::OUTPUT, 0);
353  }
354  return byte;
355  }
356 
370  bool ack {false};
371  //Initial conditions
372  SCL (0);
373  SDA (SDAMode::OUTPUT, 0);
374 
375  if (seq == Sequence::BYTE || seq == Sequence::BYTEnACK) {
376  //Send 8 bit data
377  for (int i=8 ; i!=0 ; --i) {
378  //Send MSB
379  SDA (SDAMode::OUTPUT, byte & 0x80);
380  byte <<= 1;
381  SCL (1);
382  delay (usec_);
383  SCL (0);
384  delay (usec_);
385  }
386  }
387  if (seq == Sequence::ACK || seq == Sequence::BYTEnACK) {
388  // Get ACK
389  SDA (SDAMode::INPUT, 0);
390  SCL (1);
391  delay (usec_);
392  ack = !SDA (SDAMode::INPUT, 0);
393  SCL (0); // Keep the bus busy
394  delay (usec_);
395  SDA (SDAMode::OUTPUT, 0);
396  }
397  return ack;
398  }
399 
401 } // namspace utl
402 
403 #endif // #ifndef __utl_com_i2c_bb_h__
typename i2c_i< type >::Sequence Sequence
Definition: i2c_bb.h:53
uint32_t usec_
Definition: i2c_bb.h:102
void _start()
Send start functionality.
Definition: i2c_bb.h:115
Abstract base class for i2c bus.
Definition: i2c.h:43
bool SDA(SDAMode mode, bool st)
Definition: i2c_bb.h:85
SDAMode
SDA pin direction enumerator.
Definition: i2c_bb.h:239
_CRTP_IMPL(impl_t)
A virtual base class specialization.
Definition: i2c.h:140
byte_t _rx_data(bool ack, Sequence seq)
Receive a byte from the i2c bus.
Definition: i2c_bb.h:154
void _clock(uint32_t c) final
set clock frequency of the bus [Hz]
Definition: i2c_bb.h:277
uint32_t _clock() const
Definition: i2c_bb.h:95
void _stop()
Send stop functionality.
Definition: i2c_bb.h:131
bool _tx_data(byte_t byte, Sequence seq)
Transmit a byte to the i2c bus.
Definition: i2c_bb.h:194
void _clock(uint32_t c)
Definition: i2c_bb.h:96
SDAMode
SDA pin direction enumerator.
Definition: i2c_bb.h:55
STL&#39;s core language concepts.
Definition: _1wire.h:30
i2c_bb_i(uint32_t clk) noexcept
Constructor.
Definition: i2c_bb.h:250
Sequence
I2C transmit/receive sequence.
Definition: i2c.h:49
A virtual base class interface specialization. Using the private virtual interface we provide the int...
Definition: i2c_bb.h:234
A bit banking implementation of i2c bus inherited from i2c_i base class.
Definition: i2c_bb.h:47
uint8_t byte_t
8 bits wide
Definition: types.h:31
virtual support tag type
Definition: crtp.h:40
void delay(uint32_t usec)
Definition: i2c_bb.h:87
Sequence
I2C transmit/receive sequence.
Definition: i2c.h:145
~i2c_bb_i() noexcept=default
A default destructor, allow destructor from derived only.
Implementation detail main forward header.
void SCL(uint8_t st)
Implementers&#39;s scl pin function.
Definition: i2c_bb.h:86
An Abstract base class interface for the i2c bus.