1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2025-12-25 14:33:52 +01:00

Merge pull request #4412 from DipSwitch/pr/at86rf2xx-phy-mode

at86rf2xx: Add support for channel page
This commit is contained in:
Thomas Eichinger 2015-12-08 11:40:47 +01:00
commit 10323329ce
6 changed files with 192 additions and 100 deletions

View File

@ -148,7 +148,7 @@ void at86rf2xx_reset(at86rf2xx_t *dev)
at86rf2xx_reg_write(dev, AT86RF2XX_REG__TRX_CTRL_2,
AT86RF2XX_TRX_CTRL_2_MASK__RX_SAFE_MODE);
#ifdef MODULE_AT86RF212B
at86rf2xx_set_freq(dev, AT86RF2XX_FREQ_915MHZ);
at86rf2xx_set_page(dev, 0);
#endif
/* don't populate masked interrupt flags to IRQ_STATUS register */

View File

@ -18,6 +18,7 @@
* @author Baptiste Clenet <bapclenet@gmail.com>
* @author Daniel Krebs <github@daniel-krebs.net>
* @author Kévin Roussel <Kevin.Roussel@inria.fr>
* @author Joakim Nohlgård <joakim.nohlgard@eistec.se>
*
* @}
*/
@ -47,16 +48,29 @@ static const uint8_t dbm_to_tx_pow_915[] = {0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x17,
0x04, 0x03, 0x02, 0x01, 0x00, 0x86,
0x40, 0x84, 0x83, 0x82, 0x80, 0xc1,
0xc0};
int16_t tx_pow_to_dbm(at86rf2xx_freq_t freq, uint8_t reg) {
for(int i = 0; i < 37; i++){
if(freq == AT86RF2XX_FREQ_868MHZ){
if (dbm_to_tx_pow_868[i] == reg) {
return i -25;
}
} else if (freq == AT86RF2XX_FREQ_915MHZ){
if (dbm_to_tx_pow_915[i] == reg) {
return i -25;
}
static int16_t _tx_pow_to_dbm_212b(uint8_t channel, uint8_t page, uint8_t reg) {
const uint8_t *dbm_to_tx_pow;
size_t nelem;
if (page == 0 || page == 2) {
/* Channel 0 is 868.3 MHz */
if (channel == 0) {
dbm_to_tx_pow = &dbm_to_tx_pow_868[0];
nelem = sizeof(dbm_to_tx_pow_868) / sizeof(dbm_to_tx_pow_868[0]);
}
else {
/* Channels 1+ are 915 MHz */
dbm_to_tx_pow = &dbm_to_tx_pow_915[0];
nelem = sizeof(dbm_to_tx_pow_915) / sizeof(dbm_to_tx_pow_915[0]);
}
}
else {
return 0;
}
for(size_t i = 0; i < nelem; i++){
if (dbm_to_tx_pow[i] == reg) {
return i - 25;
}
}
return 0;
@ -124,61 +138,37 @@ uint8_t at86rf2xx_get_chan(at86rf2xx_t *dev)
void at86rf2xx_set_chan(at86rf2xx_t *dev, uint8_t channel)
{
uint8_t tmp;
if (channel < AT86RF2XX_MIN_CHANNEL
|| channel > AT86RF2XX_MAX_CHANNEL) {
if ((channel < AT86RF2XX_MIN_CHANNEL) ||
(channel > AT86RF2XX_MAX_CHANNEL) ||
(dev->chan == channel)) {
return;
}
dev->chan = channel;
tmp = at86rf2xx_reg_read(dev, AT86RF2XX_REG__PHY_CC_CCA);
tmp &= ~(AT86RF2XX_PHY_CC_CCA_MASK__CHANNEL);
tmp |= (channel & AT86RF2XX_PHY_CC_CCA_MASK__CHANNEL);
at86rf2xx_reg_write(dev, AT86RF2XX_REG__PHY_CC_CCA, tmp);
at86rf2xx_configure_phy(dev);
}
uint8_t at86rf2xx_get_page(at86rf2xx_t *dev)
{
#ifdef MODULE_AT86RF212B
at86rf2xx_freq_t at86rf2xx_get_freq(at86rf2xx_t *dev)
{
return dev->freq;
}
void at86rf2xx_set_freq(at86rf2xx_t *dev, at86rf2xx_freq_t freq)
{
uint8_t trx_ctrl2 = 0, rf_ctrl0 = 0;
trx_ctrl2 = at86rf2xx_reg_read(dev, AT86RF2XX_REG__TRX_CTRL_2);
trx_ctrl2 &= ~(AT86RF2XX_TRX_CTRL_2_MASK__FREQ_MODE);
rf_ctrl0 = at86rf2xx_reg_read(dev, AT86RF2XX_REG__RF_CTRL_0);
/* Erase previous conf for GC_TX_OFFS */
rf_ctrl0 &= ~AT86RF2XX_RF_CTRL_0_MASK__GC_TX_OFFS;
trx_ctrl2 |= AT86RF2XX_TRX_CTRL_2_MASK__SUB_MODE;
rf_ctrl0 |= AT86RF2XX_RF_CTRL_0_GC_TX_OFFS__2DB;
switch(freq) {
case AT86RF2XX_FREQ_915MHZ:
if (dev->chan == 0) {
at86rf2xx_set_chan(dev,AT86RF2XX_DEFAULT_CHANNEL);
} else {
at86rf2xx_set_chan(dev,dev->chan);
}
break;
case AT86RF2XX_FREQ_868MHZ:
/* Channel = 0 for 868MHz means 868.3MHz, only one available */
at86rf2xx_set_chan(dev,0x00);
break;
default:
DEBUG("at86rf2xx: Trying to set unknown frequency 0x%lx\n",
(unsigned long) freq);
return;
}
dev->freq = freq;
at86rf2xx_reg_write(dev, AT86RF2XX_REG__TRX_CTRL_2, trx_ctrl2);
at86rf2xx_reg_write(dev, AT86RF2XX_REG__RF_CTRL_0, rf_ctrl0);
}
return dev->page;
#else
return 0;
#endif
}
void at86rf2xx_set_page(at86rf2xx_t *dev, uint8_t page)
{
#ifdef MODULE_AT86RF212B
if ((page != 0) && (page != 2)) {
return;
}
dev->page = page;
at86rf2xx_configure_phy(dev);
#endif
}
uint16_t at86rf2xx_get_pan(at86rf2xx_t *dev)
{
@ -198,7 +188,7 @@ int16_t at86rf2xx_get_txpower(at86rf2xx_t *dev)
#ifdef MODULE_AT86RF212B
uint8_t txpower = at86rf2xx_reg_read(dev, AT86RF2XX_REG__PHY_TX_PWR);
DEBUG("txpower value: %x\n", txpower);
return tx_pow_to_dbm(dev->freq, txpower);
return _tx_pow_to_dbm_212b(dev->chan, dev->page, txpower);
#else
uint8_t txpower = at86rf2xx_reg_read(dev, AT86RF2XX_REG__PHY_TX_PWR)
& AT86RF2XX_PHY_TX_PWR_MASK__TX_PWR;
@ -230,16 +220,13 @@ void at86rf2xx_set_txpower(at86rf2xx_t *dev, int16_t txpower)
#endif
}
#ifdef MODULE_AT86RF212B
if (dev->freq == AT86RF2XX_FREQ_915MHZ) {
at86rf2xx_reg_write(dev, AT86RF2XX_REG__PHY_TX_PWR,
dbm_to_tx_pow_915[txpower]);
}
else if (dev->freq == AT86RF2XX_FREQ_868MHZ) {
if (dev->chan == 0) {
at86rf2xx_reg_write(dev, AT86RF2XX_REG__PHY_TX_PWR,
dbm_to_tx_pow_868[txpower]);
}
else {
return;
else if (dev->chan < 11) {
at86rf2xx_reg_write(dev, AT86RF2XX_REG__PHY_TX_PWR,
dbm_to_tx_pow_915[txpower]);
}
#else
at86rf2xx_reg_write(dev, AT86RF2XX_REG__PHY_TX_PWR,
@ -433,12 +420,6 @@ static inline void _set_state(at86rf2xx_t *dev, uint8_t state)
dev->state = state;
}
static inline void _force_trx_off(at86rf2xx_t *dev)
{
at86rf2xx_reg_write(dev, AT86RF2XX_REG__TRX_STATE, AT86RF2XX_TRX_STATE__FORCE_TRX_OFF);
while (at86rf2xx_get_status(dev) != AT86RF2XX_STATE_TRX_OFF);
}
void at86rf2xx_set_state(at86rf2xx_t *dev, uint8_t state)
{
uint8_t old_state = at86rf2xx_get_status(dev);
@ -469,7 +450,7 @@ void at86rf2xx_set_state(at86rf2xx_t *dev, uint8_t state)
if (state == AT86RF2XX_STATE_SLEEP) {
/* First go to TRX_OFF */
_force_trx_off(dev);
at86rf2xx_force_trx_off(dev);
/* Discard all IRQ flags, framebuffer is lost anyway */
at86rf2xx_reg_read(dev, AT86RF2XX_REG__IRQ_STATUS);
/* Go to SLEEP mode from TRX_OFF */
@ -491,5 +472,5 @@ void at86rf2xx_reset_state_machine(at86rf2xx_t *dev)
old_state = at86rf2xx_get_status(dev);
} while (old_state == AT86RF2XX_STATE_IN_PROGRESS);
_force_trx_off(dev);
at86rf2xx_force_trx_off(dev);
}

View File

@ -135,3 +135,78 @@ void at86rf2xx_hardware_reset(at86rf2xx_t *dev)
gpio_set(dev->reset_pin);
xtimer_usleep(AT86RF2XX_RESET_DELAY);
}
void at86rf2xx_configure_phy(at86rf2xx_t *dev)
{
/* make sure device is not sleeping */
at86rf2xx_assert_awake(dev);
uint8_t state;
/* make sure ongoing transmissions are finished */
do {
state = at86rf2xx_get_status(dev);
}
while ((state == AT86RF2XX_STATE_BUSY_TX_ARET) || (state == AT86RF2XX_STATE_BUSY_RX_AACK));
/* we must be in TRX_OFF before changing the PHY configuration */
at86rf2xx_force_trx_off(dev);
uint8_t phy_cc_cca = at86rf2xx_reg_read(dev, AT86RF2XX_REG__PHY_CC_CCA);
#ifdef MODULE_AT86RF212B
/* The TX power register must be updated after changing the channel if
* moving between bands. */
int16_t txpower = at86rf2xx_get_txpower(dev);
uint8_t trx_ctrl2 = at86rf2xx_reg_read(dev, AT86RF2XX_REG__TRX_CTRL_2);
uint8_t rf_ctrl0 = at86rf2xx_reg_read(dev, AT86RF2XX_REG__RF_CTRL_0);
/* Clear previous configuration for PHY mode */
trx_ctrl2 &= ~(AT86RF2XX_TRX_CTRL_2_MASK__FREQ_MODE);
/* Clear previous configuration for GC_TX_OFFS */
rf_ctrl0 &= ~AT86RF2XX_RF_CTRL_0_MASK__GC_TX_OFFS;
/* Clear previous configuration for channel number */
phy_cc_cca &= ~(AT86RF2XX_PHY_CC_CCA_MASK__CHANNEL);
if (dev->chan != 0) {
/* Set sub mode bit on 915 MHz as recommended by the data sheet */
trx_ctrl2 |= AT86RF2XX_TRX_CTRL_2_MASK__SUB_MODE;
}
if (dev->page == 0) {
/* BPSK coding */
/* Data sheet recommends using a +2 dB setting for BPSK */
rf_ctrl0 |= AT86RF2XX_RF_CTRL_0_GC_TX_OFFS__2DB;
}
else if (dev->page == 2) {
/* O-QPSK coding */
trx_ctrl2 |= AT86RF2XX_TRX_CTRL_2_MASK__BPSK_OQPSK;
/* Data sheet recommends using a +1 dB setting for O-QPSK */
rf_ctrl0 |= AT86RF2XX_RF_CTRL_0_GC_TX_OFFS__1DB;
}
at86rf2xx_reg_write(dev, AT86RF2XX_REG__TRX_CTRL_2, trx_ctrl2);
at86rf2xx_reg_write(dev, AT86RF2XX_REG__RF_CTRL_0, rf_ctrl0);
#endif
/* Update the channel register */
phy_cc_cca |= (dev->chan & AT86RF2XX_PHY_CC_CCA_MASK__CHANNEL);
at86rf2xx_reg_write(dev, AT86RF2XX_REG__PHY_CC_CCA, phy_cc_cca);
#ifdef MODULE_AT86RF212B
/* Update the TX power register to achieve the same power (in dBm) */
at86rf2xx_set_txpower(dev, txpower);
#endif
/* Return to the state we had before reconfiguring */
at86rf2xx_set_state(dev, state);
}
void at86rf2xx_force_trx_off(const at86rf2xx_t *dev)
{
at86rf2xx_reg_write(dev,
AT86RF2XX_REG__TRX_STATE,
AT86RF2XX_TRX_STATE__FORCE_TRX_OFF);
while (at86rf2xx_get_status(dev) != AT86RF2XX_STATE_TRX_OFF);
}

View File

@ -442,6 +442,14 @@ static int _get(gnrc_netdev_t *device, netopt_t opt, void *val, size_t max_len)
((uint8_t *)val)[0] = at86rf2xx_get_chan(dev);
return sizeof(uint16_t);
case NETOPT_CHANNEL_PAGE:
if (max_len < sizeof(uint16_t)) {
return -EOVERFLOW;
}
((uint8_t *)val)[1] = 0;
((uint8_t *)val)[0] = at86rf2xx_get_page(dev);
return sizeof(uint16_t);
case NETOPT_MAX_PACKET_SIZE:
if (max_len < sizeof(int16_t)) {
return -EOVERFLOW;
@ -679,6 +687,29 @@ static int _set(gnrc_netdev_t *device, netopt_t opt, void *val, size_t len)
}
break;
case NETOPT_CHANNEL_PAGE:
if (len != sizeof(uint16_t)) {
res = -EINVAL;
} else {
uint8_t page = ((uint8_t *)val)[0];
#ifdef MODULE_AT86RF212B
if ((page != 0) && (page != 2)) {
res = -ENOTSUP;
} else {
at86rf2xx_set_page(dev, page);
res = sizeof(uint16_t);
}
#else
/* rf23x only supports page 0, no need to configure anything in the driver. */
if (page != 0) {
res = -ENOTSUP;
} else {
res = sizeof(uint16_t);
}
#endif
}
break;
case NETOPT_TX_POWER:
if (len > sizeof(int16_t)) {
res = -EOVERFLOW;

View File

@ -107,6 +107,13 @@ void at86rf2xx_sram_write(const at86rf2xx_t *dev,
void at86rf2xx_fb_read(const at86rf2xx_t *dev,
uint8_t *data, const size_t len);
/**
* @brief Cancel ongoing transactions and switch to TRX_OFF state
*
* @param[in] dev device to manipulate
*/
void at86rf2xx_force_trx_off(const at86rf2xx_t *dev);
/**
* @brief Convenience function for reading the status of the given device
*
@ -131,6 +138,14 @@ void at86rf2xx_assert_awake(at86rf2xx_t *dev);
void at86rf2xx_hardware_reset(at86rf2xx_t *dev);
/**
* @brief Set PHY parameters based on channel and page number
*
* @param[in] dev device to configure
*/
void at86rf2xx_configure_phy(at86rf2xx_t *dev);
#ifdef __cplusplus
}
#endif

View File

@ -23,6 +23,7 @@
* @author Kaspar Schleiser <kaspar@schleiser.de>
* @author Daniel Krebs <github@daniel-krebs.net>
* @author Kévin Roussel <Kevin.Roussel@inria.fr>
* @author Joakim Nohlgård <joakim.nohlgard@eistec.se>
*/
#ifndef AT86RF2XX_H_
@ -124,16 +125,6 @@ extern "C" {
* PAN ID */
/** @} */
/**
* @brief Frequency configuration for sub-GHz devices.
* @{
*/
typedef enum {
AT86RF2XX_FREQ_915MHZ, /**< frequency 915MHz enabled */
AT86RF2XX_FREQ_868MHZ, /**< frequency 868MHz enabled */
} at86rf2xx_freq_t;
/** @} */
/**
* @brief Device descriptor for AT86RF2XX radio devices
*/
@ -153,9 +144,10 @@ typedef struct {
uint8_t seq_nr; /**< sequence number to use next */
uint8_t frame_len; /**< length of the current TX frame */
uint16_t pan; /**< currently used PAN ID */
uint8_t chan; /**< currently used channel */
uint8_t chan; /**< currently used channel number */
#ifdef MODULE_AT86RF212B
at86rf2xx_freq_t freq; /**< currently used frequency */
/* Only AT86RF212B supports multiple pages (PHY modes) */
uint8_t page; /**< currently used channel page */
#endif
uint8_t addr_short[2]; /**< the radio's short address */
uint8_t addr_long[8]; /**< the radio's long address */
@ -245,40 +237,38 @@ uint64_t at86rf2xx_get_addr_long(at86rf2xx_t *dev);
void at86rf2xx_set_addr_long(at86rf2xx_t *dev, uint64_t addr);
/**
* @brief Get the configured channel of the given device
* @brief Get the configured channel number of the given device
*
* @param[in] dev device to read from
*
* @return the currently set channel
* @return the currently set channel number
*/
uint8_t at86rf2xx_get_chan(at86rf2xx_t *dev);
/**
* @brief Set the channel of the given device
* @brief Set the channel number of the given device
*
* @param[in] dev device to write to
* @param[in] chan channel to set
* @param[in] chan channel number to set
*/
void at86rf2xx_set_chan(at86rf2xx_t *dev, uint8_t chan);
#ifdef MODULE_AT86RF212B
/**
* @brief Get the configured frequency of the given device
* @brief Get the configured channel page of the given device
*
* @param[in] dev device to read from
*
* @return the currently set frequency
* @return the currently set channel page
*/
at86rf2xx_freq_t at86rf2xx_get_freq(at86rf2xx_t *dev);
uint8_t at86rf2xx_get_page(at86rf2xx_t *dev);
/**
* @brief Set the frequency of the given device
* @brief Set the channel page of the given device
*
* @param[in] dev device to write to
* @param[in] chan frequency to set
* @param[in] page channel page to set
*/
void at86rf2xx_set_freq(at86rf2xx_t *dev, at86rf2xx_freq_t freq);
#endif
void at86rf2xx_set_page(at86rf2xx_t *dev, uint8_t page);
/**
* @brief Get the configured PAN ID of the given device
@ -358,7 +348,7 @@ uint8_t at86rf2xx_get_csma_max_retries(at86rf2xx_t *dev);
* Valid values: 0 to 5, -1 means CSMA disabled
*
* @param[in] dev device to write to
* @param[in] max the maximum number of retries
* @param[in] retries the maximum number of retries
*/
void at86rf2xx_set_csma_max_retries(at86rf2xx_t *dev, int8_t retries);