COSA
An Object-Oriented Platform for Arduino Programming
TWI.cpp
Go to the documentation of this file.
1 
21 #include "Cosa/TWI.hh"
22 
23 #if !defined(BOARD_ATTINY)
24 
25 #include "Cosa/Bits.h"
26 
27 TWI twi __attribute__ ((weak));
28 
29 #if defined(BOARD_ATMEGA32U4)
30 #define PORT PORTD
31 #else
32 #define PORT PORTC
33 #endif
34 
35 void
37 {
38  // Acquire the device driver. Wait is busy. Synchronized update
39  uint8_t key = lock(m_busy);
40 
41  // Set the current device driver
42  m_dev = dev;
43 
44  // Power up the module
45  powerup();
46 
47  // Enable internal pullup
48  bit_mask_set(PORT, _BV(Board::SDA) | _BV(Board::SCL));
49 
50  // Set clock prescale and bit rate
51  bit_mask_clear(TWSR, _BV(TWPS0) | _BV(TWPS1));
52  TWBR = m_freq;
53  TWCR = IDLE_CMD;
54  unlock(key);
55 }
56 
57 void
59 {
60  // Check if an asynchronious read/write was issued
61  if (UNLIKELY((m_dev == NULL) || (m_dev->is_async()))) return;
62 
63  // Put into idle state
64  synchronized {
65  m_dev = NULL;
66  m_busy = false;
67  TWCR = 0;
68  }
69 
70  // Power down the module
71  powerdown();
72 }
73 
74 bool
75 TWI::request(uint8_t op)
76 {
77  // Setup buffer pointers
78  m_state = ((op == READ_OP) ? MR_STATE : MT_STATE);
79  m_addr = (m_dev->m_addr | op);
80  m_status = NO_INFO;
81  m_next = (uint8_t*) m_vec[0].buf;
82  m_last = m_next + m_vec[0].size;
83  m_ix = 0;
84  m_count = 0;
85 
86  // And issue start command
87  TWCR = START_CMD;
88  return (true);
89 }
90 
91 bool
92 TWI::write_request(void* buf, size_t size)
93 {
94  iovec_t* vp = m_vec;
95  iovec_arg(vp, buf, size);
96  iovec_end(vp);
97  return (request(WRITE_OP));
98 }
99 
100 bool
101 TWI::write_request(uint8_t header, void* buf, size_t size)
102 {
103  iovec_t* vp = m_vec;
104  m_header[0] = header;
105  iovec_arg(vp, m_header, sizeof(header));
106  iovec_arg(vp, buf, size);
107  iovec_end(vp);
108  return (request(WRITE_OP));
109 }
110 
111 bool
112 TWI::write_request(uint16_t header, void* buf, size_t size)
113 {
114  iovec_t* vp = m_vec;
115  m_header[0] = (header >> 8);
116  m_header[1] = header;
117  iovec_arg(vp, m_header, sizeof(header));
118  iovec_arg(vp, buf, size);
119  iovec_end(vp);
120  return (request(WRITE_OP));
121 }
122 
123 bool
124 TWI::read_request(void* buf, size_t size)
125 {
126  iovec_t* vp = m_vec;
127  iovec_arg(vp, buf, size);
128  iovec_end(vp);
129  return (request(READ_OP));
130 }
131 
132 int
134 {
135  while (m_state > IDLE_STATE) yield();
136  return (m_count);
137 }
138 
139 void
140 TWI::isr_start(State state, uint8_t ix)
141 {
142  if (ix == NEXT_IX) {
143  m_ix += 1;
144  ix = m_ix;
145  }
146  else m_count = 0;
147  m_next = (uint8_t*) m_vec[ix].buf;
148  m_last = m_next + m_vec[ix].size;
149  m_state = state;
150 }
151 
152 void
153 TWI::isr_stop(State state, uint8_t type)
154 {
155  TWCR = TWI::STOP_CMD;
156  loop_until_bit_is_clear(TWCR, TWSTO);
157  if (UNLIKELY(state == TWI::ERROR_STATE)) m_count = -1;
158  m_state = state;
159 
160  // Check for asynchronous mode and call completion callback
161  if (m_dev->is_async() || m_status == SR_STOP) {
162  m_dev->on_completion(type, m_count);
163  m_dev = NULL;
164  m_busy = false;
165  TWCR = 0;
166  }
167 }
168 
169 bool
170 TWI::isr_write(Command cmd)
171 {
172  if (UNLIKELY(m_next == m_last)) return (false);
173  TWDR = *m_next++;
174  TWCR = cmd;
175  m_count += 1;
176  return (true);
177 }
178 
179 bool
180 TWI::isr_read(Command cmd)
181 {
182  if (UNLIKELY(m_next == m_last)) return (false);
183  *m_next++ = TWDR;
184  m_count += 1;
185  if (cmd != 0) TWCR = cmd;
186  return (true);
187 }
188 
190 {
191  twi.m_status = TWI_STATUS(TWSR);
192  switch (twi.m_status) {
196  case TWI::START:
197  case TWI::REP_START:
198  // Write device address
199  TWDR = twi.m_addr;
200  TWCR = TWI::DATA_CMD;
201  break;
202  case TWI::ARB_LOST:
203  // Lost arbitration
204  TWCR = TWI::IDLE_CMD;
205  twi.m_state = TWI::ERROR_STATE;
206  twi.m_count = -1;
207  break;
208 
212  case TWI::MT_SLA_ACK:
213  case TWI::MT_DATA_ACK:
214  if (twi.m_next == twi.m_last) twi.isr_start(TWI::MT_STATE, TWI::NEXT_IX);
215  if (twi.isr_write(TWI::DATA_CMD)) break;
216  case TWI::MT_DATA_NACK:
217  twi.isr_stop(TWI::IDLE_STATE, Event::WRITE_COMPLETED_TYPE);
218  break;
219  case TWI::MT_SLA_NACK:
220  twi.isr_stop(TWI::ERROR_STATE, Event::ERROR_TYPE);
221  break;
222 
226  case TWI::MR_DATA_ACK:
227  twi.isr_read();
228  case TWI::MR_SLA_ACK:
229  TWCR = (twi.m_next < (twi.m_last - 1)) ? TWI::ACK_CMD : TWI::NACK_CMD;
230  break;
231  case TWI::MR_DATA_NACK:
232  twi.isr_read();
233  twi.isr_stop(TWI::IDLE_STATE, Event::READ_COMPLETED_TYPE);
234  break;
235  case TWI::MR_SLA_NACK:
236  twi.isr_stop(TWI::ERROR_STATE, Event::ERROR_TYPE);
237  break;
238 
242  case TWI::ST_SLA_ACK:
243  case TWI::ST_ARB_LOST_SLA_ACK:
244  twi.isr_start(TWI::ST_STATE, TWI::Slave::READ_IX);
245  case TWI::ST_DATA_ACK:
246  if (twi.isr_write(TWI::ACK_CMD)) break;
247  TWCR = TWI::NACK_CMD;
248  break;
249  case TWI::ST_DATA_NACK:
250  case TWI::ST_LAST_DATA:
251  TWCR = TWI::ACK_CMD;
252  twi.m_state = TWI::IDLE_STATE;
253  break;
254 
258  case TWI::SR_SLA_ACK:
259  case TWI::SR_GCALL_ACK:
260  case TWI::SR_ARB_LOST_SLA_ACK:
261  case TWI::SR_ARB_LOST_GCALL_ACK:
262  twi.isr_start(TWI::SR_STATE, TWI::Slave::WRITE_IX);
263  TWCR = TWI::ACK_CMD;
264  break;
265  case TWI::SR_DATA_ACK:
266  case TWI::SR_GCALL_DATA_ACK:
267  if (twi.isr_read(TWI::ACK_CMD)) break;
268  case TWI::SR_DATA_NACK:
269  case TWI::SR_GCALL_DATA_NACK:
270  TWCR = TWI::NACK_CMD;
271  break;
272  case TWI::SR_STOP:
273  twi.isr_stop(TWI::IDLE_STATE, Event::WRITE_COMPLETED_TYPE);
274  TWAR = 0;
275  break;
276 
277  case TWI::NO_INFO:
278  break;
279 
280  case TWI::BUS_ERROR:
281  twi.isr_stop(TWI::ERROR_STATE);
282  break;
283 
284  default:
285  TWCR = TWI::IDLE_CMD;
286  }
287 }
288 
289 void
291 {
292  twi.m_dev = this;
293  synchronized {
294  TWAR = m_addr;
295  bit_mask_clear(TWSR, _BV(TWPS0) | _BV(TWPS1));
296  TWBR = ((F_CPU / TWI::DEFAULT_FREQ) - 16) / 2;
297  TWCR = TWI::IDLE_CMD;
298  }
299 }
300 
301 void
302 TWI::Slave::on_event(uint8_t type, uint16_t value)
303 {
304  if (UNLIKELY(type != Event::WRITE_COMPLETED_TYPE)) return;
305  void* buf = twi.m_vec[WRITE_IX].buf;
306  size_t size = value;
307  on_request(buf, size);
308  TWAR = twi.m_dev->m_addr;
309 }
310 
311 void
312 TWI::Slave::write_buf(void* buf, size_t size)
313 {
314  twi.m_vec[WRITE_IX].buf = buf;
315  twi.m_vec[WRITE_IX].size = size;
316 }
317 
318 void
319 TWI::Slave::read_buf(void* buf, size_t size)
320 {
321  twi.m_vec[READ_IX].buf = buf;
322  twi.m_vec[READ_IX].size = size;
323 }
324 
325 #endif
326 
327 
TWI twi
Definition: TWI.cpp:27
Definition: TWI.hh:51
void powerdown()
Definition: TWI.hh:362
#define bit_mask_clear(p, m)
Definition: Bits.h:30
#define NULL
Definition: Types.h:101
static const uint8_t READ_IX
Definition: TWI.hh:184
virtual void on_event(uint8_t type, uint16_t value)
Definition: TWI.cpp:302
Definition: Types.h:391
void write_buf(void *buf, size_t size)
Definition: TWI.cpp:312
#define TWI_STATUS(x)
Definition: TWI.hh:384
void release()
Definition: TWI.cpp:58
uint8_t lock()
Definition: Types.h:319
bool is_async() const
Definition: TWI.hh:78
uint8_t m_addr
Definition: TWI.hh:114
size_t size
Size of buffer in bytes.
Definition: Types.h:393
static const uint32_t DEFAULT_FREQ
Definition: TWI.hh:54
void(* yield)()
void begin()
Definition: TWI.cpp:290
void * buf
Buffer pointer.
Definition: Types.h:392
friend void TWI_vect(void)
void read_buf(void *buf, size_t size)
Definition: TWI.cpp:319
void acquire(TWI::Driver *dev)
Definition: TWI.cpp:36
void powerup()
Definition: TWI.hh:354
ISR(TWI_vect)
Definition: TWI.cpp:189
static const uint8_t WRITE_IX
Definition: TWI.hh:183
#define bit_mask_set(p, m)
Definition: Bits.h:29
void unlock(uint8_t key)
Definition: Types.h:331
virtual void on_completion(uint8_t type, int count)
Definition: TWI.hh:106
#define PORT
Definition: TWI.cpp:32
bool read_request(void *buf, size_t size)
Definition: TWI.cpp:124
#define UNLIKELY(x)
Definition: Types.h:153
bool write_request(void *buf, size_t size)
Definition: TWI.cpp:92
void iovec_arg(iovec_t *&vp, const void *buf, size_t size)
Definition: Types.h:430
void iovec_end(iovec_t *&vp)
Definition: Types.h:449
int await_completed()
Definition: TWI.cpp:133