[FL-2060] FuriHal: SPI refactoring, flexible bus reconfiguration on fly, same design as i2c. (#853)

* FuriHal: SPI refactoring, flexible bus reconfigration on fly, same desiag as i2c.
* Lib: update CC1101 driver documentation
* FuriHal: update spi symbol names to match naming convention.
This commit is contained in:
あく
2021-11-30 15:09:43 +03:00
committed by GitHub
parent d86125c7f7
commit 9d27ef8901
36 changed files with 2057 additions and 1612 deletions

View File

@@ -1,10 +1,9 @@
#include <furi-hal-spi-config.h>
#include <furi-hal-resources.h>
#define SPI_R SPI1
#define SPI_D SPI2
/* SPI Presets */
const LL_SPI_InitTypeDef furi_hal_spi_config_nfc = {
const LL_SPI_InitTypeDef furi_hal_spi_preset_2edge_low_8m = {
.Mode = LL_SPI_MODE_MASTER,
.TransferDirection = LL_SPI_FULL_DUPLEX,
.DataWidth = LL_SPI_DATAWIDTH_8BIT,
@@ -17,7 +16,7 @@ const LL_SPI_InitTypeDef furi_hal_spi_config_nfc = {
.CRCPoly = 7,
};
const LL_SPI_InitTypeDef furi_hal_spi_config_subghz = {
const LL_SPI_InitTypeDef furi_hal_spi_preset_1edge_low_8m = {
.Mode = LL_SPI_MODE_MASTER,
.TransferDirection = LL_SPI_FULL_DUPLEX,
.DataWidth = LL_SPI_DATAWIDTH_8BIT,
@@ -30,7 +29,7 @@ const LL_SPI_InitTypeDef furi_hal_spi_config_subghz = {
.CRCPoly = 7,
};
const LL_SPI_InitTypeDef furi_hal_spi_config_display = {
const LL_SPI_InitTypeDef furi_hal_spi_preset_1edge_low_4m = {
.Mode = LL_SPI_MODE_MASTER,
.TransferDirection = LL_SPI_FULL_DUPLEX,
.DataWidth = LL_SPI_DATAWIDTH_8BIT,
@@ -43,10 +42,7 @@ const LL_SPI_InitTypeDef furi_hal_spi_config_display = {
.CRCPoly = 7,
};
/**
* SD Card in fast mode (after init)
*/
const LL_SPI_InitTypeDef furi_hal_spi_config_sd_fast = {
const LL_SPI_InitTypeDef furi_hal_spi_preset_1edge_low_16m = {
.Mode = LL_SPI_MODE_MASTER,
.TransferDirection = LL_SPI_FULL_DUPLEX,
.DataWidth = LL_SPI_DATAWIDTH_8BIT,
@@ -59,10 +55,7 @@ const LL_SPI_InitTypeDef furi_hal_spi_config_sd_fast = {
.CRCPoly = 7,
};
/**
* SD Card in slow mode (before init)
*/
const LL_SPI_InitTypeDef furi_hal_spi_config_sd_slow = {
const LL_SPI_InitTypeDef furi_hal_spi_preset_1edge_low_2m = {
.Mode = LL_SPI_MODE_MASTER,
.TransferDirection = LL_SPI_FULL_DUPLEX,
.DataWidth = LL_SPI_DATAWIDTH_8BIT,
@@ -75,40 +68,223 @@ const LL_SPI_InitTypeDef furi_hal_spi_config_sd_slow = {
.CRCPoly = 7,
};
const FuriHalSpiBus spi_r = {
.spi = SPI_R,
/* SPI Buses */
static void furi_hal_spi_bus_r_event_callback(FuriHalSpiBus* bus, FuriHalSpiBusEvent event) {
if(event == FuriHalSpiBusEventInit) {
LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_SPI1);
LL_APB2_GRP1_ForceReset(LL_APB2_GRP1_PERIPH_SPI1);
bus->current_handle = NULL;
} else if(event == FuriHalSpiBusEventDeinit) {
} else if(event == FuriHalSpiBusEventLock) {
} else if(event == FuriHalSpiBusEventUnlock) {
} else if(event == FuriHalSpiBusEventActivate) {
LL_APB2_GRP1_ReleaseReset(LL_APB2_GRP1_PERIPH_SPI1);
} else if(event == FuriHalSpiBusEventDeactivate) {
LL_APB2_GRP1_ForceReset(LL_APB2_GRP1_PERIPH_SPI1);
}
}
FuriHalSpiBus furi_hal_spi_bus_r = {
.spi = SPI1,
.callback = furi_hal_spi_bus_r_event_callback,
};
static void furi_hal_spi_bus_d_event_callback(FuriHalSpiBus* bus, FuriHalSpiBusEvent event) {
if(event == FuriHalSpiBusEventInit) {
LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_SPI2);
LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_SPI2);
bus->current_handle = NULL;
} else if(event == FuriHalSpiBusEventDeinit) {
} else if(event == FuriHalSpiBusEventLock) {
} else if(event == FuriHalSpiBusEventUnlock) {
} else if(event == FuriHalSpiBusEventActivate) {
LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_SPI2);
} else if(event == FuriHalSpiBusEventDeactivate) {
LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_SPI2);
}
}
FuriHalSpiBus furi_hal_spi_bus_d = {
.spi = SPI2,
.callback = furi_hal_spi_bus_d_event_callback,
};
/* SPI Bus Handles */
inline static void furi_hal_spi_bus_r_handle_event_callback(
FuriHalSpiBusHandle* handle,
FuriHalSpiBusHandleEvent event,
const LL_SPI_InitTypeDef* preset) {
if(event == FuriHalSpiBusHandleEventInit) {
hal_gpio_write(handle->cs, true);
hal_gpio_init(handle->cs, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh);
} else if(event == FuriHalSpiBusHandleEventDeinit) {
hal_gpio_write(handle->cs, true);
hal_gpio_init(handle->cs, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
} else if(event == FuriHalSpiBusHandleEventActivate) {
LL_SPI_Init(handle->bus->spi, (LL_SPI_InitTypeDef*)preset);
LL_SPI_SetRxFIFOThreshold(handle->bus->spi, LL_SPI_RX_FIFO_TH_QUARTER);
LL_SPI_Enable(handle->bus->spi);
hal_gpio_init_ex(
handle->miso,
GpioModeAltFunctionPushPull,
GpioPullNo,
GpioSpeedVeryHigh,
GpioAltFn5SPI1);
hal_gpio_init_ex(
handle->mosi,
GpioModeAltFunctionPushPull,
GpioPullNo,
GpioSpeedVeryHigh,
GpioAltFn5SPI1);
hal_gpio_init_ex(
handle->sck,
GpioModeAltFunctionPushPull,
GpioPullNo,
GpioSpeedVeryHigh,
GpioAltFn5SPI1);
hal_gpio_write(handle->cs, false);
} else if(event == FuriHalSpiBusHandleEventDeactivate) {
hal_gpio_write(handle->cs, true);
hal_gpio_init(handle->miso, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
hal_gpio_init(handle->mosi, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
hal_gpio_init(handle->sck, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
LL_SPI_Disable(handle->bus->spi);
}
}
static void furi_hal_spi_bus_handle_subghz_event_callback(
FuriHalSpiBusHandle* handle,
FuriHalSpiBusHandleEvent event) {
furi_hal_spi_bus_r_handle_event_callback(handle, event, &furi_hal_spi_preset_1edge_low_8m);
}
FuriHalSpiBusHandle furi_hal_spi_bus_handle_subghz = {
.bus = &furi_hal_spi_bus_r,
.callback = furi_hal_spi_bus_handle_subghz_event_callback,
.miso = &gpio_spi_r_miso,
.mosi = &gpio_spi_r_mosi,
.clk = &gpio_spi_r_sck,
.sck = &gpio_spi_r_sck,
.cs = &gpio_subghz_cs,
};
const FuriHalSpiBus spi_d = {
.spi = SPI_D,
static void furi_hal_spi_bus_handle_nfc_event_callback(
FuriHalSpiBusHandle* handle,
FuriHalSpiBusHandleEvent event) {
furi_hal_spi_bus_r_handle_event_callback(handle, event, &furi_hal_spi_preset_2edge_low_8m);
}
FuriHalSpiBusHandle furi_hal_spi_bus_handle_nfc = {
.bus = &furi_hal_spi_bus_r,
.callback = furi_hal_spi_bus_handle_nfc_event_callback,
.miso = &gpio_spi_r_miso,
.mosi = &gpio_spi_r_mosi,
.sck = &gpio_spi_r_sck,
.cs = &gpio_nfc_cs,
};
static void furi_hal_spi_bus_handle_external_event_callback(
FuriHalSpiBusHandle* handle,
FuriHalSpiBusHandleEvent event) {
furi_hal_spi_bus_r_handle_event_callback(handle, event, &furi_hal_spi_preset_1edge_low_2m);
}
FuriHalSpiBusHandle furi_hal_spi_bus_handle_external = {
.bus = &furi_hal_spi_bus_r,
.callback = furi_hal_spi_bus_handle_external_event_callback,
.miso = &gpio_ext_pa6,
.mosi = &gpio_ext_pa7,
.sck = &gpio_ext_pb3,
.cs = &gpio_ext_pa4,
};
inline static void furi_hal_spi_bus_d_handle_event_callback(
FuriHalSpiBusHandle* handle,
FuriHalSpiBusHandleEvent event,
const LL_SPI_InitTypeDef* preset) {
if(event == FuriHalSpiBusHandleEventInit) {
hal_gpio_write(handle->cs, true);
hal_gpio_init(handle->cs, GpioModeOutputPushPull, GpioPullUp, GpioSpeedVeryHigh);
hal_gpio_init_ex(
handle->miso,
GpioModeAltFunctionPushPull,
GpioPullNo,
GpioSpeedVeryHigh,
GpioAltFn5SPI2);
hal_gpio_init_ex(
handle->mosi,
GpioModeAltFunctionPushPull,
GpioPullNo,
GpioSpeedVeryHigh,
GpioAltFn5SPI2);
hal_gpio_init_ex(
handle->sck,
GpioModeAltFunctionPushPull,
GpioPullNo,
GpioSpeedVeryHigh,
GpioAltFn5SPI2);
} else if(event == FuriHalSpiBusHandleEventDeinit) {
hal_gpio_write(handle->cs, true);
hal_gpio_init(handle->cs, GpioModeAnalog, GpioPullUp, GpioSpeedLow);
} else if(event == FuriHalSpiBusHandleEventActivate) {
LL_SPI_Init(handle->bus->spi, (LL_SPI_InitTypeDef*)preset);
LL_SPI_SetRxFIFOThreshold(handle->bus->spi, LL_SPI_RX_FIFO_TH_QUARTER);
LL_SPI_Enable(handle->bus->spi);
hal_gpio_write(handle->cs, false);
} else if(event == FuriHalSpiBusHandleEventDeactivate) {
hal_gpio_write(handle->cs, true);
LL_SPI_Disable(handle->bus->spi);
}
}
static void furi_hal_spi_bus_handle_display_event_callback(
FuriHalSpiBusHandle* handle,
FuriHalSpiBusHandleEvent event) {
furi_hal_spi_bus_d_handle_event_callback(handle, event, &furi_hal_spi_preset_1edge_low_4m);
}
FuriHalSpiBusHandle furi_hal_spi_bus_handle_display = {
.bus = &furi_hal_spi_bus_d,
.callback = furi_hal_spi_bus_handle_display_event_callback,
.miso = &gpio_spi_d_miso,
.mosi = &gpio_spi_d_mosi,
.clk = &gpio_spi_d_sck,
.sck = &gpio_spi_d_sck,
.cs = &gpio_display_cs,
};
const FuriHalSpiDevice furi_hal_spi_devices[FuriHalSpiDeviceIdMax] = {
{
.bus = &spi_r,
.config = &furi_hal_spi_config_subghz,
.chip_select = &gpio_subghz_cs,
},
{
.bus = &spi_d,
.config = &furi_hal_spi_config_display,
.chip_select = &gpio_display_cs,
},
{
.bus = &spi_d,
.config = &furi_hal_spi_config_sd_fast,
.chip_select = &gpio_sdcard_cs,
},
{
.bus = &spi_d,
.config = &furi_hal_spi_config_sd_slow,
.chip_select = &gpio_sdcard_cs,
},
{.bus = &spi_r, .config = &furi_hal_spi_config_nfc, .chip_select = &gpio_nfc_cs},
static void furi_hal_spi_bus_handle_sd_fast_event_callback(
FuriHalSpiBusHandle* handle,
FuriHalSpiBusHandleEvent event) {
furi_hal_spi_bus_d_handle_event_callback(handle, event, &furi_hal_spi_preset_1edge_low_16m);
}
FuriHalSpiBusHandle furi_hal_spi_bus_handle_sd_fast = {
.bus = &furi_hal_spi_bus_d,
.callback = furi_hal_spi_bus_handle_sd_fast_event_callback,
.miso = &gpio_spi_d_miso,
.mosi = &gpio_spi_d_mosi,
.sck = &gpio_spi_d_sck,
.cs = &gpio_sdcard_cs,
};
static void furi_hal_spi_bus_handle_sd_slow_event_callback(
FuriHalSpiBusHandle* handle,
FuriHalSpiBusHandleEvent event) {
furi_hal_spi_bus_d_handle_event_callback(handle, event, &furi_hal_spi_preset_1edge_low_2m);
}
FuriHalSpiBusHandle furi_hal_spi_bus_handle_sd_slow = {
.bus = &furi_hal_spi_bus_d,
.callback = furi_hal_spi_bus_handle_sd_slow_event_callback,
.miso = &gpio_spi_d_miso,
.mosi = &gpio_spi_d_mosi,
.sck = &gpio_spi_d_sck,
.cs = &gpio_sdcard_cs,
};

View File

@@ -1,60 +1,60 @@
#pragma once
#include <furi-hal-gpio.h>
#include <stm32wbxx_ll_spi.h>
#include <furi-hal-spi-types.h>
#ifdef __cplusplus
extern "C" {
#endif
extern const LL_SPI_InitTypeDef furi_hal_spi_config_nfc;
extern const LL_SPI_InitTypeDef furi_hal_spi_config_subghz;
extern const LL_SPI_InitTypeDef furi_hal_spi_config_display;
extern const LL_SPI_InitTypeDef furi_hal_spi_config_sd_fast;
extern const LL_SPI_InitTypeDef furi_hal_spi_config_sd_slow;
/** Preset for ST25R916 */
extern const LL_SPI_InitTypeDef furi_hal_spi_preset_2edge_low_8m;
/** FURI HAL SPI BUS handler
* Structure content may change at some point
/** Preset for CC1101 */
extern const LL_SPI_InitTypeDef furi_hal_spi_preset_1edge_low_8m;
/** Preset for ST7567 (Display) */
extern const LL_SPI_InitTypeDef furi_hal_spi_preset_1edge_low_4m;
/** Preset for SdCard in fast mode */
extern const LL_SPI_InitTypeDef furi_hal_spi_preset_1edge_low_16m;
/** Preset for SdCard in slow mode */
extern const LL_SPI_InitTypeDef furi_hal_spi_preset_1edge_low_2m;
/** Furi Hal Spi Bus R (Radio: CC1101, Nfc, External)*/
extern FuriHalSpiBus furi_hal_spi_bus_r;
/** Furi Hal Spi Bus D (Display, SdCard) */
extern FuriHalSpiBus furi_hal_spi_bus_d;
/** CC1101 on `furi_hal_spi_bus_r` */
extern FuriHalSpiBusHandle furi_hal_spi_bus_handle_subghz;
/** ST25R3916 on `furi_hal_spi_bus_r` */
extern FuriHalSpiBusHandle furi_hal_spi_bus_handle_nfc;
/** External on `furi_hal_spi_bus_r`
* Preset: `furi_hal_spi_preset_1edge_low_2m`
*
* miso: pa6
* mosi: pa7
* sck: pb3
* cs: pa4 (software controlled)
*
* @warning not initialized by default, call `furi_hal_spi_bus_handle_init` to initialize
* Bus pins are floating on inactive state, CS high after initialization
*
*/
typedef struct {
const SPI_TypeDef* spi;
const GpioPin* miso;
const GpioPin* mosi;
const GpioPin* clk;
} FuriHalSpiBus;
extern FuriHalSpiBusHandle furi_hal_spi_bus_handle_external;
/** FURI HAL SPI Device handler
* Structure content may change at some point
*/
typedef struct {
const FuriHalSpiBus* bus;
const LL_SPI_InitTypeDef* config;
const GpioPin* chip_select;
} FuriHalSpiDevice;
/** ST7567(Display) on `furi_hal_spi_bus_d` */
extern FuriHalSpiBusHandle furi_hal_spi_bus_handle_display;
/** FURI HAL SPI Standard Device IDs */
typedef enum {
FuriHalSpiDeviceIdSubGhz, /** SubGhz: CC1101, non-standard SPI usage */
FuriHalSpiDeviceIdDisplay, /** Display: ERC12864, only have MOSI */
FuriHalSpiDeviceIdSdCardFast, /** SDCARD: fast mode, after initialization */
FuriHalSpiDeviceIdSdCardSlow, /** SDCARD: slow mode, before initialization */
FuriHalSpiDeviceIdNfc, /** NFC: ST25R3916, pretty standard, but RFAL makes it complex */
/** SdCard in fast mode on `furi_hal_spi_bus_d` */
extern FuriHalSpiBusHandle furi_hal_spi_bus_handle_sd_fast;
FuriHalSpiDeviceIdMax, /** Service Value, do not use */
} FuriHalSpiDeviceId;
/** Furi Hal Spi Bus R
* CC1101, Nfc
*/
extern const FuriHalSpiBus spi_r;
/** Furi Hal Spi Bus D
* Display, SdCard
*/
extern const FuriHalSpiBus spi_d;
/** Furi Hal Spi devices */
extern const FuriHalSpiDevice furi_hal_spi_devices[FuriHalSpiDeviceIdMax];
/** SdCard in slow mode on `furi_hal_spi_bus_d` */
extern FuriHalSpiBusHandle furi_hal_spi_bus_handle_sd_slow;
#ifdef __cplusplus
}

View File

@@ -0,0 +1,64 @@
#pragma once
#include <stdint.h>
#include <stddef.h>
#include <furi-hal-gpio.h>
#include <stm32wbxx_ll_spi.h>
#include <stm32wbxx_ll_rcc.h>
#include <stm32wbxx_ll_bus.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct FuriHalSpiBus FuriHalSpiBus;
typedef struct FuriHalSpiBusHandle FuriHalSpiBusHandle;
/** FuriHal spi bus states */
typedef enum {
FuriHalSpiBusEventInit, /**< Bus initialization event, called on system start */
FuriHalSpiBusEventDeinit, /**< Bus deinitialization event, called on system stop */
FuriHalSpiBusEventLock, /**< Bus lock event, called before activation */
FuriHalSpiBusEventUnlock, /**< Bus unlock event, called after deactivation */
FuriHalSpiBusEventActivate, /**< Bus activation event, called before handle activation */
FuriHalSpiBusEventDeactivate, /**< Bus deactivation event, called after handle deactivation */
} FuriHalSpiBusEvent;
/** FuriHal spi bus event callback */
typedef void (*FuriHalSpiBusEventCallback)(FuriHalSpiBus* bus, FuriHalSpiBusEvent event);
/** FuriHal spi bus */
struct FuriHalSpiBus {
SPI_TypeDef* spi;
FuriHalSpiBusEventCallback callback;
FuriHalSpiBusHandle* current_handle;
};
/** FuriHal spi handle states */
typedef enum {
FuriHalSpiBusHandleEventInit, /**< Handle init, called on system start, initialize gpio for idle state */
FuriHalSpiBusHandleEventDeinit, /**< Handle deinit, called on system stop, deinitialize gpio for default state */
FuriHalSpiBusHandleEventActivate, /**< Handle activate: connect gpio and apply bus config */
FuriHalSpiBusHandleEventDeactivate, /**< Handle deactivate: disconnect gpio and reset bus config */
} FuriHalSpiBusHandleEvent;
/** FuriHal spi handle event callback */
typedef void (*FuriHalSpiBusHandleEventCallback)(
FuriHalSpiBusHandle* handle,
FuriHalSpiBusHandleEvent event);
/** FuriHal spi handle */
struct FuriHalSpiBusHandle {
FuriHalSpiBus* bus;
FuriHalSpiBusHandleEventCallback callback;
const GpioPin* miso;
const GpioPin* mosi;
const GpioPin* sck;
const GpioPin* cs;
};
#ifdef __cplusplus
}
#endif

View File

@@ -2,239 +2,150 @@
#include "furi-hal-resources.h"
#include <stdbool.h>
#include <string.h>
#include <assert.h>
#include <stm32wbxx_ll_spi.h>
#include <stm32wbxx_ll_utils.h>
#include <stm32wbxx_ll_cortex.h>
extern void Enable_SPI(SPI_TypeDef* spi);
void furi_hal_spi_init() {
for(size_t i = 0; i < FuriHalSpiDeviceIdMax; ++i) {
hal_gpio_write(furi_hal_spi_devices[i].chip_select, true);
hal_gpio_init(
furi_hal_spi_devices[i].chip_select,
GpioModeOutputPushPull,
GpioPullNo,
GpioSpeedVeryHigh);
}
furi_hal_spi_bus_init(&furi_hal_spi_bus_r);
furi_hal_spi_bus_init(&furi_hal_spi_bus_d);
hal_gpio_init_ex(
&gpio_spi_r_miso,
GpioModeAltFunctionPushPull,
GpioPullNo,
GpioSpeedVeryHigh,
GpioAltFn5SPI1);
hal_gpio_init_ex(
&gpio_spi_r_mosi,
GpioModeAltFunctionPushPull,
GpioPullNo,
GpioSpeedVeryHigh,
GpioAltFn5SPI1);
hal_gpio_init_ex(
&gpio_spi_r_sck,
GpioModeAltFunctionPushPull,
GpioPullNo,
GpioSpeedVeryHigh,
GpioAltFn5SPI1);
hal_gpio_init_ex(
&gpio_spi_d_miso,
GpioModeAltFunctionPushPull,
GpioPullUp,
GpioSpeedVeryHigh,
GpioAltFn5SPI2);
hal_gpio_init_ex(
&gpio_spi_d_mosi,
GpioModeAltFunctionPushPull,
GpioPullUp,
GpioSpeedVeryHigh,
GpioAltFn5SPI2);
hal_gpio_init_ex(
&gpio_spi_d_sck,
GpioModeAltFunctionPushPull,
GpioPullUp,
GpioSpeedVeryHigh,
GpioAltFn5SPI2);
furi_hal_spi_bus_handle_init(&furi_hal_spi_bus_handle_subghz);
furi_hal_spi_bus_handle_init(&furi_hal_spi_bus_handle_nfc);
furi_hal_spi_bus_handle_init(&furi_hal_spi_bus_handle_display);
furi_hal_spi_bus_handle_init(&furi_hal_spi_bus_handle_sd_fast);
furi_hal_spi_bus_handle_init(&furi_hal_spi_bus_handle_sd_slow);
}
void furi_hal_spi_bus_lock(const FuriHalSpiBus* bus) {
void furi_hal_spi_bus_init(FuriHalSpiBus* bus) {
assert(bus);
bus->callback(bus, FuriHalSpiBusEventInit);
}
void furi_hal_spi_bus_unlock(const FuriHalSpiBus* bus) {
void furi_hal_spi_bus_deinit(FuriHalSpiBus* bus) {
assert(bus);
bus->callback(bus, FuriHalSpiBusEventDeinit);
}
void furi_hal_spi_bus_configure(const FuriHalSpiBus* bus, const LL_SPI_InitTypeDef* config) {
assert(bus);
LL_SPI_DeInit((SPI_TypeDef*)bus->spi);
LL_SPI_Init((SPI_TypeDef*)bus->spi, (LL_SPI_InitTypeDef*)config);
LL_SPI_SetRxFIFOThreshold((SPI_TypeDef*)bus->spi, LL_SPI_RX_FIFO_TH_QUARTER);
LL_SPI_Enable((SPI_TypeDef*)bus->spi);
void furi_hal_spi_bus_handle_init(FuriHalSpiBusHandle* handle) {
assert(handle);
handle->callback(handle, FuriHalSpiBusHandleEventInit);
}
void furi_hal_spi_bus_end_txrx(const FuriHalSpiBus* bus, uint32_t timeout) {
while(LL_SPI_GetTxFIFOLevel((SPI_TypeDef*)bus->spi) != LL_SPI_TX_FIFO_EMPTY)
void furi_hal_spi_bus_handle_deinit(FuriHalSpiBusHandle* handle) {
assert(handle);
handle->callback(handle, FuriHalSpiBusHandleEventDeinit);
}
void furi_hal_spi_acquire(FuriHalSpiBusHandle* handle) {
assert(handle);
handle->bus->callback(handle->bus, FuriHalSpiBusEventLock);
handle->bus->callback(handle->bus, FuriHalSpiBusEventActivate);
assert(handle->bus->current_handle == NULL);
handle->bus->current_handle = handle;
handle->callback(handle, FuriHalSpiBusHandleEventActivate);
}
void furi_hal_spi_release(FuriHalSpiBusHandle* handle) {
assert(handle);
assert(handle->bus->current_handle == handle);
// Handle event and unset handle
handle->callback(handle, FuriHalSpiBusHandleEventDeactivate);
handle->bus->current_handle = NULL;
// Bus events
handle->bus->callback(handle->bus, FuriHalSpiBusEventDeactivate);
handle->bus->callback(handle->bus, FuriHalSpiBusEventUnlock);
}
static void furi_hal_spi_bus_end_txrx(FuriHalSpiBusHandle* handle, uint32_t timeout) {
while(LL_SPI_GetTxFIFOLevel(handle->bus->spi) != LL_SPI_TX_FIFO_EMPTY)
;
while(LL_SPI_IsActiveFlag_BSY((SPI_TypeDef*)bus->spi))
while(LL_SPI_IsActiveFlag_BSY(handle->bus->spi))
;
while(LL_SPI_GetRxFIFOLevel((SPI_TypeDef*)bus->spi) != LL_SPI_RX_FIFO_EMPTY) {
LL_SPI_ReceiveData8((SPI_TypeDef*)bus->spi);
while(LL_SPI_GetRxFIFOLevel(handle->bus->spi) != LL_SPI_RX_FIFO_EMPTY) {
LL_SPI_ReceiveData8(handle->bus->spi);
}
}
bool furi_hal_spi_bus_rx(const FuriHalSpiBus* bus, uint8_t* buffer, size_t size, uint32_t timeout) {
assert(bus);
bool furi_hal_spi_bus_rx(
FuriHalSpiBusHandle* handle,
uint8_t* buffer,
size_t size,
uint32_t timeout) {
assert(handle);
assert(handle->bus->current_handle == handle);
assert(buffer);
assert(size > 0);
return furi_hal_spi_bus_trx(bus, buffer, buffer, size, timeout);
return furi_hal_spi_bus_trx(handle, buffer, buffer, size, timeout);
}
bool furi_hal_spi_bus_tx(const FuriHalSpiBus* bus, uint8_t* buffer, size_t size, uint32_t timeout) {
assert(bus);
bool furi_hal_spi_bus_tx(
FuriHalSpiBusHandle* handle,
uint8_t* buffer,
size_t size,
uint32_t timeout) {
assert(handle);
assert(handle->bus->current_handle == handle);
assert(buffer);
assert(size > 0);
bool ret = true;
while(size > 0) {
if(LL_SPI_IsActiveFlag_TXE((SPI_TypeDef*)bus->spi)) {
LL_SPI_TransmitData8((SPI_TypeDef*)bus->spi, *buffer);
if(LL_SPI_IsActiveFlag_TXE(handle->bus->spi)) {
LL_SPI_TransmitData8(handle->bus->spi, *buffer);
buffer++;
size--;
}
}
furi_hal_spi_bus_end_txrx(bus, timeout);
LL_SPI_ClearFlag_OVR((SPI_TypeDef*)bus->spi);
furi_hal_spi_bus_end_txrx(handle, timeout);
LL_SPI_ClearFlag_OVR(handle->bus->spi);
return ret;
}
bool furi_hal_spi_bus_trx(
const FuriHalSpiBus* bus,
FuriHalSpiBusHandle* handle,
uint8_t* tx_buffer,
uint8_t* rx_buffer,
size_t size,
uint32_t timeout) {
assert(bus);
assert(handle);
assert(handle->bus->current_handle == handle);
assert(tx_buffer);
assert(rx_buffer);
assert(size > 0);
bool ret = true;
size_t tx_size = size;
bool tx_allowed = true;
while(size > 0) {
if(tx_size > 0 && LL_SPI_IsActiveFlag_TXE((SPI_TypeDef*)bus->spi) && tx_allowed) {
LL_SPI_TransmitData8((SPI_TypeDef*)bus->spi, *tx_buffer);
if(tx_size > 0 && LL_SPI_IsActiveFlag_TXE(handle->bus->spi) && tx_allowed) {
LL_SPI_TransmitData8(handle->bus->spi, *tx_buffer);
tx_buffer++;
tx_size--;
tx_allowed = false;
}
if(LL_SPI_IsActiveFlag_RXNE((SPI_TypeDef*)bus->spi)) {
*rx_buffer = LL_SPI_ReceiveData8((SPI_TypeDef*)bus->spi);
if(LL_SPI_IsActiveFlag_RXNE(handle->bus->spi)) {
*rx_buffer = LL_SPI_ReceiveData8(handle->bus->spi);
rx_buffer++;
size--;
tx_allowed = true;
}
}
furi_hal_spi_bus_end_txrx(bus, timeout);
return ret;
}
void furi_hal_spi_device_configure(const FuriHalSpiDevice* device) {
assert(device);
assert(device->config);
furi_hal_spi_bus_configure(device->bus, device->config);
}
const FuriHalSpiDevice* furi_hal_spi_device_get(FuriHalSpiDeviceId device_id) {
assert(device_id < FuriHalSpiDeviceIdMax);
const FuriHalSpiDevice* device = &furi_hal_spi_devices[device_id];
assert(device);
furi_hal_spi_bus_lock(device->bus);
furi_hal_spi_device_configure(device);
return device;
}
void furi_hal_spi_device_return(const FuriHalSpiDevice* device) {
furi_hal_spi_bus_unlock(device->bus);
}
bool furi_hal_spi_device_rx(
const FuriHalSpiDevice* device,
uint8_t* buffer,
size_t size,
uint32_t timeout) {
assert(device);
assert(buffer);
assert(size > 0);
if(device->chip_select) {
hal_gpio_write(device->chip_select, false);
}
bool ret = furi_hal_spi_bus_rx(device->bus, buffer, size, timeout);
if(device->chip_select) {
hal_gpio_write(device->chip_select, true);
}
return ret;
}
bool furi_hal_spi_device_tx(
const FuriHalSpiDevice* device,
uint8_t* buffer,
size_t size,
uint32_t timeout) {
assert(device);
assert(buffer);
assert(size > 0);
if(device->chip_select) {
hal_gpio_write(device->chip_select, false);
}
bool ret = furi_hal_spi_bus_tx(device->bus, buffer, size, timeout);
if(device->chip_select) {
hal_gpio_write(device->chip_select, true);
}
return ret;
}
bool furi_hal_spi_device_trx(
const FuriHalSpiDevice* device,
uint8_t* tx_buffer,
uint8_t* rx_buffer,
size_t size,
uint32_t timeout) {
assert(device);
assert(tx_buffer);
assert(rx_buffer);
assert(size > 0);
if(device->chip_select) {
hal_gpio_write(device->chip_select, false);
}
bool ret = furi_hal_spi_bus_trx(device->bus, tx_buffer, rx_buffer, size, timeout);
if(device->chip_select) {
hal_gpio_write(device->chip_select, true);
}
furi_hal_spi_bus_end_txrx(handle, timeout);
return ret;
}

View File

@@ -1,129 +0,0 @@
#pragma once
#include "main.h"
#include "furi-hal-spi-config.h"
#include <furi-hal-gpio.h>
#include <stdbool.h>
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* Init SPI API
*/
void furi_hal_spi_init();
/* Bus Level API */
/** Lock SPI bus
* Takes bus mutex, if used
*/
void furi_hal_spi_bus_lock(const FuriHalSpiBus* bus);
/** Unlock SPI bus
* Releases BUS mutex, if used
*/
void furi_hal_spi_bus_unlock(const FuriHalSpiBus* bus);
/**
* Configure SPI bus
* @param bus - spi bus handler
* @param config - spi configuration structure
*/
void furi_hal_spi_bus_configure(const FuriHalSpiBus* bus, const LL_SPI_InitTypeDef* config);
/** SPI Receive
* @param bus - spi bus handler
* @param buffer - receive buffer
* @param size - transaction size
* @param timeout - bus operation timeout in ms
*/
bool furi_hal_spi_bus_rx(const FuriHalSpiBus* bus, uint8_t* buffer, size_t size, uint32_t timeout);
/** SPI Transmit
* @param bus - spi bus handler
* @param buffer - transmit buffer
* @param size - transaction size
* @param timeout - bus operation timeout in ms
*/
bool furi_hal_spi_bus_tx(const FuriHalSpiBus* bus, uint8_t* buffer, size_t size, uint32_t timeout);
/** SPI Transmit and Receive
* @param bus - spi bus handlere
* @param tx_buffer - device handle
* @param rx_buffer - device handle
* @param size - transaction size
* @param timeout - bus operation timeout in ms
*/
bool furi_hal_spi_bus_trx(
const FuriHalSpiBus* bus,
uint8_t* tx_buffer,
uint8_t* rx_buffer,
size_t size,
uint32_t timeout);
/* Device Level API */
/** Reconfigure SPI bus for device
* @param device - device description
*/
void furi_hal_spi_device_configure(const FuriHalSpiDevice* device);
/** Get Device handle
* And lock access to the corresponding SPI BUS
* @param device_id - device identifier
* @return device handle
*/
const FuriHalSpiDevice* furi_hal_spi_device_get(FuriHalSpiDeviceId device_id);
/** Return Device handle
* And unlock access to the corresponding SPI BUS
* @param device - device handle
*/
void furi_hal_spi_device_return(const FuriHalSpiDevice* device);
/** SPI Recieve
* @param device - device handle
* @param buffer - receive buffer
* @param size - transaction size
* @param timeout - bus operation timeout in ms
*/
bool furi_hal_spi_device_rx(
const FuriHalSpiDevice* device,
uint8_t* buffer,
size_t size,
uint32_t timeout);
/** SPI Transmit
* @param device - device handle
* @param buffer - transmit buffer
* @param size - transaction size
* @param timeout - bus operation timeout in ms
*/
bool furi_hal_spi_device_tx(
const FuriHalSpiDevice* device,
uint8_t* buffer,
size_t size,
uint32_t timeout);
/** SPI Transmit and Receive
* @param device - device handle
* @param tx_buffer - device handle
* @param rx_buffer - device handle
* @param size - transaction size
* @param timeout - bus operation timeout in ms
*/
bool furi_hal_spi_device_trx(
const FuriHalSpiDevice* device,
uint8_t* tx_buffer,
uint8_t* rx_buffer,
size_t size,
uint32_t timeout);
#ifdef __cplusplus
}
#endif

View File

@@ -1,10 +1,9 @@
#include <furi-hal-spi-config.h>
#include <furi-hal-resources.h>
#define SPI_R SPI1
#define SPI_D SPI2
/* SPI Presets */
const LL_SPI_InitTypeDef furi_hal_spi_config_nfc = {
const LL_SPI_InitTypeDef furi_hal_spi_preset_2edge_low_8m = {
.Mode = LL_SPI_MODE_MASTER,
.TransferDirection = LL_SPI_FULL_DUPLEX,
.DataWidth = LL_SPI_DATAWIDTH_8BIT,
@@ -17,7 +16,7 @@ const LL_SPI_InitTypeDef furi_hal_spi_config_nfc = {
.CRCPoly = 7,
};
const LL_SPI_InitTypeDef furi_hal_spi_config_subghz = {
const LL_SPI_InitTypeDef furi_hal_spi_preset_1edge_low_8m = {
.Mode = LL_SPI_MODE_MASTER,
.TransferDirection = LL_SPI_FULL_DUPLEX,
.DataWidth = LL_SPI_DATAWIDTH_8BIT,
@@ -30,7 +29,7 @@ const LL_SPI_InitTypeDef furi_hal_spi_config_subghz = {
.CRCPoly = 7,
};
const LL_SPI_InitTypeDef furi_hal_spi_config_display = {
const LL_SPI_InitTypeDef furi_hal_spi_preset_1edge_low_4m = {
.Mode = LL_SPI_MODE_MASTER,
.TransferDirection = LL_SPI_FULL_DUPLEX,
.DataWidth = LL_SPI_DATAWIDTH_8BIT,
@@ -43,10 +42,7 @@ const LL_SPI_InitTypeDef furi_hal_spi_config_display = {
.CRCPoly = 7,
};
/**
* SD Card in fast mode (after init)
*/
const LL_SPI_InitTypeDef furi_hal_spi_config_sd_fast = {
const LL_SPI_InitTypeDef furi_hal_spi_preset_1edge_low_16m = {
.Mode = LL_SPI_MODE_MASTER,
.TransferDirection = LL_SPI_FULL_DUPLEX,
.DataWidth = LL_SPI_DATAWIDTH_8BIT,
@@ -59,10 +55,7 @@ const LL_SPI_InitTypeDef furi_hal_spi_config_sd_fast = {
.CRCPoly = 7,
};
/**
* SD Card in slow mode (before init)
*/
const LL_SPI_InitTypeDef furi_hal_spi_config_sd_slow = {
const LL_SPI_InitTypeDef furi_hal_spi_preset_1edge_low_2m = {
.Mode = LL_SPI_MODE_MASTER,
.TransferDirection = LL_SPI_FULL_DUPLEX,
.DataWidth = LL_SPI_DATAWIDTH_8BIT,
@@ -75,40 +68,223 @@ const LL_SPI_InitTypeDef furi_hal_spi_config_sd_slow = {
.CRCPoly = 7,
};
const FuriHalSpiBus spi_r = {
.spi = SPI_R,
/* SPI Buses */
static void furi_hal_spi_bus_r_event_callback(FuriHalSpiBus* bus, FuriHalSpiBusEvent event) {
if(event == FuriHalSpiBusEventInit) {
LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_SPI1);
LL_APB2_GRP1_ForceReset(LL_APB2_GRP1_PERIPH_SPI1);
bus->current_handle = NULL;
} else if(event == FuriHalSpiBusEventDeinit) {
} else if(event == FuriHalSpiBusEventLock) {
} else if(event == FuriHalSpiBusEventUnlock) {
} else if(event == FuriHalSpiBusEventActivate) {
LL_APB2_GRP1_ReleaseReset(LL_APB2_GRP1_PERIPH_SPI1);
} else if(event == FuriHalSpiBusEventDeactivate) {
LL_APB2_GRP1_ForceReset(LL_APB2_GRP1_PERIPH_SPI1);
}
}
FuriHalSpiBus furi_hal_spi_bus_r = {
.spi = SPI1,
.callback = furi_hal_spi_bus_r_event_callback,
};
static void furi_hal_spi_bus_d_event_callback(FuriHalSpiBus* bus, FuriHalSpiBusEvent event) {
if(event == FuriHalSpiBusEventInit) {
LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_SPI2);
LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_SPI2);
bus->current_handle = NULL;
} else if(event == FuriHalSpiBusEventDeinit) {
} else if(event == FuriHalSpiBusEventLock) {
} else if(event == FuriHalSpiBusEventUnlock) {
} else if(event == FuriHalSpiBusEventActivate) {
LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_SPI2);
} else if(event == FuriHalSpiBusEventDeactivate) {
LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_SPI2);
}
}
FuriHalSpiBus furi_hal_spi_bus_d = {
.spi = SPI2,
.callback = furi_hal_spi_bus_d_event_callback,
};
/* SPI Bus Handles */
inline static void furi_hal_spi_bus_r_handle_event_callback(
FuriHalSpiBusHandle* handle,
FuriHalSpiBusHandleEvent event,
const LL_SPI_InitTypeDef* preset) {
if(event == FuriHalSpiBusHandleEventInit) {
hal_gpio_write(handle->cs, true);
hal_gpio_init(handle->cs, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh);
} else if(event == FuriHalSpiBusHandleEventDeinit) {
hal_gpio_write(handle->cs, true);
hal_gpio_init(handle->cs, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
} else if(event == FuriHalSpiBusHandleEventActivate) {
LL_SPI_Init(handle->bus->spi, (LL_SPI_InitTypeDef*)preset);
LL_SPI_SetRxFIFOThreshold(handle->bus->spi, LL_SPI_RX_FIFO_TH_QUARTER);
LL_SPI_Enable(handle->bus->spi);
hal_gpio_init_ex(
handle->miso,
GpioModeAltFunctionPushPull,
GpioPullNo,
GpioSpeedVeryHigh,
GpioAltFn5SPI1);
hal_gpio_init_ex(
handle->mosi,
GpioModeAltFunctionPushPull,
GpioPullNo,
GpioSpeedVeryHigh,
GpioAltFn5SPI1);
hal_gpio_init_ex(
handle->sck,
GpioModeAltFunctionPushPull,
GpioPullNo,
GpioSpeedVeryHigh,
GpioAltFn5SPI1);
hal_gpio_write(handle->cs, false);
} else if(event == FuriHalSpiBusHandleEventDeactivate) {
hal_gpio_write(handle->cs, true);
hal_gpio_init(handle->miso, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
hal_gpio_init(handle->mosi, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
hal_gpio_init(handle->sck, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
LL_SPI_Disable(handle->bus->spi);
}
}
static void furi_hal_spi_bus_handle_subghz_event_callback(
FuriHalSpiBusHandle* handle,
FuriHalSpiBusHandleEvent event) {
furi_hal_spi_bus_r_handle_event_callback(handle, event, &furi_hal_spi_preset_1edge_low_8m);
}
FuriHalSpiBusHandle furi_hal_spi_bus_handle_subghz = {
.bus = &furi_hal_spi_bus_r,
.callback = furi_hal_spi_bus_handle_subghz_event_callback,
.miso = &gpio_spi_r_miso,
.mosi = &gpio_spi_r_mosi,
.clk = &gpio_spi_r_sck,
.sck = &gpio_spi_r_sck,
.cs = &gpio_subghz_cs,
};
const FuriHalSpiBus spi_d = {
.spi = SPI_D,
static void furi_hal_spi_bus_handle_nfc_event_callback(
FuriHalSpiBusHandle* handle,
FuriHalSpiBusHandleEvent event) {
furi_hal_spi_bus_r_handle_event_callback(handle, event, &furi_hal_spi_preset_2edge_low_8m);
}
FuriHalSpiBusHandle furi_hal_spi_bus_handle_nfc = {
.bus = &furi_hal_spi_bus_r,
.callback = furi_hal_spi_bus_handle_nfc_event_callback,
.miso = &gpio_spi_r_miso,
.mosi = &gpio_spi_r_mosi,
.sck = &gpio_spi_r_sck,
.cs = &gpio_nfc_cs,
};
static void furi_hal_spi_bus_handle_external_event_callback(
FuriHalSpiBusHandle* handle,
FuriHalSpiBusHandleEvent event) {
furi_hal_spi_bus_r_handle_event_callback(handle, event, &furi_hal_spi_preset_1edge_low_2m);
}
FuriHalSpiBusHandle furi_hal_spi_bus_handle_external = {
.bus = &furi_hal_spi_bus_r,
.callback = furi_hal_spi_bus_handle_external_event_callback,
.miso = &gpio_ext_pa6,
.mosi = &gpio_ext_pa7,
.sck = &gpio_ext_pb3,
.cs = &gpio_ext_pa4,
};
inline static void furi_hal_spi_bus_d_handle_event_callback(
FuriHalSpiBusHandle* handle,
FuriHalSpiBusHandleEvent event,
const LL_SPI_InitTypeDef* preset) {
if(event == FuriHalSpiBusHandleEventInit) {
hal_gpio_write(handle->cs, true);
hal_gpio_init(handle->cs, GpioModeOutputPushPull, GpioPullUp, GpioSpeedVeryHigh);
hal_gpio_init_ex(
handle->miso,
GpioModeAltFunctionPushPull,
GpioPullNo,
GpioSpeedVeryHigh,
GpioAltFn5SPI2);
hal_gpio_init_ex(
handle->mosi,
GpioModeAltFunctionPushPull,
GpioPullNo,
GpioSpeedVeryHigh,
GpioAltFn5SPI2);
hal_gpio_init_ex(
handle->sck,
GpioModeAltFunctionPushPull,
GpioPullNo,
GpioSpeedVeryHigh,
GpioAltFn5SPI2);
} else if(event == FuriHalSpiBusHandleEventDeinit) {
hal_gpio_write(handle->cs, true);
hal_gpio_init(handle->cs, GpioModeAnalog, GpioPullUp, GpioSpeedLow);
} else if(event == FuriHalSpiBusHandleEventActivate) {
LL_SPI_Init(handle->bus->spi, (LL_SPI_InitTypeDef*)preset);
LL_SPI_SetRxFIFOThreshold(handle->bus->spi, LL_SPI_RX_FIFO_TH_QUARTER);
LL_SPI_Enable(handle->bus->spi);
hal_gpio_write(handle->cs, false);
} else if(event == FuriHalSpiBusHandleEventDeactivate) {
hal_gpio_write(handle->cs, true);
LL_SPI_Disable(handle->bus->spi);
}
}
static void furi_hal_spi_bus_handle_display_event_callback(
FuriHalSpiBusHandle* handle,
FuriHalSpiBusHandleEvent event) {
furi_hal_spi_bus_d_handle_event_callback(handle, event, &furi_hal_spi_preset_1edge_low_4m);
}
FuriHalSpiBusHandle furi_hal_spi_bus_handle_display = {
.bus = &furi_hal_spi_bus_d,
.callback = furi_hal_spi_bus_handle_display_event_callback,
.miso = &gpio_spi_d_miso,
.mosi = &gpio_spi_d_mosi,
.clk = &gpio_spi_d_sck,
.sck = &gpio_spi_d_sck,
.cs = &gpio_display_cs,
};
const FuriHalSpiDevice furi_hal_spi_devices[FuriHalSpiDeviceIdMax] = {
{
.bus = &spi_r,
.config = &furi_hal_spi_config_subghz,
.chip_select = &gpio_subghz_cs,
},
{
.bus = &spi_d,
.config = &furi_hal_spi_config_display,
.chip_select = &gpio_display_cs,
},
{
.bus = &spi_d,
.config = &furi_hal_spi_config_sd_fast,
.chip_select = &gpio_sdcard_cs,
},
{
.bus = &spi_d,
.config = &furi_hal_spi_config_sd_slow,
.chip_select = &gpio_sdcard_cs,
},
{.bus = &spi_r, .config = &furi_hal_spi_config_nfc, .chip_select = &gpio_nfc_cs},
static void furi_hal_spi_bus_handle_sd_fast_event_callback(
FuriHalSpiBusHandle* handle,
FuriHalSpiBusHandleEvent event) {
furi_hal_spi_bus_d_handle_event_callback(handle, event, &furi_hal_spi_preset_1edge_low_16m);
}
FuriHalSpiBusHandle furi_hal_spi_bus_handle_sd_fast = {
.bus = &furi_hal_spi_bus_d,
.callback = furi_hal_spi_bus_handle_sd_fast_event_callback,
.miso = &gpio_spi_d_miso,
.mosi = &gpio_spi_d_mosi,
.sck = &gpio_spi_d_sck,
.cs = &gpio_sdcard_cs,
};
static void furi_hal_spi_bus_handle_sd_slow_event_callback(
FuriHalSpiBusHandle* handle,
FuriHalSpiBusHandleEvent event) {
furi_hal_spi_bus_d_handle_event_callback(handle, event, &furi_hal_spi_preset_1edge_low_2m);
}
FuriHalSpiBusHandle furi_hal_spi_bus_handle_sd_slow = {
.bus = &furi_hal_spi_bus_d,
.callback = furi_hal_spi_bus_handle_sd_slow_event_callback,
.miso = &gpio_spi_d_miso,
.mosi = &gpio_spi_d_mosi,
.sck = &gpio_spi_d_sck,
.cs = &gpio_sdcard_cs,
};

View File

@@ -1,60 +1,60 @@
#pragma once
#include <furi-hal-gpio.h>
#include <stm32wbxx_ll_spi.h>
#include <furi-hal-spi-types.h>
#ifdef __cplusplus
extern "C" {
#endif
extern const LL_SPI_InitTypeDef furi_hal_spi_config_nfc;
extern const LL_SPI_InitTypeDef furi_hal_spi_config_subghz;
extern const LL_SPI_InitTypeDef furi_hal_spi_config_display;
extern const LL_SPI_InitTypeDef furi_hal_spi_config_sd_fast;
extern const LL_SPI_InitTypeDef furi_hal_spi_config_sd_slow;
/** Preset for ST25R916 */
extern const LL_SPI_InitTypeDef furi_hal_spi_preset_2edge_low_8m;
/** FURI HAL SPI BUS handler
* Structure content may change at some point
/** Preset for CC1101 */
extern const LL_SPI_InitTypeDef furi_hal_spi_preset_1edge_low_8m;
/** Preset for ST7567 (Display) */
extern const LL_SPI_InitTypeDef furi_hal_spi_preset_1edge_low_4m;
/** Preset for SdCard in fast mode */
extern const LL_SPI_InitTypeDef furi_hal_spi_preset_1edge_low_16m;
/** Preset for SdCard in slow mode */
extern const LL_SPI_InitTypeDef furi_hal_spi_preset_1edge_low_2m;
/** Furi Hal Spi Bus R (Radio: CC1101, Nfc, External)*/
extern FuriHalSpiBus furi_hal_spi_bus_r;
/** Furi Hal Spi Bus D (Display, SdCard) */
extern FuriHalSpiBus furi_hal_spi_bus_d;
/** CC1101 on `furi_hal_spi_bus_r` */
extern FuriHalSpiBusHandle furi_hal_spi_bus_handle_subghz;
/** ST25R3916 on `furi_hal_spi_bus_r` */
extern FuriHalSpiBusHandle furi_hal_spi_bus_handle_nfc;
/** External on `furi_hal_spi_bus_r`
* Preset: `furi_hal_spi_preset_1edge_low_2m`
*
* miso: pa6
* mosi: pa7
* sck: pb3
* cs: pa4 (software controlled)
*
* @warning not initialized by default, call `furi_hal_spi_bus_handle_init` to initialize
* Bus pins are floating on inactive state, CS high after initialization
*
*/
typedef struct {
const SPI_TypeDef* spi;
const GpioPin* miso;
const GpioPin* mosi;
const GpioPin* clk;
} FuriHalSpiBus;
extern FuriHalSpiBusHandle furi_hal_spi_bus_handle_external;
/** FURI HAL SPI Device handler
* Structure content may change at some point
*/
typedef struct {
const FuriHalSpiBus* bus;
const LL_SPI_InitTypeDef* config;
const GpioPin* chip_select;
} FuriHalSpiDevice;
/** ST7567(Display) on `furi_hal_spi_bus_d` */
extern FuriHalSpiBusHandle furi_hal_spi_bus_handle_display;
/** FURI HAL SPI Standard Device IDs */
typedef enum {
FuriHalSpiDeviceIdSubGhz, /** SubGhz: CC1101, non-standard SPI usage */
FuriHalSpiDeviceIdDisplay, /** Display: ERC12864, only have MOSI */
FuriHalSpiDeviceIdSdCardFast, /** SDCARD: fast mode, after initialization */
FuriHalSpiDeviceIdSdCardSlow, /** SDCARD: slow mode, before initialization */
FuriHalSpiDeviceIdNfc, /** NFC: ST25R3916, pretty standard, but RFAL makes it complex */
/** SdCard in fast mode on `furi_hal_spi_bus_d` */
extern FuriHalSpiBusHandle furi_hal_spi_bus_handle_sd_fast;
FuriHalSpiDeviceIdMax, /** Service Value, do not use */
} FuriHalSpiDeviceId;
/** Furi Hal Spi Bus R
* CC1101, Nfc
*/
extern const FuriHalSpiBus spi_r;
/** Furi Hal Spi Bus D
* Display, SdCard
*/
extern const FuriHalSpiBus spi_d;
/** Furi Hal Spi devices */
extern const FuriHalSpiDevice furi_hal_spi_devices[FuriHalSpiDeviceIdMax];
/** SdCard in slow mode on `furi_hal_spi_bus_d` */
extern FuriHalSpiBusHandle furi_hal_spi_bus_handle_sd_slow;
#ifdef __cplusplus
}

View File

@@ -0,0 +1,64 @@
#pragma once
#include <stdint.h>
#include <stddef.h>
#include <furi-hal-gpio.h>
#include <stm32wbxx_ll_spi.h>
#include <stm32wbxx_ll_rcc.h>
#include <stm32wbxx_ll_bus.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct FuriHalSpiBus FuriHalSpiBus;
typedef struct FuriHalSpiBusHandle FuriHalSpiBusHandle;
/** FuriHal spi bus states */
typedef enum {
FuriHalSpiBusEventInit, /**< Bus initialization event, called on system start */
FuriHalSpiBusEventDeinit, /**< Bus deinitialization event, called on system stop */
FuriHalSpiBusEventLock, /**< Bus lock event, called before activation */
FuriHalSpiBusEventUnlock, /**< Bus unlock event, called after deactivation */
FuriHalSpiBusEventActivate, /**< Bus activation event, called before handle activation */
FuriHalSpiBusEventDeactivate, /**< Bus deactivation event, called after handle deactivation */
} FuriHalSpiBusEvent;
/** FuriHal spi bus event callback */
typedef void (*FuriHalSpiBusEventCallback)(FuriHalSpiBus* bus, FuriHalSpiBusEvent event);
/** FuriHal spi bus */
struct FuriHalSpiBus {
SPI_TypeDef* spi;
FuriHalSpiBusEventCallback callback;
FuriHalSpiBusHandle* current_handle;
};
/** FuriHal spi handle states */
typedef enum {
FuriHalSpiBusHandleEventInit, /**< Handle init, called on system start, initialize gpio for idle state */
FuriHalSpiBusHandleEventDeinit, /**< Handle deinit, called on system stop, deinitialize gpio for default state */
FuriHalSpiBusHandleEventActivate, /**< Handle activate: connect gpio and apply bus config */
FuriHalSpiBusHandleEventDeactivate, /**< Handle deactivate: disconnect gpio and reset bus config */
} FuriHalSpiBusHandleEvent;
/** FuriHal spi handle event callback */
typedef void (*FuriHalSpiBusHandleEventCallback)(
FuriHalSpiBusHandle* handle,
FuriHalSpiBusHandleEvent event);
/** FuriHal spi handle */
struct FuriHalSpiBusHandle {
FuriHalSpiBus* bus;
FuriHalSpiBusHandleEventCallback callback;
const GpioPin* miso;
const GpioPin* mosi;
const GpioPin* sck;
const GpioPin* cs;
};
#ifdef __cplusplus
}
#endif

View File

@@ -2,239 +2,150 @@
#include "furi-hal-resources.h"
#include <stdbool.h>
#include <string.h>
#include <assert.h>
#include <stm32wbxx_ll_spi.h>
#include <stm32wbxx_ll_utils.h>
#include <stm32wbxx_ll_cortex.h>
extern void Enable_SPI(SPI_TypeDef* spi);
void furi_hal_spi_init() {
for(size_t i = 0; i < FuriHalSpiDeviceIdMax; ++i) {
hal_gpio_write(furi_hal_spi_devices[i].chip_select, true);
hal_gpio_init(
furi_hal_spi_devices[i].chip_select,
GpioModeOutputPushPull,
GpioPullNo,
GpioSpeedVeryHigh);
}
furi_hal_spi_bus_init(&furi_hal_spi_bus_r);
furi_hal_spi_bus_init(&furi_hal_spi_bus_d);
hal_gpio_init_ex(
&gpio_spi_r_miso,
GpioModeAltFunctionPushPull,
GpioPullNo,
GpioSpeedVeryHigh,
GpioAltFn5SPI1);
hal_gpio_init_ex(
&gpio_spi_r_mosi,
GpioModeAltFunctionPushPull,
GpioPullNo,
GpioSpeedVeryHigh,
GpioAltFn5SPI1);
hal_gpio_init_ex(
&gpio_spi_r_sck,
GpioModeAltFunctionPushPull,
GpioPullNo,
GpioSpeedVeryHigh,
GpioAltFn5SPI1);
hal_gpio_init_ex(
&gpio_spi_d_miso,
GpioModeAltFunctionPushPull,
GpioPullUp,
GpioSpeedVeryHigh,
GpioAltFn5SPI2);
hal_gpio_init_ex(
&gpio_spi_d_mosi,
GpioModeAltFunctionPushPull,
GpioPullUp,
GpioSpeedVeryHigh,
GpioAltFn5SPI2);
hal_gpio_init_ex(
&gpio_spi_d_sck,
GpioModeAltFunctionPushPull,
GpioPullUp,
GpioSpeedVeryHigh,
GpioAltFn5SPI2);
furi_hal_spi_bus_handle_init(&furi_hal_spi_bus_handle_subghz);
furi_hal_spi_bus_handle_init(&furi_hal_spi_bus_handle_nfc);
furi_hal_spi_bus_handle_init(&furi_hal_spi_bus_handle_display);
furi_hal_spi_bus_handle_init(&furi_hal_spi_bus_handle_sd_fast);
furi_hal_spi_bus_handle_init(&furi_hal_spi_bus_handle_sd_slow);
}
void furi_hal_spi_bus_lock(const FuriHalSpiBus* bus) {
void furi_hal_spi_bus_init(FuriHalSpiBus* bus) {
assert(bus);
bus->callback(bus, FuriHalSpiBusEventInit);
}
void furi_hal_spi_bus_unlock(const FuriHalSpiBus* bus) {
void furi_hal_spi_bus_deinit(FuriHalSpiBus* bus) {
assert(bus);
bus->callback(bus, FuriHalSpiBusEventDeinit);
}
void furi_hal_spi_bus_configure(const FuriHalSpiBus* bus, const LL_SPI_InitTypeDef* config) {
assert(bus);
LL_SPI_DeInit((SPI_TypeDef*)bus->spi);
LL_SPI_Init((SPI_TypeDef*)bus->spi, (LL_SPI_InitTypeDef*)config);
LL_SPI_SetRxFIFOThreshold((SPI_TypeDef*)bus->spi, LL_SPI_RX_FIFO_TH_QUARTER);
LL_SPI_Enable((SPI_TypeDef*)bus->spi);
void furi_hal_spi_bus_handle_init(FuriHalSpiBusHandle* handle) {
assert(handle);
handle->callback(handle, FuriHalSpiBusHandleEventInit);
}
void furi_hal_spi_bus_end_txrx(const FuriHalSpiBus* bus, uint32_t timeout) {
while(LL_SPI_GetTxFIFOLevel((SPI_TypeDef*)bus->spi) != LL_SPI_TX_FIFO_EMPTY)
void furi_hal_spi_bus_handle_deinit(FuriHalSpiBusHandle* handle) {
assert(handle);
handle->callback(handle, FuriHalSpiBusHandleEventDeinit);
}
void furi_hal_spi_acquire(FuriHalSpiBusHandle* handle) {
assert(handle);
handle->bus->callback(handle->bus, FuriHalSpiBusEventLock);
handle->bus->callback(handle->bus, FuriHalSpiBusEventActivate);
assert(handle->bus->current_handle == NULL);
handle->bus->current_handle = handle;
handle->callback(handle, FuriHalSpiBusHandleEventActivate);
}
void furi_hal_spi_release(FuriHalSpiBusHandle* handle) {
assert(handle);
assert(handle->bus->current_handle == handle);
// Handle event and unset handle
handle->callback(handle, FuriHalSpiBusHandleEventDeactivate);
handle->bus->current_handle = NULL;
// Bus events
handle->bus->callback(handle->bus, FuriHalSpiBusEventDeactivate);
handle->bus->callback(handle->bus, FuriHalSpiBusEventUnlock);
}
static void furi_hal_spi_bus_end_txrx(FuriHalSpiBusHandle* handle, uint32_t timeout) {
while(LL_SPI_GetTxFIFOLevel(handle->bus->spi) != LL_SPI_TX_FIFO_EMPTY)
;
while(LL_SPI_IsActiveFlag_BSY((SPI_TypeDef*)bus->spi))
while(LL_SPI_IsActiveFlag_BSY(handle->bus->spi))
;
while(LL_SPI_GetRxFIFOLevel((SPI_TypeDef*)bus->spi) != LL_SPI_RX_FIFO_EMPTY) {
LL_SPI_ReceiveData8((SPI_TypeDef*)bus->spi);
while(LL_SPI_GetRxFIFOLevel(handle->bus->spi) != LL_SPI_RX_FIFO_EMPTY) {
LL_SPI_ReceiveData8(handle->bus->spi);
}
}
bool furi_hal_spi_bus_rx(const FuriHalSpiBus* bus, uint8_t* buffer, size_t size, uint32_t timeout) {
assert(bus);
bool furi_hal_spi_bus_rx(
FuriHalSpiBusHandle* handle,
uint8_t* buffer,
size_t size,
uint32_t timeout) {
assert(handle);
assert(handle->bus->current_handle == handle);
assert(buffer);
assert(size > 0);
return furi_hal_spi_bus_trx(bus, buffer, buffer, size, timeout);
return furi_hal_spi_bus_trx(handle, buffer, buffer, size, timeout);
}
bool furi_hal_spi_bus_tx(const FuriHalSpiBus* bus, uint8_t* buffer, size_t size, uint32_t timeout) {
assert(bus);
bool furi_hal_spi_bus_tx(
FuriHalSpiBusHandle* handle,
uint8_t* buffer,
size_t size,
uint32_t timeout) {
assert(handle);
assert(handle->bus->current_handle == handle);
assert(buffer);
assert(size > 0);
bool ret = true;
while(size > 0) {
if(LL_SPI_IsActiveFlag_TXE((SPI_TypeDef*)bus->spi)) {
LL_SPI_TransmitData8((SPI_TypeDef*)bus->spi, *buffer);
if(LL_SPI_IsActiveFlag_TXE(handle->bus->spi)) {
LL_SPI_TransmitData8(handle->bus->spi, *buffer);
buffer++;
size--;
}
}
furi_hal_spi_bus_end_txrx(bus, timeout);
LL_SPI_ClearFlag_OVR((SPI_TypeDef*)bus->spi);
furi_hal_spi_bus_end_txrx(handle, timeout);
LL_SPI_ClearFlag_OVR(handle->bus->spi);
return ret;
}
bool furi_hal_spi_bus_trx(
const FuriHalSpiBus* bus,
FuriHalSpiBusHandle* handle,
uint8_t* tx_buffer,
uint8_t* rx_buffer,
size_t size,
uint32_t timeout) {
assert(bus);
assert(handle);
assert(handle->bus->current_handle == handle);
assert(tx_buffer);
assert(rx_buffer);
assert(size > 0);
bool ret = true;
size_t tx_size = size;
bool tx_allowed = true;
while(size > 0) {
if(tx_size > 0 && LL_SPI_IsActiveFlag_TXE((SPI_TypeDef*)bus->spi) && tx_allowed) {
LL_SPI_TransmitData8((SPI_TypeDef*)bus->spi, *tx_buffer);
if(tx_size > 0 && LL_SPI_IsActiveFlag_TXE(handle->bus->spi) && tx_allowed) {
LL_SPI_TransmitData8(handle->bus->spi, *tx_buffer);
tx_buffer++;
tx_size--;
tx_allowed = false;
}
if(LL_SPI_IsActiveFlag_RXNE((SPI_TypeDef*)bus->spi)) {
*rx_buffer = LL_SPI_ReceiveData8((SPI_TypeDef*)bus->spi);
if(LL_SPI_IsActiveFlag_RXNE(handle->bus->spi)) {
*rx_buffer = LL_SPI_ReceiveData8(handle->bus->spi);
rx_buffer++;
size--;
tx_allowed = true;
}
}
furi_hal_spi_bus_end_txrx(bus, timeout);
return ret;
}
void furi_hal_spi_device_configure(const FuriHalSpiDevice* device) {
assert(device);
assert(device->config);
furi_hal_spi_bus_configure(device->bus, device->config);
}
const FuriHalSpiDevice* furi_hal_spi_device_get(FuriHalSpiDeviceId device_id) {
assert(device_id < FuriHalSpiDeviceIdMax);
const FuriHalSpiDevice* device = &furi_hal_spi_devices[device_id];
assert(device);
furi_hal_spi_bus_lock(device->bus);
furi_hal_spi_device_configure(device);
return device;
}
void furi_hal_spi_device_return(const FuriHalSpiDevice* device) {
furi_hal_spi_bus_unlock(device->bus);
}
bool furi_hal_spi_device_rx(
const FuriHalSpiDevice* device,
uint8_t* buffer,
size_t size,
uint32_t timeout) {
assert(device);
assert(buffer);
assert(size > 0);
if(device->chip_select) {
hal_gpio_write(device->chip_select, false);
}
bool ret = furi_hal_spi_bus_rx(device->bus, buffer, size, timeout);
if(device->chip_select) {
hal_gpio_write(device->chip_select, true);
}
return ret;
}
bool furi_hal_spi_device_tx(
const FuriHalSpiDevice* device,
uint8_t* buffer,
size_t size,
uint32_t timeout) {
assert(device);
assert(buffer);
assert(size > 0);
if(device->chip_select) {
hal_gpio_write(device->chip_select, false);
}
bool ret = furi_hal_spi_bus_tx(device->bus, buffer, size, timeout);
if(device->chip_select) {
hal_gpio_write(device->chip_select, true);
}
return ret;
}
bool furi_hal_spi_device_trx(
const FuriHalSpiDevice* device,
uint8_t* tx_buffer,
uint8_t* rx_buffer,
size_t size,
uint32_t timeout) {
assert(device);
assert(tx_buffer);
assert(rx_buffer);
assert(size > 0);
if(device->chip_select) {
hal_gpio_write(device->chip_select, false);
}
bool ret = furi_hal_spi_bus_trx(device->bus, tx_buffer, rx_buffer, size, timeout);
if(device->chip_select) {
hal_gpio_write(device->chip_select, true);
}
furi_hal_spi_bus_end_txrx(handle, timeout);
return ret;
}

View File

@@ -1,129 +0,0 @@
#pragma once
#include "main.h"
#include "furi-hal-spi-config.h"
#include <furi-hal-gpio.h>
#include <stdbool.h>
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* Init SPI API
*/
void furi_hal_spi_init();
/* Bus Level API */
/** Lock SPI bus
* Takes bus mutex, if used
*/
void furi_hal_spi_bus_lock(const FuriHalSpiBus* bus);
/** Unlock SPI bus
* Releases BUS mutex, if used
*/
void furi_hal_spi_bus_unlock(const FuriHalSpiBus* bus);
/**
* Configure SPI bus
* @param bus - spi bus handler
* @param config - spi configuration structure
*/
void furi_hal_spi_bus_configure(const FuriHalSpiBus* bus, const LL_SPI_InitTypeDef* config);
/** SPI Receive
* @param bus - spi bus handler
* @param buffer - receive buffer
* @param size - transaction size
* @param timeout - bus operation timeout in ms
*/
bool furi_hal_spi_bus_rx(const FuriHalSpiBus* bus, uint8_t* buffer, size_t size, uint32_t timeout);
/** SPI Transmit
* @param bus - spi bus handler
* @param buffer - transmit buffer
* @param size - transaction size
* @param timeout - bus operation timeout in ms
*/
bool furi_hal_spi_bus_tx(const FuriHalSpiBus* bus, uint8_t* buffer, size_t size, uint32_t timeout);
/** SPI Transmit and Receive
* @param bus - spi bus handlere
* @param tx_buffer - device handle
* @param rx_buffer - device handle
* @param size - transaction size
* @param timeout - bus operation timeout in ms
*/
bool furi_hal_spi_bus_trx(
const FuriHalSpiBus* bus,
uint8_t* tx_buffer,
uint8_t* rx_buffer,
size_t size,
uint32_t timeout);
/* Device Level API */
/** Reconfigure SPI bus for device
* @param device - device description
*/
void furi_hal_spi_device_configure(const FuriHalSpiDevice* device);
/** Get Device handle
* And lock access to the corresponding SPI BUS
* @param device_id - device identifier
* @return device handle
*/
const FuriHalSpiDevice* furi_hal_spi_device_get(FuriHalSpiDeviceId device_id);
/** Return Device handle
* And unlock access to the corresponding SPI BUS
* @param device - device handle
*/
void furi_hal_spi_device_return(const FuriHalSpiDevice* device);
/** SPI Recieve
* @param device - device handle
* @param buffer - receive buffer
* @param size - transaction size
* @param timeout - bus operation timeout in ms
*/
bool furi_hal_spi_device_rx(
const FuriHalSpiDevice* device,
uint8_t* buffer,
size_t size,
uint32_t timeout);
/** SPI Transmit
* @param device - device handle
* @param buffer - transmit buffer
* @param size - transaction size
* @param timeout - bus operation timeout in ms
*/
bool furi_hal_spi_device_tx(
const FuriHalSpiDevice* device,
uint8_t* buffer,
size_t size,
uint32_t timeout);
/** SPI Transmit and Receive
* @param device - device handle
* @param tx_buffer - device handle
* @param rx_buffer - device handle
* @param size - transaction size
* @param timeout - bus operation timeout in ms
*/
bool furi_hal_spi_device_trx(
const FuriHalSpiDevice* device,
uint8_t* tx_buffer,
uint8_t* rx_buffer,
size_t size,
uint32_t timeout);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,102 @@
#pragma once
#include <furi-hal-spi-config.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
/** Initialize SPI HAL */
void furi_hal_spi_init();
/** Initialize SPI Bus
*
* @param handle pointer to FuriHalSpiBus instance
*/
void furi_hal_spi_bus_init(FuriHalSpiBus* bus);
/** Deinitialize SPI Bus
*
* @param handle pointer to FuriHalSpiBus instance
*/
void furi_hal_spi_bus_deinit(FuriHalSpiBus* bus);
/** Initialize SPI Bus Handle
*
* @param handle pointer to FuriHalSpiBusHandle instance
*/
void furi_hal_spi_bus_handle_init(FuriHalSpiBusHandle* handle);
/** Deinitialize SPI Bus Handle
*
* @param handle pointer to FuriHalSpiBusHandle instance
*/
void furi_hal_spi_bus_handle_deinit(FuriHalSpiBusHandle* handle);
/** Acquire SPI bus
*
* @warning blocking, calls `furi_crash` on programming error, CS transition is up to handler event routine
*
* @param handle pointer to FuriHalSpiBusHandle instance
*/
void furi_hal_spi_acquire(FuriHalSpiBusHandle* handle);
/** Release SPI bus
*
* @warning calls `furi_crash` on programming error, CS transition is up to handler event routine
*
* @param handle pointer to FuriHalSpiBusHandle instance
*/
void furi_hal_spi_release(FuriHalSpiBusHandle* handle);
/** SPI Receive
*
* @param handle pointer to FuriHalSpiBusHandle instance
* @param buffer receive buffer
* @param size transaction size (buffer size)
* @param timeout operation timeout in ms
*
* @return true on sucess
*/
bool furi_hal_spi_bus_rx(
FuriHalSpiBusHandle* handle,
uint8_t* buffer,
size_t size,
uint32_t timeout);
/** SPI Transmit
*
* @param handle pointer to FuriHalSpiBusHandle instance
* @param buffer transmit buffer
* @param size transaction size (buffer size)
* @param timeout operation timeout in ms
*
* @return true on success
*/
bool furi_hal_spi_bus_tx(
FuriHalSpiBusHandle* handle,
uint8_t* buffer,
size_t size,
uint32_t timeout);
/** SPI Transmit and Receive
*
* @param handle pointer to FuriHalSpiBusHandle instance
* @param tx_buffer pointer to tx buffer
* @param rx_buffer pointer to rx buffer
* @param size transaction size (buffer size)
* @param timeout operation timeout in ms
*
* @return true on success
*/
bool furi_hal_spi_bus_trx(
FuriHalSpiBusHandle* handle,
uint8_t* tx_buffer,
uint8_t* rx_buffer,
size_t size,
uint32_t timeout);
#ifdef __cplusplus
}
#endif