aboutsummaryrefslogtreecommitdiff
path: root/tmk_core
diff options
context:
space:
mode:
authorRyan <fauxpark@gmail.com>2020-04-08 11:04:31 +1000
committerGitHub <noreply@github.com>2020-04-08 11:04:31 +1000
commit400ca2d035d7bdb85c077a53b2cd85cdd04882ab (patch)
treedd6c88d9deee75d52af52ee3d208abfa99072386 /tmk_core
parente409fb47f27f9cf56479928ed86eb2eb346eec54 (diff)
downloadqmk_firmware-400ca2d035d7bdb85c077a53b2cd85cdd04882ab.tar.gz
qmk_firmware-400ca2d035d7bdb85c077a53b2cd85cdd04882ab.zip
spi_master for AVR (#8299)
* Change _delay_ms/us() to wait_ms/us() * Switch to platform-agnostic GPIO macros * Add AVR spi_master and migrate Adafruit BLE code * Set verbose back to false * Add clock divisor, bit order and SPI mode configuration for init * Add start and stop functions * Move configuration of mode, endianness and speed to `spi_start()` * Some breaks here would be good * Default Adafruit BLE clock divisor to 4 (2MHz on the Feather 32U4) * Remove mode and divisor enums * Add some docs * No hr at EOF * Add links in sidebar
Diffstat (limited to 'tmk_core')
-rw-r--r--tmk_core/protocol/lufa.mk1
-rw-r--r--tmk_core/protocol/lufa/adafruit_ble.cpp162
2 files changed, 39 insertions, 124 deletions
diff --git a/tmk_core/protocol/lufa.mk b/tmk_core/protocol/lufa.mk
index d7d1d9ffc..d87802992 100644
--- a/tmk_core/protocol/lufa.mk
+++ b/tmk_core/protocol/lufa.mk
@@ -29,6 +29,7 @@ ifeq ($(strip $(BLUETOOTH_ENABLE)), yes)
29endif 29endif
30 30
31ifeq ($(strip $(BLUETOOTH)), AdafruitBLE) 31ifeq ($(strip $(BLUETOOTH)), AdafruitBLE)
32 LUFA_SRC += spi_master.c
32 LUFA_SRC += analog.c 33 LUFA_SRC += analog.c
33 LUFA_SRC += $(LUFA_DIR)/adafruit_ble.cpp 34 LUFA_SRC += $(LUFA_DIR)/adafruit_ble.cpp
34endif 35endif
diff --git a/tmk_core/protocol/lufa/adafruit_ble.cpp b/tmk_core/protocol/lufa/adafruit_ble.cpp
index 7b3ffdef7..f04ab757e 100644
--- a/tmk_core/protocol/lufa/adafruit_ble.cpp
+++ b/tmk_core/protocol/lufa/adafruit_ble.cpp
@@ -1,15 +1,15 @@
1#include "adafruit_ble.h" 1#include "adafruit_ble.h"
2
2#include <stdio.h> 3#include <stdio.h>
3#include <stdlib.h> 4#include <stdlib.h>
4#include <alloca.h> 5#include <alloca.h>
5#include <util/delay.h>
6#include <util/atomic.h>
7#include "debug.h" 6#include "debug.h"
8#include "pincontrol.h"
9#include "timer.h" 7#include "timer.h"
10#include "action_util.h" 8#include "action_util.h"
11#include "ringbuffer.hpp" 9#include "ringbuffer.hpp"
12#include <string.h> 10#include <string.h>
11#include "spi_master.h"
12#include "wait.h"
13#include "analog.h" 13#include "analog.h"
14 14
15// These are the pin assignments for the 32u4 boards. 15// These are the pin assignments for the 32u4 boards.
@@ -27,6 +27,12 @@
27# define AdafruitBleIRQPin E6 27# define AdafruitBleIRQPin E6
28#endif 28#endif
29 29
30#ifndef AdafruitBleSpiClockSpeed
31# define AdafruitBleSpiClockSpeed 4000000UL // SCK frequency
32#endif
33
34#define SCK_DIVISOR (F_CPU / AdafruitBleSpiClockSpeed)
35
30#define SAMPLE_BATTERY 36#define SAMPLE_BATTERY
31#define ConnectionUpdateInterval 1000 /* milliseconds */ 37#define ConnectionUpdateInterval 1000 /* milliseconds */
32 38
@@ -130,10 +136,6 @@ enum ble_system_event_bits {
130 BleSystemMidiRx = 10, 136 BleSystemMidiRx = 10,
131}; 137};
132 138
133// The SDEP.md file says 2MHz but the web page and the sample driver
134// both use 4MHz
135#define SpiBusSpeed 4000000
136
137#define SdepTimeout 150 /* milliseconds */ 139#define SdepTimeout 150 /* milliseconds */
138#define SdepShortTimeout 10 /* milliseconds */ 140#define SdepShortTimeout 10 /* milliseconds */
139#define SdepBackOff 25 /* microseconds */ 141#define SdepBackOff 25 /* microseconds */
@@ -142,116 +144,32 @@ enum ble_system_event_bits {
142static bool at_command(const char *cmd, char *resp, uint16_t resplen, bool verbose, uint16_t timeout = SdepTimeout); 144static bool at_command(const char *cmd, char *resp, uint16_t resplen, bool verbose, uint16_t timeout = SdepTimeout);
143static bool at_command_P(const char *cmd, char *resp, uint16_t resplen, bool verbose = false); 145static bool at_command_P(const char *cmd, char *resp, uint16_t resplen, bool verbose = false);
144 146
145struct SPI_Settings {
146 uint8_t spcr, spsr;
147};
148
149static struct SPI_Settings spi;
150
151// Initialize 4Mhz MSBFIRST MODE0
152void SPI_init(struct SPI_Settings *spi) {
153 spi->spcr = _BV(SPE) | _BV(MSTR);
154#if F_CPU == 8000000
155 // For MCUs running at 8MHz (such as Feather 32U4, or 3.3V Pro Micros) we set the SPI doublespeed bit
156 spi->spsr = _BV(SPI2X);
157#endif
158
159 ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
160 // Ensure that SS is OUTPUT High
161 digitalWrite(B0, PinLevelHigh);
162 pinMode(B0, PinDirectionOutput);
163
164 SPCR |= _BV(MSTR);
165 SPCR |= _BV(SPE);
166 pinMode(B1 /* SCK */, PinDirectionOutput);
167 pinMode(B2 /* MOSI */, PinDirectionOutput);
168 }
169}
170
171static inline void SPI_begin(struct SPI_Settings *spi) {
172 SPCR = spi->spcr;
173 SPSR = spi->spsr;
174}
175
176static inline uint8_t SPI_TransferByte(uint8_t data) {
177 SPDR = data;
178 asm volatile("nop");
179 while (!(SPSR & _BV(SPIF))) {
180 ; // wait
181 }
182 return SPDR;
183}
184
185static inline void spi_send_bytes(const uint8_t *buf, uint8_t len) {
186 if (len == 0) return;
187 const uint8_t *end = buf + len;
188 while (buf < end) {
189 SPDR = *buf;
190 while (!(SPSR & _BV(SPIF))) {
191 ; // wait
192 }
193 ++buf;
194 }
195}
196
197static inline uint16_t spi_read_byte(void) { return SPI_TransferByte(0x00 /* dummy */); }
198
199static inline void spi_recv_bytes(uint8_t *buf, uint8_t len) {
200 const uint8_t *end = buf + len;
201 if (len == 0) return;
202 while (buf < end) {
203 SPDR = 0; // write a dummy to initiate read
204 while (!(SPSR & _BV(SPIF))) {
205 ; // wait
206 }
207 *buf = SPDR;
208 ++buf;
209 }
210}
211
212#if 0
213static void dump_pkt(const struct sdep_msg *msg) {
214 print("pkt: type=");
215 print_hex8(msg->type);
216 print(" cmd=");
217 print_hex8(msg->cmd_high);
218 print_hex8(msg->cmd_low);
219 print(" len=");
220 print_hex8(msg->len);
221 print(" more=");
222 print_hex8(msg->more);
223 print("\n");
224}
225#endif
226
227// Send a single SDEP packet 147// Send a single SDEP packet
228static bool sdep_send_pkt(const struct sdep_msg *msg, uint16_t timeout) { 148static bool sdep_send_pkt(const struct sdep_msg *msg, uint16_t timeout) {
229 SPI_begin(&spi); 149 spi_start(AdafruitBleCSPin, false, 0, SCK_DIVISOR);
230
231 digitalWrite(AdafruitBleCSPin, PinLevelLow);
232 uint16_t timerStart = timer_read(); 150 uint16_t timerStart = timer_read();
233 bool success = false; 151 bool success = false;
234 bool ready = false; 152 bool ready = false;
235 153
236 do { 154 do {
237 ready = SPI_TransferByte(msg->type) != SdepSlaveNotReady; 155 ready = spi_write(msg->type, 100) != SdepSlaveNotReady;
238 if (ready) { 156 if (ready) {
239 break; 157 break;
240 } 158 }
241 159
242 // Release it and let it initialize 160 // Release it and let it initialize
243 digitalWrite(AdafruitBleCSPin, PinLevelHigh); 161 spi_stop();
244 _delay_us(SdepBackOff); 162 wait_us(SdepBackOff);
245 digitalWrite(AdafruitBleCSPin, PinLevelLow); 163 spi_start(AdafruitBleCSPin, false, 0, SCK_DIVISOR);
246 } while (timer_elapsed(timerStart) < timeout); 164 } while (timer_elapsed(timerStart) < timeout);
247 165
248 if (ready) { 166 if (ready) {
249 // Slave is ready; send the rest of the packet 167 // Slave is ready; send the rest of the packet
250 spi_send_bytes(&msg->cmd_low, sizeof(*msg) - (1 + sizeof(msg->payload)) + msg->len); 168 spi_transmit(&msg->cmd_low, sizeof(*msg) - (1 + sizeof(msg->payload)) + msg->len, 100);
251 success = true; 169 success = true;
252 } 170 }
253 171
254 digitalWrite(AdafruitBleCSPin, PinLevelHigh); 172 spi_stop();
255 173
256 return success; 174 return success;
257} 175}
@@ -275,41 +193,39 @@ static bool sdep_recv_pkt(struct sdep_msg *msg, uint16_t timeout) {
275 bool ready = false; 193 bool ready = false;
276 194
277 do { 195 do {
278 ready = digitalRead(AdafruitBleIRQPin); 196 ready = readPin(AdafruitBleIRQPin);
279 if (ready) { 197 if (ready) {
280 break; 198 break;
281 } 199 }
282 _delay_us(1); 200 wait_us(1);
283 } while (timer_elapsed(timerStart) < timeout); 201 } while (timer_elapsed(timerStart) < timeout);
284 202
285 if (ready) { 203 if (ready) {
286 SPI_begin(&spi); 204 spi_start(AdafruitBleCSPin, false, 0, SCK_DIVISOR);
287
288 digitalWrite(AdafruitBleCSPin, PinLevelLow);
289 205
290 do { 206 do {
291 // Read the command type, waiting for the data to be ready 207 // Read the command type, waiting for the data to be ready
292 msg->type = spi_read_byte(); 208 msg->type = spi_read(100);
293 if (msg->type == SdepSlaveNotReady || msg->type == SdepSlaveOverflow) { 209 if (msg->type == SdepSlaveNotReady || msg->type == SdepSlaveOverflow) {
294 // Release it and let it initialize 210 // Release it and let it initialize
295 digitalWrite(AdafruitBleCSPin, PinLevelHigh); 211 spi_stop();
296 _delay_us(SdepBackOff); 212 wait_us(SdepBackOff);
297 digitalWrite(AdafruitBleCSPin, PinLevelLow); 213 spi_start(AdafruitBleCSPin, false, 0, SCK_DIVISOR);
298 continue; 214 continue;
299 } 215 }
300 216
301 // Read the rest of the header 217 // Read the rest of the header
302 spi_recv_bytes(&msg->cmd_low, sizeof(*msg) - (1 + sizeof(msg->payload))); 218 spi_receive(&msg->cmd_low, sizeof(*msg) - (1 + sizeof(msg->payload)), 100);
303 219
304 // and get the payload if there is any 220 // and get the payload if there is any
305 if (msg->len <= SdepMaxPayload) { 221 if (msg->len <= SdepMaxPayload) {
306 spi_recv_bytes(msg->payload, msg->len); 222 spi_receive(msg->payload, msg->len, 100);
307 } 223 }
308 success = true; 224 success = true;
309 break; 225 break;
310 } while (timer_elapsed(timerStart) < timeout); 226 } while (timer_elapsed(timerStart) < timeout);
311 227
312 digitalWrite(AdafruitBleCSPin, PinLevelHigh); 228 spi_stop();
313 } 229 }
314 return success; 230 return success;
315} 231}
@@ -320,7 +236,7 @@ static void resp_buf_read_one(bool greedy) {
320 return; 236 return;
321 } 237 }
322 238
323 if (digitalRead(AdafruitBleIRQPin)) { 239 if (readPin(AdafruitBleIRQPin)) {
324 struct sdep_msg msg; 240 struct sdep_msg msg;
325 241
326 again: 242 again:
@@ -331,7 +247,7 @@ static void resp_buf_read_one(bool greedy) {
331 dprintf("recv latency %dms\n", TIMER_DIFF_16(timer_read(), last_send)); 247 dprintf("recv latency %dms\n", TIMER_DIFF_16(timer_read(), last_send));
332 } 248 }
333 249
334 if (greedy && resp_buf.peek(last_send) && digitalRead(AdafruitBleIRQPin)) { 250 if (greedy && resp_buf.peek(last_send) && readPin(AdafruitBleIRQPin)) {
335 goto again; 251 goto again;
336 } 252 }
337 } 253 }
@@ -361,7 +277,7 @@ static void send_buf_send_one(uint16_t timeout = SdepTimeout) {
361 dprintf("send_buf_send_one: have %d remaining\n", (int)send_buf.size()); 277 dprintf("send_buf_send_one: have %d remaining\n", (int)send_buf.size());
362 } else { 278 } else {
363 dprint("failed to send, will retry\n"); 279 dprint("failed to send, will retry\n");
364 _delay_ms(SdepTimeout); 280 wait_ms(SdepTimeout);
365 resp_buf_read_one(true); 281 resp_buf_read_one(true);
366 } 282 }
367} 283}
@@ -382,20 +298,18 @@ static bool ble_init(void) {
382 state.configured = false; 298 state.configured = false;
383 state.is_connected = false; 299 state.is_connected = false;
384 300
385 pinMode(AdafruitBleIRQPin, PinDirectionInput); 301 setPinInput(AdafruitBleIRQPin);
386 pinMode(AdafruitBleCSPin, PinDirectionOutput);
387 digitalWrite(AdafruitBleCSPin, PinLevelHigh);
388 302
389 SPI_init(&spi); 303 spi_init();
390 304
391 // Perform a hardware reset 305 // Perform a hardware reset
392 pinMode(AdafruitBleResetPin, PinDirectionOutput); 306 setPinOutput(AdafruitBleResetPin);
393 digitalWrite(AdafruitBleResetPin, PinLevelHigh); 307 writePinHigh(AdafruitBleResetPin);
394 digitalWrite(AdafruitBleResetPin, PinLevelLow); 308 writePinLow(AdafruitBleResetPin);
395 _delay_ms(10); 309 wait_ms(10);
396 digitalWrite(AdafruitBleResetPin, PinLevelHigh); 310 writePinHigh(AdafruitBleResetPin);
397 311
398 _delay_ms(1000); // Give it a second to initialize 312 wait_ms(1000); // Give it a second to initialize
399 313
400 state.initialized = true; 314 state.initialized = true;
401 return state.initialized; 315 return state.initialized;
@@ -596,7 +510,7 @@ void adafruit_ble_task(void) {
596 resp_buf_read_one(true); 510 resp_buf_read_one(true);
597 send_buf_send_one(SdepShortTimeout); 511 send_buf_send_one(SdepShortTimeout);
598 512
599 if (resp_buf.empty() && (state.event_flags & UsingEvents) && digitalRead(AdafruitBleIRQPin)) { 513 if (resp_buf.empty() && (state.event_flags & UsingEvents) && readPin(AdafruitBleIRQPin)) {
600 // Must be an event update 514 // Must be an event update
601 if (at_command_P(PSTR("AT+EVENTSTATUS"), resbuf, sizeof(resbuf))) { 515 if (at_command_P(PSTR("AT+EVENTSTATUS"), resbuf, sizeof(resbuf))) {
602 uint32_t mask = strtoul(resbuf, NULL, 16); 516 uint32_t mask = strtoul(resbuf, NULL, 16);