Micro template library A library for building device drivers
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

404 lines
12 KiB

  1. /*!
  2. * \file utl/com/i2c_bb.h
  3. * \brief A bit banking implementation of i2c bus inherited from
  4. * i2c_i base class.
  5. *
  6. * Copyright (C) 2018 Christos Choutouridis
  7. *
  8. * This program is free software: you can redistribute it and/or modify
  9. * it under the terms of the GNU Lesser General Public License as
  10. * published by the Free Software Foundation, either version 3
  11. * of the License, or (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU Lesser General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU Lesser General Public License
  19. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  20. *
  21. */
  22. #ifndef __utl_com_i2c_bb_h__
  23. #define __utl_com_i2c_bb_h__
  24. #include <utl/core/impl.h>
  25. #include <utl/core/crtp.h>
  26. #include <utl/com/i2c.h>
  27. namespace utl {
  28. /*!
  29. * \ingroup Communication
  30. * \brief A bit banking implementation of i2c bus
  31. * inherited from \ref i2c_i base class.
  32. * \sa i2c_i
  33. */
  34. //!@{
  35. /*!
  36. * \brief
  37. * I2C bit banking interface template class providing
  38. * an I2C using bit banking using CRTP.
  39. * \param impl_t The CRTP type (the derived/implementation class typename).
  40. */
  41. template <typename impl_t>
  42. class i2c_bb_i : public i2c_i<i2c_bb_i<impl_t>> {
  43. _CRTP_IMPL(impl_t);
  44. friend i2c_i<i2c_bb_i<impl_t>>;
  45. public:
  46. using type = i2c_bb_i<impl_t>; //!< Export type as identity meta-function
  47. using Sequence = typename i2c_i<type>::Sequence;
  48. //! SDA pin direction enumerator
  49. enum class SDAMode {
  50. INPUT =0,
  51. OUTPUT
  52. };
  53. /*!
  54. * \name Object lifetime
  55. */
  56. //!@{
  57. protected:
  58. //! \brief A default destructor, allow destructor from derived only
  59. ~i2c_bb_i () noexcept = default;
  60. //! \brief A default constructor
  61. i2c_bb_i (uint32_t clk) noexcept
  62. : usec_ {1000000/(2*clk)} { }
  63. //!@}
  64. /*!
  65. * \name Implementation requirements
  66. * \note
  67. * In order for the implementation to have the following as private members
  68. * it also need to declare this class as friend
  69. */
  70. //!@{
  71. private:
  72. /*!
  73. * Implementers's sda pin function
  74. * \param st In SDA_OUTPUT mode, selects the pin output state
  75. * \return In SDA_INPUT mode return the pin input state
  76. */
  77. bool SDA (SDAMode mode, bool st) { return impl().SDA (mode, st); }
  78. void SCL (uint8_t st) { impl().SCL (st); } //!< Implementers's scl pin function
  79. void delay (uint32_t usec) { impl().delay(usec); } //!< Implementers's usec delay function
  80. //!@}
  81. /*!
  82. * \name Implementation of base requirements
  83. */
  84. //!@{
  85. private:
  86. uint32_t _clock () const { return 1000000/(2*usec_); }
  87. void _clock (uint32_t c) { usec_ = 1000000/(2*c); }
  88. void _start (); //!< Send start functionality
  89. void _stop (); //!< Send stop functionality
  90. byte_t _rx_data (bool ack, Sequence seq);
  91. bool _tx_data (byte_t byte, Sequence seq);
  92. uint32_t usec_; //!< half period of I2C bus
  93. //!@}
  94. };
  95. /*
  96. * ============= User functions ================
  97. */
  98. /*!
  99. * \brief
  100. * Send a START bit to the bus
  101. * \return none
  102. */
  103. template <typename impl_t>
  104. void i2c_bb_i<impl_t>::_start (void) {
  105. //Initially set pins
  106. SDA (SDAMode::OUTPUT, 1);
  107. SCL (1);
  108. delay (usec_);
  109. SDA (SDAMode::OUTPUT, 0);
  110. delay (usec_);
  111. SCL (0); //Clear Clock
  112. }
  113. /*!
  114. * \brief
  115. * Send a START bit to the bus
  116. * \return none
  117. */
  118. template <typename impl_t>
  119. void i2c_bb_i<impl_t>::_stop (void) {
  120. //Stop bit Operation
  121. SDA (SDAMode::OUTPUT, 0);
  122. SCL (0);
  123. SCL (1);
  124. delay (usec_);
  125. SDA (SDAMode::OUTPUT, 1);
  126. delay (usec_);
  127. }
  128. /*!
  129. * \brief
  130. * Receive a byte from the i2c bus.
  131. * \param ack Optional ack bit.
  132. * \arg 1 ACK the reception
  133. * \arg 0 Don't ACK the reception.
  134. * \param seq The operation sequence to execute
  135. * \arg Sequence::BYTE Receive only the byte, do not send ack clock
  136. * \arg Sequence::ACK Send only the ack bit
  137. * \arg Sequence::BYTEnACK Receive the byte and send the ack bit
  138. * \return The byte received.
  139. */
  140. template <typename impl_t>
  141. byte_t i2c_bb_i<impl_t>::_rx_data (bool ack, Sequence seq) {
  142. byte_t byte {0};
  143. //Initial conditions
  144. SCL (0);
  145. SDA (SDAMode::INPUT, 0);
  146. if (seq == Sequence::BYTE || seq == Sequence::BYTEnACK) {
  147. // read 8 data bits
  148. for (int i=8 ; i!=0 ; --i) {
  149. byte <<= 1;
  150. SCL (1);
  151. delay (usec_);
  152. byte |= SDA (SDAMode::INPUT, 0);
  153. SCL (0);
  154. delay (usec_);
  155. }
  156. }
  157. if (seq == Sequence::ACK || seq == Sequence::BYTEnACK) {
  158. SDA (SDAMode::OUTPUT, !ack); //Send (or not) ACK bit
  159. SCL (1);
  160. delay (usec_);
  161. SCL (0); // Keep the bus busy
  162. SDA (SDAMode::OUTPUT, 0);
  163. }
  164. return byte;
  165. }
  166. /*!
  167. * \brief
  168. * Transmit a byte to the i2c bus.
  169. * \param byte The byte to send.
  170. * \param seq The operation sequence to execute
  171. * \arg Sequence::BYTE Transmit only the byte, do not read ack bit
  172. * \arg Sequence::ACK Read only the ack bit
  173. * \arg Sequence::BYTEnACK Transmit the byte and read the ack bit
  174. * \return Slave's ACK bit
  175. * \arg false Slave didn't ACK
  176. * \arg true Slave did ACK
  177. */
  178. template <typename impl_t>
  179. bool i2c_bb_i<impl_t>::_tx_data (byte_t byte, Sequence seq) {
  180. bool ack {false};
  181. //Initial conditions
  182. SCL (0);
  183. SDA (SDAMode::OUTPUT, 0);
  184. if (seq == Sequence::BYTE || seq == Sequence::BYTEnACK) {
  185. //Send 8 bit data
  186. for (int i=8 ; i!=0 ; --i) {
  187. //Send MSB
  188. SDA (SDAMode::OUTPUT, byte & 0x80);
  189. byte <<= 1;
  190. SCL (1);
  191. delay (usec_);
  192. SCL (0);
  193. delay (usec_);
  194. }
  195. }
  196. if (seq == Sequence::ACK || seq == Sequence::BYTEnACK) {
  197. // Get ACK
  198. SDA (SDAMode::INPUT, 0);
  199. SCL (1);
  200. delay (usec_);
  201. ack = !SDA (SDAMode::INPUT, 0);
  202. SCL (0); // Keep the bus busy
  203. delay (usec_);
  204. SDA (SDAMode::OUTPUT, 0);
  205. }
  206. return ack;
  207. }
  208. /*!
  209. * \brief
  210. * A virtual base class interface specialization.
  211. * Using the private virtual interface we provide the interface from
  212. * i2c_i<virtual_tag>
  213. * \param impl_t = virtual_tag
  214. */
  215. template<>
  216. class i2c_bb_i<virtual_tag> : public i2c_i<virtual_tag> {
  217. public:
  218. using type = i2c_bb_i<virtual_tag>; //!< Export type as identity meta-function
  219. using Sequence = typename i2c_i<virtual_tag>::Sequence;
  220. //! SDA pin direction enumerator
  221. enum class SDAMode {
  222. INPUT =0,
  223. OUTPUT
  224. };
  225. /*!
  226. * \name Object lifetime
  227. */
  228. //!@{
  229. protected:
  230. //! \brief Constructor
  231. i2c_bb_i (uint32_t clk) noexcept
  232. : usec_ {1000000/(2*clk)} { }
  233. //! \brief Virtual destructor
  234. virtual ~i2c_bb_i () noexcept = default;
  235. //!@}
  236. /*!
  237. * \name Implementation requirements
  238. */
  239. //!@{
  240. private:
  241. /*!
  242. * Implementers's sda pin function
  243. * \param st In SDA_OUTPUT mode, selects the pin output state
  244. * \return In SDA_INPUT mode return the pin input state
  245. */
  246. virtual bool SDA (SDAMode mode, bool st) =0;
  247. virtual void SCL (bool st) =0; //!< Implementers's scl pin function
  248. virtual void delay (uint32_t usec) =0; //!< Implementers's usec delay function
  249. //!@}
  250. /*!
  251. * \name Implementation of base requirements
  252. */
  253. //!@{
  254. private:
  255. uint32_t _clock () const final { return 1000000/(2*usec_); }
  256. void _clock (uint32_t c) final { usec_ = 1000000/(2*c); }
  257. void _start () final;
  258. void _stop () final;
  259. byte_t _rx_data (bool ack, Sequence seq) final;
  260. bool _tx_data (byte_t byte, Sequence seq) final;
  261. //! half period of I2C bus
  262. uint32_t usec_;
  263. //!@}
  264. };
  265. /*!
  266. * \brief
  267. * Send a START bit to the bus
  268. * \return none
  269. */
  270. void i2c_bb_i<virtual_tag>::_start (void) {
  271. //Initially set pins
  272. SDA (SDAMode::OUTPUT, 1);
  273. SCL (1);
  274. delay (usec_);
  275. SDA (SDAMode::OUTPUT, 0);
  276. delay (usec_);
  277. SCL (0); //Clear Clock
  278. }
  279. /*!
  280. * \brief
  281. * Send a START bit to the bus
  282. * \return none
  283. */
  284. void i2c_bb_i<virtual_tag>::_stop (void) {
  285. //Stop bit Operation
  286. SDA (SDAMode::OUTPUT, 0);
  287. SCL (0);
  288. SCL (1);
  289. delay (usec_);
  290. SDA (SDAMode::OUTPUT, 1);
  291. delay (usec_);
  292. }
  293. /*!
  294. * \brief
  295. * Receive a byte from the i2c bus.
  296. * \param ack Optional ack bit.
  297. * \arg 1 ACK the reception
  298. * \arg 0 Don't ACK the reception.
  299. * \param seq The operation sequence to execute
  300. * \arg Sequence::BYTE Receive only the byte, do not send ack clock
  301. * \arg Sequence::ACK Send only the ack bit
  302. * \arg Sequence::BYTEnACK Receive the byte and send the ack bit
  303. * \return The byte received.
  304. */
  305. byte_t i2c_bb_i<virtual_tag>::_rx_data (bool ack, Sequence seq) {
  306. byte_t byte {0};
  307. //Initial conditions
  308. SCL (0);
  309. SDA (SDAMode::INPUT, 0);
  310. if (seq == Sequence::BYTE || seq == Sequence::BYTEnACK) {
  311. // read 8 data bits
  312. for (int i=8 ; i!=0 ; --i) {
  313. byte <<= 1;
  314. SCL (1);
  315. delay (usec_);
  316. byte |= SDA (SDAMode::INPUT, 0);
  317. SCL (0);
  318. delay (usec_);
  319. }
  320. }
  321. if (seq == Sequence::ACK || seq == Sequence::BYTEnACK) {
  322. SDA (SDAMode::OUTPUT, !ack); //Send (or not) ACK bit
  323. SCL (1);
  324. delay (usec_);
  325. SCL (0); // Keep the bus busy
  326. SDA (SDAMode::OUTPUT, 0);
  327. }
  328. return byte;
  329. }
  330. /*!
  331. * \brief
  332. * Transmit a byte to the i2c bus.
  333. * \param byte The byte to send.
  334. * \param seq The operation sequence to execute
  335. * \arg Sequence::BYTE Transmit only the byte, do not read ack bit
  336. * \arg Sequence::ACK Read only the ack bit
  337. * \arg Sequence::BYTEnACK Transmit the byte and read the ack bit
  338. * \return Slave's ACK bit
  339. * \arg false Slave didn't ACK
  340. * \arg true Slave did ACK
  341. */
  342. bool i2c_bb_i<virtual_tag>::_tx_data (byte_t byte, Sequence seq) {
  343. bool ack {false};
  344. //Initial conditions
  345. SCL (0);
  346. SDA (SDAMode::OUTPUT, 0);
  347. if (seq == Sequence::BYTE || seq == Sequence::BYTEnACK) {
  348. //Send 8 bit data
  349. for (int i=8 ; i!=0 ; --i) {
  350. //Send MSB
  351. SDA (SDAMode::OUTPUT, byte & 0x80);
  352. byte <<= 1;
  353. SCL (1);
  354. delay (usec_);
  355. SCL (0);
  356. delay (usec_);
  357. }
  358. }
  359. if (seq == Sequence::ACK || seq == Sequence::BYTEnACK) {
  360. // Get ACK
  361. SDA (SDAMode::INPUT, 0);
  362. SCL (1);
  363. delay (usec_);
  364. ack = !SDA (SDAMode::INPUT, 0);
  365. SCL (0); // Keep the bus busy
  366. delay (usec_);
  367. SDA (SDAMode::OUTPUT, 0);
  368. }
  369. return ack;
  370. }
  371. //!@}
  372. } // namspace utl
  373. #endif // #ifndef __utl_com_i2c_bb_h__