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.

251 lines
6.9KB

  1. // Copyright 2012 Olivier Gillet.
  2. //
  3. // Author: Olivier Gillet (ol.gillet@gmail.com)
  4. //
  5. // This program is free software: you can redistribute it and/or modify
  6. // it under the terms of the GNU General Public License as published by
  7. // the Free Software Foundation, either version 3 of the License, or
  8. // (at your option) any later version.
  9. // This program is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU General Public License for more details.
  13. // You should have received a copy of the GNU General Public License
  14. // along with this program. If not, see <http://www.gnu.org/licenses/>.
  15. #ifndef AVRLIBX_IO_TWI_H_
  16. #define AVRLIBX_IO_TWI_H_
  17. #include <avr/io.h>
  18. #include "avrlibx/avrlibx.h"
  19. #include "avrlibx/io/gpio.h"
  20. #include "avrlibx/io/ring_buffer.h"
  21. namespace avrlibx {
  22. template<typename Port> struct TwiWrapper { };
  23. #define WRAP_TWI(port) \
  24. template<> \
  25. struct TwiWrapper<Port ## port> { \
  26. static inline TWI_t& twi() { \
  27. return TWI ## port; \
  28. } \
  29. static inline TWI_MASTER_t& master() { \
  30. return twi().MASTER; \
  31. } \
  32. static inline TWI_SLAVE_t& slave() { \
  33. return twi().SLAVE; \
  34. } \
  35. static inline void Handler() { \
  36. if (handler_) { \
  37. (*handler_)(); \
  38. } \
  39. } \
  40. static inline void set_interrupt_handler(void (*handler)()) { \
  41. handler_ = handler; \
  42. } \
  43. static void (*handler_)(); \
  44. };
  45. enum TWIState {
  46. TWI_STATE_READY,
  47. TWI_STATE_TRANSMITTING,
  48. TWI_STATE_RECEIVING,
  49. };
  50. enum TWIError {
  51. TWI_ERROR_NONE = 0,
  52. TWI_ERROR_NO_ACK = 1,
  53. TWI_ERROR_ARBITRATION_LOST = 2,
  54. TWI_ERROR_BUS_ERROR = 3,
  55. TWI_ERROR_UNEXPECTED_STATE = 4
  56. };
  57. WRAP_TWI(C)
  58. WRAP_TWI(E)
  59. template<typename Port, uint8_t size = 16>
  60. class TwiOutputBufferSpecs {
  61. public:
  62. TwiOutputBufferSpecs() { }
  63. enum {
  64. buffer_size = size,
  65. data_size = 8
  66. };
  67. typedef uint8_t Value;
  68. };
  69. template<typename Port, uint8_t size = 16>
  70. class TwiInputBufferSpecs {
  71. public:
  72. TwiInputBufferSpecs() { }
  73. enum {
  74. buffer_size = size,
  75. data_size = 8
  76. };
  77. typedef uint8_t Value;
  78. };
  79. template<
  80. typename Port,
  81. uint32_t frequency = 100000, /* Hz */
  82. uint8_t input_buffer_size = 16,
  83. uint8_t output_buffer_size = 16,
  84. uint8_t int_level = 1>
  85. struct TwiMaster {
  86. typedef TwiWrapper<Port> Twi;
  87. static inline void Init() {
  88. Twi::set_interrupt_handler(&InterruptHandler);
  89. Twi::twi().CTRL = 0;
  90. Twi::master().BAUD = F_CPU / (2 * frequency) - 5;
  91. Twi::master().CTRLA = (int_level << 6) \
  92. | TWI_MASTER_RIEN_bm \
  93. | TWI_MASTER_WIEN_bm \
  94. | TWI_MASTER_ENABLE_bm;
  95. Twi::master().STATUS = TWI_MASTER_BUSSTATE_IDLE_gc;
  96. state_ = TWI_STATE_READY;
  97. }
  98. static uint8_t Wait() {
  99. while (state_ != TWI_STATE_READY) { }
  100. return error_;
  101. }
  102. static void Done() {
  103. Twi::master().CTRLA = 0;
  104. Twi::set_interrupt_handler(NULL);
  105. }
  106. static uint8_t Request(uint8_t address, uint8_t requested) {
  107. // Make sure that we don't request more than the buffer can hold.
  108. if (requested >= Input::writable()) {
  109. return 0;
  110. }
  111. if (state_ != TWI_STATE_READY) {
  112. return 0;
  113. }
  114. error_ = TWI_ERROR_NONE;
  115. state_ = TWI_STATE_RECEIVING;
  116. slarw_ = (address << 1) | 1;
  117. received_ = 0;
  118. requested_ = requested;
  119. Twi::master().ADDR = slarw_;
  120. return requested;
  121. }
  122. static uint8_t Send(uint8_t address) {
  123. if (!Output::readable()) {
  124. return 0;
  125. }
  126. if (state_ != TWI_STATE_READY) {
  127. return 0;
  128. }
  129. error_ = TWI_ERROR_NONE;
  130. state_ = TWI_STATE_TRANSMITTING;
  131. slarw_ = (address << 1) | 0;
  132. uint8_t sent = Output::readable();
  133. Twi::master().ADDR = slarw_;
  134. return sent;
  135. }
  136. // All the read/write operations are done on the buffer, so they do not
  137. // block.
  138. static inline void Write(uint8_t v) { Output::Write(v); }
  139. static inline uint8_t writable() { return Output::writable(); }
  140. static inline uint8_t NonBlockingWrite(uint8_t v) {
  141. return Output::NonBlockingWrite(v);
  142. }
  143. static inline void Overwrite(uint8_t v) { Output::Overwrite(v); }
  144. static inline uint8_t Read() { return Input::Read(); }
  145. static inline uint8_t readable() { return Input::readable(); }
  146. static inline int16_t NonBlockingRead() { return Input::NonBlockingRead(); }
  147. static inline uint8_t ImmediateRead() { return Input::ImmediateRead(); }
  148. static inline void FlushInputBuffer() { Input::Flush(); }
  149. static inline void FlushOutputBuffer() { Output::Flush(); }
  150. private:
  151. static void InterruptHandler() {
  152. uint8_t current_status = Twi::master().STATUS;
  153. if ((current_status & TWI_MASTER_ARBLOST_bm) ||
  154. (current_status & TWI_MASTER_BUSERR_bm)) {
  155. // Arbitration lost or bus error.
  156. error_ = current_status & TWI_MASTER_ARBLOST_bm
  157. ? TWI_ERROR_ARBITRATION_LOST
  158. : TWI_ERROR_BUS_ERROR;
  159. state_ = TWI_STATE_READY;
  160. } else if (current_status & TWI_MASTER_WIF_bm) {
  161. // Ready for write.
  162. // Check if slave has NACK'ed.
  163. if (current_status & TWI_MASTER_RXACK_bm) {
  164. error_ = TWI_ERROR_NO_ACK;
  165. state_ = TWI_STATE_READY;
  166. Twi::master().CTRLC = TWI_MASTER_CMD_STOP_gc;
  167. } else if (Output::readable()) {
  168. Twi::master().DATA = Output::ImmediateRead();
  169. } else if (received_ < requested_) {
  170. Twi::master().ADDR = slarw_;
  171. } else {
  172. Twi::master().CTRLC = TWI_MASTER_CMD_STOP_gc;
  173. state_ = TWI_STATE_READY;
  174. }
  175. } else if (current_status & TWI_MASTER_RIF_bm) {
  176. Input::Overwrite(Twi::master().DATA);
  177. ++received_;
  178. if (received_ < requested_) {
  179. Twi::master().CTRLC = TWI_MASTER_CMD_RECVTRANS_gc;
  180. } else {
  181. Twi::master().CTRLC = TWI_MASTER_ACKACT_bm | TWI_MASTER_CMD_STOP_gc;
  182. state_ = TWI_STATE_READY;
  183. }
  184. } else {
  185. error_ = TWI_ERROR_UNEXPECTED_STATE;
  186. state_ = TWI_STATE_READY;
  187. }
  188. }
  189. public:
  190. typedef RingBuffer<TwiInputBufferSpecs<Port, input_buffer_size> > Input;
  191. typedef RingBuffer<TwiOutputBufferSpecs<Port, output_buffer_size> > Output;
  192. private:
  193. static volatile uint8_t state_;
  194. static volatile uint8_t error_;
  195. static volatile uint8_t slarw_;
  196. static volatile uint8_t received_;
  197. static uint8_t requested_;
  198. DISALLOW_COPY_AND_ASSIGN(TwiMaster);
  199. };
  200. /* static */
  201. template<typename P, uint32_t f, uint8_t is, uint8_t os, uint8_t il>
  202. volatile uint8_t TwiMaster<P, f, is, os, il>::state_;
  203. /* static */
  204. template<typename P, uint32_t f, uint8_t is, uint8_t os, uint8_t il>
  205. volatile uint8_t TwiMaster<P, f, is, os, il>::error_;
  206. /* static */
  207. template<typename P, uint32_t f, uint8_t is, uint8_t os, uint8_t il>
  208. volatile uint8_t TwiMaster<P, f, is, os, il>::slarw_;
  209. /* static */
  210. template<typename P, uint32_t f, uint8_t is, uint8_t os, uint8_t il>
  211. volatile uint8_t TwiMaster<P, f, is, os, il>::received_;
  212. /* static */
  213. template<typename P, uint32_t f, uint8_t is, uint8_t os, uint8_t il>
  214. uint8_t TwiMaster<P, f, is, os, il>::requested_;
  215. } // namespace avrlibx
  216. #endif // AVRLIBX_IO_TWI_H_