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:
Mon Aug 10 01:47:24 2020 -0700
Revision:
3:f464b14ce62f
Parent:
2:2a447e8e50b8
Child:
4:c609cc7c9ea7
Fix compilation with Arm Compiler

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 // configure packet length to adjustable
Jamie Smith 0:0c3532738887 139 writeRegister(Register::PKT_CFG0, (0b01 << PKT_CFG0_LENGTH_CONFIG));
Jamie Smith 0:0c3532738887 140
Jamie Smith 0:0c3532738887 141 // set max packet length
Jamie Smith 0:0c3532738887 142 writeRegister(Register::PKT_LEN, MAX_PACKET_LENGTH);
Jamie Smith 0:0c3532738887 143
Jamie Smith 0:0c3532738887 144
Jamie Smith 0:0c3532738887 145 return true;
Jamie Smith 0:0c3532738887 146 }
Jamie Smith 0:0c3532738887 147
Jamie Smith 0:0c3532738887 148 size_t CC1200::getTXFIFOLen()
Jamie Smith 0:0c3532738887 149 {
Jamie Smith 0:0c3532738887 150 return readRegister(ExtRegister::NUM_TXBYTES);
Jamie Smith 0:0c3532738887 151 }
Jamie Smith 0:0c3532738887 152
Jamie Smith 0:0c3532738887 153 size_t CC1200::getRXFIFOLen()
Jamie Smith 0:0c3532738887 154 {
Jamie Smith 0:0c3532738887 155 return readRegister(ExtRegister::NUM_RXBYTES);
Jamie Smith 0:0c3532738887 156 }
Jamie Smith 0:0c3532738887 157
Jamie Smith 0:0c3532738887 158 bool CC1200::enqueuePacket(char const * data, size_t len)
Jamie Smith 0:0c3532738887 159 {
Jamie Smith 0:0c3532738887 160 uint8_t totalLength = len + 1; // add one byte for length byte
Jamie Smith 0:0c3532738887 161
Jamie Smith 0:0c3532738887 162 if(totalLength > MAX_PACKET_LENGTH)
Jamie Smith 0:0c3532738887 163 {
Jamie Smith 0:0c3532738887 164 // packet too big
Jamie Smith 0:0c3532738887 165 return false;
Jamie Smith 0:0c3532738887 166 }
Jamie Smith 0:0c3532738887 167
Jamie Smith 0:0c3532738887 168 uint8_t txFreeBytes = CC1200_FIFO_SIZE - getTXFIFOLen();
Jamie Smith 0:0c3532738887 169 if(totalLength > txFreeBytes)
Jamie Smith 0:0c3532738887 170 {
Jamie Smith 0:0c3532738887 171 // packet doesn't fit in TX FIFO
Jamie Smith 0:0c3532738887 172 return false;
Jamie Smith 0:0c3532738887 173 }
Jamie Smith 0:0c3532738887 174
Jamie Smith 0:0c3532738887 175 // burst write to TX FIFO
Jamie Smith 0:0c3532738887 176 spi.select();
Jamie Smith 0:0c3532738887 177 loadStatusByte(spi.write(CC1200_ENQUEUE_TX_FIFO | CC1200_BURST));
Jamie Smith 0:0c3532738887 178 spi.write(len);
Jamie Smith 0:0c3532738887 179 for(size_t byteIndex = 0; byteIndex < len; ++byteIndex)
Jamie Smith 0:0c3532738887 180 {
Jamie Smith 0:0c3532738887 181 spi.write(data[byteIndex]);
Jamie Smith 0:0c3532738887 182 }
Jamie Smith 0:0c3532738887 183 spi.deselect();
Jamie Smith 0:0c3532738887 184
Jamie Smith 0:0c3532738887 185 #if CC1200_REGISTER_LEVEL_DEBUG
Jamie Smith 0:0c3532738887 186 debugStream->printf("Wrote packet of data length %zu: %" PRIx8, len, static_cast<uint8_t>(len));
Jamie Smith 0:0c3532738887 187 for(size_t byteIndex = 0; byteIndex < len; ++byteIndex)
Jamie Smith 0:0c3532738887 188 {
Jamie Smith 0:0c3532738887 189 debugStream->printf(" %" 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 2:2a447e8e50b8 206 // get value of first byte of the packet, which is the length.
Jamie Smith 2:2a447e8e50b8 207
Jamie Smith 2:2a447e8e50b8 208 // The datasheet is wrong about this! It says that the first byte in the RX FIFO can
Jamie Smith 2:2a447e8e50b8 209 // be found by accessing address RXFIRST via direct fifo access.
Jamie Smith 2:2a447e8e50b8 210 // However, in my own testing, RXFIRST points to the second entry in the FIFO, and
Jamie Smith 2:2a447e8e50b8 211 // the first entry must be accessed through RXFIFO_PRE_BUF.
Jamie Smith 2:2a447e8e50b8 212 uint8_t packetLen = readRegister(ExtRegister::RXFIFO_PRE_BUF);
Jamie Smith 0:0c3532738887 213
Jamie Smith 0:0c3532738887 214 // if we have received a full packet's worth of bytes, then we have received a full packet.
Jamie Smith 0:0c3532738887 215 return bytesReceived >= static_cast<size_t>(packetLen + 1); // Add one because length field does not include itself
Jamie Smith 0:0c3532738887 216 }
Jamie Smith 0:0c3532738887 217
Jamie Smith 0:0c3532738887 218 size_t CC1200::receivePacket(char *buffer, size_t bufferLen)
Jamie Smith 0:0c3532738887 219 {
Jamie Smith 0:0c3532738887 220 // burst read from RX FIFO
Jamie Smith 0:0c3532738887 221 spi.select();
Jamie Smith 0:0c3532738887 222 loadStatusByte(spi.write(CC1200_DEQUEUE_RX_FIFO | CC1200_BURST));
Jamie Smith 0:0c3532738887 223
Jamie Smith 0:0c3532738887 224 // first read length byte
Jamie Smith 0:0c3532738887 225 uint8_t dataLen = spi.write(0);
Jamie Smith 0:0c3532738887 226
Jamie Smith 0:0c3532738887 227 for(size_t byteIndex = 0; byteIndex < dataLen; ++byteIndex)
Jamie Smith 0:0c3532738887 228 {
Jamie Smith 0:0c3532738887 229 uint8_t currByte = spi.write(0);
Jamie Smith 0:0c3532738887 230 if(byteIndex < bufferLen)
Jamie Smith 0:0c3532738887 231 {
Jamie Smith 0:0c3532738887 232 buffer[byteIndex] = currByte;
Jamie Smith 0:0c3532738887 233 }
Jamie Smith 0:0c3532738887 234 }
Jamie Smith 0:0c3532738887 235 spi.deselect();
Jamie Smith 0:0c3532738887 236
Jamie Smith 0:0c3532738887 237 #if CC1200_REGISTER_LEVEL_DEBUG
Jamie Smith 0:0c3532738887 238 debugStream->printf("Read packet of data length %" PRIu8 ": %" PRIx8, dataLen, static_cast<uint8_t>(dataLen));
Jamie Smith 0:0c3532738887 239 for(size_t byteIndex = 0; byteIndex < dataLen; ++byteIndex)
Jamie Smith 0:0c3532738887 240 {
Jamie Smith 0:0c3532738887 241 debugStream->printf(" %" PRIx8, buffer[byteIndex]);
Jamie Smith 0:0c3532738887 242 }
Jamie Smith 0:0c3532738887 243 debugStream->printf("\n");
Jamie Smith 0:0c3532738887 244 #endif
Jamie Smith 0:0c3532738887 245
Jamie Smith 0:0c3532738887 246 return dataLen;
Jamie Smith 0:0c3532738887 247 }
Jamie Smith 0:0c3532738887 248
Jamie Smith 0:0c3532738887 249 // helper function: convert a state to the bits for RXOFF_MODE and TXOFF_MODE
Jamie Smith 0:0c3532738887 250 inline uint8_t getOffModeBits(CC1200::State state)
Jamie Smith 0:0c3532738887 251 {
Jamie Smith 0:0c3532738887 252 uint8_t offBits = 0b0;
Jamie Smith 0:0c3532738887 253 if(state == CC1200::State::IDLE)
Jamie Smith 0:0c3532738887 254 {
Jamie Smith 0:0c3532738887 255 offBits = 0b0;
Jamie Smith 0:0c3532738887 256 }
Jamie Smith 0:0c3532738887 257 else if(state == CC1200::State::FAST_ON)
Jamie Smith 0:0c3532738887 258 {
Jamie Smith 0:0c3532738887 259 offBits = 0b1;
Jamie Smith 0:0c3532738887 260 }
Jamie Smith 0:0c3532738887 261 else if(state == CC1200::State::TX)
Jamie Smith 0:0c3532738887 262 {
Jamie Smith 0:0c3532738887 263 offBits = 0b10;
Jamie Smith 0:0c3532738887 264 }
Jamie Smith 0:0c3532738887 265 else if(state == CC1200::State::RX)
Jamie Smith 0:0c3532738887 266 {
Jamie Smith 0:0c3532738887 267 offBits = 0b11;
Jamie Smith 0:0c3532738887 268 }
Jamie Smith 0:0c3532738887 269 return offBits;
Jamie Smith 0:0c3532738887 270 }
Jamie Smith 0:0c3532738887 271
Jamie Smith 0:0c3532738887 272 void CC1200::setOnReceiveState(CC1200::State goodPacket, CC1200::State badPacket)
Jamie Smith 0:0c3532738887 273 {
Jamie Smith 0:0c3532738887 274 // configure good packet action via RXOFF_MODE
Jamie Smith 0:0c3532738887 275 uint8_t rfendCfg1 = readRegister(Register::RFEND_CFG1);
Jamie Smith 0:0c3532738887 276 rfendCfg1 &= ~(0b11 << RFEND_CFG1_RXOFF_MODE);
Jamie Smith 0:0c3532738887 277 rfendCfg1 |= getOffModeBits(goodPacket) << RFEND_CFG1_RXOFF_MODE;
Jamie Smith 0:0c3532738887 278 writeRegister(Register::RFEND_CFG1, rfendCfg1);
Jamie Smith 0:0c3532738887 279
Jamie Smith 0:0c3532738887 280 // configure bad packet action via TERM_ON_BAD_PACKET_EN
Jamie Smith 0:0c3532738887 281 uint8_t rfendCfg0 = readRegister(Register::RFEND_CFG0);
Jamie Smith 0:0c3532738887 282 if(badPacket == State::RX)
Jamie Smith 0:0c3532738887 283 {
Jamie Smith 0:0c3532738887 284 rfendCfg0 &= ~(1 << RFEND_CFG0_TERM_ON_BAD_PACKET_EN);
Jamie Smith 0:0c3532738887 285 }
Jamie Smith 0:0c3532738887 286 else
Jamie Smith 0:0c3532738887 287 {
Jamie Smith 0:0c3532738887 288 rfendCfg0 |= 1 << RFEND_CFG1_RXOFF_MODE;
Jamie Smith 0:0c3532738887 289 }
Jamie Smith 0:0c3532738887 290 writeRegister(Register::RFEND_CFG0, rfendCfg0);
Jamie Smith 0:0c3532738887 291 }
Jamie Smith 0:0c3532738887 292
Jamie Smith 1:98af824b145e 293 void CC1200::setOnTransmitState(CC1200::State txState)
Jamie Smith 0:0c3532738887 294 {
Jamie Smith 0:0c3532738887 295 uint8_t rfendCfg0 = readRegister(Register::RFEND_CFG0);
Jamie Smith 0:0c3532738887 296 rfendCfg0 &= ~(0b11 << RFEND_CFG0_TXOFF_MODE);
Jamie Smith 1:98af824b145e 297 rfendCfg0 |= getOffModeBits(txState) << RFEND_CFG0_TXOFF_MODE;
Jamie Smith 0:0c3532738887 298 writeRegister(Register::RFEND_CFG0, rfendCfg0);
Jamie Smith 0:0c3532738887 299 }
Jamie Smith 0:0c3532738887 300
Jamie Smith 0:0c3532738887 301 void CC1200::setFSCalMode(FSCalMode mode)
Jamie Smith 0:0c3532738887 302 {
Jamie Smith 0:0c3532738887 303 uint8_t settlingCfg = readRegister(Register::SETTLING_CFG);
Jamie Smith 0:0c3532738887 304 settlingCfg &= ~(0b11 << SETTLING_CFG_FS_AUTOCAL);
Jamie Smith 0:0c3532738887 305 settlingCfg |= static_cast<uint8_t>(mode) << SETTLING_CFG_FS_AUTOCAL;
Jamie Smith 0:0c3532738887 306 writeRegister(Register::SETTLING_CFG, settlingCfg);
Jamie Smith 0:0c3532738887 307 }
Jamie Smith 0:0c3532738887 308
Jamie Smith 0:0c3532738887 309 void CC1200::configureGPIO(uint8_t gpioNumber, CC1200::GPIOMode mode, bool outputInvert)
Jamie Smith 0:0c3532738887 310 {
Jamie Smith 0:0c3532738887 311 // gpio 3 is the first register, then it goes down to 0
Jamie Smith 0:0c3532738887 312 Register gpioReg = static_cast<Register>(static_cast<uint8_t>(Register::IOCFG3) + (3 - gpioNumber));
Jamie Smith 0:0c3532738887 313
Jamie Smith 0:0c3532738887 314 uint8_t gpioCfgVal = static_cast<uint8_t>(mode);
Jamie Smith 0:0c3532738887 315 if(outputInvert)
Jamie Smith 0:0c3532738887 316 {
Jamie Smith 0:0c3532738887 317 gpioCfgVal |= (1 << GPIO_INV);
Jamie Smith 0:0c3532738887 318 }
Jamie Smith 0:0c3532738887 319 writeRegister(gpioReg, gpioCfgVal);
Jamie Smith 0:0c3532738887 320 }
Jamie Smith 0:0c3532738887 321
Jamie Smith 0:0c3532738887 322 void CC1200::configureFIFOMode()
Jamie Smith 0:0c3532738887 323 {
Jamie Smith 0:0c3532738887 324 // configure packet format
Jamie Smith 0:0c3532738887 325 uint8_t pktCfg2 = readRegister(Register::PKT_CFG2);
Jamie Smith 0:0c3532738887 326 pktCfg2 &= ~(0b11 << PKT_CFG2_PKT_FORMAT);
Jamie Smith 0:0c3532738887 327 writeRegister(Register::PKT_CFG2, pktCfg2);
Jamie Smith 0:0c3532738887 328
Jamie Smith 0:0c3532738887 329 // enable fifo
Jamie Smith 0:0c3532738887 330 uint8_t mdmCfg1 = readRegister(Register::MDMCFG1);
Jamie Smith 0:0c3532738887 331 mdmCfg1 |= 1 << MDMCFG1_FIFO_EN;
Jamie Smith 0:0c3532738887 332 writeRegister(Register::MDMCFG1, mdmCfg1);
Jamie Smith 0:0c3532738887 333
Jamie Smith 0:0c3532738887 334 // make sure transparent mode is disabled
Jamie Smith 0:0c3532738887 335 uint8_t mdmCfg0 = readRegister(Register::MDMCFG0);
Jamie Smith 0:0c3532738887 336 mdmCfg0 &= ~(1 << MDMCFG0_TRANSPARENT_MODE_EN);
Jamie Smith 0:0c3532738887 337 writeRegister(Register::MDMCFG0, mdmCfg0);
Jamie Smith 0:0c3532738887 338 }
Jamie Smith 0:0c3532738887 339
Jamie Smith 0:0c3532738887 340 void CC1200::setModulationFormat(CC1200::ModFormat format)
Jamie Smith 0:0c3532738887 341 {
Jamie Smith 0:0c3532738887 342 uint8_t modcfgDevE = readRegister(Register::MODCFG_DEV_E);
Jamie Smith 0:0c3532738887 343 modcfgDevE &= ~(0b111 << MODCFG_DEV_E_MOD_FORMAT);
Jamie Smith 0:0c3532738887 344 modcfgDevE |= static_cast<uint8_t>(format) << MODCFG_DEV_E_DEV_E;
Jamie Smith 0:0c3532738887 345 writeRegister(Register::MODCFG_DEV_E, modcfgDevE);
Jamie Smith 0:0c3532738887 346 }
Jamie Smith 0:0c3532738887 347
Jamie Smith 0:0c3532738887 348 void CC1200::setFSKDeviation(float deviation)
Jamie Smith 0:0c3532738887 349 {
Jamie Smith 0:0c3532738887 350 // Deviation is set as two values, an exponent register from 0-3 and a mantissa register from 0-256.
Jamie Smith 0:0c3532738887 351 // See user guide page 81 for the original equation, this function was worked out from that
Jamie Smith 0:0c3532738887 352
Jamie Smith 0:0c3532738887 353 // First assume mantissa is zero and calculate the needed exponent
Jamie Smith 0:0c3532738887 354 float exactExponent = std::log2(deviation) - CC1200_OSC_FREQ_LOG2 + 14;
Jamie Smith 0:0c3532738887 355 uint8_t actualExponent = static_cast<uint8_t>(std::min(static_cast<float>(maxValue3Bits), exactExponent));
Jamie Smith 0:0c3532738887 356 // note: 14 comes from log2(2^22) - log2(256)
Jamie Smith 0:0c3532738887 357
Jamie Smith 0:0c3532738887 358 float exactMantissa;
Jamie Smith 0:0c3532738887 359 if(actualExponent >= 1)
Jamie Smith 0:0c3532738887 360 {
Jamie Smith 0:0c3532738887 361 exactMantissa = (std::pow(2.0f, static_cast<float>(22 - actualExponent)) * deviation)
Jamie Smith 0:0c3532738887 362 / CC1200_OSC_FREQ - 256;
Jamie Smith 0:0c3532738887 363 }
Jamie Smith 0:0c3532738887 364 else
Jamie Smith 0:0c3532738887 365 {
Jamie Smith 0:0c3532738887 366 // use alternate high-resolution formula for case where exponent = 0
Jamie Smith 0:0c3532738887 367 exactMantissa = deviation * twoToThe21 / CC1200_OSC_FREQ;
Jamie Smith 0:0c3532738887 368 }
Jamie Smith 0:0c3532738887 369
Jamie Smith 0:0c3532738887 370 // now calculate closest mantissa
Jamie Smith 0:0c3532738887 371 uint8_t actualMantissa = static_cast<uint8_t>(std::min(static_cast<float>(maxValue8Bits), exactMantissa));
Jamie Smith 0:0c3532738887 372
Jamie Smith 0:0c3532738887 373 // set exponent and mantissa
Jamie Smith 0:0c3532738887 374 writeRegister(Register::DEVIATION_M, actualMantissa);
Jamie Smith 0:0c3532738887 375
Jamie Smith 0:0c3532738887 376 uint8_t modcfgDevE = readRegister(Register::MODCFG_DEV_E);
Jamie Smith 0:0c3532738887 377 modcfgDevE &= ~(0b111 << MODCFG_DEV_E_DEV_E);
Jamie Smith 0:0c3532738887 378 modcfgDevE |= actualExponent << MODCFG_DEV_E_DEV_E;
Jamie Smith 0:0c3532738887 379 writeRegister(Register::MODCFG_DEV_E, modcfgDevE);
Jamie Smith 0:0c3532738887 380
Jamie Smith 0:0c3532738887 381 #if CC1200_DEBUG
Jamie Smith 0:0c3532738887 382 debugStream->printf("Setting FSK deviation, requested +-%.00f Hz, setting DEV_E = 0x%" PRIx8 " DEV_M = 0x%" PRIx8 "\n",
Jamie Smith 0:0c3532738887 383 deviation, actualExponent, actualMantissa);
Jamie Smith 0:0c3532738887 384
Jamie Smith 0:0c3532738887 385 float actualDeviation;
Jamie Smith 0:0c3532738887 386 if(actualExponent == 0)
Jamie Smith 0:0c3532738887 387 {
Jamie Smith 0:0c3532738887 388 actualDeviation = CC1200_OSC_FREQ * actualMantissa / twoToThe21;
Jamie Smith 0:0c3532738887 389 }
Jamie Smith 0:0c3532738887 390 else
Jamie Smith 0:0c3532738887 391 {
Jamie Smith 0:0c3532738887 392 actualDeviation = (CC1200_OSC_FREQ / twoToThe22) * (256.0f + static_cast<float>(actualMantissa)) * pow(2.0f, static_cast<float>(actualExponent));
Jamie Smith 0:0c3532738887 393 }
Jamie Smith 0:0c3532738887 394 // sanity check: calculate actual deviation
Jamie Smith 0:0c3532738887 395 debugStream->printf("This yields an actual deviation of +-%.00f Hz\n", actualDeviation);
Jamie Smith 0:0c3532738887 396 #endif
Jamie Smith 0:0c3532738887 397 }
Jamie Smith 0:0c3532738887 398
Jamie Smith 0:0c3532738887 399 void CC1200::setSymbolRate(float symbolRateHz)
Jamie Smith 0:0c3532738887 400 {
Jamie Smith 0:0c3532738887 401 // Datasheet says that the cc1200 works in ksps, but testing with SmartRF studio
Jamie Smith 0:0c3532738887 402 // shows that it actually is sps.
Jamie Smith 0:0c3532738887 403
Jamie Smith 0:0c3532738887 404 symbolRateSps = symbolRateHz;
Jamie Smith 0:0c3532738887 405
Jamie Smith 0:0c3532738887 406 // Note: these equations are given on page 29 of the user guide
Jamie Smith 0:0c3532738887 407
Jamie Smith 0:0c3532738887 408 float exactExponent = std::log2(symbolRateSps) - CC1200_OSC_FREQ_LOG2 + 19;
Jamie Smith 0:0c3532738887 409 // note: 19 comes from log2(2^39) - 20
Jamie Smith 0:0c3532738887 410 uint8_t actualExponent = static_cast<uint8_t>(std::min(static_cast<float>(maxValue4Bits), exactExponent));
Jamie Smith 0:0c3532738887 411 // note: 15 comes from the largest number storable in 4 bits
Jamie Smith 0:0c3532738887 412
Jamie Smith 0:0c3532738887 413 float exactMantissa;
Jamie Smith 0:0c3532738887 414 if(actualExponent >= 1)
Jamie Smith 0:0c3532738887 415 {
Jamie Smith 0:0c3532738887 416 exactMantissa = (std::pow(2.0f, static_cast<float>(39 - actualExponent)) * symbolRateSps)
Jamie Smith 0:0c3532738887 417 / CC1200_OSC_FREQ - twoToThe20;
Jamie Smith 0:0c3532738887 418 }
Jamie Smith 0:0c3532738887 419 else
Jamie Smith 0:0c3532738887 420 {
Jamie Smith 0:0c3532738887 421 // use alternate high-resolution formula for case where exponent = 0
Jamie Smith 0:0c3532738887 422 exactMantissa = symbolRateSps * twoToThe38 / CC1200_OSC_FREQ;
Jamie Smith 0:0c3532738887 423 }
Jamie Smith 0:0c3532738887 424
Jamie Smith 0:0c3532738887 425 // mantissa is a 20 bit number, so restrict it to that domain
Jamie Smith 0:0c3532738887 426 uint32_t actualMantissa = static_cast<uint32_t>(std::min(static_cast<float>(maxValue20Bits), exactMantissa));
Jamie Smith 0:0c3532738887 427
Jamie Smith 0:0c3532738887 428 // program symbol rate registers
Jamie Smith 0:0c3532738887 429 std::array<uint8_t, 3> symbolRateRegisters ={
Jamie Smith 0:0c3532738887 430 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 431 static_cast<uint8_t>((actualMantissa >> 8) & 0xFF),
Jamie Smith 0:0c3532738887 432 static_cast<uint8_t>((actualMantissa & 0xFF))
Jamie Smith 0:0c3532738887 433 };
Jamie Smith 0:0c3532738887 434 writeRegisters(Register::SYMBOL_RATE2, symbolRateRegisters);
Jamie Smith 0:0c3532738887 435
Jamie Smith 0:0c3532738887 436 // Calculate upsampler value according to the forumula in its register description
Jamie Smith 0:0c3532738887 437 float upsamplingFactor = CC1200_OSC_FREQ / (64 * symbolRateSps);
Jamie Smith 0:0c3532738887 438 uint8_t upsamplerPVal = std::floor(std::log2(upsamplingFactor));
Jamie Smith 0:0c3532738887 439
Jamie Smith 0:0c3532738887 440 uint8_t mdmcfg2 = readRegister(ExtRegister::MDMCFG2);
Jamie Smith 0:0c3532738887 441 mdmcfg2 &= ~(0b111 << MDMCFG2_UPSAMPLER_P);
Jamie Smith 0:0c3532738887 442 mdmcfg2 |= (upsamplerPVal << MDMCFG2_UPSAMPLER_P);
Jamie Smith 0:0c3532738887 443
Jamie Smith 0:0c3532738887 444 writeRegister(ExtRegister::MDMCFG2, mdmcfg2);
Jamie Smith 0:0c3532738887 445
Jamie Smith 0:0c3532738887 446 #if CC1200_DEBUG
Jamie Smith 0:0c3532738887 447 debugStream->printf("Setting symbol rate, requested %.00f Hz, setting SRATE_E = 0x%" PRIx8 " SRATE_M = 0x%" PRIx32 "\n",
Jamie Smith 0:0c3532738887 448 symbolRateHz, actualExponent, actualMantissa);
Jamie Smith 0:0c3532738887 449
Jamie Smith 0:0c3532738887 450 // sanity check: calculate actual symbol rate
Jamie Smith 0:0c3532738887 451 float actualSymbolRateKsps;
Jamie Smith 0:0c3532738887 452 if(actualExponent == 0)
Jamie Smith 0:0c3532738887 453 {
Jamie Smith 0:0c3532738887 454 actualSymbolRateKsps = (static_cast<float>(actualMantissa) * CC1200_OSC_FREQ) / twoToThe38;
Jamie Smith 0:0c3532738887 455 }
Jamie Smith 0:0c3532738887 456 else
Jamie Smith 0:0c3532738887 457 {
Jamie Smith 0:0c3532738887 458
Jamie Smith 0:0c3532738887 459 actualSymbolRateKsps = ((static_cast<float>(actualMantissa) + twoToThe20) *
Jamie Smith 0:0c3532738887 460 pow(2.0f,static_cast<float>(actualExponent)) * CC1200_OSC_FREQ)
Jamie Smith 0:0c3532738887 461 / twoToThe39;
Jamie Smith 0:0c3532738887 462 }
Jamie Smith 0:0c3532738887 463
Jamie Smith 0:0c3532738887 464 debugStream->printf("This yields an actual symbol rate of %.00f Hz\n", actualSymbolRateKsps * 1000.0f);
Jamie Smith 0:0c3532738887 465
Jamie Smith 0:0c3532738887 466 uint8_t actualUpsampling = static_cast<uint8_t>(pow(2.0f, static_cast<float>(upsamplerPVal)));
Jamie Smith 0:0c3532738887 467 debugStream->printf("Also setting upsampling factor to %" PRIu8 " via UPSAMPLER_P = %" PRIx8 "\n", actualUpsampling, upsamplerPVal);
Jamie Smith 0:0c3532738887 468 #endif
Jamie Smith 0:0c3532738887 469 }
Jamie Smith 0:0c3532738887 470
Jamie Smith 0:0c3532738887 471 void CC1200::setOutputPower(float outPower)
Jamie Smith 0:0c3532738887 472 {
Jamie Smith 0:0c3532738887 473 const float minOutputPower = -16.0f;
Jamie Smith 0:0c3532738887 474
Jamie Smith 0:0c3532738887 475 // note: datasheet says this is 14.5, but that must be a mistake: 14.5 would produce a number
Jamie Smith 0:0c3532738887 476 // too large to fit into 6 bits.
Jamie Smith 0:0c3532738887 477 const float maxOutputPower = 14.0f;
Jamie Smith 0:0c3532738887 478
Jamie Smith 0:0c3532738887 479 // clamp output power into correct range
Jamie Smith 0:0c3532738887 480 outPower = std::min(outPower, maxOutputPower);
Jamie Smith 0:0c3532738887 481 outPower = std::max(outPower, minOutputPower);
Jamie Smith 0:0c3532738887 482
Jamie Smith 0:0c3532738887 483 // this equation derived from user guide section 7.1
Jamie Smith 0:0c3532738887 484 float exactPowerRamp = (2 * outPower) + 35;
Jamie Smith 0:0c3532738887 485 uint8_t actualPowerRamp = static_cast<uint8_t>(exactPowerRamp); // round to nearest
Jamie Smith 0:0c3532738887 486
Jamie Smith 0:0c3532738887 487 uint8_t paCfg1 = readRegister(Register::PA_CFG1);
Jamie Smith 0:0c3532738887 488 paCfg1 &= ~(0b111111 << PA_CFG1_PA_POWER_RAMP);
Jamie Smith 0:0c3532738887 489 paCfg1 |= actualPowerRamp << PA_CFG1_PA_POWER_RAMP;
Jamie Smith 0:0c3532738887 490 writeRegister(Register::PA_CFG1, paCfg1);
Jamie Smith 0:0c3532738887 491 }
Jamie Smith 0:0c3532738887 492
Jamie Smith 0:0c3532738887 493 void CC1200::setRadioFrequency(CC1200::Band band, float frequencyHz)
Jamie Smith 0:0c3532738887 494 {
Jamie Smith 0:0c3532738887 495 // Frequency synthesizer configuration. This is completely opaque and it is unknown what these bits do --
Jamie Smith 0:0c3532738887 496 // they are only generated by SmartRF studio.
Jamie Smith 0:0c3532738887 497 // I manually deduplicated them since only a few change based on frequency.
Jamie Smith 0:0c3532738887 498 writeRegister(ExtRegister::IF_ADC1,0xEE);
Jamie Smith 0:0c3532738887 499 writeRegister(ExtRegister::IF_ADC0,0x10);
Jamie Smith 0:0c3532738887 500 writeRegister(ExtRegister::FS_DIG1,0x04);
Jamie Smith 0:0c3532738887 501 writeRegister(ExtRegister::FS_CAL1,0x40);
Jamie Smith 0:0c3532738887 502 writeRegister(ExtRegister::FS_CAL0,0x0E);
Jamie Smith 0:0c3532738887 503 writeRegister(ExtRegister::FS_DIVTWO,0x03);
Jamie Smith 0:0c3532738887 504 writeRegister(ExtRegister::FS_DSM0,0x33);
Jamie Smith 0:0c3532738887 505 writeRegister(ExtRegister::FS_DVC1,0xF7);
Jamie Smith 0:0c3532738887 506 writeRegister(ExtRegister::FS_PFD,0x00);
Jamie Smith 0:0c3532738887 507 writeRegister(ExtRegister::FS_PRE,0x6E);
Jamie Smith 0:0c3532738887 508 writeRegister(ExtRegister::FS_REG_DIV_CML,0x1C);
Jamie Smith 0:0c3532738887 509 writeRegister(ExtRegister::FS_SPARE,0xAC);
Jamie Smith 0:0c3532738887 510 writeRegister(ExtRegister::FS_VCO0,0xB5);
Jamie Smith 0:0c3532738887 511 writeRegister(ExtRegister::XOSC5,0x0E);
Jamie Smith 0:0c3532738887 512 writeRegister(ExtRegister::XOSC1,0x03);
Jamie Smith 0:0c3532738887 513 if(band == Band::BAND_820_960MHz)
Jamie Smith 0:0c3532738887 514 {
Jamie Smith 0:0c3532738887 515 writeRegister(ExtRegister::FS_DIG0,0x55);
Jamie Smith 0:0c3532738887 516 writeRegister(ExtRegister::FS_DVC0,0x17);
Jamie Smith 0:0c3532738887 517 writeRegister(ExtRegister::IFAMP,0x09);
Jamie Smith 0:0c3532738887 518 }
Jamie Smith 0:0c3532738887 519 else if(band == Band::BAND_410_480MHz || band == Band::BAND_164_192MHz)
Jamie Smith 0:0c3532738887 520 {
Jamie Smith 0:0c3532738887 521 writeRegister(ExtRegister::FS_DIG0,0x50);
Jamie Smith 0:0c3532738887 522 writeRegister(ExtRegister::FS_DVC0,0x0F);
Jamie Smith 0:0c3532738887 523 writeRegister(ExtRegister::IFAMP,0x0D);
Jamie Smith 0:0c3532738887 524 }
Jamie Smith 0:0c3532738887 525 else
Jamie Smith 0:0c3532738887 526 {
Jamie Smith 0:0c3532738887 527 // TI doesn't make settings public for the other radio bands.
Jamie Smith 0:0c3532738887 528 // Let's take a guess and use the 480-164MHz values.
Jamie Smith 0:0c3532738887 529 writeRegister(ExtRegister::FS_DIG0,0x50);
Jamie Smith 0:0c3532738887 530 writeRegister(ExtRegister::FS_DVC0,0x0F);
Jamie Smith 0:0c3532738887 531 writeRegister(ExtRegister::IFAMP,0x0D);
Jamie Smith 0:0c3532738887 532 }
Jamie Smith 0:0c3532738887 533
Jamie Smith 0:0c3532738887 534 // convert band to LO Divider value.
Jamie Smith 0:0c3532738887 535 // Most of the bands just multiply the register value by 2, but nooo, not BAND_136_160MHz.
Jamie Smith 0:0c3532738887 536 uint8_t loDividerValue;
Jamie Smith 0:0c3532738887 537 if(band == Band::BAND_136_160MHz)
Jamie Smith 0:0c3532738887 538 {
Jamie Smith 0:0c3532738887 539 loDividerValue = 24;
Jamie Smith 0:0c3532738887 540 }
Jamie Smith 0:0c3532738887 541 else
Jamie Smith 0:0c3532738887 542 {
Jamie Smith 0:0c3532738887 543 loDividerValue = static_cast<uint8_t>(band) * 2;
Jamie Smith 0:0c3532738887 544 }
Jamie Smith 0:0c3532738887 545
Jamie Smith 0:0c3532738887 546 // program band (also enable FS out of lock detector, which is useful for testing)
Jamie Smith 0:0c3532738887 547 writeRegister(Register::FS_CFG, (1 << FS_CFG_FS_LOCK_EN) | (static_cast<uint8_t>(band) << FS_CFG_FSD_BANDSELECT));
Jamie Smith 0:0c3532738887 548
Jamie Smith 0:0c3532738887 549 // equation derived from user guide section 9.12
Jamie Smith 0:0c3532738887 550 float exactFreqValue = (twoToThe16 * frequencyHz * static_cast<float>(loDividerValue)) / CC1200_OSC_FREQ;
Jamie Smith 0:0c3532738887 551 uint32_t actualFreqValue = static_cast<uint32_t>(std::min(static_cast<float>(maxValue24Bits), exactFreqValue));
Jamie Smith 0:0c3532738887 552
Jamie Smith 0:0c3532738887 553 // program frequency registers
Jamie Smith 0:0c3532738887 554 std::array<uint8_t, 3> freqRegisters ={
Jamie Smith 0:0c3532738887 555 static_cast<uint8_t>((actualFreqValue >> 16) & 0xFF),
Jamie Smith 0:0c3532738887 556 static_cast<uint8_t>((actualFreqValue >> 8) & 0xFF),
Jamie Smith 0:0c3532738887 557 static_cast<uint8_t>((actualFreqValue & 0xFF))
Jamie Smith 0:0c3532738887 558 };
Jamie Smith 0:0c3532738887 559 writeRegisters(ExtRegister::FREQ2, freqRegisters);
Jamie Smith 0:0c3532738887 560
Jamie Smith 0:0c3532738887 561 #if CC1200_DEBUG
Jamie Smith 0:0c3532738887 562 debugStream->printf("Setting radio frequency, requested %.00f Hz, setting FREQ = 0x%" PRIx32 "\n",
Jamie Smith 0:0c3532738887 563 frequencyHz, actualFreqValue);
Jamie Smith 0:0c3532738887 564
Jamie Smith 0:0c3532738887 565 // sanity check: calculate actual frequency
Jamie Smith 0:0c3532738887 566 float actualFrequency = (static_cast<float>(actualFreqValue) * CC1200_OSC_FREQ) / (twoToThe16 * static_cast<float>(loDividerValue));
Jamie Smith 0:0c3532738887 567
Jamie Smith 0:0c3532738887 568 debugStream->printf("This yields an actual frequency of %.00f Hz\n", actualFrequency);
Jamie Smith 0:0c3532738887 569 #endif
Jamie Smith 0:0c3532738887 570 }
Jamie Smith 0:0c3532738887 571
Jamie Smith 0:0c3532738887 572 // helper function for setRXFilterBandwidth:
Jamie Smith 0:0c3532738887 573 // calculate actual receive bandwidth from the given decimations.
Jamie Smith 0:0c3532738887 574 float calcReceiveBandwidth(uint8_t adcDecimation, uint8_t cicDecimation)
Jamie Smith 0:0c3532738887 575 {
Jamie Smith 0:0c3532738887 576 return CC1200_OSC_FREQ / (static_cast<float>(adcDecimation) * static_cast<float>(cicDecimation) * 2);
Jamie Smith 0:0c3532738887 577 }
Jamie Smith 0:0c3532738887 578
Jamie Smith 1:98af824b145e 579 void CC1200::setRXFilterBandwidth(float bandwidthHz)
Jamie Smith 0:0c3532738887 580 {
Jamie Smith 0:0c3532738887 581 // settings that the chip supports
Jamie Smith 0:0c3532738887 582 const uint8_t possibleADCDecimations[] = {12, 24, 48}; // indexes in this array represent the register value
Jamie Smith 0:0c3532738887 583 const size_t numADCDecimations = sizeof(possibleADCDecimations) / sizeof(uint8_t);
Jamie Smith 0:0c3532738887 584 const uint8_t minBBDecimation = 1;
Jamie Smith 0:0c3532738887 585
Jamie Smith 0:0c3532738887 586 // maximum supported BB decimation based on ADC decimation varies based on chip
Jamie Smith 0:0c3532738887 587 const uint8_t maxBBDecimations1201[] = {33, 16, 8};
Jamie Smith 0:0c3532738887 588 const uint8_t maxBBDecimations1200[] = {44, 44, 44};
Jamie Smith 0:0c3532738887 589 uint8_t const * maxBBDecimations = isCC1201 ? maxBBDecimations1201 : maxBBDecimations1200;
Jamie Smith 0:0c3532738887 590
Jamie Smith 0:0c3532738887 591 // the datasheet suggests to use the highest possible ADC decimation factor that will work for the requested frequency.
Jamie Smith 0:0c3532738887 592 // 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 593
Jamie Smith 0:0c3532738887 594 uint8_t actualBBDecimations[numADCDecimations];
Jamie Smith 0:0c3532738887 595
Jamie Smith 0:0c3532738887 596 for(size_t adcDecimationIndex = 0; adcDecimationIndex < numADCDecimations; ++adcDecimationIndex)
Jamie Smith 0:0c3532738887 597 {
Jamie Smith 0:0c3532738887 598 uint8_t adcDecimation = possibleADCDecimations[adcDecimationIndex];
Jamie Smith 0:0c3532738887 599
Jamie Smith 0:0c3532738887 600 // calculate BB decimation closest to the requested frequency
Jamie Smith 0:0c3532738887 601 // derived from formula in section 6.1
Jamie Smith 0:0c3532738887 602 float exactBBDecimation = CC1200_OSC_FREQ / (2 * bandwidthHz * static_cast<float>(adcDecimation));
Jamie Smith 0:0c3532738887 603 exactBBDecimation = std::max(exactBBDecimation, static_cast<float>(minBBDecimation));
Jamie Smith 0:0c3532738887 604 exactBBDecimation = std::min(exactBBDecimation, static_cast<float>(maxBBDecimations[adcDecimationIndex]));
Jamie Smith 0:0c3532738887 605
Jamie Smith 0:0c3532738887 606 actualBBDecimations[adcDecimationIndex] = static_cast<uint8_t>(exactBBDecimation);
Jamie Smith 0:0c3532738887 607 }
Jamie Smith 0:0c3532738887 608
Jamie Smith 0:0c3532738887 609 // now, choose the best of the ones we calculated
Jamie Smith 0:0c3532738887 610 uint8_t bestDecimationIndex = 0;
Jamie Smith 0:0c3532738887 611 float bestDecimationError = std::abs(bandwidthHz - calcReceiveBandwidth(possibleADCDecimations[0], actualBBDecimations[0]));
Jamie Smith 0:0c3532738887 612
Jamie Smith 0:0c3532738887 613 for(size_t adcDecimationIndex = 1; adcDecimationIndex < numADCDecimations; ++adcDecimationIndex)
Jamie Smith 0:0c3532738887 614 {
Jamie Smith 0:0c3532738887 615 float thisDecimationError = std::abs(bandwidthHz -
Jamie Smith 0:0c3532738887 616 calcReceiveBandwidth(possibleADCDecimations[adcDecimationIndex], actualBBDecimations[adcDecimationIndex]));
Jamie Smith 0:0c3532738887 617 if(thisDecimationError <= bestDecimationError)
Jamie Smith 0:0c3532738887 618 {
Jamie Smith 0:0c3532738887 619 bestDecimationError = thisDecimationError;
Jamie Smith 0:0c3532738887 620 bestDecimationIndex = adcDecimationIndex;
Jamie Smith 0:0c3532738887 621 }
Jamie Smith 0:0c3532738887 622 }
Jamie Smith 0:0c3532738887 623
Jamie Smith 0:0c3532738887 624 // now use the best value!
Jamie Smith 0:0c3532738887 625 uint8_t chanBwValue = (bestDecimationIndex << CHAN_BW_ADC_CIC_DECFACT) | (actualBBDecimations[bestDecimationIndex] << CHAN_BW_BB_CIC_DECFACT);
Jamie Smith 0:0c3532738887 626 writeRegister(Register::CHAN_BW, chanBwValue);
Jamie Smith 0:0c3532738887 627
Jamie Smith 0:0c3532738887 628 // also set DVGA_GAIN, which depends on bandwidth
Jamie Smith 0:0c3532738887 629 uint8_t mdmCfg1Value = readRegister(Register::MDMCFG1);
Jamie Smith 0:0c3532738887 630
Jamie Smith 0:0c3532738887 631 mdmCfg1Value &= ~(0b11 << MDMCFG1_DVGA_GAIN);
Jamie Smith 0:0c3532738887 632 if(bandwidthHz >= 100000)
Jamie Smith 0:0c3532738887 633 {
Jamie Smith 0:0c3532738887 634 mdmCfg1Value |= 1 << MDMCFG1_DVGA_GAIN;
Jamie Smith 0:0c3532738887 635 }
Jamie Smith 0:0c3532738887 636
Jamie Smith 0:0c3532738887 637 writeRegister(Register::MDMCFG1, mdmCfg1Value);
Jamie Smith 0:0c3532738887 638
Jamie Smith 1:98af824b145e 639 // also set MDMCFG0.DATA_FILTER_EN, which should be 0b11 iff bandwidth / symbol rate > 10
Jamie Smith 1:98af824b145e 640 uint8_t mdmCfg0Val = readRegister(Register::MDMCFG0);
Jamie Smith 1:98af824b145e 641
Jamie Smith 1:98af824b145e 642 if(bandwidthHz / symbolRateSps > 10.0f)
Jamie Smith 1:98af824b145e 643 {
Jamie Smith 1:98af824b145e 644 mdmCfg0Val |= 0b11 << MDMCFG0_DATA_FILTER_EN;
Jamie Smith 1:98af824b145e 645 }
Jamie Smith 1:98af824b145e 646 else
Jamie Smith 1:98af824b145e 647 {
Jamie Smith 1:98af824b145e 648 mdmCfg0Val &= ~(0b11 << MDMCFG0_DATA_FILTER_EN);
Jamie Smith 1:98af824b145e 649 }
Jamie Smith 1:98af824b145e 650
Jamie Smith 1:98af824b145e 651 writeRegister(Register::MDMCFG0, mdmCfg0Val);
Jamie Smith 1:98af824b145e 652
Jamie Smith 0:0c3532738887 653 // finally, we need to set RX_CONFIG_LIMITATION. It's not exactly clear what this does, but its setting changes
Jamie Smith 0:0c3532738887 654 // based on the filter BW.
Jamie Smith 0:0c3532738887 655 uint8_t syncCfg0Value = readRegister(Register::SYNC_CFG0);
Jamie Smith 0:0c3532738887 656
Jamie Smith 0:0c3532738887 657 if(symbolRateSps < bandwidthHz / 2 || bandwidthHz > 1500000)
Jamie Smith 0:0c3532738887 658 {
Jamie Smith 0:0c3532738887 659 // clear RX_CONFIG_LIMITATION
Jamie Smith 0:0c3532738887 660 syncCfg0Value &= ~(1 << SYNC_CFG0_RX_CONFIG_LIMITATION);
Jamie Smith 0:0c3532738887 661 }
Jamie Smith 0:0c3532738887 662 else
Jamie Smith 0:0c3532738887 663 {
Jamie Smith 0:0c3532738887 664 // set RX_CONFIG_LIMITATION
Jamie Smith 0:0c3532738887 665 syncCfg0Value |= (1 << SYNC_CFG0_RX_CONFIG_LIMITATION);
Jamie Smith 0:0c3532738887 666 }
Jamie Smith 0:0c3532738887 667
Jamie Smith 0:0c3532738887 668 writeRegister(Register::SYNC_CFG0, syncCfg0Value);
Jamie Smith 0:0c3532738887 669
Jamie Smith 0:0c3532738887 670 adcCicDecimation = possibleADCDecimations[bestDecimationIndex];
Jamie Smith 0:0c3532738887 671
Jamie Smith 0:0c3532738887 672 #if CC1200_DEBUG
Jamie Smith 0:0c3532738887 673 debugStream->printf("Setting BB decimation to %" PRIu8 " and ADC decimation to %" PRIu8 "\n",
Jamie Smith 0:0c3532738887 674 actualBBDecimations[bestDecimationIndex], possibleADCDecimations[bestDecimationIndex]);
Jamie Smith 0:0c3532738887 675 debugStream->printf("This yields an actual RX filter BW of %.00f\n",
Jamie Smith 0:0c3532738887 676 calcReceiveBandwidth(possibleADCDecimations[bestDecimationIndex], actualBBDecimations[bestDecimationIndex]));
Jamie Smith 0:0c3532738887 677 #endif
Jamie Smith 0:0c3532738887 678 }
Jamie Smith 0:0c3532738887 679
Jamie Smith 0:0c3532738887 680 void CC1200::configureDCFilter(bool enableAutoFilter, uint8_t settlingCfg, uint8_t cutoffCfg)
Jamie Smith 0:0c3532738887 681 {
Jamie Smith 0:0c3532738887 682 uint8_t dcfiltCfg = 0;
Jamie Smith 0:0c3532738887 683
Jamie Smith 0:0c3532738887 684 if(!enableAutoFilter)
Jamie Smith 0:0c3532738887 685 {
Jamie Smith 0:0c3532738887 686 // set "freeze coeff" bit
Jamie Smith 0:0c3532738887 687 dcfiltCfg |= (1 << DCFILT_CFG_DCFILT_FREEZE_COEFF);
Jamie Smith 0:0c3532738887 688 }
Jamie Smith 0:0c3532738887 689
Jamie Smith 0:0c3532738887 690 dcfiltCfg |= settlingCfg << DCFILT_CFG_DCFILT_BW_SETTLE;
Jamie Smith 0:0c3532738887 691 dcfiltCfg |= cutoffCfg << DCFILT_CFG_DCFILT_BW;
Jamie Smith 0:0c3532738887 692
Jamie Smith 0:0c3532738887 693 writeRegister(Register::DCFILT_CFG, dcfiltCfg);
Jamie Smith 0:0c3532738887 694 }
Jamie Smith 0:0c3532738887 695
Jamie Smith 0:0c3532738887 696 void CC1200::setIQMismatchCompensationEnabled(bool enabled)
Jamie Smith 0:0c3532738887 697 {
Jamie Smith 0:0c3532738887 698 uint8_t iqicValue = readRegister(Register::IQIC);
Jamie Smith 0:0c3532738887 699
Jamie Smith 0:0c3532738887 700 if(enabled)
Jamie Smith 0:0c3532738887 701 {
Jamie Smith 0:0c3532738887 702 iqicValue |= (1 << IQIC_IQIC_EN);
Jamie Smith 0:0c3532738887 703 }
Jamie Smith 0:0c3532738887 704 else
Jamie Smith 0:0c3532738887 705 {
Jamie Smith 0:0c3532738887 706 iqicValue &= ~(1 << IQIC_IQIC_EN);
Jamie Smith 0:0c3532738887 707 }
Jamie Smith 0:0c3532738887 708
Jamie Smith 0:0c3532738887 709 writeRegister(Register::IQIC, iqicValue);
Jamie Smith 0:0c3532738887 710 }
Jamie Smith 0:0c3532738887 711
Jamie Smith 0:0c3532738887 712 void CC1200::configureSyncWord(uint32_t syncWord, CC1200::SyncMode mode, uint8_t syncThreshold)
Jamie Smith 0:0c3532738887 713 {
Jamie Smith 0:0c3532738887 714 // program sync word registers
Jamie Smith 0:0c3532738887 715 std::array<uint8_t, 4> syncWordRegisters ={
Jamie Smith 0:0c3532738887 716 static_cast<uint8_t>((syncWord >> 24) & 0xFF),
Jamie Smith 0:0c3532738887 717 static_cast<uint8_t>((syncWord >> 16) & 0xFF),
Jamie Smith 0:0c3532738887 718 static_cast<uint8_t>((syncWord >> 8) & 0xFF),
Jamie Smith 0:0c3532738887 719 static_cast<uint8_t>(syncWord & 0xFF)
Jamie Smith 0:0c3532738887 720 };
Jamie Smith 0:0c3532738887 721 writeRegisters(Register::SYNC3, syncWordRegisters);
Jamie Smith 0:0c3532738887 722
Jamie Smith 0:0c3532738887 723 // program sync word cfg
Jamie Smith 0:0c3532738887 724 writeRegister(Register::SYNC_CFG1, (static_cast<uint8_t>(mode) << SYNC_CFG1_SYNC_MODE) | (syncThreshold << SYNC_CFG1_SYNC_THR));
Jamie Smith 0:0c3532738887 725 }
Jamie Smith 0:0c3532738887 726
Jamie Smith 0:0c3532738887 727 bool CC1200::isFSLocked()
Jamie Smith 0:0c3532738887 728 {
Jamie Smith 0:0c3532738887 729 return readRegister(ExtRegister::FSCAL_CTRL) & (1 << FSCAL_CTRL_LOCK);
Jamie Smith 0:0c3532738887 730 }
Jamie Smith 0:0c3532738887 731
Jamie Smith 0:0c3532738887 732 void CC1200::configurePreamble(uint8_t preambleLengthCfg, uint8_t preambleFormatCfg)
Jamie Smith 0:0c3532738887 733 {
Jamie Smith 0:0c3532738887 734 uint8_t preambleCfg1 = 0;
Jamie Smith 0:0c3532738887 735 preambleCfg1 |= preambleLengthCfg << PREAMBLE_CFG1_NUM_PREAMBLE;
Jamie Smith 0:0c3532738887 736 preambleCfg1 |= preambleFormatCfg << PREAMBLE_CFG1_PREAMBLE_WORD;
Jamie Smith 0:0c3532738887 737 writeRegister(Register::PREAMBLE_CFG1, preambleCfg1);
Jamie Smith 0:0c3532738887 738 }
Jamie Smith 0:0c3532738887 739
Jamie Smith 1:98af824b145e 740 void CC1200::setPARampRate(uint8_t firstRampLevel, uint8_t secondRampLevel, CC1200::RampTime rampTime)
Jamie Smith 1:98af824b145e 741 {
Jamie Smith 1:98af824b145e 742 uint8_t paCfg0Val = 0;
Jamie Smith 1:98af824b145e 743 paCfg0Val |= (firstRampLevel << PA_CFG0_FIRST_IPL);
Jamie Smith 1:98af824b145e 744 paCfg0Val |= (secondRampLevel << PA_CFG0_SECOND_IPL);
Jamie Smith 1:98af824b145e 745 paCfg0Val |= (static_cast<uint8_t>(rampTime) << PA_CFG0_RAMP_SHAPE);
Jamie Smith 1:98af824b145e 746
Jamie Smith 1:98af824b145e 747 writeRegister(Register::PA_CFG0, paCfg0Val);
Jamie Smith 1:98af824b145e 748 }
Jamie Smith 1:98af824b145e 749
Jamie Smith 1:98af824b145e 750 void CC1200::setAGCReferenceLevel(uint8_t level)
Jamie Smith 1:98af824b145e 751 {
Jamie Smith 1:98af824b145e 752 writeRegister(Register::AGC_REF, level);
Jamie Smith 1:98af824b145e 753 }
Jamie Smith 1:98af824b145e 754
Jamie Smith 1:98af824b145e 755 void CC1200::setAGCSyncBehavior(CC1200::SyncBehavior behavior)
Jamie Smith 1:98af824b145e 756 {
Jamie Smith 1:98af824b145e 757 uint8_t agcCfg3Val = readRegister(Register::AGC_CFG3);
Jamie Smith 1:98af824b145e 758 agcCfg3Val &= ~(0b111 << AGC_CFG3_AGC_SYNC_BEHAVIOUR);
Jamie Smith 1:98af824b145e 759 agcCfg3Val |= static_cast<uint8_t>(behavior) << AGC_CFG3_AGC_SYNC_BEHAVIOUR;
Jamie Smith 1:98af824b145e 760 writeRegister(Register::AGC_CFG3, agcCfg3Val);
Jamie Smith 1:98af824b145e 761 }
Jamie Smith 1:98af824b145e 762
Jamie Smith 1:98af824b145e 763 void CC1200::setAGCGainTable(CC1200::GainTable table, uint8_t minGainIndex, uint8_t maxGainIndex)
Jamie Smith 1:98af824b145e 764 {
Jamie Smith 1:98af824b145e 765 uint8_t agcCfg3Val = readRegister(Register::AGC_CFG3);
Jamie Smith 1:98af824b145e 766 uint8_t agcCfg2Val = readRegister(Register::AGC_CFG2);
Jamie Smith 1:98af824b145e 767
Jamie Smith 1:98af824b145e 768 agcCfg3Val &= ~(0b11111 << AGC_CFG3_AGC_MIN_GAIN);
Jamie Smith 1:98af824b145e 769 agcCfg2Val &= ~(0b11 << AGC_CFG2_FE_PERFORMANCE_MODE);
Jamie Smith 1:98af824b145e 770 agcCfg2Val &= ~(0b11111 << AGC_CFG2_AGC_MAX_GAIN);
Jamie Smith 1:98af824b145e 771
Jamie Smith 1:98af824b145e 772 agcCfg3Val |= maxGainIndex << AGC_CFG3_AGC_MIN_GAIN;
Jamie Smith 1:98af824b145e 773 agcCfg2Val |= static_cast<uint8_t>(table) << AGC_CFG2_FE_PERFORMANCE_MODE;
Jamie Smith 1:98af824b145e 774 agcCfg2Val |= maxGainIndex << AGC_CFG2_AGC_MAX_GAIN;
Jamie Smith 1:98af824b145e 775
Jamie Smith 1:98af824b145e 776 writeRegister(Register::AGC_CFG3, agcCfg3Val);
Jamie Smith 1:98af824b145e 777 writeRegister(Register::AGC_CFG2, agcCfg2Val);
Jamie Smith 1:98af824b145e 778 }
Jamie Smith 1:98af824b145e 779
Jamie Smith 1:98af824b145e 780 void CC1200::setAGCHysteresis(uint8_t hysteresisCfg)
Jamie Smith 1:98af824b145e 781 {
Jamie Smith 1:98af824b145e 782 uint8_t agcCfg0Val = readRegister(Register::AGC_CFG0);
Jamie Smith 1:98af824b145e 783 agcCfg0Val &= ~(0b11 << AGC_CFG0_AGC_HYST_LEVEL);
Jamie Smith 1:98af824b145e 784 agcCfg0Val |= hysteresisCfg << AGC_CFG0_AGC_HYST_LEVEL;
Jamie Smith 1:98af824b145e 785 writeRegister(Register::AGC_CFG0, agcCfg0Val);
Jamie Smith 1:98af824b145e 786 }
Jamie Smith 1:98af824b145e 787
Jamie Smith 1:98af824b145e 788 void CC1200::setAGCSlewRate(uint8_t slewrateCfg)
Jamie Smith 1:98af824b145e 789 {
Jamie Smith 1:98af824b145e 790 uint8_t agcCfg0Val = readRegister(Register::AGC_CFG0);
Jamie Smith 1:98af824b145e 791 agcCfg0Val &= ~(0b11 << AGC_CFG0_AGC_SLEWRATE_LIMIT);
Jamie Smith 1:98af824b145e 792 agcCfg0Val |= slewrateCfg << AGC_CFG0_AGC_SLEWRATE_LIMIT;
Jamie Smith 1:98af824b145e 793 writeRegister(Register::AGC_CFG0, agcCfg0Val);
Jamie Smith 1:98af824b145e 794 }
Jamie Smith 1:98af824b145e 795
Jamie Smith 0:0c3532738887 796 void CC1200::setIFMixCFG(uint8_t value)
Jamie Smith 0:0c3532738887 797 {
Jamie Smith 0:0c3532738887 798 uint8_t ifMixCfg = readRegister(ExtRegister::IF_MIX_CFG);
Jamie Smith 0:0c3532738887 799 ifMixCfg &= ~(0b111 << IF_MIX_CFG_CMIX_CFG);
Jamie Smith 0:0c3532738887 800 ifMixCfg |= (value << IF_MIX_CFG_CMIX_CFG);
Jamie Smith 0:0c3532738887 801 writeRegister(ExtRegister::IF_MIX_CFG, ifMixCfg);
Jamie Smith 0:0c3532738887 802 }
Jamie Smith 0:0c3532738887 803
Jamie Smith 0:0c3532738887 804 uint8_t CC1200::readRegister(CC1200::Register reg)
Jamie Smith 0:0c3532738887 805 {
Jamie Smith 0:0c3532738887 806 spi.select();
Jamie Smith 0:0c3532738887 807 loadStatusByte(spi.write(CC1200_READ | static_cast<uint8_t>(reg)));
Jamie Smith 0:0c3532738887 808 uint8_t regValue = spi.write(0);
Jamie Smith 0:0c3532738887 809 spi.deselect();
Jamie Smith 0:0c3532738887 810
Jamie Smith 0:0c3532738887 811 #if CC1200_REGISTER_LEVEL_DEBUG
Jamie Smith 0:0c3532738887 812 debugStream->printf("Read register 0x%" PRIx8 " -> 0x%" PRIx8 "\n", static_cast<uint8_t>(reg), regValue);
Jamie Smith 0:0c3532738887 813 #endif
Jamie Smith 0:0c3532738887 814
Jamie Smith 0:0c3532738887 815 return regValue;
Jamie Smith 0:0c3532738887 816 }
Jamie Smith 0:0c3532738887 817
Jamie Smith 0:0c3532738887 818 void CC1200::writeRegister(Register reg, uint8_t value)
Jamie Smith 0:0c3532738887 819 {
Jamie Smith 0:0c3532738887 820 spi.select();
Jamie Smith 0:0c3532738887 821 loadStatusByte(spi.write(CC1200_WRITE | static_cast<uint8_t>(reg)));
Jamie Smith 0:0c3532738887 822 spi.write(value);
Jamie Smith 0:0c3532738887 823 spi.deselect();
Jamie Smith 0:0c3532738887 824
Jamie Smith 0:0c3532738887 825 #if CC1200_REGISTER_LEVEL_DEBUG
Jamie Smith 0:0c3532738887 826 debugStream->printf("Wrote register 0x%" PRIx8 " <- 0x%" PRIx8 "\n", static_cast<uint8_t>(reg), value);
Jamie Smith 0:0c3532738887 827 #endif
Jamie Smith 0:0c3532738887 828 }
Jamie Smith 0:0c3532738887 829
Jamie Smith 0:0c3532738887 830 void CC1200::writeRegisters(CC1200::Register startReg, uint8_t const *values, size_t numRegisters)
Jamie Smith 0:0c3532738887 831 {
Jamie Smith 0:0c3532738887 832 spi.select();
Jamie Smith 0:0c3532738887 833 loadStatusByte(spi.write(CC1200_WRITE | CC1200_BURST | static_cast<uint8_t>(startReg)));
Jamie Smith 0:0c3532738887 834
Jamie Smith 0:0c3532738887 835 for(size_t byteIndex = 0; byteIndex < numRegisters; ++byteIndex)
Jamie Smith 0:0c3532738887 836 {
Jamie Smith 0:0c3532738887 837 spi.write(values[byteIndex]);
Jamie Smith 0:0c3532738887 838 }
Jamie Smith 0:0c3532738887 839 spi.deselect();
Jamie Smith 0:0c3532738887 840
Jamie Smith 0:0c3532738887 841 #if CC1200_REGISTER_LEVEL_DEBUG
Jamie Smith 0:0c3532738887 842 for(size_t byteIndex = 0; byteIndex < numRegisters; ++byteIndex)
Jamie Smith 0:0c3532738887 843 {
Jamie Smith 0:0c3532738887 844 debugStream->printf("Wrote register 0x%" PRIx8 " <- 0x%" PRIx8 "\n",
Jamie Smith 0:0c3532738887 845 static_cast<uint8_t>(static_cast<uint8_t>(startReg) + byteIndex),
Jamie Smith 0:0c3532738887 846 values[byteIndex]);
Jamie Smith 0:0c3532738887 847 }
Jamie Smith 0:0c3532738887 848 #endif
Jamie Smith 0:0c3532738887 849 }
Jamie Smith 0:0c3532738887 850
Jamie Smith 0:0c3532738887 851 void CC1200::loadStatusByte(uint8_t status)
Jamie Smith 0:0c3532738887 852 {
Jamie Smith 0:0c3532738887 853 chipReady = !(status >> 7);
Jamie Smith 0:0c3532738887 854 state = static_cast<State>((status >> 4) & 0x7);
Jamie Smith 0:0c3532738887 855
Jamie Smith 0:0c3532738887 856 #if CC1200_REGISTER_LEVEL_DEBUG
Jamie Smith 0:0c3532738887 857 debugStream->printf("Updated status, state = 0x%" PRIx8 " ready = %s\n", static_cast<uint8_t>(state), chipReady ? "true" : "false");
Jamie Smith 0:0c3532738887 858 #endif
Jamie Smith 0:0c3532738887 859 }
Jamie Smith 0:0c3532738887 860
Jamie Smith 0:0c3532738887 861 uint8_t CC1200::readRegister(CC1200::ExtRegister reg)
Jamie Smith 0:0c3532738887 862 {
Jamie Smith 0:0c3532738887 863 spi.select();
Jamie Smith 0:0c3532738887 864 loadStatusByte(spi.write(CC1200_READ | CC1200_EXT_ADDR));
Jamie Smith 0:0c3532738887 865 spi.write(static_cast<uint8_t>(reg));
Jamie Smith 0:0c3532738887 866 uint8_t regValue = spi.write(0);
Jamie Smith 0:0c3532738887 867 spi.deselect();
Jamie Smith 0:0c3532738887 868
Jamie Smith 0:0c3532738887 869 #if CC1200_REGISTER_LEVEL_DEBUG
Jamie Smith 0:0c3532738887 870 debugStream->printf("Read ext register 0x%" PRIx8 " -> 0x%" PRIx8 "\n", static_cast<uint8_t>(reg), regValue);
Jamie Smith 0:0c3532738887 871 #endif
Jamie Smith 0:0c3532738887 872
Jamie Smith 0:0c3532738887 873 return regValue;
Jamie Smith 0:0c3532738887 874 }
Jamie Smith 0:0c3532738887 875
Jamie Smith 0:0c3532738887 876 void CC1200::writeRegister(CC1200::ExtRegister reg, uint8_t value)
Jamie Smith 0:0c3532738887 877 {
Jamie Smith 0:0c3532738887 878 spi.select();
Jamie Smith 0:0c3532738887 879 loadStatusByte(spi.write(CC1200_WRITE | CC1200_EXT_ADDR));
Jamie Smith 0:0c3532738887 880 spi.write(static_cast<uint8_t>(reg));
Jamie Smith 0:0c3532738887 881 spi.write(value);
Jamie Smith 0:0c3532738887 882 spi.deselect();
Jamie Smith 0:0c3532738887 883
Jamie Smith 0:0c3532738887 884 #if CC1200_REGISTER_LEVEL_DEBUG
Jamie Smith 0:0c3532738887 885 debugStream->printf("Wrote ext register 0x%" PRIx8 " <- 0x%" PRIx8 "\n", static_cast<uint8_t>(reg), value);
Jamie Smith 0:0c3532738887 886 #endif
Jamie Smith 0:0c3532738887 887 }
Jamie Smith 0:0c3532738887 888
Jamie Smith 0:0c3532738887 889 void CC1200::writeRegisters(CC1200::ExtRegister startReg, uint8_t const *values, size_t numRegisters)
Jamie Smith 0:0c3532738887 890 {
Jamie Smith 0:0c3532738887 891 spi.select();
Jamie Smith 0:0c3532738887 892 loadStatusByte(spi.write(CC1200_WRITE | CC1200_BURST | CC1200_EXT_ADDR));
Jamie Smith 0:0c3532738887 893 spi.write(static_cast<uint8_t>(startReg));
Jamie Smith 0:0c3532738887 894
Jamie Smith 0:0c3532738887 895 for(size_t byteIndex = 0; byteIndex < numRegisters; ++byteIndex)
Jamie Smith 0:0c3532738887 896 {
Jamie Smith 0:0c3532738887 897 spi.write(values[byteIndex]);
Jamie Smith 0:0c3532738887 898 }
Jamie Smith 0:0c3532738887 899 spi.deselect();
Jamie Smith 0:0c3532738887 900
Jamie Smith 0:0c3532738887 901 #if CC1200_REGISTER_LEVEL_DEBUG
Jamie Smith 0:0c3532738887 902 for(size_t byteIndex = 0; byteIndex < numRegisters; ++byteIndex)
Jamie Smith 0:0c3532738887 903 {
Jamie Smith 0:0c3532738887 904 debugStream->printf("Wrote extended register 0x%" PRIx8 " <- 0x%" PRIx8 "\n",
Jamie Smith 0:0c3532738887 905 static_cast<uint8_t>(static_cast<uint8_t>(startReg) + byteIndex),
Jamie Smith 0:0c3532738887 906 values[byteIndex]);
Jamie Smith 0:0c3532738887 907 }
Jamie Smith 0:0c3532738887 908 #endif
Jamie Smith 0:0c3532738887 909 }
Jamie Smith 0:0c3532738887 910
Jamie Smith 0:0c3532738887 911 void CC1200::sendCommand(CC1200::Command command)
Jamie Smith 0:0c3532738887 912 {
Jamie Smith 0:0c3532738887 913 spi.select();
Jamie Smith 0:0c3532738887 914 loadStatusByte(spi.write(static_cast<uint8_t>(command)));
Jamie Smith 0:0c3532738887 915 spi.deselect();
Jamie Smith 0:0c3532738887 916
Jamie Smith 0:0c3532738887 917 #if CC1200_REGISTER_LEVEL_DEBUG
Jamie Smith 0:0c3532738887 918 debugStream->printf("Sent SPI command 0x%" PRIx8 "\n", static_cast<uint8_t>(command));
Jamie Smith 0:0c3532738887 919 #endif
Jamie Smith 0:0c3532738887 920 }
Jamie Smith 0:0c3532738887 921
Jamie Smith 0:0c3532738887 922 uint8_t CC1200::readRXFIFOByte(uint8_t address)
Jamie Smith 0:0c3532738887 923 {
Jamie Smith 0:0c3532738887 924 spi.select();
Jamie Smith 0:0c3532738887 925 loadStatusByte(spi.write(CC1200_READ | CC1200_MEM_ACCESS));
Jamie Smith 2:2a447e8e50b8 926 spi.write(CC1200_RX_FIFO | address);
Jamie Smith 2:2a447e8e50b8 927 int value = spi.write(0);
Jamie Smith 0:0c3532738887 928 spi.deselect();
Jamie Smith 0:0c3532738887 929
Jamie Smith 0:0c3532738887 930 #if CC1200_REGISTER_LEVEL_DEBUG
Jamie Smith 2:2a447e8e50b8 931 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 932 #endif
Jamie Smith 0:0c3532738887 933
Jamie Smith 0:0c3532738887 934 return value;
Jamie Smith 0:0c3532738887 935 }
Jamie Smith 0:0c3532738887 936
Jamie Smith 0:0c3532738887 937
Jamie Smith 1:98af824b145e 938 #pragma clang diagnostic pop