mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
drivers/sx126x : Add stm32wl variant
This commit is contained in:
parent
f68dab9ccb
commit
8870a885cb
@ -43,8 +43,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 +62,7 @@ typedef enum {
|
||||
SX126X_TYPE_SX1262,
|
||||
SX126X_TYPE_SX1268,
|
||||
SX126X_TYPE_LLCC68,
|
||||
SX126X_TYPE_STM32WL,
|
||||
} sx126x_type_t;
|
||||
|
||||
/**
|
||||
@ -78,6 +88,7 @@ typedef struct {
|
||||
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 */
|
||||
bool radio_sleep; /**< Radio sleep status */
|
||||
} sx126x_t;
|
||||
|
||||
/**
|
||||
|
@ -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
|
||||
|
@ -66,6 +66,8 @@ 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
|
||||
|
@ -111,7 +111,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 +134,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((netdev_t *)arg);
|
||||
}
|
||||
#endif
|
||||
|
||||
int sx126x_init(sx126x_t *dev)
|
||||
{
|
||||
@ -152,6 +154,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 +170,7 @@ int sx126x_init(sx126x_t *dev)
|
||||
DEBUG("[sx126x] error: no DIO1 pin defined\n");
|
||||
return -EIO;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Reset the device */
|
||||
sx126x_reset(dev);
|
||||
|
@ -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 = (sx126x_t *)netdev;
|
||||
@ -112,6 +125,11 @@ static int _recv(netdev_t *netdev, void *buf, size_t len, void *info)
|
||||
static int _init(netdev_t *netdev)
|
||||
{
|
||||
sx126x_t *dev = (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");
|
||||
@ -132,6 +150,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);
|
||||
|
@ -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,29 @@
|
||||
#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 +66,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 +115,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 +194,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