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.
 
 
 
 

404 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/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__