i2c_bb.h
Go to the documentation of this file.
#ifndef __utl_com_i2c_bb_h__
#define __utl_com_i2c_bb_h__
#include <utl/core/impl.h>
#include <utl/core/crtp.h>
#include <utl/com/i2c.h>
namespace utl {
template <typename impl_t>
class i2c_bb_i : public i2c_i<i2c_bb_i<impl_t>> {
_CRTP_IMPL(impl_t);
friend i2c_i<i2c_bb_i<impl_t>>;
public:
using type = i2c_bb_i<impl_t>;
using Sequence = typename i2c_i<type>::Sequence;
enum class SDAMode {
INPUT =0,
OUTPUT
};
protected:
~i2c_bb_i () noexcept = default;
i2c_bb_i (uint32_t clk) noexcept
: usec_ {1000000/(2*clk)} { }
private:
bool SDA (SDAMode mode, bool st) { return impl().SDA (mode, st); }
void SCL (uint8_t st) { impl().SCL (st); }
void delay (uint32_t usec) { impl().delay(usec); }
private:
uint32_t _clock () const { return 1000000/(2*usec_); }
void _clock (uint32_t c) { usec_ = 1000000/(2*c); }
void _start ();
void _stop ();
byte_t _rx_data (bool ack, Sequence seq);
bool _tx_data (byte_t byte, Sequence seq);
uint32_t usec_;
};
/*
* ============= User functions ================
*/
template <typename impl_t>
void i2c_bb_i<impl_t>::_start (void) {
//Initially set pins
SDA (SDAMode::OUTPUT, 1);
SCL (1);
delay (usec_);
SDA (SDAMode::OUTPUT, 0);
delay (usec_);
SCL (0); //Clear Clock
}
template <typename impl_t>
void i2c_bb_i<impl_t>::_stop (void) {
//Stop bit Operation
SDA (SDAMode::OUTPUT, 0);
SCL (0);
SCL (1);
delay (usec_);
SDA (SDAMode::OUTPUT, 1);
delay (usec_);
}
template <typename impl_t>
byte_t i2c_bb_i<impl_t>::_rx_data (bool ack, Sequence seq) {
byte_t byte {0};
//Initial conditions
SCL (0);
SDA (SDAMode::INPUT, 0);
if (seq == Sequence::BYTE || seq == Sequence::BYTEnACK) {
// read 8 data bits
for (int i=8 ; i!=0 ; --i) {
byte <<= 1;
SCL (1);
delay (usec_);
byte |= SDA (SDAMode::INPUT, 0);
SCL (0);
delay (usec_);
}
}
if (seq == Sequence::ACK || seq == Sequence::BYTEnACK) {
SDA (SDAMode::OUTPUT, !ack); //Send (or not) ACK bit
SCL (1);
delay (usec_);
SCL (0); // Keep the bus busy
SDA (SDAMode::OUTPUT, 0);
}
return byte;
}
template <typename impl_t>
bool i2c_bb_i<impl_t>::_tx_data (byte_t byte, Sequence seq) {
bool ack {false};
//Initial conditions
SCL (0);
SDA (SDAMode::OUTPUT, 0);
if (seq == Sequence::BYTE || seq == Sequence::BYTEnACK) {
//Send 8 bit data
for (int i=8 ; i!=0 ; --i) {
//Send MSB
SDA (SDAMode::OUTPUT, byte & 0x80);
byte <<= 1;
SCL (1);
delay (usec_);
SCL (0);
delay (usec_);
}
}
if (seq == Sequence::ACK || seq == Sequence::BYTEnACK) {
// Get ACK
SDA (SDAMode::INPUT, 0);
SCL (1);
delay (usec_);
ack = !SDA (SDAMode::INPUT, 0);
SCL (0); // Keep the bus busy
delay (usec_);
SDA (SDAMode::OUTPUT, 0);
}
return ack;
}
template<>
class i2c_bb_i<virtual_tag> : public i2c_i<virtual_tag> {
public:
using type = i2c_bb_i<virtual_tag>;
using Sequence = typename i2c_i<virtual_tag>::Sequence;
enum class SDAMode {
INPUT =0,
OUTPUT
};
protected:
i2c_bb_i (uint32_t clk) noexcept
: usec_ {1000000/(2*clk)} { }
virtual ~i2c_bb_i () noexcept = default;
private:
virtual bool SDA (SDAMode mode, bool st) =0;
virtual void SCL (bool st) =0;
virtual void delay (uint32_t usec) =0;
private:
uint32_t _clock () const final { return 1000000/(2*usec_); }
void _clock (uint32_t c) final { usec_ = 1000000/(2*c); }
void _start () final;
void _stop () final;
byte_t _rx_data (bool ack, Sequence seq) final;
bool _tx_data (byte_t byte, Sequence seq) final;
uint32_t usec_;
};
void i2c_bb_i<virtual_tag>::_start (void) {
//Initially set pins
SDA (SDAMode::OUTPUT, 1);
SCL (1);
delay (usec_);
SDA (SDAMode::OUTPUT, 0);
delay (usec_);
SCL (0); //Clear Clock
}
void i2c_bb_i<virtual_tag>::_stop (void) {
//Stop bit Operation
SDA (SDAMode::OUTPUT, 0);
SCL (0);
SCL (1);
delay (usec_);
SDA (SDAMode::OUTPUT, 1);
delay (usec_);
}
byte_t i2c_bb_i<virtual_tag>::_rx_data (bool ack, Sequence seq) {
byte_t byte {0};
//Initial conditions
SCL (0);
SDA (SDAMode::INPUT, 0);
if (seq == Sequence::BYTE || seq == Sequence::BYTEnACK) {
// read 8 data bits
for (int i=8 ; i!=0 ; --i) {
byte <<= 1;
SCL (1);
delay (usec_);
byte |= SDA (SDAMode::INPUT, 0);
SCL (0);
delay (usec_);
}
}
if (seq == Sequence::ACK || seq == Sequence::BYTEnACK) {
SDA (SDAMode::OUTPUT, !ack); //Send (or not) ACK bit
SCL (1);
delay (usec_);
SCL (0); // Keep the bus busy
SDA (SDAMode::OUTPUT, 0);
}
return byte;
}
bool i2c_bb_i<virtual_tag>::_tx_data (byte_t byte, Sequence seq) {
bool ack {false};
//Initial conditions
SCL (0);
SDA (SDAMode::OUTPUT, 0);
if (seq == Sequence::BYTE || seq == Sequence::BYTEnACK) {
//Send 8 bit data
for (int i=8 ; i!=0 ; --i) {
//Send MSB
SDA (SDAMode::OUTPUT, byte & 0x80);
byte <<= 1;
SCL (1);
delay (usec_);
SCL (0);
delay (usec_);
}
}
if (seq == Sequence::ACK || seq == Sequence::BYTEnACK) {
// Get ACK
SDA (SDAMode::INPUT, 0);
SCL (1);
delay (usec_);
ack = !SDA (SDAMode::INPUT, 0);
SCL (0); // Keep the bus busy
delay (usec_);
SDA (SDAMode::OUTPUT, 0);
}
return ack;
}
} // namspace utl
#endif // #ifndef __utl_com_i2c_bb_h__
utl::i2c_bb_i::Sequence
typename i2c_i< type >::Sequence Sequence
Definition: i2c_bb.h:53
utl::i2c_bb_i::usec_
uint32_t usec_
Definition: i2c_bb.h:102
utl::i2c_bb_i::SDAMode::OUTPUT
utl::i2c_bb_i::_start
void _start()
Send start functionality.
Definition: i2c_bb.h:115
utl::i2c_i
Abstract base class for i2c bus.
Definition: i2c.h:43
utl::i2c_bb_i::SDA
bool SDA(SDAMode mode, bool st)
Definition: i2c_bb.h:85
utl::i2c_bb_i< virtual_tag >::SDAMode
SDAMode
SDA pin direction enumerator.
Definition: i2c_bb.h:239
utl::i2c_bb_i::_CRTP_IMPL
_CRTP_IMPL(impl_t)
utl::i2c_i< virtual_tag >
A virtual base class specialization.
Definition: i2c.h:140
utl::i2c_bb_i::_rx_data
byte_t _rx_data(bool ack, Sequence seq)
Receive a byte from the i2c bus.
Definition: i2c_bb.h:154
crtp.h
utl::i2c_bb_i< virtual_tag >::_clock
void _clock(uint32_t c) final
set clock frequency of the bus [Hz]
Definition: i2c_bb.h:277
utl::i2c_bb_i::_clock
uint32_t _clock() const
Definition: i2c_bb.h:95
utl::i2c_bb_i::_stop
void _stop()
Send stop functionality.
Definition: i2c_bb.h:131
utl::i2c_bb_i::_tx_data
bool _tx_data(byte_t byte, Sequence seq)
Transmit a byte to the i2c bus.
Definition: i2c_bb.h:194
utl::i2c_bb_i::_clock
void _clock(uint32_t c)
Definition: i2c_bb.h:96
utl::i2c_bb_i::SDAMode
SDAMode
SDA pin direction enumerator.
Definition: i2c_bb.h:55
utl::i2c_bb_i::SDAMode::INPUT
utl
STL&#39;s core language concepts.
Definition: _1wire.h:30
utl::i2c_bb_i< virtual_tag >::i2c_bb_i
i2c_bb_i(uint32_t clk) noexcept
Constructor.
Definition: i2c_bb.h:250
utl::i2c_i::Sequence
Sequence
I2C transmit/receive sequence.
Definition: i2c.h:49
utl::i2c_bb_i< virtual_tag >
A virtual base class interface specialization. Using the private virtual interface we provide the int...
Definition: i2c_bb.h:234
utl::i2c_bb_i
A bit banking implementation of i2c bus inherited from i2c_i base class.
Definition: i2c_bb.h:47
utl::byte_t
uint8_t byte_t
8 bits wide
Definition: types.h:31
utl::virtual_tag
virtual support tag type
Definition: crtp.h:40
utl::i2c_bb_i::delay
void delay(uint32_t usec)
Definition: i2c_bb.h:87
utl::i2c_i< virtual_tag >::Sequence
Sequence
I2C transmit/receive sequence.
Definition: i2c.h:145
utl::i2c_bb_i::~i2c_bb_i
~i2c_bb_i() noexcept=default
A default destructor, allow destructor from derived only.
impl.h
Implementation detail main forward header.
utl::i2c_bb_i::SCL
void SCL(uint8_t st)
Implementers&#39;s scl pin function.
Definition: i2c_bb.h:86
i2c.h
An Abstract base class interface for the i2c bus.