1
0
Fork 0
mirror of https://github.com/betaflight/betaflight.git synced 2025-07-15 20:35:33 +03:00

SPI CS preinit for configurability

This commit is contained in:
jflyper 2018-05-18 17:22:58 +09:00
parent ca09a8e2fc
commit f9a43099db
22 changed files with 219 additions and 113 deletions

View file

@ -86,9 +86,7 @@ void bmp280BusDeinit(busDevice_t *busdev)
{ {
#ifdef USE_BARO_SPI_BMP280 #ifdef USE_BARO_SPI_BMP280
if (busdev->bustype == BUSTYPE_SPI) { if (busdev->bustype == BUSTYPE_SPI) {
IOConfigGPIO(busdev->busdev_u.spi.csnPin, IOCFG_IPU); spiPreinitCsByIO(busdev->busdev_u.spi.csnPin);
IORelease(busdev->busdev_u.spi.csnPin);
IOInit(busdev->busdev_u.spi.csnPin, OWNER_SPI_PREINIT, 0);
} }
#else #else
UNUSED(busdev); UNUSED(busdev);

View file

@ -82,9 +82,7 @@ void ms5611BusDeinit(busDevice_t *busdev)
{ {
#ifdef USE_BARO_SPI_MS5611 #ifdef USE_BARO_SPI_MS5611
if (busdev->bustype == BUSTYPE_SPI) { if (busdev->bustype == BUSTYPE_SPI) {
IOConfigGPIO(busdev->busdev_u.spi.csnPin, IOCFG_IPU); spiPreinitCsByIO(busdev->busdev_u.spi.csnPin);
IORelease(busdev->busdev_u.spi.csnPin);
IOInit(busdev->busdev_u.spi.csnPin, OWNER_SPI_PREINIT, 0);
} }
#else #else
UNUSED(busdev); UNUSED(busdev);

View file

@ -92,8 +92,13 @@ typedef enum SPIDevice {
#define SPI_CFG_TO_DEV(x) ((x) - 1) #define SPI_CFG_TO_DEV(x) ((x) - 1)
#define SPI_DEV_TO_CFG(x) ((x) + 1) #define SPI_DEV_TO_CFG(x) ((x) + 1)
void spiPreInitCs(ioTag_t iotag); // Size of SPI CS pre-initialization tag arrays
void spiPreInitCsOutPU(ioTag_t iotag); #define SPI_PREINIT_IPU_COUNT 8
#define SPI_PREINIT_OPU_COUNT 2
void spiPreinitCsByTag(ioTag_t iotag);
void spiPreinitCsByIO(IO_t io);
void spiPreInit(void);
bool spiInit(SPIDevice device); bool spiInit(SPIDevice device);
void spiSetDivisor(SPI_TypeDef *instance, uint16_t divisor); void spiSetDivisor(SPI_TypeDef *instance, uint16_t divisor);

View file

@ -28,33 +28,80 @@
#include "drivers/bus_spi.h" #include "drivers/bus_spi.h"
#include "drivers/io.h" #include "drivers/io.h"
#include "pg/bus_spi.h"
// Bring a pin for possible CS line to pull-up state in preparation for // Bring a pin for possible CS line to pull-up state in preparation for
// sequential initialization by relevant drivers. // sequential initialization by relevant drivers.
// There are two versions: // There are two versions locally:
// spiPreInitCs set the pin to input with pullup (IOCFG_IPU) for safety at this point. // spiPreInitCsIPU set the pin to input with pullup (IOCFG_IPU) for safety.
// spiPreInitCsOutPU which actually drive the pin for digital hi. // spiPreInitCsOPU actually drive the pin for digital hi.
// //
// The later is required for SPI slave devices on some targets, interfaced through level shifters, such as Kakute F4. // The later is required for SPI slave devices on some targets, interfaced through level shifters, such as Kakute F4.
// Note that with this handling, a pin declared as CS pin for MAX7456 needs special care when re-purposing the pin for other, especially, input uses. //
// This will/should be fixed when we go fully reconfigurable. // Two ioTag_t array PGs, spiPreinitIPUConfig and spiPreinitOPUConfig are used to
// determine pin to be IPU or OPU.
// The IPU array is initialized with a hard coded initialization array,
// while the OPU array is initialized from target dependent config.c.
// With generic targets, both arrays are setup with resource commands.
void spiPreInitCs(ioTag_t iotag) static void spiPreInitCsIPU(ioTag_t iotag, int index)
{ {
IO_t io = IOGetByTag(iotag); IO_t io = IOGetByTag(iotag);
if (io) { if (io) {
IOInit(io, OWNER_SPI_PREINIT, 0); IOInit(io, OWNER_SPI_PREINIT_IPU, index);
IOConfigGPIO(io, IOCFG_IPU); IOConfigGPIO(io, IOCFG_IPU);
IOHi(io);
} }
} }
void spiPreInitCsOutPU(ioTag_t iotag) static void spiPreInitCsOPU(ioTag_t iotag, int index)
{ {
IO_t io = IOGetByTag(iotag); IO_t io = IOGetByTag(iotag);
if (io) { if (io) {
IOInit(io, OWNER_SPI_PREINIT, 0); IOInit(io, OWNER_SPI_PREINIT_OPU, index);
IOConfigGPIO(io, IOCFG_OUT_PP); IOConfigGPIO(io, IOCFG_OUT_PP);
IOHi(io); IOHi(io);
} }
} }
void spiPreInit(void)
{
for (int i = 0 ; i < SPI_PREINIT_IPU_COUNT ; i++) {
if (spiPreinitIPUConfig(i)->csnTag) {
spiPreInitCsIPU(spiPreinitIPUConfig(i)->csnTag, i);
}
}
for (int i = 0 ; i < SPI_PREINIT_OPU_COUNT ; i++) {
if (spiPreinitOPUConfig(i)->csnTag) {
spiPreInitCsOPU(spiPreinitOPUConfig(i)->csnTag, i);
}
}
}
// Back to pre-init state
void spiPreinitCsByIO(IO_t io)
{
for (int i = 0 ; i < SPI_PREINIT_IPU_COUNT ; i++) {
if (IOGetByTag(spiPreinitIPUConfig(i)->csnTag) == io) {
spiPreInitCsIPU(spiPreinitIPUConfig(i)->csnTag, i);
return;
}
}
for (int i = 0 ; i < SPI_PREINIT_OPU_COUNT ; i++) {
if (IOGetByTag(spiPreinitOPUConfig(i)->csnTag) == io) {
spiPreInitCsOPU(spiPreinitOPUConfig(i)->csnTag, i);
return;
}
}
}
void spiPreinitCsByTag(ioTag_t iotag)
{
spiPreinitCsByIO(IOGetByTag(iotag));
}
#endif #endif

View file

@ -410,9 +410,7 @@ void ak8963BusDeInit(const busDevice_t *busdev)
#ifdef USE_MAG_SPI_AK8963 #ifdef USE_MAG_SPI_AK8963
case BUSTYPE_SPI: case BUSTYPE_SPI:
IOConfigGPIO(busdev->busdev_u.spi.csnPin, IOCFG_IPU); spiPreinitCsByIO(busdev->busdev_u.spi.csnPin);
IORelease(busdev->busdev_u.spi.csnPin);
IOInit(busdev->busdev_u.spi.csnPin, OWNER_SPI_PREINIT, 0);
break; break;
#endif #endif

View file

@ -52,7 +52,7 @@ bool flashInit(const flashConfig_t *flashConfig)
return false; return false;
} }
if (IOGetOwner(busdev->busdev_u.spi.csnPin) != OWNER_SPI_PREINIT) { if (!IOIsFreeOrPreinit(busdev->busdev_u.spi.csnPin)) {
return false; return false;
} }
@ -99,7 +99,7 @@ bool flashInit(const flashConfig_t *flashConfig)
} }
#endif #endif
spiPreInitCs(flashConfig->csTag); spiPreinitCsByTag(flashConfig->csTag);
return false; return false;
} }

View file

@ -275,6 +275,17 @@ resourceOwner_e IOGetOwner(IO_t io)
return ioRec->owner; return ioRec->owner;
} }
bool IOIsFreeOrPreinit(IO_t io)
{
resourceOwner_e owner = IOGetOwner(io);
if (owner == OWNER_FREE || owner == OWNER_SPI_PREINIT_IPU || owner == OWNER_SPI_PREINIT_OPU) {
return true;
}
return false;
}
#if defined(STM32F1) #if defined(STM32F1)
void IOConfigGPIO(IO_t io, ioConfig_t cfg) void IOConfigGPIO(IO_t io, ioConfig_t cfg)
@ -414,3 +425,4 @@ IO_t IOGetByTag(ioTag_t tag)
offset += ioDefUsedOffset[portIdx]; offset += ioDefUsedOffset[portIdx];
return ioRecs + offset; return ioRecs + offset;
} }

View file

@ -110,6 +110,7 @@ void IOToggle(IO_t io);
void IOInit(IO_t io, resourceOwner_e owner, uint8_t index); void IOInit(IO_t io, resourceOwner_e owner, uint8_t index);
void IORelease(IO_t io); // unimplemented void IORelease(IO_t io); // unimplemented
resourceOwner_e IOGetOwner(IO_t io); resourceOwner_e IOGetOwner(IO_t io);
bool IOIsFreeOrPreinit(IO_t io);
IO_t IOGetByTag(ioTag_t tag); IO_t IOGetByTag(ioTag_t tag);
void IOConfigGPIO(IO_t io, ioConfig_t cfg); void IOConfigGPIO(IO_t io, ioConfig_t cfg);

View file

@ -425,7 +425,7 @@ void max7456Init(const max7456Config_t *max7456Config, const vcdProfile_t *pVcdP
busdev->busdev_u.spi.csnPin = IOGetByTag(max7456Config->csTag); busdev->busdev_u.spi.csnPin = IOGetByTag(max7456Config->csTag);
if (IOGetOwner(busdev->busdev_u.spi.csnPin) != OWNER_SPI_PREINIT) { if (!IOIsFreeOrPreinit(busdev->busdev_u.spi.csnPin)) {
return; return;
} }

View file

@ -66,7 +66,6 @@ const char * const ownerNames[OWNER_TOTAL_COUNT] = {
"TRANSPONDER", "TRANSPONDER",
"VTX", "VTX",
"COMPASS_CS", "COMPASS_CS",
"SPI_PREINIT",
"RX_BIND_PLUG", "RX_BIND_PLUG",
"ESCSERIAL", "ESCSERIAL",
"CAMERA_CONTROL", "CAMERA_CONTROL",
@ -75,4 +74,6 @@ const char * const ownerNames[OWNER_TOTAL_COUNT] = {
"RX_SPI", "RX_SPI",
"PINIO", "PINIO",
"USB_MSC_PIN", "USB_MSC_PIN",
"SPI_PREINIT_IPU",
"SPI_PREINIT_OPU",
}; };

View file

@ -66,7 +66,6 @@ typedef enum {
OWNER_TRANSPONDER, OWNER_TRANSPONDER,
OWNER_VTX, OWNER_VTX,
OWNER_COMPASS_CS, OWNER_COMPASS_CS,
OWNER_SPI_PREINIT,
OWNER_RX_BIND_PLUG, OWNER_RX_BIND_PLUG,
OWNER_ESCSERIAL, OWNER_ESCSERIAL,
OWNER_CAMERA_CONTROL, OWNER_CAMERA_CONTROL,
@ -75,6 +74,8 @@ typedef enum {
OWNER_RX_SPI, OWNER_RX_SPI,
OWNER_PINIO, OWNER_PINIO,
OWNER_USB_MSC_PIN, OWNER_USB_MSC_PIN,
OWNER_SPI_PREINIT_IPU,
OWNER_SPI_PREINIT_OPU,
OWNER_TOTAL_COUNT OWNER_TOTAL_COUNT
} resourceOwner_e; } resourceOwner_e;

View file

@ -197,73 +197,6 @@ static IO_t busSwitchResetPin = IO_NONE;
} }
#endif #endif
#ifdef USE_SPI
// Pre-initialize all CS pins to input with pull-up.
// It's sad that we can't do this with an initialized array,
// since we will be taking care of configurable CS pins shortly.
void spiPreInit(void)
{
#ifdef GYRO_1_CS_PIN
spiPreInitCs(IO_TAG(GYRO_1_CS_PIN));
#endif
#ifdef GYRO_2_CS_PIN
spiPreInitCs(IO_TAG(GYRO_2_CS_PIN));
#endif
#ifdef MPU6000_CS_PIN
spiPreInitCs(IO_TAG(MPU6000_CS_PIN));
#endif
#ifdef MPU6500_CS_PIN
spiPreInitCs(IO_TAG(MPU6500_CS_PIN));
#endif
#ifdef MPU9250_CS_PIN
spiPreInitCs(IO_TAG(MPU9250_CS_PIN));
#endif
#ifdef ICM20649_CS_PIN
spiPreInitCs(IO_TAG(ICM20649_CS_PIN));
#endif
#ifdef ICM20689_CS_PIN
spiPreInitCs(IO_TAG(ICM20689_CS_PIN));
#endif
#ifdef BMI160_CS_PIN
spiPreInitCs(IO_TAG(BMI160_CS_PIN));
#endif
#ifdef L3GD20_CS_PIN
spiPreInitCs(IO_TAG(L3GD20_CS_PIN));
#endif
#ifdef MAX7456_SPI_CS_PIN
spiPreInitCsOutPU(IO_TAG(MAX7456_SPI_CS_PIN)); // XXX 3.2 workaround for Kakute F4. See comment for spiPreInitCSOutPU.
#endif
#ifdef USE_SDCARD
spiPreInitCs(sdcardConfig()->chipSelectTag);
#endif
#ifdef BMP280_CS_PIN
spiPreInitCs(IO_TAG(BMP280_CS_PIN));
#endif
#ifdef MS5611_CS_PIN
spiPreInitCs(IO_TAG(MS5611_CS_PIN));
#endif
#ifdef LPS_CS_PIN
spiPreInitCs(IO_TAG(LPS_CS_PIN));
#endif
#ifdef HMC5883_CS_PIN
spiPreInitCs(IO_TAG(HMC5883_CS_PIN));
#endif
#ifdef AK8963_CS_PIN
spiPreInitCs(IO_TAG(AK8963_CS_PIN));
#endif
#if defined(RTC6705_CS_PIN) && !defined(USE_VTX_RTC6705_SOFTSPI) // RTC6705 soft SPI initialisation handled elsewhere.
spiPreInitCs(IO_TAG(RTC6705_CS_PIN));
#endif
#ifdef FLASH_CS_PIN
spiPreInitCs(IO_TAG(FLASH_CS_PIN));
#endif
#if defined(USE_RX_SPI)
spiPreInitCs(IO_TAG(RX_NSS_PIN));
#endif
}
#endif
void init(void) void init(void)
{ {
#ifdef USE_ITCM_RAM #ifdef USE_ITCM_RAM

View file

@ -3580,6 +3580,10 @@ const cliResourceValue_t resourceTable[] = {
#ifdef USE_MAX7456 #ifdef USE_MAX7456
DEFS( OWNER_OSD_CS, PG_MAX7456_CONFIG, max7456Config_t, csTag ), DEFS( OWNER_OSD_CS, PG_MAX7456_CONFIG, max7456Config_t, csTag ),
#endif #endif
#ifdef USE_SPI
DEFA( OWNER_SPI_PREINIT_IPU, PG_SPI_PREINIT_IPU_CONFIG, spiCs_t, csnTag, SPI_PREINIT_IPU_COUNT ),
DEFA( OWNER_SPI_PREINIT_OPU, PG_SPI_PREINIT_OPU_CONFIG, spiCs_t, csnTag, SPI_PREINIT_OPU_COUNT ),
#endif
}; };
#undef DEFS #undef DEFS

View file

@ -123,20 +123,6 @@ static IO_t busSwitchResetPin = IO_NONE;
} }
#endif #endif
#ifdef USE_SPI
// Pre-initialize all CS pins to input with pull-up.
// It's sad that we can't do this with an initialized array,
// since we will be taking care of configurable CS pins shortly.
void spiPreInit(void)
{
#ifdef USE_MAX7456
spiPreInitCs(IO_TAG(MAX7456_SPI_CS_PIN));
#endif
}
#endif
void init(void) void init(void)
{ {
#ifdef USE_HAL_DRIVER #ifdef USE_HAL_DRIVER

View file

@ -62,4 +62,87 @@ void pgResetFn_spiPinConfig(spiPinConfig_t *spiPinConfig)
spiPinConfig[defconf->device].ioTagMosi = defconf->mosi; spiPinConfig[defconf->device].ioTagMosi = defconf->mosi;
} }
} }
PG_REGISTER_ARRAY_WITH_RESET_FN(spiCs_t, SPI_PREINIT_IPU_COUNT, spiPreinitIPUConfig, PG_SPI_PREINIT_IPU_CONFIG, 0);
PG_REGISTER_ARRAY(spiCs_t, SPI_PREINIT_OPU_COUNT, spiPreinitOPUConfig, PG_SPI_PREINIT_OPU_CONFIG, 0);
// Initialization values for input pull-up are listed here.
// Explicit output with pull-up should handled in target dependent config.c.
// Generic target will be specifying both values by resource commands.
ioTag_t preinitIPUList[SPI_PREINIT_IPU_COUNT] = {
#ifdef GYRO_1_CS_PIN
IO_TAG(GYRO_1_CS_PIN),
#endif
#ifdef GYRO_2_CS_PIN
IO_TAG(GYRO_2_CS_PIN),
#endif
#ifdef MPU6000_CS_PIN
IO_TAG(MPU6000_CS_PIN),
#endif
#ifdef MPU6500_CS_PIN
IO_TAG(MPU6500_CS_PIN),
#endif
#ifdef MPU9250_CS_PIN
IO_TAG(MPU9250_CS_PIN),
#endif
#ifdef ICM20649_CS_PIN
IO_TAG(ICM20649_CS_PIN),
#endif
#ifdef ICM20689_CS_PIN
IO_TAG(ICM20689_CS_PIN),
#endif
#ifdef BMI160_CS_PIN
IO_TAG(BMI160_CS_PIN),
#endif
#ifdef L3GD20_CS_PIN
IO_TAG(L3GD20_CS_PIN),
#endif
#ifdef SDCARD_SPI_CS_PIN
IO_TAG(SDCARD_SPI_CS_PIN),
#endif
#ifdef BMP280_CS_PIN
IO_TAG(BMP280_CS_PIN),
#endif
#ifdef MS5611_CS_PIN
IO_TAG(MS5611_CS_PIN),
#endif
#ifdef LPS_CS_PIN
IO_TAG(LPS_CS_PIN),
#endif
#ifdef HMC5883_CS_PIN
IO_TAG(HMC5883_CS_PIN),
#endif
#ifdef AK8963_CS_PIN
IO_TAG(AK8963_CS_PIN),
#endif
#if defined(RTC6705_CS_PIN) && !defined(USE_VTX_RTC6705_SOFTSPI) // RTC6705 soft SPI initialisation handled elsewhere.
IO_TAG(RTC6705_CS_PIN),
#endif
#ifdef FLASH_CS_PIN
IO_TAG(FLASH_CS_PIN),
#endif
#if defined(USE_RX_SPI) && !defined(USE_RX_SOFTSPI)
IO_TAG(RX_NSS_PIN),
#endif
#if defined(MAX7456_SPI_CS_PIN)
IO_TAG(MAX7456_SPI_CS_PIN),
#endif
IO_TAG(NONE)
};
void pgResetFn_spiPreinitIPUConfig(spiCs_t *config)
{
int puPins = 0;
for (int i = 0 ; i < SPI_PREINIT_IPU_COUNT ; i++) {
for (int j = 0 ; j < i ; j++) {
if (config[j].csnTag == preinitIPUList[i]) {
goto next;
}
}
config[puPins++].csnTag = preinitIPUList[i];
next:;
}
}
#endif #endif

View file

@ -32,3 +32,12 @@ typedef struct spiPinConfig_s {
} spiPinConfig_t; } spiPinConfig_t;
PG_DECLARE_ARRAY(spiPinConfig_t, SPIDEV_COUNT, spiPinConfig); PG_DECLARE_ARRAY(spiPinConfig_t, SPIDEV_COUNT, spiPinConfig);
// Place holder for CS pins for pre-initialization
typedef struct spiCs_s {
ioTag_t csnTag;
} spiCs_t;
PG_DECLARE_ARRAY(spiCs_t, SPI_PREINIT_IPU_COUNT, spiPreinitIPUConfig);
PG_DECLARE_ARRAY(spiCs_t, SPI_PREINIT_OPU_COUNT, spiPreinitOPUConfig);

View file

@ -129,7 +129,9 @@
#define PG_SDIO_CONFIG 532 #define PG_SDIO_CONFIG 532
#define PG_DISPLAY_PORT_CRSF_CONFIG 533 // no longer required -- never released #define PG_DISPLAY_PORT_CRSF_CONFIG 533 // no longer required -- never released
#define PG_TIMER_IO_CONFIG 534 // used to store the index for timer use in timerHardware array in target.c #define PG_TIMER_IO_CONFIG 534 // used to store the index for timer use in timerHardware array in target.c
#define PG_BETAFLIGHT_END 534 #define PG_SPI_PREINIT_IPU_CONFIG 535
#define PG_SPI_PREINIT_OPU_CONFIG 536
#define PG_BETAFLIGHT_END 536
// OSD configuration (subject to change) // OSD configuration (subject to change)

View file

@ -25,13 +25,11 @@
#ifdef USE_TARGET_CONFIG #ifdef USE_TARGET_CONFIG
#include "io/serial.h"
#include "rx/rx.h"
#include "telemetry/telemetry.h"
#include "config_helper.h" #include "config_helper.h"
#include "io/serial.h"
#include "pg/bus_spi.h"
#include "rx/rx.h"
#include "telemetry/telemetry.h"
#define TELEMETRY_UART SERIAL_PORT_USART1 #define TELEMETRY_UART SERIAL_PORT_USART1
@ -44,5 +42,23 @@ void targetConfiguration(void)
targetSerialPortFunctionConfig(targetSerialPortFunction, ARRAYLEN(targetSerialPortFunction)); targetSerialPortFunctionConfig(targetSerialPortFunction, ARRAYLEN(targetSerialPortFunction));
telemetryConfigMutable()->halfDuplex = 0; telemetryConfigMutable()->halfDuplex = 0;
telemetryConfigMutable()->telemetry_inverted = true; telemetryConfigMutable()->telemetry_inverted = true;
// Register MAX7456 CS pin as OPU
// Invalidate IPU entry first
for (int i = 0 ; i < SPI_PREINIT_IPU_COUNT ; i++) {
if (spiPreinitIPUConfig(i)->csnTag == IO_TAG(MAX7456_SPI_CS_PIN)) {
spiPreinitIPUConfigMutable(i)->csnTag = IO_TAG(NONE);
break;
}
}
// Add as OPU entry
for (int i = 0 ; i < SPI_PREINIT_OPU_COUNT ; i++) {
if (spiPreinitOPUConfig(i)->csnTag == IO_TAG(NONE)) {
spiPreinitOPUConfigMutable(i)->csnTag = IO_TAG(MAX7456_SPI_CS_PIN);
break;
}
}
} }
#endif #endif

View file

@ -30,6 +30,10 @@ resource SPI_SCK 3 C10
resource SPI_MISO 3 C11 resource SPI_MISO 3 C11
resource SPI_MOSI 3 C12 resource SPI_MOSI 3 C12
# SPI CS pins to pre-initialize
resource SPI_PREINIT_IPU 1 C04 // MPU6500
resource SPI_PREINIT_IPU 2 A15 // SDCARD
# Timers # Timers
# First four timers # First four timers
# timer is zero origin # timer is zero origin

View file

@ -20,6 +20,7 @@
// pg/max7456 // pg/max7456
#ifdef USE_MAX7456
#ifndef MAX7456_CLOCK_CONFIG_DEFAULT #ifndef MAX7456_CLOCK_CONFIG_DEFAULT
#define MAX7456_CLOCK_CONFIG_DEFAULT MAX7456_CLOCK_CONFIG_OC #define MAX7456_CLOCK_CONFIG_DEFAULT MAX7456_CLOCK_CONFIG_OC
#endif #endif
@ -27,6 +28,7 @@
#ifndef MAX7456_SPI_CS_PIN #ifndef MAX7456_SPI_CS_PIN
#define MAX7456_SPI_CS_PIN NONE #define MAX7456_SPI_CS_PIN NONE
#endif #endif
#endif
// pg/bus_i2c // pg/bus_i2c

View file

@ -150,6 +150,9 @@ bool busWriteRegister(const busDevice_t*, uint8_t, uint8_t) {return true;}
void spiSetDivisor() { void spiSetDivisor() {
} }
void spiPreinitCsByIO() {
}
void IOConfigGPIO() { void IOConfigGPIO() {
} }

View file

@ -152,6 +152,9 @@ bool busWriteRegister(const busDevice_t*, uint8_t, uint8_t) {return true;}
void spiSetDivisor() { void spiSetDivisor() {
} }
void spiPreinitCsByIO() {
}
void IOConfigGPIO() { void IOConfigGPIO() {
} }