mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2025-01-17 05:12:57 +01:00
Merge pull request #16579 from akshaim/pr/wl55jc_lorawan_final
drivers/sx126x: Add support for Nucleo -WL55JC
This commit is contained in:
commit
934c875aba
@ -1,4 +1,10 @@
|
||||
ifneq (,$(filter stdio_uart,$(USEMODULE)))
|
||||
FEATURES_REQUIRED += periph_lpuart
|
||||
endif
|
||||
ifneq (,$(filter netdev_default,$(USEMODULE)))
|
||||
USEMODULE += sx126x_stm32wl
|
||||
endif
|
||||
ifneq (,$(filter sx126x_stm32wl,$(USEMODULE)))
|
||||
USEMODULE += sx126x_rf_switch
|
||||
endif
|
||||
include $(RIOTBOARD)/common/nucleo/Makefile.dep
|
||||
|
73
boards/nucleo-wl55jc/board.c
Normal file
73
boards/nucleo-wl55jc/board.c
Normal file
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Freie Universität Berlin
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
* directory for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ingroup boards_nucleo-wl55jc
|
||||
* @{
|
||||
*
|
||||
* @file board.c
|
||||
* @brief Board specific implementations for the Nucleo-wl55jc board
|
||||
*
|
||||
*
|
||||
* @author Akshai M <akshai.m@fu-berlin.de>
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "board.h"
|
||||
#include "periph/gpio.h"
|
||||
|
||||
void board_init(void)
|
||||
{
|
||||
/* initialize the CPU */
|
||||
board_common_nucleo_init();
|
||||
|
||||
if (IS_USED(MODULE_SX126X_STM32WL)) {
|
||||
/* Initialize the GPIO control for RF 3-port switch (SP3T) */
|
||||
gpio_init(FE_CTRL1, GPIO_OUT);
|
||||
gpio_init(FE_CTRL2, GPIO_OUT);
|
||||
gpio_init(FE_CTRL3, GPIO_OUT);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Callback to set RF switch mode
|
||||
*
|
||||
* This function sets the GPIO's wired to the SP3T RF Switch. Nucleo-WL55JC
|
||||
* supports three modes of operation.
|
||||
*/
|
||||
#if IS_USED(MODULE_SX126X_STM32WL)
|
||||
void nucleo_wl55jc_sx126x_set_rf_mode(sx126x_t *dev, sx126x_rf_mode_t rf_mode)
|
||||
{
|
||||
(void)dev;
|
||||
switch (rf_mode) {
|
||||
case SX126X_RF_MODE_RX:
|
||||
gpio_set(FE_CTRL1);
|
||||
gpio_clear(FE_CTRL2);
|
||||
gpio_set(FE_CTRL3);
|
||||
break;
|
||||
|
||||
case SX126X_RF_MODE_TX_LPA:
|
||||
gpio_set(FE_CTRL1);
|
||||
gpio_set(FE_CTRL2);
|
||||
gpio_set(FE_CTRL3);
|
||||
break;
|
||||
|
||||
case SX126X_RF_MODE_TX_HPA:
|
||||
gpio_clear(FE_CTRL1);
|
||||
gpio_set(FE_CTRL2);
|
||||
gpio_set(FE_CTRL3);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
@ -27,6 +27,7 @@
|
||||
| Programming Manual 2 | [Reference Manual - M0](https://www.st.com/resource/en/programming_manual/dm00104451-cortexm0-programming-manual-for-stm32l0-stm32g0-stm32wl-and-stm32wb-series-stmicroelectronics.pdf) |
|
||||
| Board Manual | [Board Manual](https://www.st.com/resource/en/data_brief/nucleo-wl55jc.pdf) |
|
||||
| Board Schematic | [Board Schematic](https://www.st.com/resource/en/user_manual/dm00622917-stm32wl-nucleo64-board-mb1389-stmicroelectronics.pdf) |
|
||||
| Additional Reference | [Developing LoRaWAN Application](https://www.st.com/resource/en/application_note/dm00660451-how-to-build-a-lora-application-with-stm32cubewl-stmicroelectronics.pdf)
|
||||
|
||||
## Flashing the device
|
||||
|
||||
|
@ -22,10 +22,27 @@
|
||||
|
||||
#include "board_nucleo.h"
|
||||
|
||||
/* Required for `nucleo_wl55jc_sx126x_set_rf_mode` */
|
||||
#if IS_USED(MODULE_SX126X_STM32WL)
|
||||
#include "sx126x.h"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @name Sub-GHz radio (LoRa) configuration
|
||||
* @{
|
||||
*/
|
||||
#define SX126X_PARAM_SPI (SPI_DEV(0))
|
||||
|
||||
#if IS_USED(MODULE_SX126X_STM32WL)
|
||||
extern void nucleo_wl55jc_sx126x_set_rf_mode(sx126x_t *dev, sx126x_rf_mode_t rf_mode);
|
||||
#define SX126X_PARAM_SET_RF_MODE_CB nucleo_wl55jc_sx126x_set_rf_mode
|
||||
#endif
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name LED pin definitions and handlers
|
||||
* @{
|
||||
@ -52,7 +69,10 @@ extern "C" {
|
||||
#define LED2_TOGGLE (LED0_PORT->ODR ^= LED2_MASK)
|
||||
/** @} */
|
||||
|
||||
/* nucleo-wl55jc always use LED0, as there is no dual use of its pin */
|
||||
/**
|
||||
* @brief Nucleo-wl55jc always use LED0, as there is no dual use of its pin
|
||||
* @{
|
||||
*/
|
||||
#ifndef AUTO_INIT_LED0
|
||||
#define AUTO_INIT_LED0
|
||||
#endif
|
||||
@ -70,6 +90,17 @@ extern "C" {
|
||||
#define BTN2_MODE GPIO_IN_PU
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name RF 3-port switch (SP3T) control
|
||||
*
|
||||
* Refer Section 6.6.3 RF Overview in User Manual (UM2592)
|
||||
* @{
|
||||
*/
|
||||
#define FE_CTRL1 GPIO_PIN(PORT_C, 4)
|
||||
#define FE_CTRL2 GPIO_PIN(PORT_C, 5)
|
||||
#define FE_CTRL3 GPIO_PIN(PORT_C, 3)
|
||||
/** @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -84,6 +84,21 @@ static const uart_conf_t uart_config[] = {
|
||||
*/
|
||||
static const spi_conf_t spi_config[] = {
|
||||
{
|
||||
.dev = SUBGHZSPI, /* Internally connected to Sub-GHz radio Modem */
|
||||
.mosi_pin = GPIO_UNDEF,
|
||||
.miso_pin = GPIO_UNDEF,
|
||||
.sclk_pin = GPIO_UNDEF,
|
||||
.cs_pin = GPIO_UNDEF,
|
||||
.mosi_af = GPIO_AF_UNDEF,
|
||||
.miso_af = GPIO_AF_UNDEF,
|
||||
.sclk_af = GPIO_AF_UNDEF,
|
||||
.cs_af = GPIO_AF_UNDEF,
|
||||
.rccmask = RCC_APB3ENR_SUBGHZSPIEN,
|
||||
.apbbus = APB3,
|
||||
}
|
||||
/* SUBGHZ DEBUG PINS use the SPI1 pins */
|
||||
#if !IS_ACTIVE(CONFIG_STM32_WL55JC_SUBGHZ_DEBUG)
|
||||
,{
|
||||
.dev = SPI1,
|
||||
.mosi_pin = GPIO_PIN(PORT_A, 7),
|
||||
.miso_pin = GPIO_PIN(PORT_A, 6),
|
||||
@ -96,6 +111,7 @@ static const spi_conf_t spi_config[] = {
|
||||
.rccmask = RCC_APB2ENR_SPI1EN,
|
||||
.apbbus = APB2,
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
#define SPI_NUMOF ARRAY_SIZE(spi_config)
|
||||
|
@ -14,3 +14,9 @@
|
||||
* sharing the same architecture, the implementation is split into several CPU
|
||||
* specific parts and an architecture part (e.g. arm7_common and lpc23xx).
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup config_cpu CPU Configurations
|
||||
* @ingroup config
|
||||
* @brief Compile time configurations for different kinds of CPU.
|
||||
*/
|
||||
|
@ -172,6 +172,11 @@ void periph_clk_dis(bus_t bus, uint32_t mask)
|
||||
#endif
|
||||
break;
|
||||
#endif
|
||||
#if defined(CPU_FAM_STM32WL)
|
||||
case APB3:
|
||||
RCC->APB3ENR &= ~(mask);
|
||||
break;
|
||||
#endif
|
||||
#if defined(CPU_FAM_STM32L4) || defined(CPU_FAM_STM32WB) || \
|
||||
defined(CPU_FAM_STM32G4) || defined(CPU_FAM_STM32L5) || \
|
||||
defined(CPU_FAM_STM32WL)
|
||||
|
@ -37,6 +37,7 @@
|
||||
#include "stmclk.h"
|
||||
#include "periph_cpu.h"
|
||||
#include "periph/init.h"
|
||||
#include "periph/gpio.h"
|
||||
#include "board.h"
|
||||
|
||||
#if defined (CPU_FAM_STM32L4) || defined (CPU_FAM_STM32G4) || \
|
||||
@ -151,6 +152,52 @@ static void _gpio_init_ain(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Initialize HW debug pins for Sub-GHz Radio
|
||||
*/
|
||||
void _wl55jc_init_subghz_debug_pins(void)
|
||||
{
|
||||
#if IS_ACTIVE(CONFIG_STM32_WL55JC_SUBGHZ_DEBUG)
|
||||
/* SUBGHZSPI Debug */
|
||||
gpio_init(CPU_STM32WL_SUBGHZSPI_DEBUG_MOSIOUT, GPIO_OUT);
|
||||
gpio_init_af(CPU_STM32WL_SUBGHZSPI_DEBUG_MOSIOUT,
|
||||
CPU_STM32WL_SUBGHZSPI_DEBUG_MOSIOUT_AF);
|
||||
|
||||
gpio_init(CPU_STM32WL_SUBGHZSPI_DEBUG_MISOOUT, GPIO_OUT);
|
||||
gpio_init_af(CPU_STM32WL_SUBGHZSPI_DEBUG_MISOOUT,
|
||||
CPU_STM32WL_SUBGHZSPI_DEBUG_MISOOUT_AF);
|
||||
|
||||
gpio_init(CPU_STM32WL_SUBGHZSPI_DEBUG_SCKOUT, GPIO_OUT);
|
||||
gpio_init_af(CPU_STM32WL_SUBGHZSPI_DEBUG_SCKOUT,
|
||||
CPU_STM32WL_SUBGHZSPI_DEBUG_SCKOUT_AF);
|
||||
|
||||
gpio_init(CPU_STM32WL_SUBGHZSPI_DEBUG_NSSOUT, GPIO_OUT);
|
||||
gpio_init_af(CPU_STM32WL_SUBGHZSPI_DEBUG_NSSOUT,
|
||||
CPU_STM32WL_SUBGHZSPI_DEBUG_NSSOUT_AF);
|
||||
|
||||
/* Sub-GHz Radio Debug */
|
||||
gpio_init(CPU_STM32WL_SUBGHZ_RF_BUSY, GPIO_OUT);
|
||||
gpio_init_af(CPU_STM32WL_SUBGHZ_RF_BUSY,
|
||||
CPU_STM32WL_SUBGHZ_RF_BUSY_AF);
|
||||
|
||||
gpio_init(CPU_STM32WL_SUBGHZ_DEBUG_RF_NRESET, GPIO_OUT);
|
||||
gpio_init_af(CPU_STM32WL_SUBGHZ_DEBUG_RF_NRESET,
|
||||
CPU_STM32WL_SUBGHZ_DEBUG_RF_NRESET_AF);
|
||||
|
||||
gpio_init(CPU_STM32WL_SUBGHZ_DEBUG_RF_SMPSRDY, GPIO_OUT);
|
||||
gpio_init_af(CPU_STM32WL_SUBGHZ_DEBUG_RF_SMPSRDY,
|
||||
CPU_STM32WL_SUBGHZ_DEBUG_RF_SMPSRDY_AF);
|
||||
|
||||
gpio_init(CPU_STM32WL_SUBGHZ_DEBUG_RF_LDORDY, GPIO_OUT);
|
||||
gpio_init_af(CPU_STM32WL_SUBGHZ_DEBUG_RF_LDORDY,
|
||||
CPU_STM32WL_SUBGHZ_DEBUG_RF_LDORDY_AF);
|
||||
|
||||
gpio_init(CPU_STM32WL_SUBGHZ_DEBUG_RF_HSE32RDY, GPIO_OUT);
|
||||
gpio_init_af(CPU_STM32WL_SUBGHZ_DEBUG_RF_HSE32RDY,
|
||||
CPU_STM32WL_SUBGHZ_DEBUG_RF_HSE32RDY_AF);
|
||||
#endif
|
||||
}
|
||||
|
||||
void cpu_init(void)
|
||||
{
|
||||
/* initialize the Cortex-M core */
|
||||
@ -184,4 +231,8 @@ void cpu_init(void)
|
||||
|
||||
/* trigger static peripheral initialization */
|
||||
periph_init();
|
||||
|
||||
if (IS_ACTIVE(CONFIG_STM32_WL55JC_SUBGHZ_DEBUG)) {
|
||||
_wl55jc_init_subghz_debug_pins();
|
||||
}
|
||||
}
|
||||
|
@ -34,6 +34,95 @@ extern "C" {
|
||||
|
||||
#endif /* ndef DOXYGEN */
|
||||
|
||||
/**
|
||||
* @defgroup cpu_stm32_wl_debug STM32WL hardware debugging
|
||||
* @ingroup cpu_stm32
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* @defgroup cpu_stm32_wl_debug_subghz_spi STM32WL Sub-GHz SPI debug pins
|
||||
* @ingroup cpu_stm32_wl_debug
|
||||
* @{
|
||||
*/
|
||||
#define CPU_STM32WL_SUBGHZSPI_DEBUG_MOSIOUT GPIO_PIN(PORT_A, 7)
|
||||
#define CPU_STM32WL_SUBGHZSPI_DEBUG_MOSIOUT_AF GPIO_AF13
|
||||
|
||||
#define CPU_STM32WL_SUBGHZSPI_DEBUG_MISOOUT GPIO_PIN(PORT_A, 6)
|
||||
#define CPU_STM32WL_SUBGHZSPI_DEBUG_MISOOUT_AF GPIO_AF13
|
||||
|
||||
#define CPU_STM32WL_SUBGHZSPI_DEBUG_SCKOUT GPIO_PIN(PORT_A, 5)
|
||||
#define CPU_STM32WL_SUBGHZSPI_DEBUG_SCKOUT_AF GPIO_AF13
|
||||
|
||||
#define CPU_STM32WL_SUBGHZSPI_DEBUG_NSSOUT GPIO_PIN(PORT_A, 4)
|
||||
#define CPU_STM32WL_SUBGHZSPI_DEBUG_NSSOUT_AF GPIO_AF13
|
||||
/** @} */
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @defgroup cpu_stm32_wl_debug_subghz_radio STM32WL Sub-GHz Radio debug pins
|
||||
* @ingroup cpu_stm32_wl_debug
|
||||
* @{
|
||||
*/
|
||||
/*!
|
||||
* RF BUSY debug pin definition
|
||||
*/
|
||||
#define CPU_STM32WL_SUBGHZ_RF_BUSY GPIO_PIN(PORT_A, 12)
|
||||
/*!
|
||||
* RF BUSY debug pin alternate function
|
||||
*/
|
||||
#define CPU_STM32WL_SUBGHZ_RF_BUSY_AF GPIO_AF6
|
||||
|
||||
/*!
|
||||
* RF NRESET debug pin definition
|
||||
*/
|
||||
#define CPU_STM32WL_SUBGHZ_DEBUG_RF_NRESET GPIO_PIN(PORT_A, 11)
|
||||
/*!
|
||||
* RF NRESET debug pin alternate function
|
||||
*/
|
||||
#define CPU_STM32WL_SUBGHZ_DEBUG_RF_NRESET_AF GPIO_AF13
|
||||
|
||||
/*!
|
||||
* RF SMPSRDY debug pin definition
|
||||
*/
|
||||
#define CPU_STM32WL_SUBGHZ_DEBUG_RF_SMPSRDY GPIO_PIN(PORT_B, 2)
|
||||
/*!
|
||||
* RF SMPSRDY debug pin alternate function
|
||||
*/
|
||||
#define CPU_STM32WL_SUBGHZ_DEBUG_RF_SMPSRDY_AF GPIO_AF13
|
||||
|
||||
/*!
|
||||
* RF LDORDY debug pin definition
|
||||
*/
|
||||
#define CPU_STM32WL_SUBGHZ_DEBUG_RF_LDORDY GPIO_PIN(PORT_B, 4)
|
||||
/*!
|
||||
* RF LDORDY debug pin alternate function
|
||||
*/
|
||||
#define CPU_STM32WL_SUBGHZ_DEBUG_RF_LDORDY_AF GPIO_AF13
|
||||
|
||||
/*!
|
||||
* RF HSE32RDY debug pin definition
|
||||
*/
|
||||
#define CPU_STM32WL_SUBGHZ_DEBUG_RF_HSE32RDY GPIO_PIN(PORT_A, 10)
|
||||
/*!
|
||||
* RF HSE32RDY debug pin alternate function
|
||||
*/
|
||||
#define CPU_STM32WL_SUBGHZ_DEBUG_RF_HSE32RDY_AF GPIO_AF13
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @defgroup cpu_stm32_wl_config STM32WL compile time configuration
|
||||
* @ingroup cpu_stm32_wl_debug
|
||||
* @ingroup config_cpu
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* @brief Set this to 1 to enable hardware debugging.
|
||||
*/
|
||||
#ifdef DOXYGEN
|
||||
#define CONFIG_STM32_WL55JC_SUBGHZ_DEBUG
|
||||
#endif
|
||||
/** @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -324,8 +324,10 @@ typedef enum {
|
||||
GPIO_AF12, /**< use alternate function 12 */
|
||||
GPIO_AF13, /**< use alternate function 13 */
|
||||
GPIO_AF14, /**< use alternate function 14 */
|
||||
GPIO_AF15 /**< use alternate function 15 */
|
||||
GPIO_AF15, /**< use alternate function 15 */
|
||||
#endif
|
||||
GPIO_AF_UNDEF /** an UNDEF value definition, e.g. for register
|
||||
based spi */
|
||||
#endif
|
||||
} gpio_af_t;
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
# Copyright (c) 2021 Inria
|
||||
# Copyright (c) 2021 Freie Universitaet Berlin
|
||||
#
|
||||
# This file is subject to the terms and conditions of the GNU Lesser
|
||||
# General Public License v2.1. See the file LICENSE in the top level
|
||||
@ -22,3 +23,11 @@ config HAS_CPU_STM32WL
|
||||
bool
|
||||
help
|
||||
Indicates that the cpu being used belongs to the 'stm32wl' family.
|
||||
|
||||
config STM32_WL55JC_SUBGHZ_DEBUG
|
||||
bool "STM32WL->Enable Hardware Debugging"
|
||||
help
|
||||
Enable Hardware debug pins. This would affect onboard peripherals such as SPI
|
||||
as the pins are multiplexed. For more information check Alternate Functions
|
||||
column in Table 19 : STM32WL55/54xx pin definition in STM32WL55/54xx
|
||||
datasheet.
|
||||
|
@ -487,17 +487,18 @@ void stmclk_init_sysclk(void)
|
||||
~100 kHz and the MSI clock to be based on MSISRANGE in RCC_CSR
|
||||
(instead of MSIRANGE in the RCC_CR) */
|
||||
RCC->CR = (RCC_CR_HSION);
|
||||
|
||||
/* Use VDDTCXO regulator, required by the radio and HSE */
|
||||
if (IS_ACTIVE(CLOCK_ENABLE_HSE) || IS_USED(MODULE_SX126X_STM32WL)) {
|
||||
#ifdef RCC_CR_HSEBYPPWR
|
||||
RCC->CR |= (RCC_CR_HSEBYPPWR);
|
||||
#endif
|
||||
}
|
||||
/* Enable the HSE clock only when it's provided by the board and required:
|
||||
- Use HSE as system clock
|
||||
- Use HSE as PLL input clock
|
||||
*/
|
||||
if (IS_ACTIVE(CLOCK_ENABLE_HSE)) {
|
||||
|
||||
/* Use VDDTCXO regulator */
|
||||
#if defined(CPU_FAM_STM32WL)
|
||||
RCC->CR |= (RCC_CR_HSEBYPPWR);
|
||||
#endif
|
||||
RCC->CR |= (RCC_CR_HSEON);
|
||||
while (!(RCC->CR & RCC_CR_HSERDY)) {}
|
||||
}
|
||||
|
@ -34,6 +34,20 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* * @note Forward declaration of the SX126x device descriptor
|
||||
*/
|
||||
typedef struct sx126x sx126x_t;
|
||||
|
||||
/**
|
||||
* @brief RF switch states
|
||||
*/
|
||||
typedef enum {
|
||||
SX126X_RF_MODE_RX,
|
||||
SX126X_RF_MODE_TX_LPA,
|
||||
SX126X_RF_MODE_TX_HPA,
|
||||
} sx126x_rf_mode_t;
|
||||
|
||||
/**
|
||||
* @brief Whether there's only one variant of this driver at compile time or
|
||||
* not.
|
||||
@ -43,8 +57,17 @@ extern "C" {
|
||||
+ IS_USED(MODULE_SX1262) \
|
||||
+ IS_USED(MODULE_SX1268) \
|
||||
+ IS_USED(MODULE_LLCC68) \
|
||||
+ IS_USED(MODULE_SX126X_STM32WL) \
|
||||
) == 1)
|
||||
|
||||
/**
|
||||
* @brief Used to identify if its a generic SPI module
|
||||
*/
|
||||
#if (IS_USED(MODULE_SX1261) || IS_USED(MODULE_SX1262) || \
|
||||
IS_USED(MODULE_SX1268) || IS_USED(MODULE_LLCC68))
|
||||
#define SX126X_SPI 1
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Variant of the SX126x driver.
|
||||
*/
|
||||
@ -53,6 +76,7 @@ typedef enum {
|
||||
SX126X_TYPE_SX1262,
|
||||
SX126X_TYPE_SX1268,
|
||||
SX126X_TYPE_LLCC68,
|
||||
SX126X_TYPE_STM32WL,
|
||||
} sx126x_type_t;
|
||||
|
||||
/**
|
||||
@ -66,19 +90,26 @@ typedef struct {
|
||||
gpio_t dio1_pin; /**< Dio1 pin */
|
||||
sx126x_reg_mod_t regulator; /**< Power regulator mode */
|
||||
sx126x_type_t type; /**< Variant of sx126x */
|
||||
#if IS_USED(MODULE_SX126X_RF_SWITCH)
|
||||
/**
|
||||
* @ brief Interface to set RF switch parameters
|
||||
*/
|
||||
void(*set_rf_mode)(sx126x_t *dev, sx126x_rf_mode_t rf_mode);
|
||||
#endif
|
||||
} sx126x_params_t;
|
||||
|
||||
/**
|
||||
* @brief Device descriptor for the driver
|
||||
*/
|
||||
typedef struct {
|
||||
struct sx126x {
|
||||
netdev_t netdev; /**< Netdev parent struct */
|
||||
sx126x_params_t *params; /**< Initialization parameters */
|
||||
sx126x_pkt_params_lora_t pkt_params; /**< Lora packet parameters */
|
||||
sx126x_mod_params_lora_t mod_params; /**< Lora modulation parameters */
|
||||
uint32_t channel; /**< Current channel frequency (in Hz) */
|
||||
uint8_t rx_timeout; /**< Rx Timeout in terms of symbols */
|
||||
} sx126x_t;
|
||||
bool radio_sleep; /**< Radio sleep status */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Setup the radio device
|
||||
|
@ -39,6 +39,11 @@ config MODULE_LLCC68
|
||||
select MODULE_PERIPH_GPIO
|
||||
select MODULE_PERIPH_GPIO_IRQ
|
||||
|
||||
config MODULE_SX126X_STM32WL
|
||||
bool "SX126X-STM32WL"
|
||||
select MODULE_SX126X
|
||||
select MODULE_PERIPH_GPIO
|
||||
|
||||
endif
|
||||
|
||||
endmenu
|
||||
|
@ -103,6 +103,25 @@ static inline bool sx126x_is_sx1268(sx126x_t *dev)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check whether the device model is stm32wl (onboard radio)
|
||||
*
|
||||
* @param[in] dev Device descriptor of the driver
|
||||
*
|
||||
* @retval true if the device is stm32wl
|
||||
* @retval false otherwise
|
||||
*/
|
||||
static inline bool sx126x_is_stm32wl(sx126x_t *dev)
|
||||
{
|
||||
assert(dev);
|
||||
if (SX126X_SINGLE) {
|
||||
return IS_USED(MODULE_SX126X_STM32WL);
|
||||
}
|
||||
else {
|
||||
return dev->params->type == SX126X_TYPE_STM32WL;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -57,6 +57,10 @@ extern "C" {
|
||||
#define SX126X_PARAM_REGULATOR SX126X_REG_MODE_DCDC
|
||||
#endif
|
||||
|
||||
#ifndef SX126X_PARAM_SET_RF_MODE_CB
|
||||
#define SX126X_PARAM_SET_RF_MODE_CB NULL
|
||||
#endif
|
||||
|
||||
#ifndef SX126X_PARAM_TYPE
|
||||
# if IS_USED(MODULE_SX1261)
|
||||
# define SX126X_PARAM_TYPE SX126X_TYPE_SX1261
|
||||
@ -66,18 +70,28 @@ extern "C" {
|
||||
# define SX126X_PARAM_TYPE SX126X_TYPE_SX1268
|
||||
# elif IS_USED(MODULE_LLCC68)
|
||||
# define SX126X_PARAM_TYPE SX126X_TYPE_LLCC68
|
||||
# elif IS_USED(MODULE_SX126X_STM32WL)
|
||||
# define SX126X_PARAM_TYPE SX126X_TYPE_STM32WL
|
||||
# else
|
||||
# error "You should select at least one of the SX126x variants."
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if IS_USED(MODULE_SX126X_RF_SWITCH)
|
||||
#define SX126X_SET_RF_MODE .set_rf_mode = SX126X_PARAM_SET_RF_MODE_CB
|
||||
#else
|
||||
#define SX126X_SET_RF_MODE
|
||||
#endif
|
||||
|
||||
#define SX126X_PARAMS { .spi = SX126X_PARAM_SPI, \
|
||||
.nss_pin = SX126X_PARAM_SPI_NSS, \
|
||||
.reset_pin = SX126X_PARAM_RESET, \
|
||||
.busy_pin = SX126X_PARAM_BUSY, \
|
||||
.dio1_pin = SX126X_PARAM_DIO1, \
|
||||
.type = SX126X_PARAM_TYPE, \
|
||||
.regulator = SX126X_PARAM_REGULATOR }
|
||||
.regulator = SX126X_PARAM_REGULATOR, \
|
||||
SX126X_SET_RF_MODE }
|
||||
|
||||
/**@}*/
|
||||
|
||||
/**
|
||||
|
@ -87,7 +87,9 @@ static const uint16_t _bw_khz[3] = {
|
||||
|
||||
static uint8_t _compute_ldro(sx126x_t *dev)
|
||||
{
|
||||
uint32_t symbol_len = (uint32_t)(1 << dev->mod_params.sf) / _bw_khz[dev->mod_params.bw - SX126X_LORA_BW_125];
|
||||
uint32_t symbol_len =
|
||||
(uint32_t)(1 << dev->mod_params.sf) / _bw_khz[dev->mod_params.bw - SX126X_LORA_BW_125];
|
||||
|
||||
if (symbol_len >= 16) {
|
||||
return 0x01;
|
||||
}
|
||||
@ -111,7 +113,7 @@ static void sx126x_init_default_config(sx126x_t *dev)
|
||||
else if (sx126x_is_sx1268(dev)) {
|
||||
sx126x_set_pa_cfg(dev, &sx1268_pa_cfg);
|
||||
}
|
||||
else { /* sx126x_is_sx1261(dev) */
|
||||
else { /* sx126x_is_sx1261(dev) or sx126x_is_stm32wl(dev) */
|
||||
sx126x_set_pa_cfg(dev, &sx1261_pa_cfg);
|
||||
}
|
||||
sx126x_set_tx_params(dev, CONFIG_SX126X_TX_POWER_DEFAULT, CONFIG_SX126X_RAMP_TIME_DEFAULT);
|
||||
@ -134,10 +136,12 @@ static void sx126x_init_default_config(sx126x_t *dev)
|
||||
sx126x_set_lora_pkt_params(dev, &dev->pkt_params);
|
||||
}
|
||||
|
||||
#if IS_ACTIVE(SX126X_SPI)
|
||||
static void _dio1_isr(void *arg)
|
||||
{
|
||||
netdev_trigger_event_isr(arg);
|
||||
}
|
||||
#endif
|
||||
|
||||
int sx126x_init(sx126x_t *dev)
|
||||
{
|
||||
@ -152,6 +156,7 @@ int sx126x_init(sx126x_t *dev)
|
||||
|
||||
DEBUG("[sx126x] init: SPI_%i initialized with success\n", dev->params->spi);
|
||||
|
||||
#if IS_ACTIVE(SX126X_SPI)
|
||||
gpio_init(dev->params->reset_pin, GPIO_OUT);
|
||||
gpio_init(dev->params->busy_pin, GPIO_IN_PD);
|
||||
|
||||
@ -167,6 +172,7 @@ int sx126x_init(sx126x_t *dev)
|
||||
DEBUG("[sx126x] error: no DIO1 pin defined\n");
|
||||
return -EIO;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Reset the device */
|
||||
sx126x_reset(dev);
|
||||
@ -182,6 +188,7 @@ int sx126x_init(sx126x_t *dev)
|
||||
SX126X_IRQ_TX_DONE |
|
||||
SX126X_IRQ_RX_DONE |
|
||||
SX126X_IRQ_PREAMBLE_DETECTED |
|
||||
SX126X_IRQ_SYNC_WORD_VALID |
|
||||
SX126X_IRQ_HEADER_VALID |
|
||||
SX126X_IRQ_HEADER_ERROR |
|
||||
SX126X_IRQ_CRC_ERROR |
|
||||
@ -211,22 +218,26 @@ int sx126x_init(sx126x_t *dev)
|
||||
|
||||
uint32_t sx126x_get_channel(const sx126x_t *dev)
|
||||
{
|
||||
DEBUG("[sx126x]: sx126x_get_radio_status \n");
|
||||
return dev->channel;
|
||||
}
|
||||
|
||||
void sx126x_set_channel(sx126x_t *dev, uint32_t freq)
|
||||
{
|
||||
DEBUG("[sx126x]: sx126x_set_channel %" PRIu32 "Hz \n", freq);
|
||||
dev->channel = freq;
|
||||
sx126x_set_rf_freq(dev, dev->channel);
|
||||
}
|
||||
|
||||
uint8_t sx126x_get_bandwidth(const sx126x_t *dev)
|
||||
{
|
||||
DEBUG("[sx126x]: sx126x_get_bandwidth \n");
|
||||
return dev->mod_params.bw - SX126X_LORA_BW_125;
|
||||
}
|
||||
|
||||
void sx126x_set_bandwidth(sx126x_t *dev, uint8_t bandwidth)
|
||||
{
|
||||
DEBUG("[sx126x]: sx126x_set_bandwidth %02x\n", bandwidth);
|
||||
dev->mod_params.bw = bandwidth + SX126X_LORA_BW_125;
|
||||
dev->mod_params.ldro = _compute_ldro(dev);
|
||||
sx126x_set_lora_mod_params(dev, &dev->mod_params);
|
||||
@ -234,11 +245,13 @@ void sx126x_set_bandwidth(sx126x_t *dev, uint8_t bandwidth)
|
||||
|
||||
uint8_t sx126x_get_spreading_factor(const sx126x_t *dev)
|
||||
{
|
||||
DEBUG("[sx126x]: sx126x_get_spreading_factor \n");
|
||||
return dev->mod_params.sf;
|
||||
}
|
||||
|
||||
void sx126x_set_spreading_factor(sx126x_t *dev, uint8_t sf)
|
||||
{
|
||||
DEBUG("[sx126x]: sx126x_set_spreading_factor : %02x\n", sf);
|
||||
dev->mod_params.sf = (sx126x_lora_sf_t)sf;
|
||||
dev->mod_params.ldro = _compute_ldro(dev);
|
||||
sx126x_set_lora_mod_params(dev, &dev->mod_params);
|
||||
@ -246,17 +259,20 @@ void sx126x_set_spreading_factor(sx126x_t *dev, uint8_t sf)
|
||||
|
||||
uint8_t sx126x_get_coding_rate(const sx126x_t *dev)
|
||||
{
|
||||
DEBUG("[sx126x]: sx126x_get_coding_rate \n");
|
||||
return dev->mod_params.cr;
|
||||
}
|
||||
|
||||
void sx126x_set_coding_rate(sx126x_t *dev, uint8_t cr)
|
||||
{
|
||||
DEBUG("[sx126x]: sx126x_set_coding_rate %01x\n", cr);
|
||||
dev->mod_params.cr = (sx126x_lora_cr_t)cr;
|
||||
sx126x_set_lora_mod_params(dev, &dev->mod_params);
|
||||
}
|
||||
|
||||
uint8_t sx126x_get_lora_payload_length(const sx126x_t *dev)
|
||||
{
|
||||
DEBUG("[sx126x]: sx126x_get_lora_payload_length \n");
|
||||
sx126x_rx_buffer_status_t rx_buffer_status;
|
||||
|
||||
sx126x_get_rx_buffer_status(dev, &rx_buffer_status);
|
||||
@ -265,50 +281,59 @@ uint8_t sx126x_get_lora_payload_length(const sx126x_t *dev)
|
||||
|
||||
void sx126x_set_lora_payload_length(sx126x_t *dev, uint8_t len)
|
||||
{
|
||||
DEBUG("[sx126x]: sx126x_set_lora_payload_length %d\n", len);
|
||||
dev->pkt_params.pld_len_in_bytes = len;
|
||||
sx126x_set_lora_pkt_params(dev, &dev->pkt_params);
|
||||
}
|
||||
|
||||
bool sx126x_get_lora_crc(const sx126x_t *dev)
|
||||
{
|
||||
DEBUG("[sx126x]: sx126x_get_lora_crc \n");
|
||||
return dev->pkt_params.crc_is_on;
|
||||
}
|
||||
|
||||
void sx126x_set_lora_crc(sx126x_t *dev, bool crc)
|
||||
{
|
||||
DEBUG("[sx126x]: sx126x_set_lora_crc %d\n", crc);
|
||||
dev->pkt_params.crc_is_on = crc;
|
||||
sx126x_set_lora_pkt_params(dev, &dev->pkt_params);
|
||||
}
|
||||
|
||||
bool sx126x_get_lora_implicit_header(const sx126x_t *dev)
|
||||
{
|
||||
DEBUG("[sx126x]: sx126x_get_lora_implicit_header \n");
|
||||
return dev->pkt_params.header_type == SX126X_LORA_PKT_IMPLICIT;
|
||||
}
|
||||
|
||||
void sx126x_set_lora_implicit_header(sx126x_t *dev, bool mode)
|
||||
{
|
||||
DEBUG("[sx126x]: sx126x_set_lora_implicit_header %d\n", mode);
|
||||
dev->pkt_params.header_type = (mode ? SX126X_LORA_PKT_IMPLICIT : SX126X_LORA_PKT_EXPLICIT);
|
||||
sx126x_set_lora_pkt_params(dev, &dev->pkt_params);
|
||||
}
|
||||
|
||||
uint16_t sx126x_get_lora_preamble_length(const sx126x_t *dev)
|
||||
{
|
||||
DEBUG("[sx126x]: sx126x_get_lora_preamble_length \n");
|
||||
return dev->pkt_params.preamble_len_in_symb;
|
||||
}
|
||||
|
||||
void sx126x_set_lora_preamble_length(sx126x_t *dev, uint16_t preamble)
|
||||
{
|
||||
DEBUG("[sx126x]: sx126x_set_lora_preamble_length %" PRIu16 "\n", preamble);
|
||||
dev->pkt_params.preamble_len_in_symb = preamble;
|
||||
sx126x_set_lora_pkt_params(dev, &dev->pkt_params);
|
||||
}
|
||||
|
||||
bool sx126x_get_lora_iq_invert(const sx126x_t *dev)
|
||||
{
|
||||
DEBUG("[sx126x]: sx126x_get_lora_iq_invert \n");
|
||||
return dev->pkt_params.invert_iq_is_on;
|
||||
}
|
||||
|
||||
void sx126x_set_lora_iq_invert(sx126x_t *dev, bool iq_invert)
|
||||
{
|
||||
DEBUG("[sx126x]: sx126x_set_lora_iq_invert %d\n", iq_invert);
|
||||
dev->pkt_params.invert_iq_is_on = iq_invert;
|
||||
sx126x_set_lora_pkt_params(dev, &dev->pkt_params);
|
||||
}
|
||||
|
@ -37,6 +37,19 @@
|
||||
const uint8_t llcc68_max_sf = LORA_SF11;
|
||||
const uint8_t sx126x_max_sf = LORA_SF12;
|
||||
|
||||
#if IS_USED(MODULE_SX126X_STM32WL)
|
||||
static netdev_t *_dev;
|
||||
|
||||
void isr_subghz_radio(void)
|
||||
{
|
||||
/* Disable NVIC to avoid ISR conflict in CPU. */
|
||||
NVIC_DisableIRQ(SUBGHZ_Radio_IRQn);
|
||||
NVIC_ClearPendingIRQ(SUBGHZ_Radio_IRQn);
|
||||
netdev_trigger_event_isr(_dev);
|
||||
cortexm_isr_end();
|
||||
}
|
||||
#endif
|
||||
|
||||
static int _send(netdev_t *netdev, const iolist_t *iolist)
|
||||
{
|
||||
sx126x_t *dev = container_of(netdev, sx126x_t, netdev);
|
||||
@ -50,6 +63,7 @@ static int _send(netdev_t *netdev, const iolist_t *iolist)
|
||||
}
|
||||
|
||||
size_t pos = 0;
|
||||
|
||||
/* Write payload buffer */
|
||||
for (const iolist_t *iol = iolist; iol; iol = iol->iol_next) {
|
||||
if (iol->iol_len > 0) {
|
||||
@ -113,6 +127,12 @@ static int _init(netdev_t *netdev)
|
||||
{
|
||||
sx126x_t *dev = container_of(netdev, sx126x_t, netdev);
|
||||
|
||||
if (sx126x_is_stm32wl(dev)) {
|
||||
#if IS_USED(MODULE_SX126X_STM32WL)
|
||||
_dev = netdev;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Launch initialization of driver and device */
|
||||
DEBUG("[sx126x] netdev: initializing driver...\n");
|
||||
if (sx126x_init(dev) != 0) {
|
||||
@ -132,6 +152,12 @@ static void _isr(netdev_t *netdev)
|
||||
|
||||
sx126x_get_and_clear_irq_status(dev, &irq_mask);
|
||||
|
||||
if (sx126x_is_stm32wl(dev)) {
|
||||
#if IS_USED(MODULE_SX126X_STM32WL)
|
||||
NVIC_EnableIRQ(SUBGHZ_Radio_IRQn);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (irq_mask & SX126X_IRQ_TX_DONE) {
|
||||
DEBUG("[sx126x] netdev: SX126X_IRQ_TX_DONE\n");
|
||||
netdev->event_callback(netdev, NETDEV_EVENT_TX_COMPLETE);
|
||||
@ -287,6 +313,12 @@ static int _set_state(sx126x_t *dev, netopt_state_t state)
|
||||
case NETOPT_STATE_IDLE:
|
||||
case NETOPT_STATE_RX:
|
||||
DEBUG("[sx126x] netdev: set NETOPT_STATE_RX state\n");
|
||||
#if IS_USED(MODULE_SX126X_RF_SWITCH)
|
||||
/* Refer Section 4.2 RF Switch in Application Note (AN5406) */
|
||||
if (dev->params->set_rf_mode) {
|
||||
dev->params->set_rf_mode(dev, SX126X_RF_MODE_RX);
|
||||
}
|
||||
#endif
|
||||
sx126x_cfg_rx_boosted(dev, true);
|
||||
int _timeout = (sx126x_symbol_to_msec(dev, dev->rx_timeout));
|
||||
if (_timeout != 0) {
|
||||
@ -299,6 +331,11 @@ static int _set_state(sx126x_t *dev, netopt_state_t state)
|
||||
|
||||
case NETOPT_STATE_TX:
|
||||
DEBUG("[sx126x] netdev: set NETOPT_STATE_TX state\n");
|
||||
#if IS_USED(MODULE_SX126X_RF_SWITCH)
|
||||
if (dev->params->set_rf_mode) {
|
||||
dev->params->set_rf_mode(dev, SX126X_RF_MODE_TX_LPA);
|
||||
}
|
||||
#endif
|
||||
sx126x_set_tx(dev, 0);
|
||||
break;
|
||||
|
||||
|
@ -246,6 +246,10 @@ PSEUDOMODULES += sx1261
|
||||
PSEUDOMODULES += sx1262
|
||||
PSEUDOMODULES += sx1268
|
||||
PSEUDOMODULES += llcc68
|
||||
PSEUDOMODULES += sx126x_stm32wl
|
||||
|
||||
# include RF switch implemented in the board for use with sx126x
|
||||
PSEUDOMODULES += sx126x_rf_switch
|
||||
|
||||
# include variants of SX127X drivers as pseudo modules
|
||||
PSEUDOMODULES += sx1272
|
||||
|
@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Inria
|
||||
* 2021 Freie Universität Berlin
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
@ -14,6 +15,7 @@
|
||||
* @brief HAL implementation for the SX1261/2 LoRa radio driver
|
||||
*
|
||||
* @author Alexandre Abadie <alexandre.abadie@inria.fr>
|
||||
* @author Akshai M <akshai.m@fu-berlin.de>
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
@ -25,6 +27,7 @@
|
||||
|
||||
#include "sx126x.h"
|
||||
#include "sx126x_hal.h"
|
||||
#include "sx126x_internal.h"
|
||||
|
||||
#define ENABLE_DEBUG 0
|
||||
#include "debug.h"
|
||||
@ -32,6 +35,28 @@
|
||||
#define SX126X_SPI_SPEED (SPI_CLK_1MHZ)
|
||||
#define SX126X_SPI_MODE (SPI_MODE_0)
|
||||
|
||||
#ifndef SX126X_PERIPH_WAKEUP_TIME
|
||||
#define SX126X_PERIPH_WAKEUP_TIME 10000U
|
||||
#endif
|
||||
|
||||
#ifndef SX126X_SPI_WAKEUP_TIME
|
||||
#define SX126X_SPI_WAKEUP_TIME 500U
|
||||
#endif
|
||||
|
||||
#if IS_USED(MODULE_SX126X_STM32WL)
|
||||
static uint8_t sx126x_radio_wait_until_ready(sx126x_t *dev)
|
||||
{
|
||||
if (dev->radio_sleep == true) {
|
||||
DEBUG("[sx126x_radio] : Wakeup radio \n");
|
||||
sx126x_hal_wakeup(dev);
|
||||
}
|
||||
|
||||
/* Wait until Busy/ BusyMS signal goes low */
|
||||
while (((PWR->SR2 & PWR_SR2_RFBUSYMS) && ((PWR->SR2 & PWR_SR2_RFBUSYS))) == 1) {}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
sx126x_hal_status_t sx126x_hal_write(const void *context,
|
||||
const uint8_t *command, const uint16_t command_length,
|
||||
const uint8_t *data, const uint16_t data_length)
|
||||
@ -40,15 +65,45 @@ sx126x_hal_status_t sx126x_hal_write(const void *context,
|
||||
(void)data_length;
|
||||
sx126x_t *dev = (sx126x_t *)context;
|
||||
|
||||
/* wait for the device to not be busy anymore */
|
||||
while (gpio_read(dev->params->busy_pin)) {}
|
||||
if (sx126x_is_stm32wl(dev)) {
|
||||
#if IS_USED(MODULE_SX126X_STM32WL)
|
||||
sx126x_radio_wait_until_ready(dev);
|
||||
spi_acquire(dev->params->spi, SPI_CS_UNDEF, SX126X_SPI_MODE, SX126X_SPI_SPEED);
|
||||
|
||||
spi_acquire(dev->params->spi, SPI_CS_UNDEF, SX126X_SPI_MODE, SX126X_SPI_SPEED);
|
||||
spi_transfer_bytes(dev->params->spi, dev->params->nss_pin, data_length != 0, command, NULL,
|
||||
command_length);
|
||||
if (data_length) {
|
||||
spi_transfer_bytes(dev->params->spi, dev->params->nss_pin, false, data, NULL, data_length);
|
||||
/* Check if radio is set to sleep or `RxDutyCycle` mode */
|
||||
if (command[0] == 0x84 || command[0] == 0x94) {
|
||||
dev->radio_sleep = true;
|
||||
}
|
||||
else {
|
||||
dev->radio_sleep = false;
|
||||
}
|
||||
|
||||
/* Pull NSS low */
|
||||
PWR->SUBGHZSPICR &= ~PWR_SUBGHZSPICR_NSS;
|
||||
spi_transfer_bytes(dev->params->spi, SPI_CS_UNDEF, data_length != 0, command,
|
||||
NULL, command_length);
|
||||
if (data_length) {
|
||||
spi_transfer_bytes(dev->params->spi, SPI_CS_UNDEF, false, data, NULL,
|
||||
data_length);
|
||||
}
|
||||
|
||||
/* Pull NSS high */
|
||||
PWR->SUBGHZSPICR |= PWR_SUBGHZSPICR_NSS;
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
/* wait for the device to not be busy anymore */
|
||||
while (gpio_read(dev->params->busy_pin)) {}
|
||||
|
||||
spi_acquire(dev->params->spi, SPI_CS_UNDEF, SX126X_SPI_MODE, SX126X_SPI_SPEED);
|
||||
spi_transfer_bytes(dev->params->spi, dev->params->nss_pin, data_length != 0,
|
||||
command, NULL, command_length);
|
||||
if (data_length) {
|
||||
spi_transfer_bytes(dev->params->spi, dev->params->nss_pin, false, data,
|
||||
NULL, data_length);
|
||||
}
|
||||
}
|
||||
|
||||
spi_release(dev->params->spi);
|
||||
return 0;
|
||||
}
|
||||
@ -59,26 +114,77 @@ sx126x_hal_status_t sx126x_hal_read(const void *context,
|
||||
{
|
||||
sx126x_t *dev = (sx126x_t *)context;
|
||||
|
||||
/* wait for the device to not be busy anymore */
|
||||
while (gpio_read(dev->params->busy_pin)) {}
|
||||
if (sx126x_is_stm32wl(dev)) {
|
||||
#if IS_USED(MODULE_SX126X_STM32WL)
|
||||
sx126x_radio_wait_until_ready(dev);
|
||||
|
||||
spi_acquire(dev->params->spi, SPI_CS_UNDEF, SX126X_SPI_MODE, SX126X_SPI_SPEED);
|
||||
/* Pull NSS low */
|
||||
PWR->SUBGHZSPICR &= ~PWR_SUBGHZSPICR_NSS;
|
||||
spi_transfer_bytes(dev->params->spi, SPI_CS_UNDEF, true, command, NULL, \
|
||||
command_length);
|
||||
spi_transfer_bytes(dev->params->spi, SPI_CS_UNDEF, false, NULL, data, \
|
||||
data_length);
|
||||
/* Pull NSS high */
|
||||
PWR->SUBGHZSPICR |= PWR_SUBGHZSPICR_NSS;
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
/* wait for the device to not be busy anymore */
|
||||
while (gpio_read(dev->params->busy_pin)) {}
|
||||
|
||||
spi_acquire(dev->params->spi, SPI_CS_UNDEF, SX126X_SPI_MODE, SX126X_SPI_SPEED);
|
||||
spi_transfer_bytes(dev->params->spi, dev->params->nss_pin, true, \
|
||||
command, NULL, command_length);
|
||||
spi_transfer_bytes(dev->params->spi, dev->params->nss_pin, false, \
|
||||
NULL, data, data_length);
|
||||
}
|
||||
|
||||
spi_acquire(dev->params->spi, SPI_CS_UNDEF, SX126X_SPI_MODE, SX126X_SPI_SPEED);
|
||||
spi_transfer_bytes(dev->params->spi, dev->params->nss_pin, true, command, NULL, command_length);
|
||||
spi_transfer_bytes(dev->params->spi, dev->params->nss_pin, false, NULL, data, data_length);
|
||||
spi_release(dev->params->spi);
|
||||
return 0;
|
||||
}
|
||||
|
||||
sx126x_hal_status_t sx126x_hal_reset(const void *context)
|
||||
{
|
||||
DEBUG("[sx126x_hal] reset\n");
|
||||
sx126x_t *dev = (sx126x_t *)context;
|
||||
|
||||
gpio_set(dev->params->reset_pin);
|
||||
gpio_clear(dev->params->reset_pin);
|
||||
/* it takes 100us for the radio to be ready after reset */
|
||||
ztimer_sleep(ZTIMER_USEC, 100);
|
||||
gpio_set(dev->params->reset_pin);
|
||||
if (sx126x_is_stm32wl(dev)) {
|
||||
#if IS_USED(MODULE_SX126X_STM32WL)
|
||||
/* Reset Radio */
|
||||
RCC->CSR |= RCC_CSR_RFRST;
|
||||
/* Clear radio reset */
|
||||
RCC->CSR &= ~RCC_CSR_RFRST;
|
||||
ztimer_sleep(ZTIMER_USEC, 100);
|
||||
/* Wait while reset is done */
|
||||
while ((RCC->CSR & RCC_CSR_RFRSTF) != 0UL) {}
|
||||
|
||||
/* Asserts the reset signal of the Radio peripheral */
|
||||
PWR->SUBGHZSPICR |= PWR_SUBGHZSPICR_NSS;
|
||||
|
||||
/* Enable EXTI 44 : Radio IRQ ITs for CPU1 */
|
||||
EXTI->IMR2 |= EXTI_IMR2_IM44;
|
||||
|
||||
/* Set NVIC Priority and enable NVIC */
|
||||
NVIC_SetPriority(SUBGHZ_Radio_IRQn, 0);
|
||||
NVIC_EnableIRQ(SUBGHZ_Radio_IRQn);
|
||||
|
||||
/* Enable wakeup signal of the SUBGHZ Radio */
|
||||
PWR->CR3 |= PWR_CR3_EWRFBUSY;
|
||||
/* Clear Pending Flag */
|
||||
PWR->SCR = PWR_SCR_CWRFBUSYF;
|
||||
|
||||
dev->radio_sleep = true;
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
gpio_set(dev->params->reset_pin);
|
||||
gpio_clear(dev->params->reset_pin);
|
||||
|
||||
/* it takes 100us for the radio to be ready after reset */
|
||||
ztimer_sleep(ZTIMER_USEC, 100);
|
||||
gpio_set(dev->params->reset_pin);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -87,12 +193,23 @@ sx126x_hal_status_t sx126x_hal_wakeup(const void *context)
|
||||
DEBUG("[sx126x_hal] wakeup\n");
|
||||
sx126x_t *dev = (sx126x_t *)context;
|
||||
|
||||
spi_acquire(dev->params->spi, SPI_CS_UNDEF, SX126X_SPI_MODE, SX126X_SPI_SPEED);
|
||||
gpio_clear(dev->params->nss_pin);
|
||||
gpio_set(dev->params->nss_pin);
|
||||
spi_release(dev->params->spi);
|
||||
if (sx126x_is_stm32wl(dev)) {
|
||||
#if IS_USED(MODULE_SX126X_STM32WL)
|
||||
/* Pull NSS low */
|
||||
PWR->SUBGHZSPICR &= ~PWR_SUBGHZSPICR_NSS;
|
||||
ztimer_sleep(ZTIMER_USEC, 1000);
|
||||
/* Pull NSS high */
|
||||
PWR->SUBGHZSPICR |= PWR_SUBGHZSPICR_NSS;
|
||||
ztimer_sleep(ZTIMER_USEC, SX126X_PERIPH_WAKEUP_TIME);
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
spi_acquire(dev->params->spi, SPI_CS_UNDEF, SX126X_SPI_MODE, SX126X_SPI_SPEED);
|
||||
gpio_clear(dev->params->nss_pin);
|
||||
gpio_set(dev->params->nss_pin);
|
||||
spi_release(dev->params->spi);
|
||||
ztimer_sleep(ZTIMER_USEC, SX126X_SPI_WAKEUP_TIME);
|
||||
}
|
||||
|
||||
/* it takes 500us for the radio device to be ready after waking up */
|
||||
ztimer_sleep(ZTIMER_USEC, 500);
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user