Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[4.4 BackPort] Save/Restore SCK pin state when SPI is stopped and started before transaction #25295

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 51 additions & 10 deletions libraries/AP_HAL_ChibiOS/SPIDevice.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -86,6 +87,10 @@ 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()
#if HAL_SPI_SCK_SAVE_RESTORE
sck_mode = palReadLineMode(spi_devices[bus].sck_line);
#endif
}

/*
Expand All @@ -103,10 +108,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);
}

Expand Down Expand Up @@ -339,6 +341,48 @@ 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 HAL_SPI_SCK_SAVE_RESTORE
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);
#endif
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);
#if HAL_SPI_SCK_SAVE_RESTORE
// restore sck pin mode from stop_peripheral()
palSetLineMode(spi_devices[bus].sck_line, sck_mode);
#endif
spi_started = true;
}

/*
used to acquire bus and (optionally) assert cs
*/
Expand Down Expand Up @@ -380,12 +424,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. */
}
Expand Down
20 changes: 19 additions & 1 deletion libraries/AP_HAL_ChibiOS/SPIDevice.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@
#include "Scheduler.h"
#include "Device.h"

#ifndef HAL_SPI_SCK_SAVE_RESTORE
#define HAL_SPI_SCK_SAVE_RESTORE FALSE
#endif

namespace ChibiOS {

class SPIBus : public DeviceBus {
Expand All @@ -35,14 +39,28 @@ class SPIBus : public DeviceBus {
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
// dma_deallocate functions to cope with 3-way contention as we
// 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
#if HAL_SPI_SCK_SAVE_RESTORE
iomode_t sck_mode;
#endif
};

struct SPIDesc {
Expand Down
6 changes: 4 additions & 2 deletions libraries/AP_HAL_ChibiOS/hwdef/CubeOrangePlus/hwdef.dat
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,9 @@ SPIDEV icm42688_ext SPI4 DEVID4 ACCEL_EXT_CS MODE3 2*MHZ 8*MHZ
SPIDEV icm42688_ext2 SPI4 DEVID5 GYRO_EXT_CS MODE3 2*MHZ 8*MHZ

#IMU 2
SPIDEV icm45686 SPI1 DEVID4 ICM45686_CS MODE1 2*MHZ 8*MHZ
SPIDEV icm45686 SPI1 DEVID4 ICM45686_CS MODE0 2*MHZ 8*MHZ
SPIDEV icm20649 SPI1 DEVID4 MPU_CS MODE3 4*MHZ 8*MHZ
SPIDEV icm45686_aux SPI1 DEVID4 ICM45686_CS MODE1 2*MHZ 8*MHZ
SPIDEV icm45686_aux SPI1 DEVID4 ICM45686_CS MODE0 2*MHZ 8*MHZ
SPIDEV icm20948_aux SPI4 DEVID1 MPU_EXT_CS MODE3 4*MHZ 8*MHZ

# INSTANCE:<num> keyword is used to denote the instance number of the sensor
Expand Down Expand Up @@ -95,3 +95,5 @@ CHECK_IMU1_PRESENT $CHECK_ICM20948_EXT || $CHECK_ICM42688_EXT2 || $CHECK_IC
CHECK_IMU2_PRESENT $CHECK_ICM42688_EXT || $CHECK_ICM45686_EXT

BOARD_VALIDATE $CHECK_IMU0_PRESENT $CHECK_IMU1_PRESENT $CHECK_IMU2_PRESENT $CHECK_BARO0_PRESENT $CHECK_BARO1_PRESENT

define HAL_SPI_SCK_SAVE_RESTORE TRUE
6 changes: 4 additions & 2 deletions libraries/AP_HAL_ChibiOS/hwdef/scripts/chibios_hwdef.py
Original file line number Diff line number Diff line change
Expand Up @@ -1417,9 +1417,11 @@ def write_SPI_config(f):
for dev in spi_list:
n = int(dev[3:])
devlist.append('HAL_SPI%u_CONFIG' % n)
sck_pin = 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)

Expand Down