diff --git a/libraries/SPI/SPI.cpp b/libraries/SPI/SPI.cpp deleted file mode 100644 index bf2019abd7..0000000000 --- a/libraries/SPI/SPI.cpp +++ /dev/null @@ -1,267 +0,0 @@ -/* - * Copyright (c) 2010 by Cristian Maglie - * Copyright (c) 2014 by Paul Stoffregen (Transaction API) - * SPI Master library for arduino. - * - * This file is free software; you can redistribute it and/or modify - * it under the terms of either the GNU General Public License version 2 - * or the GNU Lesser General Public License version 2.1, both as - * published by the Free Software Foundation. - */ - -#include "SPI.h" - -/* The following contructors are available: -- SPIClass SPI -- SPIClass SPI(mosi,miso,sclk) -- SPIClass SPI(mosi,miso,sclk,ss) -*/ -SPIClass SPI; - -SPIClass::SPIClass() : g_active_id(-1) -{ - _spi.pin_miso = digitalPinToPinName(MISO); - _spi.pin_mosi = digitalPinToPinName(MOSI); - _spi.pin_sclk = digitalPinToPinName(SCK); - _spi.pin_ssel = NC; -} - -/* By default hardware SS pin is not used. To use hardware SS pin you should set -ssel pin. Enable this pin disable software CS. See microcontroller documentation -for the list of available SS pins. */ -SPIClass::SPIClass(uint8_t mosi, uint8_t miso, uint8_t sclk, uint8_t ssel) : g_active_id(-1) -{ - _spi.pin_miso = digitalPinToPinName(miso); - _spi.pin_mosi = digitalPinToPinName(mosi); - _spi.pin_sclk = digitalPinToPinName(sclk); - - if(ssel != 0xFF) { - _spi.pin_ssel = digitalPinToPinName(ssel); - } else { - _spi.pin_ssel = NC; - } -} - -//begin using the default chip select -void SPIClass::begin() -{ - begin(BOARD_SPI_OWN_SS); -} - -//Begin with a chip select defined -void SPIClass::begin(uint8_t _pin) -{ - if(_pin > SPI_CHANNELS_NUM) - return; - - if((_pin != BOARD_SPI_OWN_SS) && (_spi.pin_ssel == NC)) { - pinMode(_pin, OUTPUT); - digitalWrite(_pin, HIGH); - } - - spi_init(&_spi, spiSettings[_pin].clk, spiSettings[_pin].dMode, spiSettings[_pin].msb); - g_active_id = _pin; -#if __has_include("WiFi.h") - // Wait wifi shield initialization. - // Should be better to do in SpiDrv::begin() of WiFi library but it seems - // there is no more update on this library as shield is retired. - delay(2000); -#endif - -} - -void SPIClass::usingInterrupt(uint8_t interruptNumber) -{ - UNUSED(interruptNumber); - //Not implemented -} - -void SPIClass::beginTransaction(uint8_t _pin, SPISettings settings) -{ - if(_pin > SPI_CHANNELS_NUM) - return; - - spiSettings[_pin].clk = settings.clk; - spiSettings[_pin].dMode = settings.dMode; - spiSettings[_pin].bOrder = settings.bOrder; - if(spiSettings[_pin].bOrder == MSBFIRST) { - spiSettings[_pin].msb = MSBFIRST; - } else { - spiSettings[_pin].msb = LSBFIRST; - } - - spi_init(&_spi, spiSettings[_pin].clk, spiSettings[_pin].dMode, spiSettings[_pin].msb); - g_active_id = _pin; -} - -void SPIClass::endTransaction(void) -{ - g_active_id = -1; -} - -void SPIClass::end(uint8_t _pin) -{ - UNUSED(_pin); - end(); -} - -void SPIClass::end() -{ - spi_deinit(&_spi); - g_active_id = -1; -} - -void SPIClass::setBitOrder(uint8_t _pin, BitOrder _bitOrder) -{ - if(_pin > SPI_CHANNELS_NUM) - return; - - if(MSBFIRST == _bitOrder) { - spiSettings[_pin].msb = MSBFIRST; - spiSettings[_pin].bOrder = MSBFIRST; - } else { - spiSettings[_pin].msb = LSBFIRST; - spiSettings[_pin].bOrder = LSBFIRST; - } - - spi_init(&_spi, spiSettings[_pin].clk, spiSettings[_pin].dMode, spiSettings[_pin].msb); - g_active_id = _pin; -} - -void SPIClass::setDataMode(uint8_t _pin, uint8_t _mode) -{ - if(_pin > SPI_CHANNELS_NUM) - return; - - if(SPI_MODE0 == _mode) { - spiSettings[_pin].dMode = SPI_MODE_0; - } else if(SPI_MODE1 == _mode) { - spiSettings[_pin].dMode = SPI_MODE_1; - } else if(SPI_MODE2 == _mode) { - spiSettings[_pin].dMode = SPI_MODE_2; - } else if(SPI_MODE3 == _mode) { - spiSettings[_pin].dMode = SPI_MODE_3; - } - - spi_init(&_spi, spiSettings[_pin].clk, spiSettings[_pin].dMode, spiSettings[_pin].msb); - g_active_id = _pin; -} - -/* - * This function should not be used in new projects. - * Use SPISettings with SPI.beginTransaction() to configure SPI parameters. - */ -void SPIClass::setClockDivider(uint8_t _pin, uint8_t _divider) -{ - if(_pin > SPI_CHANNELS_NUM) - return; - - /* Get clk freq of the SPI instance */ - uint32_t spiClkFreq = spi_getClkFreq(&_spi); - - switch(_divider) { - case (SPI_CLOCK_DIV2) : - case (SPI_CLOCK_DIV4) : - case (SPI_CLOCK_DIV8) : - case (SPI_CLOCK_DIV16) : - case (SPI_CLOCK_DIV32) : - case (SPI_CLOCK_DIV64) : - case (SPI_CLOCK_DIV128) : - spiSettings[_pin].clk = spiClkFreq/_divider; - break; - default: - spiSettings[_pin].clk = SPI_SPEED_CLOCK_DEFAULT; - break; - } - - spi_init(&_spi, spiSettings[_pin].clk, spiSettings[_pin].dMode, spiSettings[_pin].msb); - g_active_id = _pin; -} - - -//Transfer a message on the selected SPI. The _pin is the CS of the SPI that -//identifies the SPI instance. -//If the _mode is set to SPI_CONTINUE, keep the spi instance alive. -byte SPIClass::transfer(uint8_t _pin, uint8_t data, SPITransferMode _mode) -{ - uint8_t rx_buffer = 0; - - if (_pin > SPI_CHANNELS_NUM) - return rx_buffer; - - if(_pin != g_active_id) { - spi_init(&_spi, spiSettings[_pin].clk, spiSettings[_pin].dMode, spiSettings[_pin].msb); - g_active_id = _pin; - } - - if((_pin != BOARD_SPI_OWN_SS) && (_spi.pin_ssel == NC)) - digitalWrite(_pin, LOW); - - spi_transfer(&_spi, &data, &rx_buffer, sizeof(uint8_t), 10000); - - if((_pin != BOARD_SPI_OWN_SS) && (_mode == SPI_LAST) && (_spi.pin_ssel == NC)) - digitalWrite(_pin, HIGH); - - return rx_buffer; -} - -uint16_t SPIClass::transfer16(uint8_t _pin, uint16_t data, SPITransferMode _mode) -{ - uint16_t rx_buffer = 0; - uint16_t tmp; - - if (_pin > SPI_CHANNELS_NUM) - return rx_buffer; - - if (spiSettings[_pin].msb) { - tmp = ((data & 0xff00) >> 8) | ((data & 0xff) << 8); - data = tmp; - } - - if(_pin != g_active_id) { - spi_init(&_spi, spiSettings[_pin].clk, spiSettings[_pin].dMode, spiSettings[_pin].msb); - g_active_id = _pin; - } - - if((_pin != BOARD_SPI_OWN_SS) && (_spi.pin_ssel == NC)) - digitalWrite(_pin, LOW); - - spi_transfer(&_spi, (uint8_t *)&data, (uint8_t *)&rx_buffer, sizeof(uint16_t), 10000000); - - if((_pin != BOARD_SPI_OWN_SS) && (_mode == SPI_LAST) && (_spi.pin_ssel == NC)) - digitalWrite(_pin, HIGH); - - if (spiSettings[_pin].msb) { - tmp = ((rx_buffer & 0xff00) >> 8) | ((rx_buffer & 0xff) << 8); - rx_buffer = tmp; - } - - return rx_buffer; -} - -void SPIClass::transfer(uint8_t _pin, void *_buf, size_t _count, SPITransferMode _mode) -{ - if ((_count == 0) || (_pin > SPI_CHANNELS_NUM)) - return; - - if(_pin != g_active_id) { - spi_init(&_spi, spiSettings[_pin].clk, spiSettings[_pin].dMode, spiSettings[_pin].msb); - g_active_id = _pin; - } - - if((_pin != BOARD_SPI_OWN_SS) && (_spi.pin_ssel == NC)) - digitalWrite(_pin, LOW); - - spi_transfer(&_spi, ((uint8_t*)_buf), ((uint8_t*)_buf), _count, 10000); - - if((_pin != BOARD_SPI_OWN_SS) && (_mode == SPI_LAST) && (_spi.pin_ssel == NC)) - digitalWrite(_pin, HIGH); -} - -void SPIClass::attachInterrupt(void) { - // Should be enableInterrupt() -} - -void SPIClass::detachInterrupt(void) { - // Should be disableInterrupt() -} diff --git a/libraries/SPI/SPI.h b/libraries/SPI/SPI.h deleted file mode 100644 index 4614936628..0000000000 --- a/libraries/SPI/SPI.h +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright (c) 2010 by Cristian Maglie - * Copyright (c) 2014 by Paul Stoffregen (Transaction API) - * SPI Master library for arduino. - * - * This file is free software; you can redistribute it and/or modify - * it under the terms of either the GNU General Public License version 2 - * or the GNU Lesser General Public License version 2.1, both as - * published by the Free Software Foundation. - */ - -#ifndef _SPI_H_INCLUDED -#define _SPI_H_INCLUDED - -#include "variant.h" -#include - -// SPI_HAS_TRANSACTION means SPI has -// - beginTransaction() -// - endTransaction() -// - usingInterrupt() -// - SPISetting(clock, bitOrder, dataMode) -#define SPI_HAS_TRANSACTION 1 - -// SPI_HAS_EXTENDED_CS_PIN_HANDLING means SPI has automatic -// CS pin handling and provides the following methods: -// - begin(pin) -// - end(pin) -// - setBitOrder(pin, bitorder) -// - setDataMode(pin, datamode) -// - setClockDivider(pin, clockdiv) -// - transfer(pin, data, SPI_LAST/SPI_CONTINUE) -// - beginTransaction(pin, SPISettings settings) (if transactions are available) -#define SPI_HAS_EXTENDED_CS_PIN_HANDLING 1 - -// For compatibility with sketches designed for AVR @ 16 MHz -// need to go from 64MHz to 16 (/4) -// This function should not be used in new projects. -// Use SPISettings with SPI.beginTransaction() to configure SPI parameters. -#define SPI_CLOCK_DIV2 2 -#define SPI_CLOCK_DIV4 4 -#define SPI_CLOCK_DIV8 8 -#define SPI_CLOCK_DIV16 16 -#define SPI_CLOCK_DIV32 32 -#define SPI_CLOCK_DIV64 64 -#define SPI_CLOCK_DIV128 128 - -#define SPI_MODE0 0x00 -#define SPI_MODE1 0x01 -#define SPI_MODE2 0x02 -#define SPI_MODE3 0x03 - -enum SPITransferMode { - SPI_CONTINUE, - SPI_LAST -}; - -class SPISettings { - public: - SPISettings(uint32_t clock, BitOrder bitOrder, uint8_t dataMode) { - clk = clock; - - if(bitOrder == MSBFIRST) { - msb = 1; - } else { - msb = 0; - } - bOrder = bitOrder; - - if(SPI_MODE0 == dataMode) { - dMode = SPI_MODE_0; - } else if(SPI_MODE1 == dataMode) { - dMode = SPI_MODE_1; - } else if(SPI_MODE2 == dataMode) { - dMode = SPI_MODE_2; - } else if(SPI_MODE3 == dataMode) { - dMode = SPI_MODE_3; - } - - } - SPISettings() { - clk = SPI_SPEED_CLOCK_DEFAULT; - bOrder = MSBFIRST; - msb = 1; - dMode = SPI_MODE_0; - } - private: - uint32_t clk; //specifies the spi bus maximum clock speed - BitOrder bOrder; //bit order (MSB/LSB first) - spi_mode_e dMode; //one of the data mode - //Mode Clock Polarity (CPOL) Clock Phase (CPHA) - //SPI_MODE0 0 0 - //SPI_MODE1 0 1 - //SPI_MODE2 1 0 - //SPI_MODE3 1 1 - uint8_t msb; //set to 1 if msb first - friend class SPIClass; -}; - - - -class SPIClass { - public: - SPIClass(); - SPIClass(uint8_t mosi, uint8_t miso, uint8_t sclk, uint8_t ssel = 0xFF); - - // Transfer functions - byte transfer(byte _pin, uint8_t _data, SPITransferMode _mode = SPI_LAST); - uint16_t transfer16(byte _pin, uint16_t _data, SPITransferMode _mode = SPI_LAST); - void transfer(byte _pin, void *_buf, size_t _count, SPITransferMode _mode = SPI_LAST); - - - // Transfer functions on default pin BOARD_SPI_DEFAULT_SS - byte transfer(uint8_t _data, SPITransferMode _mode = SPI_LAST) - { - return transfer(BOARD_SPI_OWN_SS, _data, _mode); - } - - uint16_t transfer16(uint16_t _data, SPITransferMode _mode = SPI_LAST) - { - return transfer16(BOARD_SPI_OWN_SS, _data, _mode); - } - - void transfer(void *_buf, size_t _count, SPITransferMode _mode = SPI_LAST) - { - transfer(BOARD_SPI_OWN_SS, _buf, _count, _mode); - } - - // Transaction Functions - void usingInterrupt(uint8_t interruptNumber); - - void beginTransaction(SPISettings settings) - { - beginTransaction(BOARD_SPI_OWN_SS, settings); - } - - void beginTransaction(uint8_t pin, SPISettings settings); - void endTransaction(void); - - // SPI Configuration methods - void attachInterrupt(void); - void detachInterrupt(void); - - void begin(void); - void end(void); - - // Attach/Detach pin to/from SPI controller - void begin(uint8_t _pin); - void end(uint8_t _pin); - - // These methods sets a parameter on a single pin - void setBitOrder(uint8_t _pin, BitOrder); - void setDataMode(uint8_t _pin, uint8_t); - void setClockDivider(uint8_t _pin, uint8_t); - - // These methods sets the same parameters but on default pin BOARD_SPI_OWN_SS - void setBitOrder(BitOrder _order) { setBitOrder(BOARD_SPI_OWN_SS, _order); }; - void setDataMode(uint8_t _mode) { setDataMode(BOARD_SPI_OWN_SS, _mode); }; - void setClockDivider(uint8_t _div) { setClockDivider(BOARD_SPI_OWN_SS, _div); }; - - private: - //uint32_t id; - SPISettings spiSettings[SPI_CHANNELS_NUM+1]; - int8_t g_active_id; - uint8_t _pin; - spi_t _spi; -}; - -extern SPIClass SPI; - -#endif diff --git a/libraries/SPI/library.properties b/libraries/SPI/library.properties index ff3ebf84b4..0b6c665f63 100644 --- a/libraries/SPI/library.properties +++ b/libraries/SPI/library.properties @@ -1,9 +1,9 @@ name=SPI version=1.0 -author=Arduino -maintainer=Arduino -sentence=Enables the communication with devices that use the Serial Peripheral Interface (SPI) Bus. For Arduino DUE only. -paragraph= +author=Arduino, Wi6Labs +maintainer=stm32duino +sentence=Enables the communication with devices that use the Serial Peripheral Interface (SPI) Bus. +paragraph=This library is based on the official Arduino SPI library and adapted to STM32 boards. category=Communication url=http://www.arduino.cc/en/Reference/SPI architectures=stm32 diff --git a/libraries/SPI/src/SPI.cpp b/libraries/SPI/src/SPI.cpp new file mode 100644 index 0000000000..0072b863dd --- /dev/null +++ b/libraries/SPI/src/SPI.cpp @@ -0,0 +1,327 @@ +/* + * Copyright (c) 2010 by Cristian Maglie + * Copyright (c) 2014 by Paul Stoffregen (Transaction API) + * SPI Master library for arduino. + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of either the GNU General Public License version 2 + * or the GNU Lesser General Public License version 2.1, both as + * published by the Free Software Foundation. + */ + +#include "SPI.h" + +/* The following contructors are available: +- SPIClass SPI +- SPIClass SPI(mosi,miso,sclk) +- SPIClass SPI(mosi,miso,sclk,ss) +*/ +SPIClass SPI; + +SPIClass::SPIClass() : _CSpin(-1) +{ + _spi.pin_miso = digitalPinToPinName(MISO); + _spi.pin_mosi = digitalPinToPinName(MOSI); + _spi.pin_sclk = digitalPinToPinName(SCK); + _spi.pin_ssel = NC; +} + +/* By default hardware SS pin is not used. To use hardware SS pin you should set +ssel pin. Enable this pin disable software CS. See microcontroller documentation +for the list of available SS pins. */ +SPIClass::SPIClass(uint8_t mosi, uint8_t miso, uint8_t sclk, uint8_t ssel) : _CSpin(-1) +{ + _spi.pin_miso = digitalPinToPinName(miso); + _spi.pin_mosi = digitalPinToPinName(mosi); + _spi.pin_sclk = digitalPinToPinName(sclk); + + if(ssel != 0xFF) { + _spi.pin_ssel = digitalPinToPinName(ssel); + } else { + _spi.pin_ssel = NC; + } +} + +//begin using the default chip select +void SPIClass::begin() +{ + begin(CS_PIN_CONTROLLED_BY_USER); +} + +//Begin with a chip select defined +void SPIClass::begin(uint8_t _pin) +{ + uint8_t idx; + + if(_pin > NUM_DIGITAL_PINS) + return; + + idx = pinIdx(_pin, ADD_NEW_PIN); + if(idx == NB_SPI_SETTINGS) + return; + + if((_pin != CS_PIN_CONTROLLED_BY_USER) && (_spi.pin_ssel == NC)) { + pinMode(_pin, OUTPUT); + digitalWrite(_pin, HIGH); + } + + spi_init(&_spi, spiSettings[idx].clk, + spiSettings[idx].dMode, + spiSettings[idx].msb); + _CSpin = _pin; +#if __has_include("WiFi.h") + // Wait wifi shield initialization. + // Should be better to do in SpiDrv::begin() of WiFi library but it seems + // there is no more update on this library as shield is retired. + delay(2000); +#endif + +} + +void SPIClass::usingInterrupt(uint8_t interruptNumber) +{ + UNUSED(interruptNumber); + //Not implemented +} + +void SPIClass::beginTransaction(uint8_t _pin, SPISettings settings) +{ + uint8_t idx; + + if(_pin > NUM_DIGITAL_PINS) + return; + + idx = pinIdx(_pin, ADD_NEW_PIN); + if(idx == NB_SPI_SETTINGS) { + return; + } + + spiSettings[idx].clk = settings.clk; + spiSettings[idx].dMode = settings.dMode; + spiSettings[idx].bOrder = settings.bOrder; + if(spiSettings[idx].bOrder == MSBFIRST) { + spiSettings[idx].msb = MSBFIRST; + } else { + spiSettings[idx].msb = LSBFIRST; + } + + if((_pin != CS_PIN_CONTROLLED_BY_USER) && (_spi.pin_ssel == NC)) { + pinMode(_pin, OUTPUT); + digitalWrite(_pin, HIGH); + } + + spi_init(&_spi, spiSettings[idx].clk, + spiSettings[idx].dMode, + spiSettings[idx].msb); + _CSpin = _pin; +} + +void SPIClass::endTransaction(uint8_t _pin) +{ + if(_pin > NUM_DIGITAL_PINS) + return; + + RemovePin(_pin); + _CSpin = -1; +} + +void SPIClass::end() +{ + spi_deinit(&_spi); + RemoveAllPin(); + _CSpin = -1; +} + +void SPIClass::setBitOrder(uint8_t _pin, BitOrder _bitOrder) +{ + if(_pin > NUM_DIGITAL_PINS) + return; + + uint8_t idx = pinIdx(_pin, GET_IDX); + if(idx == NB_SPI_SETTINGS) { + return; + } + + if(MSBFIRST == _bitOrder) { + spiSettings[idx].msb = MSBFIRST; + spiSettings[idx].bOrder = MSBFIRST; + } else { + spiSettings[idx].msb = LSBFIRST; + spiSettings[idx].bOrder = LSBFIRST; + } + + spi_init(&_spi, spiSettings[idx].clk, + spiSettings[idx].dMode, + spiSettings[idx].msb); +} + +void SPIClass::setDataMode(uint8_t _pin, uint8_t _mode) +{ + if(_pin > NUM_DIGITAL_PINS) + return; + + uint8_t idx = pinIdx(_pin, GET_IDX); + if(idx == NB_SPI_SETTINGS) { + return; + } + + if(SPI_MODE0 == _mode) { + spiSettings[idx].dMode = SPI_MODE_0; + } else if(SPI_MODE1 == _mode) { + spiSettings[idx].dMode = SPI_MODE_1; + } else if(SPI_MODE2 == _mode) { + spiSettings[idx].dMode = SPI_MODE_2; + } else if(SPI_MODE3 == _mode) { + spiSettings[idx].dMode = SPI_MODE_3; + } + + spi_init(&_spi, spiSettings[idx].clk, + spiSettings[idx].dMode, + spiSettings[idx].msb); +} + +/* + * This function should not be used in new projects. + * Use SPISettings with SPI.beginTransaction() to configure SPI parameters. + */ +void SPIClass::setClockDivider(uint8_t _pin, uint8_t _divider) +{ + if(_pin > NUM_DIGITAL_PINS) + return; + + uint8_t idx = pinIdx(_pin, GET_IDX); + if(idx == NB_SPI_SETTINGS) { + return; + } + + /* Get clk freq of the SPI instance */ + uint32_t spiClkFreq = spi_getClkFreq(&_spi); + + switch(_divider) { + case (SPI_CLOCK_DIV2) : + case (SPI_CLOCK_DIV4) : + case (SPI_CLOCK_DIV8) : + case (SPI_CLOCK_DIV16) : + case (SPI_CLOCK_DIV32) : + case (SPI_CLOCK_DIV64) : + case (SPI_CLOCK_DIV128) : + spiSettings[idx].clk = spiClkFreq/_divider; + break; + default: + spiSettings[idx].clk = SPI_SPEED_CLOCK_DEFAULT; + break; + } + + spi_init(&_spi, spiSettings[idx].clk, + spiSettings[idx].dMode, + spiSettings[idx].msb); +} + + +/* Transfer a message on the selected SPI. The _pin is the CS. + * The transfer function can reconfigure the SPI instance if the CS pin is + * different from the previous one. + * If the _mode is set to SPI_CONTINUE, keep the spi instance alive. That means + * the CS pin is not reset. Be careful in case you use several CS pin. + */ +byte SPIClass::transfer(uint8_t _pin, uint8_t data, SPITransferMode _mode) +{ + uint8_t rx_buffer = 0; + + if (_pin > NUM_DIGITAL_PINS) + return rx_buffer; + + if(_pin != _CSpin) { + uint8_t idx = pinIdx(_pin, GET_IDX); + if(idx == NB_SPI_SETTINGS) { + return rx_buffer; + } + spi_init(&_spi, spiSettings[idx].clk, + spiSettings[idx].dMode, + spiSettings[idx].msb); + _CSpin = _pin; + } + + if((_pin != CS_PIN_CONTROLLED_BY_USER) && (_spi.pin_ssel == NC)) + digitalWrite(_pin, LOW); + + spi_transfer(&_spi, &data, &rx_buffer, sizeof(uint8_t), SPI_TRANSFER_TIMEOUT); + + if((_pin != CS_PIN_CONTROLLED_BY_USER) && (_mode == SPI_LAST) && (_spi.pin_ssel == NC)) + digitalWrite(_pin, HIGH); + + return rx_buffer; +} + +uint16_t SPIClass::transfer16(uint8_t _pin, uint16_t data, SPITransferMode _mode) +{ + uint16_t rx_buffer = 0; + uint16_t tmp; + + if (_pin > NUM_DIGITAL_PINS) + return rx_buffer; + + if (spiSettings[_pin].msb) { + tmp = ((data & 0xff00) >> 8) | ((data & 0xff) << 8); + data = tmp; + } + + if(_pin != _CSpin) { + uint8_t idx = pinIdx(_pin, GET_IDX); + if(idx == NB_SPI_SETTINGS) { + return rx_buffer; + } + spi_init(&_spi, spiSettings[idx].clk, + spiSettings[idx].dMode, + spiSettings[idx].msb); + _CSpin = _pin; + } + + if((_pin != CS_PIN_CONTROLLED_BY_USER) && (_spi.pin_ssel == NC)) + digitalWrite(_pin, LOW); + + spi_transfer(&_spi, (uint8_t *)&data, (uint8_t *)&rx_buffer, sizeof(uint16_t), SPI_TRANSFER_TIMEOUT); + + if((_pin != CS_PIN_CONTROLLED_BY_USER) && (_mode == SPI_LAST) && (_spi.pin_ssel == NC)) + digitalWrite(_pin, HIGH); + + if (spiSettings[_pin].msb) { + tmp = ((rx_buffer & 0xff00) >> 8) | ((rx_buffer & 0xff) << 8); + rx_buffer = tmp; + } + + return rx_buffer; +} + +void SPIClass::transfer(uint8_t _pin, void *_buf, size_t _count, SPITransferMode _mode) +{ + if ((_count == 0) || (_buf == NULL) || (_pin > NUM_DIGITAL_PINS)) + return; + + if(_pin != _CSpin) { + uint8_t idx = pinIdx(_pin, GET_IDX); + if(idx == NB_SPI_SETTINGS) { + return; + } + spi_init(&_spi, spiSettings[idx].clk, + spiSettings[idx].dMode, + spiSettings[idx].msb); + _CSpin = _pin; + } + + if((_pin != CS_PIN_CONTROLLED_BY_USER) && (_spi.pin_ssel == NC)) + digitalWrite(_pin, LOW); + + spi_transfer(&_spi, ((uint8_t*)_buf), ((uint8_t*)_buf), _count, SPI_TRANSFER_TIMEOUT); + + if((_pin != CS_PIN_CONTROLLED_BY_USER) && (_mode == SPI_LAST) && (_spi.pin_ssel == NC)) + digitalWrite(_pin, HIGH); +} + +void SPIClass::attachInterrupt(void) { + // Should be enableInterrupt() +} + +void SPIClass::detachInterrupt(void) { + // Should be disableInterrupt() +} diff --git a/libraries/SPI/src/SPI.h b/libraries/SPI/src/SPI.h new file mode 100644 index 0000000000..11a23c301b --- /dev/null +++ b/libraries/SPI/src/SPI.h @@ -0,0 +1,250 @@ +/* + * Copyright (c) 2010 by Cristian Maglie + * Copyright (c) 2014 by Paul Stoffregen (Transaction API) + * SPI Master library for arduino. + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of either the GNU General Public License version 2 + * or the GNU Lesser General Public License version 2.1, both as + * published by the Free Software Foundation. + */ + +#ifndef _SPI_H_INCLUDED +#define _SPI_H_INCLUDED + +#include "variant.h" +#include + +// SPI_HAS_TRANSACTION means SPI has +// - beginTransaction() +// - endTransaction() +// - usingInterrupt() +// - SPISetting(clock, bitOrder, dataMode) +#define SPI_HAS_TRANSACTION 1 + +// For compatibility with sketches designed for AVR @ 16 MHz +// need to go from 64MHz to 16 (/4) +// This function should not be used in new projects. +// Use SPISettings with SPI.beginTransaction() to configure SPI parameters. +#define SPI_CLOCK_DIV2 2 +#define SPI_CLOCK_DIV4 4 +#define SPI_CLOCK_DIV8 8 +#define SPI_CLOCK_DIV16 16 +#define SPI_CLOCK_DIV32 32 +#define SPI_CLOCK_DIV64 64 +#define SPI_CLOCK_DIV128 128 + +#define SPI_MODE0 0x00 +#define SPI_MODE1 0x01 +#define SPI_MODE2 0x02 +#define SPI_MODE3 0x03 + +enum SPITransferMode { + SPI_CONTINUE, + SPI_LAST +}; + +// Indicates the user controls himself the CS pin +#define CS_PIN_CONTROLLED_BY_USER NUM_DIGITAL_PINS + +// Defines a default timeout delay in milliseconds for the SPI transfer +#define SPI_TRANSFER_TIMEOUT 1000 + +/* + * Defines the number of settings saved per SPI instance. Must be < 254. + * Can be redefined in variant.h + */ +#ifndef NB_SPI_SETTINGS +#define NB_SPI_SETTINGS 4 +#endif + +class SPISettings { + public: + SPISettings(uint32_t clock, BitOrder bitOrder, uint8_t dataMode) { + clk = clock; + + if(bitOrder == MSBFIRST) { + msb = 1; + } else { + msb = 0; + } + bOrder = bitOrder; + + if(SPI_MODE0 == dataMode) { + dMode = SPI_MODE_0; + } else if(SPI_MODE1 == dataMode) { + dMode = SPI_MODE_1; + } else if(SPI_MODE2 == dataMode) { + dMode = SPI_MODE_2; + } else if(SPI_MODE3 == dataMode) { + dMode = SPI_MODE_3; + } + + } + SPISettings() { + pinCS = -1; + clk = SPI_SPEED_CLOCK_DEFAULT; + bOrder = MSBFIRST; + msb = 1; + dMode = SPI_MODE_0; + } + private: + int16_t pinCS; + uint32_t clk; //specifies the spi bus maximum clock speed + BitOrder bOrder; //bit order (MSB/LSB first) + spi_mode_e dMode; //one of the data mode + //Mode Clock Polarity (CPOL) Clock Phase (CPHA) + //SPI_MODE0 0 0 + //SPI_MODE1 0 1 + //SPI_MODE2 1 0 + //SPI_MODE3 1 1 + uint8_t msb; //set to 1 if msb first + friend class SPIClass; +}; + +class SPIClass { + public: + SPIClass(); + SPIClass(uint8_t mosi, uint8_t miso, uint8_t sclk, uint8_t ssel = 0xFF); + + /* Transfer functions: must be called after initialization of the SPI + * instance with begin() or beginTransaction(). + * You can specify the CS pin to use. + */ + byte transfer(uint8_t pin, uint8_t _data, SPITransferMode _mode = SPI_LAST); + uint16_t transfer16(uint8_t pin, uint16_t _data, SPITransferMode _mode = SPI_LAST); + void transfer(uint8_t pin, void *_buf, size_t _count, SPITransferMode _mode = SPI_LAST); + + // Transfer functions when user controls himself the CS pin. + byte transfer(uint8_t _data, SPITransferMode _mode = SPI_LAST) + { + return transfer(CS_PIN_CONTROLLED_BY_USER, _data, _mode); + } + + uint16_t transfer16(uint16_t _data, SPITransferMode _mode = SPI_LAST) + { + return transfer16(CS_PIN_CONTROLLED_BY_USER, _data, _mode); + } + + void transfer(void *_buf, size_t _count, SPITransferMode _mode = SPI_LAST) + { + transfer(CS_PIN_CONTROLLED_BY_USER, _buf, _count, _mode); + } + + // Transaction Functions + void usingInterrupt(uint8_t interruptNumber); + + /* This function should be used to configure the SPI instance in case you + * don't use default parameters. + * You can attach another CS pin to the SPI instance and each CS pin can be + * attach with specific SPI settings. + */ + void beginTransaction(uint8_t pin, SPISettings settings); + void beginTransaction(SPISettings settings) + { + beginTransaction(CS_PIN_CONTROLLED_BY_USER, settings); + } + + void endTransaction(uint8_t pin); + void endTransaction(void) + { + endTransaction(CS_PIN_CONTROLLED_BY_USER); + } + + // SPI Configuration methods + void attachInterrupt(void); + void detachInterrupt(void); + + void begin(void); + void end(void); + + // Attach CS pin to SPI instance + void begin(uint8_t _pin); + + /* These methods sets a parameter on a single pin. + * These methods must be called after initialization of the SPI + * instance with begin() or beginTransaction(). + * @NOTE + * These functions should not be used in new projects. + * Use SPISettings with SPI.beginTransaction() to configure SPI parameters. + */ + void setBitOrder(uint8_t _pin, BitOrder); + void setDataMode(uint8_t _pin, uint8_t); + void setClockDivider(uint8_t _pin, uint8_t); + + // These methods sets the same parameters for the default CS pin. + void setBitOrder(BitOrder _order) { + setBitOrder(CS_PIN_CONTROLLED_BY_USER, _order); + } + void setDataMode(uint8_t _mode) { + setDataMode(CS_PIN_CONTROLLED_BY_USER, _mode); + } + void setClockDivider(uint8_t _div) { + setClockDivider(CS_PIN_CONTROLLED_BY_USER, _div); + } + + private: + SPISettings spiSettings[NB_SPI_SETTINGS]; + int16_t _CSpin; + spi_t _spi; + + typedef enum{ + GET_IDX = 0, + ADD_NEW_PIN = 1 + }pin_option_t; + + uint8_t pinIdx(uint8_t _pin, pin_option_t option) + { + uint8_t i; + + if(_pin > NUM_DIGITAL_PINS) + return NB_SPI_SETTINGS; + + for(i = 0; i < NB_SPI_SETTINGS; i++) { + if(_pin == spiSettings[i].pinCS) + return i; + } + + if(option == ADD_NEW_PIN) + { + for(i = 0; i < NB_SPI_SETTINGS; i++) { + if(spiSettings[i].pinCS == -1) { + spiSettings[i].pinCS = _pin; + return i; + } + } + } + return i; + } + + void RemovePin(uint8_t _pin) + { + if(_pin > NUM_DIGITAL_PINS) + return; + + for(uint8_t i = 0; i < NB_SPI_SETTINGS; i++) { + if(spiSettings[i].pinCS == _pin) { + spiSettings[i].pinCS = -1; + spiSettings[i].clk = SPI_SPEED_CLOCK_DEFAULT; + spiSettings[i].bOrder = MSBFIRST; + spiSettings[i].msb = 1; + spiSettings[i].dMode = SPI_MODE_0; + } + } + } + + void RemoveAllPin(void) + { + for(uint8_t i = 0; i < NB_SPI_SETTINGS; i++) { + spiSettings[i].pinCS = -1; + spiSettings[i].clk = SPI_SPEED_CLOCK_DEFAULT; + spiSettings[i].bOrder = MSBFIRST; + spiSettings[i].msb = 1; + spiSettings[i].dMode = SPI_MODE_0; + } + } +}; + +extern SPIClass SPI; + +#endif diff --git a/variants/DISCO_F100RB/variant.h b/variants/DISCO_F100RB/variant.h index 6acf72ec95..6888e978c2 100644 --- a/variants/DISCO_F100RB/variant.h +++ b/variants/DISCO_F100RB/variant.h @@ -132,16 +132,7 @@ enum { #define USER_BTN 5 //SPI definitions -//define 16 channels. As many channel as digital IOs -#define SPI_CHANNELS_NUM 16 - -//default chip salect pin -#define BOARD_SPI_DEFAULT_SS 43 - -//In case SPI CS channel is not used we define a default one -#define BOARD_SPI_OWN_SS SPI_CHANNELS_NUM - -#define SS BOARD_SPI_DEFAULT_SS +#define SS 43 #define SS1 40 #define SS2 41 #define SS3 42 diff --git a/variants/DISCO_F407VG/variant.h b/variants/DISCO_F407VG/variant.h index 32accc13dd..cb3c489261 100644 --- a/variants/DISCO_F407VG/variant.h +++ b/variants/DISCO_F407VG/variant.h @@ -160,16 +160,7 @@ enum { //SPI definitions -//define 16 channels. As many channel as digital IOs -#define SPI_CHANNELS_NUM 16 - -//default chip salect pin -#define BOARD_SPI_DEFAULT_SS 10 - -//In case SPI CS channel is not used we define a default one -#define BOARD_SPI_OWN_SS SPI_CHANNELS_NUM - -#define SS BOARD_SPI_DEFAULT_SS +#define SS 10 #define SS1 4 #define SS2 14 #define MOSI 44 @@ -222,7 +213,7 @@ extern HardwareSerial Serial; // SERIAL_PORT_HARDWARE_OPEN Hardware serial ports which are open for use. Their RX & TX // pins are NOT connected to anything by default. #define SERIAL_PORT_MONITOR Serial // Require connections for ST-LINK VCP on U2 pin 12 and 13. - // See UM �6.1.3 ST-LINK/V2-A VCP configuration) + // See UM §6.1.3 ST-LINK/V2-A VCP configuration) #define SERIAL_PORT_HARDWARE_OPEN Serial #endif diff --git a/variants/DISCO_F746NG/variant.h b/variants/DISCO_F746NG/variant.h index 5926bc464b..bfaa8f56cf 100644 --- a/variants/DISCO_F746NG/variant.h +++ b/variants/DISCO_F746NG/variant.h @@ -89,16 +89,7 @@ enum { //SPI definitions -//define 16 channels. As many channel as digital IOs -#define SPI_CHANNELS_NUM 16 - -//default chip salect pin -#define BOARD_SPI_DEFAULT_SS 10 - -//In case SPI CS channel is not used we define a default one -#define BOARD_SPI_OWN_SS SPI_CHANNELS_NUM - -#define SS BOARD_SPI_DEFAULT_SS +#define SS 10 #define SS1 4 #define SS2 7 #define SS3 8 diff --git a/variants/NUCLEO_F030R8/variant.h b/variants/NUCLEO_F030R8/variant.h index f69cbd69a9..c6b93dfb7b 100644 --- a/variants/NUCLEO_F030R8/variant.h +++ b/variants/NUCLEO_F030R8/variant.h @@ -131,16 +131,7 @@ enum { //SPI definitions -//define 16 channels. As many channel as digital IOs -#define SPI_CHANNELS_NUM 16 - -//default chip salect pin -#define BOARD_SPI_DEFAULT_SS 10 - -//In case SPI CS channel is not used we define a default one -#define BOARD_SPI_OWN_SS SPI_CHANNELS_NUM - -#define SS BOARD_SPI_DEFAULT_SS +#define SS 10 #define SS1 4 #define SS2 7 #define SS3 8 diff --git a/variants/NUCLEO_F091RC/variant.h b/variants/NUCLEO_F091RC/variant.h index 5eaef08180..d6e9d96ea2 100644 --- a/variants/NUCLEO_F091RC/variant.h +++ b/variants/NUCLEO_F091RC/variant.h @@ -129,16 +129,7 @@ enum { //SPI definitions -//define 16 channels. As many channel as digital IOs -#define SPI_CHANNELS_NUM 16 - -//default chip salect pin -#define BOARD_SPI_DEFAULT_SS 10 - -//In case SPI CS channel is not used we define a default one -#define BOARD_SPI_OWN_SS SPI_CHANNELS_NUM - -#define SS BOARD_SPI_DEFAULT_SS +#define SS 10 #define SS1 4 #define SS2 7 #define SS3 8 diff --git a/variants/NUCLEO_F103RB/variant.h b/variants/NUCLEO_F103RB/variant.h index a5d7ec6b05..c3fec5ecf3 100644 --- a/variants/NUCLEO_F103RB/variant.h +++ b/variants/NUCLEO_F103RB/variant.h @@ -129,16 +129,7 @@ enum { #define USER_BTN 23 //SPI definitions -//define 16 channels. As many channel as digital IOs -#define SPI_CHANNELS_NUM 16 - -//default chip salect pin -#define BOARD_SPI_DEFAULT_SS 10 - -//In case SPI CS channel is not used we define a default one -#define BOARD_SPI_OWN_SS SPI_CHANNELS_NUM - -#define SS BOARD_SPI_DEFAULT_SS +#define SS 10 #define SS1 4 #define SS2 7 #define SS3 8 diff --git a/variants/NUCLEO_F207ZG/variant.h b/variants/NUCLEO_F207ZG/variant.h index 77419ff4d6..e0ee3c0198 100644 --- a/variants/NUCLEO_F207ZG/variant.h +++ b/variants/NUCLEO_F207ZG/variant.h @@ -177,16 +177,7 @@ enum { //SPI definitions -//define 16 channels. As many channel as digital IOs -#define SPI_CHANNELS_NUM 16 - -//default chip salect pin -#define BOARD_SPI_DEFAULT_SS 10 - -//In case SPI CS channel is not used we define a default one -#define BOARD_SPI_OWN_SS SPI_CHANNELS_NUM - -#define SS BOARD_SPI_DEFAULT_SS +#define SS 10 #define MOSI 11 #define MISO 12 #define SCK 13 diff --git a/variants/NUCLEO_F303RE/variant.h b/variants/NUCLEO_F303RE/variant.h index 90fbd66ffe..6f699c2665 100644 --- a/variants/NUCLEO_F303RE/variant.h +++ b/variants/NUCLEO_F303RE/variant.h @@ -129,16 +129,7 @@ enum { //SPI definitions -//define 16 channels. As many channel as digital IOs -#define SPI_CHANNELS_NUM 16 - -//default chip salect pin -#define BOARD_SPI_DEFAULT_SS 10 - -//In case SPI CS channel is not used we define a default one -#define BOARD_SPI_OWN_SS SPI_CHANNELS_NUM - -#define SS BOARD_SPI_DEFAULT_SS +#define SS 10 #define SS1 4 #define SS2 7 #define SS3 8 diff --git a/variants/NUCLEO_F401RE/variant.h b/variants/NUCLEO_F401RE/variant.h index dcce0673a6..0c3a393d0c 100644 --- a/variants/NUCLEO_F401RE/variant.h +++ b/variants/NUCLEO_F401RE/variant.h @@ -130,16 +130,7 @@ enum { //SPI definitions -//define 16 channels. As many channel as digital IOs -#define SPI_CHANNELS_NUM 16 - -//default chip salect pin -#define BOARD_SPI_DEFAULT_SS 10 - -//In case SPI CS channel is not used we define a default one -#define BOARD_SPI_OWN_SS SPI_CHANNELS_NUM - -#define SS BOARD_SPI_DEFAULT_SS +#define SS 10 #define SS1 4 #define SS2 7 #define SS3 8 diff --git a/variants/NUCLEO_F411RE/variant.h b/variants/NUCLEO_F411RE/variant.h index 456a638ab4..5bf23c1482 100644 --- a/variants/NUCLEO_F411RE/variant.h +++ b/variants/NUCLEO_F411RE/variant.h @@ -130,16 +130,7 @@ enum { //SPI definitions -//define 16 channels. As many channel as digital IOs -#define SPI_CHANNELS_NUM 16 - -//default chip salect pin -#define BOARD_SPI_DEFAULT_SS 10 - -//In case SPI CS channel is not used we define a default one -#define BOARD_SPI_OWN_SS SPI_CHANNELS_NUM - -#define SS BOARD_SPI_DEFAULT_SS +#define SS 10 #define SS1 4 #define SS2 7 #define SS3 8 diff --git a/variants/NUCLEO_F429ZI/variant.h b/variants/NUCLEO_F429ZI/variant.h index c311be06a7..c6b834eac6 100644 --- a/variants/NUCLEO_F429ZI/variant.h +++ b/variants/NUCLEO_F429ZI/variant.h @@ -164,16 +164,7 @@ enum { //SPI definitions -//define 16 channels. As many channel as digital IOs -#define SPI_CHANNELS_NUM 16 - -//default chip salect pin -#define BOARD_SPI_DEFAULT_SS 10 - -//In case SPI CS channel is not used we define a default one -#define BOARD_SPI_OWN_SS SPI_CHANNELS_NUM - -#define SS BOARD_SPI_DEFAULT_SS +#define SS 10 #define SS1 4 #define SS2 7 #define SS3 8 diff --git a/variants/NUCLEO_L053R8/variant.h b/variants/NUCLEO_L053R8/variant.h index 45cd0fb2f0..3c3cbe8e23 100644 --- a/variants/NUCLEO_L053R8/variant.h +++ b/variants/NUCLEO_L053R8/variant.h @@ -129,16 +129,7 @@ enum { //SPI definitions -//define 16 channels. As many channel as digital IOs -#define SPI_CHANNELS_NUM 16 - -//default chip salect pin -#define BOARD_SPI_DEFAULT_SS 10 - -//In case SPI CS channel is not used we define a default one -#define BOARD_SPI_OWN_SS SPI_CHANNELS_NUM - -#define SS BOARD_SPI_DEFAULT_SS +#define SS 10 #define SS1 4 #define SS2 7 #define SS3 8 diff --git a/variants/NUCLEO_L152RE/variant.h b/variants/NUCLEO_L152RE/variant.h index b7930b813c..5fedc92c39 100644 --- a/variants/NUCLEO_L152RE/variant.h +++ b/variants/NUCLEO_L152RE/variant.h @@ -134,16 +134,7 @@ enum { //SPI definitions -//define 16 channels. As many channel as digital IOs -#define SPI_CHANNELS_NUM 16 - -//default chip salect pin -#define BOARD_SPI_DEFAULT_SS 10 - -//In case SPI CS channel is not used we define a default one -#define BOARD_SPI_OWN_SS SPI_CHANNELS_NUM - -#define SS BOARD_SPI_DEFAULT_SS +#define SS 10 #define SS1 4 #define SS2 7 #define SS3 8 diff --git a/variants/NUCLEO_L432KC/variant.h b/variants/NUCLEO_L432KC/variant.h index c77be56737..75bff7e3d6 100644 --- a/variants/NUCLEO_L432KC/variant.h +++ b/variants/NUCLEO_L432KC/variant.h @@ -87,16 +87,7 @@ enum { //SPI definitions -//define 16 channels. As many channel as digital IOs -#define SPI_CHANNELS_NUM 16 - -//default chip select pin -#define BOARD_SPI_DEFAULT_SS 10 - -//In case SPI CS channel is not used we define a default one -#define BOARD_SPI_OWN_SS SPI_CHANNELS_NUM - -#define SS BOARD_SPI_DEFAULT_SS +#define SS 10 #define MOSI 11 #define MISO 12 #define SCK 13 diff --git a/variants/NUCLEO_L476RG/variant.h b/variants/NUCLEO_L476RG/variant.h index afc34d6aab..502e34ed28 100644 --- a/variants/NUCLEO_L476RG/variant.h +++ b/variants/NUCLEO_L476RG/variant.h @@ -129,16 +129,7 @@ enum { //SPI definitions -//define 16 channels. As many channel as digital IOs -#define SPI_CHANNELS_NUM 16 - -//default chip salect pin -#define BOARD_SPI_DEFAULT_SS 10 - -//In case SPI CS channel is not used we define a default one -#define BOARD_SPI_OWN_SS SPI_CHANNELS_NUM - -#define SS BOARD_SPI_DEFAULT_SS +#define SS 10 #define SS1 4 #define SS2 7 #define SS3 8 diff --git a/variants/board_template/variant.h b/variants/board_template/variant.h index 4566bc095f..3bac3a75a7 100644 --- a/variants/board_template/variant.h +++ b/variants/board_template/variant.h @@ -89,16 +89,7 @@ enum { //SPI definitions -//define 16 channels. As many channel as digital IOs -#define SPI_CHANNELS_NUM 16 - -//default chip salect pin -#define BOARD_SPI_DEFAULT_SS 10 // Default for Arduino connector compatibility - -//In case SPI CS channel is not used we define a default one -#define BOARD_SPI_OWN_SS SPI_CHANNELS_NUM - -#define SS BOARD_SPI_DEFAULT_SS +#define SS 10 // Default for Arduino connector compatibility #define MOSI 11 // Default for Arduino connector compatibility #define MISO 12 // Default for Arduino connector compatibility #define SCK 13 // Default for Arduino connector compatibility