aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/spi_driver.md31
-rw-r--r--drivers/avr/spi_master.c123
-rw-r--r--drivers/avr/spi_master.h10
-rw-r--r--tmk_core/protocol/lufa/adafruit_ble.cpp10
4 files changed, 90 insertions, 84 deletions
diff --git a/docs/spi_driver.md b/docs/spi_driver.md
index 360796d2a..e2b5b140b 100644
--- a/docs/spi_driver.md
+++ b/docs/spi_driver.md
@@ -16,7 +16,7 @@ No special setup is required - just connect the `SS`, `SCK`, `MOSI` and `MISO` p
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. 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`. 17`SPI_SS_PIN` can be passed to `spi_start()` to refer to `SS`.
18 18
19## ARM Configuration 19## ChibiOS/ARM Configuration
20 20
21ARM support for this driver is not ready yet. Check back later! 21ARM support for this driver is not ready yet. Check back later!
22 22
@@ -28,7 +28,7 @@ Initialize the SPI driver. This function must be called only once, before any of
28 28
29--- 29---
30 30
31### `void spi_start(pin_t slavePin, bool lsbFirst, uint8_t mode, uint8_t divisor)` 31### `bool spi_start(pin_t slavePin, bool lsbFirst, uint8_t mode, uint16_t divisor)`
32 32
33Start an SPI transaction. 33Start an SPI transaction.
34 34
@@ -48,12 +48,16 @@ Start an SPI transaction.
48 |`2` |Leading edge falling|Sample on leading edge | 48 |`2` |Leading edge falling|Sample on leading edge |
49 |`3` |Leading edge falling|Sample on trailing edge| 49 |`3` |Leading edge falling|Sample on trailing edge|
50 50
51 - `uint8_t divisor` 51 - `uint16_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`. 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 53
54#### Return Value
55
56`false` if the supplied parameters are invalid or the SPI peripheral is already in use, or `true`.
57
54--- 58---
55 59
56### `spi_status_t spi_write(uint8_t data, uint16_t timeout)` 60### `spi_status_t spi_write(uint8_t data)`
57 61
58Write a byte to the selected SPI device. 62Write a byte to the selected SPI device.
59 63
@@ -61,8 +65,6 @@ Write a byte to the selected SPI device.
61 65
62 - `uint8_t data` 66 - `uint8_t data`
63 The byte to write. 67 The byte to write.
64 - `uint16_t timeout`
65 The amount of time to wait, in milliseconds, before timing out.
66 68
67#### Return Value 69#### Return Value
68 70
@@ -70,22 +72,17 @@ Write a byte to the selected SPI device.
70 72
71--- 73---
72 74
73### `spi_status_t spi_read(uint16_t timeout)` 75### `spi_status_t spi_read(void)`
74 76
75Read a byte from the selected SPI device. 77Read a byte from the selected SPI device.
76 78
77#### Arguments
78
79 - `uint16_t timeout`
80 The amount of time to wait, in milliseconds, before timing out.
81
82#### Return Value 79#### Return Value
83 80
84`SPI_STATUS_TIMEOUT` if the timeout period elapses, or the byte read from the device. 81`SPI_STATUS_TIMEOUT` if the timeout period elapses, or the byte read from the device.
85 82
86--- 83---
87 84
88### `spi_status_t spi_transmit(const uint8_t *data, uint16_t length, uint16_t timeout)` 85### `spi_status_t spi_transmit(const uint8_t *data, uint16_t length)`
89 86
90Send multiple bytes to the selected SPI device. 87Send multiple bytes to the selected SPI device.
91 88
@@ -95,8 +92,6 @@ Send multiple bytes to the selected SPI device.
95 A pointer to the data to write from. 92 A pointer to the data to write from.
96 - `uint16_t length` 93 - `uint16_t length`
97 The number of bytes to write. Take care not to overrun the length of `data`. 94 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 95
101#### Return Value 96#### Return Value
102 97
@@ -104,7 +99,7 @@ Send multiple bytes to the selected SPI device.
104 99
105--- 100---
106 101
107### `spi_status_t spi_receive(uint8_t *data, uint16_t length, uint16_t timeout)` 102### `spi_status_t spi_receive(uint8_t *data, uint16_t length)`
108 103
109Receive multiple bytes from the selected SPI device. 104Receive multiple bytes from the selected SPI device.
110 105
@@ -114,12 +109,10 @@ Receive multiple bytes from the selected SPI device.
114 A pointer to the buffer to read into. 109 A pointer to the buffer to read into.
115 - `uint16_t length` 110 - `uint16_t length`
116 The number of bytes to read. Take care not to overrun the length of `data`. 111 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 112
120#### Return Value 113#### Return Value
121 114
122`SPI_STATUS_TIMEOUT` if the timeout period elapses, `SPI_STATUS_SUCCESS` on success, or `SPI_STATUS_ERROR` otherwise. 115`SPI_STATUS_TIMEOUT` if the internal transmission timeout period elapses, `SPI_STATUS_SUCCESS` on success, or `SPI_STATUS_ERROR` otherwise.
123 116
124--- 117---
125 118
diff --git a/drivers/avr/spi_master.c b/drivers/avr/spi_master.c
index 3f405ddf5..32cc55c83 100644
--- a/drivers/avr/spi_master.c
+++ b/drivers/avr/spi_master.c
@@ -34,6 +34,10 @@
34# define SPI_MISO_PIN B4 34# define SPI_MISO_PIN B4
35#endif 35#endif
36 36
37#ifndef SPI_TIMEOUT
38# define SPI_TIMEOUT 100
39#endif
40
37static pin_t currentSlavePin = NO_PIN; 41static pin_t currentSlavePin = NO_PIN;
38static uint8_t currentSlaveConfig = 0; 42static uint8_t currentSlaveConfig = 0;
39static bool currentSlave2X = false; 43static bool currentSlave2X = false;
@@ -47,65 +51,74 @@ void spi_init(void) {
47 SPCR = (_BV(SPE) | _BV(MSTR)); 51 SPCR = (_BV(SPE) | _BV(MSTR));
48} 52}
49 53
50void spi_start(pin_t slavePin, bool lsbFirst, uint8_t mode, uint8_t divisor) { 54bool spi_start(pin_t slavePin, bool lsbFirst, uint8_t mode, uint16_t divisor) {
51 if (currentSlavePin == NO_PIN && slavePin != NO_PIN) { 55 if (currentSlavePin != NO_PIN || slavePin == NO_PIN) {
52 if (lsbFirst) { 56 return false;
53 currentSlaveConfig |= _BV(DORD); 57 }
54 }
55 58
56 switch (mode) { 59 currentSlaveConfig = 0;
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 60
68 uint8_t roundedDivisor = 1; 61 if (lsbFirst) {
69 while (roundedDivisor < divisor) { 62 currentSlaveConfig |= _BV(DORD);
70 roundedDivisor <<= 1; 63 }
71 }
72 64
73 switch (roundedDivisor) { 65 switch (mode) {
74 case 16: 66 case 1:
75 currentSlaveConfig |= _BV(SPR0); 67 currentSlaveConfig |= _BV(CPHA);
76 break; 68 break;
77 case 64: 69 case 2:
78 currentSlaveConfig |= _BV(SPR1); 70 currentSlaveConfig |= _BV(CPOL);
79 break; 71 break;
80 case 128: 72 case 3:
81 currentSlaveConfig |= (_BV(SPR1) | _BV(SPR0)); 73 currentSlaveConfig |= (_BV(CPOL) | _BV(CPHA));
82 break; 74 break;
83 case 2: 75 }
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 76
96 SPSR |= currentSlaveConfig; 77 uint16_t roundedDivisor = 1;
97 currentSlavePin = slavePin; 78 while (roundedDivisor < divisor) {
98 setPinOutput(currentSlavePin); 79 roundedDivisor <<= 1;
99 writePinLow(currentSlavePin); 80 }
81
82 switch (roundedDivisor) {
83 case 16:
84 currentSlaveConfig |= _BV(SPR0);
85 break;
86 case 64:
87 currentSlaveConfig |= _BV(SPR1);
88 break;
89 case 128:
90 currentSlaveConfig |= (_BV(SPR1) | _BV(SPR0));
91 break;
92 case 2:
93 currentSlave2X = true;
94 break;
95 case 8:
96 currentSlave2X = true;
97 currentSlaveConfig |= _BV(SPR0);
98 break;
99 case 32:
100 currentSlave2X = true;
101 currentSlaveConfig |= _BV(SPR1);
102 break;
100 } 103 }
104
105 SPCR |= currentSlaveConfig;
106 if (currentSlave2X) {
107 SPSR |= _BV(SPI2X);
108 }
109 currentSlavePin = slavePin;
110 setPinOutput(currentSlavePin);
111 writePinLow(currentSlavePin);
112
113 return true;
101} 114}
102 115
103spi_status_t spi_write(uint8_t data, uint16_t timeout) { 116spi_status_t spi_write(uint8_t data) {
104 SPDR = data; 117 SPDR = data;
105 118
106 uint16_t timeout_timer = timer_read(); 119 uint16_t timeout_timer = timer_read();
107 while (!(SPSR & _BV(SPIF))) { 120 while (!(SPSR & _BV(SPIF))) {
108 if ((timeout != SPI_TIMEOUT_INFINITE) && ((timer_read() - timeout_timer) >= timeout)) { 121 if ((timer_read() - timeout_timer) >= SPI_TIMEOUT) {
109 return SPI_STATUS_TIMEOUT; 122 return SPI_STATUS_TIMEOUT;
110 } 123 }
111 } 124 }
@@ -113,12 +126,12 @@ spi_status_t spi_write(uint8_t data, uint16_t timeout) {
113 return SPDR; 126 return SPDR;
114} 127}
115 128
116spi_status_t spi_read(uint16_t timeout) { 129spi_status_t spi_read() {
117 SPDR = 0x00; // Dummy 130 SPDR = 0x00; // Dummy
118 131
119 uint16_t timeout_timer = timer_read(); 132 uint16_t timeout_timer = timer_read();
120 while (!(SPSR & _BV(SPIF))) { 133 while (!(SPSR & _BV(SPIF))) {
121 if ((timeout != SPI_TIMEOUT_INFINITE) && ((timer_read() - timeout_timer) >= timeout)) { 134 if ((timer_read() - timeout_timer) >= SPI_TIMEOUT) {
122 return SPI_STATUS_TIMEOUT; 135 return SPI_STATUS_TIMEOUT;
123 } 136 }
124 } 137 }
@@ -126,21 +139,21 @@ spi_status_t spi_read(uint16_t timeout) {
126 return SPDR; 139 return SPDR;
127} 140}
128 141
129spi_status_t spi_transmit(const uint8_t *data, uint16_t length, uint16_t timeout) { 142spi_status_t spi_transmit(const uint8_t *data, uint16_t length) {
130 spi_status_t status = SPI_STATUS_ERROR; 143 spi_status_t status = SPI_STATUS_ERROR;
131 144
132 for (uint16_t i = 0; i < length; i++) { 145 for (uint16_t i = 0; i < length; i++) {
133 status = spi_write(data[i], timeout); 146 status = spi_write(data[i]);
134 } 147 }
135 148
136 return status; 149 return status;
137} 150}
138 151
139spi_status_t spi_receive(uint8_t *data, uint16_t length, uint16_t timeout) { 152spi_status_t spi_receive(uint8_t *data, uint16_t length) {
140 spi_status_t status = SPI_STATUS_ERROR; 153 spi_status_t status = SPI_STATUS_ERROR;
141 154
142 for (uint16_t i = 0; i < length; i++) { 155 for (uint16_t i = 0; i < length; i++) {
143 status = spi_read(timeout); 156 status = spi_read();
144 157
145 if (status > 0) { 158 if (status > 0) {
146 data[i] = status; 159 data[i] = status;
@@ -155,9 +168,9 @@ void spi_stop(void) {
155 setPinOutput(currentSlavePin); 168 setPinOutput(currentSlavePin);
156 writePinHigh(currentSlavePin); 169 writePinHigh(currentSlavePin);
157 currentSlavePin = NO_PIN; 170 currentSlavePin = NO_PIN;
171 SPSR &= ~(_BV(SPI2X));
158 SPCR &= ~(currentSlaveConfig); 172 SPCR &= ~(currentSlaveConfig);
159 currentSlaveConfig = 0; 173 currentSlaveConfig = 0;
160 SPSR = 0;
161 currentSlave2X = false; 174 currentSlave2X = false;
162 } 175 }
163} 176}
diff --git a/drivers/avr/spi_master.h b/drivers/avr/spi_master.h
index 0bab2dc24..b69c1cbd6 100644
--- a/drivers/avr/spi_master.h
+++ b/drivers/avr/spi_master.h
@@ -41,15 +41,15 @@ extern "C" {
41#endif 41#endif
42void spi_init(void); 42void spi_init(void);
43 43
44void spi_start(pin_t slavePin, bool lsbFirst, uint8_t mode, uint8_t divisor); 44bool spi_start(pin_t slavePin, bool lsbFirst, uint8_t mode, uint16_t divisor);
45 45
46spi_status_t spi_write(uint8_t data, uint16_t timeout); 46spi_status_t spi_write(uint8_t data);
47 47
48spi_status_t spi_read(uint16_t timeout); 48spi_status_t spi_read(void);
49 49
50spi_status_t spi_transmit(const uint8_t *data, uint16_t length, uint16_t timeout); 50spi_status_t spi_transmit(const uint8_t *data, uint16_t length);
51 51
52spi_status_t spi_receive(uint8_t *data, uint16_t length, uint16_t timeout); 52spi_status_t spi_receive(uint8_t *data, uint16_t length);
53 53
54void spi_stop(void); 54void spi_stop(void);
55#ifdef __cplusplus 55#ifdef __cplusplus
diff --git a/tmk_core/protocol/lufa/adafruit_ble.cpp b/tmk_core/protocol/lufa/adafruit_ble.cpp
index f04ab757e..b07407f38 100644
--- a/tmk_core/protocol/lufa/adafruit_ble.cpp
+++ b/tmk_core/protocol/lufa/adafruit_ble.cpp
@@ -152,7 +152,7 @@ static bool sdep_send_pkt(const struct sdep_msg *msg, uint16_t timeout) {
152 bool ready = false; 152 bool ready = false;
153 153
154 do { 154 do {
155 ready = spi_write(msg->type, 100) != SdepSlaveNotReady; 155 ready = spi_write(msg->type) != SdepSlaveNotReady;
156 if (ready) { 156 if (ready) {
157 break; 157 break;
158 } 158 }
@@ -165,7 +165,7 @@ static bool sdep_send_pkt(const struct sdep_msg *msg, uint16_t timeout) {
165 165
166 if (ready) { 166 if (ready) {
167 // Slave is ready; send the rest of the packet 167 // Slave is ready; send the rest of the packet
168 spi_transmit(&msg->cmd_low, sizeof(*msg) - (1 + sizeof(msg->payload)) + msg->len, 100); 168 spi_transmit(&msg->cmd_low, sizeof(*msg) - (1 + sizeof(msg->payload)) + msg->len);
169 success = true; 169 success = true;
170 } 170 }
171 171
@@ -205,7 +205,7 @@ static bool sdep_recv_pkt(struct sdep_msg *msg, uint16_t timeout) {
205 205
206 do { 206 do {
207 // Read the command type, waiting for the data to be ready 207 // Read the command type, waiting for the data to be ready
208 msg->type = spi_read(100); 208 msg->type = spi_read();
209 if (msg->type == SdepSlaveNotReady || msg->type == SdepSlaveOverflow) { 209 if (msg->type == SdepSlaveNotReady || msg->type == SdepSlaveOverflow) {
210 // Release it and let it initialize 210 // Release it and let it initialize
211 spi_stop(); 211 spi_stop();
@@ -215,11 +215,11 @@ static bool sdep_recv_pkt(struct sdep_msg *msg, uint16_t timeout) {
215 } 215 }
216 216
217 // Read the rest of the header 217 // Read the rest of the header
218 spi_receive(&msg->cmd_low, sizeof(*msg) - (1 + sizeof(msg->payload)), 100); 218 spi_receive(&msg->cmd_low, sizeof(*msg) - (1 + sizeof(msg->payload)));
219 219
220 // and get the payload if there is any 220 // and get the payload if there is any
221 if (msg->len <= SdepMaxPayload) { 221 if (msg->len <= SdepMaxPayload) {
222 spi_receive(msg->payload, msg->len, 100); 222 spi_receive(msg->payload, msg->len);
223 } 223 }
224 success = true; 224 success = true;
225 break; 225 break;