Allow mixed speed and mode on a SPI bus by CR1 caching

This commit is contained in:
jflyper 2018-01-06 04:50:19 +09:00
parent 4778ad6c0f
commit 343e9b3a67
22 changed files with 390 additions and 58 deletions

View File

@ -75,7 +75,11 @@ void bmp280BusInit(busDevice_t *busdev)
IOHi(busdev->busdev_u.spi.csnPin); // Disable
IOInit(busdev->busdev_u.spi.csnPin, OWNER_BARO_CS, 0);
IOConfigGPIO(busdev->busdev_u.spi.csnPin, IOCFG_OUT_PP);
spiSetDivisor(busdev->busdev_u.spi.instance, SPI_CLOCK_STANDARD); // XXX
#ifdef USE_SPI_TRANSACTION
spiBusTransactionInit(busdev, SPI_MODE0_POL_LOW_EDGE_1ST, SPI_CLOCK_STANDARD); // BMP280 supports Mode 0 or 3
#else
spiBusSetDivisor(busdev, SPI_CLOCK_STANDARD);
#endif
}
#else
UNUSED(busdev);
@ -93,6 +97,8 @@ void bmp280BusDeinit(busDevice_t *busdev)
#endif
}
#include "drivers/time.h"
bool bmp280Detect(baroDev_t *baro)
{
delay(20);

View File

@ -255,7 +255,11 @@ bool lpsDetect(baroDev_t *baro)
IOInit(busdev->busdev_u.spi.csnPin, OWNER_BARO_CS, 0);
IOConfigGPIO(busdev->busdev_u.spi.csnPin, IOCFG_OUT_PP);
IOHi(busdev->busdev_u.spi.csnPin); // Disable
spiSetDivisor(busdev->busdev_u.spi.instance, SPI_CLOCK_STANDARD); // Baro can work only on up to 10Mhz SPI bus
#ifdef USE_SPI_TRANSACTION
spiBusTransactionInit(busdev, SPI_MODE3_POL_HIGH_EDGE_2ND, SPI_CLOCK_STANDARD); // Baro can work only on up to 10Mhz SPI bus
#else
spiBusSetDivisor(busdev, SPI_CLOCK_STANDARD); // Baro can work only on up to 10Mhz SPI bus
#endif
uint8_t temp = 0x00;
lpsReadCommand(&baro->busdev, LPS_WHO_AM_I, &temp, 1);

View File

@ -71,7 +71,11 @@ void ms5611BusInit(busDevice_t *busdev)
IOHi(busdev->busdev_u.spi.csnPin); // Disable
IOInit(busdev->busdev_u.spi.csnPin, OWNER_BARO_CS, 0);
IOConfigGPIO(busdev->busdev_u.spi.csnPin, IOCFG_OUT_PP);
spiSetDivisor(busdev->busdev_u.spi.instance, SPI_CLOCK_STANDARD); // XXX
#ifdef USE_SPI_TRANSACTION
spiBusTransactionInit(busdev, SPI_MODE3_POL_HIGH_EDGE_2ND, SPI_CLOCK_STANDARD);
#else
spiBusSetDivisor(busdev, SPI_CLOCK_STANDARD); // XXX
#endif
}
#else
UNUSED(busdev);

View File

@ -104,7 +104,11 @@ void qmp6988BusInit(busDevice_t *busdev)
IOHi(busdev->busdev_u.spi.csnPin);
IOInit(busdev->busdev_u.spi.csnPin, OWNER_BARO_CS, 0);
IOConfigGPIO(busdev->busdev_u.spi.csnPin, IOCFG_OUT_PP);
spiSetDivisor(busdev->busdev_u.spi.instance, SPI_CLOCK_STANDARD);
#ifdef USE_SPI_TRANSACTION
spiBusTransactionInit(busdev, SPI_MODE3_POL_HIGH_EDGE_2ND, SPI_CLOCK_STANDARD);
#else
spiBusSetDivisor(busdev, SPI_CLOCK_STANDARD);
#endif
}
#else
UNUSED(busdev);

View File

@ -36,8 +36,13 @@ bool busWriteRegister(const busDevice_t *busdev, uint8_t reg, uint8_t data)
switch (busdev->bustype) {
#ifdef USE_SPI
case BUSTYPE_SPI:
#ifdef USE_SPI_TRANSACTION
// XXX Watch out fastpath users, if any
return spiBusTransactionWriteRegister(busdev, reg & 0x7f, data);
#else
return spiBusWriteRegister(busdev, reg & 0x7f, data);
#endif
#endif
#ifdef USE_I2C
case BUSTYPE_I2C:
return i2cBusWriteRegister(busdev, reg, data);
@ -57,8 +62,13 @@ bool busReadRegisterBuffer(const busDevice_t *busdev, uint8_t reg, uint8_t *data
switch (busdev->bustype) {
#ifdef USE_SPI
case BUSTYPE_SPI:
#ifdef USE_SPI_TRANSACTION
// XXX Watch out fastpath users, if any
return spiBusTransactionReadRegisterBuffer(busdev, reg | 0x80, data, length);
#else
return spiBusReadRegisterBuffer(busdev, reg | 0x80, data, length);
#endif
#endif
#ifdef USE_I2C
case BUSTYPE_I2C:
return i2cBusReadRegisterBuffer(busdev, reg, data, length);

View File

@ -33,11 +33,18 @@ typedef enum {
BUSTYPE_GYRO_AUTO // Only used by acc/gyro bus auto detection code
} busType_e;
struct spiDevice_s;
typedef struct busDevice_s {
busType_e bustype;
union {
struct deviceSpi_s {
SPI_TypeDef *instance;
#ifdef USE_SPI_TRANSACTION
struct SPIDevice_s *device; // Back ptr to controller for this device.
// Cached SPI_CR1 for spiBusTransactionXXX
uint16_t modeCache; // XXX cr1Value may be a better name?
#endif
#if defined(USE_HAL_DRIVER)
SPI_HandleTypeDef* handle; // cached here for efficiency
#endif

View File

@ -174,7 +174,6 @@ bool spiBusWriteRegister(const busDevice_t *bus, uint8_t reg, uint8_t data)
}
bool spiBusRawReadRegisterBuffer(const busDevice_t *bus, uint8_t reg, uint8_t *data, uint8_t length)
{
IOLo(bus->busdev_u.spi.csnPin);
spiTransferByte(bus->busdev_u.spi.instance, reg);
@ -218,4 +217,49 @@ void spiBusSetInstance(busDevice_t *bus, SPI_TypeDef *instance)
bus->bustype = BUSTYPE_SPI;
bus->busdev_u.spi.instance = instance;
}
void spiBusSetDivisor(busDevice_t *bus, uint16_t divisor)
{
spiSetDivisor(bus->busdev_u.spi.instance, divisor);
// bus->busdev_u.spi.modeCache = bus->busdev_u.spi.instance->CR1;
}
#ifdef USE_SPI_TRANSACTION
// Separate set of spiBusTransactionXXX to keep fast path for acc/gyros.
void spiBusTransactionBegin(const busDevice_t *bus)
{
spiBusTransactionSetup(bus);
IOLo(bus->busdev_u.spi.csnPin);
}
void spiBusTransactionEnd(const busDevice_t *bus)
{
IOHi(bus->busdev_u.spi.csnPin);
}
bool spiBusTransactionTransfer(const busDevice_t *bus, const uint8_t *txData, uint8_t *rxData, int length)
{
spiBusTransactionSetup(bus);
return spiBusTransfer(bus, txData, rxData, length);
}
bool spiBusTransactionWriteRegister(const busDevice_t *bus, uint8_t reg, uint8_t data)
{
spiBusTransactionSetup(bus);
return spiBusWriteRegister(bus, reg, data);
}
uint8_t spiBusTransactionReadRegister(const busDevice_t *bus, uint8_t reg)
{
spiBusTransactionSetup(bus);
return spiBusReadRegister(bus, reg);
}
bool spiBusTransactionReadRegisterBuffer(const busDevice_t *bus, uint8_t reg, uint8_t *data, uint8_t length)
{
spiBusTransactionSetup(bus);
return spiBusReadRegisterBuffer(bus, reg, data, length);
}
#endif // USE_SPI_TRANSACTION
#endif

View File

@ -69,6 +69,21 @@ typedef enum {
#endif
} SPIClockDivider_e;
// De facto standard mode
// See https://en.wikipedia.org/wiki/Serial_Peripheral_Interface
//
// Mode CPOL CPHA
// 0 0 0
// 1 0 1
// 2 1 0
// 3 1 1
typedef enum {
SPI_MODE0_POL_LOW_EDGE_1ST = 0,
SPI_MODE1_POL_LOW_EDGE_2ND,
SPI_MODE2_POL_HIGH_EDGE_1ST,
SPI_MODE3_POL_HIGH_EDGE_2ND
} SPIMode_e;
typedef enum SPIDevice {
SPIINVALID = -1,
SPIDEV_1 = 0,
@ -124,6 +139,16 @@ void spiBusWriteRegisterBuffer(const busDevice_t *bus, uint8_t reg, const uint8_
uint8_t spiBusRawReadRegister(const busDevice_t *bus, uint8_t reg);
uint8_t spiBusReadRegister(const busDevice_t *bus, uint8_t reg);
void spiBusSetInstance(busDevice_t *bus, SPI_TypeDef *instance);
void spiBusSetDivisor(busDevice_t *bus, SPIClockDivider_e divider);
void spiBusTransactionInit(busDevice_t *bus, SPIMode_e mode, SPIClockDivider_e divider);
void spiBusTransactionSetup(const busDevice_t *bus);
void spiBusTransactionBegin(const busDevice_t *bus);
void spiBusTransactionEnd(const busDevice_t *bus);
bool spiBusTransactionWriteRegister(const busDevice_t *bus, uint8_t reg, uint8_t data);
uint8_t spiBusTransactionReadRegister(const busDevice_t *bus, uint8_t reg);
bool spiBusTransactionReadRegisterBuffer(const busDevice_t *bus, uint8_t reg, uint8_t *data, uint8_t length);
bool spiBusTransactionTransfer(const busDevice_t *bus, const uint8_t *txData, uint8_t *rxData, int length);
struct spiPinConfig_s;
void spiPinConfigure(const struct spiPinConfig_s *pConfig);

View File

@ -70,6 +70,9 @@ typedef struct SPIDevice_s {
DMA_HandleTypeDef hdma;
uint8_t dmaIrqHandler;
#endif
#ifdef USE_SPI_TRANSACTION
uint16_t cr1SoftCopy; // Copy of active CR1 value for this SPI instance
#endif
} spiDevice_t;
extern spiDevice_t spiDevice[SPIDEV_COUNT];

View File

@ -73,6 +73,18 @@
#define SPI_DEFAULT_TIMEOUT 10
static LL_SPI_InitTypeDef defaultInit =
{
.TransferDirection = SPI_DIRECTION_2LINES,
.Mode = SPI_MODE_MASTER,
.DataWidth = SPI_DATASIZE_8BIT,
.NSS = SPI_NSS_SOFT,
.BaudRate = SPI_BAUDRATEPRESCALER_8,
.BitOrder = SPI_FIRSTBIT_MSB,
.CRCPoly = 7,
.CRCCalculation = SPI_CRCCALCULATION_DISABLE,
};
void spiInitDevice(SPIDevice device)
{
spiDevice_t *spi = &(spiDevice[device]);
@ -81,6 +93,7 @@ void spiInitDevice(SPIDevice device)
return;
}
#ifndef USE_SPI_TRANSACTION
#ifdef SDCARD_SPI_INSTANCE
if (spi->dev == SDCARD_SPI_INSTANCE) {
spi->leadingEdge = true;
@ -90,6 +103,7 @@ void spiInitDevice(SPIDevice device)
if (spi->dev == RX_SPI_INSTANCE) {
spi->leadingEdge = true;
}
#endif
#endif
// Enable SPI clock
@ -110,22 +124,20 @@ void spiInitDevice(SPIDevice device)
LL_SPI_Disable(spi->dev);
LL_SPI_DeInit(spi->dev);
LL_SPI_InitTypeDef init =
#ifndef USE_SPI_TRANSACTION
if (spi->leadingEdge) {
defaultInit.ClockPolarity = SPI_POLARITY_LOW;
defaultInit.ClockPhase = SPI_PHASE_1EDGE;
} else
#endif
{
.TransferDirection = SPI_DIRECTION_2LINES,
.Mode = SPI_MODE_MASTER,
.DataWidth = SPI_DATASIZE_8BIT,
.ClockPolarity = spi->leadingEdge ? SPI_POLARITY_LOW : SPI_POLARITY_HIGH,
.ClockPhase = spi->leadingEdge ? SPI_PHASE_1EDGE : SPI_PHASE_2EDGE,
.NSS = SPI_NSS_SOFT,
.BaudRate = SPI_BAUDRATEPRESCALER_8,
.BitOrder = SPI_FIRSTBIT_MSB,
.CRCPoly = 7,
.CRCCalculation = SPI_CRCCALCULATION_DISABLE,
};
defaultInit.ClockPolarity = SPI_POLARITY_HIGH;
defaultInit.ClockPhase = SPI_PHASE_2EDGE;
}
LL_SPI_SetRxFIFOThreshold(spi->dev, SPI_RXFIFO_THRESHOLD_QF);
LL_SPI_Init(spi->dev, &init);
LL_SPI_Init(spi->dev, &defaultInit);
LL_SPI_Enable(spi->dev);
}
@ -217,7 +229,7 @@ bool spiTransfer(SPI_TypeDef *instance, const uint8_t *txData, uint8_t *rxData,
return true;
}
void spiSetDivisor(SPI_TypeDef *instance, uint16_t divisor)
static uint16_t spiDivisorToBRbits(SPI_TypeDef *instance, uint16_t divisor)
{
#if !(defined(STM32F1) || defined(STM32F3))
// SPI2 and SPI3 are on APB1/AHB1 which PCLK is half that of APB2/AHB2.
@ -225,12 +237,71 @@ void spiSetDivisor(SPI_TypeDef *instance, uint16_t divisor)
if (instance == SPI2 || instance == SPI3) {
divisor /= 2; // Safe for divisor == 0 or 1
}
#else
UNUSED(instance);
#endif
divisor = constrain(divisor, 2, 256);
return (ffs(divisor) - 2) << SPI_CR1_BR_Pos;
}
void spiSetDivisor(SPI_TypeDef *instance, uint16_t divisor)
{
LL_SPI_Disable(instance);
LL_SPI_SetBaudRatePrescaler(instance, (ffs(divisor) - 2) << SPI_CR1_BR_Pos);
LL_SPI_SetBaudRatePrescaler(instance, spiDivisorToBRbits(instance, divisor));
LL_SPI_Enable(instance);
}
#ifdef USE_SPI_TRANSACTION
void spiBusTransactionInit(busDevice_t *bus, SPIMode_e mode, SPIClockDivider_e divisor)
{
switch (mode) {
case SPI_MODE0_POL_LOW_EDGE_1ST:
defaultInit.ClockPolarity = SPI_POLARITY_LOW;
defaultInit.ClockPhase = SPI_PHASE_1EDGE;
break;
case SPI_MODE1_POL_LOW_EDGE_2ND:
defaultInit.ClockPolarity = SPI_POLARITY_LOW;
defaultInit.ClockPhase = SPI_PHASE_2EDGE;
break;
case SPI_MODE2_POL_HIGH_EDGE_1ST:
defaultInit.ClockPolarity = SPI_POLARITY_HIGH;
defaultInit.ClockPhase = SPI_PHASE_1EDGE;
break;
case SPI_MODE3_POL_HIGH_EDGE_2ND:
defaultInit.ClockPolarity = SPI_POLARITY_HIGH;
defaultInit.ClockPhase = SPI_PHASE_2EDGE;
break;
}
LL_SPI_Disable(bus->busdev_u.spi.instance);
LL_SPI_DeInit(bus->busdev_u.spi.instance);
LL_SPI_Init(bus->busdev_u.spi.instance, &defaultInit);
LL_SPI_SetBaudRatePrescaler(bus->busdev_u.spi.instance, spiDivisorToBRbits(bus->busdev_u.spi.instance, divisor));
// Configure for 8-bit reads. XXX Is this STM32F303xC specific?
LL_SPI_SetRxFIFOThreshold(bus->busdev_u.spi.instance, SPI_RXFIFO_THRESHOLD_QF);
LL_SPI_Enable(bus->busdev_u.spi.instance);
bus->busdev_u.spi.device = &spiDevice[spiDeviceByInstance(bus->busdev_u.spi.instance)];
bus->busdev_u.spi.modeCache = bus->busdev_u.spi.instance->CR1;
}
void spiBusTransactionSetup(const busDevice_t *bus)
{
// We rely on MSTR bit to detect valid modeCache
if (bus->busdev_u.spi.modeCache && bus->busdev_u.spi.modeCache != bus->busdev_u.spi.device->cr1SoftCopy) {
bus->busdev_u.spi.instance->CR1 = bus->busdev_u.spi.modeCache;
bus->busdev_u.spi.device->cr1SoftCopy = bus->busdev_u.spi.modeCache;
// SCK seems to require some time to switch to a new initial level after CR1 is written.
// Here we buy some time in addition to the software copy save above.
__asm__("nop");
}
}
#endif // USE_SPI_TRANSACTION
#endif

View File

@ -34,6 +34,16 @@
#include "drivers/io.h"
#include "drivers/rcc.h"
static SPI_InitTypeDef defaultInit = {
.SPI_Mode = SPI_Mode_Master,
.SPI_Direction = SPI_Direction_2Lines_FullDuplex,
.SPI_DataSize = SPI_DataSize_8b,
.SPI_NSS = SPI_NSS_Soft,
.SPI_FirstBit = SPI_FirstBit_MSB,
.SPI_CRCPolynomial = 7,
.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8,
};
void spiInitDevice(SPIDevice device)
{
spiDevice_t *spi = &(spiDevice[device]);
@ -42,6 +52,7 @@ void spiInitDevice(SPIDevice device)
return;
}
#ifndef USE_SPI_TRANSACTION
#ifdef SDCARD_SPI_INSTANCE
if (spi->dev == SDCARD_SPI_INSTANCE) {
spi->leadingEdge = true;
@ -51,6 +62,7 @@ void spiInitDevice(SPIDevice device)
if (spi->dev == RX_SPI_INSTANCE) {
spi->leadingEdge = true;
}
#endif
#endif
// Enable SPI clock
@ -76,21 +88,15 @@ void spiInitDevice(SPIDevice device)
// Init SPI hardware
SPI_I2S_DeInit(spi->dev);
SPI_InitTypeDef spiInit;
spiInit.SPI_Mode = SPI_Mode_Master;
spiInit.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
spiInit.SPI_DataSize = SPI_DataSize_8b;
spiInit.SPI_NSS = SPI_NSS_Soft;
spiInit.SPI_FirstBit = SPI_FirstBit_MSB;
spiInit.SPI_CRCPolynomial = 7;
spiInit.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8;
#ifndef USE_SPI_TRANSACTION
if (spi->leadingEdge) {
spiInit.SPI_CPOL = SPI_CPOL_Low;
spiInit.SPI_CPHA = SPI_CPHA_1Edge;
} else {
spiInit.SPI_CPOL = SPI_CPOL_High;
spiInit.SPI_CPHA = SPI_CPHA_2Edge;
defaultInit.SPI_CPOL = SPI_CPOL_Low;
defaultInit.SPI_CPHA = SPI_CPHA_1Edge;
} else
#endif
{
defaultInit.SPI_CPOL = SPI_CPOL_High;
defaultInit.SPI_CPHA = SPI_CPHA_2Edge;
}
#ifdef STM32F303xC
@ -98,7 +104,7 @@ void spiInitDevice(SPIDevice device)
SPI_RxFIFOThresholdConfig(spi->dev, SPI_RxFIFOThreshold_QF);
#endif
SPI_Init(spi->dev, &spiInit);
SPI_Init(spi->dev, &defaultInit);
SPI_Cmd(spi->dev, ENABLE);
}
@ -158,7 +164,9 @@ bool spiTransfer(SPI_TypeDef *instance, const uint8_t *txData, uint8_t *rxData,
#else
SPI_I2S_SendData(instance, b);
#endif
spiTimeout = 1000;
while (SPI_I2S_GetFlagStatus(instance, SPI_I2S_FLAG_RXNE) == RESET) {
if ((spiTimeout--) == 0)
return spiTimeoutUserCallback(instance);
@ -175,27 +183,86 @@ bool spiTransfer(SPI_TypeDef *instance, const uint8_t *txData, uint8_t *rxData,
return true;
}
void spiSetDivisor(SPI_TypeDef *instance, uint16_t divisor)
static uint16_t spiDivisorToBRbits(SPI_TypeDef *instance, uint16_t divisor)
{
#define BR_BITS ((BIT(5) | BIT(4) | BIT(3)))
#if !(defined(STM32F1) || defined(STM32F3))
// SPI2 and SPI3 are on APB1/AHB1 which PCLK is half that of APB2/AHB2.
if (instance == SPI2 || instance == SPI3) {
divisor /= 2; // Safe for divisor == 0 or 1
}
#else
UNUSED(instance);
#endif
divisor = constrain(divisor, 2, 256);
SPI_Cmd(instance, DISABLE);
return (ffs(divisor) - 2) << 3; // SPI_CR1_BR_Pos
}
static void spiSetDivisorBRreg(SPI_TypeDef *instance, uint16_t divisor)
{
#define BR_BITS ((BIT(5) | BIT(4) | BIT(3)))
const uint16_t tempRegister = (instance->CR1 & ~BR_BITS);
instance->CR1 = tempRegister | ((ffs(divisor) - 2) << 3);
SPI_Cmd(instance, ENABLE);
instance->CR1 = tempRegister | spiDivisorToBRbits(instance, divisor);
#undef BR_BITS
}
void spiSetDivisor(SPI_TypeDef *instance, uint16_t divisor)
{
SPI_Cmd(instance, DISABLE);
spiSetDivisorBRreg(instance, divisor);
SPI_Cmd(instance, ENABLE);
}
#ifdef USE_SPI_TRANSACTION
void spiBusTransactionInit(busDevice_t *bus, SPIMode_e mode, SPIClockDivider_e divider)
{
switch (mode) {
case SPI_MODE0_POL_LOW_EDGE_1ST:
defaultInit.SPI_CPOL = SPI_CPOL_Low;
defaultInit.SPI_CPHA = SPI_CPHA_1Edge;
break;
case SPI_MODE1_POL_LOW_EDGE_2ND:
defaultInit.SPI_CPOL = SPI_CPOL_Low;
defaultInit.SPI_CPHA = SPI_CPHA_2Edge;
break;
case SPI_MODE2_POL_HIGH_EDGE_1ST:
defaultInit.SPI_CPOL = SPI_CPOL_High;
defaultInit.SPI_CPHA = SPI_CPHA_1Edge;
break;
case SPI_MODE3_POL_HIGH_EDGE_2ND:
defaultInit.SPI_CPOL = SPI_CPOL_High;
defaultInit.SPI_CPHA = SPI_CPHA_2Edge;
break;
}
// Initialize the SPI instance to setup CR1
SPI_Init(bus->busdev_u.spi.instance, &defaultInit);
spiSetDivisorBRreg(bus->busdev_u.spi.instance, divider);
#ifdef STM32F303xC
// Configure for 8-bit reads.
SPI_RxFIFOThresholdConfig(bus->busdev_u.spi.instance, SPI_RxFIFOThreshold_QF);
#endif
bus->busdev_u.spi.modeCache = bus->busdev_u.spi.instance->CR1;
bus->busdev_u.spi.device = &spiDevice[spiDeviceByInstance(bus->busdev_u.spi.instance)];
}
void spiBusTransactionSetup(const busDevice_t *bus)
{
// We rely on MSTR bit to detect valid modeCache
if (bus->busdev_u.spi.modeCache && bus->busdev_u.spi.modeCache != bus->busdev_u.spi.device->cr1SoftCopy) {
bus->busdev_u.spi.instance->CR1 = bus->busdev_u.spi.modeCache;
bus->busdev_u.spi.device->cr1SoftCopy = bus->busdev_u.spi.modeCache;
// SCK seems to require some time to switch to a new initial level after CR1 is written.
// Here we buy some time in addition to the software copy save above.
__asm__("nop");
}
}
#endif // USE_SPI_TRANSACTION
#endif

View File

@ -366,7 +366,7 @@ static bool ak8963Init(magDev_t *mag)
return true;
}
void ak8963BusInit(const busDevice_t *busdev)
void ak8963BusInit(busDevice_t *busdev)
{
switch (busdev->bustype) {
#ifdef USE_MAG_AK8963
@ -380,7 +380,11 @@ void ak8963BusInit(const busDevice_t *busdev)
IOHi(busdev->busdev_u.spi.csnPin); // Disable
IOInit(busdev->busdev_u.spi.csnPin, OWNER_COMPASS_CS, 0);
IOConfigGPIO(busdev->busdev_u.spi.csnPin, IOCFG_OUT_PP);
spiSetDivisor(busdev->busdev_u.spi.instance, SPI_CLOCK_STANDARD);
#ifdef USE_SPI_TRANSACTION
spiBusTransactionInit(busdev, SPI_MODE3_POL_HIGH_EDGE_2ND, SPI_CLOCK_STANDARD);
#else
spiBusSetDivisor(busdev, SPI_CLOCK_STANDARD);
#endif
break;
#endif

View File

@ -190,7 +190,11 @@ static void hmc5883SpiInit(busDevice_t *busdev)
IOInit(busdev->busdev_u.spi.csnPin, OWNER_COMPASS_CS, 0);
IOConfigGPIO(busdev->busdev_u.spi.csnPin, IOCFG_OUT_PP);
spiSetDivisor(busdev->busdev_u.spi.instance, SPI_CLOCK_STANDARD);
#ifdef USE_SPI_TRANSACTION
spiBusTransactionInit(busdev, SPI_MODE3_POL_HIGH_EDGE_2ND, SPI_CLOCK_STANDARD);
#else
spiBusSetDivisor(busdev, SPI_CLOCK_STANDARD);
#endif
}
#endif

View File

@ -68,10 +68,14 @@ bool flashInit(const flashConfig_t *flashConfig)
IOConfigGPIO(busdev->busdev_u.spi.csnPin, SPI_IO_CS_CFG);
IOHi(busdev->busdev_u.spi.csnPin);
#ifdef USE_SPI_TRANSACTION
spiBusTransactionInit(busdev, SPI_MODE3_POL_HIGH_EDGE_2ND, SPI_CLOCK_FAST);
#else
#ifndef FLASH_SPI_SHARED
//Maximum speed for standard READ command is 20mHz, other commands tolerate 25mHz
//spiSetDivisor(busdev->busdev_u.spi.instance, SPI_CLOCK_FAST);
spiSetDivisor(busdev->busdev_u.spi.instance, SPI_CLOCK_STANDARD*2);
#endif
#endif
flashDevice.busdev = busdev;
@ -87,7 +91,11 @@ bool flashInit(const flashConfig_t *flashConfig)
in[1] = 0;
// Clearing the CS bit terminates the command early so we don't have to read the chip UID:
#ifdef USE_SPI_TRANSACTION
spiBusTransactionTransfer(busdev, out, in, sizeof(out));
#else
spiBusTransfer(busdev, out, in, sizeof(out));
#endif
// Manufacturer, memory type, and capacity
uint32_t chipID = (in[1] << 16) | (in[2] << 8) | (in[3]);

View File

@ -80,6 +80,7 @@ STATIC_ASSERT(M25P16_PAGESIZE < FLASH_MAX_PAGE_SIZE, M25P16_PAGESIZE_too_small);
const flashVTable_t m25p16_vTable;
#ifndef USE_SPI_TRANSACTION
static void m25p16_disable(busDevice_t *bus)
{
IOHi(bus->busdev_u.spi.csnPin);
@ -91,12 +92,17 @@ static void m25p16_enable(busDevice_t *bus)
__NOP();
IOLo(bus->busdev_u.spi.csnPin);
}
#endif
static void m25p16_transfer(busDevice_t *bus, const uint8_t *txData, uint8_t *rxData, int len)
{
#ifdef USE_SPI_TRANSACTION
spiBusTransactionTransfer(bus, txData, rxData, len);
#else
m25p16_enable(bus);
spiTransfer(bus->busdev_u.spi.instance, txData, rxData, len);
m25p16_disable(bus);
#endif
}
/**
@ -104,11 +110,13 @@ static void m25p16_transfer(busDevice_t *bus, const uint8_t *txData, uint8_t *rx
*/
static void m25p16_performOneByteCommand(busDevice_t *bus, uint8_t command)
{
#ifdef USE_SPI_TRANSACTION
m25p16_transfer(bus, &command, NULL, 1);
#else
m25p16_enable(bus);
spiTransferByte(bus->busdev_u.spi.instance, command);
m25p16_disable(bus);
#endif
}
/**
@ -269,13 +277,20 @@ static void m25p16_pageProgramContinue(flashDevice_t *fdevice, const uint8_t *da
m25p16_writeEnable(fdevice);
#ifdef USE_SPI_TRANSACTION
spiBusTransactionBegin(fdevice->busdev);
#else
m25p16_enable(fdevice->busdev);
#endif
spiTransfer(fdevice->busdev->busdev_u.spi.instance, command, NULL, fdevice->isLargeFlash ? 5 : 4);
spiTransfer(fdevice->busdev->busdev_u.spi.instance, data, NULL, length);
#ifdef USE_SPI_TRANSACTION
spiBusTransactionEnd(fdevice->busdev);
#else
m25p16_disable(fdevice->busdev);
#endif
fdevice->currentWriteAddress += length;
}
@ -327,12 +342,20 @@ static int m25p16_readBytes(flashDevice_t *fdevice, uint32_t address, uint8_t *b
return 0;
}
#ifdef USE_SPI_TRANSACTION
spiBusTransactionBegin(fdevice->busdev);
#else
m25p16_enable(fdevice->busdev);
#endif
spiTransfer(fdevice->busdev->busdev_u.spi.instance, command, NULL, fdevice->isLargeFlash ? 5 : 4);
spiTransfer(fdevice->busdev->busdev_u.spi.instance, NULL, buffer, length);
#ifdef USE_SPI_TRANSACTION
spiBusTransactionEnd(fdevice->busdev);
#else
m25p16_disable(fdevice->busdev);
#endif
return length;
}

View File

@ -69,7 +69,11 @@ static void w25m_dieSelect(busDevice_t *busdev, int die)
uint8_t command[2] = { W25M_INSTRUCTION_SOFTWARE_DIE_SELECT, die };
#ifdef SPI_BUS_TRANSACTION
spiBusTransactionTransfer(busdev, command, NULL, 2);
#else
spiBusTransfer(busdev, command, NULL, 2);
#endif
activeDie = die;
}

View File

@ -174,8 +174,12 @@
// On shared SPI buss we want to change clock for OSD chip and restore for other devices.
#ifdef USE_SPI_TRANSACTION
#define __spiBusTransactionBegin(busdev) spiBusTransactionBegin(busdev)
#define __spiBusTransactionEnd(busdev) spiBusTransactionEnd(busdev)
#else
#ifdef MAX7456_SPI_CLK
#define __spiBusTransactionBegin(busdev) {spiSetDivisor((busdev)->busdev_u.spi.instance, max7456SpiClock);IOLo((busdev)->busdev_u.spi.csnPin);}
#define __spiBusTransactionBegin(busdev) {spiBusSetDivisor(busdev, max7456SpiClock);IOLo((busdev)->busdev_u.spi.csnPin);}
#else
#define __spiBusTransactionBegin(busdev) IOLo((busdev)->busdev_u.spi.csnPin)
#endif
@ -185,6 +189,7 @@
#else
#define __spiBusTransactionEnd(busdev) IOHi((busdev)->busdev_u.spi.csnPin)
#endif
#endif
busDevice_t max7456BusDevice;
busDevice_t *busdev = &max7456BusDevice;
@ -476,7 +481,11 @@ bool max7456Init(const max7456Config_t *max7456Config, const vcdProfile_t *pVcdP
UNUSED(cpuOverclock);
#endif
spiSetDivisor(busdev->busdev_u.spi.instance, max7456SpiClock);
#ifdef USE_SPI_TRANSACTION
spiBusTransactionInit(busdev, SPI_MODE3_POL_HIGH_EDGE_2ND, max7456SpiClock);
#else
spiBusSetDivisor(busdev, max7456SpiClock);
#endif
// force soft reset on Max7456
__spiBusTransactionBegin(busdev);

View File

@ -54,11 +54,13 @@ void rxSpiDevicePreInit(const rxSpiConfig_t *rxSpiConfig)
bool rxSpiDeviceInit(const rxSpiConfig_t *rxSpiConfig)
{
if (!rxSpiConfig->spibus) {
SPI_TypeDef *instance = spiInstanceByDevice(SPI_CFG_TO_DEV(rxSpiConfig->spibus));
if (!instance) {
return false;
}
spiBusSetInstance(busdev, spiInstanceByDevice(SPI_CFG_TO_DEV(rxSpiConfig->spibus)));
spiBusSetInstance(busdev, instance);
const IO_t rxCsPin = IOGetByTag(rxSpiConfig->csnTag);
IOInit(rxCsPin, OWNER_RX_SPI_CS, 0);
@ -66,8 +68,11 @@ bool rxSpiDeviceInit(const rxSpiConfig_t *rxSpiConfig)
busdev->busdev_u.spi.csnPin = rxCsPin;
IOHi(rxCsPin);
spiSetDivisor(busdev->busdev_u.spi.instance, SPI_CLOCK_STANDARD);
#ifdef USE_SPI_TRANSACTION
spiBusTransactionInit(busdev, SPI_MODE0_POL_LOW_EDGE_1ST, SPI_CLOCK_STANDARD);
#else
spiBusSetDivisor(busdev, SPI_CLOCK_STANDARD);
#endif
return true;
}

View File

@ -55,6 +55,9 @@
/* Operational speed <= 25MHz */
#define SDCARD_SPI_FULL_SPEED_CLOCK_DIVIDER SPI_CLOCK_FAST
#define SDCARD_SPI_MODE SPI_MODE0_POL_LOW_EDGE_1ST
//#define SDCARD_SPI_MODE SPI_MODE3_POL_HIGH_EDGE_2ND
/* Break up 512-byte SD card sectors into chunks of this size when writing without DMA to reduce the peak overhead
* per call to sdcard_poll().
*/
@ -71,7 +74,11 @@ static bool sdcardSpi_isFunctional(void)
static void sdcard_select(void)
{
#ifdef USE_SPI_TRANSACTION
spiBusTransactionBegin(&sdcard.busdev);
#else
IOLo(sdcard.busdev.busdev_u.spi.csnPin);
#endif
}
static void sdcard_deselect(void)
@ -82,7 +89,12 @@ static void sdcard_deselect(void)
while (spiBusIsBusBusy(&sdcard.busdev)) {
}
delayMicroseconds(10);
#ifdef USE_SPI_TRANSACTION
spiBusTransactionEnd(&sdcard.busdev);
#else
IOHi(sdcard.busdev.busdev_u.spi.csnPin);
#endif
}
/**
@ -99,7 +111,11 @@ static void sdcard_reset(void)
}
if (sdcard.state >= SDCARD_STATE_READY) {
#ifdef USE_SPI_TRANSACTION
spiBusTransactionInit(&sdcard.busdev, SDCARD_SPI_MODE, SDCARD_SPI_INITIALIZATION_CLOCK_DIVIDER);
#else
spiSetDivisor(sdcard.busdev.busdev_u.spi.instance, SDCARD_SPI_INITIALIZATION_CLOCK_DIVIDER);
#endif
}
sdcard.failureCount++;
@ -535,14 +551,18 @@ static void sdcardSpi_init(const sdcardConfig_t *config, const spiPinConfig_t *s
}
// Max frequency is initially 400kHz
#ifdef USE_SPI_TRANSACTION
spiBusTransactionInit(&sdcard.busdev, SDCARD_SPI_MODE, SDCARD_SPI_INITIALIZATION_CLOCK_DIVIDER);
#else
spiSetDivisor(sdcard.busdev.busdev_u.spi.instance, SDCARD_SPI_INITIALIZATION_CLOCK_DIVIDER);
#endif
// SDCard wants 1ms minimum delay after power is applied to it
delay(1000);
// Transmit at least 74 dummy clock cycles with CS high so the SD card can start up
IOHi(sdcard.busdev.busdev_u.spi.csnPin);
spiBusRawTransfer(&sdcard.busdev, NULL, NULL, SDCARD_INIT_NUM_DUMMY_BYTES);
// Wait for that transmission to finish before we enable the SDCard, so it receives the required number of cycles:
@ -700,7 +720,12 @@ static bool sdcardSpi_poll(void)
}
// Now we're done with init and we can switch to the full speed clock (<25MHz)
#ifdef USE_SPI_TRANSACTION
spiBusTransactionInit(&sdcard.busdev, SDCARD_SPI_MODE, SDCARD_SPI_FULL_SPEED_CLOCK_DIVIDER);
#else
spiSetDivisor(sdcard.busdev.busdev_u.spi.instance, SDCARD_SPI_FULL_SPEED_CLOCK_DIVIDER);
#endif
sdcard.multiWriteBlocksRemain = 0;

View File

@ -64,6 +64,7 @@
#if defined(STM32F40_41xxx) || defined(STM32F411xE)
#define USE_OVERCLOCK
#define USE_SPI_TRANSACTION
#endif
#endif // STM32F4
@ -83,6 +84,7 @@
#define USE_PERSISTENT_MSC_RTC
#define USE_MCO
#define USE_DMA_SPEC
#define USE_SPI_TRANSACTION
#endif // STM32F7
#if defined(STM32F4) || defined(STM32F7)

View File

@ -147,7 +147,10 @@ void delay(uint32_t) {}
bool busReadRegisterBuffer(const busDevice_t*, uint8_t, uint8_t*, uint8_t) {return true;}
bool busWriteRegister(const busDevice_t*, uint8_t, uint8_t) {return true;}
void spiSetDivisor() {
void spiBusSetDivisor() {
}
void spiBusTransactionInit() {
}
void spiPreinitByIO() {

View File

@ -149,7 +149,7 @@ void delayMicroseconds(uint32_t) {}
bool busReadRegisterBuffer(const busDevice_t*, uint8_t, uint8_t*, uint8_t) {return true;}
bool busWriteRegister(const busDevice_t*, uint8_t, uint8_t) {return true;}
void spiSetDivisor() {
void spiBusSetDivisor() {
}
void spiPreinitByIO() {