Просмотр исходного кода

Allow for inverted SPI CS logic (#23699)

Dasky 1 год назад
Родитель
Сommit
2c7bf34d09

+ 52 - 32
platforms/avr/drivers/spi_master.c

@@ -36,9 +36,18 @@
 #    define SPI_TIMEOUT 100
 #endif
 
-static pin_t   currentSlavePin    = NO_PIN;
-static uint8_t currentSlaveConfig = 0;
-static bool    currentSlave2X     = false;
+static pin_t   current_slave_pin     = NO_PIN;
+static bool    current_cs_active_low = true;
+static uint8_t current_slave_config  = 0;
+static bool    current_slave_2x      = false;
+
+static inline void spi_select(void) {
+    gpio_write_pin(current_slave_pin, current_cs_active_low ? 0 : 1);
+}
+
+static inline void spi_unselect(void) {
+    gpio_write_pin(current_slave_pin, current_cs_active_low ? 1 : 0);
+}
 
 void spi_init(void) {
     gpio_write_pin_high(SPI_SS_PIN);
@@ -50,63 +59,74 @@ void spi_init(void) {
 }
 
 bool spi_start(pin_t slavePin, bool lsbFirst, uint8_t mode, uint16_t divisor) {
-    if (currentSlavePin != NO_PIN || slavePin == NO_PIN) {
+    spi_start_config_t start_config = {0};
+    start_config.slave_pin          = slavePin;
+    start_config.lsb_first          = lsbFirst;
+    start_config.mode               = mode;
+    start_config.divisor            = divisor;
+    start_config.cs_active_low      = true;
+    return spi_start_extended(&start_config);
+}
+
+bool spi_start_extended(spi_start_config_t *start_config) {
+    if (current_slave_pin != NO_PIN || start_config->slave_pin == NO_PIN) {
         return false;
     }
 
-    currentSlaveConfig = 0;
+    current_slave_config = 0;
 
-    if (lsbFirst) {
-        currentSlaveConfig |= _BV(DORD);
+    if (start_config->lsb_first) {
+        current_slave_config |= _BV(DORD);
     }
 
-    switch (mode) {
+    switch (start_config->mode) {
         case 1:
-            currentSlaveConfig |= _BV(CPHA);
+            current_slave_config |= _BV(CPHA);
             break;
         case 2:
-            currentSlaveConfig |= _BV(CPOL);
+            current_slave_config |= _BV(CPOL);
             break;
         case 3:
-            currentSlaveConfig |= (_BV(CPOL) | _BV(CPHA));
+            current_slave_config |= (_BV(CPOL) | _BV(CPHA));
             break;
     }
 
     uint16_t roundedDivisor = 1;
-    while (roundedDivisor < divisor) {
+    while (roundedDivisor < start_config->divisor) {
         roundedDivisor <<= 1;
     }
 
     switch (roundedDivisor) {
         case 16:
-            currentSlaveConfig |= _BV(SPR0);
+            current_slave_config |= _BV(SPR0);
             break;
         case 64:
-            currentSlaveConfig |= _BV(SPR1);
+            current_slave_config |= _BV(SPR1);
             break;
         case 128:
-            currentSlaveConfig |= (_BV(SPR1) | _BV(SPR0));
+            current_slave_config |= (_BV(SPR1) | _BV(SPR0));
             break;
         case 2:
-            currentSlave2X = true;
+            current_slave_2x = true;
             break;
         case 8:
-            currentSlave2X = true;
-            currentSlaveConfig |= _BV(SPR0);
+            current_slave_2x = true;
+            current_slave_config |= _BV(SPR0);
             break;
         case 32:
-            currentSlave2X = true;
-            currentSlaveConfig |= _BV(SPR1);
+            current_slave_2x = true;
+            current_slave_config |= _BV(SPR1);
             break;
     }
 
-    SPCR |= currentSlaveConfig;
-    if (currentSlave2X) {
+    SPCR |= current_slave_config;
+    if (current_slave_2x) {
         SPSR |= _BV(SPI2X);
     }
-    currentSlavePin = slavePin;
-    gpio_set_pin_output(currentSlavePin);
-    gpio_write_pin_low(currentSlavePin);
+    current_slave_pin     = start_config->slave_pin;
+    current_cs_active_low = start_config->cs_active_low;
+    gpio_set_pin_output(current_slave_pin);
+    spi_select();
 
     return true;
 }
@@ -168,13 +188,13 @@ spi_status_t spi_receive(uint8_t *data, uint16_t length) {
 }
 
 void spi_stop(void) {
-    if (currentSlavePin != NO_PIN) {
-        gpio_set_pin_output(currentSlavePin);
-        gpio_write_pin_high(currentSlavePin);
-        currentSlavePin = NO_PIN;
+    if (current_slave_pin != NO_PIN) {
+        gpio_set_pin_output(current_slave_pin);
+        spi_unselect();
+        current_slave_pin = NO_PIN;
         SPSR &= ~(_BV(SPI2X));
-        SPCR &= ~(currentSlaveConfig);
-        currentSlaveConfig = 0;
-        currentSlave2X     = false;
+        SPCR &= ~(current_slave_config);
+        current_slave_config = 0;
+        current_slave_2x     = false;
     }
 }

+ 9 - 0
platforms/avr/drivers/spi_master.h

@@ -41,9 +41,18 @@ typedef int16_t spi_status_t;
 #ifdef __cplusplus
 extern "C" {
 #endif
+typedef struct spi_start_config_t {
+    pin_t    slave_pin;
+    bool     lsb_first;
+    uint8_t  mode;
+    uint16_t divisor;
+    bool     cs_active_low;
+} spi_start_config_t;
+
 void spi_init(void);
 
 bool spi_start(pin_t slavePin, bool lsbFirst, uint8_t mode, uint16_t divisor);
+bool spi_start_extended(spi_start_config_t *start_config);
 
 spi_status_t spi_write(uint8_t data);
 

+ 58 - 38
platforms/chibios/drivers/spi_master.c

@@ -19,13 +19,33 @@
 #include "timer.h"
 
 static bool spiStarted = false;
-
 #if SPI_SELECT_MODE == SPI_SELECT_MODE_NONE
-static pin_t currentSlavePin;
+static pin_t current_slave_pin     = NO_PIN;
+static bool  current_cs_active_low = true;
 #endif
 
 static SPIConfig spiConfig;
 
+static inline void spi_select(void) {
+    spiSelect(&SPI_DRIVER);
+
+#if SPI_SELECT_MODE == SPI_SELECT_MODE_NONE
+    if (current_slave_pin != NO_PIN) {
+        gpio_write_pin(current_slave_pin, current_cs_active_low ? 0 : 1);
+    }
+#endif
+}
+
+static inline void spi_unselect(void) {
+#if SPI_SELECT_MODE == SPI_SELECT_MODE_NONE
+    if (current_slave_pin != NO_PIN) {
+        gpio_write_pin(current_slave_pin, current_cs_active_low ? 1 : 0);
+    }
+#endif
+
+    spiUnselect(&SPI_DRIVER);
+}
+
 __attribute__((weak)) void spi_init(void) {
     static bool is_initialised = false;
     if (!is_initialised) {
@@ -63,7 +83,7 @@ __attribute__((weak)) void spi_init(void) {
     }
 }
 
-bool spi_start(pin_t slavePin, bool lsbFirst, uint8_t mode, uint16_t divisor) {
+bool spi_start_extended(spi_start_config_t *start_config) {
 #if (SPI_USE_MUTUAL_EXCLUSION == TRUE)
     spiAcquireBus(&SPI_DRIVER);
 #endif // (SPI_USE_MUTUAL_EXCLUSION == TRUE)
@@ -71,16 +91,15 @@ bool spi_start(pin_t slavePin, bool lsbFirst, uint8_t mode, uint16_t divisor) {
     if (spiStarted) {
         return false;
     }
-
 #if SPI_SELECT_MODE != SPI_SELECT_MODE_NONE
-    if (slavePin == NO_PIN) {
+    if (start_config->slave_pin == NO_PIN) {
         return false;
     }
 #endif
 
 #if !(defined(WB32F3G71xx) || defined(WB32FQ95xx))
     uint16_t roundedDivisor = 2;
-    while (roundedDivisor < divisor) {
+    while (roundedDivisor < start_config->divisor) {
         roundedDivisor <<= 1;
     }
 
@@ -92,11 +111,11 @@ bool spi_start(pin_t slavePin, bool lsbFirst, uint8_t mode, uint16_t divisor) {
 #if defined(K20x) || defined(KL2x)
     spiConfig.tar0 = SPIx_CTARn_FMSZ(7) | SPIx_CTARn_ASC(1);
 
-    if (lsbFirst) {
+    if (start_config->lsb_first) {
         spiConfig.tar0 |= SPIx_CTARn_LSBFE;
     }
 
-    switch (mode) {
+    switch (start_config->mode) {
         case 0:
             break;
         case 1:
@@ -141,11 +160,11 @@ bool spi_start(pin_t slavePin, bool lsbFirst, uint8_t mode, uint16_t divisor) {
     spiConfig.cr0 = SPI_CR0_SELOEN;
     spiConfig.cr1 = SPI_CR1_MODE | 8; // 8 bits and in master mode
 
-    if (lsbFirst) {
+    if (start_config->lsb_first) {
         spiConfig.cr1 |= SPI_CR1_FIRSTBIT;
     }
 
-    switch (mode) {
+    switch (start_config->mode) {
         case 0:
             spiConfig.cr1 |= SPI_CR1_FORMAT_MODE0;
             break;
@@ -163,17 +182,17 @@ bool spi_start(pin_t slavePin, bool lsbFirst, uint8_t mode, uint16_t divisor) {
     spiConfig.cpr = (roundedDivisor - 1) >> 1;
 
 #elif defined(WB32F3G71xx) || defined(WB32FQ95xx)
-    if (!lsbFirst) {
-        osalDbgAssert(lsbFirst != FALSE, "unsupported lsbFirst");
+    if (!start_config->lsb_first) {
+        osalDbgAssert(start_config->lsb_first != FALSE, "unsupported lsb_first");
     }
 
-    if (divisor < 1) {
+    if (start_config->divisor < 1) {
         return false;
     }
 
-    spiConfig.SPI_BaudRatePrescaler = (divisor << 2);
+    spiConfig.SPI_BaudRatePrescaler = (start_config->divisor << 2);
 
-    switch (mode) {
+    switch (start_config->mode) {
         case 0:
             spiConfig.SPI_CPHA = SPI_CPHA_1Edge;
             spiConfig.SPI_CPOL = SPI_CPOL_Low;
@@ -192,8 +211,8 @@ bool spi_start(pin_t slavePin, bool lsbFirst, uint8_t mode, uint16_t divisor) {
             break;
     }
 #elif defined(MCU_RP)
-    if (lsbFirst) {
-        osalDbgAssert(lsbFirst == false, "RP2040s PrimeCell SPI implementation does not support sending LSB first.");
+    if (start_config->lsb_first) {
+        osalDbgAssert(start_config->lsb_first == false, "RP2040s PrimeCell SPI implementation does not support sending LSB first.");
     }
 
     // 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) {
     // passed divisor to be the only value to divide the input clock by.
     spiConfig.SSPCPSR = roundedDivisor; // Even number from 2 to 254
 
-    switch (mode) {
+    switch (start_config->mode) {
         case 0:
             spiConfig.SSPCR0 &= ~SPI_SSPCR0_SPO; // Clock polarity: low
             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) {
 #else
     spiConfig.cr1 = 0;
 
-    if (lsbFirst) {
+    if (start_config->lsb_first) {
         spiConfig.cr1 |= SPI_CR1_LSBFIRST;
     }
 
-    switch (mode) {
+    switch (start_config->mode) {
         case 0:
             break;
         case 1:
@@ -271,31 +290,37 @@ bool spi_start(pin_t slavePin, bool lsbFirst, uint8_t mode, uint16_t divisor) {
 
     spiStarted = true;
 #if SPI_SELECT_MODE == SPI_SELECT_MODE_NONE
-    currentSlavePin = slavePin;
+    current_slave_pin     = start_config->slave_pin;
+    current_cs_active_low = start_config->cs_active_low;
 #endif
 #if SPI_SELECT_MODE == SPI_SELECT_MODE_PAD
-    spiConfig.ssport = PAL_PORT(slavePin);
-    spiConfig.sspad  = PAL_PAD(slavePin);
-    gpio_set_pin_output(slavePin);
+    spiConfig.ssport = PAL_PORT(start_config->slave_pin);
+    spiConfig.sspad  = PAL_PAD(start_config->slave_pin);
+    gpio_set_pin_output(start_config->slave_pin);
 #elif SPI_SELECT_MODE == SPI_SELECT_MODE_NONE
-    if (slavePin != NO_PIN) {
-        gpio_set_pin_output(slavePin);
+    if (start_config->slave_pin != NO_PIN) {
+        gpio_set_pin_output(start_config->slave_pin);
     }
 #else
 #    error "Unsupported SPI_SELECT_MODE"
 #endif
 
     spiStart(&SPI_DRIVER, &spiConfig);
-    spiSelect(&SPI_DRIVER);
-#if SPI_SELECT_MODE == SPI_SELECT_MODE_NONE
-    if (slavePin != NO_PIN) {
-        gpio_write_pin_low(slavePin);
-    }
-#endif
+    spi_select();
 
     return true;
 }
 
+bool spi_start(pin_t slavePin, bool lsbFirst, uint8_t mode, uint16_t divisor) {
+    spi_start_config_t start_config = {0};
+    start_config.slave_pin          = slavePin;
+    start_config.lsb_first          = lsbFirst;
+    start_config.mode               = mode;
+    start_config.divisor            = divisor;
+    start_config.cs_active_low      = true;
+    return spi_start_extended(&start_config);
+}
+
 spi_status_t spi_write(uint8_t data) {
     uint8_t rxData;
     spiExchange(&SPI_DRIVER, 1, &data, &rxData);
@@ -322,12 +347,7 @@ spi_status_t spi_receive(uint8_t *data, uint16_t length) {
 
 void spi_stop(void) {
     if (spiStarted) {
-#if SPI_SELECT_MODE == SPI_SELECT_MODE_NONE
-        if (currentSlavePin != NO_PIN) {
-            gpio_write_pin_high(currentSlavePin);
-        }
-#endif
-        spiUnselect(&SPI_DRIVER);
+        spi_unselect();
         spiStop(&SPI_DRIVER);
         spiStarted = false;
     }

+ 9 - 0
platforms/chibios/drivers/spi_master.h

@@ -75,9 +75,18 @@ typedef int16_t spi_status_t;
 #ifdef __cplusplus
 extern "C" {
 #endif
+typedef struct spi_start_config_t {
+    pin_t    slave_pin;
+    bool     lsb_first;
+    uint8_t  mode;
+    uint16_t divisor;
+    bool     cs_active_low;
+} spi_start_config_t;
+
 void spi_init(void);
 
 bool spi_start(pin_t slavePin, bool lsbFirst, uint8_t mode, uint16_t divisor);
+bool spi_start_extended(spi_start_config_t *start_config);
 
 spi_status_t spi_write(uint8_t data);