1
0
Fork 0
mirror of https://github.com/betaflight/betaflight.git synced 2025-07-23 08:15:30 +03:00

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

@ -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