summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDasky <32983009+daskygit@users.noreply.github.com>2024-09-09 23:44:35 +0100
committerGitHub <noreply@github.com>2024-09-10 08:44:35 +1000
commit2c7bf34d09247c2f306f0068e34a2a3a4f3f58e1 (patch)
tree63052adc2c43f2e676bed9dc4957f961f3cb4eff
parent3aaa086ac8a50ed7fc501c2dc93c1d195b63dcc3 (diff)
Allow for inverted SPI CS logic (#23699)
-rw-r--r--platforms/avr/drivers/spi_master.c84
-rw-r--r--platforms/avr/drivers/spi_master.h9
-rw-r--r--platforms/chibios/drivers/spi_master.c96
-rw-r--r--platforms/chibios/drivers/spi_master.h9
4 files changed, 128 insertions, 70 deletions
diff --git a/platforms/avr/drivers/spi_master.c b/platforms/avr/drivers/spi_master.c
index 74b847c71a..ba7d782ab0 100644
--- a/platforms/avr/drivers/spi_master.c
+++ b/platforms/avr/drivers/spi_master.c
@@ -36,9 +36,18 @@
36# define SPI_TIMEOUT 100 36# define SPI_TIMEOUT 100
37#endif 37#endif
38 38
39static pin_t currentSlavePin = NO_PIN; 39static pin_t current_slave_pin = NO_PIN;
40static uint8_t currentSlaveConfig = 0; 40static bool current_cs_active_low = true;
41static bool currentSlave2X = false; 41static uint8_t current_slave_config = 0;
42static bool current_slave_2x = false;
43
44static inline void spi_select(void) {
45 gpio_write_pin(current_slave_pin, current_cs_active_low ? 0 : 1);
46}
47
48static inline void spi_unselect(void) {
49 gpio_write_pin(current_slave_pin, current_cs_active_low ? 1 : 0);
50}
42 51
43void spi_init(void) { 52void spi_init(void) {
44 gpio_write_pin_high(SPI_SS_PIN); 53 gpio_write_pin_high(SPI_SS_PIN);
@@ -50,63 +59,74 @@ void spi_init(void) {
50} 59}
51 60
52bool spi_start(pin_t slavePin, bool lsbFirst, uint8_t mode, uint16_t divisor) { 61bool spi_start(pin_t slavePin, bool lsbFirst, uint8_t mode, uint16_t divisor) {
53 if (currentSlavePin != NO_PIN || slavePin == NO_PIN) { 62 spi_start_config_t start_config = {0};
63 start_config.slave_pin = slavePin;
64 start_config.lsb_first = lsbFirst;
65 start_config.mode = mode;
66 start_config.divisor = divisor;
67 start_config.cs_active_low = true;
68 return spi_start_extended(&start_config);
69}
70
71bool spi_start_extended(spi_start_config_t *start_config) {
72 if (current_slave_pin != NO_PIN || start_config->slave_pin == NO_PIN) {
54 return false; 73 return false;
55 } 74 }
56 75
57 currentSlaveConfig = 0; 76 current_slave_config = 0;
58 77
59 if (lsbFirst) { 78 if (start_config->lsb_first) {
60 currentSlaveConfig |= _BV(DORD); 79 current_slave_config |= _BV(DORD);
61 } 80 }
62 81
63 switch (mode) { 82 switch (start_config->mode) {
64 case 1: 83 case 1:
65 currentSlaveConfig |= _BV(CPHA); 84 current_slave_config |= _BV(CPHA);
66 break; 85 break;
67 case 2: 86 case 2:
68 currentSlaveConfig |= _BV(CPOL); 87 current_slave_config |= _BV(CPOL);
69 break; 88 break;
70 case 3: 89 case 3:
71 currentSlaveConfig |= (_BV(CPOL) | _BV(CPHA)); 90 current_slave_config |= (_BV(CPOL) | _BV(CPHA));
72 break; 91 break;
73 } 92 }
74 93
75 uint16_t roundedDivisor = 1; 94 uint16_t roundedDivisor = 1;
76 while (roundedDivisor < divisor) { 95 while (roundedDivisor < start_config->divisor) {
77 roundedDivisor <<= 1; 96 roundedDivisor <<= 1;
78 } 97 }
79 98
80 switch (roundedDivisor) { 99 switch (roundedDivisor) {
81 case 16: 100 case 16:
82 currentSlaveConfig |= _BV(SPR0); 101 current_slave_config |= _BV(SPR0);
83 break; 102 break;
84 case 64: 103 case 64:
85 currentSlaveConfig |= _BV(SPR1); 104 current_slave_config |= _BV(SPR1);
86 break; 105 break;
87 case 128: 106 case 128:
88 currentSlaveConfig |= (_BV(SPR1) | _BV(SPR0)); 107 current_slave_config |= (_BV(SPR1) | _BV(SPR0));
89 break; 108 break;
90 case 2: 109 case 2:
91 currentSlave2X = true; 110 current_slave_2x = true;
92 break; 111 break;
93 case 8: 112 case 8:
94 currentSlave2X = true; 113 current_slave_2x = true;
95 currentSlaveConfig |= _BV(SPR0); 114 current_slave_config |= _BV(SPR0);
96 break; 115 break;
97 case 32: 116 case 32:
98 currentSlave2X = true; 117 current_slave_2x = true;
99 currentSlaveConfig |= _BV(SPR1); 118 current_slave_config |= _BV(SPR1);
100 break; 119 break;
101 } 120 }
102 121
103 SPCR |= currentSlaveConfig; 122 SPCR |= current_slave_config;
104 if (currentSlave2X) { 123 if (current_slave_2x) {
105 SPSR |= _BV(SPI2X); 124 SPSR |= _BV(SPI2X);
106 } 125 }
107 currentSlavePin = slavePin; 126 current_slave_pin = start_config->slave_pin;
108 gpio_set_pin_output(currentSlavePin); 127 current_cs_active_low = start_config->cs_active_low;
109 gpio_write_pin_low(currentSlavePin); 128 gpio_set_pin_output(current_slave_pin);
129 spi_select();
110 130
111 return true; 131 return true;
112} 132}
@@ -168,13 +188,13 @@ spi_status_t spi_receive(uint8_t *data, uint16_t length) {
168} 188}
169 189
170void spi_stop(void) { 190void spi_stop(void) {
171 if (currentSlavePin != NO_PIN) { 191 if (current_slave_pin != NO_PIN) {
172 gpio_set_pin_output(currentSlavePin); 192 gpio_set_pin_output(current_slave_pin);
173 gpio_write_pin_high(currentSlavePin); 193 spi_unselect();
174 currentSlavePin = NO_PIN; 194 current_slave_pin = NO_PIN;
175 SPSR &= ~(_BV(SPI2X)); 195 SPSR &= ~(_BV(SPI2X));
176 SPCR &= ~(currentSlaveConfig); 196 SPCR &= ~(current_slave_config);
177 currentSlaveConfig = 0; 197 current_slave_config = 0;
178 currentSlave2X = false; 198 current_slave_2x = false;
179 } 199 }
180} 200}
diff --git a/platforms/avr/drivers/spi_master.h b/platforms/avr/drivers/spi_master.h
index 8a30f47ae4..ebbf7ddeab 100644
--- a/platforms/avr/drivers/spi_master.h
+++ b/platforms/avr/drivers/spi_master.h
@@ -41,9 +41,18 @@ typedef int16_t spi_status_t;
41#ifdef __cplusplus 41#ifdef __cplusplus
42extern "C" { 42extern "C" {
43#endif 43#endif
44typedef struct spi_start_config_t {
45 pin_t slave_pin;
46 bool lsb_first;
47 uint8_t mode;
48 uint16_t divisor;
49 bool cs_active_low;
50} spi_start_config_t;
51
44void spi_init(void); 52void spi_init(void);
45 53
46bool spi_start(pin_t slavePin, bool lsbFirst, uint8_t mode, uint16_t divisor); 54bool spi_start(pin_t slavePin, bool lsbFirst, uint8_t mode, uint16_t divisor);
55bool spi_start_extended(spi_start_config_t *start_config);
47 56
48spi_status_t spi_write(uint8_t data); 57spi_status_t spi_write(uint8_t data);
49 58
diff --git a/platforms/chibios/drivers/spi_master.c b/platforms/chibios/drivers/spi_master.c
index fcdbc9ecf0..cbe765e233 100644
--- a/platforms/chibios/drivers/spi_master.c
+++ b/platforms/chibios/drivers/spi_master.c
@@ -19,13 +19,33 @@
19#include "timer.h" 19#include "timer.h"
20 20
21static bool spiStarted = false; 21static bool spiStarted = false;
22
23#if SPI_SELECT_MODE == SPI_SELECT_MODE_NONE 22#if SPI_SELECT_MODE == SPI_SELECT_MODE_NONE
24static pin_t currentSlavePin; 23static pin_t current_slave_pin = NO_PIN;
24static bool current_cs_active_low = true;
25#endif 25#endif
26 26
27static SPIConfig spiConfig; 27static SPIConfig spiConfig;
28 28
29static inline void spi_select(void) {
30 spiSelect(&SPI_DRIVER);
31
32#if SPI_SELECT_MODE == SPI_SELECT_MODE_NONE
33 if (current_slave_pin != NO_PIN) {
34 gpio_write_pin(current_slave_pin, current_cs_active_low ? 0 : 1);
35 }
36#endif
37}
38
39static inline void spi_unselect(void) {
40#if SPI_SELECT_MODE == SPI_SELECT_MODE_NONE
41 if (current_slave_pin != NO_PIN) {
42 gpio_write_pin(current_slave_pin, current_cs_active_low ? 1 : 0);
43 }
44#endif
45
46 spiUnselect(&SPI_DRIVER);
47}
48
29__attribute__((weak)) void spi_init(void) { 49__attribute__((weak)) void spi_init(void) {
30 static bool is_initialised = false; 50 static bool is_initialised = false;
31 if (!is_initialised) { 51 if (!is_initialised) {
@@ -63,7 +83,7 @@ __attribute__((weak)) void spi_init(void) {
63 } 83 }
64} 84}
65 85
66bool spi_start(pin_t slavePin, bool lsbFirst, uint8_t mode, uint16_t divisor) { 86bool spi_start_extended(spi_start_config_t *start_config) {
67#if (SPI_USE_MUTUAL_EXCLUSION == TRUE) 87#if (SPI_USE_MUTUAL_EXCLUSION == TRUE)
68 spiAcquireBus(&SPI_DRIVER); 88 spiAcquireBus(&SPI_DRIVER);
69#endif // (SPI_USE_MUTUAL_EXCLUSION == TRUE) 89#endif // (SPI_USE_MUTUAL_EXCLUSION == TRUE)
@@ -71,16 +91,15 @@ bool spi_start(pin_t slavePin, bool lsbFirst, uint8_t mode, uint16_t divisor) {
71 if (spiStarted) { 91 if (spiStarted) {
72 return false; 92 return false;
73 } 93 }
74
75#if SPI_SELECT_MODE != SPI_SELECT_MODE_NONE 94#if SPI_SELECT_MODE != SPI_SELECT_MODE_NONE
76 if (slavePin == NO_PIN) { 95 if (start_config->slave_pin == NO_PIN) {
77 return false; 96 return false;
78 } 97 }
79#endif 98#endif
80 99
81#if !(defined(WB32F3G71xx) || defined(WB32FQ95xx)) 100#if !(defined(WB32F3G71xx) || defined(WB32FQ95xx))
82 uint16_t roundedDivisor = 2; 101 uint16_t roundedDivisor = 2;
83 while (roundedDivisor < divisor) { 102 while (roundedDivisor < start_config->divisor) {
84 roundedDivisor <<= 1; 103 roundedDivisor <<= 1;
85 } 104 }
86 105
@@ -92,11 +111,11 @@ bool spi_start(pin_t slavePin, bool lsbFirst, uint8_t mode, uint16_t divisor) {
92#if defined(K20x) || defined(KL2x) 111#if defined(K20x) || defined(KL2x)
93 spiConfig.tar0 = SPIx_CTARn_FMSZ(7) | SPIx_CTARn_ASC(1); 112 spiConfig.tar0 = SPIx_CTARn_FMSZ(7) | SPIx_CTARn_ASC(1);
94 113
95 if (lsbFirst) { 114 if (start_config->lsb_first) {
96 spiConfig.tar0 |= SPIx_CTARn_LSBFE; 115 spiConfig.tar0 |= SPIx_CTARn_LSBFE;
97 } 116 }
98 117
99 switch (mode) { 118 switch (start_config->mode) {
100 case 0: 119 case 0:
101 break; 120 break;
102 case 1: 121 case 1:
@@ -141,11 +160,11 @@ bool spi_start(pin_t slavePin, bool lsbFirst, uint8_t mode, uint16_t divisor) {
141 spiConfig.cr0 = SPI_CR0_SELOEN; 160 spiConfig.cr0 = SPI_CR0_SELOEN;
142 spiConfig.cr1 = SPI_CR1_MODE | 8; // 8 bits and in master mode 161 spiConfig.cr1 = SPI_CR1_MODE | 8; // 8 bits and in master mode
143 162
144 if (lsbFirst) { 163 if (start_config->lsb_first) {
145 spiConfig.cr1 |= SPI_CR1_FIRSTBIT; 164 spiConfig.cr1 |= SPI_CR1_FIRSTBIT;
146 } 165 }
147 166
148 switch (mode) { 167 switch (start_config->mode) {
149 case 0: 168 case 0:
150 spiConfig.cr1 |= SPI_CR1_FORMAT_MODE0; 169 spiConfig.cr1 |= SPI_CR1_FORMAT_MODE0;
151 break; 170 break;
@@ -163,17 +182,17 @@ bool spi_start(pin_t slavePin, bool lsbFirst, uint8_t mode, uint16_t divisor) {
163 spiConfig.cpr = (roundedDivisor - 1) >> 1; 182 spiConfig.cpr = (roundedDivisor - 1) >> 1;
164 183
165#elif defined(WB32F3G71xx) || defined(WB32FQ95xx) 184#elif defined(WB32F3G71xx) || defined(WB32FQ95xx)
166 if (!lsbFirst) { 185 if (!start_config->lsb_first) {
167 osalDbgAssert(lsbFirst != FALSE, "unsupported lsbFirst"); 186 osalDbgAssert(start_config->lsb_first != FALSE, "unsupported lsb_first");
168 } 187 }
169 188
170 if (divisor < 1) { 189 if (start_config->divisor < 1) {
171 return false; 190 return false;
172 } 191 }
173 192
174 spiConfig.SPI_BaudRatePrescaler = (divisor << 2); 193 spiConfig.SPI_BaudRatePrescaler = (start_config->divisor << 2);
175 194
176 switch (mode) { 195 switch (start_config->mode) {
177 case 0: 196 case 0:
178 spiConfig.SPI_CPHA = SPI_CPHA_1Edge; 197 spiConfig.SPI_CPHA = SPI_CPHA_1Edge;
179 spiConfig.SPI_CPOL = SPI_CPOL_Low; 198 spiConfig.SPI_CPOL = SPI_CPOL_Low;
@@ -192,8 +211,8 @@ bool spi_start(pin_t slavePin, bool lsbFirst, uint8_t mode, uint16_t divisor) {
192 break; 211 break;
193 } 212 }
194#elif defined(MCU_RP) 213#elif defined(MCU_RP)
195 if (lsbFirst) { 214 if (start_config->lsb_first) {
196 osalDbgAssert(lsbFirst == false, "RP2040s PrimeCell SPI implementation does not support sending LSB first."); 215 osalDbgAssert(start_config->lsb_first == false, "RP2040s PrimeCell SPI implementation does not support sending LSB first.");
197 } 216 }
198 217
199 // Motorola frame format and 8bit transfer data size. 218 // Motorola frame format and 8bit transfer data size.
@@ -203,7 +222,7 @@ bool spi_start(pin_t slavePin, bool lsbFirst, uint8_t mode, uint16_t divisor) {
203 // passed divisor to be the only value to divide the input clock by. 222 // passed divisor to be the only value to divide the input clock by.
204 spiConfig.SSPCPSR = roundedDivisor; // Even number from 2 to 254 223 spiConfig.SSPCPSR = roundedDivisor; // Even number from 2 to 254
205 224
206 switch (mode) { 225 switch (start_config->mode) {
207 case 0: 226 case 0:
208 spiConfig.SSPCR0 &= ~SPI_SSPCR0_SPO; // Clock polarity: low 227 spiConfig.SSPCR0 &= ~SPI_SSPCR0_SPO; // Clock polarity: low
209 spiConfig.SSPCR0 &= ~SPI_SSPCR0_SPH; // Clock phase: sample on first edge 228 spiConfig.SSPCR0 &= ~SPI_SSPCR0_SPH; // Clock phase: sample on first edge
@@ -224,11 +243,11 @@ bool spi_start(pin_t slavePin, bool lsbFirst, uint8_t mode, uint16_t divisor) {
224#else 243#else
225 spiConfig.cr1 = 0; 244 spiConfig.cr1 = 0;
226 245
227 if (lsbFirst) { 246 if (start_config->lsb_first) {
228 spiConfig.cr1 |= SPI_CR1_LSBFIRST; 247 spiConfig.cr1 |= SPI_CR1_LSBFIRST;
229 } 248 }
230 249
231 switch (mode) { 250 switch (start_config->mode) {
232 case 0: 251 case 0:
233 break; 252 break;
234 case 1: 253 case 1:
@@ -271,31 +290,37 @@ bool spi_start(pin_t slavePin, bool lsbFirst, uint8_t mode, uint16_t divisor) {
271 290
272 spiStarted = true; 291 spiStarted = true;
273#if SPI_SELECT_MODE == SPI_SELECT_MODE_NONE 292#if SPI_SELECT_MODE == SPI_SELECT_MODE_NONE
274 currentSlavePin = slavePin; 293 current_slave_pin = start_config->slave_pin;
294 current_cs_active_low = start_config->cs_active_low;
275#endif 295#endif
276#if SPI_SELECT_MODE == SPI_SELECT_MODE_PAD 296#if SPI_SELECT_MODE == SPI_SELECT_MODE_PAD
277 spiConfig.ssport = PAL_PORT(slavePin); 297 spiConfig.ssport = PAL_PORT(start_config->slave_pin);
278 spiConfig.sspad = PAL_PAD(slavePin); 298 spiConfig.sspad = PAL_PAD(start_config->slave_pin);
279 gpio_set_pin_output(slavePin); 299 gpio_set_pin_output(start_config->slave_pin);
280#elif SPI_SELECT_MODE == SPI_SELECT_MODE_NONE 300#elif SPI_SELECT_MODE == SPI_SELECT_MODE_NONE
281 if (slavePin != NO_PIN) { 301 if (start_config->slave_pin != NO_PIN) {
282 gpio_set_pin_output(slavePin); 302 gpio_set_pin_output(start_config->slave_pin);
283 } 303 }
284#else 304#else
285# error "Unsupported SPI_SELECT_MODE" 305# error "Unsupported SPI_SELECT_MODE"
286#endif 306#endif
287 307
288 spiStart(&SPI_DRIVER, &spiConfig); 308 spiStart(&SPI_DRIVER, &spiConfig);
289 spiSelect(&SPI_DRIVER); 309 spi_select();
290#if SPI_SELECT_MODE == SPI_SELECT_MODE_NONE
291 if (slavePin != NO_PIN) {
292 gpio_write_pin_low(slavePin);
293 }
294#endif
295 310
296 return true; 311 return true;
297} 312}
298 313
314bool spi_start(pin_t slavePin, bool lsbFirst, uint8_t mode, uint16_t divisor) {
315 spi_start_config_t start_config = {0};
316 start_config.slave_pin = slavePin;
317 start_config.lsb_first = lsbFirst;
318 start_config.mode = mode;
319 start_config.divisor = divisor;
320 start_config.cs_active_low = true;
321 return spi_start_extended(&start_config);
322}
323
299spi_status_t spi_write(uint8_t data) { 324spi_status_t spi_write(uint8_t data) {
300 uint8_t rxData; 325 uint8_t rxData;
301 spiExchange(&SPI_DRIVER, 1, &data, &rxData); 326 spiExchange(&SPI_DRIVER, 1, &data, &rxData);
@@ -322,12 +347,7 @@ spi_status_t spi_receive(uint8_t *data, uint16_t length) {
322 347
323void spi_stop(void) { 348void spi_stop(void) {
324 if (spiStarted) { 349 if (spiStarted) {
325#if SPI_SELECT_MODE == SPI_SELECT_MODE_NONE 350 spi_unselect();
326 if (currentSlavePin != NO_PIN) {
327 gpio_write_pin_high(currentSlavePin);
328 }
329#endif
330 spiUnselect(&SPI_DRIVER);
331 spiStop(&SPI_DRIVER); 351 spiStop(&SPI_DRIVER);
332 spiStarted = false; 352 spiStarted = false;
333 } 353 }
diff --git a/platforms/chibios/drivers/spi_master.h b/platforms/chibios/drivers/spi_master.h
index 6a3ce481f1..4ad6144091 100644
--- a/platforms/chibios/drivers/spi_master.h
+++ b/platforms/chibios/drivers/spi_master.h
@@ -75,9 +75,18 @@ typedef int16_t spi_status_t;
75#ifdef __cplusplus 75#ifdef __cplusplus
76extern "C" { 76extern "C" {
77#endif 77#endif
78typedef struct spi_start_config_t {
79 pin_t slave_pin;
80 bool lsb_first;
81 uint8_t mode;
82 uint16_t divisor;
83 bool cs_active_low;
84} spi_start_config_t;
85
78void spi_init(void); 86void spi_init(void);
79 87
80bool spi_start(pin_t slavePin, bool lsbFirst, uint8_t mode, uint16_t divisor); 88bool spi_start(pin_t slavePin, bool lsbFirst, uint8_t mode, uint16_t divisor);
89bool spi_start_extended(spi_start_config_t *start_config);
81 90
82spi_status_t spi_write(uint8_t data); 91spi_status_t spi_write(uint8_t data);
83 92