aboutsummaryrefslogtreecommitdiffstats
path: root/arduino/libraries/SPI/SPI.h
blob: 778575bcfd0c9790339e23058894f156a444728b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
/*
 * SPI Master library for nRF5x.
 * Copyright (c) 2015 Arduino LLC
 * Copyright (c) 2016 Sandeep Mistry All right reserved.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#ifndef _SPI_H_INCLUDED
#define _SPI_H_INCLUDED

#include <Arduino.h>

// SPI_HAS_TRANSACTION means SPI has
//   - beginTransaction()
//   - endTransaction()
//   - usingInterrupt()
//   - SPISetting(clock, bitOrder, dataMode)
#define SPI_HAS_TRANSACTION 1

#define SPI_MODE0 0x02
#define SPI_MODE1 0x00
#define SPI_MODE2 0x03
#define SPI_MODE3 0x01


class SPISettings {
  public:
  SPISettings(uint32_t clock, BitOrder bitOrder, uint8_t dataMode) {
    if (__builtin_constant_p(clock)) {
      init_AlwaysInline(clock, bitOrder, dataMode);
    } else {
      init_MightInline(clock, bitOrder, dataMode);
    }
  }

  // Default speed set to 4MHz, SPI mode set to MODE 0 and Bit order set to MSB first.
  SPISettings() { init_AlwaysInline(4000000, MSBFIRST, SPI_MODE0); }

  private:
  void init_MightInline(uint32_t clock, BitOrder bitOrder, uint8_t dataMode) {
    init_AlwaysInline(clock, bitOrder, dataMode);
  }

  void init_AlwaysInline(uint32_t clock, BitOrder bitOrder, uint8_t dataMode) __attribute__((__always_inline__)) {
    if (clock <= 125000) {
      this->clockFreq = SPI_FREQUENCY_FREQUENCY_K125;
    } else if (clock <= 250000) {
      this->clockFreq = SPI_FREQUENCY_FREQUENCY_K250;
    } else if (clock <= 500000) {
      this->clockFreq = SPI_FREQUENCY_FREQUENCY_K500;
    } else if (clock <= 1000000) {
      this->clockFreq = SPI_FREQUENCY_FREQUENCY_M1;
    } else if (clock <= 2000000) {
      this->clockFreq = SPI_FREQUENCY_FREQUENCY_M2;
    } else if (clock <= 4000000) {
      this->clockFreq = SPI_FREQUENCY_FREQUENCY_M4;
    } else {
      this->clockFreq = SPI_FREQUENCY_FREQUENCY_M8;
    }

    this->bitOrder = (bitOrder == MSBFIRST ? SPI_CONFIG_ORDER_MsbFirst : SPI_CONFIG_ORDER_LsbFirst);
    this->dataMode = dataMode;
  }

  uint32_t clockFreq;
  uint8_t dataMode;
  uint32_t bitOrder;

  friend class SPIClass;
};

class SPIClass {
  public:
  SPIClass(NRF_SPI_Type *p_spi, uint8_t uc_pinMISO, uint8_t uc_pinSCK, uint8_t uc_pinMOSI);


  byte transfer(uint8_t data);
  uint16_t transfer16(uint16_t data);
  inline void transfer(void *buf, size_t count);

  // Transaction Functions
  void usingInterrupt(int interruptNumber);
  void beginTransaction(SPISettings settings);
  void endTransaction(void);

  // SPI Configuration methods
  void attachInterrupt();
  void detachInterrupt();

  void begin();
  void end();

  void setBitOrder(BitOrder order);
  void setDataMode(uint8_t uc_mode);
  void setClockDivider(uint8_t uc_div);

  private:
  void init();
  void config(SPISettings settings);

  NRF_SPI_Type *_p_spi;
  uint8_t _uc_pinMiso;
  uint8_t _uc_pinMosi;
  uint8_t _uc_pinSCK;

  uint8_t _dataMode;
  uint32_t _bitOrder;

  bool initialized;
  uint8_t interruptMode;
  char interruptSave;
  uint32_t interruptMask;
};

void SPIClass::transfer(void *buf, size_t count)
{
  // TODO: Optimize for faster block-transfer
  uint8_t *buffer = reinterpret_cast<uint8_t *>(buf);
  for (size_t i=0; i<count; i++)
    buffer[i] = transfer(buffer[i]);
}

#if SPI_INTERFACES_COUNT > 0
extern SPIClass SPI;
#endif

// For compatibility with sketches designed for AVR @ 64 MHz
// New programs should use SPI.beginTransaction to set the SPI clock
#if F_CPU == 64000000 // feather52 run @ 64Mhz
  #define SPI_CLOCK_DIV2   2
  #define SPI_CLOCK_DIV4   4
  #define SPI_CLOCK_DIV8   8
  #define SPI_CLOCK_DIV16  16
  #define SPI_CLOCK_DIV32  32
  #define SPI_CLOCK_DIV64  64
  #define SPI_CLOCK_DIV128 128
  #define SPI_CLOCK_DIV256 256
  #define SPI_CLOCK_DIV512 512
#endif

#endif