1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00
RIOT/drivers/cc110x/cc110x_calibration.c

138 lines
3.9 KiB
C
Raw Normal View History

drivers/cc110x: Rewrite of the cc110x driver The cc110x driver has been re-written from scratch to overcome the limitations of the old driver. The main motivation of the rewrite was to achieve better maintainability by a detailed documentation, reduce the complexity and the overhead of the SPI communication with the device, and to allow to simultaneously use transceivers with different configuration regarding the used base band, the channel bandwidth, the modulation rate, and the channel map. Features of this driver include: - Support for the CC1100, CC1101, and the CC1100e sub-gigahertz transceivers. - Detailed documentation of every aspect of this driver. - An easy to use configuration API that allows setting the transceiver configuration (modulation rate, channel bandwidth, base frequency) and the channel map. - Fast channel hopping by pre-calibration of the channels during device configuration (so that no calibration is needed during hopping). - Simplified SPI communication: Only during start-up the MCU has to wait for the transceiver to be ready (for the power regulators and the crystal to stabilize). The old driver did this for every SPI transfer, which resulted in complex communication code. This driver will wait on start up for the transceiver to power up and then use RIOT's SPI API like every other driver. (Not only the data sheet states that this is fine, it also proved to be reliable in practise.) - Greatly reduced latency: The RTT on the old driver (@150 kbps data rate) was about 16ms, the new driver (@250 kbps data rate) has as RTT of ~3ms (depending on SPI clock and on CPU performance) (measured with ping6). - Increased reliability: The preamble size and the sync word size have been doubled compared to the old driver (preamble: 8 bytes instead of 4, sync word: 4 byte instead of 2). The new values are the once recommended by the data sheet for reliable communication. - Basic diagnostic during driver initialization to detect common issues as SPI communication issues and GDO pin configuration/wiring issues. - TX power configuration with netdev_driver_t::set() API-integration - Calls to netdev_driver_t::send() block until the transmission has completed to ease the use of the API (implemented without busy waiting, so that the MCU can enter lower power states or other threads can be executed).
2018-11-08 17:37:07 +01:00
/*
* Copyright (C) 2018 Otto-von-Guericke-Universität Magdeburg
*
* 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_cc110x
drivers/cc110x: Rewrite of the cc110x driver The cc110x driver has been re-written from scratch to overcome the limitations of the old driver. The main motivation of the rewrite was to achieve better maintainability by a detailed documentation, reduce the complexity and the overhead of the SPI communication with the device, and to allow to simultaneously use transceivers with different configuration regarding the used base band, the channel bandwidth, the modulation rate, and the channel map. Features of this driver include: - Support for the CC1100, CC1101, and the CC1100e sub-gigahertz transceivers. - Detailed documentation of every aspect of this driver. - An easy to use configuration API that allows setting the transceiver configuration (modulation rate, channel bandwidth, base frequency) and the channel map. - Fast channel hopping by pre-calibration of the channels during device configuration (so that no calibration is needed during hopping). - Simplified SPI communication: Only during start-up the MCU has to wait for the transceiver to be ready (for the power regulators and the crystal to stabilize). The old driver did this for every SPI transfer, which resulted in complex communication code. This driver will wait on start up for the transceiver to power up and then use RIOT's SPI API like every other driver. (Not only the data sheet states that this is fine, it also proved to be reliable in practise.) - Greatly reduced latency: The RTT on the old driver (@150 kbps data rate) was about 16ms, the new driver (@250 kbps data rate) has as RTT of ~3ms (depending on SPI clock and on CPU performance) (measured with ping6). - Increased reliability: The preamble size and the sync word size have been doubled compared to the old driver (preamble: 8 bytes instead of 4, sync word: 4 byte instead of 2). The new values are the once recommended by the data sheet for reliable communication. - Basic diagnostic during driver initialization to detect common issues as SPI communication issues and GDO pin configuration/wiring issues. - TX power configuration with netdev_driver_t::set() API-integration - Calls to netdev_driver_t::send() block until the transmission has completed to ease the use of the API (implemented without busy waiting, so that the MCU can enter lower power states or other threads can be executed).
2018-11-08 17:37:07 +01:00
* @{
*
* @file
* @brief Implementation of the manual calibration facility of the
* CC1100/CC1101 driver
drivers/cc110x: Rewrite of the cc110x driver The cc110x driver has been re-written from scratch to overcome the limitations of the old driver. The main motivation of the rewrite was to achieve better maintainability by a detailed documentation, reduce the complexity and the overhead of the SPI communication with the device, and to allow to simultaneously use transceivers with different configuration regarding the used base band, the channel bandwidth, the modulation rate, and the channel map. Features of this driver include: - Support for the CC1100, CC1101, and the CC1100e sub-gigahertz transceivers. - Detailed documentation of every aspect of this driver. - An easy to use configuration API that allows setting the transceiver configuration (modulation rate, channel bandwidth, base frequency) and the channel map. - Fast channel hopping by pre-calibration of the channels during device configuration (so that no calibration is needed during hopping). - Simplified SPI communication: Only during start-up the MCU has to wait for the transceiver to be ready (for the power regulators and the crystal to stabilize). The old driver did this for every SPI transfer, which resulted in complex communication code. This driver will wait on start up for the transceiver to power up and then use RIOT's SPI API like every other driver. (Not only the data sheet states that this is fine, it also proved to be reliable in practise.) - Greatly reduced latency: The RTT on the old driver (@150 kbps data rate) was about 16ms, the new driver (@250 kbps data rate) has as RTT of ~3ms (depending on SPI clock and on CPU performance) (measured with ping6). - Increased reliability: The preamble size and the sync word size have been doubled compared to the old driver (preamble: 8 bytes instead of 4, sync word: 4 byte instead of 2). The new values are the once recommended by the data sheet for reliable communication. - Basic diagnostic during driver initialization to detect common issues as SPI communication issues and GDO pin configuration/wiring issues. - TX power configuration with netdev_driver_t::set() API-integration - Calls to netdev_driver_t::send() block until the transmission has completed to ease the use of the API (implemented without busy waiting, so that the MCU can enter lower power states or other threads can be executed).
2018-11-08 17:37:07 +01:00
*
* @author Marian Buschsieweke <marian.buschsieweke@ovgu.de>
drivers/cc110x: Rewrite of the cc110x driver The cc110x driver has been re-written from scratch to overcome the limitations of the old driver. The main motivation of the rewrite was to achieve better maintainability by a detailed documentation, reduce the complexity and the overhead of the SPI communication with the device, and to allow to simultaneously use transceivers with different configuration regarding the used base band, the channel bandwidth, the modulation rate, and the channel map. Features of this driver include: - Support for the CC1100, CC1101, and the CC1100e sub-gigahertz transceivers. - Detailed documentation of every aspect of this driver. - An easy to use configuration API that allows setting the transceiver configuration (modulation rate, channel bandwidth, base frequency) and the channel map. - Fast channel hopping by pre-calibration of the channels during device configuration (so that no calibration is needed during hopping). - Simplified SPI communication: Only during start-up the MCU has to wait for the transceiver to be ready (for the power regulators and the crystal to stabilize). The old driver did this for every SPI transfer, which resulted in complex communication code. This driver will wait on start up for the transceiver to power up and then use RIOT's SPI API like every other driver. (Not only the data sheet states that this is fine, it also proved to be reliable in practise.) - Greatly reduced latency: The RTT on the old driver (@150 kbps data rate) was about 16ms, the new driver (@250 kbps data rate) has as RTT of ~3ms (depending on SPI clock and on CPU performance) (measured with ping6). - Increased reliability: The preamble size and the sync word size have been doubled compared to the old driver (preamble: 8 bytes instead of 4, sync word: 4 byte instead of 2). The new values are the once recommended by the data sheet for reliable communication. - Basic diagnostic during driver initialization to detect common issues as SPI communication issues and GDO pin configuration/wiring issues. - TX power configuration with netdev_driver_t::set() API-integration - Calls to netdev_driver_t::send() block until the transmission has completed to ease the use of the API (implemented without busy waiting, so that the MCU can enter lower power states or other threads can be executed).
2018-11-08 17:37:07 +01:00
* @}
*/
#include <errno.h>
#include <stdint.h>
#include "periph/gpio.h"
#include "xtimer.h"
#include "cc110x.h"
#include "cc110x_internal.h"
2020-10-22 11:34:31 +02:00
#define ENABLE_DEBUG 0
drivers/cc110x: Rewrite of the cc110x driver The cc110x driver has been re-written from scratch to overcome the limitations of the old driver. The main motivation of the rewrite was to achieve better maintainability by a detailed documentation, reduce the complexity and the overhead of the SPI communication with the device, and to allow to simultaneously use transceivers with different configuration regarding the used base band, the channel bandwidth, the modulation rate, and the channel map. Features of this driver include: - Support for the CC1100, CC1101, and the CC1100e sub-gigahertz transceivers. - Detailed documentation of every aspect of this driver. - An easy to use configuration API that allows setting the transceiver configuration (modulation rate, channel bandwidth, base frequency) and the channel map. - Fast channel hopping by pre-calibration of the channels during device configuration (so that no calibration is needed during hopping). - Simplified SPI communication: Only during start-up the MCU has to wait for the transceiver to be ready (for the power regulators and the crystal to stabilize). The old driver did this for every SPI transfer, which resulted in complex communication code. This driver will wait on start up for the transceiver to power up and then use RIOT's SPI API like every other driver. (Not only the data sheet states that this is fine, it also proved to be reliable in practise.) - Greatly reduced latency: The RTT on the old driver (@150 kbps data rate) was about 16ms, the new driver (@250 kbps data rate) has as RTT of ~3ms (depending on SPI clock and on CPU performance) (measured with ping6). - Increased reliability: The preamble size and the sync word size have been doubled compared to the old driver (preamble: 8 bytes instead of 4, sync word: 4 byte instead of 2). The new values are the once recommended by the data sheet for reliable communication. - Basic diagnostic during driver initialization to detect common issues as SPI communication issues and GDO pin configuration/wiring issues. - TX power configuration with netdev_driver_t::set() API-integration - Calls to netdev_driver_t::send() block until the transmission has completed to ease the use of the API (implemented without busy waiting, so that the MCU can enter lower power states or other threads can be executed).
2018-11-08 17:37:07 +01:00
#include "debug.h"
/**
* @brief Read the calibration data from the transceiver and store it
drivers/cc110x: Rewrite of the cc110x driver The cc110x driver has been re-written from scratch to overcome the limitations of the old driver. The main motivation of the rewrite was to achieve better maintainability by a detailed documentation, reduce the complexity and the overhead of the SPI communication with the device, and to allow to simultaneously use transceivers with different configuration regarding the used base band, the channel bandwidth, the modulation rate, and the channel map. Features of this driver include: - Support for the CC1100, CC1101, and the CC1100e sub-gigahertz transceivers. - Detailed documentation of every aspect of this driver. - An easy to use configuration API that allows setting the transceiver configuration (modulation rate, channel bandwidth, base frequency) and the channel map. - Fast channel hopping by pre-calibration of the channels during device configuration (so that no calibration is needed during hopping). - Simplified SPI communication: Only during start-up the MCU has to wait for the transceiver to be ready (for the power regulators and the crystal to stabilize). The old driver did this for every SPI transfer, which resulted in complex communication code. This driver will wait on start up for the transceiver to power up and then use RIOT's SPI API like every other driver. (Not only the data sheet states that this is fine, it also proved to be reliable in practise.) - Greatly reduced latency: The RTT on the old driver (@150 kbps data rate) was about 16ms, the new driver (@250 kbps data rate) has as RTT of ~3ms (depending on SPI clock and on CPU performance) (measured with ping6). - Increased reliability: The preamble size and the sync word size have been doubled compared to the old driver (preamble: 8 bytes instead of 4, sync word: 4 byte instead of 2). The new values are the once recommended by the data sheet for reliable communication. - Basic diagnostic during driver initialization to detect common issues as SPI communication issues and GDO pin configuration/wiring issues. - TX power configuration with netdev_driver_t::set() API-integration - Calls to netdev_driver_t::send() block until the transmission has completed to ease the use of the API (implemented without busy waiting, so that the MCU can enter lower power states or other threads can be executed).
2018-11-08 17:37:07 +01:00
*
* @param dev Device descriptor of the transceiver
drivers/cc110x: Rewrite of the cc110x driver The cc110x driver has been re-written from scratch to overcome the limitations of the old driver. The main motivation of the rewrite was to achieve better maintainability by a detailed documentation, reduce the complexity and the overhead of the SPI communication with the device, and to allow to simultaneously use transceivers with different configuration regarding the used base band, the channel bandwidth, the modulation rate, and the channel map. Features of this driver include: - Support for the CC1100, CC1101, and the CC1100e sub-gigahertz transceivers. - Detailed documentation of every aspect of this driver. - An easy to use configuration API that allows setting the transceiver configuration (modulation rate, channel bandwidth, base frequency) and the channel map. - Fast channel hopping by pre-calibration of the channels during device configuration (so that no calibration is needed during hopping). - Simplified SPI communication: Only during start-up the MCU has to wait for the transceiver to be ready (for the power regulators and the crystal to stabilize). The old driver did this for every SPI transfer, which resulted in complex communication code. This driver will wait on start up for the transceiver to power up and then use RIOT's SPI API like every other driver. (Not only the data sheet states that this is fine, it also proved to be reliable in practise.) - Greatly reduced latency: The RTT on the old driver (@150 kbps data rate) was about 16ms, the new driver (@250 kbps data rate) has as RTT of ~3ms (depending on SPI clock and on CPU performance) (measured with ping6). - Increased reliability: The preamble size and the sync word size have been doubled compared to the old driver (preamble: 8 bytes instead of 4, sync word: 4 byte instead of 2). The new values are the once recommended by the data sheet for reliable communication. - Basic diagnostic during driver initialization to detect common issues as SPI communication issues and GDO pin configuration/wiring issues. - TX power configuration with netdev_driver_t::set() API-integration - Calls to netdev_driver_t::send() block until the transmission has completed to ease the use of the API (implemented without busy waiting, so that the MCU can enter lower power states or other threads can be executed).
2018-11-08 17:37:07 +01:00
*
* @pre @p dev is acquired using @p cc110x_acquire
drivers/cc110x: Rewrite of the cc110x driver The cc110x driver has been re-written from scratch to overcome the limitations of the old driver. The main motivation of the rewrite was to achieve better maintainability by a detailed documentation, reduce the complexity and the overhead of the SPI communication with the device, and to allow to simultaneously use transceivers with different configuration regarding the used base band, the channel bandwidth, the modulation rate, and the channel map. Features of this driver include: - Support for the CC1100, CC1101, and the CC1100e sub-gigahertz transceivers. - Detailed documentation of every aspect of this driver. - An easy to use configuration API that allows setting the transceiver configuration (modulation rate, channel bandwidth, base frequency) and the channel map. - Fast channel hopping by pre-calibration of the channels during device configuration (so that no calibration is needed during hopping). - Simplified SPI communication: Only during start-up the MCU has to wait for the transceiver to be ready (for the power regulators and the crystal to stabilize). The old driver did this for every SPI transfer, which resulted in complex communication code. This driver will wait on start up for the transceiver to power up and then use RIOT's SPI API like every other driver. (Not only the data sheet states that this is fine, it also proved to be reliable in practise.) - Greatly reduced latency: The RTT on the old driver (@150 kbps data rate) was about 16ms, the new driver (@250 kbps data rate) has as RTT of ~3ms (depending on SPI clock and on CPU performance) (measured with ping6). - Increased reliability: The preamble size and the sync word size have been doubled compared to the old driver (preamble: 8 bytes instead of 4, sync word: 4 byte instead of 2). The new values are the once recommended by the data sheet for reliable communication. - Basic diagnostic during driver initialization to detect common issues as SPI communication issues and GDO pin configuration/wiring issues. - TX power configuration with netdev_driver_t::set() API-integration - Calls to netdev_driver_t::send() block until the transmission has completed to ease the use of the API (implemented without busy waiting, so that the MCU can enter lower power states or other threads can be executed).
2018-11-08 17:37:07 +01:00
*/
static inline void get_calibration_data(cc110x_t *dev)
{
char caldata[3];
cc110x_burst_read(dev, CC110X_REG_FSCAL3, caldata, sizeof(caldata));
dev->fscal.fscal3 = caldata[0];
dev->fscal.fscal2 = caldata[1];
dev->fscal.fscal1[dev->channel] = caldata[2];
}
int cc110x_recalibrate(cc110x_t *dev)
{
/* Sadly we cannot use GDO0 to check for calibration, as it only
* provides output in RX/TX state. But after successful manual
* calibration, the device returns to IDLE state. Thus, we keep
* calibrating until IDLE state is reached
*/
do {
/* Start calibration */
cc110x_cmd(dev, CC110X_STROBE_CALIBRATE);
/* Release SPI interface to give other threads a chance to use it */
cc110x_release(dev);
/* Manual calibration take 735 micro seconds (see Table 34 on page
* 54 in the date sheet). We'll wait 750 to be sure
*/
xtimer_usleep(750);
/* Re-acquire SPI interface in order to check if calibration
* succeeded
*/
2021-02-01 14:25:22 +01:00
cc110x_acquire(dev);
drivers/cc110x: Rewrite of the cc110x driver The cc110x driver has been re-written from scratch to overcome the limitations of the old driver. The main motivation of the rewrite was to achieve better maintainability by a detailed documentation, reduce the complexity and the overhead of the SPI communication with the device, and to allow to simultaneously use transceivers with different configuration regarding the used base band, the channel bandwidth, the modulation rate, and the channel map. Features of this driver include: - Support for the CC1100, CC1101, and the CC1100e sub-gigahertz transceivers. - Detailed documentation of every aspect of this driver. - An easy to use configuration API that allows setting the transceiver configuration (modulation rate, channel bandwidth, base frequency) and the channel map. - Fast channel hopping by pre-calibration of the channels during device configuration (so that no calibration is needed during hopping). - Simplified SPI communication: Only during start-up the MCU has to wait for the transceiver to be ready (for the power regulators and the crystal to stabilize). The old driver did this for every SPI transfer, which resulted in complex communication code. This driver will wait on start up for the transceiver to power up and then use RIOT's SPI API like every other driver. (Not only the data sheet states that this is fine, it also proved to be reliable in practise.) - Greatly reduced latency: The RTT on the old driver (@150 kbps data rate) was about 16ms, the new driver (@250 kbps data rate) has as RTT of ~3ms (depending on SPI clock and on CPU performance) (measured with ping6). - Increased reliability: The preamble size and the sync word size have been doubled compared to the old driver (preamble: 8 bytes instead of 4, sync word: 4 byte instead of 2). The new values are the once recommended by the data sheet for reliable communication. - Basic diagnostic during driver initialization to detect common issues as SPI communication issues and GDO pin configuration/wiring issues. - TX power configuration with netdev_driver_t::set() API-integration - Calls to netdev_driver_t::send() block until the transmission has completed to ease the use of the API (implemented without busy waiting, so that the MCU can enter lower power states or other threads can be executed).
2018-11-08 17:37:07 +01:00
} while (cc110x_state_from_status(cc110x_status(dev)) != CC110X_STATE_IDLE);
get_calibration_data(dev);
return 0;
}
int cc110x_full_calibration(cc110x_t *dev)
{
DEBUG("[cc110x] Obtaining calibration data for fast channel hopping\n");
if (!dev) {
return -EINVAL;
}
2021-02-01 14:25:22 +01:00
cc110x_acquire(dev);
drivers/cc110x: Rewrite of the cc110x driver The cc110x driver has been re-written from scratch to overcome the limitations of the old driver. The main motivation of the rewrite was to achieve better maintainability by a detailed documentation, reduce the complexity and the overhead of the SPI communication with the device, and to allow to simultaneously use transceivers with different configuration regarding the used base band, the channel bandwidth, the modulation rate, and the channel map. Features of this driver include: - Support for the CC1100, CC1101, and the CC1100e sub-gigahertz transceivers. - Detailed documentation of every aspect of this driver. - An easy to use configuration API that allows setting the transceiver configuration (modulation rate, channel bandwidth, base frequency) and the channel map. - Fast channel hopping by pre-calibration of the channels during device configuration (so that no calibration is needed during hopping). - Simplified SPI communication: Only during start-up the MCU has to wait for the transceiver to be ready (for the power regulators and the crystal to stabilize). The old driver did this for every SPI transfer, which resulted in complex communication code. This driver will wait on start up for the transceiver to power up and then use RIOT's SPI API like every other driver. (Not only the data sheet states that this is fine, it also proved to be reliable in practise.) - Greatly reduced latency: The RTT on the old driver (@150 kbps data rate) was about 16ms, the new driver (@250 kbps data rate) has as RTT of ~3ms (depending on SPI clock and on CPU performance) (measured with ping6). - Increased reliability: The preamble size and the sync word size have been doubled compared to the old driver (preamble: 8 bytes instead of 4, sync word: 4 byte instead of 2). The new values are the once recommended by the data sheet for reliable communication. - Basic diagnostic during driver initialization to detect common issues as SPI communication issues and GDO pin configuration/wiring issues. - TX power configuration with netdev_driver_t::set() API-integration - Calls to netdev_driver_t::send() block until the transmission has completed to ease the use of the API (implemented without busy waiting, so that the MCU can enter lower power states or other threads can be executed).
2018-11-08 17:37:07 +01:00
switch (dev->state) {
case CC110X_STATE_IDLE:
/* falls through */
case CC110X_STATE_RX_MODE:
/* falls through */
case CC110X_STATE_FSTXON:
/* Current state is fine for deliberate calibration */
break;
default:
/* Current state prevents deliberate calibration */
cc110x_release(dev);
return -EAGAIN;
}
uint8_t old_channel = dev->channel;
/* Disable interrupts on GDO pins */
gpio_irq_disable(dev->params.gdo0);
gpio_irq_disable(dev->params.gdo2);
/* While waiting for calibration to be done, another thread could
* be scheduled. Setting the state should prevent other threads from
* messing around with the driver
*/
dev->state = CC110X_STATE_CALIBRATE;
/* Go to IDLE to allow setting the channel */
cc110x_cmd(dev, CC110X_STROBE_IDLE);
for (dev->channel = 0; dev->channel < CC110X_MAX_CHANNELS; dev->channel++) {
uint8_t phy_chan = dev->channels->map[dev->channel];
if (phy_chan == 0xff) {
/* Channel not supported by channel map */
continue;
}
/* Set the channel to calibrate for fast hopping */
cc110x_write(dev, CC110X_REG_CHANNR, phy_chan);
if (cc110x_recalibrate(dev)) {
/* cc110x_recalibrate() release device on error */
return -EIO;
}
}
/* Update device to reflect current transceiver state */
dev->state = CC110X_STATE_IDLE;
cc110x_release(dev);
/* Hop back to old channel, IRQs are restored by cc110x_set_channel */
return cc110x_set_channel(dev, old_channel);
}