summary refs log tree commit diff
path: root/tmk_core/protocol
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/protocol
parente409fb47f27f9cf56479928ed86eb2eb346eec54 (diff)
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/protocol')
-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 d7d1d9ffcc..d87802992e 100644
--- a/tmk_core/protocol/lufa.mk
+++ b/tmk_core/protocol/lufa.mk
@@ -29,6 +29,7 @@ ifeq ($(strip $(BLUETOOTH_ENABLE)), yes)
 endif
 
 ifeq ($(strip $(BLUETOOTH)), AdafruitBLE)
+		LUFA_SRC += spi_master.c
 		LUFA_SRC += analog.c
 		LUFA_SRC += $(LUFA_DIR)/adafruit_ble.cpp
 endif
diff --git a/tmk_core/protocol/lufa/adafruit_ble.cpp b/tmk_core/protocol/lufa/adafruit_ble.cpp
index 7b3ffdef7a..f04ab757ea 100644
--- a/tmk_core/protocol/lufa/adafruit_ble.cpp
+++ b/tmk_core/protocol/lufa/adafruit_ble.cpp
@@ -1,15 +1,15 @@
 #include "adafruit_ble.h"
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <alloca.h>
-#include <util/delay.h>
-#include <util/atomic.h>
 #include "debug.h"
-#include "pincontrol.h"
 #include "timer.h"
 #include "action_util.h"
 #include "ringbuffer.hpp"
 #include <string.h>
+#include "spi_master.h"
+#include "wait.h"
 #include "analog.h"
 
 // These are the pin assignments for the 32u4 boards.
@@ -27,6 +27,12 @@
 #    define AdafruitBleIRQPin E6
 #endif
 
+#ifndef AdafruitBleSpiClockSpeed
+#    define AdafruitBleSpiClockSpeed 4000000UL  // SCK frequency
+#endif
+
+#define SCK_DIVISOR (F_CPU / AdafruitBleSpiClockSpeed)
+
 #define SAMPLE_BATTERY
 #define ConnectionUpdateInterval 1000 /* milliseconds */
 
@@ -130,10 +136,6 @@ enum ble_system_event_bits {
     BleSystemMidiRx       = 10,
 };
 
-// The SDEP.md file says 2MHz but the web page and the sample driver
-// both use 4MHz
-#define SpiBusSpeed 4000000
-
 #define SdepTimeout 150             /* milliseconds */
 #define SdepShortTimeout 10         /* milliseconds */
 #define SdepBackOff 25              /* microseconds */
@@ -142,116 +144,32 @@ enum ble_system_event_bits {
 static bool at_command(const char *cmd, char *resp, uint16_t resplen, bool verbose, uint16_t timeout = SdepTimeout);
 static bool at_command_P(const char *cmd, char *resp, uint16_t resplen, bool verbose = false);
 
-struct SPI_Settings {
-    uint8_t spcr, spsr;
-};
-
-static struct SPI_Settings spi;
-
-// Initialize 4Mhz MSBFIRST MODE0
-void SPI_init(struct SPI_Settings *spi) {
-    spi->spcr = _BV(SPE) | _BV(MSTR);
-#if F_CPU == 8000000
-    // For MCUs running at 8MHz (such as Feather 32U4, or 3.3V Pro Micros) we set the SPI doublespeed bit
-    spi->spsr = _BV(SPI2X);
-#endif
-
-    ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
-        // Ensure that SS is OUTPUT High
-        digitalWrite(B0, PinLevelHigh);
-        pinMode(B0, PinDirectionOutput);
-
-        SPCR |= _BV(MSTR);
-        SPCR |= _BV(SPE);
-        pinMode(B1 /* SCK */, PinDirectionOutput);
-        pinMode(B2 /* MOSI */, PinDirectionOutput);
-    }
-}
-
-static inline void SPI_begin(struct SPI_Settings *spi) {
-    SPCR = spi->spcr;
-    SPSR = spi->spsr;
-}
-
-static inline uint8_t SPI_TransferByte(uint8_t data) {
-    SPDR = data;
-    asm volatile("nop");
-    while (!(SPSR & _BV(SPIF))) {
-        ;  // wait
-    }
-    return SPDR;
-}
-
-static inline void spi_send_bytes(const uint8_t *buf, uint8_t len) {
-    if (len == 0) return;
-    const uint8_t *end = buf + len;
-    while (buf < end) {
-        SPDR = *buf;
-        while (!(SPSR & _BV(SPIF))) {
-            ;  // wait
-        }
-        ++buf;
-    }
-}
-
-static inline uint16_t spi_read_byte(void) { return SPI_TransferByte(0x00 /* dummy */); }
-
-static inline void spi_recv_bytes(uint8_t *buf, uint8_t len) {
-    const uint8_t *end = buf + len;
-    if (len == 0) return;
-    while (buf < end) {
-        SPDR = 0;  // write a dummy to initiate read
-        while (!(SPSR & _BV(SPIF))) {
-            ;  // wait
-        }
-        *buf = SPDR;
-        ++buf;
-    }
-}
-
-#if 0
-static void dump_pkt(const struct sdep_msg *msg) {
-  print("pkt: type=");
-  print_hex8(msg->type);
-  print(" cmd=");
-  print_hex8(msg->cmd_high);
-  print_hex8(msg->cmd_low);
-  print(" len=");
-  print_hex8(msg->len);
-  print(" more=");
-  print_hex8(msg->more);
-  print("\n");
-}
-#endif
-
 // Send a single SDEP packet
 static bool sdep_send_pkt(const struct sdep_msg *msg, uint16_t timeout) {
-    SPI_begin(&spi);
-
-    digitalWrite(AdafruitBleCSPin, PinLevelLow);
+    spi_start(AdafruitBleCSPin, false, 0, SCK_DIVISOR);
     uint16_t timerStart = timer_read();
     bool     success    = false;
     bool     ready      = false;
 
     do {
-        ready = SPI_TransferByte(msg->type) != SdepSlaveNotReady;
+        ready = spi_write(msg->type, 100) != SdepSlaveNotReady;
         if (ready) {
             break;
         }
 
         // Release it and let it initialize
-        digitalWrite(AdafruitBleCSPin, PinLevelHigh);
-        _delay_us(SdepBackOff);
-        digitalWrite(AdafruitBleCSPin, PinLevelLow);
+        spi_stop();
+        wait_us(SdepBackOff);
+        spi_start(AdafruitBleCSPin, false, 0, SCK_DIVISOR);
     } while (timer_elapsed(timerStart) < timeout);
 
     if (ready) {
         // Slave is ready; send the rest of the packet
-        spi_send_bytes(&msg->cmd_low, sizeof(*msg) - (1 + sizeof(msg->payload)) + msg->len);
+        spi_transmit(&msg->cmd_low, sizeof(*msg) - (1 + sizeof(msg->payload)) + msg->len, 100);
         success = true;
     }
 
-    digitalWrite(AdafruitBleCSPin, PinLevelHigh);
+    spi_stop();
 
     return success;
 }
@@ -275,41 +193,39 @@ static bool sdep_recv_pkt(struct sdep_msg *msg, uint16_t timeout) {
     bool     ready      = false;
 
     do {
-        ready = digitalRead(AdafruitBleIRQPin);
+        ready = readPin(AdafruitBleIRQPin);
         if (ready) {
             break;
         }
-        _delay_us(1);
+        wait_us(1);
     } while (timer_elapsed(timerStart) < timeout);
 
     if (ready) {
-        SPI_begin(&spi);
-
-        digitalWrite(AdafruitBleCSPin, PinLevelLow);
+        spi_start(AdafruitBleCSPin, false, 0, SCK_DIVISOR);
 
         do {
             // Read the command type, waiting for the data to be ready
-            msg->type = spi_read_byte();
+            msg->type = spi_read(100);
             if (msg->type == SdepSlaveNotReady || msg->type == SdepSlaveOverflow) {
                 // Release it and let it initialize
-                digitalWrite(AdafruitBleCSPin, PinLevelHigh);
-                _delay_us(SdepBackOff);
-                digitalWrite(AdafruitBleCSPin, PinLevelLow);
+                spi_stop();
+                wait_us(SdepBackOff);
+                spi_start(AdafruitBleCSPin, false, 0, SCK_DIVISOR);
                 continue;
             }
 
             // Read the rest of the header
-            spi_recv_bytes(&msg->cmd_low, sizeof(*msg) - (1 + sizeof(msg->payload)));
+            spi_receive(&msg->cmd_low, sizeof(*msg) - (1 + sizeof(msg->payload)), 100);
 
             // and get the payload if there is any
             if (msg->len <= SdepMaxPayload) {
-                spi_recv_bytes(msg->payload, msg->len);
+                spi_receive(msg->payload, msg->len, 100);
             }
             success = true;
             break;
         } while (timer_elapsed(timerStart) < timeout);
 
-        digitalWrite(AdafruitBleCSPin, PinLevelHigh);
+        spi_stop();
     }
     return success;
 }
@@ -320,7 +236,7 @@ static void resp_buf_read_one(bool greedy) {
         return;
     }
 
-    if (digitalRead(AdafruitBleIRQPin)) {
+    if (readPin(AdafruitBleIRQPin)) {
         struct sdep_msg msg;
 
     again:
@@ -331,7 +247,7 @@ static void resp_buf_read_one(bool greedy) {
                 dprintf("recv latency %dms\n", TIMER_DIFF_16(timer_read(), last_send));
             }
 
-            if (greedy && resp_buf.peek(last_send) && digitalRead(AdafruitBleIRQPin)) {
+            if (greedy && resp_buf.peek(last_send) && readPin(AdafruitBleIRQPin)) {
                 goto again;
             }
         }
@@ -361,7 +277,7 @@ static void send_buf_send_one(uint16_t timeout = SdepTimeout) {
         dprintf("send_buf_send_one: have %d remaining\n", (int)send_buf.size());
     } else {
         dprint("failed to send, will retry\n");
-        _delay_ms(SdepTimeout);
+        wait_ms(SdepTimeout);
         resp_buf_read_one(true);
     }
 }
@@ -382,20 +298,18 @@ static bool ble_init(void) {
     state.configured   = false;
     state.is_connected = false;
 
-    pinMode(AdafruitBleIRQPin, PinDirectionInput);
-    pinMode(AdafruitBleCSPin, PinDirectionOutput);
-    digitalWrite(AdafruitBleCSPin, PinLevelHigh);
+    setPinInput(AdafruitBleIRQPin);
 
-    SPI_init(&spi);
+    spi_init();
 
     // Perform a hardware reset
-    pinMode(AdafruitBleResetPin, PinDirectionOutput);
-    digitalWrite(AdafruitBleResetPin, PinLevelHigh);
-    digitalWrite(AdafruitBleResetPin, PinLevelLow);
-    _delay_ms(10);
-    digitalWrite(AdafruitBleResetPin, PinLevelHigh);
+    setPinOutput(AdafruitBleResetPin);
+    writePinHigh(AdafruitBleResetPin);
+    writePinLow(AdafruitBleResetPin);
+    wait_ms(10);
+    writePinHigh(AdafruitBleResetPin);
 
-    _delay_ms(1000);  // Give it a second to initialize
+    wait_ms(1000);  // Give it a second to initialize
 
     state.initialized = true;
     return state.initialized;
@@ -596,7 +510,7 @@ void adafruit_ble_task(void) {
     resp_buf_read_one(true);
     send_buf_send_one(SdepShortTimeout);
 
-    if (resp_buf.empty() && (state.event_flags & UsingEvents) && digitalRead(AdafruitBleIRQPin)) {
+    if (resp_buf.empty() && (state.event_flags & UsingEvents) && readPin(AdafruitBleIRQPin)) {
         // Must be an event update
         if (at_command_P(PSTR("AT+EVENTSTATUS"), resbuf, sizeof(resbuf))) {
             uint32_t mask = strtoul(resbuf, NULL, 16);