-
Notifications
You must be signed in to change notification settings - Fork 1k
/
Copy pathSPI.cpp
291 lines (257 loc) · 8.69 KB
/
SPI.cpp
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
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
/*
* Copyright (c) 2010 by Cristian Maglie <c.maglie@arduino.cc>
* Copyright (c) 2014 by Paul Stoffregen <paul@pjrc.com> (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.
*/
#include "SPI.h"
SPIClass SPI;
/**
* @brief Default constructor. Uses pin configuration of variant.h.
*/
SPIClass::SPIClass()
{
_spi.pin_miso = digitalPinToPinName(MISO);
_spi.pin_mosi = digitalPinToPinName(MOSI);
_spi.pin_sclk = digitalPinToPinName(SCK);
_spi.pin_ssel = NC;
}
/**
* @brief Constructor to create another SPI instance attached to another SPI
* peripheral different of the default SPI. All pins must be attached to
* the same SPI peripheral. See datasheet of the microcontroller.
* @param mosi: SPI mosi pin. Accepted format: number or Arduino format (Dx)
* or ST format (Pxy).
* @param miso: SPI miso pin. Accepted format: number or Arduino format (Dx)
* or ST format (Pxy).
* @param sclk: SPI clock pin. Accepted format: number or Arduino format (Dx)
* or ST format (Pxy).
* @param ssel: SPI ssel pin (optional). Accepted format: number or
* Arduino format (Dx) or ST format (Pxy). By default is set to NC.
* This pin must correspond to a hardware CS pin which can be managed
* by the SPI peripheral itself. See the datasheet of the microcontroller
* or look at PinMap_SPI_SSEL[] inside the file PeripheralPins.c
* corresponding to the board. If you configure this pin you can't use
* another CS pin and don't pass a CS pin as parameter to any functions
* of the class.
*/
SPIClass::SPIClass(uint32_t mosi, uint32_t miso, uint32_t sclk, uint32_t ssel)
{
_spi.pin_miso = digitalPinToPinName(miso);
_spi.pin_mosi = digitalPinToPinName(mosi);
_spi.pin_sclk = digitalPinToPinName(sclk);
_spi.pin_ssel = digitalPinToPinName(ssel);
}
/**
* @brief Initialize the SPI instance.
*/
void SPIClass::begin(void)
{
_spi.handle.State = HAL_SPI_STATE_RESET;
_spiSettings = SPISettings();
spi_init(&_spi, _spiSettings.clockFreq,
_spiSettings.dataMode,
_spiSettings.bitOrder);
}
/**
* @brief This function should be used to configure the SPI instance in case you
* don't use the default parameters set by the begin() function.
* @param settings: SPI settings(clock speed, bit order, data mode).
*/
void SPIClass::beginTransaction(SPISettings settings)
{
if (_spiSettings != settings) {
_spiSettings = settings;
spi_init(&_spi, _spiSettings.clockFreq,
_spiSettings.dataMode,
_spiSettings.bitOrder);
}
}
/**
* @brief End the transaction after beginTransaction usage
*/
void SPIClass::endTransaction(void)
{
}
/**
* @brief Deinitialize the SPI instance and stop it.
*/
void SPIClass::end(void)
{
spi_deinit(&_spi);
}
/**
* @brief Deprecated function.
* Configure the bit order: MSB first or LSB first.
* @param bitOrder: MSBFIRST or LSBFIRST
*/
void SPIClass::setBitOrder(BitOrder bitOrder)
{
_spiSettings.bitOrder = bitOrder;
spi_init(&_spi, _spiSettings.clockFreq,
_spiSettings.dataMode,
_spiSettings.bitOrder);
}
/**
* @brief Deprecated function.
* Configure the data mode (clock polarity and clock phase)
* @param mode: SPI_MODE0, SPI_MODE1, SPI_MODE2 or SPI_MODE3
* @note
* Mode Clock Polarity (CPOL) Clock Phase (CPHA)
* SPI_MODE0 0 0
* SPI_MODE1 0 1
* SPI_MODE2 1 0
* SPI_MODE3 1 1
*/
void SPIClass::setDataMode(uint8_t mode)
{
setDataMode((SPIMode)mode);
}
void SPIClass::setDataMode(SPIMode mode)
{
_spiSettings.dataMode = mode;
spi_init(&_spi, _spiSettings.clockFreq,
_spiSettings.dataMode,
_spiSettings.bitOrder);
}
/**
* @brief Deprecated function.
* Configure the clock speed
* @param divider: the SPI clock can be divided by values from 1 to 255.
* If 0, default SPI speed is used.
*/
void SPIClass::setClockDivider(uint8_t divider)
{
if (divider == 0) {
_spiSettings.clockFreq = SPI_SPEED_CLOCK_DEFAULT;
} else {
/* Get clk freq of the SPI instance and compute it */
_spiSettings.clockFreq = spi_getClkFreq(&_spi) / divider;
}
spi_init(&_spi, _spiSettings.clockFreq,
_spiSettings.dataMode,
_spiSettings.bitOrder);
}
/**
* @brief Transfer one byte on the SPI bus.
* begin() or beginTransaction() must be called at least once before.
* @param data: byte to send.
* @param skipReceive: skip receiving data after transmit or not.
* SPI_TRANSMITRECEIVE or SPI_TRANSMITONLY.
* Optional, default: SPI_TRANSMITRECEIVE.
* @return byte received from the slave.
*/
uint8_t SPIClass::transfer(uint8_t data, bool skipReceive)
{
spi_transfer(&_spi, &data, (!skipReceive) ? &data : NULL, sizeof(uint8_t));
return data;
}
/**
* @brief Transfer two bytes on the SPI bus in 16 bits format.
* begin() or beginTransaction() must be called at least once before.
* @param data: bytes to send.
* @param skipReceive: skip receiving data after transmit or not.
* SPI_TRANSMITRECEIVE or SPI_TRANSMITONLY.
* Optional, default: SPI_TRANSMITRECEIVE.
* @return bytes received from the slave in 16 bits format.
*/
uint16_t SPIClass::transfer16_obsoleted(uint16_t data, bool skipReceive)
{
uint16_t tmp;
if (_spiSettings.bitOrder) {
tmp = ((data & 0xff00) >> 8) | ((data & 0xff) << 8);
data = tmp;
}
spi_transfer(&_spi, (uint8_t *)&data, (!skipReceive) ? (uint8_t *)&data : NULL, sizeof(uint16_t));
if (_spiSettings.bitOrder) {
tmp = ((data & 0xff00) >> 8) | ((data & 0xff) << 8);
data = tmp;
}
return data;
}
uint16_t SPIClass::transfer16(uint16_t data, bool skipReceive)
{
uint16_t tmp;
uint16_t out;
if (_spiSettings.bitOrder) {
tmp = ((data & 0xff00) >> 8) | ((data & 0xff) << 8);
data = tmp;
}
spi_transfer16(&_spi, (uint16_t *)&data, (!skipReceive) ? (uint16_t *)&out : NULL);
if (_spiSettings.bitOrder) {
tmp = ((out & 0xff00) >> 8) | ((out & 0xff) << 8);
out = tmp;
}
return out;
}
/**
* @brief Transfer several bytes. Only one buffer used to send and receive data.
* begin() or beginTransaction() must be called at least once before.
* @param buf: pointer to the bytes to send. The bytes received are copy in
* this buffer.
* @param count: number of bytes to send/receive.
* @param skipReceive: skip receiving data after transmit or not.
* SPI_TRANSMITRECEIVE or SPI_TRANSMITONLY.
* Optional, default: SPI_TRANSMITRECEIVE.
*/
void SPIClass::transfer(void *buf, size_t count, bool skipReceive)
{
spi_transfer(&_spi, (uint8_t *)buf, (!skipReceive) ? (uint8_t *)buf : NULL, count);
}
/**
* @brief Transfer several bytes. One constant buffer used to send and
* one to receive data.
* begin() or beginTransaction() must be called at least once before.
* @param tx_buf: array of Tx bytes that is filled by the user before starting
* the SPI transfer. If NULL, default dummy 0xFF bytes will be
* clocked out.
* @param rx_buf: array of Rx bytes that will be filled by the slave during
* the SPI transfer. If NULL, the received data will be discarded.
* @param count: number of bytes to send/receive.
*/
void SPIClass::transfer(const void *tx_buf, void *rx_buf, size_t count)
{
spi_transfer(&_spi, ((const uint8_t *)tx_buf), ((uint8_t *)rx_buf), count);
}
/**
* @brief Not implemented.
*/
void SPIClass::usingInterrupt(int interruptNumber)
{
UNUSED(interruptNumber);
}
/**
* @brief Not implemented.
*/
void SPIClass::notUsingInterrupt(int interruptNumber)
{
UNUSED(interruptNumber);
}
/**
* @brief Not implemented.
*/
void SPIClass::attachInterrupt(void)
{
// Should be enableInterrupt()
}
/**
* @brief Not implemented.
*/
void SPIClass::detachInterrupt(void)
{
// Should be disableInterrupt()
}
#if defined(SUBGHZSPI_BASE)
void SUBGHZSPIClass::enableDebugPins(uint32_t mosi, uint32_t miso, uint32_t sclk, uint32_t ssel)
{
/* Configure SPI GPIO pins */
pinmap_pinout(digitalPinToPinName(mosi), PinMap_SPI_MOSI);
pinmap_pinout(digitalPinToPinName(miso), PinMap_SPI_MISO);
pinmap_pinout(digitalPinToPinName(sclk), PinMap_SPI_SCLK);
pinmap_pinout(digitalPinToPinName(ssel), PinMap_SPI_SSEL);
}
#endif