1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00
RIOT/drivers/at86rf215/include/at86rf215_internal.h
Benjamin Valentin 14bb15d91f drivers/at86rf215: make reset pulse width configurable
Some hardware designers like to include filtering capacitors into reset
lines in order to protect against ESD or other pulses.

This increases the raise time of the reset signal. To still reach the
required 16 µs reset pulse width, we thus have to increase the reset pulse
width via board config.
2020-06-11 15:05:21 +02:00

536 lines
16 KiB
C

/*
* Copyright (C) 2019 ML!PA Consulting 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_at86rf215
* @{
*
* @file
* @brief Low-Level functions for the AT86RF215 driver
*
* @author Benjamin Valentin <benjamin.valentin@ml-pa.com>
*/
#ifndef AT86RF215_INTERNAL_H
#define AT86RF215_INTERNAL_H
#include <stdint.h>
#include "at86rf215.h"
#include "at86rf215_registers.h"
#include "board.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Minimum reset pulse width (tRST) in µs
*/
#ifndef CONFIG_AT86RF215_RESET_PULSE_WIDTH_US
#define CONFIG_AT86RF215_RESET_PULSE_WIDTH_US (16U)
#endif
/**
* @brief The typical transition time to TRX_OFF after reset (tPOWERON) in µs
*/
#define AT86RF215_RESET_DELAY_US (16U)
/** Default energy detect threshold for CSMA (reset value) */
#define AT86RF215_EDT_DEFAULT (-84) /* dBm */
/**
* This is used to calculate the csma backoff based on the bitrate.
*/
/** 20 symbols is the std period length */
#define AT86RF215_BACKOFF_PERIOD_IN_SYMBOLS (20U)
/**
* Default Parameters for 802.15.4 retransmissions & CSMA
* @{
*/
#define AT86RF215_RETRIES_MAX_DEFAULT (3)
#define AT86RF215_CSMA_RETRIES_MAX_DEFAULT (4)
#define AT86RF215_CSMA_MIN_BE_DEFAULT (3)
#define AT86RF215_CSMA_MAX_BE_DEFAULT (5)
/** @} */
/** An ACK consists of 5 payload bytes */
#define AT86RF215_ACK_PSDU_BYTES (5)
/**
* This is used to calculate the ACK timeout based on the bitrate.
* AT86RF233 uses an ACK timeout of 54 symbol periods, or 864 µs @ 250 kbit/s
* -> 864µs * 250kbit/s = 216 bit */
#define AT86RF215_ACK_PERIOD_IN_SYMBOLS (54U)
#define AT86RF215_OQPSK_MODE_LEGACY (0x1) /**< legacy mode, 250 kbit/s */
#define AT86RF215_OQPSK_MODE_LEGACY_HDR (0x3) /**< legacy mode, high data rate */
#define AT86RF215_MR_OQPSK_MODE(n) ((n) << OQPSKPHRTX_MOD_SHIFT) /**< MR-QPSK */
/**
* @brief Perform a reset of the entire chip.
*
* @param dev device to reset, will also reset sibling device
* @return 0 on success, error if device is not available
*/
int at86rf215_hardware_reset(at86rf215_t *dev);
/**
* @brief Write to a register at address `addr` from device `dev`.
*
* @param[in] dev device to write to
* @param[in] reg address of the register to write
* @param[in] val value to write to the given register
*/
void at86rf215_reg_write(const at86rf215_t *dev, uint16_t reg, uint8_t val);
/**
* @brief Write a chunk of data into the memory of the given device
*
* @param[in] dev device to write to
* @param[in] reg address in the device to write to
* @param[in] data data to copy into the device
* @param[in] len number of bytes to write into the device
*/
void at86rf215_reg_write_bytes(const at86rf215_t *dev, uint16_t reg, const void *data, size_t len);
/**
* @brief Read from a register at address `addr` from device `dev`.
*
* @param[in] dev device to read from
* @param[in] reg address of the register to read
*
* @return the value of the specified register
*/
uint8_t at86rf215_reg_read(const at86rf215_t *dev, uint16_t reg);
/**
* @brief Read a chunk of data from the memory of the given device
*
* @param[in] dev device to read from
* @param[in] reg starting address to read from
* @param[out] data buffer to read data into
* @param[in] len number of bytes to read
*/
void at86rf215_reg_read_bytes(const at86rf215_t *dev, uint16_t reg, void *data, size_t len);
/**
* @brief Enable / Disable the ACK filter
*
* @param[in] dev device to configure
* @param[in] on if true, only ACK frames are received
* if false, only non-ACK frames are received
*/
void at86rf215_filter_ack(at86rf215_t *dev, bool on);
/**
* @brief Read random data from the RNG
*
* @pre The device has to be in state RX with PLL locked.
*
* @param[in] dev device to configure
* @param[out] data buffer to copy the random data to
* @param[in] len number of random bytes to store in data
*/
void at86rf215_get_random(at86rf215_t *dev, void *data, size_t len);
/**
* @brief Configure the radio to make use of OFDM modulation.
* There are 4 OFDM options, each with a different number of active tones.
* The device supports BPSK, QPSK and 16-QAM modulation and coding schemes (MCS)
*
* @param[in] dev device to configure
* @param[in] option modulation option, each increment halves the data rate
* @param[in] mcs modulation scheme, `BB_MCS_BPSK_REP4` … `BB_MCS_16QAM_3BY4`
*
* @return 0 on success, error otherwise
*/
int at86rf215_configure_OFDM(at86rf215_t *dev, uint8_t option, uint8_t mcs);
/**
* @brief Set the current modulation and coding scheme (MCS)
*
* @param[in] dev device to configure
* @param[in] mcs modulation and coding scheme
*
* @return 0 on success, error otherwise
*/
int at86rf215_OFDM_set_scheme(at86rf215_t *dev, uint8_t mcs);
/**
* @brief Get the current modulation and coding scheme (MCS)
*
* @param[in] dev device to read from
*
* @return the current modulation & coding scheme
*/
uint8_t at86rf215_OFDM_get_scheme(at86rf215_t *dev);
/**
* @brief Set the current OFDM option
*
* @param[in] dev device to configure
* @param[in] option OFDM option
*
* @return 0 on success, error otherwise
*/
int at86rf215_OFDM_set_option(at86rf215_t *dev, uint8_t option);
/**
* @brief Get the current OFDM option
*
* @param[in] dev device to read from
*
* @return the current OFDM option
*/
uint8_t at86rf215_OFDM_get_option(at86rf215_t *dev);
/**
* @ingroup drivers_at86rf215
* @defgroup drivers_at86rf215_oqpsk AT86RF215 MR-O-QPSK PHY
* @{
*/
/**
* @brief Configure the radio to make use of O-QPSK modulation.
* The rate mode may be
* - 0 for compatibility with first-gen 802.15.4 devices (250 kbit/s)
* - 1 for compatibility with the proprietary high-data rate modes of at86rf2xx
*
* @param[in] dev device to configure
* @param[in] high_rate use proprietary high data rate compatible with at86rf2xx
*
* @return 0 on success, error otherwise
*/
int at86rf215_configure_legacy_OQPSK(at86rf215_t *dev, bool high_rate);
/**
* @brief Configure the radio to make use of O-QPSK modulation.
* The chip rate is the number of bits per second (chips per second) used in the spreading signal.
* The rate mode may be
* - @ref AT86RF215_OQPSK_MODE_LEGACY for compatibility with first-gen 802.15.4 devices (250 kbit/s)
* - @ref AT86RF215_OQPSK_MODE_LEGACY_HDR for compatibility with the proprietary high-data rate mode
* of the at86rf233 (1000 kbit/s, 2.4 GHz) and at86rf212b (500 kbit/s, sub-GHz)
* - @ref AT86RF215_MR_OQPSK_MODE for the rate modes specified in 802.15.4g-2012
*
* @param[in] dev device to configure
* @param[in] chips chip rate, `BB_FCHIP100` … `BB_FCHIP2000`
* @param[in] rate rate mode, may be @ref AT86RF215_OQPSK_MODE_LEGACY or @ref AT86RF215_MR_OQPSK_MODE
*
* @return 0 on success, error otherwise
*/
int at86rf215_configure_OQPSK(at86rf215_t *dev, uint8_t chips, uint8_t rate);
/**
* @brief Get the current O-QPSK chip rate
*
* @param[in] dev device to read from
*
* @return the current chip rate
*/
uint8_t at86rf215_OQPSK_get_chips(at86rf215_t *dev);
/**
* @brief Set the current O-QPSK chip rate
*
* @param[in] dev device to configure
* @param[in] chips chip rate in chip/s
*
* @return 0 on success, error otherwise
*/
int at86rf215_OQPSK_set_chips(at86rf215_t *dev, uint8_t chips);
/**
* @brief Get the current O-QPSK rate mode
*
* @param[in] dev device to read from
*
* @return the current rate mode
*/
uint8_t at86rf215_OQPSK_get_mode(at86rf215_t *dev);
/**
* @brief Set the current O-QPSK rate mode
*
* @param[in] dev device to configure
* @param[in] mode rate mode
*
* @return 0 on success, error otherwise
*/
int at86rf215_OQPSK_set_mode(at86rf215_t *dev, uint8_t mode);
/**
* @brief Get the current legacy O-QPSK mode
*
* @param[in] dev device to read from
*
* @return 0 for IEEE 802.15.4 mode, 1 for high data rate
*/
uint8_t at86rf215_OQPSK_get_mode_legacy(at86rf215_t *dev);
/**
* @brief Set the current legacy O-QPSK rate mode
*
* @param[in] dev device to configure
* @param[in] high_rate set to use proprietary high data rate
*
* @return 0 on success, error otherwise
*/
int at86rf215_OQPSK_set_mode_legacy(at86rf215_t *dev, bool high_rate);
/**
* @brief Test if O-QPSK PHY operates in legacy mode
*
* @param[in] dev device to test
*
* @return true if device operates in legacy mode
*/
static inline bool at86rf215_OQPSK_is_legacy(at86rf215_t *dev) {
return at86rf215_reg_read(dev, dev->BBC->RG_OQPSKPHRTX) & AT86RF215_OQPSK_MODE_LEGACY;
}
/** @} */
/**
* @brief Get the current PHY modulation.
* May be @ref IEEE802154_PHY_MR_FSK, @ref IEEE802154_PHY_MR_OFDM,
* @ref IEEE802154_PHY_MR_OQPSK, @ref IEEE802154_PHY_OQPSK
* or @ref IEEE802154_PHY_DISABLED.
*
* @param[in] dev device to read from
*
* @return the current PHY mode the device is operating with
*/
uint8_t at86rf215_get_phy_mode(at86rf215_t *dev);
/**
* @brief Check if a channel number is valid.
* The function takes the current frequency band and modulation into
* account to determine if `chan` would be a legal channel number.
* If so, it is returned unmodified. Otherwise the next closest legal
* channel number is returned.
*
* @note This function does not change the configuration.
*
* @param[in] dev device to check against
* @param[in] chan the channel number to check
*
* @return If the channel number is legal, `chan` is returned.
* Otherwise the next closest legal channel number is
* returned.
*/
uint16_t at86rf215_chan_valid(at86rf215_t *dev, uint16_t chan);
/**
* @brief Converts radio state into human readable string.
*
* @param[in] state radio state
*
* @return fixed string representation of the radio state
*/
const char* at86rf215_hw_state2a(uint8_t state);
/**
* @brief Converts state machine state into human readable string.
*
* @param[in] state state of the driver's state machine
*
* @return fixed string representation of the state machine state
*/
const char* at86rf215_sw_state2a(at86rf215_state_t state);
/**
* @brief Reads the contents of `reg`, apply `val` with a bitwise AND
* and then writes the result back to `reg`.
*
* @param[in] dev device to write to
* @param[in] reg register to write to
* @param[in] val value to bitwise AND with the register content
*/
static inline void at86rf215_reg_and(const at86rf215_t *dev, uint16_t reg, uint8_t val)
{
val &= at86rf215_reg_read(dev, reg);
at86rf215_reg_write(dev, reg, val);
}
/**
* @brief Reads the contents of `reg`, apply `val` with a bitwise OR
* and then writes the result back to `reg`.
*
* @param[in] dev device to write to
* @param[in] reg register to write to
* @param[in] val value to bitwise OR with the register content
*/
static inline void at86rf215_reg_or(const at86rf215_t *dev, uint16_t reg, uint8_t val)
{
val |= at86rf215_reg_read(dev, reg);
at86rf215_reg_write(dev, reg, val);
}
/**
* @brief Write a 16-bit word to a register at address `addr` from device `dev`.
*
* @param[in] dev device to write to
* @param[in] reg address of the register to write
* @param[in] val value to write to the given register
*/
static inline void at86rf215_reg_write16(const at86rf215_t *dev, uint16_t reg, uint16_t val)
{
at86rf215_reg_write_bytes(dev, reg, &val, sizeof(val));
}
/**
* @brief Read a 16-bit word from a register at address `addr` from device `dev`.
*
* @param[in] dev device to read from
* @param[in] reg address of the register to read
*
* @return the value of the specified register
*/
static inline uint16_t at86rf215_reg_read16(const at86rf215_t *dev, uint16_t reg)
{
uint16_t value;
at86rf215_reg_read_bytes(dev, reg, &value, sizeof(value));
return value;
}
/**
* @brief Issue a radio command to the device
*
* @param[in] dev device to configure
* @param[in] rf_cmd command to send
*/
static inline void at86rf215_rf_cmd(const at86rf215_t *dev, uint8_t rf_cmd)
{
at86rf215_reg_write(dev, dev->RF->RG_CMD, rf_cmd);
}
/**
* @brief Get the radio state of the device
*
* @param[in] dev device to read from
*
* @return the current radio state
*/
static inline uint8_t at86rf215_get_rf_state(const at86rf215_t *dev)
{
return at86rf215_reg_read(dev, dev->RF->RG_STATE) & STATE_STATE_MASK;
}
/**
* @brief Blocks until the device has reached the given state
*
* @param[in] dev device to poll
* @param[in] state the expected state
*/
static inline void at86rf215_await_state(const at86rf215_t *dev, uint8_t state)
{
while (at86rf215_get_rf_state(dev) != state) {}
}
/**
* @brief Blocks until the device has reached the given state
*
* @param[in] dev device to poll
* @param[in] state the expected state
*/
static inline void at86rf215_await_state_end(const at86rf215_t *dev, uint8_t state)
{
while (at86rf215_get_rf_state(dev) == state) {}
}
/**
* @brief Switch device back to IDLE-RX from non-RX idle
*
* @param[in] dev device to update
* @param[out] old_state pointer to store the previous state, may be NULL
*
* @return true if the operation was possible
*/
bool at86rf215_set_rx_from_idle(at86rf215_t *dev, uint8_t *old_state);
/**
* @brief Switch device to non-RX idle state from RX
*
* @param[in] dev device to update
* @param[out] state the new state (may be CMD_RF_TRXOFF or CMD_RF_SLEEP)
*
* @return true if the operation was possible
*/
bool at86rf215_set_idle_from_rx(at86rf215_t *dev, uint8_t state);
/**
* @brief Enable the baseband processor of the device
*
* @param[in] dev device to enable the baseband on
*/
static inline void at86rf215_enable_baseband(const at86rf215_t *dev)
{
at86rf215_reg_or(dev, dev->BBC->RG_PC, PC_BBEN_MASK);
}
/**
* @brief Disable the baseband processor of the device
*
* @param[in] dev device to disable the baseband on
*/
static inline void at86rf215_disable_baseband(const at86rf215_t *dev) {
at86rf215_reg_and(dev, dev->BBC->RG_PC, ~PC_BBEN_MASK);
}
/**
* @brief Enable the radio hardware with a given modulation.
*
* @param[in] dev device to enable
* @param[in] modulation modulation to configure on the radio
*/
static inline void at86rf215_enable_radio(at86rf215_t *dev, uint8_t modulation)
{
/* 16 bit frame-checksum, baseband enabled, checksum calculated by chip,
frames with invalid cs are dropped */
at86rf215_reg_write(dev, dev->BBC->RG_PC, modulation | PC_BBEN_MASK
| PC_FCST_MASK | PC_TXAFCS_MASK
| PC_FCSFE_MASK);
}
/**
* @brief Internal convenience function to disable reduced power
* consumption (RPC) for energy detection.
*
* @param[in] dev device to configure
*/
void at86rf215_disable_rpc(at86rf215_t *dev);
/**
* @brief Internal convenience function to re-enable reduced power
* consumption (RPC) after energy detection.
*
* @param[in] dev device to configure
*/
void at86rf215_enable_rpc(at86rf215_t *dev);
/**
* @brief Checks whether the device operates in the sub-GHz band.
*
* @param[in] dev device to read from
*
* @return true if the device operates in the sub-GHz band
* false if the device operates in the 2.4-GHz band
*/
static inline bool is_subGHz(const at86rf215_t *dev)
{
return dev->RF->RG_IRQS == RG_RF09_IRQS;
}
#ifdef __cplusplus
}
#endif
#endif /* AT86RF215_INTERNAL_H */
/** @} */