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:
Fri Aug 28 15:39:31 2020 -0700
Revision:
4:c609cc7c9ea7
Parent:
3:f464b14ce62f
Child:
5:d22a8885800b
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.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Jamie Smith 1:98af824b145e 1 #pragma clang diagnostic push
Jamie Smith 1:98af824b145e 2 #pragma ide diagnostic ignored "readability-magic-numbers"
Jamie Smith 0:0c3532738887 3 //
Jamie Smith 0:0c3532738887 4 // Created by jamie on 3/27/2020.
Jamie Smith 0:0c3532738887 5 //
Jamie Smith 0:0c3532738887 6
Jamie Smith 0:0c3532738887 7 #include "CC1200.h"
Jamie Smith 0:0c3532738887 8 #include "CC1200Bits.h"
Jamie Smith 0:0c3532738887 9
Jamie Smith 0:0c3532738887 10 #include <cinttypes>
Jamie Smith 0:0c3532738887 11 #include <cmath>
Jamie Smith 3:f464b14ce62f 12 #include <array>
Jamie Smith 0:0c3532738887 13
Jamie Smith 0:0c3532738887 14 // change to 1 to print debug info
Jamie Smith 3:f464b14ce62f 15 #define CC1200_DEBUG 0
Jamie Smith 0:0c3532738887 16
Jamie Smith 0:0c3532738887 17 // change to 1 to print register read/write level debug info
Jamie Smith 0:0c3532738887 18 #define CC1200_REGISTER_LEVEL_DEBUG 0
Jamie Smith 0:0c3532738887 19
Jamie Smith 0:0c3532738887 20 // miscellaneous constants
Jamie Smith 0:0c3532738887 21 #define CC1200_READ (1 << 7) // SPI initial byte flag indicating read
Jamie Smith 0:0c3532738887 22 #define CC1200_WRITE 0 // SPI initial byte flag indicating write
Jamie Smith 0:0c3532738887 23 #define CC1200_BURST (1 << 6) // SPI initial byte flag indicating burst access
Jamie Smith 0:0c3532738887 24
Jamie Smith 0:0c3532738887 25 // SPI commands to access data buffers. Can be used with CC1200_BURST.
Jamie Smith 0:0c3532738887 26 #define CC1200_ENQUEUE_TX_FIFO 0x3F
Jamie Smith 0:0c3532738887 27 #define CC1200_DEQUEUE_RX_FIFO 0xBF
Jamie Smith 0:0c3532738887 28
Jamie Smith 0:0c3532738887 29 // SPI command to access FIFO memory (or several other areas depending on mode)
Jamie Smith 0:0c3532738887 30 #define CC1200_MEM_ACCESS 0x3E
Jamie Smith 0:0c3532738887 31
Jamie Smith 0:0c3532738887 32 #define CC1200_RX_FIFO (1 << 7) // address flag to access RX FIFO
Jamie Smith 0:0c3532738887 33 #define CC1200_TX_FIFO 0 // address flag to access TX FIFO
Jamie Smith 0:0c3532738887 34
Jamie Smith 0:0c3532738887 35
Jamie Smith 0:0c3532738887 36 #define CC1200_PART_NUMBER ((uint8_t)0x20) // part number we expect the chip to read
Jamie Smith 0:0c3532738887 37 #define CC1201_PART_NUMBER ((uint8_t)0x21)
Jamie Smith 0:0c3532738887 38 #define CC1200_EXT_ADDR 0x2F // SPI initial byte address indicating extended register space
Jamie Smith 0:0c3532738887 39
Jamie Smith 0:0c3532738887 40 #define SPI_MODE 0
Jamie Smith 0:0c3532738887 41 #define SPI_FREQ 5000000 // hz
Jamie Smith 0:0c3532738887 42 // NOTE: the chip supports a higher frequency for most operations but reads to extended registers require a lower frequency
Jamie Smith 0:0c3532738887 43
Jamie Smith 0:0c3532738887 44 // frequency of the chip's crystal oscillator
Jamie Smith 0:0c3532738887 45 #define CC1200_OSC_FREQ 40000000 // hz
Jamie Smith 0:0c3532738887 46 #define CC1200_OSC_FREQ_LOG2 25.253496f // log2 of above number
Jamie Smith 0:0c3532738887 47
Jamie Smith 0:0c3532738887 48 // length of the TX and RX FIFOS
Jamie Smith 0:0c3532738887 49 #define CC1200_FIFO_SIZE 128
Jamie Smith 0:0c3532738887 50
Jamie Smith 0:0c3532738887 51 // maximum length of the packets we can send, including the length byte which we add.
Jamie Smith 0:0c3532738887 52 // Since the TX and RX FIFOs are 128 bytes, supporting packet lengths longer than 128 bytes
Jamie Smith 0:0c3532738887 53 // requires streaming bytes in during the transmission, which would make things complicated.
Jamie Smith 0:0c3532738887 54 #define MAX_PACKET_LENGTH 128
Jamie Smith 0:0c3532738887 55
Jamie Smith 0:0c3532738887 56 // utility function: compile-time power calculator.
Jamie Smith 0:0c3532738887 57 // Works on all signed and unsigned integer types for T.
Jamie Smith 0:0c3532738887 58 // from: http://prosepoetrycode.potterpcs.net/2015/07/a-simple-constexpr-power-function-c/
Jamie Smith 0:0c3532738887 59 template <typename T>
Jamie Smith 0:0c3532738887 60 constexpr T constexpr_pow(T num, unsigned int pow)
Jamie Smith 0:0c3532738887 61 {
Jamie Smith 0:0c3532738887 62 return pow == 0 ? 1 : num * constexpr_pow(num, pow-1);
Jamie Smith 0:0c3532738887 63 }
Jamie Smith 0:0c3532738887 64
Jamie Smith 0:0c3532738887 65 // power of two constants
Jamie Smith 0:0c3532738887 66 const float twoToThe16 = constexpr_pow(2.0f, 16);
Jamie Smith 0:0c3532738887 67 const float twoToThe20 = constexpr_pow(2.0f, 20);
Jamie Smith 0:0c3532738887 68 const float twoToThe21 = constexpr_pow(2.0f, 21);
Jamie Smith 0:0c3532738887 69 const float twoToThe22 = constexpr_pow(2.0f, 22);
Jamie Smith 0:0c3532738887 70 const float twoToThe38 = constexpr_pow(2.0f, 38);
Jamie Smith 0:0c3532738887 71 const float twoToThe39 = constexpr_pow(2.0f, 39);
Jamie Smith 0:0c3532738887 72
Jamie Smith 0:0c3532738887 73 // binary value size constants
Jamie Smith 0:0c3532738887 74 const size_t maxValue3Bits = constexpr_pow(2, 3) - 1;
Jamie Smith 0:0c3532738887 75 const size_t maxValue4Bits = constexpr_pow(2, 4) - 1;
Jamie Smith 0:0c3532738887 76 const size_t maxValue8Bits = constexpr_pow(2, 8) - 1;
Jamie Smith 0:0c3532738887 77 const size_t maxValue20Bits = constexpr_pow(2, 20) - 1;
Jamie Smith 0:0c3532738887 78 const size_t maxValue24Bits = constexpr_pow(2, 24) - 1;
Jamie Smith 0:0c3532738887 79
Jamie Smith 0:0c3532738887 80 CC1200::CC1200(PinName mosiPin, PinName misoPin, PinName sclkPin, PinName csPin, PinName rstPin, Stream * _debugStream, bool _isCC1201):
Jamie Smith 0:0c3532738887 81 spi(mosiPin, misoPin, sclkPin, csPin, use_gpio_ssel),
Jamie Smith 0:0c3532738887 82 rst(rstPin, 1),
Jamie Smith 0:0c3532738887 83 debugStream(_debugStream),
Jamie Smith 0:0c3532738887 84 isCC1201(_isCC1201)
Jamie Smith 0:0c3532738887 85 {
Jamie Smith 0:0c3532738887 86 spi.format(8, SPI_MODE);
Jamie Smith 0:0c3532738887 87 spi.frequency(SPI_FREQ);
Jamie Smith 0:0c3532738887 88 }
Jamie Smith 0:0c3532738887 89
Jamie Smith 0:0c3532738887 90 bool CC1200::begin()
Jamie Smith 0:0c3532738887 91 {
Jamie Smith 0:0c3532738887 92 chipReady = false;
Jamie Smith 0:0c3532738887 93
Jamie Smith 0:0c3532738887 94 // reset
Jamie Smith 0:0c3532738887 95 rst.write(0);
Jamie Smith 0:0c3532738887 96 wait_us(100);
Jamie Smith 0:0c3532738887 97 rst.write(1);
Jamie Smith 0:0c3532738887 98
Jamie Smith 2:2a447e8e50b8 99 const auto resetTimeout = 10ms;
Jamie Smith 0:0c3532738887 100 Timer timeoutTimer;
Jamie Smith 0:0c3532738887 101 timeoutTimer.start();
Jamie Smith 0:0c3532738887 102
Jamie Smith 0:0c3532738887 103 while(!chipReady)
Jamie Smith 0:0c3532738887 104 {
Jamie Smith 0:0c3532738887 105 // datasheet specifies 240us reset time
Jamie Smith 0:0c3532738887 106 wait_us(250);
Jamie Smith 0:0c3532738887 107 updateState();
Jamie Smith 0:0c3532738887 108
Jamie Smith 2:2a447e8e50b8 109 if(timeoutTimer.elapsed_time() > resetTimeout)
Jamie Smith 0:0c3532738887 110 {
Jamie Smith 0:0c3532738887 111 debugStream->printf("Timeout waiting for ready response from CC1200\n");
Jamie Smith 0:0c3532738887 112 return false;
Jamie Smith 0:0c3532738887 113 }
Jamie Smith 0:0c3532738887 114 }
Jamie Smith 0:0c3532738887 115
Jamie Smith 0:0c3532738887 116 // read ID register
Jamie Smith 0:0c3532738887 117 uint8_t partNumber = readRegister(ExtRegister::PARTNUMBER);
Jamie Smith 0:0c3532738887 118 uint8_t partVersion = readRegister(ExtRegister::PARTVERSION);
Jamie Smith 0:0c3532738887 119
Jamie Smith 0:0c3532738887 120 uint8_t expectedPartNumber = isCC1201 ? CC1201_PART_NUMBER : CC1200_PART_NUMBER;
Jamie Smith 0:0c3532738887 121 if(partNumber != expectedPartNumber)
Jamie Smith 0:0c3532738887 122 {
Jamie Smith 0:0c3532738887 123 debugStream->printf("Read incorrect part number 0x%" PRIx8 " from CC1200, expected 0x%" PRIx8 "\n", partNumber, expectedPartNumber);
Jamie Smith 0:0c3532738887 124 return false;
Jamie Smith 0:0c3532738887 125 }
Jamie Smith 0:0c3532738887 126
Jamie Smith 0:0c3532738887 127 #if CC1200_DEBUG
Jamie Smith 0:0c3532738887 128 debugStream->printf("Detected CC1200, Part Number 0x%" PRIx8 ", Hardware Version %" PRIx8 "\n", partNumber, partVersion);
Jamie Smith 0:0c3532738887 129 #endif
Jamie Smith 0:0c3532738887 130
Jamie Smith 0:0c3532738887 131
Jamie Smith 0:0c3532738887 132 // Set packet format settings for this driver
Jamie Smith 0:0c3532738887 133 // ------------------------------------------------------------------------
Jamie Smith 0:0c3532738887 134
Jamie Smith 0:0c3532738887 135 // enable CRC but disable status bytes
Jamie Smith 0:0c3532738887 136 writeRegister(Register::PKT_CFG1, (0b01 << PKT_CFG1_CRC_CFG));
Jamie Smith 0:0c3532738887 137
Jamie Smith 0:0c3532738887 138 return true;
Jamie Smith 0:0c3532738887 139 }
Jamie Smith 0:0c3532738887 140
Jamie Smith 0:0c3532738887 141 size_t CC1200::getTXFIFOLen()
Jamie Smith 0:0c3532738887 142 {
Jamie Smith 0:0c3532738887 143 return readRegister(ExtRegister::NUM_TXBYTES);
Jamie Smith 0:0c3532738887 144 }
Jamie Smith 0:0c3532738887 145
Jamie Smith 0:0c3532738887 146 size_t CC1200::getRXFIFOLen()
Jamie Smith 0:0c3532738887 147 {
Jamie Smith 0:0c3532738887 148 return readRegister(ExtRegister::NUM_RXBYTES);
Jamie Smith 0:0c3532738887 149 }
Jamie Smith 0:0c3532738887 150
Jamie Smith 0:0c3532738887 151 bool CC1200::enqueuePacket(char const * data, size_t len)
Jamie Smith 0:0c3532738887 152 {
Jamie Smith 0:0c3532738887 153 uint8_t totalLength = len + 1; // add one byte for length byte
Jamie Smith 0:0c3532738887 154
Jamie Smith 0:0c3532738887 155 if(totalLength > MAX_PACKET_LENGTH)
Jamie Smith 0:0c3532738887 156 {
Jamie Smith 0:0c3532738887 157 // packet too big
Jamie Smith 0:0c3532738887 158 return false;
Jamie Smith 0:0c3532738887 159 }
Jamie Smith 0:0c3532738887 160
Jamie Smith 0:0c3532738887 161 uint8_t txFreeBytes = CC1200_FIFO_SIZE - getTXFIFOLen();
Jamie Smith 0:0c3532738887 162 if(totalLength > txFreeBytes)
Jamie Smith 0:0c3532738887 163 {
Jamie Smith 0:0c3532738887 164 // packet doesn't fit in TX FIFO
Jamie Smith 0:0c3532738887 165 return false;
Jamie Smith 0:0c3532738887 166 }
Jamie Smith 0:0c3532738887 167
Jamie Smith 0:0c3532738887 168 // burst write to TX FIFO
Jamie Smith 0:0c3532738887 169 spi.select();
Jamie Smith 0:0c3532738887 170 loadStatusByte(spi.write(CC1200_ENQUEUE_TX_FIFO | CC1200_BURST));
Jamie Smith 4:c609cc7c9ea7 171 if(_packetMode == PacketMode::VARIABLE_LENGTH)
Jamie Smith 4:c609cc7c9ea7 172 {
Jamie Smith 4:c609cc7c9ea7 173 spi.write(len);
Jamie Smith 4:c609cc7c9ea7 174 }
Jamie Smith 0:0c3532738887 175 for(size_t byteIndex = 0; byteIndex < len; ++byteIndex)
Jamie Smith 0:0c3532738887 176 {
Jamie Smith 0:0c3532738887 177 spi.write(data[byteIndex]);
Jamie Smith 0:0c3532738887 178 }
Jamie Smith 0:0c3532738887 179 spi.deselect();
Jamie Smith 0:0c3532738887 180
Jamie Smith 0:0c3532738887 181 #if CC1200_REGISTER_LEVEL_DEBUG
Jamie Smith 4:c609cc7c9ea7 182 debugStream->printf("Wrote packet of data length %zu:", len);
Jamie Smith 4:c609cc7c9ea7 183 if(_packetMode == PacketMode::VARIABLE_LENGTH)
Jamie Smith 4:c609cc7c9ea7 184 {
Jamie Smith 4:c609cc7c9ea7 185 debugStream->printf(" %02" PRIx8, static_cast<uint8_t>(len));
Jamie Smith 4:c609cc7c9ea7 186 }
Jamie Smith 0:0c3532738887 187 for(size_t byteIndex = 0; byteIndex < len; ++byteIndex)
Jamie Smith 0:0c3532738887 188 {
Jamie Smith 4:c609cc7c9ea7 189 debugStream->printf(" %02" PRIx8, data[byteIndex]);
Jamie Smith 0:0c3532738887 190 }
Jamie Smith 0:0c3532738887 191 debugStream->printf("\n");
Jamie Smith 0:0c3532738887 192 #endif
Jamie Smith 0:0c3532738887 193 return true;
Jamie Smith 0:0c3532738887 194 }
Jamie Smith 0:0c3532738887 195
Jamie Smith 0:0c3532738887 196 bool CC1200::hasReceivedPacket()
Jamie Smith 0:0c3532738887 197 {
Jamie Smith 0:0c3532738887 198 size_t bytesReceived = getRXFIFOLen();
Jamie Smith 0:0c3532738887 199
Jamie Smith 0:0c3532738887 200 if(bytesReceived < 1)
Jamie Smith 0:0c3532738887 201 {
Jamie Smith 0:0c3532738887 202 // no bytes at all, can't check the length
Jamie Smith 0:0c3532738887 203 return false;
Jamie Smith 0:0c3532738887 204 }
Jamie Smith 0:0c3532738887 205
Jamie Smith 4:c609cc7c9ea7 206 if(_packetMode == PacketMode::FIXED_LENGTH)
Jamie Smith 4:c609cc7c9ea7 207 {
Jamie Smith 4:c609cc7c9ea7 208 return bytesReceived >= _packetTotalLength;
Jamie Smith 4:c609cc7c9ea7 209 }
Jamie Smith 4:c609cc7c9ea7 210 else // _packetMode == PacketMode::VARIABLE_LENGTH
Jamie Smith 4:c609cc7c9ea7 211 {
Jamie Smith 4:c609cc7c9ea7 212 // get value of first byte of the packet, which is the length.
Jamie Smith 2:2a447e8e50b8 213
Jamie Smith 4:c609cc7c9ea7 214 // The datasheet is wrong about this! It says that the first byte in the RX FIFO can
Jamie Smith 4:c609cc7c9ea7 215 // be found by accessing address RXFIRST via direct fifo access.
Jamie Smith 4:c609cc7c9ea7 216 // However, in my own testing, RXFIRST points to the second entry in the FIFO, and
Jamie Smith 4:c609cc7c9ea7 217 // the first entry must be accessed through RXFIFO_PRE_BUF.
Jamie Smith 4:c609cc7c9ea7 218 uint8_t packetLen = readRegister(ExtRegister::RXFIFO_PRE_BUF);
Jamie Smith 0:0c3532738887 219
Jamie Smith 4:c609cc7c9ea7 220 // if we have received a full packet's worth of bytes, then we have received a full packet.
Jamie Smith 4:c609cc7c9ea7 221 return bytesReceived >= static_cast<size_t>(packetLen + 1); // Add one because length field does not include itself
Jamie Smith 4:c609cc7c9ea7 222 }
Jamie Smith 0:0c3532738887 223 }
Jamie Smith 0:0c3532738887 224
Jamie Smith 0:0c3532738887 225 size_t CC1200::receivePacket(char *buffer, size_t bufferLen)
Jamie Smith 0:0c3532738887 226 {
Jamie Smith 0:0c3532738887 227 // burst read from RX FIFO
Jamie Smith 0:0c3532738887 228 spi.select();
Jamie Smith 0:0c3532738887 229 loadStatusByte(spi.write(CC1200_DEQUEUE_RX_FIFO | CC1200_BURST));
Jamie Smith 0:0c3532738887 230
Jamie Smith 4:c609cc7c9ea7 231 uint8_t dataLen;
Jamie Smith 4:c609cc7c9ea7 232 if(_packetMode == PacketMode::VARIABLE_LENGTH)
Jamie Smith 4:c609cc7c9ea7 233 {
Jamie Smith 4:c609cc7c9ea7 234 // first read length byte
Jamie Smith 4:c609cc7c9ea7 235 dataLen = spi.write(0);
Jamie Smith 4:c609cc7c9ea7 236 }
Jamie Smith 4:c609cc7c9ea7 237 else // _packetMode == PacketMode::FIXED_LENGTH)
Jamie Smith 4:c609cc7c9ea7 238 {
Jamie Smith 4:c609cc7c9ea7 239 dataLen = _packetTotalLength;
Jamie Smith 4:c609cc7c9ea7 240 }
Jamie Smith 0:0c3532738887 241
Jamie Smith 0:0c3532738887 242 for(size_t byteIndex = 0; byteIndex < dataLen; ++byteIndex)
Jamie Smith 0:0c3532738887 243 {
Jamie Smith 0:0c3532738887 244 uint8_t currByte = spi.write(0);
Jamie Smith 0:0c3532738887 245 if(byteIndex < bufferLen)
Jamie Smith 0:0c3532738887 246 {
Jamie Smith 0:0c3532738887 247 buffer[byteIndex] = currByte;
Jamie Smith 0:0c3532738887 248 }
Jamie Smith 0:0c3532738887 249 }
Jamie Smith 0:0c3532738887 250 spi.deselect();
Jamie Smith 0:0c3532738887 251
Jamie Smith 0:0c3532738887 252 #if CC1200_REGISTER_LEVEL_DEBUG
Jamie Smith 0:0c3532738887 253 debugStream->printf("Read packet of data length %" PRIu8 ": %" PRIx8, dataLen, static_cast<uint8_t>(dataLen));
Jamie Smith 0:0c3532738887 254 for(size_t byteIndex = 0; byteIndex < dataLen; ++byteIndex)
Jamie Smith 0:0c3532738887 255 {
Jamie Smith 0:0c3532738887 256 debugStream->printf(" %" PRIx8, buffer[byteIndex]);
Jamie Smith 0:0c3532738887 257 }
Jamie Smith 0:0c3532738887 258 debugStream->printf("\n");
Jamie Smith 0:0c3532738887 259 #endif
Jamie Smith 0:0c3532738887 260
Jamie Smith 0:0c3532738887 261 return dataLen;
Jamie Smith 0:0c3532738887 262 }
Jamie Smith 0:0c3532738887 263
Jamie Smith 0:0c3532738887 264 // helper function: convert a state to the bits for RXOFF_MODE and TXOFF_MODE
Jamie Smith 0:0c3532738887 265 inline uint8_t getOffModeBits(CC1200::State state)
Jamie Smith 0:0c3532738887 266 {
Jamie Smith 0:0c3532738887 267 uint8_t offBits = 0b0;
Jamie Smith 0:0c3532738887 268 if(state == CC1200::State::IDLE)
Jamie Smith 0:0c3532738887 269 {
Jamie Smith 0:0c3532738887 270 offBits = 0b0;
Jamie Smith 0:0c3532738887 271 }
Jamie Smith 0:0c3532738887 272 else if(state == CC1200::State::FAST_ON)
Jamie Smith 0:0c3532738887 273 {
Jamie Smith 0:0c3532738887 274 offBits = 0b1;
Jamie Smith 0:0c3532738887 275 }
Jamie Smith 0:0c3532738887 276 else if(state == CC1200::State::TX)
Jamie Smith 0:0c3532738887 277 {
Jamie Smith 0:0c3532738887 278 offBits = 0b10;
Jamie Smith 0:0c3532738887 279 }
Jamie Smith 0:0c3532738887 280 else if(state == CC1200::State::RX)
Jamie Smith 0:0c3532738887 281 {
Jamie Smith 0:0c3532738887 282 offBits = 0b11;
Jamie Smith 0:0c3532738887 283 }
Jamie Smith 0:0c3532738887 284 return offBits;
Jamie Smith 0:0c3532738887 285 }
Jamie Smith 0:0c3532738887 286
Jamie Smith 0:0c3532738887 287 void CC1200::setOnReceiveState(CC1200::State goodPacket, CC1200::State badPacket)
Jamie Smith 0:0c3532738887 288 {
Jamie Smith 0:0c3532738887 289 // configure good packet action via RXOFF_MODE
Jamie Smith 0:0c3532738887 290 uint8_t rfendCfg1 = readRegister(Register::RFEND_CFG1);
Jamie Smith 0:0c3532738887 291 rfendCfg1 &= ~(0b11 << RFEND_CFG1_RXOFF_MODE);
Jamie Smith 0:0c3532738887 292 rfendCfg1 |= getOffModeBits(goodPacket) << RFEND_CFG1_RXOFF_MODE;
Jamie Smith 0:0c3532738887 293 writeRegister(Register::RFEND_CFG1, rfendCfg1);
Jamie Smith 0:0c3532738887 294
Jamie Smith 0:0c3532738887 295 // configure bad packet action via TERM_ON_BAD_PACKET_EN
Jamie Smith 0:0c3532738887 296 uint8_t rfendCfg0 = readRegister(Register::RFEND_CFG0);
Jamie Smith 0:0c3532738887 297 if(badPacket == State::RX)
Jamie Smith 0:0c3532738887 298 {
Jamie Smith 0:0c3532738887 299 rfendCfg0 &= ~(1 << RFEND_CFG0_TERM_ON_BAD_PACKET_EN);
Jamie Smith 0:0c3532738887 300 }
Jamie Smith 0:0c3532738887 301 else
Jamie Smith 0:0c3532738887 302 {
Jamie Smith 0:0c3532738887 303 rfendCfg0 |= 1 << RFEND_CFG1_RXOFF_MODE;
Jamie Smith 0:0c3532738887 304 }
Jamie Smith 0:0c3532738887 305 writeRegister(Register::RFEND_CFG0, rfendCfg0);
Jamie Smith 0:0c3532738887 306 }
Jamie Smith 0:0c3532738887 307
Jamie Smith 1:98af824b145e 308 void CC1200::setOnTransmitState(CC1200::State txState)
Jamie Smith 0:0c3532738887 309 {
Jamie Smith 0:0c3532738887 310 uint8_t rfendCfg0 = readRegister(Register::RFEND_CFG0);
Jamie Smith 0:0c3532738887 311 rfendCfg0 &= ~(0b11 << RFEND_CFG0_TXOFF_MODE);
Jamie Smith 1:98af824b145e 312 rfendCfg0 |= getOffModeBits(txState) << RFEND_CFG0_TXOFF_MODE;
Jamie Smith 0:0c3532738887 313 writeRegister(Register::RFEND_CFG0, rfendCfg0);
Jamie Smith 0:0c3532738887 314 }
Jamie Smith 0:0c3532738887 315
Jamie Smith 0:0c3532738887 316 void CC1200::setFSCalMode(FSCalMode mode)
Jamie Smith 0:0c3532738887 317 {
Jamie Smith 0:0c3532738887 318 uint8_t settlingCfg = readRegister(Register::SETTLING_CFG);
Jamie Smith 0:0c3532738887 319 settlingCfg &= ~(0b11 << SETTLING_CFG_FS_AUTOCAL);
Jamie Smith 0:0c3532738887 320 settlingCfg |= static_cast<uint8_t>(mode) << SETTLING_CFG_FS_AUTOCAL;
Jamie Smith 0:0c3532738887 321 writeRegister(Register::SETTLING_CFG, settlingCfg);
Jamie Smith 0:0c3532738887 322 }
Jamie Smith 0:0c3532738887 323
Jamie Smith 0:0c3532738887 324 void CC1200::configureGPIO(uint8_t gpioNumber, CC1200::GPIOMode mode, bool outputInvert)
Jamie Smith 0:0c3532738887 325 {
Jamie Smith 0:0c3532738887 326 // gpio 3 is the first register, then it goes down to 0
Jamie Smith 0:0c3532738887 327 Register gpioReg = static_cast<Register>(static_cast<uint8_t>(Register::IOCFG3) + (3 - gpioNumber));
Jamie Smith 0:0c3532738887 328
Jamie Smith 0:0c3532738887 329 uint8_t gpioCfgVal = static_cast<uint8_t>(mode);
Jamie Smith 0:0c3532738887 330 if(outputInvert)
Jamie Smith 0:0c3532738887 331 {
Jamie Smith 0:0c3532738887 332 gpioCfgVal |= (1 << GPIO_INV);
Jamie Smith 0:0c3532738887 333 }
Jamie Smith 0:0c3532738887 334 writeRegister(gpioReg, gpioCfgVal);
Jamie Smith 0:0c3532738887 335 }
Jamie Smith 0:0c3532738887 336
Jamie Smith 0:0c3532738887 337 void CC1200::configureFIFOMode()
Jamie Smith 0:0c3532738887 338 {
Jamie Smith 0:0c3532738887 339 // configure packet format
Jamie Smith 0:0c3532738887 340 uint8_t pktCfg2 = readRegister(Register::PKT_CFG2);
Jamie Smith 0:0c3532738887 341 pktCfg2 &= ~(0b11 << PKT_CFG2_PKT_FORMAT);
Jamie Smith 0:0c3532738887 342 writeRegister(Register::PKT_CFG2, pktCfg2);
Jamie Smith 0:0c3532738887 343
Jamie Smith 0:0c3532738887 344 // enable fifo
Jamie Smith 0:0c3532738887 345 uint8_t mdmCfg1 = readRegister(Register::MDMCFG1);
Jamie Smith 0:0c3532738887 346 mdmCfg1 |= 1 << MDMCFG1_FIFO_EN;
Jamie Smith 0:0c3532738887 347 writeRegister(Register::MDMCFG1, mdmCfg1);
Jamie Smith 0:0c3532738887 348
Jamie Smith 0:0c3532738887 349 // make sure transparent mode is disabled
Jamie Smith 0:0c3532738887 350 uint8_t mdmCfg0 = readRegister(Register::MDMCFG0);
Jamie Smith 0:0c3532738887 351 mdmCfg0 &= ~(1 << MDMCFG0_TRANSPARENT_MODE_EN);
Jamie Smith 0:0c3532738887 352 writeRegister(Register::MDMCFG0, mdmCfg0);
Jamie Smith 0:0c3532738887 353 }
Jamie Smith 0:0c3532738887 354
Jamie Smith 4:c609cc7c9ea7 355 void CC1200::setPacketMode(PacketMode mode)
Jamie Smith 4:c609cc7c9ea7 356 {
Jamie Smith 4:c609cc7c9ea7 357 _packetMode = mode;
Jamie Smith 4:c609cc7c9ea7 358
Jamie Smith 4:c609cc7c9ea7 359 uint8_t pktCfg0 = readRegister(Register::PKT_CFG0);
Jamie Smith 4:c609cc7c9ea7 360 // set length config field
Jamie Smith 4:c609cc7c9ea7 361 pktCfg0 &= ~(0b11 << PKT_CFG0_LENGTH_CONFIG);
Jamie Smith 4:c609cc7c9ea7 362 pktCfg0 |= static_cast<uint8_t>(mode) << PKT_CFG0_LENGTH_CONFIG;
Jamie Smith 4:c609cc7c9ea7 363 writeRegister(Register::PKT_CFG0, pktCfg0);
Jamie Smith 4:c609cc7c9ea7 364
Jamie Smith 4:c609cc7c9ea7 365 if(mode == PacketMode::VARIABLE_LENGTH)
Jamie Smith 4:c609cc7c9ea7 366 {
Jamie Smith 4:c609cc7c9ea7 367 // disable packet length limit
Jamie Smith 4:c609cc7c9ea7 368 writeRegister(Register::PKT_LEN, MAX_PACKET_LENGTH);
Jamie Smith 4:c609cc7c9ea7 369 }
Jamie Smith 4:c609cc7c9ea7 370 else
Jamie Smith 4:c609cc7c9ea7 371 {
Jamie Smith 4:c609cc7c9ea7 372 // reset to selected fixed lengths
Jamie Smith 4:c609cc7c9ea7 373 setPacketLength(_packetByteLength, _packetBitLength);
Jamie Smith 4:c609cc7c9ea7 374 }
Jamie Smith 4:c609cc7c9ea7 375 }
Jamie Smith 4:c609cc7c9ea7 376
Jamie Smith 4:c609cc7c9ea7 377 void CC1200::setPacketLength(uint8_t length, uint8_t bitLength)
Jamie Smith 4:c609cc7c9ea7 378 {
Jamie Smith 4:c609cc7c9ea7 379 _packetByteLength = length;
Jamie Smith 4:c609cc7c9ea7 380 _packetBitLength = bitLength;
Jamie Smith 4:c609cc7c9ea7 381 _packetTotalLength = _packetByteLength;
Jamie Smith 4:c609cc7c9ea7 382
Jamie Smith 4:c609cc7c9ea7 383 if(bitLength > 0)
Jamie Smith 4:c609cc7c9ea7 384 {
Jamie Smith 4:c609cc7c9ea7 385 // tell the driver to read the extra bits into another byte
Jamie Smith 4:c609cc7c9ea7 386 _packetTotalLength++;
Jamie Smith 4:c609cc7c9ea7 387 }
Jamie Smith 4:c609cc7c9ea7 388
Jamie Smith 4:c609cc7c9ea7 389 writeRegister(Register::PKT_LEN, _packetByteLength);
Jamie Smith 4:c609cc7c9ea7 390
Jamie Smith 4:c609cc7c9ea7 391 uint8_t pktCfg0 = readRegister(Register::PKT_CFG0);
Jamie Smith 4:c609cc7c9ea7 392 pktCfg0 &= ~(0b111 << PKT_CFG0_PKT_BIT_LEN);
Jamie Smith 4:c609cc7c9ea7 393 pktCfg0 |= _packetBitLength << PKT_CFG0_PKT_BIT_LEN;
Jamie Smith 4:c609cc7c9ea7 394 writeRegister(Register::PKT_CFG0, pktCfg0);
Jamie Smith 4:c609cc7c9ea7 395
Jamie Smith 4:c609cc7c9ea7 396 #if CC1200_DEBUG
Jamie Smith 4:c609cc7c9ea7 397 debugStream->printf("Set total length to %zu, byte length = %zu, bit length = %" PRIu8 "\n", _packetTotalLength, _packetByteLength, _packetBitLength);
Jamie Smith 4:c609cc7c9ea7 398 #endif
Jamie Smith 4:c609cc7c9ea7 399 }
Jamie Smith 4:c609cc7c9ea7 400
Jamie Smith 4:c609cc7c9ea7 401 void CC1200::setCRCEnabled(bool enabled)
Jamie Smith 4:c609cc7c9ea7 402 {
Jamie Smith 4:c609cc7c9ea7 403 uint8_t pktCfg1 = readRegister(Register::PKT_CFG1);
Jamie Smith 4:c609cc7c9ea7 404 pktCfg1 &= ~(0b11 << PKT_CFG1_CRC_CFG);
Jamie Smith 4:c609cc7c9ea7 405 pktCfg1 |= (enabled ? 0b01 : 0b00) << PKT_CFG1_CRC_CFG;
Jamie Smith 4:c609cc7c9ea7 406 writeRegister(Register::PKT_CFG1, pktCfg1);
Jamie Smith 4:c609cc7c9ea7 407 }
Jamie Smith 4:c609cc7c9ea7 408
Jamie Smith 0:0c3532738887 409 void CC1200::setModulationFormat(CC1200::ModFormat format)
Jamie Smith 0:0c3532738887 410 {
Jamie Smith 0:0c3532738887 411 uint8_t modcfgDevE = readRegister(Register::MODCFG_DEV_E);
Jamie Smith 0:0c3532738887 412 modcfgDevE &= ~(0b111 << MODCFG_DEV_E_MOD_FORMAT);
Jamie Smith 4:c609cc7c9ea7 413 modcfgDevE |= static_cast<uint8_t>(format) << MODCFG_DEV_E_MOD_FORMAT;
Jamie Smith 0:0c3532738887 414 writeRegister(Register::MODCFG_DEV_E, modcfgDevE);
Jamie Smith 0:0c3532738887 415 }
Jamie Smith 0:0c3532738887 416
Jamie Smith 0:0c3532738887 417 void CC1200::setFSKDeviation(float deviation)
Jamie Smith 0:0c3532738887 418 {
Jamie Smith 0:0c3532738887 419 // Deviation is set as two values, an exponent register from 0-3 and a mantissa register from 0-256.
Jamie Smith 0:0c3532738887 420 // See user guide page 81 for the original equation, this function was worked out from that
Jamie Smith 0:0c3532738887 421
Jamie Smith 0:0c3532738887 422 // First assume mantissa is zero and calculate the needed exponent
Jamie Smith 0:0c3532738887 423 float exactExponent = std::log2(deviation) - CC1200_OSC_FREQ_LOG2 + 14;
Jamie Smith 0:0c3532738887 424 uint8_t actualExponent = static_cast<uint8_t>(std::min(static_cast<float>(maxValue3Bits), exactExponent));
Jamie Smith 0:0c3532738887 425 // note: 14 comes from log2(2^22) - log2(256)
Jamie Smith 0:0c3532738887 426
Jamie Smith 0:0c3532738887 427 float exactMantissa;
Jamie Smith 0:0c3532738887 428 if(actualExponent >= 1)
Jamie Smith 0:0c3532738887 429 {
Jamie Smith 0:0c3532738887 430 exactMantissa = (std::pow(2.0f, static_cast<float>(22 - actualExponent)) * deviation)
Jamie Smith 0:0c3532738887 431 / CC1200_OSC_FREQ - 256;
Jamie Smith 0:0c3532738887 432 }
Jamie Smith 0:0c3532738887 433 else
Jamie Smith 0:0c3532738887 434 {
Jamie Smith 0:0c3532738887 435 // use alternate high-resolution formula for case where exponent = 0
Jamie Smith 0:0c3532738887 436 exactMantissa = deviation * twoToThe21 / CC1200_OSC_FREQ;
Jamie Smith 0:0c3532738887 437 }
Jamie Smith 0:0c3532738887 438
Jamie Smith 0:0c3532738887 439 // now calculate closest mantissa
Jamie Smith 0:0c3532738887 440 uint8_t actualMantissa = static_cast<uint8_t>(std::min(static_cast<float>(maxValue8Bits), exactMantissa));
Jamie Smith 0:0c3532738887 441
Jamie Smith 0:0c3532738887 442 // set exponent and mantissa
Jamie Smith 0:0c3532738887 443 writeRegister(Register::DEVIATION_M, actualMantissa);
Jamie Smith 0:0c3532738887 444
Jamie Smith 0:0c3532738887 445 uint8_t modcfgDevE = readRegister(Register::MODCFG_DEV_E);
Jamie Smith 0:0c3532738887 446 modcfgDevE &= ~(0b111 << MODCFG_DEV_E_DEV_E);
Jamie Smith 0:0c3532738887 447 modcfgDevE |= actualExponent << MODCFG_DEV_E_DEV_E;
Jamie Smith 0:0c3532738887 448 writeRegister(Register::MODCFG_DEV_E, modcfgDevE);
Jamie Smith 0:0c3532738887 449
Jamie Smith 0:0c3532738887 450 #if CC1200_DEBUG
Jamie Smith 0:0c3532738887 451 debugStream->printf("Setting FSK deviation, requested +-%.00f Hz, setting DEV_E = 0x%" PRIx8 " DEV_M = 0x%" PRIx8 "\n",
Jamie Smith 0:0c3532738887 452 deviation, actualExponent, actualMantissa);
Jamie Smith 0:0c3532738887 453
Jamie Smith 0:0c3532738887 454 float actualDeviation;
Jamie Smith 0:0c3532738887 455 if(actualExponent == 0)
Jamie Smith 0:0c3532738887 456 {
Jamie Smith 0:0c3532738887 457 actualDeviation = CC1200_OSC_FREQ * actualMantissa / twoToThe21;
Jamie Smith 0:0c3532738887 458 }
Jamie Smith 0:0c3532738887 459 else
Jamie Smith 0:0c3532738887 460 {
Jamie Smith 0:0c3532738887 461 actualDeviation = (CC1200_OSC_FREQ / twoToThe22) * (256.0f + static_cast<float>(actualMantissa)) * pow(2.0f, static_cast<float>(actualExponent));
Jamie Smith 0:0c3532738887 462 }
Jamie Smith 0:0c3532738887 463 // sanity check: calculate actual deviation
Jamie Smith 0:0c3532738887 464 debugStream->printf("This yields an actual deviation of +-%.00f Hz\n", actualDeviation);
Jamie Smith 0:0c3532738887 465 #endif
Jamie Smith 0:0c3532738887 466 }
Jamie Smith 0:0c3532738887 467
Jamie Smith 0:0c3532738887 468 void CC1200::setSymbolRate(float symbolRateHz)
Jamie Smith 0:0c3532738887 469 {
Jamie Smith 0:0c3532738887 470 // Datasheet says that the cc1200 works in ksps, but testing with SmartRF studio
Jamie Smith 0:0c3532738887 471 // shows that it actually is sps.
Jamie Smith 0:0c3532738887 472
Jamie Smith 0:0c3532738887 473 symbolRateSps = symbolRateHz;
Jamie Smith 0:0c3532738887 474
Jamie Smith 0:0c3532738887 475 // Note: these equations are given on page 29 of the user guide
Jamie Smith 0:0c3532738887 476
Jamie Smith 0:0c3532738887 477 float exactExponent = std::log2(symbolRateSps) - CC1200_OSC_FREQ_LOG2 + 19;
Jamie Smith 0:0c3532738887 478 // note: 19 comes from log2(2^39) - 20
Jamie Smith 0:0c3532738887 479 uint8_t actualExponent = static_cast<uint8_t>(std::min(static_cast<float>(maxValue4Bits), exactExponent));
Jamie Smith 0:0c3532738887 480
Jamie Smith 0:0c3532738887 481 float exactMantissa;
Jamie Smith 0:0c3532738887 482 if(actualExponent >= 1)
Jamie Smith 0:0c3532738887 483 {
Jamie Smith 0:0c3532738887 484 exactMantissa = (std::pow(2.0f, static_cast<float>(39 - actualExponent)) * symbolRateSps)
Jamie Smith 0:0c3532738887 485 / CC1200_OSC_FREQ - twoToThe20;
Jamie Smith 0:0c3532738887 486 }
Jamie Smith 0:0c3532738887 487 else
Jamie Smith 0:0c3532738887 488 {
Jamie Smith 0:0c3532738887 489 // use alternate high-resolution formula for case where exponent = 0
Jamie Smith 0:0c3532738887 490 exactMantissa = symbolRateSps * twoToThe38 / CC1200_OSC_FREQ;
Jamie Smith 0:0c3532738887 491 }
Jamie Smith 0:0c3532738887 492
Jamie Smith 0:0c3532738887 493 // mantissa is a 20 bit number, so restrict it to that domain
Jamie Smith 0:0c3532738887 494 uint32_t actualMantissa = static_cast<uint32_t>(std::min(static_cast<float>(maxValue20Bits), exactMantissa));
Jamie Smith 0:0c3532738887 495
Jamie Smith 0:0c3532738887 496 // program symbol rate registers
Jamie Smith 0:0c3532738887 497 std::array<uint8_t, 3> symbolRateRegisters ={
Jamie Smith 0:0c3532738887 498 static_cast<uint8_t>((actualExponent << SYMBOL_RATE2_SRATE_E) | (static_cast<uint8_t>((actualMantissa >> 16) & 0xFF) << SYMBOL_RATE2_SRATE_M_19_16)),
Jamie Smith 0:0c3532738887 499 static_cast<uint8_t>((actualMantissa >> 8) & 0xFF),
Jamie Smith 0:0c3532738887 500 static_cast<uint8_t>((actualMantissa & 0xFF))
Jamie Smith 0:0c3532738887 501 };
Jamie Smith 0:0c3532738887 502 writeRegisters(Register::SYMBOL_RATE2, symbolRateRegisters);
Jamie Smith 0:0c3532738887 503
Jamie Smith 4:c609cc7c9ea7 504 // Calculate upsampler value according to the formula in its register description
Jamie Smith 4:c609cc7c9ea7 505 float upsamplingFactor = CC1200_OSC_FREQ / (64 * symbolRateSps); // 2^upsamplerPVal needs to be less than this value
Jamie Smith 0:0c3532738887 506 uint8_t upsamplerPVal = std::floor(std::log2(upsamplingFactor));
Jamie Smith 0:0c3532738887 507
Jamie Smith 4:c609cc7c9ea7 508 // prevent low sampling rates from choosing a nonexistent upsampling
Jamie Smith 4:c609cc7c9ea7 509 upsamplerPVal = std::min<uint8_t>(upsamplerPVal, 0b110);
Jamie Smith 4:c609cc7c9ea7 510
Jamie Smith 0:0c3532738887 511 uint8_t mdmcfg2 = readRegister(ExtRegister::MDMCFG2);
Jamie Smith 0:0c3532738887 512 mdmcfg2 &= ~(0b111 << MDMCFG2_UPSAMPLER_P);
Jamie Smith 0:0c3532738887 513 mdmcfg2 |= (upsamplerPVal << MDMCFG2_UPSAMPLER_P);
Jamie Smith 0:0c3532738887 514
Jamie Smith 0:0c3532738887 515 writeRegister(ExtRegister::MDMCFG2, mdmcfg2);
Jamie Smith 0:0c3532738887 516
Jamie Smith 0:0c3532738887 517 #if CC1200_DEBUG
Jamie Smith 4:c609cc7c9ea7 518 debugStream->printf("Setting symbol rate, requested %.03f Hz, setting SRATE_E = 0x%" PRIx8 " SRATE_M = 0x%" PRIx32 "\n",
Jamie Smith 0:0c3532738887 519 symbolRateHz, actualExponent, actualMantissa);
Jamie Smith 0:0c3532738887 520
Jamie Smith 0:0c3532738887 521 // sanity check: calculate actual symbol rate
Jamie Smith 4:c609cc7c9ea7 522 float actualSymbolRateSps;
Jamie Smith 0:0c3532738887 523 if(actualExponent == 0)
Jamie Smith 0:0c3532738887 524 {
Jamie Smith 4:c609cc7c9ea7 525 actualSymbolRateSps = (static_cast<float>(actualMantissa) * CC1200_OSC_FREQ) / twoToThe38;
Jamie Smith 0:0c3532738887 526 }
Jamie Smith 0:0c3532738887 527 else
Jamie Smith 0:0c3532738887 528 {
Jamie Smith 0:0c3532738887 529
Jamie Smith 4:c609cc7c9ea7 530 actualSymbolRateSps = ((static_cast<float>(actualMantissa) + twoToThe20) *
Jamie Smith 4:c609cc7c9ea7 531 pow(2.0f,static_cast<float>(actualExponent)) * CC1200_OSC_FREQ)
Jamie Smith 4:c609cc7c9ea7 532 / twoToThe39;
Jamie Smith 0:0c3532738887 533 }
Jamie Smith 0:0c3532738887 534
Jamie Smith 4:c609cc7c9ea7 535 debugStream->printf("This yields an actual symbol rate of %.02f Hz\n", actualSymbolRateSps);
Jamie Smith 0:0c3532738887 536
Jamie Smith 0:0c3532738887 537 uint8_t actualUpsampling = static_cast<uint8_t>(pow(2.0f, static_cast<float>(upsamplerPVal)));
Jamie Smith 0:0c3532738887 538 debugStream->printf("Also setting upsampling factor to %" PRIu8 " via UPSAMPLER_P = %" PRIx8 "\n", actualUpsampling, upsamplerPVal);
Jamie Smith 0:0c3532738887 539 #endif
Jamie Smith 0:0c3532738887 540 }
Jamie Smith 0:0c3532738887 541
Jamie Smith 4:c609cc7c9ea7 542 // helper function for power setting
Jamie Smith 4:c609cc7c9ea7 543 inline uint8_t dBPowerToRegValue(float powerDB)
Jamie Smith 0:0c3532738887 544 {
Jamie Smith 0:0c3532738887 545 const float minOutputPower = -16.0f;
Jamie Smith 0:0c3532738887 546
Jamie Smith 0:0c3532738887 547 // note: datasheet says this is 14.5, but that must be a mistake: 14.5 would produce a number
Jamie Smith 0:0c3532738887 548 // too large to fit into 6 bits.
Jamie Smith 0:0c3532738887 549 const float maxOutputPower = 14.0f;
Jamie Smith 0:0c3532738887 550
Jamie Smith 0:0c3532738887 551 // clamp output power into correct range
Jamie Smith 4:c609cc7c9ea7 552 powerDB = std::min(powerDB, maxOutputPower);
Jamie Smith 4:c609cc7c9ea7 553 powerDB = std::max(powerDB, minOutputPower);
Jamie Smith 0:0c3532738887 554
Jamie Smith 0:0c3532738887 555 // this equation derived from user guide section 7.1
Jamie Smith 4:c609cc7c9ea7 556 float exactPowerRamp = (2 * powerDB) + 35;
Jamie Smith 4:c609cc7c9ea7 557 return static_cast<uint8_t>(exactPowerRamp); // round to nearest
Jamie Smith 4:c609cc7c9ea7 558 }
Jamie Smith 4:c609cc7c9ea7 559
Jamie Smith 4:c609cc7c9ea7 560 void CC1200::setOutputPower(float outPower)
Jamie Smith 4:c609cc7c9ea7 561 {
Jamie Smith 4:c609cc7c9ea7 562 uint8_t actualPowerRamp = dBPowerToRegValue(outPower);
Jamie Smith 0:0c3532738887 563
Jamie Smith 0:0c3532738887 564 uint8_t paCfg1 = readRegister(Register::PA_CFG1);
Jamie Smith 0:0c3532738887 565 paCfg1 &= ~(0b111111 << PA_CFG1_PA_POWER_RAMP);
Jamie Smith 0:0c3532738887 566 paCfg1 |= actualPowerRamp << PA_CFG1_PA_POWER_RAMP;
Jamie Smith 0:0c3532738887 567 writeRegister(Register::PA_CFG1, paCfg1);
Jamie Smith 0:0c3532738887 568 }
Jamie Smith 0:0c3532738887 569
Jamie Smith 4:c609cc7c9ea7 570 const float CC1200::ASK_MIN_POWER_OFF = -17.5f;
Jamie Smith 4:c609cc7c9ea7 571
Jamie Smith 4:c609cc7c9ea7 572 void CC1200::setASKPowers(float maxPower, float minPower)
Jamie Smith 4:c609cc7c9ea7 573 {
Jamie Smith 4:c609cc7c9ea7 574 uint8_t maxPowerValue = dBPowerToRegValue(maxPower);
Jamie Smith 4:c609cc7c9ea7 575
Jamie Smith 4:c609cc7c9ea7 576 minPower = std::min(minPower, maxPower);
Jamie Smith 4:c609cc7c9ea7 577 minPower = std::max(minPower, -17.5f);
Jamie Smith 4:c609cc7c9ea7 578
Jamie Smith 4:c609cc7c9ea7 579 // calculate min power using formula derived from manual
Jamie Smith 4:c609cc7c9ea7 580 uint8_t minPowerValue = static_cast<uint8_t>((maxPower - minPower) * 2);
Jamie Smith 4:c609cc7c9ea7 581
Jamie Smith 4:c609cc7c9ea7 582 // write registers
Jamie Smith 4:c609cc7c9ea7 583 uint8_t paCfg1 = readRegister(Register::PA_CFG1);
Jamie Smith 4:c609cc7c9ea7 584 paCfg1 &= ~(0b111111 << PA_CFG1_PA_POWER_RAMP);
Jamie Smith 4:c609cc7c9ea7 585 paCfg1 |= maxPowerValue << PA_CFG1_PA_POWER_RAMP;
Jamie Smith 4:c609cc7c9ea7 586 writeRegister(Register::PA_CFG1, paCfg1);
Jamie Smith 4:c609cc7c9ea7 587
Jamie Smith 4:c609cc7c9ea7 588 uint8_t askCfg = readRegister(Register::ASK_CFG);
Jamie Smith 4:c609cc7c9ea7 589 askCfg &= ~(0b111111 << ASK_CFG_ASK_DEPTH);
Jamie Smith 4:c609cc7c9ea7 590 askCfg |= minPowerValue << ASK_CFG_ASK_DEPTH;
Jamie Smith 4:c609cc7c9ea7 591 writeRegister(Register::ASK_CFG, askCfg);
Jamie Smith 4:c609cc7c9ea7 592 }
Jamie Smith 4:c609cc7c9ea7 593
Jamie Smith 0:0c3532738887 594 void CC1200::setRadioFrequency(CC1200::Band band, float frequencyHz)
Jamie Smith 0:0c3532738887 595 {
Jamie Smith 0:0c3532738887 596 // Frequency synthesizer configuration. This is completely opaque and it is unknown what these bits do --
Jamie Smith 0:0c3532738887 597 // they are only generated by SmartRF studio.
Jamie Smith 0:0c3532738887 598 // I manually deduplicated them since only a few change based on frequency.
Jamie Smith 0:0c3532738887 599 writeRegister(ExtRegister::IF_ADC1,0xEE);
Jamie Smith 0:0c3532738887 600 writeRegister(ExtRegister::IF_ADC0,0x10);
Jamie Smith 0:0c3532738887 601 writeRegister(ExtRegister::FS_DIG1,0x04);
Jamie Smith 0:0c3532738887 602 writeRegister(ExtRegister::FS_CAL1,0x40);
Jamie Smith 0:0c3532738887 603 writeRegister(ExtRegister::FS_CAL0,0x0E);
Jamie Smith 0:0c3532738887 604 writeRegister(ExtRegister::FS_DIVTWO,0x03);
Jamie Smith 0:0c3532738887 605 writeRegister(ExtRegister::FS_DSM0,0x33);
Jamie Smith 0:0c3532738887 606 writeRegister(ExtRegister::FS_DVC1,0xF7);
Jamie Smith 0:0c3532738887 607 writeRegister(ExtRegister::FS_PFD,0x00);
Jamie Smith 0:0c3532738887 608 writeRegister(ExtRegister::FS_PRE,0x6E);
Jamie Smith 0:0c3532738887 609 writeRegister(ExtRegister::FS_REG_DIV_CML,0x1C);
Jamie Smith 0:0c3532738887 610 writeRegister(ExtRegister::FS_SPARE,0xAC);
Jamie Smith 0:0c3532738887 611 writeRegister(ExtRegister::FS_VCO0,0xB5);
Jamie Smith 0:0c3532738887 612 writeRegister(ExtRegister::XOSC5,0x0E);
Jamie Smith 0:0c3532738887 613 writeRegister(ExtRegister::XOSC1,0x03);
Jamie Smith 0:0c3532738887 614 if(band == Band::BAND_820_960MHz)
Jamie Smith 0:0c3532738887 615 {
Jamie Smith 0:0c3532738887 616 writeRegister(ExtRegister::FS_DIG0,0x55);
Jamie Smith 0:0c3532738887 617 writeRegister(ExtRegister::FS_DVC0,0x17);
Jamie Smith 0:0c3532738887 618 writeRegister(ExtRegister::IFAMP,0x09);
Jamie Smith 0:0c3532738887 619 }
Jamie Smith 0:0c3532738887 620 else if(band == Band::BAND_410_480MHz || band == Band::BAND_164_192MHz)
Jamie Smith 0:0c3532738887 621 {
Jamie Smith 0:0c3532738887 622 writeRegister(ExtRegister::FS_DIG0,0x50);
Jamie Smith 0:0c3532738887 623 writeRegister(ExtRegister::FS_DVC0,0x0F);
Jamie Smith 0:0c3532738887 624 writeRegister(ExtRegister::IFAMP,0x0D);
Jamie Smith 0:0c3532738887 625 }
Jamie Smith 0:0c3532738887 626 else
Jamie Smith 0:0c3532738887 627 {
Jamie Smith 0:0c3532738887 628 // TI doesn't make settings public for the other radio bands.
Jamie Smith 0:0c3532738887 629 // Let's take a guess and use the 480-164MHz values.
Jamie Smith 0:0c3532738887 630 writeRegister(ExtRegister::FS_DIG0,0x50);
Jamie Smith 0:0c3532738887 631 writeRegister(ExtRegister::FS_DVC0,0x0F);
Jamie Smith 0:0c3532738887 632 writeRegister(ExtRegister::IFAMP,0x0D);
Jamie Smith 0:0c3532738887 633 }
Jamie Smith 0:0c3532738887 634
Jamie Smith 0:0c3532738887 635 // convert band to LO Divider value.
Jamie Smith 0:0c3532738887 636 // Most of the bands just multiply the register value by 2, but nooo, not BAND_136_160MHz.
Jamie Smith 0:0c3532738887 637 uint8_t loDividerValue;
Jamie Smith 0:0c3532738887 638 if(band == Band::BAND_136_160MHz)
Jamie Smith 0:0c3532738887 639 {
Jamie Smith 0:0c3532738887 640 loDividerValue = 24;
Jamie Smith 0:0c3532738887 641 }
Jamie Smith 0:0c3532738887 642 else
Jamie Smith 0:0c3532738887 643 {
Jamie Smith 0:0c3532738887 644 loDividerValue = static_cast<uint8_t>(band) * 2;
Jamie Smith 0:0c3532738887 645 }
Jamie Smith 0:0c3532738887 646
Jamie Smith 0:0c3532738887 647 // program band (also enable FS out of lock detector, which is useful for testing)
Jamie Smith 0:0c3532738887 648 writeRegister(Register::FS_CFG, (1 << FS_CFG_FS_LOCK_EN) | (static_cast<uint8_t>(band) << FS_CFG_FSD_BANDSELECT));
Jamie Smith 0:0c3532738887 649
Jamie Smith 0:0c3532738887 650 // equation derived from user guide section 9.12
Jamie Smith 0:0c3532738887 651 float exactFreqValue = (twoToThe16 * frequencyHz * static_cast<float>(loDividerValue)) / CC1200_OSC_FREQ;
Jamie Smith 0:0c3532738887 652 uint32_t actualFreqValue = static_cast<uint32_t>(std::min(static_cast<float>(maxValue24Bits), exactFreqValue));
Jamie Smith 0:0c3532738887 653
Jamie Smith 0:0c3532738887 654 // program frequency registers
Jamie Smith 0:0c3532738887 655 std::array<uint8_t, 3> freqRegisters ={
Jamie Smith 0:0c3532738887 656 static_cast<uint8_t>((actualFreqValue >> 16) & 0xFF),
Jamie Smith 0:0c3532738887 657 static_cast<uint8_t>((actualFreqValue >> 8) & 0xFF),
Jamie Smith 0:0c3532738887 658 static_cast<uint8_t>((actualFreqValue & 0xFF))
Jamie Smith 0:0c3532738887 659 };
Jamie Smith 0:0c3532738887 660 writeRegisters(ExtRegister::FREQ2, freqRegisters);
Jamie Smith 0:0c3532738887 661
Jamie Smith 0:0c3532738887 662 #if CC1200_DEBUG
Jamie Smith 0:0c3532738887 663 debugStream->printf("Setting radio frequency, requested %.00f Hz, setting FREQ = 0x%" PRIx32 "\n",
Jamie Smith 0:0c3532738887 664 frequencyHz, actualFreqValue);
Jamie Smith 0:0c3532738887 665
Jamie Smith 0:0c3532738887 666 // sanity check: calculate actual frequency
Jamie Smith 0:0c3532738887 667 float actualFrequency = (static_cast<float>(actualFreqValue) * CC1200_OSC_FREQ) / (twoToThe16 * static_cast<float>(loDividerValue));
Jamie Smith 0:0c3532738887 668
Jamie Smith 0:0c3532738887 669 debugStream->printf("This yields an actual frequency of %.00f Hz\n", actualFrequency);
Jamie Smith 0:0c3532738887 670 #endif
Jamie Smith 0:0c3532738887 671 }
Jamie Smith 0:0c3532738887 672
Jamie Smith 0:0c3532738887 673 // helper function for setRXFilterBandwidth:
Jamie Smith 0:0c3532738887 674 // calculate actual receive bandwidth from the given decimations.
Jamie Smith 0:0c3532738887 675 float calcReceiveBandwidth(uint8_t adcDecimation, uint8_t cicDecimation)
Jamie Smith 0:0c3532738887 676 {
Jamie Smith 0:0c3532738887 677 return CC1200_OSC_FREQ / (static_cast<float>(adcDecimation) * static_cast<float>(cicDecimation) * 2);
Jamie Smith 0:0c3532738887 678 }
Jamie Smith 0:0c3532738887 679
Jamie Smith 1:98af824b145e 680 void CC1200::setRXFilterBandwidth(float bandwidthHz)
Jamie Smith 0:0c3532738887 681 {
Jamie Smith 0:0c3532738887 682 // settings that the chip supports
Jamie Smith 0:0c3532738887 683 const uint8_t possibleADCDecimations[] = {12, 24, 48}; // indexes in this array represent the register value
Jamie Smith 0:0c3532738887 684 const size_t numADCDecimations = sizeof(possibleADCDecimations) / sizeof(uint8_t);
Jamie Smith 0:0c3532738887 685 const uint8_t minBBDecimation = 1;
Jamie Smith 0:0c3532738887 686
Jamie Smith 0:0c3532738887 687 // maximum supported BB decimation based on ADC decimation varies based on chip
Jamie Smith 0:0c3532738887 688 const uint8_t maxBBDecimations1201[] = {33, 16, 8};
Jamie Smith 0:0c3532738887 689 const uint8_t maxBBDecimations1200[] = {44, 44, 44};
Jamie Smith 0:0c3532738887 690 uint8_t const * maxBBDecimations = isCC1201 ? maxBBDecimations1201 : maxBBDecimations1200;
Jamie Smith 0:0c3532738887 691
Jamie Smith 0:0c3532738887 692 // the datasheet suggests to use the highest possible ADC decimation factor that will work for the requested frequency.
Jamie Smith 0:0c3532738887 693 // So, we compute the closest we can get with each ADC decimation, and if there's a tie, we choose the one with the higher ADC bandwidth
Jamie Smith 0:0c3532738887 694
Jamie Smith 0:0c3532738887 695 uint8_t actualBBDecimations[numADCDecimations];
Jamie Smith 0:0c3532738887 696
Jamie Smith 0:0c3532738887 697 for(size_t adcDecimationIndex = 0; adcDecimationIndex < numADCDecimations; ++adcDecimationIndex)
Jamie Smith 0:0c3532738887 698 {
Jamie Smith 0:0c3532738887 699 uint8_t adcDecimation = possibleADCDecimations[adcDecimationIndex];
Jamie Smith 0:0c3532738887 700
Jamie Smith 0:0c3532738887 701 // calculate BB decimation closest to the requested frequency
Jamie Smith 0:0c3532738887 702 // derived from formula in section 6.1
Jamie Smith 0:0c3532738887 703 float exactBBDecimation = CC1200_OSC_FREQ / (2 * bandwidthHz * static_cast<float>(adcDecimation));
Jamie Smith 0:0c3532738887 704 exactBBDecimation = std::max(exactBBDecimation, static_cast<float>(minBBDecimation));
Jamie Smith 0:0c3532738887 705 exactBBDecimation = std::min(exactBBDecimation, static_cast<float>(maxBBDecimations[adcDecimationIndex]));
Jamie Smith 0:0c3532738887 706
Jamie Smith 0:0c3532738887 707 actualBBDecimations[adcDecimationIndex] = static_cast<uint8_t>(exactBBDecimation);
Jamie Smith 0:0c3532738887 708 }
Jamie Smith 0:0c3532738887 709
Jamie Smith 0:0c3532738887 710 // now, choose the best of the ones we calculated
Jamie Smith 0:0c3532738887 711 uint8_t bestDecimationIndex = 0;
Jamie Smith 0:0c3532738887 712 float bestDecimationError = std::abs(bandwidthHz - calcReceiveBandwidth(possibleADCDecimations[0], actualBBDecimations[0]));
Jamie Smith 0:0c3532738887 713
Jamie Smith 0:0c3532738887 714 for(size_t adcDecimationIndex = 1; adcDecimationIndex < numADCDecimations; ++adcDecimationIndex)
Jamie Smith 0:0c3532738887 715 {
Jamie Smith 0:0c3532738887 716 float thisDecimationError = std::abs(bandwidthHz -
Jamie Smith 0:0c3532738887 717 calcReceiveBandwidth(possibleADCDecimations[adcDecimationIndex], actualBBDecimations[adcDecimationIndex]));
Jamie Smith 0:0c3532738887 718 if(thisDecimationError <= bestDecimationError)
Jamie Smith 0:0c3532738887 719 {
Jamie Smith 0:0c3532738887 720 bestDecimationError = thisDecimationError;
Jamie Smith 0:0c3532738887 721 bestDecimationIndex = adcDecimationIndex;
Jamie Smith 0:0c3532738887 722 }
Jamie Smith 0:0c3532738887 723 }
Jamie Smith 0:0c3532738887 724
Jamie Smith 0:0c3532738887 725 // now use the best value!
Jamie Smith 0:0c3532738887 726 uint8_t chanBwValue = (bestDecimationIndex << CHAN_BW_ADC_CIC_DECFACT) | (actualBBDecimations[bestDecimationIndex] << CHAN_BW_BB_CIC_DECFACT);
Jamie Smith 0:0c3532738887 727 writeRegister(Register::CHAN_BW, chanBwValue);
Jamie Smith 0:0c3532738887 728
Jamie Smith 0:0c3532738887 729 // also set DVGA_GAIN, which depends on bandwidth
Jamie Smith 0:0c3532738887 730 uint8_t mdmCfg1Value = readRegister(Register::MDMCFG1);
Jamie Smith 0:0c3532738887 731
Jamie Smith 0:0c3532738887 732 mdmCfg1Value &= ~(0b11 << MDMCFG1_DVGA_GAIN);
Jamie Smith 0:0c3532738887 733 if(bandwidthHz >= 100000)
Jamie Smith 0:0c3532738887 734 {
Jamie Smith 0:0c3532738887 735 mdmCfg1Value |= 1 << MDMCFG1_DVGA_GAIN;
Jamie Smith 0:0c3532738887 736 }
Jamie Smith 0:0c3532738887 737
Jamie Smith 0:0c3532738887 738 writeRegister(Register::MDMCFG1, mdmCfg1Value);
Jamie Smith 0:0c3532738887 739
Jamie Smith 1:98af824b145e 740 // also set MDMCFG0.DATA_FILTER_EN, which should be 0b11 iff bandwidth / symbol rate > 10
Jamie Smith 1:98af824b145e 741 uint8_t mdmCfg0Val = readRegister(Register::MDMCFG0);
Jamie Smith 1:98af824b145e 742
Jamie Smith 1:98af824b145e 743 if(bandwidthHz / symbolRateSps > 10.0f)
Jamie Smith 1:98af824b145e 744 {
Jamie Smith 1:98af824b145e 745 mdmCfg0Val |= 0b11 << MDMCFG0_DATA_FILTER_EN;
Jamie Smith 1:98af824b145e 746 }
Jamie Smith 1:98af824b145e 747 else
Jamie Smith 1:98af824b145e 748 {
Jamie Smith 1:98af824b145e 749 mdmCfg0Val &= ~(0b11 << MDMCFG0_DATA_FILTER_EN);
Jamie Smith 1:98af824b145e 750 }
Jamie Smith 1:98af824b145e 751
Jamie Smith 1:98af824b145e 752 writeRegister(Register::MDMCFG0, mdmCfg0Val);
Jamie Smith 1:98af824b145e 753
Jamie Smith 0:0c3532738887 754 // finally, we need to set RX_CONFIG_LIMITATION. It's not exactly clear what this does, but its setting changes
Jamie Smith 0:0c3532738887 755 // based on the filter BW.
Jamie Smith 0:0c3532738887 756 uint8_t syncCfg0Value = readRegister(Register::SYNC_CFG0);
Jamie Smith 0:0c3532738887 757
Jamie Smith 0:0c3532738887 758 if(symbolRateSps < bandwidthHz / 2 || bandwidthHz > 1500000)
Jamie Smith 0:0c3532738887 759 {
Jamie Smith 0:0c3532738887 760 // clear RX_CONFIG_LIMITATION
Jamie Smith 0:0c3532738887 761 syncCfg0Value &= ~(1 << SYNC_CFG0_RX_CONFIG_LIMITATION);
Jamie Smith 0:0c3532738887 762 }
Jamie Smith 0:0c3532738887 763 else
Jamie Smith 0:0c3532738887 764 {
Jamie Smith 0:0c3532738887 765 // set RX_CONFIG_LIMITATION
Jamie Smith 0:0c3532738887 766 syncCfg0Value |= (1 << SYNC_CFG0_RX_CONFIG_LIMITATION);
Jamie Smith 0:0c3532738887 767 }
Jamie Smith 0:0c3532738887 768
Jamie Smith 0:0c3532738887 769 writeRegister(Register::SYNC_CFG0, syncCfg0Value);
Jamie Smith 0:0c3532738887 770
Jamie Smith 0:0c3532738887 771 adcCicDecimation = possibleADCDecimations[bestDecimationIndex];
Jamie Smith 0:0c3532738887 772
Jamie Smith 0:0c3532738887 773 #if CC1200_DEBUG
Jamie Smith 0:0c3532738887 774 debugStream->printf("Setting BB decimation to %" PRIu8 " and ADC decimation to %" PRIu8 "\n",
Jamie Smith 0:0c3532738887 775 actualBBDecimations[bestDecimationIndex], possibleADCDecimations[bestDecimationIndex]);
Jamie Smith 0:0c3532738887 776 debugStream->printf("This yields an actual RX filter BW of %.00f\n",
Jamie Smith 0:0c3532738887 777 calcReceiveBandwidth(possibleADCDecimations[bestDecimationIndex], actualBBDecimations[bestDecimationIndex]));
Jamie Smith 0:0c3532738887 778 #endif
Jamie Smith 0:0c3532738887 779 }
Jamie Smith 0:0c3532738887 780
Jamie Smith 0:0c3532738887 781 void CC1200::configureDCFilter(bool enableAutoFilter, uint8_t settlingCfg, uint8_t cutoffCfg)
Jamie Smith 0:0c3532738887 782 {
Jamie Smith 0:0c3532738887 783 uint8_t dcfiltCfg = 0;
Jamie Smith 0:0c3532738887 784
Jamie Smith 0:0c3532738887 785 if(!enableAutoFilter)
Jamie Smith 0:0c3532738887 786 {
Jamie Smith 0:0c3532738887 787 // set "freeze coeff" bit
Jamie Smith 0:0c3532738887 788 dcfiltCfg |= (1 << DCFILT_CFG_DCFILT_FREEZE_COEFF);
Jamie Smith 0:0c3532738887 789 }
Jamie Smith 0:0c3532738887 790
Jamie Smith 0:0c3532738887 791 dcfiltCfg |= settlingCfg << DCFILT_CFG_DCFILT_BW_SETTLE;
Jamie Smith 0:0c3532738887 792 dcfiltCfg |= cutoffCfg << DCFILT_CFG_DCFILT_BW;
Jamie Smith 0:0c3532738887 793
Jamie Smith 0:0c3532738887 794 writeRegister(Register::DCFILT_CFG, dcfiltCfg);
Jamie Smith 0:0c3532738887 795 }
Jamie Smith 0:0c3532738887 796
Jamie Smith 0:0c3532738887 797 void CC1200::setIQMismatchCompensationEnabled(bool enabled)
Jamie Smith 0:0c3532738887 798 {
Jamie Smith 0:0c3532738887 799 uint8_t iqicValue = readRegister(Register::IQIC);
Jamie Smith 0:0c3532738887 800
Jamie Smith 0:0c3532738887 801 if(enabled)
Jamie Smith 0:0c3532738887 802 {
Jamie Smith 0:0c3532738887 803 iqicValue |= (1 << IQIC_IQIC_EN);
Jamie Smith 0:0c3532738887 804 }
Jamie Smith 0:0c3532738887 805 else
Jamie Smith 0:0c3532738887 806 {
Jamie Smith 0:0c3532738887 807 iqicValue &= ~(1 << IQIC_IQIC_EN);
Jamie Smith 0:0c3532738887 808 }
Jamie Smith 0:0c3532738887 809
Jamie Smith 0:0c3532738887 810 writeRegister(Register::IQIC, iqicValue);
Jamie Smith 0:0c3532738887 811 }
Jamie Smith 0:0c3532738887 812
Jamie Smith 0:0c3532738887 813 void CC1200::configureSyncWord(uint32_t syncWord, CC1200::SyncMode mode, uint8_t syncThreshold)
Jamie Smith 0:0c3532738887 814 {
Jamie Smith 0:0c3532738887 815 // program sync word registers
Jamie Smith 0:0c3532738887 816 std::array<uint8_t, 4> syncWordRegisters ={
Jamie Smith 0:0c3532738887 817 static_cast<uint8_t>((syncWord >> 24) & 0xFF),
Jamie Smith 0:0c3532738887 818 static_cast<uint8_t>((syncWord >> 16) & 0xFF),
Jamie Smith 0:0c3532738887 819 static_cast<uint8_t>((syncWord >> 8) & 0xFF),
Jamie Smith 0:0c3532738887 820 static_cast<uint8_t>(syncWord & 0xFF)
Jamie Smith 0:0c3532738887 821 };
Jamie Smith 0:0c3532738887 822 writeRegisters(Register::SYNC3, syncWordRegisters);
Jamie Smith 0:0c3532738887 823
Jamie Smith 0:0c3532738887 824 // program sync word cfg
Jamie Smith 0:0c3532738887 825 writeRegister(Register::SYNC_CFG1, (static_cast<uint8_t>(mode) << SYNC_CFG1_SYNC_MODE) | (syncThreshold << SYNC_CFG1_SYNC_THR));
Jamie Smith 0:0c3532738887 826 }
Jamie Smith 0:0c3532738887 827
Jamie Smith 0:0c3532738887 828 bool CC1200::isFSLocked()
Jamie Smith 0:0c3532738887 829 {
Jamie Smith 0:0c3532738887 830 return readRegister(ExtRegister::FSCAL_CTRL) & (1 << FSCAL_CTRL_LOCK);
Jamie Smith 0:0c3532738887 831 }
Jamie Smith 0:0c3532738887 832
Jamie Smith 0:0c3532738887 833 void CC1200::configurePreamble(uint8_t preambleLengthCfg, uint8_t preambleFormatCfg)
Jamie Smith 0:0c3532738887 834 {
Jamie Smith 0:0c3532738887 835 uint8_t preambleCfg1 = 0;
Jamie Smith 0:0c3532738887 836 preambleCfg1 |= preambleLengthCfg << PREAMBLE_CFG1_NUM_PREAMBLE;
Jamie Smith 0:0c3532738887 837 preambleCfg1 |= preambleFormatCfg << PREAMBLE_CFG1_PREAMBLE_WORD;
Jamie Smith 0:0c3532738887 838 writeRegister(Register::PREAMBLE_CFG1, preambleCfg1);
Jamie Smith 0:0c3532738887 839 }
Jamie Smith 0:0c3532738887 840
Jamie Smith 1:98af824b145e 841 void CC1200::setPARampRate(uint8_t firstRampLevel, uint8_t secondRampLevel, CC1200::RampTime rampTime)
Jamie Smith 1:98af824b145e 842 {
Jamie Smith 4:c609cc7c9ea7 843 // enable PA ramping
Jamie Smith 4:c609cc7c9ea7 844 uint8_t paCfg1Val = readRegister(Register::PA_CFG1);
Jamie Smith 4:c609cc7c9ea7 845 paCfg1Val |= 1 << PA_CFG1_PA_RAMP_SHAPE_EN;
Jamie Smith 4:c609cc7c9ea7 846 writeRegister(Register::PA_CFG1, paCfg1Val);
Jamie Smith 4:c609cc7c9ea7 847
Jamie Smith 4:c609cc7c9ea7 848 // configure properties
Jamie Smith 1:98af824b145e 849 uint8_t paCfg0Val = 0;
Jamie Smith 1:98af824b145e 850 paCfg0Val |= (firstRampLevel << PA_CFG0_FIRST_IPL);
Jamie Smith 1:98af824b145e 851 paCfg0Val |= (secondRampLevel << PA_CFG0_SECOND_IPL);
Jamie Smith 1:98af824b145e 852 paCfg0Val |= (static_cast<uint8_t>(rampTime) << PA_CFG0_RAMP_SHAPE);
Jamie Smith 1:98af824b145e 853
Jamie Smith 1:98af824b145e 854 writeRegister(Register::PA_CFG0, paCfg0Val);
Jamie Smith 1:98af824b145e 855 }
Jamie Smith 1:98af824b145e 856
Jamie Smith 4:c609cc7c9ea7 857 void CC1200::disablePARamping()
Jamie Smith 4:c609cc7c9ea7 858 {
Jamie Smith 4:c609cc7c9ea7 859 uint8_t paCfg1Val = readRegister(Register::PA_CFG1);
Jamie Smith 4:c609cc7c9ea7 860 paCfg1Val &= ~(1 << PA_CFG1_PA_RAMP_SHAPE_EN);
Jamie Smith 4:c609cc7c9ea7 861 writeRegister(Register::PA_CFG1, paCfg1Val);
Jamie Smith 4:c609cc7c9ea7 862 }
Jamie Smith 4:c609cc7c9ea7 863
Jamie Smith 1:98af824b145e 864 void CC1200::setAGCReferenceLevel(uint8_t level)
Jamie Smith 1:98af824b145e 865 {
Jamie Smith 1:98af824b145e 866 writeRegister(Register::AGC_REF, level);
Jamie Smith 1:98af824b145e 867 }
Jamie Smith 1:98af824b145e 868
Jamie Smith 1:98af824b145e 869 void CC1200::setAGCSyncBehavior(CC1200::SyncBehavior behavior)
Jamie Smith 1:98af824b145e 870 {
Jamie Smith 1:98af824b145e 871 uint8_t agcCfg3Val = readRegister(Register::AGC_CFG3);
Jamie Smith 1:98af824b145e 872 agcCfg3Val &= ~(0b111 << AGC_CFG3_AGC_SYNC_BEHAVIOUR);
Jamie Smith 1:98af824b145e 873 agcCfg3Val |= static_cast<uint8_t>(behavior) << AGC_CFG3_AGC_SYNC_BEHAVIOUR;
Jamie Smith 1:98af824b145e 874 writeRegister(Register::AGC_CFG3, agcCfg3Val);
Jamie Smith 1:98af824b145e 875 }
Jamie Smith 1:98af824b145e 876
Jamie Smith 1:98af824b145e 877 void CC1200::setAGCGainTable(CC1200::GainTable table, uint8_t minGainIndex, uint8_t maxGainIndex)
Jamie Smith 1:98af824b145e 878 {
Jamie Smith 1:98af824b145e 879 uint8_t agcCfg3Val = readRegister(Register::AGC_CFG3);
Jamie Smith 1:98af824b145e 880 uint8_t agcCfg2Val = readRegister(Register::AGC_CFG2);
Jamie Smith 1:98af824b145e 881
Jamie Smith 1:98af824b145e 882 agcCfg3Val &= ~(0b11111 << AGC_CFG3_AGC_MIN_GAIN);
Jamie Smith 1:98af824b145e 883 agcCfg2Val &= ~(0b11 << AGC_CFG2_FE_PERFORMANCE_MODE);
Jamie Smith 1:98af824b145e 884 agcCfg2Val &= ~(0b11111 << AGC_CFG2_AGC_MAX_GAIN);
Jamie Smith 1:98af824b145e 885
Jamie Smith 1:98af824b145e 886 agcCfg3Val |= maxGainIndex << AGC_CFG3_AGC_MIN_GAIN;
Jamie Smith 1:98af824b145e 887 agcCfg2Val |= static_cast<uint8_t>(table) << AGC_CFG2_FE_PERFORMANCE_MODE;
Jamie Smith 1:98af824b145e 888 agcCfg2Val |= maxGainIndex << AGC_CFG2_AGC_MAX_GAIN;
Jamie Smith 1:98af824b145e 889
Jamie Smith 1:98af824b145e 890 writeRegister(Register::AGC_CFG3, agcCfg3Val);
Jamie Smith 1:98af824b145e 891 writeRegister(Register::AGC_CFG2, agcCfg2Val);
Jamie Smith 1:98af824b145e 892 }
Jamie Smith 1:98af824b145e 893
Jamie Smith 1:98af824b145e 894 void CC1200::setAGCHysteresis(uint8_t hysteresisCfg)
Jamie Smith 1:98af824b145e 895 {
Jamie Smith 1:98af824b145e 896 uint8_t agcCfg0Val = readRegister(Register::AGC_CFG0);
Jamie Smith 1:98af824b145e 897 agcCfg0Val &= ~(0b11 << AGC_CFG0_AGC_HYST_LEVEL);
Jamie Smith 1:98af824b145e 898 agcCfg0Val |= hysteresisCfg << AGC_CFG0_AGC_HYST_LEVEL;
Jamie Smith 1:98af824b145e 899 writeRegister(Register::AGC_CFG0, agcCfg0Val);
Jamie Smith 1:98af824b145e 900 }
Jamie Smith 1:98af824b145e 901
Jamie Smith 1:98af824b145e 902 void CC1200::setAGCSlewRate(uint8_t slewrateCfg)
Jamie Smith 1:98af824b145e 903 {
Jamie Smith 1:98af824b145e 904 uint8_t agcCfg0Val = readRegister(Register::AGC_CFG0);
Jamie Smith 1:98af824b145e 905 agcCfg0Val &= ~(0b11 << AGC_CFG0_AGC_SLEWRATE_LIMIT);
Jamie Smith 1:98af824b145e 906 agcCfg0Val |= slewrateCfg << AGC_CFG0_AGC_SLEWRATE_LIMIT;
Jamie Smith 1:98af824b145e 907 writeRegister(Register::AGC_CFG0, agcCfg0Val);
Jamie Smith 1:98af824b145e 908 }
Jamie Smith 1:98af824b145e 909
Jamie Smith 0:0c3532738887 910 void CC1200::setIFMixCFG(uint8_t value)
Jamie Smith 0:0c3532738887 911 {
Jamie Smith 0:0c3532738887 912 uint8_t ifMixCfg = readRegister(ExtRegister::IF_MIX_CFG);
Jamie Smith 0:0c3532738887 913 ifMixCfg &= ~(0b111 << IF_MIX_CFG_CMIX_CFG);
Jamie Smith 0:0c3532738887 914 ifMixCfg |= (value << IF_MIX_CFG_CMIX_CFG);
Jamie Smith 0:0c3532738887 915 writeRegister(ExtRegister::IF_MIX_CFG, ifMixCfg);
Jamie Smith 0:0c3532738887 916 }
Jamie Smith 0:0c3532738887 917
Jamie Smith 0:0c3532738887 918 uint8_t CC1200::readRegister(CC1200::Register reg)
Jamie Smith 0:0c3532738887 919 {
Jamie Smith 0:0c3532738887 920 spi.select();
Jamie Smith 0:0c3532738887 921 loadStatusByte(spi.write(CC1200_READ | static_cast<uint8_t>(reg)));
Jamie Smith 0:0c3532738887 922 uint8_t regValue = spi.write(0);
Jamie Smith 0:0c3532738887 923 spi.deselect();
Jamie Smith 0:0c3532738887 924
Jamie Smith 0:0c3532738887 925 #if CC1200_REGISTER_LEVEL_DEBUG
Jamie Smith 0:0c3532738887 926 debugStream->printf("Read register 0x%" PRIx8 " -> 0x%" PRIx8 "\n", static_cast<uint8_t>(reg), regValue);
Jamie Smith 0:0c3532738887 927 #endif
Jamie Smith 0:0c3532738887 928
Jamie Smith 0:0c3532738887 929 return regValue;
Jamie Smith 0:0c3532738887 930 }
Jamie Smith 0:0c3532738887 931
Jamie Smith 0:0c3532738887 932 void CC1200::writeRegister(Register reg, uint8_t value)
Jamie Smith 0:0c3532738887 933 {
Jamie Smith 0:0c3532738887 934 spi.select();
Jamie Smith 0:0c3532738887 935 loadStatusByte(spi.write(CC1200_WRITE | static_cast<uint8_t>(reg)));
Jamie Smith 0:0c3532738887 936 spi.write(value);
Jamie Smith 0:0c3532738887 937 spi.deselect();
Jamie Smith 0:0c3532738887 938
Jamie Smith 0:0c3532738887 939 #if CC1200_REGISTER_LEVEL_DEBUG
Jamie Smith 0:0c3532738887 940 debugStream->printf("Wrote register 0x%" PRIx8 " <- 0x%" PRIx8 "\n", static_cast<uint8_t>(reg), value);
Jamie Smith 0:0c3532738887 941 #endif
Jamie Smith 0:0c3532738887 942 }
Jamie Smith 0:0c3532738887 943
Jamie Smith 0:0c3532738887 944 void CC1200::writeRegisters(CC1200::Register startReg, uint8_t const *values, size_t numRegisters)
Jamie Smith 0:0c3532738887 945 {
Jamie Smith 0:0c3532738887 946 spi.select();
Jamie Smith 0:0c3532738887 947 loadStatusByte(spi.write(CC1200_WRITE | CC1200_BURST | static_cast<uint8_t>(startReg)));
Jamie Smith 0:0c3532738887 948
Jamie Smith 0:0c3532738887 949 for(size_t byteIndex = 0; byteIndex < numRegisters; ++byteIndex)
Jamie Smith 0:0c3532738887 950 {
Jamie Smith 0:0c3532738887 951 spi.write(values[byteIndex]);
Jamie Smith 0:0c3532738887 952 }
Jamie Smith 0:0c3532738887 953 spi.deselect();
Jamie Smith 0:0c3532738887 954
Jamie Smith 0:0c3532738887 955 #if CC1200_REGISTER_LEVEL_DEBUG
Jamie Smith 0:0c3532738887 956 for(size_t byteIndex = 0; byteIndex < numRegisters; ++byteIndex)
Jamie Smith 0:0c3532738887 957 {
Jamie Smith 0:0c3532738887 958 debugStream->printf("Wrote register 0x%" PRIx8 " <- 0x%" PRIx8 "\n",
Jamie Smith 0:0c3532738887 959 static_cast<uint8_t>(static_cast<uint8_t>(startReg) + byteIndex),
Jamie Smith 0:0c3532738887 960 values[byteIndex]);
Jamie Smith 0:0c3532738887 961 }
Jamie Smith 0:0c3532738887 962 #endif
Jamie Smith 0:0c3532738887 963 }
Jamie Smith 0:0c3532738887 964
Jamie Smith 0:0c3532738887 965 void CC1200::loadStatusByte(uint8_t status)
Jamie Smith 0:0c3532738887 966 {
Jamie Smith 0:0c3532738887 967 chipReady = !(status >> 7);
Jamie Smith 0:0c3532738887 968 state = static_cast<State>((status >> 4) & 0x7);
Jamie Smith 0:0c3532738887 969
Jamie Smith 0:0c3532738887 970 #if CC1200_REGISTER_LEVEL_DEBUG
Jamie Smith 0:0c3532738887 971 debugStream->printf("Updated status, state = 0x%" PRIx8 " ready = %s\n", static_cast<uint8_t>(state), chipReady ? "true" : "false");
Jamie Smith 0:0c3532738887 972 #endif
Jamie Smith 0:0c3532738887 973 }
Jamie Smith 0:0c3532738887 974
Jamie Smith 0:0c3532738887 975 uint8_t CC1200::readRegister(CC1200::ExtRegister reg)
Jamie Smith 0:0c3532738887 976 {
Jamie Smith 0:0c3532738887 977 spi.select();
Jamie Smith 0:0c3532738887 978 loadStatusByte(spi.write(CC1200_READ | CC1200_EXT_ADDR));
Jamie Smith 0:0c3532738887 979 spi.write(static_cast<uint8_t>(reg));
Jamie Smith 0:0c3532738887 980 uint8_t regValue = spi.write(0);
Jamie Smith 0:0c3532738887 981 spi.deselect();
Jamie Smith 0:0c3532738887 982
Jamie Smith 0:0c3532738887 983 #if CC1200_REGISTER_LEVEL_DEBUG
Jamie Smith 0:0c3532738887 984 debugStream->printf("Read ext register 0x%" PRIx8 " -> 0x%" PRIx8 "\n", static_cast<uint8_t>(reg), regValue);
Jamie Smith 0:0c3532738887 985 #endif
Jamie Smith 0:0c3532738887 986
Jamie Smith 0:0c3532738887 987 return regValue;
Jamie Smith 0:0c3532738887 988 }
Jamie Smith 0:0c3532738887 989
Jamie Smith 0:0c3532738887 990 void CC1200::writeRegister(CC1200::ExtRegister reg, uint8_t value)
Jamie Smith 0:0c3532738887 991 {
Jamie Smith 0:0c3532738887 992 spi.select();
Jamie Smith 0:0c3532738887 993 loadStatusByte(spi.write(CC1200_WRITE | CC1200_EXT_ADDR));
Jamie Smith 0:0c3532738887 994 spi.write(static_cast<uint8_t>(reg));
Jamie Smith 0:0c3532738887 995 spi.write(value);
Jamie Smith 0:0c3532738887 996 spi.deselect();
Jamie Smith 0:0c3532738887 997
Jamie Smith 0:0c3532738887 998 #if CC1200_REGISTER_LEVEL_DEBUG
Jamie Smith 0:0c3532738887 999 debugStream->printf("Wrote ext register 0x%" PRIx8 " <- 0x%" PRIx8 "\n", static_cast<uint8_t>(reg), value);
Jamie Smith 0:0c3532738887 1000 #endif
Jamie Smith 0:0c3532738887 1001 }
Jamie Smith 0:0c3532738887 1002
Jamie Smith 0:0c3532738887 1003 void CC1200::writeRegisters(CC1200::ExtRegister startReg, uint8_t const *values, size_t numRegisters)
Jamie Smith 0:0c3532738887 1004 {
Jamie Smith 0:0c3532738887 1005 spi.select();
Jamie Smith 0:0c3532738887 1006 loadStatusByte(spi.write(CC1200_WRITE | CC1200_BURST | CC1200_EXT_ADDR));
Jamie Smith 0:0c3532738887 1007 spi.write(static_cast<uint8_t>(startReg));
Jamie Smith 0:0c3532738887 1008
Jamie Smith 0:0c3532738887 1009 for(size_t byteIndex = 0; byteIndex < numRegisters; ++byteIndex)
Jamie Smith 0:0c3532738887 1010 {
Jamie Smith 0:0c3532738887 1011 spi.write(values[byteIndex]);
Jamie Smith 0:0c3532738887 1012 }
Jamie Smith 0:0c3532738887 1013 spi.deselect();
Jamie Smith 0:0c3532738887 1014
Jamie Smith 0:0c3532738887 1015 #if CC1200_REGISTER_LEVEL_DEBUG
Jamie Smith 0:0c3532738887 1016 for(size_t byteIndex = 0; byteIndex < numRegisters; ++byteIndex)
Jamie Smith 0:0c3532738887 1017 {
Jamie Smith 0:0c3532738887 1018 debugStream->printf("Wrote extended register 0x%" PRIx8 " <- 0x%" PRIx8 "\n",
Jamie Smith 0:0c3532738887 1019 static_cast<uint8_t>(static_cast<uint8_t>(startReg) + byteIndex),
Jamie Smith 0:0c3532738887 1020 values[byteIndex]);
Jamie Smith 0:0c3532738887 1021 }
Jamie Smith 0:0c3532738887 1022 #endif
Jamie Smith 0:0c3532738887 1023 }
Jamie Smith 0:0c3532738887 1024
Jamie Smith 0:0c3532738887 1025 void CC1200::sendCommand(CC1200::Command command)
Jamie Smith 0:0c3532738887 1026 {
Jamie Smith 0:0c3532738887 1027 spi.select();
Jamie Smith 0:0c3532738887 1028 loadStatusByte(spi.write(static_cast<uint8_t>(command)));
Jamie Smith 0:0c3532738887 1029 spi.deselect();
Jamie Smith 0:0c3532738887 1030
Jamie Smith 0:0c3532738887 1031 #if CC1200_REGISTER_LEVEL_DEBUG
Jamie Smith 0:0c3532738887 1032 debugStream->printf("Sent SPI command 0x%" PRIx8 "\n", static_cast<uint8_t>(command));
Jamie Smith 0:0c3532738887 1033 #endif
Jamie Smith 0:0c3532738887 1034 }
Jamie Smith 0:0c3532738887 1035
Jamie Smith 0:0c3532738887 1036 uint8_t CC1200::readRXFIFOByte(uint8_t address)
Jamie Smith 0:0c3532738887 1037 {
Jamie Smith 0:0c3532738887 1038 spi.select();
Jamie Smith 0:0c3532738887 1039 loadStatusByte(spi.write(CC1200_READ | CC1200_MEM_ACCESS));
Jamie Smith 2:2a447e8e50b8 1040 spi.write(CC1200_RX_FIFO | address);
Jamie Smith 2:2a447e8e50b8 1041 int value = spi.write(0);
Jamie Smith 0:0c3532738887 1042 spi.deselect();
Jamie Smith 0:0c3532738887 1043
Jamie Smith 0:0c3532738887 1044 #if CC1200_REGISTER_LEVEL_DEBUG
Jamie Smith 2:2a447e8e50b8 1045 debugStream->printf("Read RX FIFO[0x%" PRIx8 "]: 0x%x 0x%x -> 0x%" PRIx8 "\n", static_cast<uint8_t>(address), CC1200_READ | CC1200_MEM_ACCESS, CC1200_RX_FIFO | address, value);
Jamie Smith 0:0c3532738887 1046 #endif
Jamie Smith 0:0c3532738887 1047
Jamie Smith 0:0c3532738887 1048 return value;
Jamie Smith 0:0c3532738887 1049 }
Jamie Smith 0:0c3532738887 1050
Jamie Smith 0:0c3532738887 1051
Jamie Smith 4:c609cc7c9ea7 1052
Jamie Smith 4:c609cc7c9ea7 1053