diff --git a/CI/build/examples/BareMinimum/BareMinimum.ino b/CI/build/examples/BareMinimum/BareMinimum.ino index ac299b56f9..404d98c22c 100644 --- a/CI/build/examples/BareMinimum/BareMinimum.ino +++ b/CI/build/examples/BareMinimum/BareMinimum.ino @@ -19,26 +19,25 @@ /* ---------------------------------------------------------------------- Defines each of the tests performed ------------------------------------------------------------------- */ -#define MAX_BLOCKSIZE 2 -#define DELTA (0.0001f) +#define MAX_BLOCKSIZE 2 +#define DELTA (0.0001f) /* ---------------------------------------------------------------------- Test input data for Floating point sin_cos example for 32-blockSize Generated by the MATLAB randn() function ------------------------------------------------------------------- */ -const float32_t testInput_f32[MAX_BLOCKSIZE] = -{ - -1.244916875853235400, -4.793533929171324800 +const float32_t testInput_f32[MAX_BLOCKSIZE] = { + -1.244916875853235400, -4.793533929171324800 }; const float32_t testRefOutput_f32 = 1.000000000; /* ---------------------------------------------------------------------- Declare Global variables ------------------------------------------------------------------- */ uint32_t blockSize = 2; -float32_t testOutput; -float32_t cosOutput; -float32_t sinOutput; -float32_t cosSquareOutput; -float32_t sinSquareOutput; +float32_t testOutput; +float32_t cosOutput; +float32_t sinOutput; +float32_t cosSquareOutput; +float32_t sinSquareOutput; /* ---------------------------------------------------------------------- Max magnitude FFT Bin test ------------------------------------------------------------------- */ @@ -46,11 +45,11 @@ arm_status status; /* CMSIS_DSP */ #ifndef USER_BTN -#define USER_BTN 2 +#define USER_BTN 2 #endif #ifndef LED_BUILTIN -#define LED_BUILTIN 13 +#define LED_BUILTIN 13 #endif #ifndef PIN_SERIAL_RX @@ -72,8 +71,7 @@ SoftwareSerial swSerial(10, 11); void setup() { // Serial HW & SW -#if (!defined(USBD_USE_CDC) && !defined(DISABLE_GENERIC_SERIALUSB)) &&\ - (!defined(VIRTIOCON) && !defined(DISABLE_GENERIC_SERIALVIRTIO)) +#if (!defined(USBD_USE_CDC) && !defined(DISABLE_GENERIC_SERIALUSB)) && (!defined(VIRTIOCON) && !defined(DISABLE_GENERIC_SERIALVIRTIO)) Serial.setRx(PIN_SERIAL_RX); Serial.setTx(digitalPinToPinName(PIN_SERIAL_TX)); #endif @@ -92,7 +90,7 @@ void setup() { // EEPROM byte value = EEPROM.read(0x01); - EEPROM.write(EEPROM.length()-1, value); + EEPROM.write(EEPROM.length() - 1, value); #ifndef STM32MP1xx // IWDG @@ -111,13 +109,13 @@ void setup() { #endif // SPI - SPISettings settings(SPI_SPEED_CLOCK_DEFAULT, MSBFIRST, SPI_MODE_0); + SPISettings settings(SPI_SPEED_CLOCK_DEFAULT, MSBFIRST, SPI_MODE0); SPI.setMISO(PIN_SPI_MISO); SPI.setMOSI(PIN_SPI_MOSI); SPI.setSCLK(PIN_SPI_SCK); SPI.setSSEL(digitalPinToPinName(PIN_SPI_SS)); - SPI.begin(PIN_SPI_SS); - SPI.beginTransaction(1, settings); + SPI.begin(); + SPI.beginTransaction(settings); SPI.endTransaction(); SPI.transfer(1); SPI.end(); @@ -146,7 +144,7 @@ void setup() { diff = fabsf(testRefOutput_f32 - testOutput); /* Comparison of sin_cos value with reference */ status = (diff > DELTA) ? ARM_MATH_TEST_FAILURE : ARM_MATH_SUCCESS; - if ( status == ARM_MATH_TEST_FAILURE) { + if (status == ARM_MATH_TEST_FAILURE) { break; } } diff --git a/libraries/SPI/README.md b/libraries/SPI/README.md index 18fa5c632d..5bf0889c59 100644 --- a/libraries/SPI/README.md +++ b/libraries/SPI/README.md @@ -1,70 +1,63 @@ ## SPI -STM32 SPI library has been modified with the possibility to manage several CS pins without to stop the SPI interface. +STM32 SPI library has been modified with the possibility to manage hardware CS pin linked to the SPI peripheral. _We do not describe here the [SPI Arduino API](https://www.arduino.cc/en/Reference/SPI) but the functionalities added._ -We give to the user 3 possibilities about the management of the CS pin: -1. the CS pin is managed directly by the user code before to transfer the data (like the Arduino SPI library) -2. the user gives the CS pin number to the library API and the library manages itself the CS pin (see example below) -3. the user uses a hardware CS pin linked to the SPI peripheral +User have 2 possibilities about the management of the CS pin: +* the CS pin is managed directly by the user code before to transfer the data (like the Arduino SPI library) +* the user uses a hardware CS pin linked to the SPI peripheral -### New API functions +### New SPISetting parameter -* **`SPIClass::SPIClass(uint8_t mosi, uint8_t miso, uint8_t sclk, uint8_t ssel)`**: alternative class constructor -_Params_ SPI mosi pin -_Params_ SPI miso pin -_Params_ SPI sclk pin -_Params_ (optional) SPI ssel pin. This pin must be an hardware CS pin. If you configure this pin, the chip select will be managed by the SPI peripheral. Do not use API functions with CS pin in parameter. +* `noReceive`: value can be `SPI_TRANSMITRECEIVE` or `SPI_TRANSMITONLY`. It allows to skip receive data after transmitting. Default `SPI_TRANSMITRECEIVE`. -* **`void SPIClass::begin(uint8_t _pin)`**: initialize the SPI interface and add a CS pin -_Params_ spi CS pin to be managed by the SPI library +### New API functions -* **`void beginTransaction(uint8_t pin, SPISettings settings)`**: allows to configure the SPI with other parameter. These new parameter are saved this an associated CS pin. -_Params_ SPI CS pin to be managed by the SPI library -_Params_ SPI settings +* `SPIClass::SPIClass(uint8_t mosi, uint8_t miso, uint8_t sclk, uint8_t ssel)`: alternative class constructor +_Params_ SPI `mosi` pin +_Params_ SPI `miso` pin +_Params_ SPI `sclk` pin +_Params_ (optional) SPI `ssel` pin. This pin must be an hardware CS pin. If you configure this pin, the chip select will be managed by the SPI peripheral. -* **`void endTransaction(uint8_t pin)`**: removes a CS pin and the SPI settings associated -_Params_ SPI CS pin managed by the SPI library + * `SPI_HandleTypeDef *getHandle(void)`: Could be used to mix Arduino API and STM32Cube HAL API (ex: DMA). **Use at your own risk.** -**_Note 1_** The following functions must be called after initialization of the SPI instance with `begin()` or `beginTransaction()`. -If you have several device to manage, you can call `beginTransaction()` several time with different CS pin in parameter. -Then you can call the following functions with different CS pin without call again `beginTransaction()` (until you call `end()` or `endTransaction()`). -**_Note 2_** If the mode is set to `SPI_CONTINUE`, the CS pin is kept enabled. Be careful in case you use several CS pin. +##### Example -* **`byte transfer(uint8_t pin, uint8_t _data, SPITransferMode _mode = SPI_LAST)`**: write/read one byte -_Params_ SPI CS pin managed by the SPI library -_Params_ data to write -_Params_ (optional) if `SPI_LAST` CS pin is reset, `SPI_CONTINUE` the CS pin is kept enabled. -_Return_ byte received +This is an example of the use of the hardware CS pin linked to the SPI peripheral: -* **`uint16_t transfer16(uint8_t pin, uint16_t _data, SPITransferMode _mode = SPI_LAST)`**: write/read half-word -_Params_ SPI CS pin managed by the SPI library -_Params_ 16bits data to write -_Params_ (optional) if `SPI_LAST` CS pin is reset, `SPI_CONTINUE` the CS pin is kept enabled. -_Return_ 16bits data received +```C++ +#include +// MOSI MISO SCLK SSEL +SPIClass SPI_3(PC12, PC11, PC10, PC9); + +void setup() { + SPI_3.begin(); // Enable the SPI_3 instance with default SPISsettings + SPI_3.beginTransaction(settings); // Configure the SPI_3 instance with other settings + SPI_3.transfer(0x52); // Transfers data to the first device + SPI_3.end() //SPI_3 instance is disabled +} +``` -* **`void transfer(uint8_t pin, void *_buf, size_t _count, SPITransferMode _mode = SPI_LAST)`**: write/read several bytes. Only one buffer used to write and read the data -_Params_ SPI CS pin managed by the SPI library -_Params_ pointer to data to write. The data will be replaced by the data read. -_Params_ number of data to write/read. -_Params_ (optional) if `SPI_LAST` CS pin is reset, `SPI_CONTINUE` the CS pin is kept enabled. +#### Change default `SPI` instance pins +It is also possible to change the default pins used by the `SPI` instance using above API: -* **`void transfer(byte _pin, void *_bufout, void *_bufin, size_t _count, SPITransferMode _mode = SPI_LAST)`**: write/read several bytes. One buffer for the output data and one for the input data -_Params_ SPI CS pin managed by the SPI library -_Params_ pointer to data to write. -_Params_ pointer where to store the data read. -_Params_ number of data to write/read. -_Params_ (optional) if `SPI_LAST` CS pin is reset, `SPI_CONTINUE` the CS pin is kept enabled. +[[/img/Warning-icon.png|alt="Warning"]] **Have to be called before `begin()`.** -### Example +* `void setMISO(uint32_t miso)` +* `void setMOSI(uint32_t mosi)` +* `void setSCLK(uint32_t sclk)` +* `void setSSEL(uint32_t ssel)` +* `void setMISO(PinName miso)` +* `void setMOSI(PinName mosi)` +* `void setSCLK(PinName sclk)` +* `void setSSEL(PinName ssel)` -This is an example of the use of the CS pin management: +**_Note 1_** Using `setSSEL()` allows to enable hardware CS pin management linked to the SPI peripheral. +##### Example: ```C++ -SPI.begin(2); //Enables the SPI instance with default settings and attaches the CS pin -SPI.beginTransaction(1, settings); //Attaches another CS pin and configure the SPI instance with other settings -SPI.transfer(1, 0x52); //Transfers data to the first device -SPI.transfer(2, 0xA4); //Transfers data to the second device. The SPI instance is configured with the right settings -SPI.end() //SPI instance is disabled + SPI.setMISO(PC_4); // using pin name PY_n + SPI.setMOSI(PC2); // using pin number PYn + SPI.begin(2); ``` diff --git a/libraries/SPI/src/SPI.cpp b/libraries/SPI/src/SPI.cpp index eab0792182..b3266d348a 100644 --- a/libraries/SPI/src/SPI.cpp +++ b/libraries/SPI/src/SPI.cpp @@ -16,7 +16,7 @@ SPIClass SPI; /** * @brief Default constructor. Uses pin configuration of variant.h. */ -SPIClass::SPIClass() : _CSPinConfig(NO_CONFIG) +SPIClass::SPIClass() { _spi.pin_miso = digitalPinToPinName(MISO); _spi.pin_mosi = digitalPinToPinName(MOSI); @@ -43,7 +43,7 @@ SPIClass::SPIClass() : _CSPinConfig(NO_CONFIG) * another CS pin and don't pass a CS pin as parameter to any functions * of the class. */ -SPIClass::SPIClass(uint32_t mosi, uint32_t miso, uint32_t sclk, uint32_t ssel) : _CSPinConfig(NO_CONFIG) +SPIClass::SPIClass(uint32_t mosi, uint32_t miso, uint32_t sclk, uint32_t ssel) { _spi.pin_miso = digitalPinToPinName(miso); _spi.pin_mosi = digitalPinToPinName(mosi); @@ -53,77 +53,37 @@ SPIClass::SPIClass(uint32_t mosi, uint32_t miso, uint32_t sclk, uint32_t ssel) : /** * @brief Initialize the SPI instance. - * @param _pin: chip select pin (optional). If this parameter is filled, - * it gives the management of the CS pin to the SPI class. In this case - * do not manage the CS pin outside of the SPI class. */ -void SPIClass::begin(uint8_t _pin) +void SPIClass::begin(void) { - uint8_t 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.handle.State = HAL_SPI_STATE_RESET; - spi_init(&_spi, spiSettings[idx].clk, - spiSettings[idx].dMode, - spiSettings[idx].bOrder); - _CSPinConfig = _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 - + _spiSettings = DEFAULT_SPI_SETTINGS; + spi_init(&_spi, _spiSettings.getClockFreq(), + _spiSettings.getDataMode(), + _spiSettings.getBitOrder()); } /** * @brief This function should be used to configure the SPI instance in case you * don't use the default parameters set by the begin() function. - * @param _pin: CS pin (optional). This pin will be attached with the settings. * @param settings: SPI settings(clock speed, bit order, data mode). - * @Note For each SPI instance you are able to manage until NB_SPI_SETTINGS - * devices attached to the same SPI peripheral. You need to indicate the - * CS pin used to the transfer() function and the SPI instance will be - * configured with the right settings. */ -void SPIClass::beginTransaction(uint8_t _pin, SPISettings settings) +void SPIClass::beginTransaction(SPISettings settings) { - uint8_t idx = pinIdx(_pin, ADD_NEW_PIN); - if (idx >= NB_SPI_SETTINGS) { - return; + if (_spiSettings != settings) { + _spiSettings = settings; + spi_init(&_spi, _spiSettings.getClockFreq(), + _spiSettings.getDataMode(), + _spiSettings.getBitOrder()); } - - spiSettings[idx].clk = settings.clk; - spiSettings[idx].dMode = settings.dMode; - spiSettings[idx].bOrder = settings.bOrder; - spiSettings[idx].noReceive = settings.noReceive; - - 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].bOrder); - _CSPinConfig = _pin; } /** - * @brief Remove the CS pin and the settings associated to the SPI instance. - * @param _pin: CS pin (optional) + * @brief End the transaction after beginTransaction usage */ -void SPIClass::endTransaction(uint8_t _pin) +void SPIClass::endTransaction(void) { - RemovePin(_pin); - _CSPinConfig = NO_CONFIG; + } /** @@ -132,35 +92,26 @@ void SPIClass::endTransaction(uint8_t _pin) void SPIClass::end() { spi_deinit(&_spi); - RemoveAllPin(); - _CSPinConfig = NO_CONFIG; } /** * @brief Deprecated function. * Configure the bit order: MSB first or LSB first. - * @param _pin: CS pin associated to a configuration (optional). * @param _bitOrder: MSBFIRST or LSBFIRST */ -void SPIClass::setBitOrder(uint8_t _pin, BitOrder _bitOrder) +void SPIClass::setBitOrder(BitOrder bitOrder) { - uint8_t idx = pinIdx(_pin, GET_IDX); - if (idx >= NB_SPI_SETTINGS) { - return; - } - - spiSettings[idx].bOrder = _bitOrder; + _spiSettings.setBitOrder(bitOrder); - spi_init(&_spi, spiSettings[idx].clk, - spiSettings[idx].dMode, - spiSettings[idx].bOrder); + spi_init(&_spi, _spiSettings.getClockFreq(), + _spiSettings.getDataMode(), + _spiSettings.getBitOrder()); } /** * @brief Deprecated function. * Configure the data mode (clock polarity and clock phase) - * @param _pin: CS pin associated to a configuration (optional). - * @param _mode: SPI_MODE0, SPI_MODE1, SPI_MODE2 or SPI_MODE3 + * @param mode: SPI_MODE0, SPI_MODE1, SPI_MODE2 or SPI_MODE3 * @note * Mode Clock Polarity (CPOL) Clock Phase (CPHA) * SPI_MODE0 0 0 @@ -168,240 +119,105 @@ void SPIClass::setBitOrder(uint8_t _pin, BitOrder _bitOrder) * SPI_MODE2 1 0 * SPI_MODE3 1 1 */ -void SPIClass::setDataMode(uint8_t _pin, uint8_t _mode) + +void SPIClass::setDataMode(uint8_t mode) { - uint8_t idx = pinIdx(_pin, GET_IDX); - if (idx >= NB_SPI_SETTINGS) { - return; - } + setDataMode((SPIMode)mode); +} - 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; - } +void SPIClass::setDataMode(SPIMode mode) +{ + _spiSettings.setDataMode(mode); - spi_init(&_spi, spiSettings[idx].clk, - spiSettings[idx].dMode, - spiSettings[idx].bOrder); + spi_init(&_spi, _spiSettings.getClockFreq(), + _spiSettings.getDataMode(), + _spiSettings.getBitOrder()); } /** * @brief Deprecated function. * Configure the clock speed - * @param _pin: CS pin associated to a configuration (optional). * @param _divider: the SPI clock can be divided by values from 1 to 255. * If 0, default SPI speed is used. */ -void SPIClass::setClockDivider(uint8_t _pin, uint8_t _divider) +void SPIClass::setClockDivider(uint8_t _divider) { - uint8_t idx = pinIdx(_pin, GET_IDX); - if (idx >= NB_SPI_SETTINGS) { - return; - } if (_divider == 0) { - spiSettings[idx].clk = SPI_SPEED_CLOCK_DEFAULT; + _spiSettings.setClockFreq(SPI_SPEED_CLOCK_DEFAULT); } else { - /* Get clk freq of the SPI instance and compute it */ - spiSettings[idx].clk = spi_getClkFreq(&_spi) / _divider; + /* Get clock freq of the SPI instance and compute it */ + _spiSettings.setClockFreq(spi_getClkFreq(&_spi) / _divider); } - spi_init(&_spi, spiSettings[idx].clk, - spiSettings[idx].dMode, - spiSettings[idx].bOrder); + spi_init(&_spi, _spiSettings.getClockFreq(), + _spiSettings.getDataMode(), + _spiSettings.getBitOrder()); } /** * @brief Transfer one byte on the SPI bus. * begin() or beginTransaction() must be called at least once before. - * @param _pin: CS pin to select a device (optional). If the previous transfer - * used another CS pin then the SPI instance will be reconfigured. * @param data: byte to send. - * @param _mode: (optional) can be SPI_CONTINUE in case of multiple successive - * send or SPI_LAST to indicate the end of send. - * 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. * @return byte received from the slave. */ -byte SPIClass::transfer(uint8_t _pin, uint8_t data, SPITransferMode _mode) +uint8_t SPIClass::transfer(uint8_t data) { - uint8_t rx_buffer = 0; - - uint8_t idx = pinIdx(_pin, GET_IDX); - if (idx >= NB_SPI_SETTINGS) { - return rx_buffer; - } - - if (_pin != _CSPinConfig) { - spi_init(&_spi, spiSettings[idx].clk, - spiSettings[idx].dMode, - spiSettings[idx].bOrder); - _CSPinConfig = _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, spiSettings[idx].noReceive); - - if ((_pin != CS_PIN_CONTROLLED_BY_USER) && (_mode == SPI_LAST) && (_spi.pin_ssel == NC)) { - digitalWrite(_pin, HIGH); - } - - return rx_buffer; + spi_transfer(&_spi, &data, sizeof(uint8_t), SPI_TRANSFER_TIMEOUT, _spiSettings.getSkipRecv()); + return data; } /** * @brief Transfer two bytes on the SPI bus in 16 bits format. * begin() or beginTransaction() must be called at least once before. - * @param _pin: CS pin to select a device (optional). If the previous transfer - * used another CS pin then the SPI instance will be reconfigured. * @param data: bytes to send. - * @param _mode: (optional) can be SPI_CONTINUE in case of multiple successive - * send or SPI_LAST to indicate the end of send. - * 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. * @return bytes received from the slave in 16 bits format. */ -uint16_t SPIClass::transfer16(uint8_t _pin, uint16_t data, SPITransferMode _mode) +uint16_t SPIClass::transfer16(uint16_t data) { - uint16_t rx_buffer = 0; uint16_t tmp; - uint8_t idx = pinIdx(_pin, GET_IDX); - if (idx >= NB_SPI_SETTINGS) { - return rx_buffer; - } - - if (_pin != _CSPinConfig) { - spi_init(&_spi, spiSettings[idx].clk, - spiSettings[idx].dMode, - spiSettings[idx].bOrder); - _CSPinConfig = _pin; - } - - if (spiSettings[idx].bOrder) { + if (_spiSettings.getBitOrder()) { tmp = ((data & 0xff00) >> 8) | ((data & 0xff) << 8); data = tmp; } + spi_transfer(&_spi, (uint8_t *)&data, sizeof(uint16_t), + SPI_TRANSFER_TIMEOUT, _spiSettings.getSkipRecv()); - 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, spiSettings[idx].noReceive); - - if ((_pin != CS_PIN_CONTROLLED_BY_USER) && (_mode == SPI_LAST) && (_spi.pin_ssel == NC)) { - digitalWrite(_pin, HIGH); - } - - if (spiSettings[idx].bOrder) { - tmp = ((rx_buffer & 0xff00) >> 8) | ((rx_buffer & 0xff) << 8); - rx_buffer = tmp; + if (_spiSettings.getBitOrder()) { + tmp = ((data & 0xff00) >> 8) | ((data & 0xff) << 8); + data = tmp; } - return rx_buffer; + return data; } /** * @brief Transfer several bytes. Only one buffer used to send and receive data. * begin() or beginTransaction() must be called at least once before. - * @param _pin: CS pin to select a device (optional). If the previous transfer - * used another CS pin then the SPI instance will be reconfigured. - * @param _buf: pointer to the bytes to send. The bytes received are copy in + * @param buf: pointer to the bytes to send. The bytes received are copy in * this buffer. - * @param _count: number of bytes to send/receive. - * @param _mode: (optional) can be SPI_CONTINUE in case of multiple successive - * send or SPI_LAST to indicate the end of send. - * 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. + * @param count: number of bytes to send/receive. */ -void SPIClass::transfer(uint8_t _pin, void *_buf, size_t _count, SPITransferMode _mode) +void SPIClass::transfer(void *buf, size_t count) { - if ((_count == 0) || (_buf == NULL)) { - return; - } - uint8_t idx = pinIdx(_pin, GET_IDX); - if (idx >= NB_SPI_SETTINGS) { - return; - } - if (_pin != _CSPinConfig) { - - spi_init(&_spi, spiSettings[idx].clk, - spiSettings[idx].dMode, - spiSettings[idx].bOrder); - _CSPinConfig = _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, spiSettings[idx].noReceive); - - if ((_pin != CS_PIN_CONTROLLED_BY_USER) && (_mode == SPI_LAST) && (_spi.pin_ssel == NC)) { - digitalWrite(_pin, HIGH); + if ((count != 0) && (buf != NULL)) { + spi_transfer(&_spi, ((uint8_t *)buf), count, + SPI_TRANSFER_TIMEOUT, _spiSettings.getSkipRecv()); } } /** - * @brief Transfer several bytes. One buffer contains the data to send and - * another one will contains the data received. begin() or - * beginTransaction() must be called at least once before. - * @param _pin: CS pin to select a device (optional). If the previous transfer - * used another CS pin then the SPI instance will be reconfigured. - * @param _bufout: pointer to the bytes to send. - * @param _bufin: pointer to the bytes received. - * @param _count: number of bytes to send/receive. - * @param _mode: (optional) can be SPI_CONTINUE in case of multiple successive - * send or SPI_LAST to indicate the end of send. - * 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. + * @brief Not implemented. */ -void SPIClass::transfer(byte _pin, void *_bufout, void *_bufin, size_t _count, SPITransferMode _mode) +void SPIClass::usingInterrupt(int interruptNumber) { - if ((_count == 0) || (_bufout == NULL) || (_bufin == NULL)) { - return; - } - uint8_t idx = pinIdx(_pin, GET_IDX); - if (idx >= NB_SPI_SETTINGS) { - return; - } - - if (_pin != _CSPinConfig) { - spi_init(&_spi, spiSettings[idx].clk, - spiSettings[idx].dMode, - spiSettings[idx].bOrder); - _CSPinConfig = _pin; - } - - if ((_pin != CS_PIN_CONTROLLED_BY_USER) && (_spi.pin_ssel == NC)) { - digitalWrite(_pin, LOW); - } - - spi_transfer(&_spi, ((uint8_t *)_bufout), ((uint8_t *)_bufin), _count, - SPI_TRANSFER_TIMEOUT, spiSettings[idx].noReceive); - - if ((_pin != CS_PIN_CONTROLLED_BY_USER) && (_mode == SPI_LAST) && (_spi.pin_ssel == NC)) { - digitalWrite(_pin, HIGH); - } + UNUSED(interruptNumber); } /** * @brief Not implemented. */ -void SPIClass::usingInterrupt(uint8_t interruptNumber) +void SPIClass::notUsingInterrupt(int interruptNumber) { UNUSED(interruptNumber); } @@ -423,68 +239,33 @@ void SPIClass::detachInterrupt(void) } #if defined(SUBGHZSPI_BASE) -void SUBGHZSPIClass::begin(uint8_t _pin) +void SUBGHZSPIClass::begin() { - if (_pin != CS_PIN_CONTROLLED_BY_USER) { - LL_PWR_UnselectSUBGHZSPI_NSS(); - } - SPIClass::begin(CS_PIN_CONTROLLED_BY_USER); + SPIClass::begin(); } -void SUBGHZSPIClass::beginTransaction(uint8_t _pin, SPISettings settings) +void SUBGHZSPIClass::beginTransaction(SPISettings settings) { - if (_pin != CS_PIN_CONTROLLED_BY_USER) { - LL_PWR_UnselectSUBGHZSPI_NSS(); - } - SPIClass::beginTransaction(CS_PIN_CONTROLLED_BY_USER, settings); + SPIClass::beginTransaction(settings); } -byte SUBGHZSPIClass::transfer(uint8_t _pin, uint8_t _data, SPITransferMode _mode) +byte SUBGHZSPIClass::transfer(uint8_t _data) { byte res; - if (_pin != CS_PIN_CONTROLLED_BY_USER) { - LL_PWR_SelectSUBGHZSPI_NSS(); - } - res = SPIClass::transfer(CS_PIN_CONTROLLED_BY_USER, _data, _mode); - if (_pin != CS_PIN_CONTROLLED_BY_USER) { - LL_PWR_UnselectSUBGHZSPI_NSS(); - } + res = SPIClass::transfer(_data); return res; } -uint16_t SUBGHZSPIClass::transfer16(uint8_t _pin, uint16_t _data, SPITransferMode _mode) +uint16_t SUBGHZSPIClass::transfer16(uint16_t _data) { uint16_t rx_buffer = 0; - if (_pin != CS_PIN_CONTROLLED_BY_USER) { - LL_PWR_SelectSUBGHZSPI_NSS(); - } - SPIClass::transfer16(CS_PIN_CONTROLLED_BY_USER, _data, _mode); - if (_pin != CS_PIN_CONTROLLED_BY_USER) { - LL_PWR_UnselectSUBGHZSPI_NSS(); - } + rx_buffer = SPIClass::transfer16(_data); return rx_buffer; } -void SUBGHZSPIClass::transfer(uint8_t _pin, void *_buf, size_t _count, SPITransferMode _mode) +void SUBGHZSPIClass::transfer(void *_buf, size_t _count) { - if (_pin != CS_PIN_CONTROLLED_BY_USER) { - LL_PWR_SelectSUBGHZSPI_NSS(); - } - SPIClass::transfer(CS_PIN_CONTROLLED_BY_USER, _buf, _count, _mode); - if (_pin != CS_PIN_CONTROLLED_BY_USER) { - LL_PWR_UnselectSUBGHZSPI_NSS(); - } -} - -void SUBGHZSPIClass::transfer(byte _pin, void *_bufout, void *_bufin, size_t _count, SPITransferMode _mode) -{ - if (_pin != CS_PIN_CONTROLLED_BY_USER) { - LL_PWR_SelectSUBGHZSPI_NSS(); - } - SPIClass::transfer(CS_PIN_CONTROLLED_BY_USER, _bufout, _bufin, _count, _mode); - if (_pin != CS_PIN_CONTROLLED_BY_USER) { - LL_PWR_UnselectSUBGHZSPI_NSS(); - } + SPIClass::transfer(_buf, _count); } void SUBGHZSPIClass::enableDebugPins(uint32_t mosi, uint32_t miso, uint32_t sclk, uint32_t ssel) diff --git a/libraries/SPI/src/SPI.h b/libraries/SPI/src/SPI.h index 7bde790337..9509c871eb 100644 --- a/libraries/SPI/src/SPI.h +++ b/libraries/SPI/src/SPI.h @@ -38,76 +38,115 @@ extern "C" { #define SPI_CLOCK_DIV64 64 #define SPI_CLOCK_DIV128 128 -// SPI mode parameters for SPISettings -#define SPI_MODE0 0x00 -#define SPI_MODE1 0x01 -#define SPI_MODE2 0x02 -#define SPI_MODE3 0x03 - #define SPI_TRANSMITRECEIVE 0x0 #define SPI_TRANSMITONLY 0x1 -// Transfer mode -enum SPITransferMode { - SPI_CONTINUE, /* Transfer not finished: CS pin kept active */ - SPI_LAST /* Transfer ended: CS pin released */ -}; - -// Indicates the user controls himself the CS pin outside of the spi class -#define CS_PIN_CONTROLLED_BY_USER NUM_DIGITAL_PINS - -// Indicates there is no configuration selected -#define NO_CONFIG ((int16_t)(-1)) - // Defines a default timeout delay in milliseconds for the SPI transfer #ifndef SPI_TRANSFER_TIMEOUT #define SPI_TRANSFER_TIMEOUT 1000 #endif -/* - * Defines the number of settings saved per SPI instance. Must be in range 1 to 254. - * Can be redefined in variant.h - */ -#ifndef NB_SPI_SETTINGS - #define NB_SPI_SETTINGS 4 -#endif - class SPISettings { public: - constexpr SPISettings(uint32_t clock, BitOrder bitOrder, uint8_t dataMode, bool noRecv = SPI_TRANSMITRECEIVE) - : pinCS(-1), - clk(clock), - bOrder(bitOrder), - dMode((spi_mode_e)( - (SPI_MODE0 == dataMode) ? SPI_MODE_0 : - (SPI_MODE1 == dataMode) ? SPI_MODE_1 : - (SPI_MODE2 == dataMode) ? SPI_MODE_2 : - (SPI_MODE3 == dataMode) ? SPI_MODE_3 : - SPI_MODE0 - )), - noReceive(noRecv) - { } - constexpr SPISettings() - : pinCS(-1), - clk(SPI_SPEED_CLOCK_DEFAULT), - bOrder(MSBFIRST), - dMode(SPI_MODE_0), - noReceive(SPI_TRANSMITRECEIVE) - { } + SPISettings(uint32_t clock, BitOrder bitOrder, SPIMode dataMode, bool skipRecv = SPI_TRANSMITRECEIVE) + { + if (__builtin_constant_p(clock)) { + init_AlwaysInline(clock, bitOrder, dataMode, skipRecv); + } else { + init_MightInline(clock, bitOrder, dataMode, skipRecv); + } + } + + SPISettings(uint32_t clock, BitOrder bitOrder, int dataMode, bool skipRecv = SPI_TRANSMITRECEIVE) + { + if (__builtin_constant_p(clock)) { + init_AlwaysInline(clock, bitOrder, (SPIMode)dataMode, skipRecv); + } else { + init_MightInline(clock, bitOrder, (SPIMode)dataMode, skipRecv); + } + } + + // Default speed set to 4MHz, SPI mode set to MODE 0 and Bit order set to MSB first. + SPISettings() + { + init_AlwaysInline(SPI_SPEED_CLOCK_DEFAULT, MSBFIRST, SPI_MODE0, SPI_TRANSMITRECEIVE); + } + + bool operator==(const SPISettings &rhs) const + { + if ((this->clockFreq == rhs.clockFreq) && + (this->bitOrder == rhs.bitOrder) && + (this->dataMode == rhs.dataMode) && + (this->skipRecv == rhs.skipRecv)) { + return true; + } + return false; + } + + bool operator!=(const SPISettings &rhs) const + { + return !(*this == rhs); + } + + uint32_t getClockFreq() const + { + return clockFreq; + } + SPIMode getDataMode() const + { + return dataMode; + } + BitOrder getBitOrder() const + { + return (bitOrder); + } + bool getSkipRecv() const + { + return skipRecv; + } + + void setClockFreq(uint32_t clkFreq) + { + clockFreq = clkFreq; + } + void setDataMode(SPIMode mode) + { + dataMode = mode; + } + void setBitOrder(BitOrder order) + { + bitOrder = order; + } + void setSkipRecv(bool skip) + { + skipRecv = skip; + } + private: - int16_t pinCS; //CS pin associated to the configuration - uint32_t clk; //specifies the spi bus maximum clock speed - BitOrder bOrder; //bit order (MSBFirst or LSBFirst) - 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 - friend class SPIClass; - bool noReceive; + void init_MightInline(uint32_t clock, BitOrder bitOrder, SPIMode dataMode, bool skipRecv) + { + init_AlwaysInline(clock, bitOrder, dataMode, skipRecv); + } + + // Core developer MUST use an helper function in beginTransaction() to use this data + void init_AlwaysInline(uint32_t clock, BitOrder bitOrder, SPIMode dataMode, bool skipRecv) __attribute__((__always_inline__)) + { + this->clockFreq = clock; + this->dataMode = dataMode; + this->bitOrder = bitOrder; + this->skipRecv = skipRecv; + } + + uint32_t clockFreq; + SPIMode dataMode; + BitOrder bitOrder; + bool skipRecv; + + friend class HardwareSPI; }; +const SPISettings DEFAULT_SPI_SETTINGS = SPISettings(); + class SPIClass { public: SPIClass(); @@ -148,79 +187,33 @@ class SPIClass { _spi.pin_ssel = (ssel); }; - virtual void begin(uint8_t _pin = CS_PIN_CONTROLLED_BY_USER); + virtual void begin(void); void end(void); /* 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. */ - virtual 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); - } + void beginTransaction(SPISettings settings); + virtual void endTransaction(void); /* Transfer functions: must be called after initialization of the SPI * instance with begin() or beginTransaction(). - * You can specify the CS pin to use. */ - virtual byte transfer(uint8_t pin, uint8_t _data, SPITransferMode _mode = SPI_LAST); - virtual uint16_t transfer16(uint8_t pin, uint16_t _data, SPITransferMode _mode = SPI_LAST); - virtual void transfer(uint8_t pin, void *_buf, size_t _count, SPITransferMode _mode = SPI_LAST); - virtual void transfer(byte _pin, void *_bufout, void *_bufin, 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); - } - - void transfer(void *_bufout, void *_bufin, size_t _count, SPITransferMode _mode = SPI_LAST) - { - transfer(CS_PIN_CONTROLLED_BY_USER, _bufout, _bufin, _count, _mode); - } + virtual uint8_t transfer(uint8_t _data); + virtual uint16_t transfer16(uint16_t _data); + virtual void transfer(void *buf, size_t count); /* These methods are deprecated and kept for compatibility. * Use SPISettings with SPI.beginTransaction() to configure SPI parameters. */ - void setBitOrder(uint8_t _pin, BitOrder); - void setBitOrder(BitOrder _order) - { - setBitOrder(CS_PIN_CONTROLLED_BY_USER, _order); - } - - void setDataMode(uint8_t _pin, uint8_t); - void setDataMode(uint8_t _mode) - { - setDataMode(CS_PIN_CONTROLLED_BY_USER, _mode); - } - - void setClockDivider(uint8_t _pin, uint8_t); - void setClockDivider(uint8_t _div) - { - setClockDivider(CS_PIN_CONTROLLED_BY_USER, _div); - } - - // Not implemented functions. Kept for backward compatibility. - void usingInterrupt(uint8_t interruptNumber); + void setBitOrder(BitOrder); + void setDataMode(uint8_t); + void setDataMode(SPIMode); + void setClockDivider(uint8_t); + + // Not implemented functions. Kept for compatibility. + void usingInterrupt(int interruptNumber); + void notUsingInterrupt(int interruptNumber); void attachInterrupt(void); void detachInterrupt(void); @@ -235,68 +228,8 @@ class SPIClass { spi_t _spi; private: - /* Contains various spiSettings for the same spi instance. Each spi spiSettings - is associated to a CS pin. */ - SPISettings spiSettings[NB_SPI_SETTINGS]; - - // Use to know which configuration is selected. - int16_t _CSPinConfig; - - 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) && (!digitalPinIsValid(_pin))) { - 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) && (!digitalPinIsValid(_pin))) { - 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].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].dMode = SPI_MODE_0; - } - } + /* Current SPISettings */ + SPISettings _spiSettings = DEFAULT_SPI_SETTINGS; }; extern SPIClass SPI; @@ -309,12 +242,11 @@ class SUBGHZSPIClass : public SPIClass { _spi.spi = SUBGHZSPI; } - void begin(uint8_t _pin = CS_PIN_CONTROLLED_BY_USER); - void beginTransaction(uint8_t pin, SPISettings settings); - 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); - void transfer(byte _pin, void *_bufout, void *_bufin, size_t _count, SPITransferMode _mode = SPI_LAST); + void begin(); + void beginTransaction(SPISettings settings); + byte transfer(uint8_t _data); + uint16_t transfer16(uint16_t _data); + void transfer(void *_buf, size_t _count); void enableDebugPins(uint32_t mosi = DEBUG_SUBGHZSPI_MOSI, uint32_t miso = DEBUG_SUBGHZSPI_MISO, uint32_t sclk = DEBUG_SUBGHZSPI_SCLK, uint32_t ssel = DEBUG_SUBGHZSPI_SS); using SPIClass::beginTransaction; diff --git a/libraries/SPI/src/utility/spi_com.c b/libraries/SPI/src/utility/spi_com.c index 2cc6c28907..bd582681bd 100644 --- a/libraries/SPI/src/utility/spi_com.c +++ b/libraries/SPI/src/utility/spi_com.c @@ -227,7 +227,7 @@ static uint32_t compute_disable_delay(spi_t *obj) * @param msb : set to 1 in msb first * @retval None */ -void spi_init(spi_t *obj, uint32_t speed, spi_mode_e mode, uint8_t msb) +void spi_init(spi_t *obj, uint32_t speed, SPIMode mode, uint8_t msb) { if (obj == NULL) { return; @@ -313,13 +313,13 @@ void spi_init(spi_t *obj, uint32_t speed, spi_mode_e mode, uint8_t msb) handle->Init.Direction = SPI_DIRECTION_2LINES; - if ((mode == SPI_MODE_0) || (mode == SPI_MODE_2)) { + if ((mode == SPI_MODE0) || (mode == SPI_MODE2)) { handle->Init.CLKPhase = SPI_PHASE_1EDGE; } else { handle->Init.CLKPhase = SPI_PHASE_2EDGE; } - if ((mode == SPI_MODE_0) || (mode == SPI_MODE_1)) { + if ((mode == SPI_MODE0) || (mode == SPI_MODE1)) { handle->Init.CLKPolarity = SPI_POLARITY_LOW; } else { handle->Init.CLKPolarity = SPI_POLARITY_HIGH; @@ -496,38 +496,25 @@ void spi_deinit(spi_t *obj) #endif } -/** - * @brief This function is implemented by user to send data over SPI interface - * @param obj : pointer to spi_t structure - * @param Data : data to be sent - * @param len : length in bytes of the data to be sent - * @param Timeout: Timeout duration in tick - * @retval status of the send operation (0) in case of error - */ -spi_status_e spi_send(spi_t *obj, uint8_t *Data, uint16_t len, uint32_t Timeout) -{ - return spi_transfer(obj, Data, Data, len, Timeout, 1 /* SPI_TRANSMITONLY */); -} - /** * @brief This function is implemented by user to send/receive data over * SPI interface * @param obj : pointer to spi_t structure - * @param tx_buffer : tx data to send before reception - * @param rx_buffer : data to receive + * @param buffer : tx data to send before reception * @param len : length in byte of the data to send and receive * @param Timeout: Timeout duration in tick * @param skipReceive: skip receiving data after transmit or not * @retval status of the send operation (0) in case of error */ -spi_status_e spi_transfer(spi_t *obj, uint8_t *tx_buffer, uint8_t *rx_buffer, - uint16_t len, uint32_t Timeout, bool skipReceive) +spi_status_e spi_transfer(spi_t *obj, uint8_t *buffer, uint16_t len, + uint32_t Timeout, bool skipReceive) { spi_status_e ret = SPI_OK; uint32_t tickstart, size = len; SPI_TypeDef *_SPI = obj->handle.Instance; + uint8_t *tx_buffer = buffer; - if ((obj == NULL) || (len == 0) || (Timeout == 0U)) { + if ((len == 0) || (Timeout == 0U)) { return Timeout > 0U ? SPI_ERROR : SPI_TIMEOUT; } tickstart = HAL_GetTick(); @@ -553,7 +540,7 @@ spi_status_e spi_transfer(spi_t *obj, uint8_t *tx_buffer, uint8_t *rx_buffer, #else while (!LL_SPI_IsActiveFlag_RXNE(_SPI)); #endif - *rx_buffer++ = LL_SPI_ReceiveData8(_SPI); + *buffer++ = LL_SPI_ReceiveData8(_SPI); } if ((Timeout != HAL_MAX_DELAY) && (HAL_GetTick() - tickstart >= Timeout)) { ret = SPI_TIMEOUT; diff --git a/libraries/SPI/src/utility/spi_com.h b/libraries/SPI/src/utility/spi_com.h index daba244b4c..7562c08118 100644 --- a/libraries/SPI/src/utility/spi_com.h +++ b/libraries/SPI/src/utility/spi_com.h @@ -85,12 +85,13 @@ typedef struct spi_s spi_t; //SPI_MODE2 1 0 //SPI_MODE3 1 1 //enum definitions coming from SPI.h of SAM +// SPI mode parameters for SPISettings typedef enum { - SPI_MODE_0 = 0x00, - SPI_MODE_1 = 0x01, - SPI_MODE_2 = 0x02, - SPI_MODE_3 = 0x03 -} spi_mode_e; + SPI_MODE0 = 0, + SPI_MODE1 = 1, + SPI_MODE2 = 2, + SPI_MODE3 = 3, +} SPIMode; ///@brief SPI errors typedef enum { @@ -100,11 +101,10 @@ typedef enum { } spi_status_e; /* Exported functions ------------------------------------------------------- */ -void spi_init(spi_t *obj, uint32_t speed, spi_mode_e mode, uint8_t msb); +void spi_init(spi_t *obj, uint32_t speed, SPIMode mode, uint8_t msb); void spi_deinit(spi_t *obj); -spi_status_e spi_send(spi_t *obj, uint8_t *Data, uint16_t len, uint32_t Timeout); -spi_status_e spi_transfer(spi_t *obj, uint8_t *tx_buffer, - uint8_t *rx_buffer, uint16_t len, uint32_t Timeout, bool skipReceive); +spi_status_e spi_transfer(spi_t *obj, uint8_t *buffer, uint16_t len, + uint32_t Timeout, bool skipReceive); uint32_t spi_getClkFreq(spi_t *obj); #ifdef __cplusplus