diff --git a/libraries/SPI/examples/SPIMaster/SPIMaster.ino b/libraries/SPI/examples/SPIMaster/SPIMaster.ino new file mode 100644 index 0000000000..e42552156e --- /dev/null +++ b/libraries/SPI/examples/SPIMaster/SPIMaster.ino @@ -0,0 +1,205 @@ +/* + SPI Master + + This example implements a SPI Master device for the SPI Slave example. + The data is transmitted to the SPI Slave and its response received back. + + Every 1000ms the LED state toggles and the latest received data is printed + to the Serial port + + The circuit: + * A LED to show a heartbeat signal + * CS - to digital pin PA4 (SS pin) + * SCK - to digital pin PA5 (SCK pin) + * MISO - to digital pin PA6 (MISO pin) + * MOSI - to digital pin PA7 (MOSI pin) + + Default SPI pin definitions can be found at variants/STM32XXxx//variant_generic.h + + created 29 Dec 2021 + by brainelectronics +*/ + +#include + +// PC13 on the Bluepill board +#define DEBUG_LED PC13 + +// comment this line to disable debug output on Serial +#define DEBUG_OUTPUT + +// amount of data to be sent to the SPI Slave device +#define BUFFER_SIZE 8 + +uint8_t TX_Buffer[BUFFER_SIZE] = {0}; +uint8_t RX_Buffer[BUFFER_SIZE] = {0}; +uint8_t up_counter = 0; //< data to be transmitted + +uint32_t prevTime = 0; //< previous timestamp of printing received data +uint32_t interval = 1000; //< [ms] interval at which to print received data + +spi_t _spi; + +void setup() { + // put your setup code here, to run once: + pinMode(DEBUG_LED, OUTPUT); + + // setup serial communication at 115200 baud + Serial.begin(115200); + + // setup SPI interface + setup_spi(); +} + +void setup_spi() { + uint32_t clk = SPI_SPEED_CLOCK_DEFAULT; + + // communicating at full clock speed might not work + // check the documentation at system/Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_spi.c + clk = spi_getClkFreq(&_spi) / SPI_CLOCK_DIV16; + +#ifdef DEBUG_OUTPUT + Serial.printf("PCLK: %d Hz\n", HAL_RCC_GetPCLK2Freq()); + // e.g. 48.000.000 Hz if running on the internal oscillator + Serial.printf("SPI CLK: %d Hz\n", clk); + // becomes 3.000.000 Hz in case PCLK is 48MHz and SPI_CLOCK_DIV16 is used +#endif + + // set the default CS pin as an output + pinMode(PIN_SPI_SS, OUTPUT); + + _spi.pin_mosi = digitalPinToPinName(PIN_SPI_MOSI); + _spi.pin_miso = digitalPinToPinName(PIN_SPI_MISO); + _spi.pin_sclk = digitalPinToPinName(PIN_SPI_SCK); + _spi.pin_ssel = NC; // in send_and_receive_data function + + _spi.mode = SPI_MASTER; //< master mode + + _spi.handle.State = HAL_SPI_STATE_RESET; + + spi_init(&_spi, clk, SPI_MODE_0, MSBFIRST); + +#ifdef DEBUG_OUTPUT + Serial.printf("SPI State: %d\n", _spi.handle.State); + // should be in state "1": Peripheral Initialized and ready for use +#endif +} + +void loop() { + uint32_t now = millis(); + + if (now > (prevTime + interval)) + { + // save the last time the data has been printed + prevTime = now; + + // toggle the LED state + digitalWrite(DEBUG_LED, !digitalRead(DEBUG_LED)); + +#ifdef DEBUG_OUTPUT + Serial.printf("HAL_SPI_GetError: %d\n", HAL_SPI_GetError(&(_spi.handle))); + Serial.printf("SPI State: %d\n", _spi.handle.State); +#endif + + // increment counter. This value will be sent to the SPI slave device + up_counter++; + + // reset value to zero, just to be save + if (up_counter >= 255) { + up_counter = 0; + } + + // to only send data to the slave device use this function + // send_data_to_slave(up_counter); + + // to send data and read the slave device response use this function + send_and_receive_data(up_counter); + } +} + +void send_data_to_slave(uint8_t data) { + uint8_t tmp_data_rx = 0; + + // take the SS pin low to select the chip + digitalWrite(PIN_SPI_SS, LOW); + + // transfer the given data 8 times in a row to slave -> Slave BUFFER_SIZE = 8 + // [1, 1, 1, 1, 1, 1, 1, 1] + for (uint8_t i = 0; i < 8; i++) + { + spi_transfer(&_spi, + &data, + &tmp_data_rx, + sizeof(uint8_t), + SPI_TRANSFER_TIMEOUT, + SPI_TRANSMITONLY); + } + + // take the SS pin high to de-select the chip + digitalWrite(PIN_SPI_SS, HIGH); +} + +void send_and_receive_data(uint8_t data) { + uint8_t tmp_data_rx = 0; + uint8_t tmp_data_tx = 0; + + for (uint8_t i = 0; i < BUFFER_SIZE; i++) + { + TX_Buffer[i] = data + i; + } + // e.g. [1, 2, 3, 4, 5, 6, 7, 8] if data = 1 + + Serial.print("Send data to Slave: "); + for (uint8_t i = 0; i < BUFFER_SIZE; i++) + { + Serial.printf("%d, ", TX_Buffer[i]); + } + Serial.println(); + + // take the CS pin low to select the Slave device + digitalWrite(PIN_SPI_SS, LOW); + + for (uint8_t i = 0; i < BUFFER_SIZE; i++) + { + tmp_data_tx = TX_Buffer[i]; + spi_transfer(&_spi, + &tmp_data_tx, + &tmp_data_rx, + sizeof(uint8_t), + SPI_TRANSFER_TIMEOUT, + SPI_TRANSMITONLY); + } + + // Serial print on slave requires approx. 1 ms + // wait for that amount of time until dummy data is sent to the slave in + // order to provide a CLK signal for the response of the slave device +#ifdef DEBUG_OUTPUT + delay(2); +#else + delay(1); +#endif + + tmp_data_tx = 0x0; // dummy data + for (uint8_t i = 0; i < BUFFER_SIZE; i++) + { + spi_transfer(&_spi, + &tmp_data_tx, + &tmp_data_rx, + sizeof(uint8_t), + SPI_TRANSFER_TIMEOUT, + SPI_TRANSMITRECEIVE); + RX_Buffer[i] = tmp_data_rx; + } + + // take the SS pin high to de-select the slave device again + digitalWrite(PIN_SPI_SS, HIGH); + + Serial.print("Received data from Slave: "); + for (uint8_t i = 0; i < BUFFER_SIZE; i++) + { + Serial.printf("%d, ", RX_Buffer[i]); + RX_Buffer[i] = 0; // clear buffer entry + } + // e.g. [2, 3, 4, 5, 6, 7, 8, 9] if data = 1 + Serial.println(); +} diff --git a/libraries/SPI/examples/SPISlave/SPISlave.ino b/libraries/SPI/examples/SPISlave/SPISlave.ino new file mode 100644 index 0000000000..b09fc6965d --- /dev/null +++ b/libraries/SPI/examples/SPISlave/SPISlave.ino @@ -0,0 +1,167 @@ +/* + SPI Slave + + This example implements a SPI Slave device for the SPI Master example. + The data is received from the SPI Master, incremented by one and sent back. + + Every 1000ms the LED state toggles and the latest received data is printed + to the Serial port + + The circuit: + * A LED to show a heartbeat signal + * CS - to digital pin PA4 (SS pin) + * SCK - to digital pin PA5 (SCK pin) + * MISO - to digital pin PA6 (MISO pin) + * MOSI - to digital pin PA7 (MOSI pin) + + Default SPI pin definitions can be found at variants/STM32XXxx//variant_generic.h + + created 29 Dec 2021 + by brainelectronics +*/ + +#include + +// PC13 on the Bluepill board +#define DEBUG_LED PC13 + +// comment this line to disable debug output on Serial +#define DEBUG_OUTPUT + +// amount of data being sent by the SPI Master device +#define BUFFER_SIZE 8 + +uint8_t RX_Buffer[BUFFER_SIZE] = {0}; + +uint32_t prevTime = 0; //< previous timestamp of printing received data +uint32_t interval = 1000; //< [ms] interval at which to print received data + +volatile uint32_t tmpCounterRx = 0, tmpCounterTx = 0; + +spi_t _spi; + +void setup() { + // put your setup code here, to run once: + pinMode(DEBUG_LED, OUTPUT); + + // setup serial communication at 115200 baud + Serial.begin(115200); + + // wait for 1 second in order to let the Master be ready before the slave + delay(1000); + + // setup SPI interface + setup_spi(); +} + +void setup_spi() { + uint32_t clk = SPI_SPEED_CLOCK_DEFAULT; + + // communicating at full clock speed might not work + // check the documentation at system/Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_spi.c + clk = spi_getClkFreq(&_spi) / SPI_CLOCK_DIV16; + +#ifdef DEBUG_OUTPUT + Serial.printf("PCLK: %d Hz\n", HAL_RCC_GetPCLK2Freq()); + // e.g. 48.000.000 Hz if running on the internal oscillator + Serial.printf("SPI CLK: %d Hz\n", clk); + // becomes 3.000.000 Hz in case PCLK is 48MHz and SPI_CLOCK_DIV16 is used +#endif + + // set the default CS pin as an input + pinMode(PIN_SPI_SS, INPUT); + + _spi.pin_mosi = digitalPinToPinName(PIN_SPI_MOSI); + _spi.pin_miso = digitalPinToPinName(PIN_SPI_MISO); + _spi.pin_sclk = digitalPinToPinName(PIN_SPI_SCK); + _spi.pin_ssel = NC; // set later manually + + _spi.mode = SPI_SLAVE; //< slave mode + + _spi.handle.State = HAL_SPI_STATE_RESET; + + spi_init(&_spi, clk, SPI_MODE_0, MSBFIRST); + +#ifdef DEBUG_OUTPUT + Serial.printf("SPI State: %d\n", _spi.handle.State); + // should be in state "1": Peripheral Initialized and ready for use +#endif + + // attach an interrupt as last step to avoid calls before a full SPI setup + + // to receive only data from a Master, use the "receive_data" function + // attachInterrupt(PIN_SPI_SS, receive_data, FALLING); + + // to receive data and transmit a response back to the Master use this + attachInterrupt(PIN_SPI_SS, receive_and_respond_data, FALLING); +} + +void loop() { + uint32_t now = millis(); + + if (now > (prevTime + interval)) + { + // save the last time the data has been printed + prevTime = now; + + // toggle the LED state + digitalWrite(DEBUG_LED, !digitalRead(DEBUG_LED)); + +#ifdef DEBUG_OUTPUT + Serial.printf("HAL_SPI_GetError: %d\n", HAL_SPI_GetError(&(_spi.handle))); + Serial.printf("SPI State: %d\n", _spi.handle.State); + Serial.printf("RX Counter: %d\n", tmpCounterRx); + Serial.printf("TX Counter: %d\n", tmpCounterTx); +#endif + + // print the data in the received buffer in DEC format + for (uint8_t i = 0; i < BUFFER_SIZE; i++) + { + Serial.printf("%d, ", RX_Buffer[i]); + RX_Buffer[i] = 0; // clear buffer entry + } + Serial.println(); + } +} + +void receive_data() +{ + // put received data from SPI into the RX_Buffer + // return from function if no data is received within 10 ticks (10 ms) + HAL_SPI_Receive(&(_spi.handle), RX_Buffer, sizeof(RX_Buffer), 10); + tmpCounterRx++; + + // this is for demo purpose only, try to keep IRQ functions short and quick +#ifdef DEBUG_OUTPUT + // print received data directly after receiving it + for (uint8_t i = 0; i < BUFFER_SIZE; i++) + { + Serial.printf("%d, ", RX_Buffer[i]); + } + Serial.println(); +#endif +} + +void receive_and_respond_data() +{ + // put received data from SPI into the RX_Buffer + // return from function if no data is received within 10 ticks (10 ms) + HAL_SPI_Receive(&(_spi.handle), RX_Buffer, sizeof(RX_Buffer), 10); + tmpCounterRx++; + // e.g. [1, 2, 3, 4, 5, 6, 7, 8] + + // response data shall be available as soon as possible + // avoid long intermediate processing or other functions + uint8_t TX_Buffer[BUFFER_SIZE] = {0}; + for (uint8_t i = 0; i < BUFFER_SIZE; i++) + { + // create response message, which is the received data + 1 + TX_Buffer[i] = RX_Buffer[i] + 1; + } + // e.g. [2, 3, 4, 5, 6, 7, 8, 9] + + // send response as the data of the TX_Buffer to the SPI Master + // return from function within 10 ticks (10 ms) + HAL_SPI_Transmit(&(_spi.handle), TX_Buffer, sizeof(TX_Buffer), 10); + tmpCounterTx++; +} diff --git a/libraries/SPI/src/SPI.cpp b/libraries/SPI/src/SPI.cpp index 0d836a0295..0e7a47afd1 100644 --- a/libraries/SPI/src/SPI.cpp +++ b/libraries/SPI/src/SPI.cpp @@ -69,6 +69,7 @@ void SPIClass::begin(uint8_t _pin) digitalWrite(_pin, HIGH); } + _spi.mode = SPI_MASTER; _spi.handle.State = HAL_SPI_STATE_RESET; spi_init(&_spi, spiSettings[idx].clk, spiSettings[idx].dMode, diff --git a/libraries/SPI/src/utility/spi_com.c b/libraries/SPI/src/utility/spi_com.c index 32d46261dc..3eb371444f 100644 --- a/libraries/SPI/src/utility/spi_com.c +++ b/libraries/SPI/src/utility/spi_com.c @@ -256,7 +256,11 @@ void spi_init(spi_t *obj, uint32_t speed, spi_mode_e mode, uint8_t msb) /* Fill default value */ handle->Instance = obj->spi; - handle->Init.Mode = SPI_MODE_MASTER; + if (obj->mode == SPI_SLAVE) { + handle->Init.Mode = SPI_MODE_SLAVE; + } else { + handle->Init.Mode = SPI_MODE_MASTER; + } spi_freq = spi_getClkFreqInst(obj->spi); if (speed >= (spi_freq / SPI_SPEED_CLOCK_DIV2_MHZ)) { diff --git a/libraries/SPI/src/utility/spi_com.h b/libraries/SPI/src/utility/spi_com.h index daba244b4c..788565abdf 100644 --- a/libraries/SPI/src/utility/spi_com.h +++ b/libraries/SPI/src/utility/spi_com.h @@ -49,6 +49,12 @@ extern "C" { /* Exported types ------------------------------------------------------------*/ +///@brief SPI device modes +typedef enum { + SPI_SLAVE = 0, + SPI_MASTER = 1 +} spi_device_mode_e; + struct spi_s { SPI_HandleTypeDef handle; SPI_TypeDef *spi; @@ -56,6 +62,7 @@ struct spi_s { PinName pin_mosi; PinName pin_sclk; PinName pin_ssel; + spi_device_mode_e mode; #if defined(SPI_IFCR_EOTC) // Delay before disabling SPI. // See https://github.com/stm32duino/Arduino_Core_STM32/issues/1294 pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy