COSA
An Object-Oriented Platform for Arduino Programming
SPI.hh
Go to the documentation of this file.
1 
21 #ifndef COSA_SOFT_SPI_HH
22 #define COSA_SOFT_SPI_HH
23 
24 #include "Cosa/Types.h"
25 #include "Cosa/InputPin.hh"
26 #include "Cosa/OutputPin.hh"
27 #include "Cosa/Interrupt.hh"
28 
32 namespace Soft {
33 
37  class SPI {
38  public:
40  enum Clock {
41  DIV2_CLOCK = 0x04,
42  DIV4_CLOCK = 0x00,
43  DIV8_CLOCK = 0x05,
44  DIV16_CLOCK = 0x01,
45  DIV32_CLOCK = 0x06,
46  DIV64_CLOCK = 0x02,
47  DIV128_CLOCK = 0x03,
49  } __attribute__((packed));
50 
52  enum Order {
53  MSB_ORDER = 0,
54  LSB_ORDER = 1,
56  } __attribute__((packed));
57 
59  enum Pulse {
60  ACTIVE_LOW = 0,
62  PULSE_LOW = 2,
63  PULSE_HIGH = 3,
65  } __attribute__((packed));
66 
72  class Driver {
73  friend class SPI;
74  public:
86  Pulse pulse = DEFAULT_PULSE,
88  uint8_t mode = 0,
89  Order order = MSB_ORDER,
90  Interrupt::Handler* irq = NULL);
91 
97  static Clock clock(uint32_t freq)
98  __attribute__((always_inline))
99  {
100  if (freq >= (F_CPU / 2)) return (SPI::DIV2_CLOCK);
101  if (freq >= (F_CPU / 4)) return (SPI::DIV4_CLOCK);
102  if (freq >= (F_CPU / 8)) return (SPI::DIV8_CLOCK);
103  if (freq >= (F_CPU / 16)) return (SPI::DIV16_CLOCK);
104  if (freq >= (F_CPU / 32)) return (SPI::DIV32_CLOCK);
105  if (freq >= (F_CPU / 64)) return (SPI::DIV64_CLOCK);
106  return (SPI::DIV128_CLOCK);
107  }
108 
115  static Clock cycle(uint16_t ns)
116  __attribute__((always_inline))
117  {
118  if (ns <= (1000000L / (F_CPU/2000L))) return (SPI::DIV2_CLOCK);
119  if (ns <= (1000000L / (F_CPU/4000L))) return (SPI::DIV4_CLOCK);
120  if (ns <= (1000000L / (F_CPU/8000L))) return (SPI::DIV8_CLOCK);
121  if (ns <= (1000000L / (F_CPU/16000L))) return (SPI::DIV16_CLOCK);
122  if (ns <= (1000000L / (F_CPU/32000L))) return (SPI::DIV32_CLOCK);
123  if (ns <= (1000000L / (F_CPU/64000L))) return (SPI::DIV64_CLOCK);
124  return (SPI::DIV128_CLOCK);
125  }
126 
131  void set_clock(Clock rate);
132 
137  void set_clock(uint32_t freq)
138  __attribute__((always_inline))
139  {
140  set_clock(clock(freq));
141  }
142 
143  protected:
148  uint8_t m_mode;
150  uint8_t m_data;
151  };
152 
153  public:
158  Board::DigitalPin mosi,
159  Board::DigitalPin sck) :
160  m_list(0),
161  m_busy(false),
162  m_dev(0),
163  m_miso(miso),
164  m_mosi(mosi, 0),
165  m_sck(sck, 0)
166  {}
167 
173  bool attach(Driver* dev);
174 
194  void acquire(Driver* dev);
195 
199  void release();
200 
216  void begin()
217  __attribute__((always_inline))
218  {
219  if (m_dev->m_pulse < PULSE_LOW) m_dev->m_cs.toggle();
220  }
221 
226  void end()
227  __attribute__((always_inline))
228  {
229  m_dev->m_cs.toggle();
230  if (m_dev->m_pulse > ACTIVE_HIGH) m_dev->m_cs.toggle();
231  }
232 
238  void transfer_start(uint8_t data)
239  __attribute__((always_inline))
240  {
241  m_dev->m_data = data;
242  }
243 
249  uint8_t transfer_await()
250  __attribute__((always_inline))
251  {
252  return (transfer(m_dev->m_data));
253  }
254 
261  uint8_t transfer_next(uint8_t data)
262  __attribute__((always_inline))
263  {
264  uint8_t res = transfer_await();
265  transfer_start(data);
266  return (res);
267  }
268 
275  uint8_t transfer(uint8_t data);
276 
284  void transfer(void* buf, size_t count);
285 
294  void transfer(void* dst, const void* src, size_t count)
295  {
296  if (UNLIKELY(count == 0)) return;
297  uint8_t* dp = (uint8_t*) dst;
298  const uint8_t* sp = (const uint8_t*) src;
299  do *dp++ = transfer(*sp++); while (--count);
300  }
301 
308  void read(void* buf, size_t count)
309  {
310  if (UNLIKELY(count == 0)) return;
311  uint8_t* bp = (uint8_t*) buf;
312  do *bp++ = transfer(0x00); while (--count);
313  }
314 
321  void write(const void* buf, size_t count)
322  {
323  if (UNLIKELY(count == 0)) return;
324  const uint8_t* bp = (const uint8_t*) buf;
325  do transfer(*bp++); while (--count);
326  }
327 
334  void write_P(const uint8_t* buf, size_t count)
335  {
336  if (UNLIKELY(count == 0)) return;
337  do transfer(pgm_read_byte(buf++)); while (--count);
338  }
339 
345  void write(const iovec_t* vec)
346  __attribute__((always_inline))
347  {
348  for (const iovec_t* vp = vec; vp->buf != NULL; vp++)
349  write(vp->buf, vp->size);
350  }
351 
352  private:
353  Driver* m_list;
354  volatile bool m_busy;
355  Driver* m_dev;
356  InputPin m_miso;
357  OutputPin m_mosi;
358  OutputPin m_sck;
359  };
360 
361  extern SPI spi;
362 };
363 #endif
Pulse high on end of transaction.
Definition: SPI.hh:63
Default clock rate.
Definition: SPI.hh:48
Default is MSB.
Definition: SPI.hh:55
uint8_t transfer(uint8_t data)
Definition: SOFT_SPI.cpp:87
static Clock clock(uint32_t freq)
Definition: SPI.hh:97
Least significant bit first.
Definition: SPI.hh:54
void write(const iovec_t *vec)
Definition: SPI.hh:345
Divide system clock by 128.
Definition: SPI.hh:47
Definition: Clock.hh:33
Driver(Board::DigitalPin cs, Pulse pulse=DEFAULT_PULSE, Clock clock=DEFAULT_CLOCK, uint8_t mode=0, Order order=MSB_ORDER, Interrupt::Handler *irq=NULL)
void acquire(Driver *dev)
Definition: SOFT_SPI.cpp:43
#define NULL
Definition: Types.h:101
Definition: SPI.hh:32
Divide system clock by 8.
Definition: SPI.hh:43
Order
Definition: SPI.hh:52
Divide system clock by 64.
Definition: SPI.hh:46
void read(void *buf, size_t count)
Definition: SPI.hh:308
Definition: Types.h:391
static Clock cycle(uint16_t ns)
Definition: SPI.hh:115
uint8_t transfer_next(uint8_t data)
Definition: SPI.hh:261
Active low logic during transaction.
Definition: SPI.hh:60
void set_clock(uint32_t freq)
Definition: SPI.hh:137
void transfer(void *dst, const void *src, size_t count)
Definition: SPI.hh:294
Pulse
Definition: SPI.hh:59
Divide system clock by 16.
Definition: SPI.hh:44
void write(const void *buf, size_t count)
Definition: SPI.hh:321
void * buf
Buffer pointer.
Definition: Types.h:392
void begin()
Definition: SPI.hh:216
void end()
Definition: SPI.hh:226
Active high logic during transaction.
Definition: SPI.hh:61
uint8_t transfer_await()
Definition: SPI.hh:249
Divide system clock by 32.
Definition: SPI.hh:45
Pulse m_pulse
Chip select pulse mode.
Definition: SPI.hh:147
uint8_t m_mode
Mode for phase and transition.
Definition: SPI.hh:148
Pulse low on end of transaction.
Definition: SPI.hh:62
bool attach(Driver *dev)
Definition: SOFT_SPI.cpp:78
Definition: SPI.hh:37
void transfer_start(uint8_t data)
Definition: SPI.hh:238
OutputPin m_cs
Device chip select pin.
Definition: SPI.hh:146
Default is low logic.
Definition: SPI.hh:64
void write_P(const uint8_t *buf, size_t count)
Definition: SPI.hh:334
Driver * m_next
List of drivers.
Definition: SPI.hh:144
SPI spi
Definition: SPI.cpp:29
Most significant bit first.
Definition: SPI.hh:53
Divide system clock by 2.
Definition: SPI.hh:41
void release()
Definition: SOFT_SPI.cpp:64
Interrupt::Handler * m_irq
Interrupt handler.
Definition: SPI.hh:145
#define UNLIKELY(x)
Definition: Types.h:153
Order m_order
Data direction; bit order.
Definition: SPI.hh:149
SPI(Board::DigitalPin miso, Board::DigitalPin mosi, Board::DigitalPin sck)
Definition: SPI.hh:157
Divide system clock by 4.
Definition: SPI.hh:42
uint8_t m_data
Data to transfer.
Definition: SPI.hh:150
void set_clock(Clock rate)