-
-
Notifications
You must be signed in to change notification settings - Fork 111
/
Copy pathSPI.h
148 lines (126 loc) · 4.63 KB
/
SPI.h
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
/*
* Copyright (c) 2010 by Cristian Maglie <[email protected]>
* Copyright (c) 2014 by Paul Stoffregen <[email protected]> (Transaction API)
* SPI Master library for arduino.
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of either the GNU General Public License version 2
* or the GNU Lesser General Public License version 2.1, both as
* published by the Free Software Foundation.
*/
#ifndef _SPI_H_INCLUDED
#define _SPI_H_INCLUDED
#include "variant.h"
#include <stdio.h>
// SPI_HAS_TRANSACTION means SPI has
// - beginTransaction()
// - endTransaction()
// - usingInterrupt()
// - SPISetting(clock, bitOrder, dataMode)
#define SPI_HAS_TRANSACTION 1
// SPI_HAS_EXTENDED_CS_PIN_HANDLING means SPI has automatic
// CS pin handling and provides the following methods:
// - begin(pin)
// - end(pin)
// - setBitOrder(pin, bitorder)
// - setDataMode(pin, datamode)
// - setClockDivider(pin, clockdiv)
// - transfer(pin, data, SPI_LAST/SPI_CONTINUE)
// - beginTransaction(pin, SPISettings settings) (if transactions are available)
#define SPI_HAS_EXTENDED_CS_PIN_HANDLING 1
#define SPI_MODE0 0x02
#define SPI_MODE1 0x00
#define SPI_MODE2 0x03
#define SPI_MODE3 0x01
enum SPITransferMode {
SPI_CONTINUE,
SPI_LAST
};
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);
}
}
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__)) {
border = bitOrder;
uint8_t div;
if (clock < (F_CPU / 255)) {
div = 255;
} else if (clock >= (F_CPU / 2)) {
div = 2;
} else {
div = (F_CPU / (clock + 1)) + 1;
}
config = (dataMode & 3) | SPI_CSR_CSAAT | SPI_CSR_SCBR(div) | SPI_CSR_DLYBCT(1);
}
uint32_t config;
BitOrder border;
friend class SPIClass;
};
class SPIClass {
public:
SPIClass(Spi *_spi, uint32_t _id, void(*_initCb)(void));
// Transfer functions
byte transfer(byte _pin, uint8_t _data, SPITransferMode _mode = SPI_LAST);
uint16_t transfer16(byte _pin, uint16_t _data, SPITransferMode _mode = SPI_LAST);
void transfer(byte _pin, void *_buf, size_t _count, SPITransferMode _mode = SPI_LAST);
// Transfer functions on default pin BOARD_SPI_DEFAULT_SS
byte transfer(uint8_t _data, SPITransferMode _mode = SPI_LAST) { return transfer(BOARD_SPI_DEFAULT_SS, _data, _mode); }
uint16_t transfer16(uint16_t _data, SPITransferMode _mode = SPI_LAST) { return transfer16(BOARD_SPI_DEFAULT_SS, _data, _mode); }
void transfer(void *_buf, size_t _count, SPITransferMode _mode = SPI_LAST) { transfer(BOARD_SPI_DEFAULT_SS, _buf, _count, _mode); }
// Transaction Functions
void usingInterrupt(uint8_t interruptNumber);
void beginTransaction(SPISettings settings) { beginTransaction(BOARD_SPI_DEFAULT_SS, settings); }
void beginTransaction(uint8_t pin, SPISettings settings);
void endTransaction(void);
// SPI Configuration methods
void attachInterrupt(void);
void detachInterrupt(void);
void begin(void);
void end(void);
// Attach/Detach pin to/from SPI controller
void begin(uint8_t _pin);
void end(uint8_t _pin);
// These methods sets a parameter on a single pin
void setBitOrder(uint8_t _pin, BitOrder);
void setDataMode(uint8_t _pin, uint8_t);
void setClockDivider(uint8_t _pin, uint8_t);
// These methods sets the same parameters but on default pin BOARD_SPI_DEFAULT_SS
void setBitOrder(BitOrder _order) { setBitOrder(BOARD_SPI_DEFAULT_SS, _order); };
void setDataMode(uint8_t _mode) { setDataMode(BOARD_SPI_DEFAULT_SS, _mode); };
void setClockDivider(uint8_t _div) { setClockDivider(BOARD_SPI_DEFAULT_SS, _div); };
private:
void init();
Spi *spi;
uint32_t id;
BitOrder bitOrder[SPI_CHANNELS_NUM];
uint32_t divider[SPI_CHANNELS_NUM];
uint32_t mode[SPI_CHANNELS_NUM];
void (*initCb)(void);
bool initialized;
uint8_t interruptMode; // 0=none, 1-15=mask, 16=global
uint8_t interruptSave; // temp storage, to restore state
uint32_t interruptMask[4];
};
#if SPI_INTERFACES_COUNT > 0
extern SPIClass SPI;
#endif
// For compatibility with sketches designed for AVR @ 16 MHz
// New programs should use SPI.beginTransaction to set the SPI clock
#define SPI_CLOCK_DIV2 11
#define SPI_CLOCK_DIV4 21
#define SPI_CLOCK_DIV8 42
#define SPI_CLOCK_DIV16 84
#define SPI_CLOCK_DIV32 168
#define SPI_CLOCK_DIV64 255
#define SPI_CLOCK_DIV128 255
#endif