COSA
An Object-Oriented Platform for Arduino Programming
USI_TWI.cpp
Go to the documentation of this file.
1 
21 #include "Cosa/Board.hh"
22 #if defined(BOARD_ATTINY)
23 #include "Cosa/USI/TWI.hh"
24 
25 #if defined(USE_FAST_MODE)
26 // TWI timing constants (us) for fast mode (100-400 kHz)
27 #define T2 ((((I_CPU * 1300) / 10000) + 1) / 4)
28 #define T4 ((((I_CPU * 600) / 10000) + 1) / 4)
29 #else
30 // TWI timing constants (us) for standard mode (100 kHz)
31 #define T2 ((((I_CPU * 4700) / 10000) + 1) / 4)
32 #define T4 ((((I_CPU * 4000) / 10000) + 1) / 4)
33 #endif
34 
35 TWI twi __attribute__ ((weak));
36 
37 void
38 TWI::Slave::write_buf(void* buf, size_t size)
39 {
40  twi.m_vec[WRITE_IX].buf = buf;
41  twi.m_vec[WRITE_IX].size = size;
42 }
43 
44 void
45 TWI::Slave::read_buf(void* buf, size_t size)
46 {
47  twi.m_vec[READ_IX].buf = buf;
48  twi.m_vec[READ_IX].size = size;
49 }
50 
51 void
53 {
54  twi.m_dev = this;
55  twi.state(TWI::IDLE);
56  synchronized {
57  USICR = TWI::CR_START_MODE;
58  USISR = TWI::SR_CLEAR_ALL;
59  }
60 }
61 
63 {
64  if (twi.state() != TWI::IDLE) return;
65  twi.mode(IOPin::INPUT_MODE);
66  USICR = TWI::CR_TRANSFER_MODE;
67  USISR = TWI::SR_CLEAR_ALL;
68  twi.state(TWI::START_CHECK);
69 }
70 
72 {
73  switch (twi.state()) {
77  case TWI::START_CHECK:
78  {
79  uint8_t addr = USIDR;
80  if ((addr & TWI::ADDR_MASK) != twi.m_dev->m_addr) goto restart;
81  if (addr & TWI::READ_OP) {
82  twi.state(TWI::READ_REQUEST);
83  twi.buf(TWI::READ_IX);
84  }
85  else {
86  twi.state(TWI::WRITE_REQUEST);
87  twi.buf(TWI::WRITE_IX);
88  }
89  USIDR = 0;
90  twi.mode(IOPin::OUTPUT_MODE);
91  USISR = TWI::SR_CLEAR_ACK;
92  }
93  break;
94 
98  case TWI::ACK_CHECK:
99  if (USIDR) goto restart;
100 
101  case TWI::READ_REQUEST:
102  {
103  uint8_t data;
104  if (!twi.get(data)) goto restart;
105  USIDR = data;
106  twi.mode(IOPin::OUTPUT_MODE);
107  USISR = TWI::SR_CLEAR_DATA;
108  twi.state(TWI::READ_COMPLETED);
109  }
110  break;
111 
112  case TWI::READ_COMPLETED:
113  twi.mode(IOPin::INPUT_MODE);
114  USIDR = 0;
115  USISR = TWI::SR_CLEAR_ACK;
116  twi.state(TWI::ACK_CHECK);
117  break;
118 
122  case TWI::WRITE_REQUEST:
123  twi.mode(IOPin::INPUT_MODE);
124  USISR = TWI::SR_CLEAR_DATA;
125  twi.state(TWI::WRITE_COMPLETED);
126  DELAY(20);
127  if (USISR & _BV(USIPF)) {
128  USICR = TWI::CR_SERVICE_MODE;
129  USISR = TWI::SR_CLEAR_ALL;
131  twi.state(TWI::SERVICE_REQUEST);
132  }
133  break;
134 
135  case TWI::WRITE_COMPLETED:
136  {
137  uint8_t data = USIDR;
138  USIDR = (twi.put(data) ? 0x00 : 0x80);
139  twi.mode(IOPin::OUTPUT_MODE);
140  USISR = TWI::SR_CLEAR_ACK;
141  twi.state(TWI::WRITE_REQUEST);
142  }
143  break;
144 
145  restart:
146  default:
147  twi.mode(IOPin::INPUT_MODE);
148  USICR = TWI::CR_START_MODE;
149  USISR = TWI::SR_CLEAR_DATA;
150  twi.state(TWI::IDLE);
151  }
152 }
153 
154 void
155 TWI::Slave::on_event(uint8_t type, uint16_t value)
156 {
157  if (type != Event::WRITE_COMPLETED_TYPE) return;
158  void* buf = twi.m_vec[WRITE_IX].buf;
159  size_t size = value;
160  on_request(buf, size);
161  twi.state(IDLE);
162  synchronized {
163  USICR = TWI::CR_START_MODE;
164  USISR = TWI::SR_CLEAR_DATA;
165  }
166 }
167 
168 TWI::TWI() :
169  m_sda((Board::DigitalPin) Board::SDA, IOPin::INPUT_MODE, true),
170  m_scl((Board::DigitalPin) Board::SCL, IOPin::OUTPUT_MODE, true),
171  m_state(IDLE),
172  m_next(0),
173  m_last(0),
174  m_count(0),
175  m_dev(0),
176  m_busy(false)
177 {
178  for (uint8_t ix = 0; ix < VEC_MAX; ix++) {
179  m_vec[ix].buf = 0;
180  m_vec[ix].size = 0;
181  }
182 }
183 
184 bool
185 TWI::start()
186 {
187  // Release SCL to ensure that (repeated) start can be performed
188  m_scl.set();
189  while (!m_scl.is_set())
190  ;
191  DELAY(T4);
192 
193  // Generate the start condition
194  m_sda.clear();
195  DELAY(T4);
196  m_scl.clear();
197  m_sda.set();
198 
199  // Verify start condition
200  return ((USISR & _BV(USISIF)) != 0);
201 }
202 
203 uint8_t
204 TWI::transfer(uint8_t data, uint8_t bits)
205 {
206  // Setup data and number of bits to be clocked
207  uint8_t SR = SR_CLEAR_ALL;
208  if (bits == 1) SR |= (0x0E << USICNT0);
209  USIDR = data;
210  USISR = SR;
211 
212  // Clock bits onto the bus using software strobe
213  do {
214  DELAY(T2);
215  USICR = CR_DATA_MODE;
216  while (!m_scl.is_set())
217  ;
218  DELAY(T4);
219  USICR = CR_DATA_MODE;
220  } while (!(USISR & _BV(USIOIF)));
221  DELAY(T2);
222 
223  // Read received data and release bus
224  uint8_t res = USIDR;
225  USIDR = 0xff;
226  mode(IOPin::OUTPUT_MODE);
227  return (res);
228 }
229 
230 bool
231 TWI::stop()
232 {
233  // Release SCL and signal stop. Assume SCL/SDA are both output
234  m_sda.clear();
235  m_scl.set();
236  while (!m_scl.is_set())
237  ;
238  DELAY(T4);
239  m_sda.set();
240  DELAY(T2);
241 
242  // Verify stop condition
243  return ((USISR & _BV(USIPF)) != 0);
244 }
245 
246 int
247 TWI::request(uint8_t op)
248 {
249  bool is_read = (op & READ_OP);
250  uint8_t* next = (uint8_t*) m_vec[0].buf;
251  uint8_t* last = next + m_vec[0].size;
252  int count = 0;
253 
254  // Send start condition and write address
255  if (!start()) return (EFAULT);
256  m_scl.clear();
257  transfer(m_dev->m_addr | is_read);
258  mode(IOPin::INPUT_MODE);
259  if (transfer(0, 1)) goto nack;
260 
261  // Read or write data
262  for (uint8_t ix = 1; next != 0; ix++) {
263  while (next != last) {
264  count += 1;
265  if (is_read) {
266  mode(IOPin::INPUT_MODE);
267  *next++ = transfer(0);
268  transfer((next != last) ? 0x00 : 0xff, 1);
269  }
270  else {
271  m_scl.clear();
272  transfer(*next++);
273  mode(IOPin::INPUT_MODE);
274  if (transfer(0, 1)) goto nack;
275  }
276  }
277  next = (uint8_t*) m_vec[ix].buf;
278  last = next + m_vec[ix].size;
279  }
280 
281  nack:
282  if (!stop()) return (EFAULT);
283  return (count);
284 }
285 
286 void
288 {
289  // Acquire the device driver. Wait is busy. Synchronized update
290  uint8_t key = lock(m_busy);
291 
292  // Set the current device driver
293  m_dev = dev;
294 
295  // Power up the module
296  powerup();
297 
298  // Release level data and init mode
299  USIDR = 0xff;
300  USICR = CR_INIT_MODE;
301  USISR = SR_CLEAR_ALL;
302  mode(IOPin::OUTPUT_MODE);
303  unlock(key);
304 }
305 
306 void
307 TWI::release()
308 {
309  // Check if an asynchronious read/write was issued
310  if (UNLIKELY((m_dev == NULL) || (m_dev->is_async()))) return;
311 
312  // Put into idle state
313  synchronized {
314  m_dev = NULL;
315  m_busy = false;
316  USICR = 0;
317  }
318 
319  // Power down the module
320  powerdown();
321 }
322 
323 int
324 TWI::write(void* buf, size_t size)
325 {
326  iovec_t* vp = m_vec;
327  iovec_arg(vp, buf, size);
328  iovec_end(vp);
329  return (request(WRITE_OP));
330 }
331 
332 int
333 TWI::write(uint8_t header, void* buf, size_t size)
334 {
335  iovec_t* vp = m_vec;
336  m_header[0] = header;
337  iovec_arg(vp, m_header, sizeof(header));
338  iovec_arg(vp, buf, size);
339  iovec_end(vp);
340  return (request(WRITE_OP));
341 }
342 
343 int
344 TWI::write(uint16_t header, void* buf, size_t size)
345 {
346  iovec_t* vp = m_vec;
347  m_header[0] = (header >> 8);
348  m_header[1] = header;
349  iovec_arg(vp, m_header, sizeof(header));
350  iovec_arg(vp, buf, size);
351  iovec_end(vp);
352  return (request(WRITE_OP));
353 }
354 
355 int
356 TWI::read(void* buf, size_t size)
357 {
358  iovec_t* vp = m_vec;
359  iovec_arg(vp, buf, size);
360  iovec_end(vp);
361  return (request(READ_OP));
362 }
363 #endif
TWI()
Definition: TWI.hh:206
TWI twi
Definition: TWI.cpp:27
Definition: TWI.hh:51
void powerdown()
Definition: TWI.hh:362
void USI_START_vect(void)
#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
ISR(ANALOG_COMP_vect)
#define DELAY(us)
Definition: Types.h:280
void release()
Definition: TWI.cpp:58
uint8_t lock()
Definition: Types.h:319
bool is_async() const
Definition: TWI.hh:78
virtual void on_request(void *buf, size_t size)=0
uint8_t m_addr
Definition: TWI.hh:114
size_t size
Size of buffer in bytes.
Definition: Types.h:393
void USI_OVF_vect(void)
int read(void *buf, size_t size)
Definition: TWI.hh:326
void begin()
Definition: TWI.cpp:290
void * buf
Buffer pointer.
Definition: Types.h:392
void read_buf(void *buf, size_t size)
Definition: TWI.cpp:319
int write(void *buf, size_t size)
Definition: TWI.hh:282
Definition: IOPin.hh:29
void acquire(TWI::Driver *dev)
Definition: TWI.cpp:36
void powerup()
Definition: TWI.hh:354
static const uint8_t WRITE_IX
Definition: TWI.hh:183
void unlock(uint8_t key)
Definition: Types.h:331
virtual void on_completion(uint8_t type, int count)
Definition: TWI.hh:106
#define UNLIKELY(x)
Definition: Types.h:153
#define EFAULT
Definition: Errno.h:41
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