1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00
RIOT/drivers/kw41zrf/include/kw41zrf_intern.h
Joakim Nohlgård 5bd67d88a8 drivers/kw41zrf: Transceiver driver for the KW41Z radio
This is the radio found in NXP Kinetis KW41Z, KW21Z. Only 802.15.4 mode
is implemented (KW41Z also supports BLE on the same transceiver).

The driver uses vendor supplied initialization code for the low level
XCVR hardware, these files were imported from KSDK 2.2.0 (framework_5.3.5)
2020-03-19 17:00:04 -05:00

294 lines
7.8 KiB
C

/*
* Copyright (C) 2017 SKF AB
* Copyright (C) 2016 Phytec Messtechnik GmbH
*
* 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 drivers_kw41zrf
* @{
*
* @file
* @brief Internal function interfaces for kw41zrf driver
*
* @author Joakim Nohlgård <joakim.nohlgard@eistec.se>
*/
#ifndef KW41ZRF_INTERN_H
#define KW41ZRF_INTERN_H
#include <stdint.h>
#include "kw41zrf.h"
/* For XCVSEQ_IDLE */
#include "kw41zrf_getset.h"
/* For ZLL CPU registers */
#include "cpu.h"
#ifdef MODULE_PM_LAYERED
#include "pm_layered.h"
#define PM_BLOCK(x) pm_block(x)
#define PM_UNBLOCK(x) pm_unblock(x)
/* When the transceiver is not in DSM, this power mode will be blocked.
* TODO: Change this to symbolic name KINETIS_PM_VLPS when Kinetis power
* management is merged (https://github.com/RIOT-OS/RIOT/pull/7897) */
#define KW41ZRF_PM_BLOCKER 1
#else
#define PM_BLOCK(x)
#define PM_UNBLOCK(x)
#endif
/* Set to 1 to use on board LEDs to show RX/TX activity */
#ifndef KW41ZRF_ENABLE_LEDS
#define KW41ZRF_ENABLE_LEDS (0)
#endif
#if KW41ZRF_ENABLE_LEDS
/* For LED macros */
#include "board.h"
#if !defined(KW41ZRF_LED_RX_ON)
#if defined(LED0_ON)
#define KW41ZRF_LED_RX_ON LED0_ON
#define KW41ZRF_LED_RX_OFF LED0_OFF
#else /* defined(LED0_ON) */
#define KW41ZRF_LED_RX_ON
#define KW41ZRF_LED_RX_OFF
#endif /* defined(LED0_ON) */
#endif /* !defined(KW41ZRF_LED_RX_ON) */
#if !defined(KW41ZRF_LED_TX_ON)
#if defined(LED1_ON)
/* Separate TX LED */
#define KW41ZRF_LED_TX_ON LED1_ON
#define KW41ZRF_LED_TX_OFF LED1_OFF
#elif defined(LED0_ON)
/* Combined RX+TX in one LED */
#define KW41ZRF_LED_TX_ON LED0_ON
#define KW41ZRF_LED_TX_OFF LED0_OFF
#else /* defined(LEDx_ON) */
#define KW41ZRF_LED_TX_ON
#define KW41ZRF_LED_TX_OFF
#endif /* defined(LEDx_ON) */
#endif /* !defined(KW41ZRF_LED_TX_ON) */
#if !defined(KW41ZRF_LED_NDSM_ON)
#if defined(LED2_ON)
#define KW41ZRF_LED_NDSM_ON LED2_ON
#define KW41ZRF_LED_NDSM_OFF LED2_OFF
#else /* defined(LEDx_ON) */
#define KW41ZRF_LED_NDSM_ON
#define KW41ZRF_LED_NDSM_OFF
#endif /* defined(LEDx_ON) */
#endif /* !defined(KW41ZRF_LED_NDSM_ON) */
#if !defined(KW41ZRF_LED_IRQ_ON)
#if defined(LED3_ON)
#define KW41ZRF_LED_IRQ_ON LED3_ON
#define KW41ZRF_LED_IRQ_OFF LED3_OFF
#else /* defined(LEDx_ON) */
#define KW41ZRF_LED_IRQ_ON
#define KW41ZRF_LED_IRQ_OFF
#endif /* defined(LEDx_ON) */
#endif /* !defined(KW41ZRF_LED_IRQ_ON) */
#else /* KW41ZRF_ENABLE_LEDS */
#define KW41ZRF_LED_NDSM_ON
#define KW41ZRF_LED_NDSM_OFF
#define KW41ZRF_LED_TX_ON
#define KW41ZRF_LED_TX_OFF
#define KW41ZRF_LED_RX_ON
#define KW41ZRF_LED_RX_OFF
#define KW41ZRF_LED_IRQ_ON
#define KW41ZRF_LED_IRQ_OFF
#endif /* KW41ZRF_ENABLE_LEDS */
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief KW41Z transceiver power modes
*/
typedef enum {
KW41ZRF_POWER_IDLE = 0, /**< All parts powered */
KW41ZRF_POWER_DSM, /**< Deep sleep mode */
} kw41zrf_powermode_t;
/**
* @brief Timebase settings
*/
typedef enum kw41zrf_timer_timebase {
KW41ZRF_TIMEBASE_500000HZ = 0b010,
KW41ZRF_TIMEBASE_250000HZ = 0b011,
KW41ZRF_TIMEBASE_125000HZ = 0b100,
KW41ZRF_TIMEBASE_62500HZ = 0b101,
KW41ZRF_TIMEBASE_31250HZ = 0b110,
KW41ZRF_TIMEBASE_15625HZ = 0b111,
} kw41zrf_timer_timebase_t;
/**
* @brief Mask all transceiver interrupts
*/
static inline void kw41zrf_mask_irqs(void)
{
NVIC_DisableIRQ(Radio_1_IRQn);
NVIC_ClearPendingIRQ(Radio_1_IRQn);
}
/**
* @brief Unmask all transceiver interrupts
*/
static inline void kw41zrf_unmask_irqs(void)
{
KW41ZRF_LED_IRQ_OFF;
NVIC_EnableIRQ(Radio_1_IRQn);
}
/**
* @brief Set the callback function for the radio ISR
*
* This callback will be called from ISR context when a radio_1 interrupt occurs
*
* @param[in] cb Pointer to callback function
* @param[in] arg Argument that will be passed to the callback
*/
void kw41zrf_set_irq_callback(void (*cb)(void *arg), void *arg);
/**
* @brief Set power mode for device
*
* @param[in] dev kw41zrf device descriptor
* @param[in] pm power mode value
*/
void kw41zrf_set_power_mode(kw41zrf_t *dev, kw41zrf_powermode_t pm);
/**
* @brief Determine if the transceiver is busy doing TX or RX
*
* @param[in] dev kw41zrf device descriptor
*
* @return 0 if transceiver is in progress transmitting a packet
* @return 1 otherwise
*/
int kw41zrf_can_switch_to_idle(kw41zrf_t *dev);
/**
* @brief Set sequence state of device
*
* @param[in] dev kw41zrf device descriptor
* @param[in] seq sequence
*/
void kw41zrf_set_sequence(kw41zrf_t *dev, uint32_t seq);
/**
* @brief Abort the current autosequence
*
* @param[in] dev kw41zrf device descriptor
*/
static inline void kw41zrf_abort_sequence(kw41zrf_t *dev)
{
(void) dev;
/* Writing IDLE to XCVSEQ aborts any ongoing sequence */
ZLL->PHY_CTRL = (ZLL->PHY_CTRL &
~(ZLL_PHY_CTRL_XCVSEQ_MASK |
ZLL_PHY_CTRL_TC3TMOUT_MASK | ZLL_PHY_CTRL_TMRTRIGEN_MASK)) |
ZLL_PHY_CTRL_XCVSEQ(XCVSEQ_IDLE) | ZLL_PHY_CTRL_SEQMSK_MASK;
/* Spin until the sequence manager has acknowledged the sequence abort, this
* should not take many cycles */
while (!(ZLL->SEQ_CTRL_STS & ZLL_SEQ_CTRL_STS_SEQ_IDLE_MASK)) {}
/* Clear interrupt flags */
uint32_t irqsts = ZLL->IRQSTS;
ZLL->IRQSTS = irqsts;
}
/**
* @brief Check if the radio is in deep sleep mode
*
* @return non-zero if radio is in deep sleep
* @return 0 if radio is not in deep sleep mode
*/
static inline uint32_t kw41zrf_is_dsm(void)
{
return (RSIM->DSM_CONTROL & RSIM_DSM_CONTROL_ZIG_DEEP_SLEEP_STATUS_MASK);
}
/**
* @brief Set event timer counter value
*
* @param[in] dev kw41zrf device descriptor
* @param[in] value new time
*/
static inline void kw41zrf_timer_load(kw41zrf_t *dev, uint32_t value)
{
(void) dev;
ZLL->EVENT_TMR = ZLL_EVENT_TMR_EVENT_TMR(value) | ZLL_EVENT_TMR_EVENT_TMR_LD_MASK;
}
/**
* @brief Get current event timer counter value
*
* @param[in] dev kw41zrf device descriptor
*
* @return Current timer value
*/
static inline uint32_t kw41zrf_timer_get(kw41zrf_t *dev)
{
(void) dev;
return (ZLL->EVENT_TMR & ZLL_EVENT_TMR_EVENT_TMR_MASK) >> ZLL_EVENT_TMR_EVENT_TMR_SHIFT;
}
/**
* @brief Set a timeout value for the given compare register of the Event Timer
*
* @param[in] dev kw41zrf device descriptor
* @param[out] cmp_reg pointer to timer compare register, &ZLL->TxCMP
* @param[in] timeout timer offset from current time
*/
static inline void kw41zrf_timer_set(kw41zrf_t *dev, volatile uint32_t *cmp_reg, uint32_t timeout)
{
uint32_t now = kw41zrf_timer_get(dev);
*cmp_reg = now + timeout;
}
/**
* @brief Initialize the Event Timer Block (up counter)
*
* The Event Timer Block provides:
* - Abort an RX and CCA sequence at pre-determined time
* - Latches "timestamp" value during packet reception
* - Initiates timer-triggered sequences
*
* @param[in] dev kw41zrf device descriptor
* @param[in] tb timer base value
*/
static inline void kw41zrf_timer_init(kw41zrf_t *dev, kw41zrf_timer_timebase_t tb)
{
ZLL->TMR_PRESCALE = (ZLL->TMR_PRESCALE & ~ZLL_TMR_PRESCALE_TMR_PRESCALE_MASK) |
ZLL_TMR_PRESCALE_TMR_PRESCALE(tb);
kw41zrf_timer_load(dev, 0);
}
/**
* @brief Returns timestamp of the beginning of the most recently received packet
*
* The latched timestamp corresponds to the point where the SFD detection was
* triggered for the most recent packet, i.e. right before the first byte of the
* packet.
*
* @param[in] dev kw41zrf device descriptor
*
* @return timestamp value
*/
static inline uint32_t kw41zrf_get_timestamp(kw41zrf_t *dev)
{
(void) dev;
return ZLL->TIMESTAMP;
}
#ifdef __cplusplus
}
#endif
#endif /* KW41ZRF_INTERN_H */
/** @} */