diff --git a/drivers/SPI.h b/drivers/SPI.h index c247b3ea70..eb2c714ba0 100644 --- a/drivers/SPI.h +++ b/drivers/SPI.h @@ -131,6 +131,33 @@ public: */ SPI(PinName mosi, PinName miso, PinName sclk, PinName ssel, use_gpio_ssel_t); + /** Create a SPI master connected to the specified pins. + * + * @note This constructor passes the SSEL pin selection to the target HAL. + * Not all targets support SSEL, so this cannot be relied on in portable code. + * Portable code should use the alternative constructor that uses GPIO + * for SSEL. + * + * @note You can specify mosi or miso as NC if not used. + * + * @param explicit_pinmap reference to strucure which holds static pinmap. + */ + SPI(const spi_pinmap_t &explicit_pinmap); + + /** Create a SPI master connected to the specified pins. + * + * @note This constructor manipulates the SSEL pin as a GPIO output + * using a DigitalOut object. This should work on any target, and permits + * the use of select() and deselect() methods to keep the pin asserted + * between transfers. + * + * @note You can specify mosi or miso as NC if not used. + * + * @param explicit_pinmap reference to strucure which holds static pinmap. + * @param ssel SPI Chip Select pin. + */ + SPI(const spi_pinmap_t &explicit_pinmap, PinName ssel); + virtual ~SPI(); /** Configure the data transmission format. @@ -408,6 +435,12 @@ protected: char _write_fill; /* Select count to handle re-entrant selection */ int8_t _select_count; + /* Static pinmap data */ + const spi_pinmap_t *_explicit_pinmap; + /* SPI peripheral name */ + SPIName _peripheral_name; + /* Pointer to spi init function */ + void (*_init_func)(SPI*); private: void _do_construct(); @@ -425,6 +458,10 @@ private: */ static spi_peripheral_s *_alloc(); + static void _do_init(SPI *obj); + static void _do_init_direct(SPI *obj); + + #endif //!defined(DOXYGEN_ONLY) }; diff --git a/drivers/source/SPI.cpp b/drivers/source/SPI.cpp index 61d337dbf0..1837fc17ab 100644 --- a/drivers/source/SPI.cpp +++ b/drivers/source/SPI.cpp @@ -36,8 +36,17 @@ SPI::SPI(PinName mosi, PinName miso, PinName sclk, PinName ssel) : _miso(miso), _sclk(sclk), _hw_ssel(ssel), - _sw_ssel(NC) + _sw_ssel(NC), + _explicit_pinmap(NULL), + _init_func(_do_init) { + // Need backwards compatibility with HALs not providing API +#ifdef DEVICE_SPI_COUNT + _peripheral_name = spi_get_peripheral_name(_mosi, _miso, _sclk); +#else + _peripheral_name = GlobalSPI; +#endif + _do_construct(); } @@ -49,11 +58,62 @@ SPI::SPI(PinName mosi, PinName miso, PinName sclk, PinName ssel, use_gpio_ssel_t _miso(miso), _sclk(sclk), _hw_ssel(NC), - _sw_ssel(ssel, 1) + _sw_ssel(ssel, 1), + _explicit_pinmap(NULL), + _init_func(_do_init) +{ + // Need backwards compatibility with HALs not providing API +#ifdef DEVICE_SPI_COUNT + _peripheral_name = spi_get_peripheral_name(_mosi, _miso, _sclk); +#else + _peripheral_name = GlobalSPI; +#endif + _do_construct(); +} + +SPI::SPI(const spi_pinmap_t &pinmap) : +#if DEVICE_SPI_ASYNCH + _irq(this), +#endif + _mosi(pinmap.mosi_pin), + _miso(pinmap.miso_pin), + _sclk(pinmap.sclk_pin), + _hw_ssel(pinmap.ssel_pin), + _sw_ssel(NC), + _explicit_pinmap(&pinmap), + _peripheral_name((SPIName)pinmap.peripheral), + _init_func(_do_init_direct) + { _do_construct(); } +SPI::SPI(const spi_pinmap_t &pinmap, PinName ssel) : +#if DEVICE_SPI_ASYNCH + _irq(this), +#endif + _mosi(pinmap.mosi_pin), + _miso(pinmap.miso_pin), + _sclk(pinmap.sclk_pin), + _hw_ssel(NC), + _sw_ssel(ssel, 1), + _explicit_pinmap(&pinmap), + _peripheral_name((SPIName)pinmap.peripheral), + _init_func(_do_init_direct) +{ + _do_construct(); +} + +void SPI::_do_init(SPI *obj) +{ + spi_init(&obj->_peripheral->spi, obj->_mosi, obj->_miso, obj->_sclk, obj->_hw_ssel); +} + +void SPI::_do_init_direct(SPI *obj) +{ + spi_init_direct(&obj->_peripheral->spi, obj->_explicit_pinmap); +} + void SPI::_do_construct() { // No lock needed in the constructor @@ -67,20 +127,13 @@ void SPI::_do_construct() _hz = 1000000; _write_fill = SPI_FILL_CHAR; - // Need backwards compatibility with HALs not providing API -#ifdef DEVICE_SPI_COUNT - SPIName name = spi_get_peripheral_name(_mosi, _miso, _sclk); -#else - SPIName name = GlobalSPI; -#endif - core_util_critical_section_enter(); // lookup in a critical section if we already have it else initialize it - _peripheral = SPI::_lookup(name); + _peripheral = SPI::_lookup(_peripheral_name); if (!_peripheral) { _peripheral = SPI::_alloc(); - _peripheral->name = name; + _peripheral->name = _peripheral_name; } core_util_critical_section_exit(); @@ -158,7 +211,7 @@ void SPI::frequency(int hz) void SPI::_acquire() { if (_peripheral->owner != this) { - spi_init(&_peripheral->spi, _mosi, _miso, _sclk, _hw_ssel); + _init_func(this); spi_format(&_peripheral->spi, _bits, _mode, 0); spi_frequency(&_peripheral->spi, _hz); _peripheral->owner = this;