HAL struct SPI_HandleTypeDef* used for handling SPI info.
For transmit/receive data use spi_xfer function:
bool spi_xfer(
SPI_HandleTypeDef* spi,
uint8_t* tx_data, uint8_t* rx_data, size_t len,
PubSubCallback cb, void* ctx);
tx_data and rx_data size must be equal (and equal len)cb called after spi operation is completed, (NULL, ctx) passed to callback.Blocking verison:
inline static bool spi_xfer_block(SPI_HandleTypeDef* spi, uint8_t* tx_data, uint8_t* rx_data, size_t len) {
semaphoreInfo s;
osSemaphore block = createSemaphoreStatic(s);
if(!spi_xfer(spi, tx_data, rx_data, len, RELEASE_SEMAPHORE, (void*)block)) {
osReleaseSemaphore(block);
return false;
}
osWaitSemaphore(block);
return false;
}
Common implementation of SPI bus: serial interface + CS pin
typedef struct {
GpioPin* cs; ///< CS pin
ValueMutex* spi; ///< <SPI_HandleTypeDef*>
} SpiBus;
For dedicated work with one device there is SpiDevice entity. It contains ValueMutex around SpiBus: after you acquire device you can acquire spi to work with it (don't forget SPI bus is shared around many device, release it after every transaction as quick as possible).
typedef struct {
ValueMutex* bus; ///< <SpiBus*>
} SpiDevice;
Many devices (like CC1101 and NFC) present as SPI bus and IRQ line. For work with it there is special entity SpiIrqDevice. Use subscribe_pubsub for subscribinq to irq events.
typedef struct {
ValueMutex* bus; ///< <SpiBus*>
PubSub* irq;
} SpiIrqDevice;
Special implementation of SPI bus: serial interface + CS, Res, D/I lines.
typedef struct {
GpioPin* cs; ///< CS pin
GpioPin* res; ///< reset pin
GpioPin* di; ///< D/I pin
ValueMutex* spi; ///< <SPI_HandleTypeDef*>
} DisplayBus;
C typedef struct {
ValueMutex* bus; ///< <DisplayBus*>
} DisplayDevice;
# SPI devices (F2)
* `/dev/sdcard` - SD card SPI, `SpiDevice`
* `/dev/cc1101_bus` - Sub-GHz radio (CC1101), `SpiIrqDevice`
* `/dev/nfc` - NFC (ST25R3916), `SpiIrqDevice`
* `/dev/display` - `DisplayDevice`
* `/dev/spiext` - External SPI (warning! Lock PA4, PA5, PA6, PA7)
### Application example
C // Be careful, this function called from IRQ context void handle_irq(void* _arg, void* _ctx) { }
void cc1101_example() {
SpiIrqDevice* cc1101_device = open_input("/dev/cc1101_bus");
if(cc1101_device == NULL) return; // bus not available, critical error
subscribe_pubsub(cc1101_device->irq, handle_irq, NULL);
{
// acquire device as device bus
SpiBus* spi_bus = acquire_mutex(cc1101_device->bus, 0);
if(spi_bus == NULL) {
printf("Device busy\n");
// wait for device
spi_bus = acquire_mutex_block(cc1101_device->bus);
}
// make transaction
uint8_t request[4] = {0xDE, 0xAD, 0xBE, 0xEF};
uint8_t response[4];
{
SPI_HandleTypeDef* spi = acquire_mutex_block(spi_bus->spi);
gpio_write(spi_bus->cs, false);
spi_xfer_block(spi, request, response, 4);
gpio_write(spi_bus->cs, true);
release_mutex(cc1101_device->spi, spi);
}
// release device (device bus)
release_mutex(cc1101_device->bus, spi_bus);
}
} ```