mirror of https://github.com/ArduPilot/ardupilot
AP_HAL_ChibiOS: add support for saving and restoring SCK pin state
when SPI goes into undefined state during reset
This commit is contained in:
parent
6a97817fa6
commit
829fcf5f33
|
@ -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. */
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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'''
|
||||
|
|
Loading…
Reference in New Issue