From f9650bdbc343b5b8827433cb0c66f7d68a3efe93 Mon Sep 17 00:00:00 2001 From: Benjamin Valentin Date: Mon, 7 Sep 2020 23:37:06 +0200 Subject: [PATCH] drivers/at86rf215: implement Battery Monitor --- drivers/at86rf215/Kconfig | 18 ++++++++++ drivers/at86rf215/Makefile.dep | 4 +++ drivers/at86rf215/at86rf215_getset.c | 46 ++++++++++++++++++++++++++ drivers/at86rf215/at86rf215_internal.c | 5 +++ drivers/at86rf215/at86rf215_netdev.c | 26 +++++++++++++++ drivers/include/at86rf215.h | 28 ++++++++++++++++ 6 files changed, 127 insertions(+) diff --git a/drivers/at86rf215/Kconfig b/drivers/at86rf215/Kconfig index caad2dae7d..8a2d2458a9 100644 --- a/drivers/at86rf215/Kconfig +++ b/drivers/at86rf215/Kconfig @@ -12,6 +12,24 @@ menuconfig KCONFIG_USEMODULE_AT86RF215 if KCONFIG_USEMODULE_AT86RF215 +menuconfig KCONFIG_USEMODULE_AT86RF215_BATMON + bool "AT86RF215 Battery Monitor" + depends on USEMODULE_AT86RF215 + help + Configure the AT86RF215 battery monitor using Kconfig. + +config AT86RF215_BATMON_THRESHOLD + int "Treshold voltage (in mV) of the battery monitor" + range 1700 3675 + default 1800 + depends on KCONFIG_USEMODULE_AT86RF215_BATMON + help + If the supply voltage falls below the configured threshold + a SYS_BUS_POWER_EVENT_LOW_VOLTAGE event is generated on the + SYS_BUS_POWER bus. + + Battery Monitoring is disabled when the device is in Deep Sleep. + config AT86RF215_USE_CLOCK_OUTPUT bool "Enable clock output" help diff --git a/drivers/at86rf215/Makefile.dep b/drivers/at86rf215/Makefile.dep index 449212108d..4e54465b2a 100644 --- a/drivers/at86rf215/Makefile.dep +++ b/drivers/at86rf215/Makefile.dep @@ -9,6 +9,10 @@ ifeq (,$(filter at86rf215_subghz at86rf215_24ghz,$(USEMODULE))) DEFAULT_MODULE += at86rf215_24ghz endif +ifneq (,$(filter at86rf215_batmon,$(USEMODULE))) + USEMODULE += sys_bus_power +endif + DEFAULT_MODULE += netdev_ieee802154_multimode DEFAULT_MODULE += netdev_ieee802154_oqpsk diff --git a/drivers/at86rf215/at86rf215_getset.c b/drivers/at86rf215/at86rf215_getset.c index 35950be32d..473139a72c 100644 --- a/drivers/at86rf215/at86rf215_getset.c +++ b/drivers/at86rf215/at86rf215_getset.c @@ -396,3 +396,49 @@ bool at86rf215_set_idle_from_rx(at86rf215_t *dev, uint8_t state) return false; } + +int at86rf215_enable_batmon(at86rf215_t *dev, unsigned voltage) +{ + uint8_t bmdvc; + + /* only configure BATMON on one interface */ + if (!is_subGHz(dev) && dev->sibling != NULL) { + dev = dev->sibling; + } + + /* ensure valid range */ + if (voltage < 1700 || voltage > 3675) { + return -ERANGE; + } + + if (voltage > 2500) { + /* high range */ + bmdvc = (voltage - 2550 + 37) / 75; + DEBUG("[at86rf215] BATMON set to %u mV\n", 2550 + 75 * bmdvc); + + bmdvc |= BMDVC_BMHR_MASK; + } else { + /* low range */ + bmdvc = (voltage - 1700 + 25) / 50; + DEBUG("[at86rf215] BATMON set to %u mV\n", 1700 + 50 * bmdvc); + } + + /* set batmon threshold */ + at86rf215_reg_write(dev, RG_RF_BMDVC, bmdvc); + + /* enable interrupt */ + at86rf215_reg_or(dev, dev->RF->RG_IRQM, RF_IRQ_BATLOW); + + return 0; +} + +void at86rf215_disable_batmon(at86rf215_t *dev) +{ + /* only configure BATMON on one interface */ + if (!is_subGHz(dev) && dev->sibling != NULL) { + dev = dev->sibling; + } + + /* disable interrupt */ + at86rf215_reg_and(dev, dev->RF->RG_IRQM, ~RF_IRQ_BATLOW); +} diff --git a/drivers/at86rf215/at86rf215_internal.c b/drivers/at86rf215/at86rf215_internal.c index 0592d787a2..2ee9ffda59 100644 --- a/drivers/at86rf215/at86rf215_internal.c +++ b/drivers/at86rf215/at86rf215_internal.c @@ -69,6 +69,11 @@ int at86rf215_hardware_reset(at86rf215_t *dev) return -ENODEV; } + /* enable battery monitor */ + if (IS_ACTIVE(MODULE_AT86RF215_BATMON)) { + at86rf215_enable_batmon(dev, CONFIG_AT86RF215_BATMON_THRESHOLD); + } + /* clear interrupts */ at86rf215_reg_read(dev, RG_RF09_IRQS); at86rf215_reg_read(dev, RG_RF24_IRQS); diff --git a/drivers/at86rf215/at86rf215_netdev.c b/drivers/at86rf215/at86rf215_netdev.c index fbd1713d49..baf87da98b 100644 --- a/drivers/at86rf215/at86rf215_netdev.c +++ b/drivers/at86rf215/at86rf215_netdev.c @@ -30,6 +30,8 @@ #include "net/netdev/ieee802154.h" #include "net/gnrc/netif/internal.h" +#include "sys/bus.h" + #include "at86rf215.h" #include "at86rf215_netdev.h" #include "at86rf215_internal.h" @@ -551,6 +553,22 @@ static int _set(netdev_t *netdev, netopt_t opt, const void *val, size_t len) res = sizeof(netopt_enable_t); break; +#ifdef MODULE_AT86RF215_BATMON + case NETOPT_BATMON: + assert(len <= sizeof(uint16_t)); + { + uint16_t mV = *(const uint16_t *)val; + if (mV) { + res = at86rf215_enable_batmon(dev, mV); + res = (res == 0) ? (int)sizeof(uint16_t) : res; + } else { + at86rf215_disable_batmon(dev); + res = sizeof(uint16_t); + } + } + break; +#endif + case NETOPT_RETRANS: assert(len <= sizeof(uint8_t)); dev->retries_max = *((const uint8_t *)val); @@ -1052,6 +1070,14 @@ static void _isr(netdev_t *netdev) } } + /* Handle Low Battery IRQ */ +#if MODULE_AT86RF215_BATMON + if ((rf_irq_mask & RF_IRQ_BATLOW)) { + msg_bus_t *bus = sys_bus_get(SYS_BUS_POWER); + msg_bus_post(bus, SYS_BUS_POWER_EVENT_LOW_VOLTAGE, NULL); + } +#endif + /* exit early if the interrupt was not for this interface */ if (!((bb_irq_mask & bb_irqs_enabled) || (rf_irq_mask & (RF_IRQ_EDC | RF_IRQ_TRXRDY)) || timeout)) { diff --git a/drivers/include/at86rf215.h b/drivers/include/at86rf215.h index f3978a55c6..022d23cdba 100644 --- a/drivers/include/at86rf215.h +++ b/drivers/include/at86rf215.h @@ -123,6 +123,16 @@ enum { #endif /** @} */ +/** + * @name Default Battery Monitor trigger threshold (in mV) + * if battery monitoring is enabled + * @{ + */ +#ifndef CONFIG_AT86RF215_BATMON_THRESHOLD +#define CONFIG_AT86RF215_BATMON_THRESHOLD (1800) +#endif +/** @} */ + /** * @name Default PHY Mode * @{ @@ -591,6 +601,24 @@ void at86rf215_tx_done(at86rf215_t *dev); */ bool at86rf215_cca(at86rf215_t *dev); +/** + * @brief Generate an interrupt if supply voltage drops below the configured + * threshold. + * + * @param[in] dev device to configure + * @param[in] voltage Threshold voltage in mV + * + * @return 0 on success, error otherwise + */ +int at86rf215_enable_batmon(at86rf215_t *dev, unsigned voltage); + +/** + * @brief Disable the Battery Monitor interrupt. + * + * @param[in] dev device to configure + */ +void at86rf215_disable_batmon(at86rf215_t *dev); + #ifdef __cplusplus } #endif