SPI: Add explicit pinmap support

pull/11892/head
Przemyslaw Stekiel 2019-08-09 09:28:21 +02:00
parent ca80cd22f7
commit beec0f1e84
2 changed files with 102 additions and 12 deletions

View File

@ -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)
};

View File

@ -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;