Micro template library A library for building device drivers
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.
 
 
 
 

408 lignes
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/impl/impl.h>
  25. #include <utl/helper/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 frequency =100000) noexcept
  62. : usec_ {1000000/(2*frequency)} { }
  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. * bool SDA (SDAMode mode, bool st);
  70. * void SCL (uint8_t st);
  71. * void delay (uint32_t usec);
  72. */
  73. //!@{
  74. private:
  75. /*!
  76. * Implementers's sda pin function
  77. * \param st In SDA_OUTPUT mode, selects the pin output state
  78. * \return In SDA_INPUT mode return the pin input state
  79. */
  80. bool SDA (SDAMode mode, bool st) { return impl().SDA (mode, st); }
  81. void SCL (uint8_t st) { impl().SCL (st); } //!< Implementers's scl pin function
  82. void delay (uint32_t usec) { impl().delay(usec); } //!< Implementers's usec delay function
  83. //!@}
  84. /*!
  85. * \name Implementation of base requirements
  86. */
  87. //!@{
  88. private:
  89. uint32_t _frequency () const { return 1000000/(2*usec_); }
  90. void _frequency (uint32_t f) { usec_ = 1000000/(2*f); }
  91. void _start (); //!< Send start functionality
  92. void _stop (); //!< Send stop functionality
  93. byte_t _read (bool ack, Sequence seq);
  94. bool _write (byte_t byte, Sequence seq);
  95. uint32_t usec_; //!< half period of I2C nus
  96. //!@}
  97. };
  98. /*
  99. * ============= User functions ================
  100. */
  101. /*!
  102. * \brief
  103. * Send a START bit to the bus
  104. * \return none
  105. */
  106. template <typename impl_t>
  107. void i2c_bb_i<impl_t>::_start (void) {
  108. //Initially set pins
  109. SDA (SDAMode::OUTPUT, 1);
  110. SCL (1);
  111. delay (usec_);
  112. SDA (SDAMode::OUTPUT, 0);
  113. delay (usec_);
  114. SCL (0); //Clear Clock
  115. }
  116. /*!
  117. * \brief
  118. * Send a START bit to the bus
  119. * \return none
  120. */
  121. template <typename impl_t>
  122. void i2c_bb_i<impl_t>::_stop (void) {
  123. //Stop bit Operation
  124. SDA (SDAMode::OUTPUT, 0);
  125. SCL (0);
  126. SCL (1);
  127. delay (usec_);
  128. SDA (SDAMode::OUTPUT, 1);
  129. delay (usec_);
  130. }
  131. /*!
  132. * \brief
  133. * Receive a byte from the i2c bus.
  134. * \param ack Optional ack bit.
  135. * \arg 1 ACK the reception
  136. * \arg 0 Don't ACK the reception.
  137. * \param seq The operation sequence to execute
  138. * \arg Sequence::BYTE Receive only the byte, do not send ack clock
  139. * \arg Sequence::ACK Send only the ack bit
  140. * \arg Sequence::BYTEnACK Receive the byte and send the ack bit
  141. * \return The byte received.
  142. */
  143. template <typename impl_t>
  144. byte_t i2c_bb_i<impl_t>::_read (bool ack, Sequence seq) {
  145. byte_t byte {0};
  146. //Initial conditions
  147. SCL (0);
  148. SDA (SDAMode::INPUT, 0);
  149. if (seq == Sequence::BYTE || seq == Sequence::BYTEnACK) {
  150. // read 8 data bits
  151. for (int i=8 ; i!=0 ; --i) {
  152. byte <<= 1;
  153. SCL (1);
  154. delay (usec_);
  155. byte |= SDA (SDAMode::INPUT, 0);
  156. SCL (0);
  157. delay (usec_);
  158. }
  159. }
  160. if (seq == Sequence::ACK || seq == Sequence::BYTEnACK) {
  161. SDA (SDAMode::OUTPUT, !ack); //Send (or not) ACK bit
  162. SCL (1);
  163. delay (usec_);
  164. SCL (0); // Keep the bus busy
  165. SDA (SDAMode::OUTPUT, 0);
  166. }
  167. return byte;
  168. }
  169. /*!
  170. * \brief
  171. * Transmit a byte to the i2c bus.
  172. * \param byte The byte to send.
  173. * \param seq The operation sequence to execute
  174. * \arg Sequence::BYTE Transmit only the byte, do not read ack bit
  175. * \arg Sequence::ACK Read only the ack bit
  176. * \arg Sequence::BYTEnACK Transmit the byte and read the ack bit
  177. * \return Slave's ACK bit
  178. * \arg false Slave didn't ACK
  179. * \arg true Slave did ACK
  180. */
  181. template <typename impl_t>
  182. bool i2c_bb_i<impl_t>::_write (byte_t byte, Sequence seq) {
  183. bool ack {false};
  184. //Initial conditions
  185. SCL (0);
  186. SDA (SDAMode::OUTPUT, 0);
  187. if (seq == Sequence::BYTE || seq == Sequence::BYTEnACK) {
  188. //Send 8 bit data
  189. for (int i=8 ; i!=0 ; --i) {
  190. //Send MSB
  191. SDA (SDAMode::OUTPUT, byte & 0x80);
  192. byte <<= 1;
  193. SCL (1);
  194. delay (usec_);
  195. SCL (0);
  196. delay (usec_);
  197. }
  198. }
  199. if (seq == Sequence::ACK || seq == Sequence::BYTEnACK) {
  200. // Get ACK
  201. SDA (SDAMode::INPUT, 0);
  202. SCL (1);
  203. delay (usec_);
  204. ack = !SDA (SDAMode::INPUT, 0);
  205. SCL (0); // Keep the bus busy
  206. delay (usec_);
  207. SDA (SDAMode::OUTPUT, 0);
  208. }
  209. return ack;
  210. }
  211. /*!
  212. * \brief
  213. * A virtual base class interface specialization.
  214. * Using the private virtual interface we provide the interface from
  215. * i2c_i<virtual_tag>
  216. * \param impl_t = virtual_tag
  217. */
  218. template<>
  219. class i2c_bb_i<virtual_tag> : public i2c_i<virtual_tag> {
  220. public:
  221. using type = i2c_bb_i<virtual_tag>; //!< Export type as identity meta-function
  222. using Sequence = typename i2c_i<virtual_tag>::Sequence;
  223. //! SDA pin direction enumerator
  224. enum class SDAMode {
  225. INPUT =0,
  226. OUTPUT
  227. };
  228. /*!
  229. * \name Object lifetime
  230. */
  231. //!@{
  232. protected:
  233. //! \brief Constructor
  234. i2c_bb_i (uint32_t frequency =100000) noexcept
  235. : usec_ {1000000/(2*frequency)} { }
  236. //! \brief Virtual destructor
  237. virtual ~i2c_bb_i () noexcept = default;
  238. //!@}
  239. /*!
  240. * \name Implementation requirements
  241. */
  242. //!@{
  243. private:
  244. /*!
  245. * Implementers's sda pin function
  246. * \param st In SDA_OUTPUT mode, selects the pin output state
  247. * \return In SDA_INPUT mode return the pin input state
  248. */
  249. virtual bool SDA (SDAMode mode, bool st) =0;
  250. virtual void SCL (bool st) =0; //!< Implementers's scl pin function
  251. virtual void delay (uint32_t usec) =0; //!< Implementers's usec delay function
  252. //!@}
  253. /*!
  254. * \name Implementation of base requirements
  255. */
  256. //!@{
  257. private:
  258. uint32_t _frequency () const final { return 1000000/(2*usec_); }
  259. void _frequency (uint32_t f) final { usec_ = 1000000/(2*f); }
  260. void _start () final;
  261. void _stop () final;
  262. byte_t _read (bool ack, Sequence seq) final;
  263. bool _write (byte_t byte, Sequence seq) final;
  264. //!< half period of I2C bus
  265. uint32_t usec_;
  266. //!@}
  267. };
  268. /*!
  269. * \brief
  270. * Send a START bit to the bus
  271. * \return none
  272. */
  273. void i2c_bb_i<virtual_tag>::_start (void) {
  274. //Initially set pins
  275. SDA (SDAMode::OUTPUT, 1);
  276. SCL (1);
  277. delay (usec_);
  278. SDA (SDAMode::OUTPUT, 0);
  279. delay (usec_);
  280. SCL (0); //Clear Clock
  281. }
  282. /*!
  283. * \brief
  284. * Send a START bit to the bus
  285. * \return none
  286. */
  287. void i2c_bb_i<virtual_tag>::_stop (void) {
  288. //Stop bit Operation
  289. SDA (SDAMode::OUTPUT, 0);
  290. SCL (0);
  291. SCL (1);
  292. delay (usec_);
  293. SDA (SDAMode::OUTPUT, 1);
  294. delay (usec_);
  295. }
  296. /*!
  297. * \brief
  298. * Receive a byte from the i2c bus.
  299. * \param ack Optional ack bit.
  300. * \arg 1 ACK the reception
  301. * \arg 0 Don't ACK the reception.
  302. * \param seq The operation sequence to execute
  303. * \arg Sequence::BYTE Receive only the byte, do not send ack clock
  304. * \arg Sequence::ACK Send only the ack bit
  305. * \arg Sequence::BYTEnACK Receive the byte and send the ack bit
  306. * \return The byte received.
  307. */
  308. byte_t i2c_bb_i<virtual_tag>::_read (bool ack, Sequence seq) {
  309. byte_t byte {0};
  310. //Initial conditions
  311. SCL (0);
  312. SDA (SDAMode::INPUT, 0);
  313. if (seq == Sequence::BYTE || seq == Sequence::BYTEnACK) {
  314. // read 8 data bits
  315. for (int i=8 ; i!=0 ; --i) {
  316. byte <<= 1;
  317. SCL (1);
  318. delay (usec_);
  319. byte |= SDA (SDAMode::INPUT, 0);
  320. SCL (0);
  321. delay (usec_);
  322. }
  323. }
  324. if (seq == Sequence::ACK || seq == Sequence::BYTEnACK) {
  325. SDA (SDAMode::OUTPUT, !ack); //Send (or not) ACK bit
  326. SCL (1);
  327. delay (usec_);
  328. SCL (0); // Keep the bus busy
  329. SDA (SDAMode::OUTPUT, 0);
  330. }
  331. return byte;
  332. }
  333. /*!
  334. * \brief
  335. * Transmit a byte to the i2c bus.
  336. * \param byte The byte to send.
  337. * \param seq The operation sequence to execute
  338. * \arg Sequence::BYTE Transmit only the byte, do not read ack bit
  339. * \arg Sequence::ACK Read only the ack bit
  340. * \arg Sequence::BYTEnACK Transmit the byte and read the ack bit
  341. * \return Slave's ACK bit
  342. * \arg false Slave didn't ACK
  343. * \arg true Slave did ACK
  344. */
  345. bool i2c_bb_i<virtual_tag>::_write (byte_t byte, Sequence seq) {
  346. bool ack {false};
  347. //Initial conditions
  348. SCL (0);
  349. SDA (SDAMode::OUTPUT, 0);
  350. if (seq == Sequence::BYTE || seq == Sequence::BYTEnACK) {
  351. //Send 8 bit data
  352. for (int i=8 ; i!=0 ; --i) {
  353. //Send MSB
  354. SDA (SDAMode::OUTPUT, byte & 0x80);
  355. byte <<= 1;
  356. SCL (1);
  357. delay (usec_);
  358. SCL (0);
  359. delay (usec_);
  360. }
  361. }
  362. if (seq == Sequence::ACK || seq == Sequence::BYTEnACK) {
  363. // Get ACK
  364. SDA (SDAMode::INPUT, 0);
  365. SCL (1);
  366. delay (usec_);
  367. ack = !SDA (SDAMode::INPUT, 0);
  368. SCL (0); // Keep the bus busy
  369. delay (usec_);
  370. SDA (SDAMode::OUTPUT, 0);
  371. }
  372. return ack;
  373. }
  374. //!@}
  375. } // namspace utl
  376. #endif // #ifndef __utl_com_i2c_bb_h__