From 4b1b4f72af5529cb9efa0c2f98891e246f0f53f5 Mon Sep 17 00:00:00 2001 From: Przemyslaw Stekiel Date: Tue, 5 Nov 2019 12:34:31 +0100 Subject: [PATCH] Add spi_get_capabilities() function to HAL API Add also default weak version of spi_get_capabilities() which provides default/most common SPI parameters. This function can be replaced if a specific target has different capabilities. --- hal/mbed_compat.c | 50 +++++++++++++++++++++++++++++++++++++++++++++++ hal/spi_api.h | 32 ++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+) diff --git a/hal/mbed_compat.c b/hal/mbed_compat.c index eefe5f3a4c..5aa93138f5 100644 --- a/hal/mbed_compat.c +++ b/hal/mbed_compat.c @@ -17,6 +17,7 @@ #include "analogin_api.h" #include "i2c_api.h" +#include "spi_api.h" #include "gpio_api.h" #include "mbed_toolchain.h" @@ -40,4 +41,53 @@ MBED_WEAK void analogin_free(analogin_t *obj) { // Do nothing } +#endif + +#if DEVICE_SPI +// Default SPI capabilities. If specific target has different capabilities this function needs to be re-implemented. +MBED_WEAK void spi_get_capabilities(PinName ssel, bool slave, spi_capabilities_t *cap) +{ + if (slave) { + cap->minimum_frequency = 200000; // 200 kHz + cap->maximum_frequency = 2000000; // 2 MHz + cap->word_length = 0x00008080; // 8 and 16 bit symbols + cap->support_slave_mode = false; // to be determined later based on ssel + cap->hw_cs_handle = false; // irrelevant in slave mode + cap->slave_delay_between_symbols_ns = 2500; // 2.5 us + cap->clk_modes = 0x0f; // all clock modes +#if DEVICE_SPI_ASYNCH + cap->async_mode = true; +#else + cap->async_mode = false; +#endif + } else { + cap->minimum_frequency = 200000; // 200 kHz + cap->maximum_frequency = 2000000; // 2 MHz + cap->word_length = 0x00008080; // 8 and 16 bit symbols + cap->support_slave_mode = false; // to be determined later based on ssel + cap->hw_cs_handle = false; // to be determined later based on ssel + cap->slave_delay_between_symbols_ns = 0; // irrelevant in master mode + cap->clk_modes = 0x0f; // all clock modes +#if DEVICE_SPI_ASYNCH + cap->async_mode = true; +#else + cap->async_mode = false; +#endif + } + + // check if given ssel pin is in the cs pinmap + const PinMap *cs_pins = spi_master_cs_pinmap(); + PinName pin = NC; + while (cs_pins->pin != NC) { + if (cs_pins->pin == ssel) { +#if DEVICE_SPISLAVE + cap->support_slave_mode = true; +#endif + cap->hw_cs_handle = true; + break; + } + cs_pins++; + } +} + #endif \ No newline at end of file diff --git a/hal/spi_api.h b/hal/spi_api.h index 21a22d1b95..54ea7fa221 100644 --- a/hal/spi_api.h +++ b/hal/spi_api.h @@ -53,6 +53,28 @@ typedef struct spi_s spi_t; #endif +/** + * Describes the capabilities of a SPI peripherals + */ +typedef struct { + /** Minimum frequency supported must be set by target device and it will be assessed during + * testing. + */ + uint32_t minimum_frequency; + /** Maximum frequency supported must be set by target device and it will be assessed during + * testing. + */ + uint32_t maximum_frequency; + /** Each bit represents the corresponding word length. lsb => 1bit, msb => 32bit. */ + uint32_t word_length; + uint16_t slave_delay_between_symbols_ns; /**< specifies required number of ns between transmission of successive symbols in slave mode. */ + uint8_t clk_modes; /**< specifies supported modes from spi_mode_t. Each bit represents the corresponding mode. */ + bool support_slave_mode; /**< If true, the device can handle SPI slave mode using hardware management on the specified ssel pin. */ + bool hw_cs_handle; /**< If true, in SPI master mode Chip Select can be handled by hardware. */ + bool async_mode; /**< If true, in async mode is supported. */ + +} spi_capabilities_t; + #ifdef __cplusplus extern "C" { #endif @@ -63,6 +85,11 @@ extern "C" { * # Defined behavior * * ::spi_init initializes the spi_t control structure * * ::spi_init configures the pins used by SPI + * * ::spi_get_capabilities() fills the given `spi_capabilities_t` instance + * * ::spi_get_capabilities() should consider the `ssel` pin when evaluation the `support_slave_mode` and `hw_cs_handle` capability + * * ::spi_get_capabilities(): if the given `ssel` pin cannot be managed by hardware, `support_slave_mode` and `hw_cs_handle` should be false + * * At least a symbol width of 8bit must be supported + * * The supported frequency range must include the range [0.2..2] MHz * * ::spi_free returns the pins owned by the SPI object to their reset state * * ::spi_format sets the number of bits per frame * * ::spi_format configures clock polarity and phase @@ -125,6 +152,11 @@ extern "C" { SPIName spi_get_peripheral_name(PinName mosi, PinName miso, PinName mclk); #endif +/** + * Fills the given spi_capabilities_t structure with the capabilities of the given peripheral. + */ +void spi_get_capabilities(PinName ssel, bool slave, spi_capabilities_t *cap); + /** Initialize the SPI peripheral * * Configures the pins used by SPI, sets a default format and frequency, and enables the peripheral