aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDimitris Papavasiliou <dpapavas@protonmail.ch>2021-04-20 20:17:39 +0300
committerGitHub <noreply@github.com>2021-04-20 10:17:39 -0700
commitbd07120d3303ee38498e01bbef9052d4d50f77f5 (patch)
tree48ac3549b24f43172ceea06ffdd18fc14c30ed62
parent4ff16fe73e0850beeca446d53902527c2cbabe8a (diff)
downloadqmk_firmware-bd07120d3303ee38498e01bbef9052d4d50f77f5.tar.gz
qmk_firmware-bd07120d3303ee38498e01bbef9052d4d50f77f5.zip
[Keyboard] Fix and improve SPI transport in the Lagrange (#12606)
Co-authored-by: Dimitris Papavasiliou <dpapavas@gmail.com>
-rw-r--r--keyboards/handwired/lagrange/transport.c81
1 files changed, 57 insertions, 24 deletions
diff --git a/keyboards/handwired/lagrange/transport.c b/keyboards/handwired/lagrange/transport.c
index 2a567f24b..8f6973925 100644
--- a/keyboards/handwired/lagrange/transport.c
+++ b/keyboards/handwired/lagrange/transport.c
@@ -18,6 +18,7 @@
18 18
19#include "quantum.h" 19#include "quantum.h"
20#include "split_util.h" 20#include "split_util.h"
21#include "transport.h"
21#include "timer.h" 22#include "timer.h"
22 23
23#include "lagrange.h" 24#include "lagrange.h"
@@ -32,15 +33,16 @@ uint8_t transceive(uint8_t b) {
32 return SPDR; 33 return SPDR;
33} 34}
34 35
35/* The SPI bus, doens't have any form of protocol built in, so when 36/* The SPI bus, doesn't have any form of protocol built in, so when
36 * the other side isn't present, any old noise on the line will appear 37 * the other side isn't present, any old noise on the line will appear
37 * as matrix data. To avoid interpreting data as keystrokes, we do a 38 * as matrix data. To avoid interpreting data as keystrokes, we do a
38 * simple n-way (8-way here) handshake before each scan, where each 39 * simple n-way (8-way here) handshake before each scan, where each
39 * side sends a prearranged sequence of bytes. */ 40 * side sends a prearranged sequence of bytes. */
40 41
41void shake_hands(bool master) { 42bool shake_hands(bool master) {
42 const uint8_t m = master ? 0xf8 : 0; 43 const uint8_t m = master ? 0xf8 : 0;
43 const uint8_t a = 0xa8 ^ m, b = 0x50 ^ m; 44 const uint8_t a = 0xa8 ^ m, b = 0x50 ^ m;
45 bool synchronized = true;
44 46
45 uint8_t i; 47 uint8_t i;
46 48
@@ -48,7 +50,7 @@ void shake_hands(bool master) {
48 i = SPDR; 50 i = SPDR;
49 51
50 do { 52 do {
51 /* Cylcling the SS pin on each attempt is necessary, as it 53 /* Cycling the SS pin on each attempt is necessary, as it
52 * resets the AVR's SPI core and guarantees proper 54 * resets the AVR's SPI core and guarantees proper
53 * alignment. */ 55 * alignment. */
54 56
@@ -58,6 +60,7 @@ void shake_hands(bool master) {
58 60
59 for (i = 0 ; i < 8 ; i += 1) { 61 for (i = 0 ; i < 8 ; i += 1) {
60 if (transceive(a + i) != b + i) { 62 if (transceive(a + i) != b + i) {
63 synchronized = false;
61 break; 64 break;
62 } 65 }
63 } 66 }
@@ -66,9 +69,11 @@ void shake_hands(bool master) {
66 writePinHigh(SPI_SS_PIN); 69 writePinHigh(SPI_SS_PIN);
67 } 70 }
68 } while (i < 8); 71 } while (i < 8);
72
73 return synchronized;
69} 74}
70 75
71bool transport_master(matrix_row_t matrix[]) { 76bool transport_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
72 const struct led_context context = { 77 const struct led_context context = {
73 host_keyboard_led_state(), 78 host_keyboard_led_state(),
74 layer_state 79 layer_state
@@ -76,32 +81,58 @@ bool transport_master(matrix_row_t matrix[]) {
76 81
77 uint8_t i; 82 uint8_t i;
78 83
79 /* Shake hands and then receive the matrix from the other side, 84 /* We shake hands both before and after transmitting the matrix.
80 * while transmitting LED and layer states. */ 85 * Doing it before transmitting is necessary to ensure
86 * synchronization: Due to the master-slave nature of the SPI bus,
87 * the master calls the shots. If we just go ahead and start
88 * clocking bits, the slave side might be otherwise engaged at
89 * that moment, so we'll initially read zeros, or garbage. Then
90 * when the slave gets around to transmitting its matrix, we'll
91 * misinterpret the keys it sends, leading to spurious
92 * keypresses. */
81 93
82 shake_hands(true); 94 /* The handshake forces the master to wait for the slave to be
95 * ready to start transmitting. */
96
97 do {
98 shake_hands(true);
83 99
84 spi_start(SPI_SS_PIN, 0, 0, 4); 100 /* Receive the matrix from the other side, while transmitting
101 * LED and layer states. */
85 102
86 for (i = 0 ; i < sizeof(matrix_row_t[MATRIX_ROWS / 2]) ; i += 1) { 103 spi_start(SPI_SS_PIN, 0, 0, 4);
87 spi_status_t x;
88 104
89 x = spi_write(i < sizeof(struct led_context) ? 105 for (i = 0 ; i < sizeof(matrix_row_t[MATRIX_ROWS / 2]) ; i += 1) {
90 ((uint8_t *)&context)[i] : 0); 106 spi_status_t x;
107
108 x = spi_write(i < sizeof(struct led_context) ?
109 ((uint8_t *)&context)[i] : 0);
110
111 if (x == SPI_STATUS_TIMEOUT) {
112 return false;
113 }
91 114
92 if (x == SPI_STATUS_TIMEOUT) { 115 ((uint8_t *)slave_matrix)[i] = (uint8_t)x;
93 return false;
94 } 116 }
95 117
96 ((uint8_t *)matrix)[i] = (uint8_t)x; 118 spi_stop();
97 } 119
120 /* In case of errors during the transmission, e.g. if the
121 * cable was disconnected and since there is no inherent
122 * error-checking protocol, we would simply interpret noise as
123 * data. */
124
125 /* To avoid this, both sides shake hands after transmitting.
126 * If synchronization was lost during transmission, the (first)
127 * handshake will fail. In that case we go around and
128 * re-transmit. */
98 129
99 spi_stop(); 130 } while (!shake_hands(true));
100 131
101 return true; 132 return true;
102} 133}
103 134
104void transport_slave(matrix_row_t matrix[]) { 135void transport_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
105 static struct led_context context; 136 static struct led_context context;
106 struct led_context new_context; 137 struct led_context new_context;
107 138
@@ -113,15 +144,17 @@ void transport_slave(matrix_row_t matrix[]) {
113 cli(); 144 cli();
114 shake_hands(false); 145 shake_hands(false);
115 146
116 for (i = 0 ; i < sizeof(matrix_row_t[MATRIX_ROWS / 2]) ; i += 1) { 147 do {
117 uint8_t b; 148 for (i = 0 ; i < sizeof(matrix_row_t[MATRIX_ROWS / 2]) ; i += 1) {
149 uint8_t b;
118 150
119 b = transceive(((uint8_t *)matrix)[i]); 151 b = transceive(((uint8_t *)slave_matrix)[i]);
120 152
121 if (i < sizeof(struct led_context)) { 153 if (i < sizeof(struct led_context)) {
122 ((uint8_t *)&new_context)[i] = b; 154 ((uint8_t *)&new_context)[i] = b;
155 }
123 } 156 }
124 } 157 } while (!shake_hands(false));
125 158
126 sei(); 159 sei();
127 160