aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/_summary.md1
-rw-r--r--docs/de/_summary.md1
-rw-r--r--docs/es/_summary.md1
-rw-r--r--docs/fr-fr/_summary.md3
-rw-r--r--docs/he-il/_summary.md1
-rw-r--r--docs/ja/_summary.md1
-rw-r--r--docs/pt-br/_summary.md1
-rw-r--r--docs/ru-ru/_summary.md1
-rw-r--r--docs/spi_driver.md128
-rw-r--r--docs/zh-cn/_summary.md1
-rw-r--r--drivers/avr/spi_master.c163
-rw-r--r--drivers/avr/spi_master.h57
-rw-r--r--tmk_core/protocol/lufa.mk1
-rw-r--r--tmk_core/protocol/lufa/adafruit_ble.cpp162
14 files changed, 397 insertions, 125 deletions
diff --git a/docs/_summary.md b/docs/_summary.md
index 4a6e6996e..e35125109 100644
--- a/docs/_summary.md
+++ b/docs/_summary.md
@@ -121,6 +121,7 @@
121 * [Drivers](hardware_drivers.md) 121 * [Drivers](hardware_drivers.md)
122 * [ADC Driver](adc_driver.md) 122 * [ADC Driver](adc_driver.md)
123 * [I2C Driver](i2c_driver.md) 123 * [I2C Driver](i2c_driver.md)
124 * [SPI Driver](spi_driver.md)
124 * [WS2812 Driver](ws2812_driver.md) 125 * [WS2812 Driver](ws2812_driver.md)
125 * [EEPROM Driver](eeprom_driver.md) 126 * [EEPROM Driver](eeprom_driver.md)
126 * [GPIO Controls](internals_gpio_control.md) 127 * [GPIO Controls](internals_gpio_control.md)
diff --git a/docs/de/_summary.md b/docs/de/_summary.md
index a894420a2..19c75ecd3 100644
--- a/docs/de/_summary.md
+++ b/docs/de/_summary.md
@@ -98,6 +98,7 @@
98 * [ISP Flashing Guide](de/isp_flashing_guide.md) 98 * [ISP Flashing Guide](de/isp_flashing_guide.md)
99 * [ARM Debugging Guide](de/arm_debugging.md) 99 * [ARM Debugging Guide](de/arm_debugging.md)
100 * [I2C Driver](de/i2c_driver.md) 100 * [I2C Driver](de/i2c_driver.md)
101 * [SPI Driver](de/spi_driver.md)
101 * [GPIO Controls](de/internals_gpio_control.md) 102 * [GPIO Controls](de/internals_gpio_control.md)
102 * [Proton C Conversion](de/proton_c_conversion.md) 103 * [Proton C Conversion](de/proton_c_conversion.md)
103 104
diff --git a/docs/es/_summary.md b/docs/es/_summary.md
index 7dffea7d2..b58d825f7 100644
--- a/docs/es/_summary.md
+++ b/docs/es/_summary.md
@@ -98,6 +98,7 @@
98 * [Guía de flasheado de ISP](es/isp_flashing_guide.md) 98 * [Guía de flasheado de ISP](es/isp_flashing_guide.md)
99 * [Guía de depuración de ARM](es/arm_debugging.md) 99 * [Guía de depuración de ARM](es/arm_debugging.md)
100 * [Driver I2C](es/i2c_driver.md) 100 * [Driver I2C](es/i2c_driver.md)
101 * [Driver SPI](es/spi_driver.md)
101 * [Controles GPIO](es/internals_gpio_control.md) 102 * [Controles GPIO](es/internals_gpio_control.md)
102 * [Conversión Proton C](es/proton_c_conversion.md) 103 * [Conversión Proton C](es/proton_c_conversion.md)
103 104
diff --git a/docs/fr-fr/_summary.md b/docs/fr-fr/_summary.md
index bb14d2f0a..25a593b2e 100644
--- a/docs/fr-fr/_summary.md
+++ b/docs/fr-fr/_summary.md
@@ -101,7 +101,8 @@
101 * [Guide des claviers soudés à la main](fr-fr/hand_wire.md) 101 * [Guide des claviers soudés à la main](fr-fr/hand_wire.md)
102 * [Guide de flash de l’ISP](fr-fr/isp_flashing_guide.md) 102 * [Guide de flash de l’ISP](fr-fr/isp_flashing_guide.md)
103 * [Guide du débogage ARM](fr-fr/arm_debugging.md) 103 * [Guide du débogage ARM](fr-fr/arm_debugging.md)
104 * [Drivers i2c](fr-fr/i2c_driver.md) 104 * [Drivers I2C](fr-fr/i2c_driver.md)
105 * [Drivers SPI](fr-fr/spi_driver.md)
105 * [Contrôles des GPIO](fr-fr/internals_gpio_control.md) 106 * [Contrôles des GPIO](fr-fr/internals_gpio_control.md)
106 * [Conversion en Proton C](fr-fr/proton_c_conversion.md) 107 * [Conversion en Proton C](fr-fr/proton_c_conversion.md)
107 108
diff --git a/docs/he-il/_summary.md b/docs/he-il/_summary.md
index 21059f997..bdacd0d1f 100644
--- a/docs/he-il/_summary.md
+++ b/docs/he-il/_summary.md
@@ -114,6 +114,7 @@
114 * [מדריך לצריבת ISP](he-il/isp_flashing_guide.md) 114 * [מדריך לצריבת ISP](he-il/isp_flashing_guide.md)
115 * [מדריך לדיבאגינג ARM](he-il/arm_debugging.md) 115 * [מדריך לדיבאגינג ARM](he-il/arm_debugging.md)
116 * [מנהל התקן I2C](he-il/i2c_driver.md) 116 * [מנהל התקן I2C](he-il/i2c_driver.md)
117 * [מנהל התקן SPI](he-il/spi_driver.md)
117 * [בקרת GPIO](he-il/internals_gpio_control.md) 118 * [בקרת GPIO](he-il/internals_gpio_control.md)
118 * [המרת Proton C](he-il/proton_c_conversion.md) 119 * [המרת Proton C](he-il/proton_c_conversion.md)
119 120
diff --git a/docs/ja/_summary.md b/docs/ja/_summary.md
index 10279471a..e6423c6c2 100644
--- a/docs/ja/_summary.md
+++ b/docs/ja/_summary.md
@@ -121,6 +121,7 @@
121 * [ドライバ](ja/hardware_drivers.md) 121 * [ドライバ](ja/hardware_drivers.md)
122 * [ADC ドライバ](ja/adc_driver.md) 122 * [ADC ドライバ](ja/adc_driver.md)
123 * [I2C ドライバ](ja/i2c_driver.md) 123 * [I2C ドライバ](ja/i2c_driver.md)
124 * [SPI ドライバ](ja/spi_driver.md)
124 * [WS2812 ドライバ](ja/ws2812_driver.md) 125 * [WS2812 ドライバ](ja/ws2812_driver.md)
125 * [EEPROM ドライバ](ja/eeprom_driver.md) 126 * [EEPROM ドライバ](ja/eeprom_driver.md)
126 * [GPIO コントロール](ja/internals_gpio_control.md) 127 * [GPIO コントロール](ja/internals_gpio_control.md)
diff --git a/docs/pt-br/_summary.md b/docs/pt-br/_summary.md
index 9c29c5a3a..78b3b2021 100644
--- a/docs/pt-br/_summary.md
+++ b/docs/pt-br/_summary.md
@@ -98,6 +98,7 @@
98 * [ISP Flashing Guide](pt-br/isp_flashing_guide.md) 98 * [ISP Flashing Guide](pt-br/isp_flashing_guide.md)
99 * [ARM Debugging Guide](pt-br/arm_debugging.md) 99 * [ARM Debugging Guide](pt-br/arm_debugging.md)
100 * [I2C Driver](pt-br/i2c_driver.md) 100 * [I2C Driver](pt-br/i2c_driver.md)
101 * [SPI Driver](pt-br/spi_driver.md)
101 * [GPIO Controls](pt-br/internals_gpio_control.md) 102 * [GPIO Controls](pt-br/internals_gpio_control.md)
102 * [Proton C Conversion](pt-br/proton_c_conversion.md) 103 * [Proton C Conversion](pt-br/proton_c_conversion.md)
103 104
diff --git a/docs/ru-ru/_summary.md b/docs/ru-ru/_summary.md
index caa7cdd56..f893be3cf 100644
--- a/docs/ru-ru/_summary.md
+++ b/docs/ru-ru/_summary.md
@@ -99,6 +99,7 @@
99 * [ISP Flashing Guide](ru-ru/isp_flashing_guide.md) 99 * [ISP Flashing Guide](ru-ru/isp_flashing_guide.md)
100 * [ARM Debugging Guide](ru-ru/arm_debugging.md) 100 * [ARM Debugging Guide](ru-ru/arm_debugging.md)
101 * [I2C Driver](ru-ru/i2c_driver.md) 101 * [I2C Driver](ru-ru/i2c_driver.md)
102 * [SPI Driver](ru-ru/spi_driver.md)
102 * [WS2812 Driver](ru-ru/ws2812_driver.md) 103 * [WS2812 Driver](ru-ru/ws2812_driver.md)
103 * [GPIO Controls](ru-ru/internals_gpio_control.md) 104 * [GPIO Controls](ru-ru/internals_gpio_control.md)
104 * [Proton C Conversion](ru-ru/proton_c_conversion.md) 105 * [Proton C Conversion](ru-ru/proton_c_conversion.md)
diff --git a/docs/spi_driver.md b/docs/spi_driver.md
new file mode 100644
index 000000000..360796d2a
--- /dev/null
+++ b/docs/spi_driver.md
@@ -0,0 +1,128 @@
1# SPI Master Driver
2
3The SPI Master drivers used in QMK have a set of common functions to allow portability between MCUs.
4
5## AVR Configuration
6
7No special setup is required - just connect the `SS`, `SCK`, `MOSI` and `MISO` pins of your SPI devices to the matching pins on the MCU:
8
9|MCU |`SS`|`SCK`|`MOSI`|`MISO`|
10|---------------|----|-----|------|------|
11|ATMega16/32U2/4|`B0`|`B1` |`B2` |`B3` |
12|AT90USB64/128 |`B0`|`B1` |`B2` |`B3` |
13|ATmega32A |`B4`|`B7` |`B5` |`B6` |
14|ATmega328P |`B2`|`B5` |`B3` |`B4` |
15
16You may use more than one slave select pin, not just the `SS` pin. This is useful when you have multiple devices connected and need to communicate with them individually.
17`SPI_SS_PIN` can be passed to `spi_start()` to refer to `SS`.
18
19## ARM Configuration
20
21ARM support for this driver is not ready yet. Check back later!
22
23## Functions
24
25### `void spi_init(void)`
26
27Initialize the SPI driver. This function must be called only once, before any of the below functions can be called.
28
29---
30
31### `void spi_start(pin_t slavePin, bool lsbFirst, uint8_t mode, uint8_t divisor)`
32
33Start an SPI transaction.
34
35#### Arguments
36
37 - `pin_t slavePin`
38 The QMK pin to assert as the slave select pin, eg. `B4`.
39 - `bool lsbFirst`
40 Determines the endianness of the transmission. If `true`, the least significant bit of each byte is sent first.
41 - `uint8_t mode`
42 The SPI mode to use:
43
44 |Mode|Clock Polarity |Clock Phase |
45 |----|--------------------|-----------------------|
46 |`0` |Leading edge rising |Sample on leading edge |
47 |`1` |Leading edge rising |Sample on trailing edge|
48 |`2` |Leading edge falling|Sample on leading edge |
49 |`3` |Leading edge falling|Sample on trailing edge|
50
51 - `uint8_t divisor`
52 The SPI clock divisor, will be rounded up to the nearest power of two. This number can be calculated by dividing the MCU's clock speed by the desired SPI clock speed. For example, an MCU running at 8 MHz wanting to talk to an SPI device at 4 MHz would set the divisor to `2`.
53
54---
55
56### `spi_status_t spi_write(uint8_t data, uint16_t timeout)`
57
58Write a byte to the selected SPI device.
59
60#### Arguments
61
62 - `uint8_t data`
63 The byte to write.
64 - `uint16_t timeout`
65 The amount of time to wait, in milliseconds, before timing out.
66
67#### Return Value
68
69`SPI_STATUS_TIMEOUT` if the timeout period elapses, or `SPI_STATUS_SUCCESS`.
70
71---
72
73### `spi_status_t spi_read(uint16_t timeout)`
74
75Read a byte from the selected SPI device.
76
77#### Arguments
78
79 - `uint16_t timeout`
80 The amount of time to wait, in milliseconds, before timing out.
81
82#### Return Value
83
84`SPI_STATUS_TIMEOUT` if the timeout period elapses, or the byte read from the device.
85
86---
87
88### `spi_status_t spi_transmit(const uint8_t *data, uint16_t length, uint16_t timeout)`
89
90Send multiple bytes to the selected SPI device.
91
92#### Arguments
93
94 - `const uint8_t *data`
95 A pointer to the data to write from.
96 - `uint16_t length`
97 The number of bytes to write. Take care not to overrun the length of `data`.
98 - `uint16_t timeout`
99 The amount of time to wait, in milliseconds, before timing out.
100
101#### Return Value
102
103`SPI_STATUS_TIMEOUT` if the timeout period elapses, `SPI_STATUS_SUCCESS` on success, or `SPI_STATUS_ERROR` otherwise.
104
105---
106
107### `spi_status_t spi_receive(uint8_t *data, uint16_t length, uint16_t timeout)`
108
109Receive multiple bytes from the selected SPI device.
110
111#### Arguments
112
113 - `uint8_t *data`
114 A pointer to the buffer to read into.
115 - `uint16_t length`
116 The number of bytes to read. Take care not to overrun the length of `data`.
117 - `uint16_t timeout`
118 The amount of time to wait, in milliseconds, before timing out.
119
120#### Return Value
121
122`SPI_STATUS_TIMEOUT` if the timeout period elapses, `SPI_STATUS_SUCCESS` on success, or `SPI_STATUS_ERROR` otherwise.
123
124---
125
126### `void spi_stop(void)`
127
128End the current SPI transaction. This will deassert the slave select pin and reset the endianness, mode and divisor configured by `spi_start()`.
diff --git a/docs/zh-cn/_summary.md b/docs/zh-cn/_summary.md
index 12bd07a21..201b83894 100644
--- a/docs/zh-cn/_summary.md
+++ b/docs/zh-cn/_summary.md
@@ -104,6 +104,7 @@
104 * [ARM调试指南](zh-cn/arm_debugging.md) 104 * [ARM调试指南](zh-cn/arm_debugging.md)
105 * [ADC设备](zh-cn/adc_driver.md) 105 * [ADC设备](zh-cn/adc_driver.md)
106 * [I2C设备](zh-cn/i2c_driver.md) 106 * [I2C设备](zh-cn/i2c_driver.md)
107 * [SPI设备](zh-cn/spi_driver.md)
107 * [WS2812设备](zh-cn/ws2812_driver.md) 108 * [WS2812设备](zh-cn/ws2812_driver.md)
108 * [EEPROM设备](zh-cn/eeprom_driver.md) 109 * [EEPROM设备](zh-cn/eeprom_driver.md)
109 * [GPIO控制](zh-cn/internals_gpio_control.md) 110 * [GPIO控制](zh-cn/internals_gpio_control.md)
diff --git a/drivers/avr/spi_master.c b/drivers/avr/spi_master.c
new file mode 100644
index 000000000..497d50536
--- /dev/null
+++ b/drivers/avr/spi_master.c
@@ -0,0 +1,163 @@
1/* Copyright 2020
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <https://www.gnu.org/licenses/>.
15 */
16
17#include <avr/io.h>
18
19#include "spi_master.h"
20#include "quantum.h"
21#include "timer.h"
22
23#if defined(__AVR_ATmega16U2__) || defined(__AVR_ATmega32U2__) || defined(__AVR_ATmega16U4__) || defined(__AVR_ATmega32U4__) || defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB647__) || defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB1287__)
24# define SPI_SCK_PIN B1
25# define SPI_MOSI_PIN B2
26# define SPI_MISO_PIN B3
27#elif defined(__AVR_ATmega32A__)
28# define SPI_SCK_PIN B7
29# define SPI_MOSI_PIN B5
30# define SPI_MISO_PIN B6
31#elif defined(__AVR_ATmega328P__)
32# define SPI_SCK_PIN B5
33# define SPI_MOSI_PIN B3
34# define SPI_MISO_PIN B4
35#endif
36
37static pin_t currentSlavePin = NO_PIN;
38static uint8_t currentSlaveConfig = 0;
39static bool currentSlave2X = false;
40
41void spi_init(void) {
42 writePinHigh(SPI_SS_PIN);
43 setPinOutput(SPI_SCK_PIN);
44 setPinOutput(SPI_MOSI_PIN);
45 setPinInput(SPI_MISO_PIN);
46
47 SPCR = (_BV(SPE) | _BV(MSTR));
48}
49
50void spi_start(pin_t slavePin, bool lsbFirst, uint8_t mode, uint8_t divisor) {
51 if (currentSlavePin == NO_PIN && slavePin != NO_PIN) {
52 if (lsbFirst) {
53 currentSlaveConfig |= _BV(DORD);
54 }
55
56 switch (mode) {
57 case 1:
58 currentSlaveConfig |= _BV(CPHA);
59 break;
60 case 2:
61 currentSlaveConfig |= _BV(CPOL);
62 break;
63 case 3:
64 currentSlaveConfig |= (_BV(CPOL) | _BV(CPHA));
65 break;
66 }
67
68 uint8_t roundedDivisor = 1;
69 while (roundedDivisor < divisor) {
70 roundedDivisor <<= 1;
71 }
72
73 switch (roundedDivisor) {
74 case 16:
75 currentSlaveConfig |= _BV(SPR0);
76 break;
77 case 64:
78 currentSlaveConfig |= _BV(SPR1);
79 break;
80 case 128:
81 currentSlaveConfig |= (_BV(SPR1) | _BV(SPR0));
82 break;
83 case 2:
84 currentSlave2X = true;
85 break;
86 case 8:
87 currentSlave2X = true;
88 currentSlaveConfig |= _BV(SPR0);
89 break;
90 case 32:
91 currentSlave2X = true;
92 currentSlaveConfig |= _BV(SPR1);
93 break;
94 }
95
96 SPSR |= currentSlaveConfig;
97 currentSlavePin = slavePin;
98 setPinOutput(currentSlavePin);
99 writePinLow(currentSlavePin);
100 }
101}
102
103spi_status_t spi_write(uint8_t data, uint16_t timeout) {
104 SPDR = data;
105
106 uint16_t timeout_timer = timer_read();
107 while (!(SPSR & _BV(SPIF))) {
108 if ((timeout != SPI_TIMEOUT_INFINITE) && ((timer_read() - timeout_timer) >= timeout)) {
109 return SPI_STATUS_TIMEOUT;
110 }
111 }
112
113 return SPDR;
114}
115
116spi_status_t spi_read(uint16_t timeout) {
117 SPDR = 0x00; // Dummy
118
119 uint16_t timeout_timer = timer_read();
120 while (!(SPSR & _BV(SPIF))) {
121 if ((timeout != SPI_TIMEOUT_INFINITE) && ((timer_read() - timeout_timer) >= timeout)) {
122 return SPI_STATUS_TIMEOUT;
123 }
124 }
125
126 return SPDR;
127}
128
129spi_status_t spi_transmit(const uint8_t *data, uint16_t length, uint16_t timeout) {
130 spi_status_t status = SPI_STATUS_ERROR;
131
132 for (uint16_t i = 0; i < length; i++) {
133 status = spi_write(data[i], timeout);
134 }
135
136 return status;
137}
138
139spi_status_t spi_receive(uint8_t *data, uint16_t length, uint16_t timeout) {
140 spi_status_t status = SPI_STATUS_ERROR;
141
142 for (uint16_t i = 0; i < length; i++) {
143 status = spi_read(timeout);
144
145 if (status > 0) {
146 data[i] = status;
147 }
148 }
149
150 return (status < 0) ? status : SPI_STATUS_SUCCESS;
151}
152
153void spi_stop(void) {
154 if (currentSlavePin != NO_PIN) {
155 setPinOutput(currentSlavePin);
156 writePinHigh(currentSlavePin);
157 currentSlavePin = NO_PIN;
158 SPCR &= ~(currentSlaveConfig);
159 currentSlaveConfig = 0;
160 SPSR = 0;
161 currentSlave2X = false;
162 }
163}
diff --git a/drivers/avr/spi_master.h b/drivers/avr/spi_master.h
new file mode 100644
index 000000000..0bab2dc24
--- /dev/null
+++ b/drivers/avr/spi_master.h
@@ -0,0 +1,57 @@
1/* Copyright 2020
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <https://www.gnu.org/licenses/>.
15 */
16
17#pragma once
18
19#include "quantum.h"
20
21typedef int16_t spi_status_t;
22
23// Hardware SS pin is defined in the header so that user code can refer to it
24#if defined(__AVR_ATmega16U2__) || defined(__AVR_ATmega32U2__) || defined(__AVR_ATmega16U4__) || defined(__AVR_ATmega32U4__) || defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB647__) || defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB1287__)
25# define SPI_SS_PIN B0
26#elif defined(__AVR_ATmega32A__)
27# define SPI_SS_PIN B4
28#elif defined(__AVR_ATmega328P__)
29# define SPI_SS_PIN B2
30#endif
31
32#define SPI_STATUS_SUCCESS (0)
33#define SPI_STATUS_ERROR (-1)
34#define SPI_STATUS_TIMEOUT (-2)
35
36#define SPI_TIMEOUT_IMMEDIATE (0)
37#define SPI_TIMEOUT_INFINITE (0xFFFF)
38
39#ifdef __cplusplus
40extern "C" {
41#endif
42void spi_init(void);
43
44void spi_start(pin_t slavePin, bool lsbFirst, uint8_t mode, uint8_t divisor);
45
46spi_status_t spi_write(uint8_t data, uint16_t timeout);
47
48spi_status_t spi_read(uint16_t timeout);
49
50spi_status_t spi_transmit(const uint8_t *data, uint16_t length, uint16_t timeout);
51
52spi_status_t spi_receive(uint8_t *data, uint16_t length, uint16_t timeout);
53
54void spi_stop(void);
55#ifdef __cplusplus
56}
57#endif
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);