COSA
An Object-Oriented Platform for Arduino Programming
SPI.hh
Go to the documentation of this file.
1 
21 #ifndef COSA_SPI_HH
22 #define COSA_SPI_HH
23 
24 #include "Cosa/Types.h"
25 #include "Cosa/Bits.h"
26 #include "Cosa/OutputPin.hh"
27 #include "Cosa/Interrupt.hh"
28 #include "Cosa/Event.hh"
29 #include "Cosa/IOStream.hh"
30 
57 class SPI {
58 public:
60  enum Clock {
61  DIV2_CLOCK = 0x04,
62  DIV4_CLOCK = 0x00,
63  DIV8_CLOCK = 0x05,
64  DIV16_CLOCK = 0x01,
65  DIV32_CLOCK = 0x06,
66  DIV64_CLOCK = 0x02,
67  DIV128_CLOCK = 0x03,
69  } __attribute__((packed));
70 
72  enum Order {
73  MSB_ORDER = 0,
74  LSB_ORDER = 1,
76  } __attribute__((packed));
77 
79  enum Pulse {
80  ACTIVE_LOW = 0,
82  PULSE_LOW = 2,
83  PULSE_HIGH = 3,
85  } __attribute__((packed));
86 
93  class Driver {
94  public:
106  Pulse pulse = DEFAULT_PULSE,
107  Clock rate = DEFAULT_CLOCK,
108  uint8_t mode = 0,
109  Order order = MSB_ORDER,
110  Interrupt::Handler* irq = NULL);
111 
117  static Clock clock(uint32_t freq)
118  __attribute__((always_inline))
119  {
120  if (freq >= (F_CPU / 2)) return (SPI::DIV2_CLOCK);
121  if (freq >= (F_CPU / 4)) return (SPI::DIV4_CLOCK);
122  if (freq >= (F_CPU / 8)) return (SPI::DIV8_CLOCK);
123  if (freq >= (F_CPU / 16)) return (SPI::DIV16_CLOCK);
124  if (freq >= (F_CPU / 32)) return (SPI::DIV32_CLOCK);
125  if (freq >= (F_CPU / 64)) return (SPI::DIV64_CLOCK);
126  return (SPI::DIV128_CLOCK);
127  }
128 
135  static Clock cycle(uint16_t ns)
136  __attribute__((always_inline))
137  {
138  if (ns <= (1000000L / (F_CPU/2000L))) return (SPI::DIV2_CLOCK);
139  if (ns <= (1000000L / (F_CPU/4000L))) return (SPI::DIV4_CLOCK);
140  if (ns <= (1000000L / (F_CPU/8000L))) return (SPI::DIV8_CLOCK);
141  if (ns <= (1000000L / (F_CPU/16000L))) return (SPI::DIV16_CLOCK);
142  if (ns <= (1000000L / (F_CPU/32000L))) return (SPI::DIV32_CLOCK);
143  if (ns <= (1000000L / (F_CPU/64000L))) return (SPI::DIV64_CLOCK);
144  return (SPI::DIV128_CLOCK);
145  }
146 
151  void set_clock(Clock rate);
152 
157  void set_clock(uint32_t freq)
158  __attribute__((always_inline))
159  {
160  set_clock(clock(freq));
161  }
162 
163  protected:
168 #if defined(USICR)
169  const uint8_t m_cpol;
170  uint8_t m_usicr;
171  uint8_t m_data;
172 #else
173  uint8_t m_spcr;
174  uint8_t m_spsr;
175 #endif
176  friend class SPI;
177  };
178 
182  SPI();
183 
189  bool attach(Driver* dev);
190 
210  void acquire(Driver* dev);
211 
215  void release();
216 
232  void begin()
233  __attribute__((always_inline))
234  {
235  if (m_dev->m_pulse < PULSE_LOW) m_dev->m_cs.toggle();
236  }
237 
242  void end()
243  __attribute__((always_inline))
244  {
245  m_dev->m_cs.toggle();
246  if (m_dev->m_pulse > ACTIVE_HIGH) m_dev->m_cs.toggle();
247  }
248 
249 #if defined(USIDR)
250 
256  uint8_t transfer(uint8_t data)
257  __attribute__((always_inline))
258  {
259  USIDR = data;
260  USISR = _BV(USIOIF);
261  register uint8_t cntl = m_dev->m_usicr;
262  do {
263  USICR = cntl;
264  } while ((USISR & _BV(USIOIF)) == 0);
265  return (USIDR);
266  }
267 
273  void transfer_start(uint8_t data)
274  __attribute__((always_inline))
275  {
276  m_dev->m_data = data;
277  }
278 
284  uint8_t transfer_await()
285  __attribute__((always_inline))
286  {
287  return (transfer(m_dev->m_data));
288  }
289 
296  uint8_t transfer_next(uint8_t data)
297  __attribute__((always_inline))
298  {
299  uint8_t res = transfer_await();
300  transfer_start(data);
301  return (res);
302  }
303 
307  static void powerup()
308  {
309  power_usi_enable();
310  }
311 
315  static void powerdown()
316  {
317  power_usi_disable();
318  }
319 #else
320 
326  uint8_t transfer(uint8_t data)
327  __attribute__((always_inline))
328  {
329  SPDR = data;
330  loop_until_bit_is_set(SPSR, SPIF);
331  return (SPDR);
332  }
333 
339  void transfer_start(uint8_t data)
340  __attribute__((always_inline))
341  {
342  SPDR = data;
343  }
344 
350  uint8_t transfer_await()
351  __attribute__((always_inline))
352  {
353  loop_until_bit_is_set(SPSR, SPIF);
354  return (SPDR);
355  }
356 
363  uint8_t transfer_next(uint8_t data)
364  __attribute__((always_inline))
365  {
366  loop_until_bit_is_set(SPSR, SPIF);
367  uint8_t res = SPDR;
368  SPDR = data;
369  return (res);
370  }
371 
375  static void powerup()
376  {
377  power_spi_enable();
378  }
379 
383  static void powerdown()
384  {
385  power_spi_disable();
386  }
387 #endif
388 
396  void transfer(void* buf, size_t count);
397 
406  void transfer(void* dst, const void* src, size_t count);
407 
414  void read(void* buf, size_t count);
415 
422  void write(const void* buf, size_t count);
423 
430  void write_P(const void* buf, size_t count);
431 
437  void write(const iovec_t* vec)
438  __attribute__((always_inline))
439  {
440  for (const iovec_t* vp = vec; vp->buf != NULL; vp++)
441  write(vp->buf, vp->size);
442  }
443 
444 private:
445  Driver* m_list;
446  Driver* m_dev;
447  volatile bool m_busy;
448 };
449 
453 extern SPI spi;
454 
461 IOStream& operator<<(IOStream& outs, SPI::Clock rate);
462 
463 #endif
uint8_t m_spsr
SPI/SPSR hardware status register.
Definition: SPI.hh:174
static Clock cycle(uint16_t ns)
Definition: SPI.hh:135
Order
Definition: SPI.hh:72
IOStream & operator<<(IOStream &outs, SPI::Clock rate)
Definition: SPI.cpp:307
Pulse high on end of transaction.
Definition: SPI.hh:83
Clock
Definition: SPI.hh:60
Divide system clock by 4.
Definition: SPI.hh:62
Definition: Clock.hh:33
void acquire(Driver *dev)
Definition: SPI.cpp:255
uint8_t transfer_next(uint8_t data)
Definition: SPI.hh:363
Definition: SPI.hh:57
Interrupt::Handler * m_irq
Interrupt handler.
Definition: SPI.hh:165
Pulse
Definition: SPI.hh:79
void set_clock(Clock rate)
Definition: SPI.cpp:297
#define NULL
Definition: Types.h:101
Least significant bit first.
Definition: SPI.hh:74
Driver * m_next
List of drivers.
Definition: SPI.hh:164
Divide system clock by 128.
Definition: SPI.hh:67
Definition: Types.h:391
static void powerup()
Definition: SPI.hh:375
void release()
Definition: SPI.cpp:281
void set_clock(uint32_t freq)
Definition: SPI.hh:157
Divide system clock by 8.
Definition: SPI.hh:63
bool attach(Driver *dev)
Definition: SPI.cpp:246
void transfer_start(uint8_t data)
Definition: SPI.hh:339
void write(const iovec_t *vec)
Definition: SPI.hh:437
Divide system clock by 16.
Definition: SPI.hh:64
uint8_t transfer_await()
Definition: SPI.hh:350
uint8_t transfer(uint8_t data)
Definition: SPI.hh:326
uint8_t m_spcr
SPI/SPCR hardware control register setting.
Definition: SPI.hh:173
Default is MSB.
Definition: SPI.hh:75
void * buf
Buffer pointer.
Definition: Types.h:392
Divide system clock by 64.
Definition: SPI.hh:66
static Clock clock(uint32_t freq)
Definition: SPI.hh:117
void begin()
Definition: SPI.hh:232
Active high logic during transaction.
Definition: SPI.hh:81
Default is low logic.
Definition: SPI.hh:84
Divide system clock by 32.
Definition: SPI.hh:65
void write_P(const void *buf, size_t count)
Definition: SPI.cpp:184
Active low logic during transaction.
Definition: SPI.hh:80
SPI spi
Definition: SPI.cpp:29
Divide system clock by 2.
Definition: SPI.hh:61
friend class SPI
Definition: SPI.hh:176
static void powerdown()
Definition: SPI.hh:383
Most significant bit first.
Definition: SPI.hh:73
Pulse low on end of transaction.
Definition: SPI.hh:82
Default clock rate.
Definition: SPI.hh:68
void end()
Definition: SPI.hh:242
void read(void *buf, size_t count)
Definition: SPI.cpp:160
OutputPin m_cs
Device chip select pin.
Definition: SPI.hh:166
Driver(Board::DigitalPin cs, Pulse pulse=DEFAULT_PULSE, Clock rate=DEFAULT_CLOCK, uint8_t mode=0, Order order=MSB_ORDER, Interrupt::Handler *irq=NULL)
Definition: SOFT_SPI.cpp:25
Pulse m_pulse
Chip select pulse width.
Definition: SPI.hh:167
void write(const void *buf, size_t count)
Definition: SPI.cpp:170