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.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
2019-09-04 13:15:15 +02:00
|
|
|
* @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
|
2019-09-04 13:15:15 +02:00
|
|
|
* @brief Functions to manage sending/receiving frames with the 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
|
|
|
*
|
2019-09-04 13:15:15 +02: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 "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"
|
|
|
|
|
|
|
|
/* Use NETDEV_EVENT_ISR to indicate that no event needs to be passed to upper
|
|
|
|
* layer at end of ISR, as ISR will never need this event
|
|
|
|
*/
|
|
|
|
#define NETDEV_NO_EVENT NETDEV_EVENT_ISR
|
|
|
|
|
|
|
|
void cc110x_enter_rx_mode(cc110x_t *dev)
|
|
|
|
{
|
|
|
|
DEBUG("[cc110x] Going to RX\n");
|
|
|
|
/* bring device to IDLE state and flush FIFOs (just in case) */
|
|
|
|
gpio_irq_disable(dev->params.gdo0);
|
|
|
|
gpio_irq_disable(dev->params.gdo2);
|
|
|
|
cc110x_cmd(dev, CC110X_STROBE_IDLE);
|
|
|
|
cc110x_cmd(dev, CC110X_STROBE_FLUSH_RX);
|
|
|
|
cc110x_cmd(dev, CC110X_STROBE_FLUSH_TX);
|
|
|
|
dev->buf.pos = dev->buf.len = 0;
|
|
|
|
/* Apply GDO2 config and go to RX */
|
|
|
|
cc110x_write(dev, CC110X_REG_IOCFG2, CC110X_GDO_ON_RX_DATA);
|
|
|
|
cc110x_write(dev, CC110X_REG_IOCFG0, CC110X_GDO_ON_TRANSMISSION);
|
|
|
|
cc110x_cmd(dev, CC110X_STROBE_RX);
|
|
|
|
dev->state = CC110X_STATE_RX_MODE;
|
|
|
|
gpio_irq_enable(dev->params.gdo2);
|
|
|
|
gpio_irq_enable(dev->params.gdo0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2019-09-04 13:15:15 +02:00
|
|
|
* @brief Function to run when frame is fully received
|
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
|
|
|
*
|
2019-09-04 13:15:15 +02: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
|
|
|
*
|
|
|
|
* Intended to be called from @ref cc110x_rx_continue
|
|
|
|
*/
|
|
|
|
static netdev_event_t cc110x_rx_done(cc110x_t *dev)
|
|
|
|
{
|
|
|
|
uint8_t lqi_crc;
|
|
|
|
int8_t rssi;
|
|
|
|
|
|
|
|
cc110x_read(dev, CC110X_REG_LQI, &lqi_crc);
|
|
|
|
cc110x_read(dev, CC110X_REG_RSSI, (uint8_t *)&rssi);
|
|
|
|
|
|
|
|
/* CRC_OK bit is most significant bit, see page 92 in the data sheet */
|
|
|
|
if (!(lqi_crc & 0x80)) {
|
|
|
|
DEBUG("[cc110x] ISR: CRC error, dropping frame\n");
|
|
|
|
/* Drop frame and go back to RX */
|
|
|
|
cc110x_enter_rx_mode(dev);
|
|
|
|
return NETDEV_EVENT_CRC_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Copy all but the CRC_OK bit */
|
|
|
|
dev->rx_info.lqi = (uint8_t)lqi_crc & 0x7f;
|
|
|
|
|
|
|
|
/* Use the formula in section 17.3 on page 44 in the data sheet to obtain
|
|
|
|
* the correct RSSI value in dBm.
|
|
|
|
*/
|
|
|
|
dev->rx_info.rssi = (int16_t)(rssi / 2) - (int16_t)dev->rssi_offset;
|
|
|
|
|
|
|
|
/* Transceiver has automatically gone to IDLE. We keep it in IDLE until
|
|
|
|
* upper layer fetched the frame
|
|
|
|
*/
|
|
|
|
dev->state = CC110X_STATE_FRAME_READY;
|
|
|
|
return NETDEV_EVENT_RX_COMPLETE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2019-09-04 13:15:15 +02:00
|
|
|
* @brief Read a chunk of data from the RX-FIFO
|
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
|
|
|
*
|
2019-09-04 13:15:15 +02: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
|
|
|
*
|
|
|
|
* This function should be called from the ISR when data in the RX-FIFO is
|
|
|
|
* available or the last byte of the frame was received
|
|
|
|
*/
|
|
|
|
static netdev_event_t cc110x_rx_continue(cc110x_t *dev)
|
|
|
|
{
|
|
|
|
uint8_t in_fifo;
|
|
|
|
netdev_event_t retval = NETDEV_NO_EVENT;
|
|
|
|
|
|
|
|
while (gpio_read(dev->params.gdo2)) {
|
|
|
|
cc110x_read_reliable(dev, CC110X_REG_RXBYTES, &in_fifo);
|
|
|
|
|
|
|
|
if (in_fifo & 0x80) {
|
|
|
|
/* RXFIFO_OVERFLOW bit is set (see RXBYTES on page 94) */
|
|
|
|
DEBUG("[cc110x] ISR: RX-FIFO overflown, ISR too slow\n");
|
|
|
|
/* Drop frame and go to RX */
|
|
|
|
cc110x_enter_rx_mode(dev);
|
|
|
|
return NETDEV_EVENT_RX_TIMEOUT;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!in_fifo) {
|
|
|
|
/* GDO2 will be high when data is present *or* at end of packet */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Handle first read from RX FIFO differently from subsequent reads, as
|
|
|
|
* in first reads the Length Field is read as well
|
|
|
|
*/
|
|
|
|
if (!dev->buf.len) {
|
|
|
|
if (in_fifo < sizeof(cc1xxx_l2hdr_t) + 1) {
|
|
|
|
/* At least a frame header + Length Field (1B) is expected */
|
|
|
|
DEBUG("[cc110x] ISR: Incoming frame smaller than header "
|
|
|
|
"--> drop\n");
|
|
|
|
cc110x_enter_rx_mode(dev);
|
|
|
|
/* Not exactly CRC, but incorrect CRC indicates a broken frame*/
|
|
|
|
return NETDEV_EVENT_CRC_ERROR;
|
|
|
|
}
|
|
|
|
cc110x_burst_read(dev, CC110X_MULTIREG_FIFO, &dev->buf,
|
|
|
|
in_fifo - 1);
|
|
|
|
/* Update read position in payload, that is number of bytes read
|
|
|
|
* minus the Length Filed and minus the byte left in the FIFO to not
|
|
|
|
* trigger a silicon bug
|
|
|
|
*/
|
|
|
|
dev->buf.pos = in_fifo - 2;
|
|
|
|
retval = NETDEV_EVENT_RX_STARTED;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* Prevent overflow of buffer */
|
|
|
|
if (dev->buf.pos + in_fifo > CC110X_MAX_FRAME_SIZE) {
|
|
|
|
DEBUG("[cc110x] ISR: Incoming frame exceeds maximum size\n");
|
|
|
|
cc110x_enter_rx_mode(dev);
|
|
|
|
/* Not exactly CRC, but incorrect CRC indicates a broken frame */
|
|
|
|
return NETDEV_EVENT_CRC_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dev->buf.pos + in_fifo < dev->buf.len) {
|
|
|
|
/* Frame not fully received yet, keeping one byte in RX FIFO
|
|
|
|
* to prevent triggering a silicon bug
|
|
|
|
*/
|
|
|
|
in_fifo--;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Continue reading data */
|
|
|
|
cc110x_burst_read(dev, CC110X_MULTIREG_FIFO,
|
|
|
|
dev->buf.data + dev->buf.pos, in_fifo);
|
|
|
|
dev->buf.pos += in_fifo;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dev->buf.pos > dev->buf.len) {
|
|
|
|
DEBUG("[cc110x] ISR: Incoming frame larger than Length Field "
|
|
|
|
"--> drop\n");
|
|
|
|
cc110x_enter_rx_mode(dev);
|
|
|
|
/* Not exactly CRC, but incorrect CRC indicates a broken frame */
|
|
|
|
return NETDEV_EVENT_CRC_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!gpio_read(dev->params.gdo0)) {
|
|
|
|
/* GDO0 is low when transmission is over ==> RX complete or corrupt
|
|
|
|
frame */
|
|
|
|
if (dev->buf.pos == dev->buf.len) {
|
|
|
|
return cc110x_rx_done(dev);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
DEBUG("[cc110x] ISR: Incoming frame smaller than Length Field "
|
|
|
|
"--> drop\n");
|
|
|
|
cc110x_enter_rx_mode(dev);
|
|
|
|
/* Not exactly CRC, but incorrect CRC indicates a broken frame */
|
|
|
|
return NETDEV_EVENT_CRC_ERROR;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2019-09-04 13:15:15 +02:00
|
|
|
* @brief Function to run when frame is fully send
|
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
|
|
|
*
|
2019-09-04 13:15:15 +02: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
|
|
|
*/
|
|
|
|
static netdev_event_t cc110x_tx_done(cc110x_t *dev)
|
|
|
|
{
|
|
|
|
uint8_t status = cc110x_status(dev);
|
|
|
|
cc110x_state_t state = cc110x_state_from_status(status);
|
|
|
|
switch (state){
|
|
|
|
case CC110X_STATE_SETTLING:
|
|
|
|
case CC110X_STATE_CALIBRATE:
|
|
|
|
case CC110X_STATE_TX_MODE:
|
|
|
|
/* TX still in progress, or hasn't even started yet */
|
|
|
|
return NETDEV_NO_EVENT;
|
|
|
|
case CC110X_STATE_IDLE:
|
|
|
|
cc110x_enter_rx_mode(dev);
|
|
|
|
return NETDEV_EVENT_TX_COMPLETE;
|
|
|
|
case CC110X_STATE_TXFIFO_UNDERFLOW:
|
|
|
|
DEBUG("[cc110x] ISR: TX FIFO underflown.\n");
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
DEBUG("[cc110x] ISR: Unknown state during TX.\n");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
cc110x_enter_rx_mode(dev);
|
|
|
|
/* TX timeout is the only TX-related error event known to RIOT */
|
|
|
|
return NETDEV_EVENT_TX_TIMEOUT;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2019-09-04 13:15:15 +02:00
|
|
|
* @brief Refill the TX-FIFO
|
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
|
|
|
*
|
2019-09-04 13:15:15 +02: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
|
|
|
*/
|
|
|
|
static netdev_event_t cc110x_tx_continue(cc110x_t *dev)
|
|
|
|
{
|
|
|
|
uint8_t in_fifo;
|
|
|
|
|
|
|
|
cc110x_read_reliable(dev, CC110X_REG_TXBYTES, &in_fifo);
|
|
|
|
|
|
|
|
/* most significant bit indicates TXFIFO underflow, see page 94 in the
|
|
|
|
* data sheet
|
|
|
|
*/
|
|
|
|
if (in_fifo & 0x80) {
|
|
|
|
DEBUG("[cc110x] ISR: ERROR: TX-FIFO underflown, ISR too slow\n");
|
|
|
|
/* Abort: Flush TX and go back to RX */
|
|
|
|
cc110x_cmd(dev, CC110X_STROBE_IDLE);
|
|
|
|
cc110x_cmd(dev, CC110X_STROBE_FLUSH_TX);
|
|
|
|
cc110x_enter_rx_mode(dev);
|
|
|
|
return NETDEV_EVENT_TX_TIMEOUT;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t to_write = CC110X_FIFO_SIZE - in_fifo;
|
|
|
|
|
|
|
|
if (to_write == 0) {
|
|
|
|
/* ISR came to early, nothing to do yet */
|
|
|
|
return NETDEV_NO_EVENT;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t left = dev->buf.len - dev->buf.pos;
|
|
|
|
to_write = (left < to_write) ? left : to_write;
|
|
|
|
|
|
|
|
cc110x_burst_write(dev, CC110X_MULTIREG_FIFO,
|
|
|
|
dev->buf.data + dev->buf.pos, to_write);
|
|
|
|
dev->buf.pos += to_write;
|
|
|
|
|
|
|
|
if (dev->buf.pos == dev->buf.len) {
|
|
|
|
/* All data send to the transceiver, now waiting for transceiver to
|
|
|
|
* complete transmission
|
|
|
|
*/
|
|
|
|
dev->state = CC110X_STATE_TX_COMPLETING;
|
|
|
|
/* Disable GDO2, as we do not need to further feed TX FIFO */
|
|
|
|
cc110x_write(dev, CC110X_REG_IOCFG2, CC110X_GDO_CONSTANT_LOW);
|
|
|
|
}
|
|
|
|
|
|
|
|
return NETDEV_NO_EVENT;
|
|
|
|
}
|
|
|
|
|
|
|
|
void cc110x_isr(netdev_t *netdev)
|
|
|
|
{
|
|
|
|
cc110x_t *dev = (cc110x_t *)netdev;
|
|
|
|
/* We don't want to create events while device descriptor is acquired, to
|
|
|
|
* prevent a dead lock. (Currently e.g. on NETDEV_EVENT_RX_COMPLETE the
|
|
|
|
* upper layer will immediately call netdev_driver_t::recv(), which in
|
|
|
|
* turn wants to operate on the device descriptor. We could rely on this
|
|
|
|
* behaviour by skipping cc110x_acquire() there, but the driver would break
|
|
|
|
* when upper layer behaviour is changed. By moving the event notification
|
|
|
|
* at the end of the ISR (end after cc110x_release()), the driver becomes
|
|
|
|
* agnostic to which behaviour the upper layer implements.)
|
|
|
|
*/
|
|
|
|
netdev_event_t post_isr_event = NETDEV_NO_EVENT;
|
|
|
|
|
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
|
|
|
|
|
|
|
/* Disable IRQs in a coarse manner, instead of doing so any time the
|
|
|
|
* IOCFGx configuration registers are changed. (This should be less
|
|
|
|
* bug prone.)
|
|
|
|
*/
|
|
|
|
gpio_irq_disable(dev->params.gdo0);
|
|
|
|
gpio_irq_disable(dev->params.gdo2);
|
|
|
|
|
|
|
|
switch (dev->state) {
|
|
|
|
case CC110X_STATE_RX_MODE:
|
|
|
|
if (gpio_read(dev->params.gdo0) || gpio_read(dev->params.gdo2)) {
|
|
|
|
dev->state = CC110X_STATE_RECEIVING;
|
|
|
|
dev->buf.pos = dev->buf.len = 0;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case CC110X_STATE_RECEIVING:
|
|
|
|
post_isr_event = cc110x_rx_continue(dev);
|
|
|
|
break;
|
|
|
|
case CC110X_STATE_TX_MODE:
|
|
|
|
post_isr_event = cc110x_tx_continue(dev);
|
|
|
|
break;
|
|
|
|
case CC110X_STATE_TX_COMPLETING:
|
|
|
|
post_isr_event = cc110x_tx_done(dev);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
DEBUG("[cc110x] ISR: CRITICAL ERROR: No interrupt expected "
|
|
|
|
"for current state\n");
|
|
|
|
/* Go back to RX and pray that solved the problem */
|
|
|
|
cc110x_enter_rx_mode(dev);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Re-enable IRQs again, unless device state */
|
|
|
|
gpio_irq_enable(dev->params.gdo0);
|
|
|
|
gpio_irq_enable(dev->params.gdo2);
|
|
|
|
cc110x_release(dev);
|
2023-05-01 21:16:11 +02:00
|
|
|
/* Pass event to upper layer, if needed */
|
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
|
|
|
if (post_isr_event != NETDEV_NO_EVENT) {
|
|
|
|
dev->netdev.event_callback(&dev->netdev, post_isr_event);
|
|
|
|
}
|
|
|
|
}
|