From 829fcf5f33825c6c59654d58eb4367c1e73b0b1b Mon Sep 17 00:00:00 2001 From: bugobliterator Date: Fri, 13 Oct 2023 15:18:35 +1100 Subject: [PATCH] AP_HAL_ChibiOS: add support for saving and restoring SCK pin state when SPI goes into undefined state during reset --- libraries/AP_HAL_ChibiOS/SPIDevice.cpp | 57 +++++++++++++++---- libraries/AP_HAL_ChibiOS/SPIDevice.h | 14 ++++- .../hwdef/scripts/chibios_hwdef.py | 22 +++---- 3 files changed, 71 insertions(+), 22 deletions(-) diff --git a/libraries/AP_HAL_ChibiOS/SPIDevice.cpp b/libraries/AP_HAL_ChibiOS/SPIDevice.cpp index ae1b8da471..fbbda7875c 100644 --- a/libraries/AP_HAL_ChibiOS/SPIDevice.cpp +++ b/libraries/AP_HAL_ChibiOS/SPIDevice.cpp @@ -69,6 +69,7 @@ static const struct SPIDriverInfo { uint8_t busid; // used for device IDs in parameters uint8_t dma_channel_rx; uint8_t dma_channel_tx; + ioline_t sck_line; } spi_devices[] = { HAL_SPI_BUS_LIST }; // device list comes from hwdef.dat @@ -86,6 +87,8 @@ SPIBus::SPIBus(uint8_t _bus) : FUNCTOR_BIND_MEMBER(&SPIBus::dma_allocate, void, Shared_DMA *), FUNCTOR_BIND_MEMBER(&SPIBus::dma_deallocate, void, Shared_DMA *)); + // remember the SCK line for stop_peripheral()/start_peripheral() + sck_mode = palReadLineMode(spi_devices[bus].sck_line); } /* @@ -103,10 +106,7 @@ void SPIBus::dma_deallocate(Shared_DMA *ctx) { chMtxLock(&dma_lock); // another non-SPI peripheral wants one of our DMA channels - if (spi_started) { - spiStop(spi_devices[bus].driver); - spi_started = false; - } + stop_peripheral(); chMtxUnlock(&dma_lock); } @@ -339,6 +339,46 @@ bool SPIDevice::adjust_periodic_callback(AP_HAL::Device::PeriodicHandle h, uint3 return bus.adjust_timer(h, period_usec); } +/* + stop the SPI peripheral and set the SCK line as a GPIO to prevent the clock + line floating while we are waiting for the next spiStart() + */ +void SPIBus::stop_peripheral(void) +{ + if (!spi_started) { + return; + } + const auto &sbus = spi_devices[bus]; + if (spi_mode == SPIDEV_MODE0 || spi_mode == SPIDEV_MODE1) { + // Clock polarity is 0, so we need to set the clock line low before spi reset + palClearLine(sbus.sck_line); + } else { + // Clock polarity is 1, so we need to set the clock line high before spi reset + palSetLine(sbus.sck_line); + } + palSetLineMode(sbus.sck_line, PAL_MODE_OUTPUT_PUSHPULL); + spiStop(sbus.driver); + spi_started = false; +} + +/* + start the SPI peripheral and restore the IO mode of the SCK line + */ +void SPIBus::start_peripheral(void) +{ + if (spi_started) { + return; + } + + /* start driver and setup transfer parameters */ + spiStart(spi_devices[bus].driver, &spicfg); + + // restore sck pin mode from stop_peripheral() + palSetLineMode(spi_devices[bus].sck_line, sck_mode); + + spi_started = true; +} + /* used to acquire bus and (optionally) assert cs */ @@ -380,12 +420,9 @@ bool SPIDevice::acquire_bus(bool set, bool skip_cs) bus.spicfg.cr1 = (uint16_t)(freq_flag | device_desc.mode); bus.spicfg.cr2 = 0; #endif - if (bus.spi_started) { - spiStop(spi_devices[device_desc.bus].driver); - bus.spi_started = false; - } - spiStart(spi_devices[device_desc.bus].driver, &bus.spicfg); /* Setup transfer parameters. */ - bus.spi_started = true; + bus.spi_mode = device_desc.mode; + bus.stop_peripheral(); + bus.start_peripheral(); if(!skip_cs) { spiSelectI(spi_devices[device_desc.bus].driver); /* Slave Select assertion. */ } diff --git a/libraries/AP_HAL_ChibiOS/SPIDevice.h b/libraries/AP_HAL_ChibiOS/SPIDevice.h index 325fc26460..55a9c4d674 100644 --- a/libraries/AP_HAL_ChibiOS/SPIDevice.h +++ b/libraries/AP_HAL_ChibiOS/SPIDevice.h @@ -35,7 +35,6 @@ public: SPIConfig spicfg; void dma_allocate(Shared_DMA *ctx); void dma_deallocate(Shared_DMA *ctx); - bool spi_started; uint8_t slowdown; // we need an additional lock in the dma_allocate and @@ -43,6 +42,19 @@ public: // have two DMA channels that we are handling with the shared_dma // code mutex_t dma_lock; + + // store the last spi mode for stop_peripheral() + uint32_t spi_mode; + + // start and stop the hardware peripheral + void start_peripheral(void); + void stop_peripheral(void); + +private: + bool spi_started; + + // mode line for SCK pin + iomode_t sck_mode; }; struct SPIDesc { diff --git a/libraries/AP_HAL_ChibiOS/hwdef/scripts/chibios_hwdef.py b/libraries/AP_HAL_ChibiOS/hwdef/scripts/chibios_hwdef.py index cd928e2709..101d03de18 100644 --- a/libraries/AP_HAL_ChibiOS/hwdef/scripts/chibios_hwdef.py +++ b/libraries/AP_HAL_ChibiOS/hwdef/scripts/chibios_hwdef.py @@ -1403,26 +1403,26 @@ def write_SPI_table(f): f.write("\n") -def write_SPI_config(f): +def write_SPI_config(self, f): '''write SPI config defines''' - global spi_list - for t in list(bytype.keys()) + list(alttype.keys()): + for t in list(self.bytype.keys()) + list(self.alttype.keys()): if t.startswith('SPI'): - spi_list.append(t) - spi_list = sorted(spi_list) - if len(spi_list) == 0: + self.spi_list.append(t) + self.spi_list = sorted(self.spi_list) + if len(self.spi_list) == 0: f.write('#define HAL_USE_SPI FALSE\n') return devlist = [] - for dev in spi_list: + for dev in self.spi_list: n = int(dev[3:]) devlist.append('HAL_SPI%u_CONFIG' % n) + sck_pin = self.bylabel['SPI%s_SCK' % n] + sck_line = 'PAL_LINE(GPIO%s,%uU)' % (sck_pin.port, sck_pin.pin) f.write( - '#define HAL_SPI%u_CONFIG { &SPID%u, %u, STM32_SPI_SPI%u_DMA_STREAMS }\n' - % (n, n, n, n)) + '#define HAL_SPI%u_CONFIG { &SPID%u, %u, STM32_SPI_SPI%u_DMA_STREAMS, %s }\n' + % (n, n, n, n, sck_line)) f.write('#define HAL_SPI_BUS_LIST %s\n\n' % ','.join(devlist)) - write_SPI_table(f) - + self.write_SPI_table(f) def write_QSPI_table(f): '''write SPI device table'''