Driver for TI's CC1200 radio ICs. Forget hardcoded register settings -- this driver calculates everything from scratch!

Dependents:   CC1200-MorseEncoder CC1200-Examples

CC1200 Driver

by Jamie Smith / USC Rocket Propulsion Lab

After months of work, we are proud to present our driver for Texas Instruments' CC1200 digital radio IC! This driver has been written from scratch to be an easy and flexible way of using this radio transceiver. For our application, we needed to be able to tune each and every setting of the radio to try and eke that last bit of performance of our system - so using premade configurations alone wasn't going to cut it! Instead, this driver calculates each parameter of the radio using the equations and instructions given in the datasheet. So, you can tweak parameters to your heart's content, and you shouldn't have to do any math yourself!

Features

  • Automatic calculation of correct register values for:
    • RF frequency
    • FSK deviation
    • Symbol rate
    • Output power
    • RX filter bandwidth (this one's harder than it looks!)
  • Easy handling of data packets
  • GPIO configuration
  • Preamble and sync word configuration
  • RTOS compatible (always locks SPI bus during transactions)
  • Two debug levels available
  • RSSI and LQI support

Not Supported

  • Transparent mode
  • FM mode
  • ASK parameter configuration
  • Frequency offsets

Examples

  • See the example project here for an example of how to use the driver.
  • Another example (using a more exotic configuration) is the CC1200-MorseEncoder.

Changelog

Version 1.2 May 3 2021

  • Added unfinished infinite length packet support via the readStream() and writeStream() functions. The API is complete and basic usage works but there's still a bug I haven't been able to track down yet where incorrect data is transmitted at the end of a stream. Use with caution!
  • Added preferHigherCICDec parameter to setRXFilterBandwidth
  • Removed setIFMixCFG() (which takes a byte parameter) and replaced it with setIFCfg(), which takes documented enum class values.
  • Added setAGCSettleWait(), which per my testing is needed for correct 430MHz operation.
  • Added support for reading RSSI and LQI values, both from packet appended status bytes and from the registers.
  • Update 430MHz black box registers based on SmartRF values
  • Removed setIQMismatchCompensationEnabled(). This call has been replaced by the new 2nd parameter to setIFCfg().

Version 1.1 Aug 28 2020

  • Add fixed length packet support and other features needed for Morse support.
  • Fix bug causing weird behavior with low sample rates (<1ksps).

NOTE: you must now call setPacketMode() when configuring the radio.

Version 1.0 Aug 10 2020

Initial Release

Committer:
Jamie Smith
Date:
Tue Jun 30 02:26:28 2020 -0700
Revision:
0:0c3532738887
Child:
1:98af824b145e
Add initial version of driver

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Jamie Smith 0:0c3532738887 1 //
Jamie Smith 0:0c3532738887 2 // Created by jamie on 3/27/2020.
Jamie Smith 0:0c3532738887 3 //
Jamie Smith 0:0c3532738887 4
Jamie Smith 0:0c3532738887 5 #ifndef LIGHTSPEEDRANGEFINDER_CC1200_H
Jamie Smith 0:0c3532738887 6 #define LIGHTSPEEDRANGEFINDER_CC1200_H
Jamie Smith 0:0c3532738887 7
Jamie Smith 0:0c3532738887 8 #include <mbed.h>
Jamie Smith 0:0c3532738887 9
Jamie Smith 0:0c3532738887 10 #include <cstdint>
Jamie Smith 0:0c3532738887 11
Jamie Smith 0:0c3532738887 12 /**
Jamie Smith 0:0c3532738887 13 * Base driver for the CC1200 radio communications IC.
Jamie Smith 0:0c3532738887 14 * This class provides basic functions and register level IO with the chip.
Jamie Smith 0:0c3532738887 15 */
Jamie Smith 0:0c3532738887 16 class CC1200
Jamie Smith 0:0c3532738887 17 {
Jamie Smith 0:0c3532738887 18 // connections to chip
Jamie Smith 0:0c3532738887 19 SPI spi;
Jamie Smith 0:0c3532738887 20 DigitalOut rst;
Jamie Smith 0:0c3532738887 21
Jamie Smith 0:0c3532738887 22 // Output to print debug messages to
Jamie Smith 0:0c3532738887 23 Stream * debugStream;
Jamie Smith 0:0c3532738887 24
Jamie Smith 0:0c3532738887 25 public:
Jamie Smith 0:0c3532738887 26
Jamie Smith 0:0c3532738887 27 // register definitions
Jamie Smith 0:0c3532738887 28 enum class Register : uint8_t
Jamie Smith 0:0c3532738887 29 {
Jamie Smith 0:0c3532738887 30 IOCFG3 = 0x00,
Jamie Smith 0:0c3532738887 31 IOCFG2 = 0x01,
Jamie Smith 0:0c3532738887 32 IOCFG1 = 0x02,
Jamie Smith 0:0c3532738887 33 IOCFG0 = 0x03,
Jamie Smith 0:0c3532738887 34 SYNC3 = 0x4,
Jamie Smith 0:0c3532738887 35 SYNC2 = 0x5,
Jamie Smith 0:0c3532738887 36 SYNC1 = 0x6,
Jamie Smith 0:0c3532738887 37 SYNC0 = 0x7,
Jamie Smith 0:0c3532738887 38 SYNC_CFG1 = 0x8,
Jamie Smith 0:0c3532738887 39 SYNC_CFG0 = 0x9,
Jamie Smith 0:0c3532738887 40 DEVIATION_M = 0xA,
Jamie Smith 0:0c3532738887 41 MODCFG_DEV_E = 0xB,
Jamie Smith 0:0c3532738887 42 DCFILT_CFG = 0xC,
Jamie Smith 0:0c3532738887 43 PREAMBLE_CFG1 = 0xD,
Jamie Smith 0:0c3532738887 44 PREAMBLE_CFG0 = 0xE,
Jamie Smith 0:0c3532738887 45 IQIC = 0xF,
Jamie Smith 0:0c3532738887 46 CHAN_BW = 0x10,
Jamie Smith 0:0c3532738887 47 MDMCFG1 = 0x11,
Jamie Smith 0:0c3532738887 48 MDMCFG0 = 0x12,
Jamie Smith 0:0c3532738887 49 SYMBOL_RATE2 = 0x13,
Jamie Smith 0:0c3532738887 50 SYMBOL_RATE1 = 0x14,
Jamie Smith 0:0c3532738887 51 SYMBOL_RATE0 = 0x15,
Jamie Smith 0:0c3532738887 52 AGC_REF = 0x16,
Jamie Smith 0:0c3532738887 53 AGC_CS_THR = 0x17,
Jamie Smith 0:0c3532738887 54 AGC_GAIN_ADJUST = 0x18,
Jamie Smith 0:0c3532738887 55 AGC_CFG3 = 0x19,
Jamie Smith 0:0c3532738887 56 AGC_CFG2 = 0x1A,
Jamie Smith 0:0c3532738887 57 AGC_CFG1 = 0x1B,
Jamie Smith 0:0c3532738887 58 AGC_CFG0 = 0x1C,
Jamie Smith 0:0c3532738887 59 FIFO_CFG = 0x1D,
Jamie Smith 0:0c3532738887 60 DEV_ADDR = 0x1E,
Jamie Smith 0:0c3532738887 61 SETTLING_CFG = 0x1F,
Jamie Smith 0:0c3532738887 62 FS_CFG = 0x20,
Jamie Smith 0:0c3532738887 63 WOR_CFG1 = 0x21,
Jamie Smith 0:0c3532738887 64 WOR_CFG0 = 0x22,
Jamie Smith 0:0c3532738887 65 WOR_EVENT0_MSB = 0x23,
Jamie Smith 0:0c3532738887 66 WOR_EVENT0_LSB = 0x24,
Jamie Smith 0:0c3532738887 67 RXDCM_TIME = 0x25,
Jamie Smith 0:0c3532738887 68 PKT_CFG2 = 0x26,
Jamie Smith 0:0c3532738887 69 PKT_CFG1 = 0x27,
Jamie Smith 0:0c3532738887 70 PKT_CFG0 = 0x28,
Jamie Smith 0:0c3532738887 71 RFEND_CFG1 = 0x29,
Jamie Smith 0:0c3532738887 72 RFEND_CFG0 = 0x2A,
Jamie Smith 0:0c3532738887 73 PA_CFG1 = 0x2B,
Jamie Smith 0:0c3532738887 74 PA_CFG0 = 0x2C,
Jamie Smith 0:0c3532738887 75 ASK_CFG = 0x2D,
Jamie Smith 0:0c3532738887 76 PKT_LEN = 0x2E
Jamie Smith 0:0c3532738887 77 };
Jamie Smith 0:0c3532738887 78
Jamie Smith 0:0c3532738887 79 // extended register definitions
Jamie Smith 0:0c3532738887 80 enum class ExtRegister : uint8_t
Jamie Smith 0:0c3532738887 81 {
Jamie Smith 0:0c3532738887 82 IF_MIX_CFG = 0x0,
Jamie Smith 0:0c3532738887 83 FREQOFF_CFG = 0x1,
Jamie Smith 0:0c3532738887 84 TOC_CFG = 0x2,
Jamie Smith 0:0c3532738887 85 //...
Jamie Smith 0:0c3532738887 86 MDMCFG2 = 0x5,
Jamie Smith 0:0c3532738887 87 //...
Jamie Smith 0:0c3532738887 88 FREQOFF1 = 0xA,
Jamie Smith 0:0c3532738887 89 FREQOFF2 = 0xB,
Jamie Smith 0:0c3532738887 90 FREQ2 = 0xC,
Jamie Smith 0:0c3532738887 91 FREQ1 = 0xD,
Jamie Smith 0:0c3532738887 92 FREQ0 = 0xE,
Jamie Smith 0:0c3532738887 93 IF_ADC2 = 0xF,
Jamie Smith 0:0c3532738887 94 IF_ADC1 = 0x10,
Jamie Smith 0:0c3532738887 95 IF_ADC0 = 0x11,
Jamie Smith 0:0c3532738887 96 FS_DIG1 = 0x12,
Jamie Smith 0:0c3532738887 97 FS_DIG0 = 0x13,
Jamie Smith 0:0c3532738887 98 //...
Jamie Smith 0:0c3532738887 99 FS_CAL1 = 0x16,
Jamie Smith 0:0c3532738887 100 FS_CAL0 = 0x17,
Jamie Smith 0:0c3532738887 101 FS_CHP = 0x18,
Jamie Smith 0:0c3532738887 102 FS_DIVTWO = 0x19,
Jamie Smith 0:0c3532738887 103 FS_DSM1 = 0x1A,
Jamie Smith 0:0c3532738887 104 FS_DSM0 = 0x1B,
Jamie Smith 0:0c3532738887 105 FS_DVC1 = 0x1C,
Jamie Smith 0:0c3532738887 106 FS_DVC0 = 0x1D,
Jamie Smith 0:0c3532738887 107 FS_LBI = 0x1E,
Jamie Smith 0:0c3532738887 108 FS_PFD = 0x1F,
Jamie Smith 0:0c3532738887 109 FS_PRE = 0x20,
Jamie Smith 0:0c3532738887 110 FS_REG_DIV_CML = 0x21,
Jamie Smith 0:0c3532738887 111 FS_SPARE = 0x22,
Jamie Smith 0:0c3532738887 112 FS_VCO4 = 0x23,
Jamie Smith 0:0c3532738887 113 FS_VCO3 = 0x24,
Jamie Smith 0:0c3532738887 114 FS_VCO2 = 0x25,
Jamie Smith 0:0c3532738887 115 FS_VCO1 = 0x26,
Jamie Smith 0:0c3532738887 116 FS_VCO0 = 0x27,
Jamie Smith 0:0c3532738887 117 //...
Jamie Smith 0:0c3532738887 118 IFAMP = 0x2F,
Jamie Smith 0:0c3532738887 119 //..
Jamie Smith 0:0c3532738887 120 XOSC5 = 0x32,
Jamie Smith 0:0c3532738887 121 XOSC4 = 0x33,
Jamie Smith 0:0c3532738887 122 XOSC3 = 0x34,
Jamie Smith 0:0c3532738887 123 XOSC2 = 0x35,
Jamie Smith 0:0c3532738887 124 XOSC1 = 0x36,
Jamie Smith 0:0c3532738887 125 XOSC0 = 0x37,
Jamie Smith 0:0c3532738887 126 //...
Jamie Smith 0:0c3532738887 127 FREQOFF_EST1 = 0x77,
Jamie Smith 0:0c3532738887 128 FREQOFF_EST2 = 0x78,
Jamie Smith 0:0c3532738887 129 //...
Jamie Smith 0:0c3532738887 130 FSCAL_CTRL = 0x8D,
Jamie Smith 0:0c3532738887 131 PARTNUMBER = 0x8F,
Jamie Smith 0:0c3532738887 132 PARTVERSION = 0x90,
Jamie Smith 0:0c3532738887 133 //...
Jamie Smith 0:0c3532738887 134 RXFIRST = 0xD2,
Jamie Smith 0:0c3532738887 135 TXFIRST = 0xD3,
Jamie Smith 0:0c3532738887 136 RXLAST = 0xD4,
Jamie Smith 0:0c3532738887 137 TXLAST = 0xD5,
Jamie Smith 0:0c3532738887 138 NUM_TXBYTES = 0xD6,
Jamie Smith 0:0c3532738887 139 NUM_RXBYTES = 0xD7,
Jamie Smith 0:0c3532738887 140 };
Jamie Smith 0:0c3532738887 141
Jamie Smith 0:0c3532738887 142 // Command strobe definitions. See user guide section 3.2.2
Jamie Smith 0:0c3532738887 143 enum class Command : uint8_t
Jamie Smith 0:0c3532738887 144 {
Jamie Smith 0:0c3532738887 145 SOFT_RESET = 0x30,
Jamie Smith 0:0c3532738887 146 ENABLE_FREQ_SYNTH = 0x31,
Jamie Smith 0:0c3532738887 147 OSC_OFF = 0x32,
Jamie Smith 0:0c3532738887 148 CAL_FREQ_SYNTH = 0x33,
Jamie Smith 0:0c3532738887 149 RX = 0x34,
Jamie Smith 0:0c3532738887 150 TX = 0x35,
Jamie Smith 0:0c3532738887 151 IDLE = 0x36,
Jamie Smith 0:0c3532738887 152 AUTO_FREQ_COMP = 0x37,
Jamie Smith 0:0c3532738887 153 WAKE_ON_RADIO = 0x38,
Jamie Smith 0:0c3532738887 154 SLEEP = 0x39,
Jamie Smith 0:0c3532738887 155 FLUSH_RX = 0x3A,
Jamie Smith 0:0c3532738887 156 FLUSH_TX = 0x3B,
Jamie Smith 0:0c3532738887 157 WOR_RESET = 0x3C,
Jamie Smith 0:0c3532738887 158 NOP = 0x3D
Jamie Smith 0:0c3532738887 159 };
Jamie Smith 0:0c3532738887 160
Jamie Smith 0:0c3532738887 161 // State of the radio chip. See user guide Figure 2.
Jamie Smith 0:0c3532738887 162 enum class State : uint8_t
Jamie Smith 0:0c3532738887 163 {
Jamie Smith 0:0c3532738887 164 IDLE = 0x0,
Jamie Smith 0:0c3532738887 165 RX = 0x1,
Jamie Smith 0:0c3532738887 166 TX = 0x2,
Jamie Smith 0:0c3532738887 167 FAST_ON = 0x3,
Jamie Smith 0:0c3532738887 168 CALIBRATE = 0x4,
Jamie Smith 0:0c3532738887 169 SETTLING = 0x5,
Jamie Smith 0:0c3532738887 170 RX_FIFO_ERROR = 0x6,
Jamie Smith 0:0c3532738887 171 TX_FIFO_ERROR = 0x7
Jamie Smith 0:0c3532738887 172 };
Jamie Smith 0:0c3532738887 173
Jamie Smith 0:0c3532738887 174 private:
Jamie Smith 0:0c3532738887 175 // chip data variables
Jamie Smith 0:0c3532738887 176 bool chipReady = false;
Jamie Smith 0:0c3532738887 177 State state;
Jamie Smith 0:0c3532738887 178 bool isCC1201;
Jamie Smith 0:0c3532738887 179
Jamie Smith 0:0c3532738887 180 // current state variables
Jamie Smith 0:0c3532738887 181
Jamie Smith 0:0c3532738887 182 // current symbol rate of the radio
Jamie Smith 0:0c3532738887 183 float symbolRateSps = 0;
Jamie Smith 0:0c3532738887 184
Jamie Smith 0:0c3532738887 185 // current ADC CIC decimation of the radio
Jamie Smith 0:0c3532738887 186 uint8_t adcCicDecimation = 0;
Jamie Smith 0:0c3532738887 187
Jamie Smith 0:0c3532738887 188 public:
Jamie Smith 0:0c3532738887 189
Jamie Smith 0:0c3532738887 190 /**
Jamie Smith 0:0c3532738887 191 * Construct a CC1200 radio driver from the given set of pins.
Jamie Smith 0:0c3532738887 192 *
Jamie Smith 0:0c3532738887 193 * @param misoPin
Jamie Smith 0:0c3532738887 194 * @param mosiPin
Jamie Smith 0:0c3532738887 195 * @param sclkPin
Jamie Smith 0:0c3532738887 196 * @param csPin
Jamie Smith 0:0c3532738887 197 * @param rstPin
Jamie Smith 0:0c3532738887 198 * @param _debugStream Stream to print error/debug information on.
Jamie Smith 0:0c3532738887 199 * @param isCC1201 True if the chip is a CC1201, false if it is a CC1200. The CC1201 is a cheaper option that lacks low bandwidth settings but is otherwise identical.
Jamie Smith 0:0c3532738887 200 */
Jamie Smith 0:0c3532738887 201 CC1200(PinName mosiPin, PinName misoPin, PinName sclkPin, PinName csPin, PinName rstPin, Stream * _debugStream, bool _isCC1201 = false);
Jamie Smith 0:0c3532738887 202
Jamie Smith 0:0c3532738887 203 /**
Jamie Smith 0:0c3532738887 204 * Reset the chip and attempt to connect to it.
Jamie Smith 0:0c3532738887 205 * Returns whether the chip could be contacted.
Jamie Smith 0:0c3532738887 206 * @return
Jamie Smith 0:0c3532738887 207 */
Jamie Smith 0:0c3532738887 208 bool begin();
Jamie Smith 0:0c3532738887 209
Jamie Smith 0:0c3532738887 210 /**
Jamie Smith 0:0c3532738887 211 * Get the radio's most recently known state.
Jamie Smith 0:0c3532738887 212 * State is updated whenever registers are read or commands are sent, or when you call updateState.
Jamie Smith 0:0c3532738887 213 * @return
Jamie Smith 0:0c3532738887 214 */
Jamie Smith 0:0c3532738887 215 State getState() { return state; }
Jamie Smith 0:0c3532738887 216
Jamie Smith 0:0c3532738887 217 // Data tx & rx functions
Jamie Smith 0:0c3532738887 218 // ------------------------------------------------------------------------------
Jamie Smith 0:0c3532738887 219
Jamie Smith 0:0c3532738887 220 /**
Jamie Smith 0:0c3532738887 221 * Get the number of bytes currently in the TX FIFO
Jamie Smith 0:0c3532738887 222 * @return
Jamie Smith 0:0c3532738887 223 */
Jamie Smith 0:0c3532738887 224 size_t getTXFIFOLen();
Jamie Smith 0:0c3532738887 225
Jamie Smith 0:0c3532738887 226 /**
Jamie Smith 0:0c3532738887 227 * Get the number of bytes currently in the RX FIFO
Jamie Smith 0:0c3532738887 228 * @return
Jamie Smith 0:0c3532738887 229 */
Jamie Smith 0:0c3532738887 230 size_t getRXFIFOLen();
Jamie Smith 0:0c3532738887 231
Jamie Smith 0:0c3532738887 232 /**
Jamie Smith 0:0c3532738887 233 * Enqueue a packet to be sent over the radio. It will be sent the next time the radio is in
Jamie Smith 0:0c3532738887 234 * transmit state.
Jamie Smith 0:0c3532738887 235 *
Jamie Smith 0:0c3532738887 236 * The length of a packet is variable, from 1 byte to 127 bytes. The length will be transmitted
Jamie Smith 0:0c3532738887 237 * along with the packet data.
Jamie Smith 0:0c3532738887 238 *
Jamie Smith 0:0c3532738887 239 * Also reads the radio's state.
Jamie Smith 0:0c3532738887 240 *
Jamie Smith 0:0c3532738887 241 * @param data
Jamie Smith 0:0c3532738887 242 * @param len
Jamie Smith 0:0c3532738887 243 *
Jamie Smith 0:0c3532738887 244 * @return Whether the packet was enqueued. Could return false if there was not enough FIFO
Jamie Smith 0:0c3532738887 245 * space to enqueue the packet, or if the packet is too long.
Jamie Smith 0:0c3532738887 246 */
Jamie Smith 0:0c3532738887 247 bool enqueuePacket(char const * data, size_t len);
Jamie Smith 0:0c3532738887 248
Jamie Smith 0:0c3532738887 249 /**
Jamie Smith 0:0c3532738887 250 * Check whether there is at least one complete packet in the RX FIFO.
Jamie Smith 0:0c3532738887 251 * NOTE: An alternate way to do this using hardware is to configure one
Jamie Smith 0:0c3532738887 252 * of the CC1200's GPIOs as PKT_SYNC_RXTX, then set a falling edge interrupt to receive a packet.
Jamie Smith 0:0c3532738887 253 * @return
Jamie Smith 0:0c3532738887 254 */
Jamie Smith 0:0c3532738887 255 bool hasReceivedPacket();
Jamie Smith 0:0c3532738887 256
Jamie Smith 0:0c3532738887 257 /**
Jamie Smith 0:0c3532738887 258 * Receive a packet from the radio. Only packets that pass CRC check are received into the FIFO;
Jamie Smith 0:0c3532738887 259 * those which do not pass checksum will be discarded.
Jamie Smith 0:0c3532738887 260 *
Jamie Smith 0:0c3532738887 261 * This function assumes that there is a packet in the buffer. You should only call it after
Jamie Smith 0:0c3532738887 262 * hasReceivedPacket() is true or a PKT_SYNC_RXTX pulse is received. If there is not a packet
Jamie Smith 0:0c3532738887 263 * in the FIFO, *undefined behavior* can occur. An arbitrary amount of data will be read from
Jamie Smith 0:0c3532738887 264 * the FIFO and garbage may be returned.
Jamie Smith 0:0c3532738887 265 *
Jamie Smith 0:0c3532738887 266 * NOTE: A null terminator is NOT added unless it was present in the transmitted data.
Jamie Smith 0:0c3532738887 267 * Be careful when treating the returned data as a string!
Jamie Smith 0:0c3532738887 268 *
Jamie Smith 0:0c3532738887 269 * @param buffer Buffer to store received bytes in.
Jamie Smith 0:0c3532738887 270 * @param bufferLen Length of the buffer supplied. If the packet is longer than this buffer, then
Jamie Smith 0:0c3532738887 271 * the full packet will be read from the FIFO but only a buffer's worth will be stored.
Jamie Smith 0:0c3532738887 272 * @return Number of bytes actually received.
Jamie Smith 0:0c3532738887 273 */
Jamie Smith 0:0c3532738887 274 size_t receivePacket(char * buffer, size_t bufferLen);
Jamie Smith 0:0c3532738887 275
Jamie Smith 0:0c3532738887 276 /**
Jamie Smith 0:0c3532738887 277 * Set what state the radio will enter when a packet is received.
Jamie Smith 0:0c3532738887 278 * @param goodPacket State when a good (CRC pass) packet is received.
Jamie Smith 0:0c3532738887 279 * Accepts State::TX, State::IDLE, State::FAST_TX_ON, and State::RX.
Jamie Smith 0:0c3532738887 280 * @param badPacket State when a bad (CRC fail) packet is received.
Jamie Smith 0:0c3532738887 281 * Accepts State::RX and State::IDLE
Jamie Smith 0:0c3532738887 282 */
Jamie Smith 0:0c3532738887 283 void setOnReceiveState(State goodPacket, State badPacket);
Jamie Smith 0:0c3532738887 284
Jamie Smith 0:0c3532738887 285 /**
Jamie Smith 0:0c3532738887 286 * Set what state the radio will enter when a packet is sent.
Jamie Smith 0:0c3532738887 287 * @param state State when a packet is transmitted.
Jamie Smith 0:0c3532738887 288 * Accepts State::TX, State::IDLE, State::FAST_TX_ON, and State::RX.
Jamie Smith 0:0c3532738887 289 */
Jamie Smith 0:0c3532738887 290 void setOnTransmitState(State state);
Jamie Smith 0:0c3532738887 291
Jamie Smith 0:0c3532738887 292 enum class FSCalMode : uint8_t
Jamie Smith 0:0c3532738887 293 {
Jamie Smith 0:0c3532738887 294 NONE = 0b00, // never calibrate the FS automatically
Jamie Smith 0:0c3532738887 295 FROM_IDLE = 0b01, // calibrate the FS when going from idle to TX, RX, or fast TX on
Jamie Smith 0:0c3532738887 296 TO_IDLE = 0b10, // calibrate the FS when going from TX, RX, or fast TX on to idle
Jamie Smith 0:0c3532738887 297 TO_IDLE_1_4 = 0b11 // calibrate the FS 1/4 of the time when going from TX, RX, or fast TX on to idle
Jamie Smith 0:0c3532738887 298 };
Jamie Smith 0:0c3532738887 299
Jamie Smith 0:0c3532738887 300 /**
Jamie Smith 0:0c3532738887 301 * Set when the radio calibrates its frequency synthesizer.
Jamie Smith 0:0c3532738887 302 *
Jamie Smith 0:0c3532738887 303 * Per https://e2e.ti.com/support/wireless-connectivity/sub-1-ghz/f/156/t/375189
Jamie Smith 0:0c3532738887 304 * it looks like the FS can drift with changes in supply voltage and/or temperature,
Jamie Smith 0:0c3532738887 305 * so it is good to continually calibrate it in case these change.
Jamie Smith 0:0c3532738887 306 */
Jamie Smith 0:0c3532738887 307 void setFSCalMode(FSCalMode mode);
Jamie Smith 0:0c3532738887 308
Jamie Smith 0:0c3532738887 309 // GPIO configuration
Jamie Smith 0:0c3532738887 310 // ------------------------------------------------------------------------------
Jamie Smith 0:0c3532738887 311
Jamie Smith 0:0c3532738887 312 /**
Jamie Smith 0:0c3532738887 313 * Enum for all possible GPIO modes.
Jamie Smith 0:0c3532738887 314 * Note: Some modes do different things depending on which GPIOs they're assigned to.
Jamie Smith 0:0c3532738887 315 * Duplicate enum values have been intentionally defined for this.
Jamie Smith 0:0c3532738887 316 */
Jamie Smith 0:0c3532738887 317 enum class GPIOMode : uint8_t
Jamie Smith 0:0c3532738887 318 {
Jamie Smith 0:0c3532738887 319 RXFIFO_THR_PKT = 1,
Jamie Smith 0:0c3532738887 320 PKT_SYNC_RXTX = 6,
Jamie Smith 0:0c3532738887 321 RSSI_UPDATE = 14, // GPIO3 and GPIO2
Jamie Smith 0:0c3532738887 322 AGC_HOLD = 14, // GPIO1
Jamie Smith 0:0c3532738887 323 AGC_UPDATE = 14, // GPIO0
Jamie Smith 0:0c3532738887 324 SYNC_EVENT = 41, // GPIO2
Jamie Smith 0:0c3532738887 325 HIGHZ = 48,
Jamie Smith 0:0c3532738887 326 HW0 = 51
Jamie Smith 0:0c3532738887 327 };
Jamie Smith 0:0c3532738887 328
Jamie Smith 0:0c3532738887 329 /**
Jamie Smith 0:0c3532738887 330 * Configure a CC1200 GPIO pin.
Jamie Smith 0:0c3532738887 331 * @param gpioNumber Pin number, from 0-3.
Jamie Smith 0:0c3532738887 332 * @param mode Mode to set the pin to.
Jamie Smith 0:0c3532738887 333 * @param outputInvert Whether to invert the output of the pin.
Jamie Smith 0:0c3532738887 334 */
Jamie Smith 0:0c3532738887 335 void configureGPIO(uint8_t gpioNumber, GPIOMode mode, bool outputInvert = false);
Jamie Smith 0:0c3532738887 336
Jamie Smith 0:0c3532738887 337 // RF configuration
Jamie Smith 0:0c3532738887 338 // ------------------------------------------------------------------------------
Jamie Smith 0:0c3532738887 339
Jamie Smith 0:0c3532738887 340 /**
Jamie Smith 0:0c3532738887 341 * Set up the radio for FIFO mode.
Jamie Smith 0:0c3532738887 342 */
Jamie Smith 0:0c3532738887 343 void configureFIFOMode();
Jamie Smith 0:0c3532738887 344
Jamie Smith 0:0c3532738887 345 enum class ModFormat : uint8_t
Jamie Smith 0:0c3532738887 346 {
Jamie Smith 0:0c3532738887 347 FSK_2 = 0x0,
Jamie Smith 0:0c3532738887 348 GFSK_2 = 0x1,
Jamie Smith 0:0c3532738887 349 ASK = 0x3,
Jamie Smith 0:0c3532738887 350 FSK_4 = 0x4,
Jamie Smith 0:0c3532738887 351 GFSK_4 = 0x5
Jamie Smith 0:0c3532738887 352 };
Jamie Smith 0:0c3532738887 353
Jamie Smith 0:0c3532738887 354 /**
Jamie Smith 0:0c3532738887 355 * Set the modulation format of the radio.
Jamie Smith 0:0c3532738887 356 * @param format
Jamie Smith 0:0c3532738887 357 */
Jamie Smith 0:0c3532738887 358 void setModulationFormat(ModFormat format);
Jamie Smith 0:0c3532738887 359
Jamie Smith 0:0c3532738887 360 /**
Jamie Smith 0:0c3532738887 361 * Set the frequency deviation from the center frequency in Hz.
Jamie Smith 0:0c3532738887 362 * See user guide section 5.2.1 for details, and cc1200 datasheet section 4.10.2 for example values.
Jamie Smith 0:0c3532738887 363 */
Jamie Smith 0:0c3532738887 364 void setFSKDeviation(float deviation);
Jamie Smith 0:0c3532738887 365
Jamie Smith 0:0c3532738887 366 /**
Jamie Smith 0:0c3532738887 367 * Set the RF symbol rate in Hz. If this radio is to be used in receive mode you must call
Jamie Smith 0:0c3532738887 368 * setRXFilterBandwidth() after calling this function.
Jamie Smith 0:0c3532738887 369 * @param symbolRateHz
Jamie Smith 0:0c3532738887 370 */
Jamie Smith 0:0c3532738887 371 void setSymbolRate(float symbolRateHz);
Jamie Smith 0:0c3532738887 372
Jamie Smith 0:0c3532738887 373 /**
Jamie Smith 0:0c3532738887 374 * Set the approximate output power in dBm.
Jamie Smith 0:0c3532738887 375 * Must be between -16dBm and +14dBm.
Jamie Smith 0:0c3532738887 376 * @param outPower
Jamie Smith 0:0c3532738887 377 */
Jamie Smith 0:0c3532738887 378 void setOutputPower(float outPower);
Jamie Smith 0:0c3532738887 379
Jamie Smith 0:0c3532738887 380 // Radio band for the chip to operate on.
Jamie Smith 0:0c3532738887 381 // See user guide description for FS_CFG register.
Jamie Smith 0:0c3532738887 382 enum class Band : uint8_t
Jamie Smith 0:0c3532738887 383 {
Jamie Smith 0:0c3532738887 384 BAND_820_960MHz = 0x2,
Jamie Smith 0:0c3532738887 385 BAND_410_480MHz = 0x4,
Jamie Smith 0:0c3532738887 386 BAND_273_320MHz = 0x6,
Jamie Smith 0:0c3532738887 387 BAND_205_240MHz = 0x8,
Jamie Smith 0:0c3532738887 388 BAND_164_192MHz = 0xA,
Jamie Smith 0:0c3532738887 389 BAND_136_160MHz = 0xB
Jamie Smith 0:0c3532738887 390 };
Jamie Smith 0:0c3532738887 391
Jamie Smith 0:0c3532738887 392 /**
Jamie Smith 0:0c3532738887 393 * Set the radio band and specific frequency. See user guide section 9.12 for details.
Jamie Smith 0:0c3532738887 394 * Note: Frequency offsets are not currently implemented, so the frequency can't be
Jamie Smith 0:0c3532738887 395 * set at the finest resolution. However, the resolution should be fine for most applications.
Jamie Smith 0:0c3532738887 396 * (at 900MHz this function has a resolution of 152.5Hz)
Jamie Smith 0:0c3532738887 397 * @param band
Jamie Smith 0:0c3532738887 398 * @param frequencyHz
Jamie Smith 0:0c3532738887 399 */
Jamie Smith 0:0c3532738887 400 void setRadioFrequency(Band band, float frequencyHz);
Jamie Smith 0:0c3532738887 401
Jamie Smith 0:0c3532738887 402 /**
Jamie Smith 0:0c3532738887 403 * Set the the RX filter bandwidth. You must call this AFTER setting the symbol rate.
Jamie Smith 0:0c3532738887 404 * See user guide section 6.1 for details.
Jamie Smith 0:0c3532738887 405 *
Jamie Smith 0:0c3532738887 406 * NOTE: The symbol rate and the RX filter bandwidth must be compatible with each other.
Jamie Smith 0:0c3532738887 407 * See the user guide for details.
Jamie Smith 0:0c3532738887 408 *
Jamie Smith 0:0c3532738887 409 * @param bandwidthHz the bandwidth in Hz
Jamie Smith 0:0c3532738887 410 * @param isCC1201 whether the current chip is a CC1201 instead of a CC1200. The CC1201 has a more limited set of valid bandwidth settings.
Jamie Smith 0:0c3532738887 411 */
Jamie Smith 0:0c3532738887 412 void setRXFilterBandwidth(float bandwidthHz, bool isCC1201 = false);
Jamie Smith 0:0c3532738887 413
Jamie Smith 0:0c3532738887 414 /**
Jamie Smith 0:0c3532738887 415 * Get the ADC CIC decimation that was calculated by the most recent setRXFilterBandwidth() call.
Jamie Smith 0:0c3532738887 416 * This is used for certain other calculations such as the DC offset.
Jamie Smith 0:0c3532738887 417 * @return
Jamie Smith 0:0c3532738887 418 */
Jamie Smith 0:0c3532738887 419 uint8_t getADCCICDecimation() { return adcCicDecimation; }
Jamie Smith 0:0c3532738887 420
Jamie Smith 0:0c3532738887 421 /**
Jamie Smith 0:0c3532738887 422 * Configure the radio's automatic DC offset removal algorithm is enabled.
Jamie Smith 0:0c3532738887 423 * DC offset correction must be enabled when using zero IF mode, and in my testing
Jamie Smith 0:0c3532738887 424 * it seems to be important when staying in TX mode for a long time at
Jamie Smith 0:0c3532738887 425 * higher sample rates.
Jamie Smith 0:0c3532738887 426 *
Jamie Smith 0:0c3532738887 427 * See the datasheet register description for DCFILT_CFG for explanations of what these values do.
Jamie Smith 0:0c3532738887 428 * Maybe you'll actually be able to make some sense out of what it says... I sure couldn't.
Jamie Smith 0:0c3532738887 429 *
Jamie Smith 0:0c3532738887 430 * @param enableAutoFilter Whether automatic filtering is enabled.
Jamie Smith 0:0c3532738887 431 * @param settlingCfg Settling time configuration bits.
Jamie Smith 0:0c3532738887 432 * @param cutoffCfg Cutoff frequency configuration bits.
Jamie Smith 0:0c3532738887 433 */
Jamie Smith 0:0c3532738887 434 void configureDCFilter(bool enableAutoFilter, uint8_t settlingCfg, uint8_t cutoffCfg);
Jamie Smith 0:0c3532738887 435
Jamie Smith 0:0c3532738887 436 /**
Jamie Smith 0:0c3532738887 437 * Set the IF mixing configuration.
Jamie Smith 0:0c3532738887 438 * See the user guide section on IF_MIX_CFG.CMIX_CFG for details.
Jamie Smith 0:0c3532738887 439 */
Jamie Smith 0:0c3532738887 440 void setIFMixCFG(uint8_t value);
Jamie Smith 0:0c3532738887 441
Jamie Smith 0:0c3532738887 442 /**
Jamie Smith 0:0c3532738887 443 * Set whether the ImageExtinct IQ mismatch compensation logic is enabled.
Jamie Smith 0:0c3532738887 444 * This should be disabled if IF < RX filter bandwidth
Jamie Smith 0:0c3532738887 445 * @param enabled
Jamie Smith 0:0c3532738887 446 */
Jamie Smith 0:0c3532738887 447 void setIQMismatchCompensationEnabled(bool enabled);
Jamie Smith 0:0c3532738887 448
Jamie Smith 0:0c3532738887 449 /**
Jamie Smith 0:0c3532738887 450 * Mode describing the size and setup of the sync word.
Jamie Smith 0:0c3532738887 451 * See user guide register description for SYNC_CFG1
Jamie Smith 0:0c3532738887 452 */
Jamie Smith 0:0c3532738887 453 enum class SyncMode : uint8_t
Jamie Smith 0:0c3532738887 454 {
Jamie Smith 0:0c3532738887 455 SYNC_NONE = 0,
Jamie Smith 0:0c3532738887 456 SYNC_11_BITS = 0b1,
Jamie Smith 0:0c3532738887 457 SYNC_16_BITS = 0b10,
Jamie Smith 0:0c3532738887 458 SYNC_18_BITS = 0b11,
Jamie Smith 0:0c3532738887 459 SYNC_24_BITS = 0b100,
Jamie Smith 0:0c3532738887 460 SYNC_32_BITS = 0b101,
Jamie Smith 0:0c3532738887 461 SYNC_16_BITS_HIGH_BYTE = 0b110,
Jamie Smith 0:0c3532738887 462 SYNC_16_BITS_DUAL = 0b111
Jamie Smith 0:0c3532738887 463 };
Jamie Smith 0:0c3532738887 464
Jamie Smith 0:0c3532738887 465 /**
Jamie Smith 0:0c3532738887 466 * Configure the sync word settings of the radio. The sync word is the bit string sent before each packet -- the
Jamie Smith 0:0c3532738887 467 * radio knows to switch into receive mode when it detects it. Specific values with low autocorrelation should
Jamie Smith 0:0c3532738887 468 * be used for the sync word.
Jamie Smith 0:0c3532738887 469 *
Jamie Smith 0:0c3532738887 470 * @param syncWord Sync word value.
Jamie Smith 0:0c3532738887 471 * @param mode Sync word mode. Configures how many bits of the value are significant.
Jamie Smith 0:0c3532738887 472 * @param syncThreshold Correspondance threshold before the radio switches into receive mode.
Jamie Smith 0:0c3532738887 473 */
Jamie Smith 0:0c3532738887 474 void configureSyncWord(uint32_t syncWord, SyncMode mode, uint8_t syncThreshold);
Jamie Smith 0:0c3532738887 475
Jamie Smith 0:0c3532738887 476 /**
Jamie Smith 0:0c3532738887 477 * Check whether the frequency synthesizer is locked on to the correct frequency.
Jamie Smith 0:0c3532738887 478 * If not, then the correct RF frequency is not being used.
Jamie Smith 0:0c3532738887 479 * If the FS is not locking then check that the correct black box FS registers are applied
Jamie Smith 0:0c3532738887 480 * and that the FS has been calibrated.
Jamie Smith 0:0c3532738887 481 * @return
Jamie Smith 0:0c3532738887 482 */
Jamie Smith 0:0c3532738887 483 bool isFSLocked();
Jamie Smith 0:0c3532738887 484
Jamie Smith 0:0c3532738887 485 /**
Jamie Smith 0:0c3532738887 486 * Configure the preamble that the radio is configured to send/receive. The main purpose of the preamble is to
Jamie Smith 0:0c3532738887 487 * provide receiving radios with a chance to calibrate their RX gain. However, you can also require that receiving
Jamie Smith 0:0c3532738887 488 * radios see a valid preamble before they can detect the sync word (this is not on by default).
Jamie Smith 0:0c3532738887 489 *
Jamie Smith 0:0c3532738887 490 * @param preambleLengthCfg Bits that determine the length of the preamble. See the PREAMBLE_CFG1 register description for details. Set to 0 disable transmitting a preamble.
Jamie Smith 0:0c3532738887 491 * @param preambleFormatCfg Bits that determine the format of the preamble. See the PREAMBLE_CFG1 register description for details.
Jamie Smith 0:0c3532738887 492 */
Jamie Smith 0:0c3532738887 493 void configurePreamble(uint8_t preambleLengthCfg, uint8_t preambleFormatCfg);
Jamie Smith 0:0c3532738887 494
Jamie Smith 0:0c3532738887 495 // Register level functions
Jamie Smith 0:0c3532738887 496 // ------------------------------------------------------------------------------
Jamie Smith 0:0c3532738887 497
Jamie Smith 0:0c3532738887 498 /**
Jamie Smith 0:0c3532738887 499 * Read a register and return the byte value. Also reads the radio's state.
Jamie Smith 0:0c3532738887 500 */
Jamie Smith 0:0c3532738887 501 uint8_t readRegister(Register reg);
Jamie Smith 0:0c3532738887 502
Jamie Smith 0:0c3532738887 503 /**
Jamie Smith 0:0c3532738887 504 * Write a register with a byte value. Also reads the radio's state.
Jamie Smith 0:0c3532738887 505 */
Jamie Smith 0:0c3532738887 506 void writeRegister(Register reg, uint8_t value);
Jamie Smith 0:0c3532738887 507
Jamie Smith 0:0c3532738887 508 /**
Jamie Smith 0:0c3532738887 509 * Write a series of consecutive registers with byte values. Also reads the radio's state.
Jamie Smith 0:0c3532738887 510 */
Jamie Smith 0:0c3532738887 511 void writeRegisters(CC1200::Register startReg, uint8_t const *values, size_t numRegisters);
Jamie Smith 0:0c3532738887 512
Jamie Smith 0:0c3532738887 513 /**
Jamie Smith 0:0c3532738887 514 * Write a series of consecutive registers with byte values. Also reads the radio's state.
Jamie Smith 0:0c3532738887 515 * Template version that takes an std::array.
Jamie Smith 0:0c3532738887 516 */
Jamie Smith 0:0c3532738887 517 template<size_t numRegisters>
Jamie Smith 0:0c3532738887 518 void writeRegisters(CC1200::Register startReg, std::array<uint8_t, numRegisters> const & values)
Jamie Smith 0:0c3532738887 519 {
Jamie Smith 0:0c3532738887 520 writeRegisters(startReg, values.data(), values.size());
Jamie Smith 0:0c3532738887 521 }
Jamie Smith 0:0c3532738887 522
Jamie Smith 0:0c3532738887 523 /**
Jamie Smith 0:0c3532738887 524 * Read an extended register and return the byte value. Also reads the radio's state.
Jamie Smith 0:0c3532738887 525 */
Jamie Smith 0:0c3532738887 526 uint8_t readRegister(ExtRegister reg);
Jamie Smith 0:0c3532738887 527
Jamie Smith 0:0c3532738887 528 /**
Jamie Smith 0:0c3532738887 529 * Write an extended register with a byte value. Also reads the radio's state.
Jamie Smith 0:0c3532738887 530 */
Jamie Smith 0:0c3532738887 531 void writeRegister(ExtRegister reg, uint8_t value);
Jamie Smith 0:0c3532738887 532
Jamie Smith 0:0c3532738887 533 /**
Jamie Smith 0:0c3532738887 534 * Write a series of consecutive extended registers with byte values. Also reads the radio's state.
Jamie Smith 0:0c3532738887 535 */
Jamie Smith 0:0c3532738887 536 void writeRegisters(CC1200::ExtRegister startReg, uint8_t const *values, size_t numRegisters);
Jamie Smith 0:0c3532738887 537
Jamie Smith 0:0c3532738887 538 /**
Jamie Smith 0:0c3532738887 539 * Write a series of consecutive registers with byte values. Also reads the radio's state.
Jamie Smith 0:0c3532738887 540 * Template version that takes an std::array.
Jamie Smith 0:0c3532738887 541 */
Jamie Smith 0:0c3532738887 542 template<size_t numRegisters>
Jamie Smith 0:0c3532738887 543 void writeRegisters(CC1200::ExtRegister startReg, std::array<uint8_t, numRegisters> const & values)
Jamie Smith 0:0c3532738887 544 {
Jamie Smith 0:0c3532738887 545 writeRegisters(startReg, values.data(), values.size());
Jamie Smith 0:0c3532738887 546 }
Jamie Smith 0:0c3532738887 547
Jamie Smith 0:0c3532738887 548
Jamie Smith 0:0c3532738887 549 /**
Jamie Smith 0:0c3532738887 550 * Send a command. Also reads the radio's state.
Jamie Smith 0:0c3532738887 551 * @param command
Jamie Smith 0:0c3532738887 552 */
Jamie Smith 0:0c3532738887 553 void sendCommand(Command command);
Jamie Smith 0:0c3532738887 554
Jamie Smith 0:0c3532738887 555 /**
Jamie Smith 0:0c3532738887 556 * Update the current known state of the radio.
Jamie Smith 0:0c3532738887 557 */
Jamie Smith 0:0c3532738887 558 void updateState() { sendCommand(Command::NOP); }
Jamie Smith 0:0c3532738887 559
Jamie Smith 0:0c3532738887 560 /**
Jamie Smith 0:0c3532738887 561 * Get a byte from the RX FIFO.
Jamie Smith 0:0c3532738887 562 * @param address The byte address, from 0-127.
Jamie Smith 0:0c3532738887 563 */
Jamie Smith 0:0c3532738887 564 uint8_t readRXFIFOByte(uint8_t address);
Jamie Smith 0:0c3532738887 565
Jamie Smith 0:0c3532738887 566 // State change functions
Jamie Smith 0:0c3532738887 567 // ------------------------------------------------------------------------------
Jamie Smith 0:0c3532738887 568
Jamie Smith 0:0c3532738887 569 /**
Jamie Smith 0:0c3532738887 570 * Send the STX strobe to change the radio into TX state.
Jamie Smith 0:0c3532738887 571 * Valid when the radio is in IDLE, FAST_TX_ON, and RX.
Jamie Smith 0:0c3532738887 572 * A calibration will be performed if needed.
Jamie Smith 0:0c3532738887 573 *
Jamie Smith 0:0c3532738887 574 * The radio will stay in TX state until it is commanded to a different state, or a packet is
Jamie Smith 0:0c3532738887 575 * transmitted and it is configured to change states when this happens, or a FIFO error occurs (which
Jamie Smith 0:0c3532738887 576 * shouldn't be possible with the current configuration).
Jamie Smith 0:0c3532738887 577 */
Jamie Smith 0:0c3532738887 578 void startTX() { sendCommand(Command::TX); }
Jamie Smith 0:0c3532738887 579
Jamie Smith 0:0c3532738887 580 /**
Jamie Smith 0:0c3532738887 581 * Send the SRX strobe to change the radio into TX state.
Jamie Smith 0:0c3532738887 582 * Valid when the radio is in IDLE, FAST_TX_ON, and TX.
Jamie Smith 0:0c3532738887 583 * A calibration will be performed if needed.
Jamie Smith 0:0c3532738887 584 *
Jamie Smith 0:0c3532738887 585 * The radio will stay in RX state until it is commanded to a different state, or a packet is
Jamie Smith 0:0c3532738887 586 * received and it configured to change states when this happens, or a FIFO overflow occurs
Jamie Smith 0:0c3532738887 587 * (because the host is not reading data out fast enough).
Jamie Smith 0:0c3532738887 588 */
Jamie Smith 0:0c3532738887 589 void startRX() { sendCommand(Command::RX); }
Jamie Smith 0:0c3532738887 590
Jamie Smith 0:0c3532738887 591 private:
Jamie Smith 0:0c3532738887 592
Jamie Smith 0:0c3532738887 593 /**
Jamie Smith 0:0c3532738887 594 * Called whenever we get a status byte from another operation. Saves the info from it to member variables.
Jamie Smith 0:0c3532738887 595 * @param status
Jamie Smith 0:0c3532738887 596 */
Jamie Smith 0:0c3532738887 597 void loadStatusByte(uint8_t status);
Jamie Smith 0:0c3532738887 598 };
Jamie Smith 0:0c3532738887 599
Jamie Smith 0:0c3532738887 600
Jamie Smith 0:0c3532738887 601 #endif //LIGHTSPEEDRANGEFINDER_CC1200_H