From 477938e46e16cea2c62003d0da5278f1e02e5948 Mon Sep 17 00:00:00 2001 From: Benjamin Valentin Date: Mon, 15 Apr 2019 16:16:55 +0200 Subject: [PATCH] drivers/mrf24j40: add external PA/LNA control on MC/MD/ME devices The MRF24J40MC/MD/ME modules contain an external power amplifier & low noise amplifier that has to be enabled manually by setting three bits in the TESTMODE register. On MRF24J40MC the power amplifier is powered by a separate voltage regualtor that has to be enabled by setting GPIO3 to HIGH. During Sleep and CCA the PA should be disabled. Co-authored-by: Carton Co-authored-by: Benjamin Valentin --- drivers/include/mrf24j40.h | 10 +++ drivers/mrf24j40/include/mrf24j40_internal.h | 33 ++++++++++ drivers/mrf24j40/include/mrf24j40_registers.h | 22 +++++++ drivers/mrf24j40/mrf24j40.c | 4 ++ drivers/mrf24j40/mrf24j40_getset.c | 4 ++ drivers/mrf24j40/mrf24j40_internal.c | 64 +++++++++++++++++++ 6 files changed, 137 insertions(+) diff --git a/drivers/include/mrf24j40.h b/drivers/include/mrf24j40.h index 6b5427df15..7752f1f04d 100644 --- a/drivers/include/mrf24j40.h +++ b/drivers/include/mrf24j40.h @@ -115,6 +115,16 @@ extern "C" { #define MRF24J40_MAX_FRAME_RETRIES (3U) /**< Number of frame retries (fixed) */ +/** + * @brief Enable external PA/LNA control + * + * Increase RSSI for MRF24J40MC/MD/ME devices. No effect on MRF24J40MA. + * For more information, please refer to section 4.2 of MRF24J40 datasheet. + */ +#ifndef MRF24J40_USE_EXT_PA_LNA +#define MRF24J40_USE_EXT_PA_LNA (0U) +#endif + /** * @brief struct holding all params needed for device initialization */ diff --git a/drivers/mrf24j40/include/mrf24j40_internal.h b/drivers/mrf24j40/include/mrf24j40_internal.h index fb4c623e34..da65c5afb4 100644 --- a/drivers/mrf24j40/include/mrf24j40_internal.h +++ b/drivers/mrf24j40/include/mrf24j40_internal.h @@ -114,6 +114,39 @@ void mrf24j40_update_tasks(mrf24j40_t *dev); */ void mrf24j40_hardware_reset(mrf24j40_t *dev); +/** + * @brief Enable automatic External Power Amplifier & Low Noise Amplifier control + * + * @param[in] dev device to enable the PA & LNA on + */ +#if MRF24J40_USE_EXT_PA_LNA +void mrf24j40_enable_auto_pa_lna(mrf24j40_t *dev); +#else +static inline void mrf24j40_enable_auto_pa_lna(mrf24j40_t *dev) { (void) dev; } +#endif + +/** + * @brief Disable automatic External Power Amplifier & Low Noise Amplifier control + * + * @param[in] dev device to disable the PA & LNA on + */ +#if MRF24J40_USE_EXT_PA_LNA +void mrf24j40_disable_auto_pa_lna(mrf24j40_t *dev); +#else +static inline void mrf24j40_disable_auto_pa_lna(mrf24j40_t *dev) { (void) dev; } +#endif + +/** + * @brief Enable only the External Low Noise Amplifier + * + * @param[in] dev device enable the LNA on + */ +#if MRF24J40_USE_EXT_PA_LNA +void mrf24j40_enable_lna(mrf24j40_t *dev); +#else +static inline void mrf24j40_enable_lna(mrf24j40_t *dev) { (void) dev; } +#endif + #ifdef __cplusplus } #endif diff --git a/drivers/mrf24j40/include/mrf24j40_registers.h b/drivers/mrf24j40/include/mrf24j40_registers.h index cc5d3c6828..f55dc7b7a8 100644 --- a/drivers/mrf24j40/include/mrf24j40_registers.h +++ b/drivers/mrf24j40/include/mrf24j40_registers.h @@ -326,6 +326,18 @@ extern "C" { #define MRF24J40_INTCON_TXNIE (0x01) /** @} */ +/** + * @name Bitfield definitions for the GPIO register (0x33) + * @{ + */ +#define MRF24J40_GPIO_0 (0x01) +#define MRF24J40_GPIO_1 (0x02) +#define MRF24J40_GPIO_2 (0x04) +#define MRF24J40_GPIO_3 (0x08) +#define MRF24J40_GPIO_4 (0x10) +#define MRF24J40_GPIO_5 (0x20) +/** @} */ + /** * @name Bitfield definitions for the SLPACK register (0x35) * @{ @@ -453,6 +465,16 @@ extern "C" { #define MRF24J40_SLPCON1_SLPCLKDIV0 (0x01) /** @} */ +/** + * @name Bitfield definitions for the TESTMODE register (0x22F) + * @{ + */ +#define MRF24J40_TESTMODE_RSSIWAIT1 (0x10) +#define MRF24J40_TESTMODE_RSSIWAIT0 (0x08) +#define MRF24J40_TESTMODE_TESTMODE2 (0x04) +#define MRF24J40_TESTMODE_TESTMODE1 (0x02) +#define MRF24J40_TESTMODE_TESTMODE0 (0x01) +/** @} */ #ifdef __cplusplus } diff --git a/drivers/mrf24j40/mrf24j40.c b/drivers/mrf24j40/mrf24j40.c index 2e58731781..b59d1e820a 100644 --- a/drivers/mrf24j40/mrf24j40.c +++ b/drivers/mrf24j40/mrf24j40.c @@ -81,6 +81,7 @@ bool mrf24j40_cca(mrf24j40_t *dev) uint8_t tmp_rssi; mrf24j40_assert_awake(dev); + mrf24j40_enable_lna(dev); /* trigger CCA measurment */ /* take a look onto datasheet chapter 3.6.1 */ @@ -93,6 +94,9 @@ bool mrf24j40_cca(mrf24j40_t *dev) /* return according to measurement */ tmp_ccaedth = mrf24j40_reg_read_short(dev, MRF24J40_REG_CCAEDTH); /* Energy detection threshold */ tmp_rssi = mrf24j40_reg_read_long(dev, MRF24J40_REG_RSSI); + + mrf24j40_enable_auto_pa_lna(dev); + if (tmp_rssi < tmp_ccaedth) { /* channel is clear */ return true; /* idle */ diff --git a/drivers/mrf24j40/mrf24j40_getset.c b/drivers/mrf24j40/mrf24j40_getset.c index 74fd1b187e..3a64bfb3ce 100644 --- a/drivers/mrf24j40/mrf24j40_getset.c +++ b/drivers/mrf24j40/mrf24j40_getset.c @@ -434,6 +434,9 @@ void mrf24j40_set_state(mrf24j40_t *dev, uint8_t state) void mrf24j40_sleep(mrf24j40_t *dev) { DEBUG("[mrf24j40] Putting into sleep mode\n"); + + /* disable the PA & LNA */ + mrf24j40_disable_auto_pa_lna(dev); /* Datasheet chapter 3.15.2 IMMEDIATE SLEEP AND WAKE-UP MODE */ /* First force a Power Management Reset */ mrf24j40_reg_write_short(dev, MRF24J40_REG_SOFTRST, MRF24J40_SOFTRST_RSTPWR); @@ -467,6 +470,7 @@ void mrf24j40_assert_awake(mrf24j40_t *dev) xtimer_usleep(MRF24J40_WAKEUP_DELAY); /* reset interrupts */ mrf24j40_reg_read_short(dev, MRF24J40_REG_INTSTAT); + mrf24j40_enable_auto_pa_lna(dev); dev->state = MRF24J40_PSEUDO_STATE_IDLE; } } diff --git a/drivers/mrf24j40/mrf24j40_internal.c b/drivers/mrf24j40/mrf24j40_internal.c index 39e09cdd95..5fae71b54c 100644 --- a/drivers/mrf24j40/mrf24j40_internal.c +++ b/drivers/mrf24j40/mrf24j40_internal.c @@ -36,6 +36,68 @@ static inline void getbus(mrf24j40_t *dev) spi_acquire(SPIDEV, CSPIN, SPI_MODE_0, dev->params.spi_clk); } +#if MRF24J40_USE_EXT_PA_LNA +static inline void mrf24j40_reg_and_short(mrf24j40_t *dev, const uint8_t addr, uint8_t value) +{ + value &= mrf24j40_reg_read_short(dev, addr); + mrf24j40_reg_write_short(dev, addr, value); +} + +static inline void mrf24j40_reg_or_short(mrf24j40_t *dev, const uint8_t addr, uint8_t value) +{ + value |= mrf24j40_reg_read_short(dev, addr); + mrf24j40_reg_write_short(dev, addr, value); +} + +void mrf24j40_enable_auto_pa_lna(mrf24j40_t *dev) +{ + /* Configure enable pin of the Voltage Regulator for the PA (GPIO3) on MRF24J40MC */ + mrf24j40_reg_or_short(dev, MRF24J40_REG_TRISGPIO, MRF24J40_GPIO_3); + + /* Enable the volate regulator to power the Power Amplifier */ + mrf24j40_reg_or_short(dev, MRF24J40_REG_GPIO, MRF24J40_GPIO_3); + + mrf24j40_reg_write_long(dev, MRF24J40_REG_TESTMODE, (MRF24J40_TESTMODE_RSSIWAIT0 | + MRF24J40_TESTMODE_TESTMODE2 | + MRF24J40_TESTMODE_TESTMODE1 | + MRF24J40_TESTMODE_TESTMODE0)); +} + +void mrf24j40_disable_auto_pa_lna(mrf24j40_t *dev) +{ + /* Disable automatic switch on PA/LNA */ + mrf24j40_reg_write_long(dev, MRF24J40_REG_TESTMODE, MRF24J40_TESTMODE_RSSIWAIT0); + + /* Configure all GPIOs as Output */ + mrf24j40_reg_or_short(dev, MRF24J40_REG_TRISGPIO, (MRF24J40_GPIO_0 | + MRF24J40_GPIO_1 | + MRF24J40_GPIO_2 | + MRF24J40_GPIO_3)); + + /* Disable all GPIO outputs */ + mrf24j40_reg_and_short(dev, MRF24J40_REG_GPIO, ~(MRF24J40_GPIO_0 | + MRF24J40_GPIO_1 | + MRF24J40_GPIO_2 | + MRF24J40_GPIO_3)); +} + +void mrf24j40_enable_lna(mrf24j40_t *dev) +{ + /* Disable automatic switch on PA/LNA */ + mrf24j40_reg_write_long(dev, MRF24J40_REG_TESTMODE, MRF24J40_TESTMODE_RSSIWAIT0); + + /* Configure all GPIOs as Output */ + mrf24j40_reg_or_short(dev, MRF24J40_REG_TRISGPIO, (MRF24J40_GPIO_0 | + MRF24J40_GPIO_1 | + MRF24J40_GPIO_2 | + MRF24J40_GPIO_3)); + + /* Enable LNA, keep PA voltage regulator on */ + mrf24j40_reg_and_short(dev, MRF24J40_REG_GPIO, ~(MRF24J40_GPIO_0 | MRF24J40_GPIO_1)); + mrf24j40_reg_or_short(dev, MRF24J40_REG_GPIO, MRF24J40_GPIO_2 | MRF24J40_GPIO_3); +} +#endif /* MRF24J40_USE_EXT_PA_LNA */ + void mrf24j40_init(mrf24j40_t *dev) { @@ -88,6 +150,8 @@ void mrf24j40_init(mrf24j40_t *dev) mrf24j40_reg_write_short(dev, MRF24J40_REG_CCAEDTH, 0x60); mrf24j40_reg_write_short(dev, MRF24J40_REG_BBREG6, MRF24J40_BBREG6_RSSIMODE2 ); + mrf24j40_enable_auto_pa_lna(dev); + /* Enable immediate sleep mode */ mrf24j40_reg_write_short(dev, MRF24J40_REG_WAKECON, MRF24J40_WAKECON_IMMWAKE);