1
0
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:
Akshai M 2021-07-07 13:25:20 +02:00
parent f68dab9ccb
commit 8870a885cb
7 changed files with 208 additions and 25 deletions

View File

@ -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;
/**

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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);

View File

@ -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;
}