From 6a220b39770d9c2556ffa2a1bff7f5ccc28868e0 Mon Sep 17 00:00:00 2001 From: Peter Lawrence <12226419+majbthrd@users.noreply.github.com> Date: Sun, 14 Aug 2022 12:32:58 -0500 Subject: [PATCH] feat: add the STM32WL SUBGHZSPI to the SPI library Signed-off-by: Peter Lawrence <12226419+majbthrd@users.noreply.github.com> Co-authored-by: Frederic Pillon --- libraries/SPI/src/SPI.cpp | 78 +++++++++++++++++++++ libraries/SPI/src/SPI.h | 50 +++++++++++--- libraries/SPI/src/utility/spi_com.c | 102 +++++++++++++++++++--------- 3 files changed, 187 insertions(+), 43 deletions(-) diff --git a/libraries/SPI/src/SPI.cpp b/libraries/SPI/src/SPI.cpp index 0d836a0295..a93b65a4ea 100644 --- a/libraries/SPI/src/SPI.cpp +++ b/libraries/SPI/src/SPI.cpp @@ -421,3 +421,81 @@ void SPIClass::detachInterrupt(void) { // Should be disableInterrupt() } + +#if defined(SUBGHZSPI_BASE) +SUBGHZSPIClass SubGHZ_SPI; + +void SUBGHZSPIClass::begin(uint8_t _pin) +{ + if (_pin != CS_PIN_CONTROLLED_BY_USER) { + LL_PWR_UnselectSUBGHZSPI_NSS(); + } + SPIClass::begin(CS_PIN_CONTROLLED_BY_USER); +} + +void SUBGHZSPIClass::beginTransaction(uint8_t _pin, SPISettings settings) +{ + if (_pin != CS_PIN_CONTROLLED_BY_USER) { + LL_PWR_UnselectSUBGHZSPI_NSS(); + } + SPIClass::beginTransaction(CS_PIN_CONTROLLED_BY_USER, settings); +} + +byte SUBGHZSPIClass::transfer(uint8_t _pin, uint8_t _data, SPITransferMode _mode) +{ + 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(); + } + return res; +} + +uint16_t SUBGHZSPIClass::transfer16(uint8_t _pin, uint16_t _data, SPITransferMode _mode) +{ + 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(); + } + return rx_buffer; +} + +void SUBGHZSPIClass::transfer(uint8_t _pin, void *_buf, size_t _count, SPITransferMode _mode) +{ + 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(); + } +} + +void SUBGHZSPIClass::enableDebugPins(void) +{ + spi_t *obj = getSpiObj(); + /* Configure SPI GPIO pins */ + pinmap_pinout(obj->pin_mosi, PinMap_SPI_MOSI); + pinmap_pinout(obj->pin_miso, PinMap_SPI_MISO); + pinmap_pinout(obj->pin_sclk, PinMap_SPI_SCLK); + pinmap_pinout(obj->pin_ssel, PinMap_SPI_SSEL); +} +#endif diff --git a/libraries/SPI/src/SPI.h b/libraries/SPI/src/SPI.h index 72f6d59fda..c9c446e73c 100644 --- a/libraries/SPI/src/SPI.h +++ b/libraries/SPI/src/SPI.h @@ -151,7 +151,7 @@ class SPIClass { _spi.pin_ssel = (ssel); }; - void begin(uint8_t _pin = CS_PIN_CONTROLLED_BY_USER); + virtual void begin(uint8_t _pin = CS_PIN_CONTROLLED_BY_USER); void end(void); /* This function should be used to configure the SPI instance in case you @@ -159,7 +159,7 @@ class SPIClass { * 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); + virtual void beginTransaction(uint8_t pin, SPISettings settings); void beginTransaction(SPISettings settings) { beginTransaction(CS_PIN_CONTROLLED_BY_USER, settings); @@ -175,10 +175,10 @@ class SPIClass { * 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); - void transfer(byte _pin, void *_bufout, void *_bufin, size_t _count, SPITransferMode _mode = SPI_LAST); + 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) @@ -227,12 +227,22 @@ class SPIClass { void attachInterrupt(void); void detachInterrupt(void); + spi_t *getSpiObj(void) + { + return &_spi; + } + + // Could be used to mix Arduino API and STM32Cube HAL API (ex: DMA). Use at your own risk. SPI_HandleTypeDef *getHandle(void) { return &(_spi.handle); } + protected: + // spi instance + spi_t _spi; + private: /* Contains various spiSettings for the same spi instance. Each spi spiSettings is associated to a CS pin. */ @@ -241,10 +251,6 @@ class SPIClass { // Use to know which configuration is selected. int16_t _CSPinConfig; - // spi instance - spi_t _spi; - - typedef enum { GET_IDX = 0, ADD_NEW_PIN = 1 @@ -304,4 +310,28 @@ class SPIClass { extern SPIClass SPI; +#if defined(SUBGHZSPI_BASE) +class SUBGHZSPIClass : public SPIClass { + public: + SUBGHZSPIClass(): SPIClass{DEBUG_SUBGHZSPI_MOSI, DEBUG_SUBGHZSPI_MISO, DEBUG_SUBGHZSPI_SCLK, DEBUG_SUBGHZSPI_SS} + { + _spi.spi = SUBGHZSPI; + } + SUBGHZSPIClass(uint32_t mosi, uint32_t miso, uint32_t sclk, uint32_t ssel): SPIClass{mosi, miso, sclk, ssel} + { + _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 enableDebugPins(void); +}; + +extern SUBGHZSPIClass SubGHZ_SPI; #endif + +#endif /* _SPI_H_INCLUDED */ diff --git a/libraries/SPI/src/utility/spi_com.c b/libraries/SPI/src/utility/spi_com.c index 32d46261dc..7492e92f2a 100644 --- a/libraries/SPI/src/utility/spi_com.c +++ b/libraries/SPI/src/utility/spi_com.c @@ -159,6 +159,12 @@ uint32_t spi_getClkFreqInst(SPI_TypeDef *spi_inst) } } #endif // SPI6_BASE +#if defined(SUBGHZSPI_BASE) + if (spi_inst == SUBGHZSPI) { + /* Source CLK is APB3 (PCLK3) is derived from AHB3 clock */ + spi_freq = HAL_RCC_GetHCLK3Freq(); + } +#endif // SUBGHZSPI_BASE #endif } return spi_freq; @@ -224,41 +230,50 @@ void spi_init(spi_t *obj, uint32_t speed, spi_mode_e mode, uint8_t msb) uint32_t spi_freq = 0; uint32_t pull = 0; - // Determine the SPI to use - SPI_TypeDef *spi_mosi = pinmap_peripheral(obj->pin_mosi, PinMap_SPI_MOSI); - SPI_TypeDef *spi_miso = pinmap_peripheral(obj->pin_miso, PinMap_SPI_MISO); - SPI_TypeDef *spi_sclk = pinmap_peripheral(obj->pin_sclk, PinMap_SPI_SCLK); - SPI_TypeDef *spi_ssel = pinmap_peripheral(obj->pin_ssel, PinMap_SPI_SSEL); +#if defined(SUBGHZSPI_BASE) + if (handle->Instance != SUBGHZSPI) { +#endif + // Determine the SPI to use + SPI_TypeDef *spi_mosi = pinmap_peripheral(obj->pin_mosi, PinMap_SPI_MOSI); + SPI_TypeDef *spi_miso = pinmap_peripheral(obj->pin_miso, PinMap_SPI_MISO); + SPI_TypeDef *spi_sclk = pinmap_peripheral(obj->pin_sclk, PinMap_SPI_SCLK); + SPI_TypeDef *spi_ssel = pinmap_peripheral(obj->pin_ssel, PinMap_SPI_SSEL); - /* Pins MOSI/MISO/SCLK must not be NP. ssel can be NP. */ - if (spi_mosi == NP || spi_miso == NP || spi_sclk == NP) { - core_debug("ERROR: at least one SPI pin has no peripheral\n"); - return; - } + /* Pins MOSI/MISO/SCLK must not be NP. ssel can be NP. */ + if (spi_mosi == NP || spi_miso == NP || spi_sclk == NP) { + core_debug("ERROR: at least one SPI pin has no peripheral\n"); + return; + } - SPI_TypeDef *spi_data = pinmap_merge_peripheral(spi_mosi, spi_miso); - SPI_TypeDef *spi_cntl = pinmap_merge_peripheral(spi_sclk, spi_ssel); + SPI_TypeDef *spi_data = pinmap_merge_peripheral(spi_mosi, spi_miso); + SPI_TypeDef *spi_cntl = pinmap_merge_peripheral(spi_sclk, spi_ssel); - obj->spi = pinmap_merge_peripheral(spi_data, spi_cntl); + obj->spi = pinmap_merge_peripheral(spi_data, spi_cntl); - // Are all pins connected to the same SPI instance? - if (spi_data == NP || spi_cntl == NP || obj->spi == NP) { - core_debug("ERROR: SPI pins mismatch\n"); - return; - } + // Are all pins connected to the same SPI instance? + if (spi_data == NP || spi_cntl == NP || obj->spi == NP) { + core_debug("ERROR: SPI pins mismatch\n"); + return; + } - // Configure the SPI pins - if (obj->pin_ssel != NC) { - handle->Init.NSS = SPI_NSS_HARD_OUTPUT; + // Configure the SPI pins + if (obj->pin_ssel != NC) { + handle->Init.NSS = SPI_NSS_HARD_OUTPUT; + } else { + handle->Init.NSS = SPI_NSS_SOFT; + } +#if defined(SUBGHZSPI_BASE) } else { handle->Init.NSS = SPI_NSS_SOFT; } +#endif /* Fill default value */ handle->Instance = obj->spi; handle->Init.Mode = SPI_MODE_MASTER; spi_freq = spi_getClkFreqInst(obj->spi); + /* For SUBGHZSPI, 'SPI_BAUDRATEPRESCALER_*' == 'SUBGHZSPI_BAUDRATEPRESCALER_*' */ if (speed >= (spi_freq / SPI_SPEED_CLOCK_DIV2_MHZ)) { handle->Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2; } else if (speed >= (spi_freq / SPI_SPEED_CLOCK_DIV4_MHZ)) { @@ -318,18 +333,23 @@ void spi_init(spi_t *obj, uint32_t speed, spi_mode_e mode, uint8_t msb) handle->Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_ENABLE; /* Recommended setting to avoid glitches */ #endif - /* Configure SPI GPIO pins */ - pinmap_pinout(obj->pin_mosi, PinMap_SPI_MOSI); - pinmap_pinout(obj->pin_miso, PinMap_SPI_MISO); - pinmap_pinout(obj->pin_sclk, PinMap_SPI_SCLK); - /* - * According the STM32 Datasheet for SPI peripheral we need to PULLDOWN - * or PULLUP the SCK pin according the polarity used. - */ - pull = (handle->Init.CLKPolarity == SPI_POLARITY_LOW) ? GPIO_PULLDOWN : GPIO_PULLUP; - pin_PullConfig(get_GPIO_Port(STM_PORT(obj->pin_sclk)), STM_LL_GPIO_PIN(obj->pin_sclk), pull); - pinmap_pinout(obj->pin_ssel, PinMap_SPI_SSEL); - +#if defined(SUBGHZSPI_BASE) + if (handle->Instance != SUBGHZSPI) { +#endif + /* Configure SPI GPIO pins */ + pinmap_pinout(obj->pin_mosi, PinMap_SPI_MOSI); + pinmap_pinout(obj->pin_miso, PinMap_SPI_MISO); + pinmap_pinout(obj->pin_sclk, PinMap_SPI_SCLK); + /* + * According the STM32 Datasheet for SPI peripheral we need to PULLDOWN + * or PULLUP the SCK pin according the polarity used. + */ + pull = (handle->Init.CLKPolarity == SPI_POLARITY_LOW) ? GPIO_PULLDOWN : GPIO_PULLUP; + pin_PullConfig(get_GPIO_Port(STM_PORT(obj->pin_sclk)), STM_LL_GPIO_PIN(obj->pin_sclk), pull); + pinmap_pinout(obj->pin_ssel, PinMap_SPI_SSEL); +#if defined(SUBGHZSPI_BASE) + } +#endif #if defined SPI1_BASE // Enable SPI clock if (handle->Instance == SPI1) { @@ -379,6 +399,14 @@ void spi_init(spi_t *obj, uint32_t speed, spi_mode_e mode, uint8_t msb) } #endif +#if defined SUBGHZSPI_BASE + if (handle->Instance == SUBGHZSPI) { + __HAL_RCC_SUBGHZSPI_CLK_ENABLE(); + __HAL_RCC_SUBGHZSPI_FORCE_RESET(); + __HAL_RCC_SUBGHZSPI_RELEASE_RESET(); + } +#endif + HAL_SPI_Init(handle); /* In order to set correctly the SPI polarity we need to enable the peripheral */ @@ -448,6 +476,14 @@ void spi_deinit(spi_t *obj) __HAL_RCC_SPI6_CLK_DISABLE(); } #endif + +#if defined SUBGHZSPI_BASE + if (handle->Instance == SUBGHZSPI) { + __HAL_RCC_SUBGHZSPI_FORCE_RESET(); + __HAL_RCC_SUBGHZSPI_RELEASE_RESET(); + __HAL_RCC_SUBGHZSPI_CLK_DISABLE(); + } +#endif } /**