From 8656ba72a6dccc77eed44f3128e8b2f109f3f221 Mon Sep 17 00:00:00 2001 From: Jose Roberto Colombo Junior Date: Tue, 16 Aug 2022 10:22:26 -0300 Subject: [PATCH] Added initial support to STM32 (using CubeHAL API). --- RF24.cpp | 46 ++++++++++++++- RF24.h | 35 ++++++++++- RF24_config.h | 9 +++ utility/STM32/RF24_arch_config.h | 99 ++++++++++++++++++++++++++++++++ utility/STM32/rf24_stm32.cpp | 47 +++++++++++++++ 5 files changed, 233 insertions(+), 3 deletions(-) create mode 100644 utility/STM32/RF24_arch_config.h create mode 100644 utility/STM32/rf24_stm32.cpp diff --git a/RF24.cpp b/RF24.cpp index 5c7fc2b11..698c720a6 100644 --- a/RF24.cpp +++ b/RF24.cpp @@ -91,7 +91,11 @@ void RF24::csn(bool mode) #endif // defined(RF24_RPi) #if !defined(RF24_LINUX) +#if defined(STM32) + HAL_GPIO_WritePin(csn_port, csn_pin, mode ? GPIO_PIN_SET : GPIO_PIN_RESET); +#else digitalWrite(csn_pin, mode); +#endif delayMicroseconds(csDelay); #else static_cast(mode); // ignore -Wunused-parameter @@ -104,7 +108,11 @@ void RF24::ce(bool level) { //Allow for 3-pin use on ATTiny if (ce_pin != csn_pin) { + #if defined(STM32) + HAL_GPIO_WritePin(ce_port, ce_pin, level ? GPIO_PIN_SET : GPIO_PIN_RESET); + #else digitalWrite(ce_pin, level); + #endif } } @@ -593,7 +601,7 @@ void RF24::_init_obj() { // Use a pointer on the Arduino platform -#if defined(RF24_SPI_PTR) && !defined(RF24_RP2) +#if defined(RF24_SPI_PTR) && !defined(RF24_RP2) && !defined(STM32) _spi = &SPI; #endif // defined (RF24_SPI_PTR) @@ -945,7 +953,7 @@ void RF24::encodeRadioDetails(uint8_t* encoded_details) #endif // !defined(MINIMAL) /****************************************************************************/ -#if defined(RF24_SPI_PTR) || defined(DOXYGEN_FORCED) +#if (defined(RF24_SPI_PTR) || defined(DOXYGEN_FORCED)) && !defined(STM32) // does not apply to RF24_LINUX bool RF24::begin(_SPI* spiBus) @@ -967,6 +975,20 @@ bool RF24::begin(_SPI* spiBus, uint16_t _cepin, uint16_t _cspin) /****************************************************************************/ +#if defined(STM32) +bool RF24::begin(SPI_HandleTypeDef * spiBus, uint16_t _cepin, GPIO_TypeDef* _ceport, uint16_t _cspin, GPIO_TypeDef* _csport) +{ + ce_pin = _cepin; + ce_port = _ceport; + csn_pin = _cspin; + csn_port = _csport; + _spi = new DummySpi(spiBus); + return begin(); +} +#endif + +/****************************************************************************/ + bool RF24::begin(uint16_t _cepin, uint16_t _cspin) { ce_pin = _cepin; @@ -1001,6 +1023,11 @@ bool RF24::begin(void) #elif defined(RF24_RP2) _spi->begin(PICO_DEFAULT_SPI ? spi1 : spi0); +#elif defined(STM32) + // you should configure the spi handler outside because your microcontroller may have more than one spi bus + _spi->begin(); + spi_speed = _spi->get_baud(); + #else // using an Arduino platform || defined (LITTLEWIRE) #if defined(RF24_SPI_PTR) @@ -1046,6 +1073,21 @@ bool RF24::_init_pins() csn(HIGH); delay(200); +#elif defined(STM32) + if (ce_pin != csn_pin) { + GPIO_InitTypeDef gpio; + gpio.Speed = GPIO_SPEED_FREQ_HIGH; + gpio.Mode = GPIO_MODE_OUTPUT_PP; + gpio.Pull = GPIO_NOPULL; + gpio.Pin = ce_pin; + HAL_GPIO_Init(ce_port, &gpio); + gpio.Pin = csn_pin; + HAL_GPIO_Init(csn_port, &gpio); + } + + ce(LOW); + csn(HIGH); + #else // using an Arduino platform // Initialize pins diff --git a/RF24.h b/RF24.h index b34164857..ce76546ef 100644 --- a/RF24.h +++ b/RF24.h @@ -133,6 +133,12 @@ class RF24 uint16_t ce_pin; /* "Chip Enable" pin, activates the RX or TX role */ uint16_t csn_pin; /* SPI Chip select */ + +#if defined(STM32) + GPIO_TypeDef* ce_port; + GPIO_TypeDef* csn_port; +#endif + uint32_t spi_speed; /* SPI Bus Speed */ #if defined(RF24_LINUX) || defined(XMEGA_D3) || defined(RF24_RP2) uint8_t spi_rxbuff[32 + 1]; //SPI receive buffer (payload max 32 bytes) @@ -242,7 +248,7 @@ class RF24 */ bool begin(void); -#if defined(RF24_SPI_PTR) || defined(DOXYGEN_FORCED) +#if (defined(RF24_SPI_PTR) || defined(DOXYGEN_FORCED)) && !defined(STM32) /** * Same as begin(), but allows specifying a non-default SPI bus to use. * @@ -284,6 +290,33 @@ class RF24 bool begin(_SPI* spiBus, uint16_t _cepin, uint16_t _cspin); #endif // defined (RF24_SPI_PTR) || defined (DOXYGEN_FORCED) +#if defined(STM32) + /** + * Same as begin(), but allows dynamically specifying a SPI bus, CE pin, + * and CSN pin to use. + * + * @note This function assumes the `SPI::begin()` method was called before to + * calling this function. + * + * @warning This function is for the Arduino platforms only + * + * @param spiBus A pointer or reference to an instantiated SPI bus object. + * The `_SPI` datatype is a "wrapped" definition that will represent + * various SPI implementations based on the specified platform. + * @param _cepin The pin attached to Chip Enable on the RF module. + * @param _ceport The handle object associated with the pin attached to Chip Enable on the RF module. + * @param _cspin The pin attached to Chip Select (often labeled CSN) on the radio module. + * @param _csport The handle object associated with the pin attached to Chip Select (often labeled CSN) on the radio module. + * - For the Arduino Due board, the [Arduino Due extended SPI feature](https://www.arduino.cc/en/Reference/DueExtendedSPI) + * is not supported. This means that the Due's pins 4, 10, or 52 are not mandated options (can use any digital output pin) for the radio's CSN pin. + * + * @see Review the [Arduino support page](md_docs_arduino.html). + * + * @return same result as begin() + */ + bool begin(SPI_HandleTypeDef * spiBus, uint16_t _cepin, GPIO_TypeDef* _ceport, uint16_t _cspin, GPIO_TypeDef* _csport); +#endif + /** * Same as begin(), but allows dynamically specifying a CE pin * and CSN pin to use. diff --git a/RF24_config.h b/RF24_config.h index e5e8d0d92..bf532f158 100644 --- a/RF24_config.h +++ b/RF24_config.h @@ -56,6 +56,15 @@ #include "utility/rp2/RF24_arch_config.h" #define sprintf_P sprintf +#elif (defined(STM32)) +#include "utility/stm32/RF24_arch_config.h" + +#ifdef SERIAL_DEBUG +#define IF_SERIAL_DEBUG(x) ({ x; }) +#else +#define IF_SERIAL_DEBUG(x) +#endif // SERIAL_DEBUG + #elif (!defined(ARDUINO)) // Any non-arduino device is handled via configure/Makefile // The configure script detects device and copies the correct includes.h file to /utility/includes.h // This behavior can be overridden by calling configure with respective parameters diff --git a/utility/STM32/RF24_arch_config.h b/utility/STM32/RF24_arch_config.h new file mode 100644 index 000000000..34caee4ee --- /dev/null +++ b/utility/STM32/RF24_arch_config.h @@ -0,0 +1,99 @@ +#ifndef RF24_UTILITY_STM32_RF24_ARCH_CONFIG_H +#define RF24_UTILITY_STM32_RF24_ARCH_CONFIG_H + + +#include +#include + + +#if defined(STM32F0) +#include "stm32f0xx_hal.h" +#elif defined(STM32F1) +#include "stm32f1xx_hal.h" +#include "stm32f1xx_hal_gpio.h" +#include "stm32f1xx_hal_spi.h" +#elif defined(STM32F4) +#include "stm32f4xx_hal.h" +#include "stm32f4xx_hal_gpio.h" +#elif defined(STM32L0) +#include "stm32l0xx_hal.h" +#elif defined(STM32L1) +#include "stm32l1xx_hal.h" +#elif defined(STM32L4) +#include "stm32l4xx_hal.h" +#elif defined(STM32F3) +#include "stm32f3xx_hal.h" +#elif defined(STM32H7) +#include "stm32h7xx_hal.h" +#elif defined(STM32F7) +#include "stm32f7xx_hal.h" +#elif defined(STM32G0) +#include "stm32g0xx_hal.h" +#elif defined(STM32G4) +#include "stm32g4xx_hal.h" +#endif + + +#if !defined(PROGMEM) +#define PROGMEM +#endif + +#if !defined(HIGH) +#define HIGH true +#endif + +#if !defined(LOW) +#define LOW false +#endif + +#if !defined(millis) +#define millis HAL_GetTick +#endif + +#if !defined(delayMicroseconds) +void delayMicroseconds(uint32_t usecs); +#endif + +#if !defined(delay) +#define delay(msecs) delayMicroseconds(1000*msecs) +#endif + +#if !defined(_BV) +#define _BV(bit) (1<<(bit)) +#endif + +#if !defined(PSTR) +#define PSTR(x) (x) +#endif + +#if !defined(printf_P) +#define printf_P printf +#endif + +#if !defined(pgm_read_word) +#define pgm_read_word(p) (*(p)) +#endif + +#if !defined(pgm_read_byte) +#define pgm_read_byte(p) (*(p)) +#endif + +#if !defined(pgm_read_ptr) +#define pgm_read_ptr(p) (*(p)) +#endif + +class DummySpi { +public: + DummySpi(SPI_HandleTypeDef* hspi); + void begin(); + uint8_t transfer(uint8_t data_to_send); + uint32_t get_baud(); +private: + SPI_HandleTypeDef* _hspi; +}; + +#define RF24_SPI_PTR +#define _SPI DummySpi + + +#endif //RF24_UTILITY_STM32_RF24_ARCH_CONFIG_H diff --git a/utility/STM32/rf24_stm32.cpp b/utility/STM32/rf24_stm32.cpp new file mode 100644 index 000000000..0b031e7f8 --- /dev/null +++ b/utility/STM32/rf24_stm32.cpp @@ -0,0 +1,47 @@ +#include "RF24_arch_config.h" + + +static uint32_t rf24_get_time_us() +{ + return 1000 * HAL_GetTick() + 1000 - (SysTick->VAL / (SystemCoreClock / 1000000)); +} + + +void delayMicroseconds(uint32_t usecs) +{ + uint32_t now = rf24_get_time_us(); + uint32_t blocked_until = now + usecs; + while (blocked_until > rf24_get_time_us()) {} +} + + +DummySpi::DummySpi(SPI_HandleTypeDef *hspi) { + _hspi = hspi; +} + + +void DummySpi::begin() { + HAL_SPI_Init(_hspi); +} + + +uint8_t DummySpi::transfer(uint8_t data_to_send) { + const uint16_t size = 1; + uint8_t rx_data; + HAL_SPI_TransmitReceive(_hspi, &data_to_send, &rx_data, size, HAL_MAX_DELAY); + return rx_data; +} + +uint32_t DummySpi::get_baud() { + // This method was tested with stm32f103c8t6. It may be different on other architectures + const uint8_t actual_config = _hspi->Init.BaudRatePrescaler; + uint16_t preescaler = 2; + if ((actual_config & SPI_CR1_BR_0) > 0) + preescaler = 2 * preescaler; + if ((actual_config & SPI_CR1_BR_1) > 0) + preescaler = 4 * preescaler; + if ((actual_config & SPI_CR1_BR_2) > 0) + preescaler = 16 * preescaler; + uint32_t baud = SystemCoreClock / preescaler; + return baud; +}