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 May 03 02:41:34 2021 -0700
Revision:
5:d22a8885800b
Parent:
4:c609cc7c9ea7
Update to v1.2

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 5:d22a8885800b 15 #define CC1200_DEBUG 1
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 5:d22a8885800b 56 // Length of the status bytes that can be appended to packets
Jamie Smith 5:d22a8885800b 57 #define PACKET_STATUS_LEN 2U
Jamie Smith 5:d22a8885800b 58
Jamie Smith 0:0c3532738887 59 // utility function: compile-time power calculator.
Jamie Smith 0:0c3532738887 60 // Works on all signed and unsigned integer types for T.
Jamie Smith 0:0c3532738887 61 // from: http://prosepoetrycode.potterpcs.net/2015/07/a-simple-constexpr-power-function-c/
Jamie Smith 0:0c3532738887 62 template <typename T>
Jamie Smith 0:0c3532738887 63 constexpr T constexpr_pow(T num, unsigned int pow)
Jamie Smith 0:0c3532738887 64 {
Jamie Smith 0:0c3532738887 65 return pow == 0 ? 1 : num * constexpr_pow(num, pow-1);
Jamie Smith 0:0c3532738887 66 }
Jamie Smith 0:0c3532738887 67
Jamie Smith 0:0c3532738887 68 // power of two constants
Jamie Smith 0:0c3532738887 69 const float twoToThe16 = constexpr_pow(2.0f, 16);
Jamie Smith 0:0c3532738887 70 const float twoToThe20 = constexpr_pow(2.0f, 20);
Jamie Smith 0:0c3532738887 71 const float twoToThe21 = constexpr_pow(2.0f, 21);
Jamie Smith 0:0c3532738887 72 const float twoToThe22 = constexpr_pow(2.0f, 22);
Jamie Smith 0:0c3532738887 73 const float twoToThe38 = constexpr_pow(2.0f, 38);
Jamie Smith 0:0c3532738887 74 const float twoToThe39 = constexpr_pow(2.0f, 39);
Jamie Smith 0:0c3532738887 75
Jamie Smith 0:0c3532738887 76 // binary value size constants
Jamie Smith 0:0c3532738887 77 const size_t maxValue3Bits = constexpr_pow(2, 3) - 1;
Jamie Smith 0:0c3532738887 78 const size_t maxValue4Bits = constexpr_pow(2, 4) - 1;
Jamie Smith 0:0c3532738887 79 const size_t maxValue8Bits = constexpr_pow(2, 8) - 1;
Jamie Smith 0:0c3532738887 80 const size_t maxValue20Bits = constexpr_pow(2, 20) - 1;
Jamie Smith 0:0c3532738887 81 const size_t maxValue24Bits = constexpr_pow(2, 24) - 1;
Jamie Smith 0:0c3532738887 82
Jamie Smith 0:0c3532738887 83 CC1200::CC1200(PinName mosiPin, PinName misoPin, PinName sclkPin, PinName csPin, PinName rstPin, Stream * _debugStream, bool _isCC1201):
Jamie Smith 0:0c3532738887 84 spi(mosiPin, misoPin, sclkPin, csPin, use_gpio_ssel),
Jamie Smith 0:0c3532738887 85 rst(rstPin, 1),
Jamie Smith 0:0c3532738887 86 debugStream(_debugStream),
Jamie Smith 0:0c3532738887 87 isCC1201(_isCC1201)
Jamie Smith 0:0c3532738887 88 {
Jamie Smith 0:0c3532738887 89 spi.format(8, SPI_MODE);
Jamie Smith 0:0c3532738887 90 spi.frequency(SPI_FREQ);
Jamie Smith 0:0c3532738887 91 }
Jamie Smith 0:0c3532738887 92
Jamie Smith 0:0c3532738887 93 bool CC1200::begin()
Jamie Smith 0:0c3532738887 94 {
Jamie Smith 0:0c3532738887 95 chipReady = false;
Jamie Smith 0:0c3532738887 96
Jamie Smith 0:0c3532738887 97 // reset
Jamie Smith 0:0c3532738887 98 rst.write(0);
Jamie Smith 0:0c3532738887 99 wait_us(100);
Jamie Smith 0:0c3532738887 100 rst.write(1);
Jamie Smith 0:0c3532738887 101
Jamie Smith 2:2a447e8e50b8 102 const auto resetTimeout = 10ms;
Jamie Smith 0:0c3532738887 103 Timer timeoutTimer;
Jamie Smith 0:0c3532738887 104 timeoutTimer.start();
Jamie Smith 0:0c3532738887 105
Jamie Smith 0:0c3532738887 106 while(!chipReady)
Jamie Smith 0:0c3532738887 107 {
Jamie Smith 0:0c3532738887 108 // datasheet specifies 240us reset time
Jamie Smith 0:0c3532738887 109 wait_us(250);
Jamie Smith 0:0c3532738887 110 updateState();
Jamie Smith 0:0c3532738887 111
Jamie Smith 2:2a447e8e50b8 112 if(timeoutTimer.elapsed_time() > resetTimeout)
Jamie Smith 0:0c3532738887 113 {
Jamie Smith 0:0c3532738887 114 debugStream->printf("Timeout waiting for ready response from CC1200\n");
Jamie Smith 5:d22a8885800b 115 break;
Jamie Smith 0:0c3532738887 116 }
Jamie Smith 0:0c3532738887 117 }
Jamie Smith 0:0c3532738887 118
Jamie Smith 0:0c3532738887 119 // read ID register
Jamie Smith 0:0c3532738887 120 uint8_t partNumber = readRegister(ExtRegister::PARTNUMBER);
Jamie Smith 0:0c3532738887 121 uint8_t partVersion = readRegister(ExtRegister::PARTVERSION);
Jamie Smith 0:0c3532738887 122
Jamie Smith 0:0c3532738887 123 uint8_t expectedPartNumber = isCC1201 ? CC1201_PART_NUMBER : CC1200_PART_NUMBER;
Jamie Smith 0:0c3532738887 124 if(partNumber != expectedPartNumber)
Jamie Smith 0:0c3532738887 125 {
Jamie Smith 0:0c3532738887 126 debugStream->printf("Read incorrect part number 0x%" PRIx8 " from CC1200, expected 0x%" PRIx8 "\n", partNumber, expectedPartNumber);
Jamie Smith 0:0c3532738887 127 return false;
Jamie Smith 0:0c3532738887 128 }
Jamie Smith 0:0c3532738887 129
Jamie Smith 0:0c3532738887 130 #if CC1200_DEBUG
Jamie Smith 0:0c3532738887 131 debugStream->printf("Detected CC1200, Part Number 0x%" PRIx8 ", Hardware Version %" PRIx8 "\n", partNumber, partVersion);
Jamie Smith 0:0c3532738887 132 #endif
Jamie Smith 0:0c3532738887 133
Jamie Smith 0:0c3532738887 134
Jamie Smith 0:0c3532738887 135 // Set packet format settings for this driver
Jamie Smith 0:0c3532738887 136 // ------------------------------------------------------------------------
Jamie Smith 0:0c3532738887 137
Jamie Smith 0:0c3532738887 138 // enable CRC but disable status bytes
Jamie Smith 0:0c3532738887 139 writeRegister(Register::PKT_CFG1, (0b01 << PKT_CFG1_CRC_CFG));
Jamie Smith 0:0c3532738887 140
Jamie Smith 0:0c3532738887 141 return true;
Jamie Smith 0:0c3532738887 142 }
Jamie Smith 0:0c3532738887 143
Jamie Smith 0:0c3532738887 144 size_t CC1200::getTXFIFOLen()
Jamie Smith 0:0c3532738887 145 {
Jamie Smith 0:0c3532738887 146 return readRegister(ExtRegister::NUM_TXBYTES);
Jamie Smith 0:0c3532738887 147 }
Jamie Smith 0:0c3532738887 148
Jamie Smith 0:0c3532738887 149 size_t CC1200::getRXFIFOLen()
Jamie Smith 0:0c3532738887 150 {
Jamie Smith 0:0c3532738887 151 return readRegister(ExtRegister::NUM_RXBYTES);
Jamie Smith 0:0c3532738887 152 }
Jamie Smith 0:0c3532738887 153
Jamie Smith 0:0c3532738887 154 bool CC1200::enqueuePacket(char const * data, size_t len)
Jamie Smith 0:0c3532738887 155 {
Jamie Smith 0:0c3532738887 156 uint8_t totalLength = len + 1; // add one byte for length byte
Jamie Smith 0:0c3532738887 157
Jamie Smith 0:0c3532738887 158 if(totalLength > MAX_PACKET_LENGTH)
Jamie Smith 0:0c3532738887 159 {
Jamie Smith 0:0c3532738887 160 // packet too big
Jamie Smith 0:0c3532738887 161 return false;
Jamie Smith 0:0c3532738887 162 }
Jamie Smith 0:0c3532738887 163
Jamie Smith 0:0c3532738887 164 uint8_t txFreeBytes = CC1200_FIFO_SIZE - getTXFIFOLen();
Jamie Smith 0:0c3532738887 165 if(totalLength > txFreeBytes)
Jamie Smith 0:0c3532738887 166 {
Jamie Smith 0:0c3532738887 167 // packet doesn't fit in TX FIFO
Jamie Smith 0:0c3532738887 168 return false;
Jamie Smith 0:0c3532738887 169 }
Jamie Smith 0:0c3532738887 170
Jamie Smith 0:0c3532738887 171 // burst write to TX FIFO
Jamie Smith 0:0c3532738887 172 spi.select();
Jamie Smith 0:0c3532738887 173 loadStatusByte(spi.write(CC1200_ENQUEUE_TX_FIFO | CC1200_BURST));
Jamie Smith 4:c609cc7c9ea7 174 if(_packetMode == PacketMode::VARIABLE_LENGTH)
Jamie Smith 4:c609cc7c9ea7 175 {
Jamie Smith 4:c609cc7c9ea7 176 spi.write(len);
Jamie Smith 4:c609cc7c9ea7 177 }
Jamie Smith 0:0c3532738887 178 for(size_t byteIndex = 0; byteIndex < len; ++byteIndex)
Jamie Smith 0:0c3532738887 179 {
Jamie Smith 0:0c3532738887 180 spi.write(data[byteIndex]);
Jamie Smith 0:0c3532738887 181 }
Jamie Smith 0:0c3532738887 182 spi.deselect();
Jamie Smith 0:0c3532738887 183
Jamie Smith 0:0c3532738887 184 #if CC1200_REGISTER_LEVEL_DEBUG
Jamie Smith 4:c609cc7c9ea7 185 debugStream->printf("Wrote packet of data length %zu:", len);
Jamie Smith 4:c609cc7c9ea7 186 if(_packetMode == PacketMode::VARIABLE_LENGTH)
Jamie Smith 4:c609cc7c9ea7 187 {
Jamie Smith 4:c609cc7c9ea7 188 debugStream->printf(" %02" PRIx8, static_cast<uint8_t>(len));
Jamie Smith 4:c609cc7c9ea7 189 }
Jamie Smith 0:0c3532738887 190 for(size_t byteIndex = 0; byteIndex < len; ++byteIndex)
Jamie Smith 0:0c3532738887 191 {
Jamie Smith 4:c609cc7c9ea7 192 debugStream->printf(" %02" PRIx8, data[byteIndex]);
Jamie Smith 0:0c3532738887 193 }
Jamie Smith 0:0c3532738887 194 debugStream->printf("\n");
Jamie Smith 0:0c3532738887 195 #endif
Jamie Smith 0:0c3532738887 196 return true;
Jamie Smith 0:0c3532738887 197 }
Jamie Smith 0:0c3532738887 198
Jamie Smith 0:0c3532738887 199 bool CC1200::hasReceivedPacket()
Jamie Smith 0:0c3532738887 200 {
Jamie Smith 0:0c3532738887 201 size_t bytesReceived = getRXFIFOLen();
Jamie Smith 0:0c3532738887 202
Jamie Smith 0:0c3532738887 203 if(bytesReceived < 1)
Jamie Smith 0:0c3532738887 204 {
Jamie Smith 0:0c3532738887 205 // no bytes at all, can't check the length
Jamie Smith 0:0c3532738887 206 return false;
Jamie Smith 0:0c3532738887 207 }
Jamie Smith 0:0c3532738887 208
Jamie Smith 4:c609cc7c9ea7 209 if(_packetMode == PacketMode::FIXED_LENGTH)
Jamie Smith 4:c609cc7c9ea7 210 {
Jamie Smith 5:d22a8885800b 211 return bytesReceived >= _packetTotalLength + (appendStatusEnabled ? PACKET_STATUS_LEN : 0);
Jamie Smith 5:d22a8885800b 212 }
Jamie Smith 5:d22a8885800b 213 else if(_packetMode == PacketMode::INFINITE_LENGTH)
Jamie Smith 5:d22a8885800b 214 {
Jamie Smith 5:d22a8885800b 215 // Any amount of bytes constitutes a packet.
Jamie Smith 5:d22a8885800b 216 return bytesReceived > 0;
Jamie Smith 4:c609cc7c9ea7 217 }
Jamie Smith 4:c609cc7c9ea7 218 else // _packetMode == PacketMode::VARIABLE_LENGTH
Jamie Smith 4:c609cc7c9ea7 219 {
Jamie Smith 4:c609cc7c9ea7 220 // get value of first byte of the packet, which is the length.
Jamie Smith 2:2a447e8e50b8 221
Jamie Smith 4:c609cc7c9ea7 222 // The datasheet is wrong about this! It says that the first byte in the RX FIFO can
Jamie Smith 4:c609cc7c9ea7 223 // be found by accessing address RXFIRST via direct fifo access.
Jamie Smith 4:c609cc7c9ea7 224 // However, in my own testing, RXFIRST points to the second entry in the FIFO, and
Jamie Smith 4:c609cc7c9ea7 225 // the first entry must be accessed through RXFIFO_PRE_BUF.
Jamie Smith 4:c609cc7c9ea7 226 uint8_t packetLen = readRegister(ExtRegister::RXFIFO_PRE_BUF);
Jamie Smith 0:0c3532738887 227
Jamie Smith 4:c609cc7c9ea7 228 // if we have received a full packet's worth of bytes, then we have received a full packet.
Jamie Smith 5:d22a8885800b 229 return bytesReceived >= static_cast<size_t>(packetLen + 1 /* Add one because length field does not include itself */) + (appendStatusEnabled ? PACKET_STATUS_LEN : 0);
Jamie Smith 4:c609cc7c9ea7 230 }
Jamie Smith 0:0c3532738887 231 }
Jamie Smith 0:0c3532738887 232
Jamie Smith 0:0c3532738887 233 size_t CC1200::receivePacket(char *buffer, size_t bufferLen)
Jamie Smith 0:0c3532738887 234 {
Jamie Smith 0:0c3532738887 235 // burst read from RX FIFO
Jamie Smith 0:0c3532738887 236 spi.select();
Jamie Smith 0:0c3532738887 237 loadStatusByte(spi.write(CC1200_DEQUEUE_RX_FIFO | CC1200_BURST));
Jamie Smith 0:0c3532738887 238
Jamie Smith 4:c609cc7c9ea7 239 uint8_t dataLen;
Jamie Smith 4:c609cc7c9ea7 240 if(_packetMode == PacketMode::VARIABLE_LENGTH)
Jamie Smith 4:c609cc7c9ea7 241 {
Jamie Smith 4:c609cc7c9ea7 242 // first read length byte
Jamie Smith 4:c609cc7c9ea7 243 dataLen = spi.write(0);
Jamie Smith 4:c609cc7c9ea7 244 }
Jamie Smith 4:c609cc7c9ea7 245 else // _packetMode == PacketMode::FIXED_LENGTH)
Jamie Smith 4:c609cc7c9ea7 246 {
Jamie Smith 4:c609cc7c9ea7 247 dataLen = _packetTotalLength;
Jamie Smith 4:c609cc7c9ea7 248 }
Jamie Smith 0:0c3532738887 249
Jamie Smith 0:0c3532738887 250 for(size_t byteIndex = 0; byteIndex < dataLen; ++byteIndex)
Jamie Smith 0:0c3532738887 251 {
Jamie Smith 0:0c3532738887 252 uint8_t currByte = spi.write(0);
Jamie Smith 0:0c3532738887 253 if(byteIndex < bufferLen)
Jamie Smith 0:0c3532738887 254 {
Jamie Smith 0:0c3532738887 255 buffer[byteIndex] = currByte;
Jamie Smith 0:0c3532738887 256 }
Jamie Smith 0:0c3532738887 257 }
Jamie Smith 5:d22a8885800b 258
Jamie Smith 5:d22a8885800b 259 if(appendStatusEnabled)
Jamie Smith 5:d22a8885800b 260 {
Jamie Smith 5:d22a8885800b 261 uint8_t statusBytes[PACKET_STATUS_LEN];
Jamie Smith 5:d22a8885800b 262 for(size_t byteIndex = 0; byteIndex < PACKET_STATUS_LEN; ++byteIndex)
Jamie Smith 5:d22a8885800b 263 {
Jamie Smith 5:d22a8885800b 264 statusBytes[byteIndex] = spi.write(0);
Jamie Smith 5:d22a8885800b 265 }
Jamie Smith 5:d22a8885800b 266
Jamie Smith 5:d22a8885800b 267 lastRSSI = statusBytes[0];
Jamie Smith 5:d22a8885800b 268 lastLQI = statusBytes[1] & 0b01111111;
Jamie Smith 5:d22a8885800b 269 }
Jamie Smith 5:d22a8885800b 270
Jamie Smith 0:0c3532738887 271 spi.deselect();
Jamie Smith 0:0c3532738887 272
Jamie Smith 0:0c3532738887 273 #if CC1200_REGISTER_LEVEL_DEBUG
Jamie Smith 0:0c3532738887 274 debugStream->printf("Read packet of data length %" PRIu8 ": %" PRIx8, dataLen, static_cast<uint8_t>(dataLen));
Jamie Smith 0:0c3532738887 275 for(size_t byteIndex = 0; byteIndex < dataLen; ++byteIndex)
Jamie Smith 0:0c3532738887 276 {
Jamie Smith 0:0c3532738887 277 debugStream->printf(" %" PRIx8, buffer[byteIndex]);
Jamie Smith 0:0c3532738887 278 }
Jamie Smith 0:0c3532738887 279 debugStream->printf("\n");
Jamie Smith 0:0c3532738887 280 #endif
Jamie Smith 0:0c3532738887 281
Jamie Smith 0:0c3532738887 282 return dataLen;
Jamie Smith 0:0c3532738887 283 }
Jamie Smith 0:0c3532738887 284
Jamie Smith 5:d22a8885800b 285 size_t CC1200::writeStream(const char *buffer, size_t count)
Jamie Smith 5:d22a8885800b 286 {
Jamie Smith 5:d22a8885800b 287 size_t freeBytes = CC1200_FIFO_SIZE - getTXFIFOLen();
Jamie Smith 5:d22a8885800b 288
Jamie Smith 5:d22a8885800b 289 /*if(state == State::TX)
Jamie Smith 5:d22a8885800b 290 {
Jamie Smith 5:d22a8885800b 291 if(freeBytes > 0)
Jamie Smith 5:d22a8885800b 292 {
Jamie Smith 5:d22a8885800b 293 freeBytes--;
Jamie Smith 5:d22a8885800b 294 }
Jamie Smith 5:d22a8885800b 295 }*/
Jamie Smith 5:d22a8885800b 296
Jamie Smith 5:d22a8885800b 297 size_t bytesToWrite = std::min(freeBytes, count);
Jamie Smith 5:d22a8885800b 298
Jamie Smith 5:d22a8885800b 299 if(bytesToWrite == 0)
Jamie Smith 5:d22a8885800b 300 {
Jamie Smith 5:d22a8885800b 301 return 0;
Jamie Smith 5:d22a8885800b 302 }
Jamie Smith 5:d22a8885800b 303
Jamie Smith 5:d22a8885800b 304 spi.select();
Jamie Smith 5:d22a8885800b 305 loadStatusByte(spi.write(CC1200_ENQUEUE_TX_FIFO | CC1200_BURST));
Jamie Smith 5:d22a8885800b 306 for(size_t byteIndex = 0; byteIndex < bytesToWrite; ++byteIndex)
Jamie Smith 5:d22a8885800b 307 {
Jamie Smith 5:d22a8885800b 308 spi.write(buffer[byteIndex]);
Jamie Smith 5:d22a8885800b 309 }
Jamie Smith 5:d22a8885800b 310 spi.deselect();
Jamie Smith 5:d22a8885800b 311
Jamie Smith 5:d22a8885800b 312 #if CC1200_REGISTER_LEVEL_DEBUG
Jamie Smith 5:d22a8885800b 313 debugStream->printf("%zu bytes were free, wrote stream of data length %zu:", freeBytes, bytesToWrite);
Jamie Smith 5:d22a8885800b 314 for(size_t byteIndex = 0; byteIndex < bytesToWrite; ++byteIndex)
Jamie Smith 5:d22a8885800b 315 {
Jamie Smith 5:d22a8885800b 316 debugStream->printf(" %02" PRIx8, buffer[byteIndex]);
Jamie Smith 5:d22a8885800b 317 }
Jamie Smith 5:d22a8885800b 318 debugStream->printf("\n");
Jamie Smith 5:d22a8885800b 319 #endif
Jamie Smith 5:d22a8885800b 320
Jamie Smith 5:d22a8885800b 321 return bytesToWrite;
Jamie Smith 5:d22a8885800b 322 }
Jamie Smith 5:d22a8885800b 323
Jamie Smith 5:d22a8885800b 324 bool CC1200::writeStreamBlocking(const char *buffer, size_t count)
Jamie Smith 5:d22a8885800b 325 {
Jamie Smith 5:d22a8885800b 326 //size_t origCount = count;
Jamie Smith 5:d22a8885800b 327 size_t bufferOffset = 0;
Jamie Smith 5:d22a8885800b 328 while(state == State::TX && count > 0)
Jamie Smith 5:d22a8885800b 329 {
Jamie Smith 5:d22a8885800b 330 size_t bytesWritten = writeStream(buffer + bufferOffset, count);
Jamie Smith 5:d22a8885800b 331 count -= bytesWritten;
Jamie Smith 5:d22a8885800b 332 bufferOffset += bytesWritten;
Jamie Smith 5:d22a8885800b 333 }
Jamie Smith 5:d22a8885800b 334
Jamie Smith 5:d22a8885800b 335 //debugStream->printf("Read stream of data length %zu\n:", origCount);
Jamie Smith 5:d22a8885800b 336
Jamie Smith 5:d22a8885800b 337 return count == 0;
Jamie Smith 5:d22a8885800b 338 }
Jamie Smith 5:d22a8885800b 339
Jamie Smith 5:d22a8885800b 340 size_t CC1200::readStream(char *buffer, size_t maxLen)
Jamie Smith 5:d22a8885800b 341 {
Jamie Smith 5:d22a8885800b 342 size_t bytesToRead = std::min(maxLen, getRXFIFOLen());
Jamie Smith 5:d22a8885800b 343 if(bytesToRead == 0)
Jamie Smith 5:d22a8885800b 344 {
Jamie Smith 5:d22a8885800b 345 return 0;
Jamie Smith 5:d22a8885800b 346 }
Jamie Smith 5:d22a8885800b 347
Jamie Smith 5:d22a8885800b 348 // burst read from RX FIFO
Jamie Smith 5:d22a8885800b 349 spi.select();
Jamie Smith 5:d22a8885800b 350 loadStatusByte(spi.write(CC1200_DEQUEUE_RX_FIFO | CC1200_BURST));
Jamie Smith 5:d22a8885800b 351 for(size_t byteIndex = 0; byteIndex < bytesToRead; ++byteIndex)
Jamie Smith 5:d22a8885800b 352 {
Jamie Smith 5:d22a8885800b 353 buffer[byteIndex] = spi.write(0);
Jamie Smith 5:d22a8885800b 354 }
Jamie Smith 5:d22a8885800b 355 spi.deselect();
Jamie Smith 5:d22a8885800b 356
Jamie Smith 5:d22a8885800b 357 #if CC1200_REGISTER_LEVEL_DEBUG
Jamie Smith 5:d22a8885800b 358 debugStream->printf("Read stream of data length %zu:", bytesToRead);
Jamie Smith 5:d22a8885800b 359 for(size_t byteIndex = 0; byteIndex < bytesToRead; ++byteIndex)
Jamie Smith 5:d22a8885800b 360 {
Jamie Smith 5:d22a8885800b 361 debugStream->printf(" %" PRIx8, buffer[byteIndex]);
Jamie Smith 5:d22a8885800b 362 }
Jamie Smith 5:d22a8885800b 363 debugStream->printf("\n");
Jamie Smith 5:d22a8885800b 364 #endif
Jamie Smith 5:d22a8885800b 365
Jamie Smith 5:d22a8885800b 366 return bytesToRead;
Jamie Smith 5:d22a8885800b 367 }
Jamie Smith 5:d22a8885800b 368
Jamie Smith 5:d22a8885800b 369 bool CC1200::readStreamBlocking(char *buffer, size_t count, std::chrono::microseconds timeout)
Jamie Smith 5:d22a8885800b 370 {
Jamie Smith 5:d22a8885800b 371 //size_t origCount = count;
Jamie Smith 5:d22a8885800b 372 Timer timeoutTimer;
Jamie Smith 5:d22a8885800b 373
Jamie Smith 5:d22a8885800b 374 if(timeout > 0us)
Jamie Smith 5:d22a8885800b 375 {
Jamie Smith 5:d22a8885800b 376 timeoutTimer.start();
Jamie Smith 5:d22a8885800b 377 }
Jamie Smith 5:d22a8885800b 378
Jamie Smith 5:d22a8885800b 379 size_t bufferOffset = 0;
Jamie Smith 5:d22a8885800b 380 while((timeoutTimer.elapsed_time() < timeout || timeout == 0us) && state == State::RX && count > 0)
Jamie Smith 5:d22a8885800b 381 {
Jamie Smith 5:d22a8885800b 382 size_t bytesRead = readStream(buffer + bufferOffset, count);
Jamie Smith 5:d22a8885800b 383 count -= bytesRead;
Jamie Smith 5:d22a8885800b 384 bufferOffset += bytesRead;
Jamie Smith 5:d22a8885800b 385 }
Jamie Smith 5:d22a8885800b 386
Jamie Smith 5:d22a8885800b 387 //debugStream->printf("Read stream of data length %zu, first %" PRIx8 " last %" PRIx8 "\n:", origCount,
Jamie Smith 5:d22a8885800b 388 // buffer[0], buffer[origCount - 1]);
Jamie Smith 5:d22a8885800b 389
Jamie Smith 5:d22a8885800b 390 return count == 0;
Jamie Smith 5:d22a8885800b 391 }
Jamie Smith 5:d22a8885800b 392
Jamie Smith 5:d22a8885800b 393
Jamie Smith 0:0c3532738887 394 // helper function: convert a state to the bits for RXOFF_MODE and TXOFF_MODE
Jamie Smith 0:0c3532738887 395 inline uint8_t getOffModeBits(CC1200::State state)
Jamie Smith 0:0c3532738887 396 {
Jamie Smith 0:0c3532738887 397 uint8_t offBits = 0b0;
Jamie Smith 0:0c3532738887 398 if(state == CC1200::State::IDLE)
Jamie Smith 0:0c3532738887 399 {
Jamie Smith 0:0c3532738887 400 offBits = 0b0;
Jamie Smith 0:0c3532738887 401 }
Jamie Smith 0:0c3532738887 402 else if(state == CC1200::State::FAST_ON)
Jamie Smith 0:0c3532738887 403 {
Jamie Smith 0:0c3532738887 404 offBits = 0b1;
Jamie Smith 0:0c3532738887 405 }
Jamie Smith 0:0c3532738887 406 else if(state == CC1200::State::TX)
Jamie Smith 0:0c3532738887 407 {
Jamie Smith 0:0c3532738887 408 offBits = 0b10;
Jamie Smith 0:0c3532738887 409 }
Jamie Smith 0:0c3532738887 410 else if(state == CC1200::State::RX)
Jamie Smith 0:0c3532738887 411 {
Jamie Smith 0:0c3532738887 412 offBits = 0b11;
Jamie Smith 0:0c3532738887 413 }
Jamie Smith 0:0c3532738887 414 return offBits;
Jamie Smith 0:0c3532738887 415 }
Jamie Smith 0:0c3532738887 416
Jamie Smith 0:0c3532738887 417 void CC1200::setOnReceiveState(CC1200::State goodPacket, CC1200::State badPacket)
Jamie Smith 0:0c3532738887 418 {
Jamie Smith 0:0c3532738887 419 // configure good packet action via RXOFF_MODE
Jamie Smith 0:0c3532738887 420 uint8_t rfendCfg1 = readRegister(Register::RFEND_CFG1);
Jamie Smith 0:0c3532738887 421 rfendCfg1 &= ~(0b11 << RFEND_CFG1_RXOFF_MODE);
Jamie Smith 0:0c3532738887 422 rfendCfg1 |= getOffModeBits(goodPacket) << RFEND_CFG1_RXOFF_MODE;
Jamie Smith 0:0c3532738887 423 writeRegister(Register::RFEND_CFG1, rfendCfg1);
Jamie Smith 0:0c3532738887 424
Jamie Smith 0:0c3532738887 425 // configure bad packet action via TERM_ON_BAD_PACKET_EN
Jamie Smith 0:0c3532738887 426 uint8_t rfendCfg0 = readRegister(Register::RFEND_CFG0);
Jamie Smith 0:0c3532738887 427 if(badPacket == State::RX)
Jamie Smith 0:0c3532738887 428 {
Jamie Smith 0:0c3532738887 429 rfendCfg0 &= ~(1 << RFEND_CFG0_TERM_ON_BAD_PACKET_EN);
Jamie Smith 0:0c3532738887 430 }
Jamie Smith 0:0c3532738887 431 else
Jamie Smith 0:0c3532738887 432 {
Jamie Smith 0:0c3532738887 433 rfendCfg0 |= 1 << RFEND_CFG1_RXOFF_MODE;
Jamie Smith 0:0c3532738887 434 }
Jamie Smith 0:0c3532738887 435 writeRegister(Register::RFEND_CFG0, rfendCfg0);
Jamie Smith 0:0c3532738887 436 }
Jamie Smith 0:0c3532738887 437
Jamie Smith 1:98af824b145e 438 void CC1200::setOnTransmitState(CC1200::State txState)
Jamie Smith 0:0c3532738887 439 {
Jamie Smith 0:0c3532738887 440 uint8_t rfendCfg0 = readRegister(Register::RFEND_CFG0);
Jamie Smith 0:0c3532738887 441 rfendCfg0 &= ~(0b11 << RFEND_CFG0_TXOFF_MODE);
Jamie Smith 1:98af824b145e 442 rfendCfg0 |= getOffModeBits(txState) << RFEND_CFG0_TXOFF_MODE;
Jamie Smith 0:0c3532738887 443 writeRegister(Register::RFEND_CFG0, rfendCfg0);
Jamie Smith 0:0c3532738887 444 }
Jamie Smith 0:0c3532738887 445
Jamie Smith 0:0c3532738887 446 void CC1200::setFSCalMode(FSCalMode mode)
Jamie Smith 0:0c3532738887 447 {
Jamie Smith 0:0c3532738887 448 uint8_t settlingCfg = readRegister(Register::SETTLING_CFG);
Jamie Smith 0:0c3532738887 449 settlingCfg &= ~(0b11 << SETTLING_CFG_FS_AUTOCAL);
Jamie Smith 0:0c3532738887 450 settlingCfg |= static_cast<uint8_t>(mode) << SETTLING_CFG_FS_AUTOCAL;
Jamie Smith 0:0c3532738887 451 writeRegister(Register::SETTLING_CFG, settlingCfg);
Jamie Smith 0:0c3532738887 452 }
Jamie Smith 0:0c3532738887 453
Jamie Smith 0:0c3532738887 454 void CC1200::configureGPIO(uint8_t gpioNumber, CC1200::GPIOMode mode, bool outputInvert)
Jamie Smith 0:0c3532738887 455 {
Jamie Smith 0:0c3532738887 456 // gpio 3 is the first register, then it goes down to 0
Jamie Smith 0:0c3532738887 457 Register gpioReg = static_cast<Register>(static_cast<uint8_t>(Register::IOCFG3) + (3 - gpioNumber));
Jamie Smith 0:0c3532738887 458
Jamie Smith 0:0c3532738887 459 uint8_t gpioCfgVal = static_cast<uint8_t>(mode);
Jamie Smith 0:0c3532738887 460 if(outputInvert)
Jamie Smith 0:0c3532738887 461 {
Jamie Smith 0:0c3532738887 462 gpioCfgVal |= (1 << GPIO_INV);
Jamie Smith 0:0c3532738887 463 }
Jamie Smith 0:0c3532738887 464 writeRegister(gpioReg, gpioCfgVal);
Jamie Smith 0:0c3532738887 465 }
Jamie Smith 0:0c3532738887 466
Jamie Smith 0:0c3532738887 467 void CC1200::configureFIFOMode()
Jamie Smith 0:0c3532738887 468 {
Jamie Smith 0:0c3532738887 469 // configure packet format
Jamie Smith 0:0c3532738887 470 uint8_t pktCfg2 = readRegister(Register::PKT_CFG2);
Jamie Smith 0:0c3532738887 471 pktCfg2 &= ~(0b11 << PKT_CFG2_PKT_FORMAT);
Jamie Smith 0:0c3532738887 472 writeRegister(Register::PKT_CFG2, pktCfg2);
Jamie Smith 0:0c3532738887 473
Jamie Smith 0:0c3532738887 474 // enable fifo
Jamie Smith 0:0c3532738887 475 uint8_t mdmCfg1 = readRegister(Register::MDMCFG1);
Jamie Smith 0:0c3532738887 476 mdmCfg1 |= 1 << MDMCFG1_FIFO_EN;
Jamie Smith 0:0c3532738887 477 writeRegister(Register::MDMCFG1, mdmCfg1);
Jamie Smith 0:0c3532738887 478
Jamie Smith 0:0c3532738887 479 // make sure transparent mode is disabled
Jamie Smith 0:0c3532738887 480 uint8_t mdmCfg0 = readRegister(Register::MDMCFG0);
Jamie Smith 0:0c3532738887 481 mdmCfg0 &= ~(1 << MDMCFG0_TRANSPARENT_MODE_EN);
Jamie Smith 0:0c3532738887 482 writeRegister(Register::MDMCFG0, mdmCfg0);
Jamie Smith 0:0c3532738887 483 }
Jamie Smith 0:0c3532738887 484
Jamie Smith 5:d22a8885800b 485 void CC1200::setPacketMode(PacketMode mode, bool appendStatus)
Jamie Smith 4:c609cc7c9ea7 486 {
Jamie Smith 4:c609cc7c9ea7 487 _packetMode = mode;
Jamie Smith 4:c609cc7c9ea7 488
Jamie Smith 4:c609cc7c9ea7 489 uint8_t pktCfg0 = readRegister(Register::PKT_CFG0);
Jamie Smith 4:c609cc7c9ea7 490 // set length config field
Jamie Smith 4:c609cc7c9ea7 491 pktCfg0 &= ~(0b11 << PKT_CFG0_LENGTH_CONFIG);
Jamie Smith 4:c609cc7c9ea7 492 pktCfg0 |= static_cast<uint8_t>(mode) << PKT_CFG0_LENGTH_CONFIG;
Jamie Smith 4:c609cc7c9ea7 493 writeRegister(Register::PKT_CFG0, pktCfg0);
Jamie Smith 4:c609cc7c9ea7 494
Jamie Smith 4:c609cc7c9ea7 495 if(mode == PacketMode::VARIABLE_LENGTH)
Jamie Smith 4:c609cc7c9ea7 496 {
Jamie Smith 4:c609cc7c9ea7 497 // disable packet length limit
Jamie Smith 4:c609cc7c9ea7 498 writeRegister(Register::PKT_LEN, MAX_PACKET_LENGTH);
Jamie Smith 4:c609cc7c9ea7 499 }
Jamie Smith 5:d22a8885800b 500 else if(mode == PacketMode::FIXED_LENGTH)
Jamie Smith 4:c609cc7c9ea7 501 {
Jamie Smith 4:c609cc7c9ea7 502 // reset to selected fixed lengths
Jamie Smith 4:c609cc7c9ea7 503 setPacketLength(_packetByteLength, _packetBitLength);
Jamie Smith 4:c609cc7c9ea7 504 }
Jamie Smith 5:d22a8885800b 505 else
Jamie Smith 5:d22a8885800b 506 {
Jamie Smith 5:d22a8885800b 507 // Infinite length packets, PKT_LEN register is a don't care.
Jamie Smith 5:d22a8885800b 508 }
Jamie Smith 5:d22a8885800b 509
Jamie Smith 5:d22a8885800b 510 // set append status
Jamie Smith 5:d22a8885800b 511 appendStatusEnabled = appendStatus;
Jamie Smith 5:d22a8885800b 512 uint8_t pktCfg1 = readRegister(Register::PKT_CFG1);
Jamie Smith 5:d22a8885800b 513 if(appendStatus)
Jamie Smith 5:d22a8885800b 514 {
Jamie Smith 5:d22a8885800b 515 pktCfg1 |= 1 << PKT_CFG1_APPEND_STATUS;
Jamie Smith 5:d22a8885800b 516 }
Jamie Smith 5:d22a8885800b 517 else
Jamie Smith 5:d22a8885800b 518 {
Jamie Smith 5:d22a8885800b 519 pktCfg1 &= ~(1 << PKT_CFG1_APPEND_STATUS);
Jamie Smith 5:d22a8885800b 520 }
Jamie Smith 5:d22a8885800b 521 writeRegister(Register::PKT_CFG1, pktCfg1);
Jamie Smith 4:c609cc7c9ea7 522 }
Jamie Smith 4:c609cc7c9ea7 523
Jamie Smith 5:d22a8885800b 524 void CC1200::setPacketLength(uint16_t length, uint8_t bitLength)
Jamie Smith 4:c609cc7c9ea7 525 {
Jamie Smith 4:c609cc7c9ea7 526 _packetByteLength = length;
Jamie Smith 4:c609cc7c9ea7 527 _packetBitLength = bitLength;
Jamie Smith 4:c609cc7c9ea7 528 _packetTotalLength = _packetByteLength;
Jamie Smith 4:c609cc7c9ea7 529
Jamie Smith 4:c609cc7c9ea7 530 if(bitLength > 0)
Jamie Smith 4:c609cc7c9ea7 531 {
Jamie Smith 4:c609cc7c9ea7 532 // tell the driver to read the extra bits into another byte
Jamie Smith 4:c609cc7c9ea7 533 _packetTotalLength++;
Jamie Smith 4:c609cc7c9ea7 534 }
Jamie Smith 4:c609cc7c9ea7 535
Jamie Smith 5:d22a8885800b 536 if(_packetTotalLength == 256)
Jamie Smith 5:d22a8885800b 537 {
Jamie Smith 5:d22a8885800b 538 // Length byte of 0 indicates 256 bytes
Jamie Smith 5:d22a8885800b 539 writeRegister(Register::PKT_LEN, 0);
Jamie Smith 5:d22a8885800b 540 }
Jamie Smith 5:d22a8885800b 541 else
Jamie Smith 5:d22a8885800b 542 {
Jamie Smith 5:d22a8885800b 543 writeRegister(Register::PKT_LEN, _packetByteLength);
Jamie Smith 5:d22a8885800b 544 }
Jamie Smith 4:c609cc7c9ea7 545
Jamie Smith 4:c609cc7c9ea7 546 uint8_t pktCfg0 = readRegister(Register::PKT_CFG0);
Jamie Smith 4:c609cc7c9ea7 547 pktCfg0 &= ~(0b111 << PKT_CFG0_PKT_BIT_LEN);
Jamie Smith 4:c609cc7c9ea7 548 pktCfg0 |= _packetBitLength << PKT_CFG0_PKT_BIT_LEN;
Jamie Smith 4:c609cc7c9ea7 549 writeRegister(Register::PKT_CFG0, pktCfg0);
Jamie Smith 4:c609cc7c9ea7 550
Jamie Smith 4:c609cc7c9ea7 551 #if CC1200_DEBUG
Jamie Smith 4:c609cc7c9ea7 552 debugStream->printf("Set total length to %zu, byte length = %zu, bit length = %" PRIu8 "\n", _packetTotalLength, _packetByteLength, _packetBitLength);
Jamie Smith 4:c609cc7c9ea7 553 #endif
Jamie Smith 4:c609cc7c9ea7 554 }
Jamie Smith 4:c609cc7c9ea7 555
Jamie Smith 4:c609cc7c9ea7 556 void CC1200::setCRCEnabled(bool enabled)
Jamie Smith 4:c609cc7c9ea7 557 {
Jamie Smith 4:c609cc7c9ea7 558 uint8_t pktCfg1 = readRegister(Register::PKT_CFG1);
Jamie Smith 4:c609cc7c9ea7 559 pktCfg1 &= ~(0b11 << PKT_CFG1_CRC_CFG);
Jamie Smith 4:c609cc7c9ea7 560 pktCfg1 |= (enabled ? 0b01 : 0b00) << PKT_CFG1_CRC_CFG;
Jamie Smith 4:c609cc7c9ea7 561 writeRegister(Register::PKT_CFG1, pktCfg1);
Jamie Smith 4:c609cc7c9ea7 562 }
Jamie Smith 4:c609cc7c9ea7 563
Jamie Smith 0:0c3532738887 564 void CC1200::setModulationFormat(CC1200::ModFormat format)
Jamie Smith 0:0c3532738887 565 {
Jamie Smith 0:0c3532738887 566 uint8_t modcfgDevE = readRegister(Register::MODCFG_DEV_E);
Jamie Smith 0:0c3532738887 567 modcfgDevE &= ~(0b111 << MODCFG_DEV_E_MOD_FORMAT);
Jamie Smith 4:c609cc7c9ea7 568 modcfgDevE |= static_cast<uint8_t>(format) << MODCFG_DEV_E_MOD_FORMAT;
Jamie Smith 0:0c3532738887 569 writeRegister(Register::MODCFG_DEV_E, modcfgDevE);
Jamie Smith 0:0c3532738887 570 }
Jamie Smith 0:0c3532738887 571
Jamie Smith 0:0c3532738887 572 void CC1200::setFSKDeviation(float deviation)
Jamie Smith 0:0c3532738887 573 {
Jamie Smith 0:0c3532738887 574 // Deviation is set as two values, an exponent register from 0-3 and a mantissa register from 0-256.
Jamie Smith 0:0c3532738887 575 // See user guide page 81 for the original equation, this function was worked out from that
Jamie Smith 0:0c3532738887 576
Jamie Smith 0:0c3532738887 577 // First assume mantissa is zero and calculate the needed exponent
Jamie Smith 0:0c3532738887 578 float exactExponent = std::log2(deviation) - CC1200_OSC_FREQ_LOG2 + 14;
Jamie Smith 0:0c3532738887 579 uint8_t actualExponent = static_cast<uint8_t>(std::min(static_cast<float>(maxValue3Bits), exactExponent));
Jamie Smith 0:0c3532738887 580 // note: 14 comes from log2(2^22) - log2(256)
Jamie Smith 0:0c3532738887 581
Jamie Smith 0:0c3532738887 582 float exactMantissa;
Jamie Smith 0:0c3532738887 583 if(actualExponent >= 1)
Jamie Smith 0:0c3532738887 584 {
Jamie Smith 0:0c3532738887 585 exactMantissa = (std::pow(2.0f, static_cast<float>(22 - actualExponent)) * deviation)
Jamie Smith 0:0c3532738887 586 / CC1200_OSC_FREQ - 256;
Jamie Smith 0:0c3532738887 587 }
Jamie Smith 0:0c3532738887 588 else
Jamie Smith 0:0c3532738887 589 {
Jamie Smith 0:0c3532738887 590 // use alternate high-resolution formula for case where exponent = 0
Jamie Smith 0:0c3532738887 591 exactMantissa = deviation * twoToThe21 / CC1200_OSC_FREQ;
Jamie Smith 0:0c3532738887 592 }
Jamie Smith 0:0c3532738887 593
Jamie Smith 0:0c3532738887 594 // now calculate closest mantissa
Jamie Smith 0:0c3532738887 595 uint8_t actualMantissa = static_cast<uint8_t>(std::min(static_cast<float>(maxValue8Bits), exactMantissa));
Jamie Smith 0:0c3532738887 596
Jamie Smith 0:0c3532738887 597 // set exponent and mantissa
Jamie Smith 0:0c3532738887 598 writeRegister(Register::DEVIATION_M, actualMantissa);
Jamie Smith 0:0c3532738887 599
Jamie Smith 0:0c3532738887 600 uint8_t modcfgDevE = readRegister(Register::MODCFG_DEV_E);
Jamie Smith 0:0c3532738887 601 modcfgDevE &= ~(0b111 << MODCFG_DEV_E_DEV_E);
Jamie Smith 0:0c3532738887 602 modcfgDevE |= actualExponent << MODCFG_DEV_E_DEV_E;
Jamie Smith 0:0c3532738887 603 writeRegister(Register::MODCFG_DEV_E, modcfgDevE);
Jamie Smith 0:0c3532738887 604
Jamie Smith 0:0c3532738887 605 #if CC1200_DEBUG
Jamie Smith 0:0c3532738887 606 debugStream->printf("Setting FSK deviation, requested +-%.00f Hz, setting DEV_E = 0x%" PRIx8 " DEV_M = 0x%" PRIx8 "\n",
Jamie Smith 0:0c3532738887 607 deviation, actualExponent, actualMantissa);
Jamie Smith 0:0c3532738887 608
Jamie Smith 0:0c3532738887 609 float actualDeviation;
Jamie Smith 0:0c3532738887 610 if(actualExponent == 0)
Jamie Smith 0:0c3532738887 611 {
Jamie Smith 0:0c3532738887 612 actualDeviation = CC1200_OSC_FREQ * actualMantissa / twoToThe21;
Jamie Smith 0:0c3532738887 613 }
Jamie Smith 0:0c3532738887 614 else
Jamie Smith 0:0c3532738887 615 {
Jamie Smith 0:0c3532738887 616 actualDeviation = (CC1200_OSC_FREQ / twoToThe22) * (256.0f + static_cast<float>(actualMantissa)) * pow(2.0f, static_cast<float>(actualExponent));
Jamie Smith 0:0c3532738887 617 }
Jamie Smith 0:0c3532738887 618 // sanity check: calculate actual deviation
Jamie Smith 0:0c3532738887 619 debugStream->printf("This yields an actual deviation of +-%.00f Hz\n", actualDeviation);
Jamie Smith 0:0c3532738887 620 #endif
Jamie Smith 0:0c3532738887 621 }
Jamie Smith 0:0c3532738887 622
Jamie Smith 0:0c3532738887 623 void CC1200::setSymbolRate(float symbolRateHz)
Jamie Smith 0:0c3532738887 624 {
Jamie Smith 0:0c3532738887 625 // Datasheet says that the cc1200 works in ksps, but testing with SmartRF studio
Jamie Smith 0:0c3532738887 626 // shows that it actually is sps.
Jamie Smith 0:0c3532738887 627
Jamie Smith 0:0c3532738887 628 symbolRateSps = symbolRateHz;
Jamie Smith 0:0c3532738887 629
Jamie Smith 0:0c3532738887 630 // Note: these equations are given on page 29 of the user guide
Jamie Smith 0:0c3532738887 631
Jamie Smith 0:0c3532738887 632 float exactExponent = std::log2(symbolRateSps) - CC1200_OSC_FREQ_LOG2 + 19;
Jamie Smith 0:0c3532738887 633 // note: 19 comes from log2(2^39) - 20
Jamie Smith 0:0c3532738887 634 uint8_t actualExponent = static_cast<uint8_t>(std::min(static_cast<float>(maxValue4Bits), exactExponent));
Jamie Smith 0:0c3532738887 635
Jamie Smith 0:0c3532738887 636 float exactMantissa;
Jamie Smith 0:0c3532738887 637 if(actualExponent >= 1)
Jamie Smith 0:0c3532738887 638 {
Jamie Smith 0:0c3532738887 639 exactMantissa = (std::pow(2.0f, static_cast<float>(39 - actualExponent)) * symbolRateSps)
Jamie Smith 0:0c3532738887 640 / CC1200_OSC_FREQ - twoToThe20;
Jamie Smith 0:0c3532738887 641 }
Jamie Smith 0:0c3532738887 642 else
Jamie Smith 0:0c3532738887 643 {
Jamie Smith 0:0c3532738887 644 // use alternate high-resolution formula for case where exponent = 0
Jamie Smith 0:0c3532738887 645 exactMantissa = symbolRateSps * twoToThe38 / CC1200_OSC_FREQ;
Jamie Smith 0:0c3532738887 646 }
Jamie Smith 0:0c3532738887 647
Jamie Smith 0:0c3532738887 648 // mantissa is a 20 bit number, so restrict it to that domain
Jamie Smith 0:0c3532738887 649 uint32_t actualMantissa = static_cast<uint32_t>(std::min(static_cast<float>(maxValue20Bits), exactMantissa));
Jamie Smith 0:0c3532738887 650
Jamie Smith 0:0c3532738887 651 // program symbol rate registers
Jamie Smith 0:0c3532738887 652 std::array<uint8_t, 3> symbolRateRegisters ={
Jamie Smith 0:0c3532738887 653 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 654 static_cast<uint8_t>((actualMantissa >> 8) & 0xFF),
Jamie Smith 0:0c3532738887 655 static_cast<uint8_t>((actualMantissa & 0xFF))
Jamie Smith 0:0c3532738887 656 };
Jamie Smith 0:0c3532738887 657 writeRegisters(Register::SYMBOL_RATE2, symbolRateRegisters);
Jamie Smith 0:0c3532738887 658
Jamie Smith 4:c609cc7c9ea7 659 // Calculate upsampler value according to the formula in its register description
Jamie Smith 4:c609cc7c9ea7 660 float upsamplingFactor = CC1200_OSC_FREQ / (64 * symbolRateSps); // 2^upsamplerPVal needs to be less than this value
Jamie Smith 0:0c3532738887 661 uint8_t upsamplerPVal = std::floor(std::log2(upsamplingFactor));
Jamie Smith 0:0c3532738887 662
Jamie Smith 4:c609cc7c9ea7 663 // prevent low sampling rates from choosing a nonexistent upsampling
Jamie Smith 4:c609cc7c9ea7 664 upsamplerPVal = std::min<uint8_t>(upsamplerPVal, 0b110);
Jamie Smith 4:c609cc7c9ea7 665
Jamie Smith 0:0c3532738887 666 uint8_t mdmcfg2 = readRegister(ExtRegister::MDMCFG2);
Jamie Smith 0:0c3532738887 667 mdmcfg2 &= ~(0b111 << MDMCFG2_UPSAMPLER_P);
Jamie Smith 0:0c3532738887 668 mdmcfg2 |= (upsamplerPVal << MDMCFG2_UPSAMPLER_P);
Jamie Smith 0:0c3532738887 669
Jamie Smith 0:0c3532738887 670 writeRegister(ExtRegister::MDMCFG2, mdmcfg2);
Jamie Smith 0:0c3532738887 671
Jamie Smith 0:0c3532738887 672 #if CC1200_DEBUG
Jamie Smith 4:c609cc7c9ea7 673 debugStream->printf("Setting symbol rate, requested %.03f Hz, setting SRATE_E = 0x%" PRIx8 " SRATE_M = 0x%" PRIx32 "\n",
Jamie Smith 0:0c3532738887 674 symbolRateHz, actualExponent, actualMantissa);
Jamie Smith 0:0c3532738887 675
Jamie Smith 0:0c3532738887 676 // sanity check: calculate actual symbol rate
Jamie Smith 4:c609cc7c9ea7 677 float actualSymbolRateSps;
Jamie Smith 0:0c3532738887 678 if(actualExponent == 0)
Jamie Smith 0:0c3532738887 679 {
Jamie Smith 4:c609cc7c9ea7 680 actualSymbolRateSps = (static_cast<float>(actualMantissa) * CC1200_OSC_FREQ) / twoToThe38;
Jamie Smith 0:0c3532738887 681 }
Jamie Smith 0:0c3532738887 682 else
Jamie Smith 0:0c3532738887 683 {
Jamie Smith 0:0c3532738887 684
Jamie Smith 4:c609cc7c9ea7 685 actualSymbolRateSps = ((static_cast<float>(actualMantissa) + twoToThe20) *
Jamie Smith 4:c609cc7c9ea7 686 pow(2.0f,static_cast<float>(actualExponent)) * CC1200_OSC_FREQ)
Jamie Smith 4:c609cc7c9ea7 687 / twoToThe39;
Jamie Smith 0:0c3532738887 688 }
Jamie Smith 0:0c3532738887 689
Jamie Smith 4:c609cc7c9ea7 690 debugStream->printf("This yields an actual symbol rate of %.02f Hz\n", actualSymbolRateSps);
Jamie Smith 0:0c3532738887 691
Jamie Smith 0:0c3532738887 692 uint8_t actualUpsampling = static_cast<uint8_t>(pow(2.0f, static_cast<float>(upsamplerPVal)));
Jamie Smith 0:0c3532738887 693 debugStream->printf("Also setting upsampling factor to %" PRIu8 " via UPSAMPLER_P = %" PRIx8 "\n", actualUpsampling, upsamplerPVal);
Jamie Smith 0:0c3532738887 694 #endif
Jamie Smith 0:0c3532738887 695 }
Jamie Smith 0:0c3532738887 696
Jamie Smith 4:c609cc7c9ea7 697 // helper function for power setting
Jamie Smith 4:c609cc7c9ea7 698 inline uint8_t dBPowerToRegValue(float powerDB)
Jamie Smith 0:0c3532738887 699 {
Jamie Smith 0:0c3532738887 700 const float minOutputPower = -16.0f;
Jamie Smith 0:0c3532738887 701
Jamie Smith 0:0c3532738887 702 // note: datasheet says this is 14.5, but that must be a mistake: 14.5 would produce a number
Jamie Smith 0:0c3532738887 703 // too large to fit into 6 bits.
Jamie Smith 0:0c3532738887 704 const float maxOutputPower = 14.0f;
Jamie Smith 0:0c3532738887 705
Jamie Smith 0:0c3532738887 706 // clamp output power into correct range
Jamie Smith 4:c609cc7c9ea7 707 powerDB = std::min(powerDB, maxOutputPower);
Jamie Smith 4:c609cc7c9ea7 708 powerDB = std::max(powerDB, minOutputPower);
Jamie Smith 0:0c3532738887 709
Jamie Smith 0:0c3532738887 710 // this equation derived from user guide section 7.1
Jamie Smith 4:c609cc7c9ea7 711 float exactPowerRamp = (2 * powerDB) + 35;
Jamie Smith 4:c609cc7c9ea7 712 return static_cast<uint8_t>(exactPowerRamp); // round to nearest
Jamie Smith 4:c609cc7c9ea7 713 }
Jamie Smith 4:c609cc7c9ea7 714
Jamie Smith 4:c609cc7c9ea7 715 void CC1200::setOutputPower(float outPower)
Jamie Smith 4:c609cc7c9ea7 716 {
Jamie Smith 4:c609cc7c9ea7 717 uint8_t actualPowerRamp = dBPowerToRegValue(outPower);
Jamie Smith 0:0c3532738887 718
Jamie Smith 0:0c3532738887 719 uint8_t paCfg1 = readRegister(Register::PA_CFG1);
Jamie Smith 0:0c3532738887 720 paCfg1 &= ~(0b111111 << PA_CFG1_PA_POWER_RAMP);
Jamie Smith 0:0c3532738887 721 paCfg1 |= actualPowerRamp << PA_CFG1_PA_POWER_RAMP;
Jamie Smith 0:0c3532738887 722 writeRegister(Register::PA_CFG1, paCfg1);
Jamie Smith 5:d22a8885800b 723
Jamie Smith 5:d22a8885800b 724 #if CC1200_DEBUG
Jamie Smith 5:d22a8885800b 725 debugStream->printf("Output power set to %.01f dBm\n", outPower);
Jamie Smith 5:d22a8885800b 726 #endif
Jamie Smith 0:0c3532738887 727 }
Jamie Smith 0:0c3532738887 728
Jamie Smith 4:c609cc7c9ea7 729 const float CC1200::ASK_MIN_POWER_OFF = -17.5f;
Jamie Smith 4:c609cc7c9ea7 730
Jamie Smith 4:c609cc7c9ea7 731 void CC1200::setASKPowers(float maxPower, float minPower)
Jamie Smith 4:c609cc7c9ea7 732 {
Jamie Smith 4:c609cc7c9ea7 733 uint8_t maxPowerValue = dBPowerToRegValue(maxPower);
Jamie Smith 4:c609cc7c9ea7 734
Jamie Smith 4:c609cc7c9ea7 735 minPower = std::min(minPower, maxPower);
Jamie Smith 4:c609cc7c9ea7 736 minPower = std::max(minPower, -17.5f);
Jamie Smith 4:c609cc7c9ea7 737
Jamie Smith 4:c609cc7c9ea7 738 // calculate min power using formula derived from manual
Jamie Smith 4:c609cc7c9ea7 739 uint8_t minPowerValue = static_cast<uint8_t>((maxPower - minPower) * 2);
Jamie Smith 4:c609cc7c9ea7 740
Jamie Smith 4:c609cc7c9ea7 741 // write registers
Jamie Smith 4:c609cc7c9ea7 742 uint8_t paCfg1 = readRegister(Register::PA_CFG1);
Jamie Smith 4:c609cc7c9ea7 743 paCfg1 &= ~(0b111111 << PA_CFG1_PA_POWER_RAMP);
Jamie Smith 4:c609cc7c9ea7 744 paCfg1 |= maxPowerValue << PA_CFG1_PA_POWER_RAMP;
Jamie Smith 4:c609cc7c9ea7 745 writeRegister(Register::PA_CFG1, paCfg1);
Jamie Smith 4:c609cc7c9ea7 746
Jamie Smith 4:c609cc7c9ea7 747 uint8_t askCfg = readRegister(Register::ASK_CFG);
Jamie Smith 4:c609cc7c9ea7 748 askCfg &= ~(0b111111 << ASK_CFG_ASK_DEPTH);
Jamie Smith 4:c609cc7c9ea7 749 askCfg |= minPowerValue << ASK_CFG_ASK_DEPTH;
Jamie Smith 4:c609cc7c9ea7 750 writeRegister(Register::ASK_CFG, askCfg);
Jamie Smith 4:c609cc7c9ea7 751 }
Jamie Smith 4:c609cc7c9ea7 752
Jamie Smith 0:0c3532738887 753 void CC1200::setRadioFrequency(CC1200::Band band, float frequencyHz)
Jamie Smith 0:0c3532738887 754 {
Jamie Smith 0:0c3532738887 755 // Frequency synthesizer configuration. This is completely opaque and it is unknown what these bits do --
Jamie Smith 0:0c3532738887 756 // they are only generated by SmartRF studio.
Jamie Smith 0:0c3532738887 757 // I manually deduplicated them since only a few change based on frequency.
Jamie Smith 0:0c3532738887 758 writeRegister(ExtRegister::IF_ADC1,0xEE);
Jamie Smith 0:0c3532738887 759 writeRegister(ExtRegister::IF_ADC0,0x10);
Jamie Smith 0:0c3532738887 760 writeRegister(ExtRegister::FS_DIG1,0x04);
Jamie Smith 0:0c3532738887 761 writeRegister(ExtRegister::FS_CAL1,0x40);
Jamie Smith 0:0c3532738887 762 writeRegister(ExtRegister::FS_CAL0,0x0E);
Jamie Smith 0:0c3532738887 763 writeRegister(ExtRegister::FS_DIVTWO,0x03);
Jamie Smith 0:0c3532738887 764 writeRegister(ExtRegister::FS_DSM0,0x33);
Jamie Smith 0:0c3532738887 765 writeRegister(ExtRegister::FS_DVC1,0xF7);
Jamie Smith 0:0c3532738887 766 writeRegister(ExtRegister::FS_PFD,0x00);
Jamie Smith 0:0c3532738887 767 writeRegister(ExtRegister::FS_PRE,0x6E);
Jamie Smith 0:0c3532738887 768 writeRegister(ExtRegister::FS_REG_DIV_CML,0x1C);
Jamie Smith 0:0c3532738887 769 writeRegister(ExtRegister::FS_SPARE,0xAC);
Jamie Smith 0:0c3532738887 770 writeRegister(ExtRegister::FS_VCO0,0xB5);
Jamie Smith 0:0c3532738887 771 writeRegister(ExtRegister::XOSC5,0x0E);
Jamie Smith 0:0c3532738887 772 writeRegister(ExtRegister::XOSC1,0x03);
Jamie Smith 0:0c3532738887 773 if(band == Band::BAND_820_960MHz)
Jamie Smith 0:0c3532738887 774 {
Jamie Smith 0:0c3532738887 775 writeRegister(ExtRegister::FS_DIG0,0x55);
Jamie Smith 0:0c3532738887 776 writeRegister(ExtRegister::FS_DVC0,0x17);
Jamie Smith 0:0c3532738887 777 writeRegister(ExtRegister::IFAMP,0x09);
Jamie Smith 0:0c3532738887 778 }
Jamie Smith 5:d22a8885800b 779 else if(band == Band::BAND_410_480MHz)
Jamie Smith 5:d22a8885800b 780 {
Jamie Smith 5:d22a8885800b 781 writeRegister(ExtRegister::FS_DIG0,0xA3);
Jamie Smith 5:d22a8885800b 782 writeRegister(ExtRegister::FS_DVC0,0x0F);
Jamie Smith 5:d22a8885800b 783 writeRegister(ExtRegister::IFAMP,0x0D);
Jamie Smith 5:d22a8885800b 784 }
Jamie Smith 5:d22a8885800b 785 else if(band == Band::BAND_164_192MHz)
Jamie Smith 0:0c3532738887 786 {
Jamie Smith 0:0c3532738887 787 writeRegister(ExtRegister::FS_DIG0,0x50);
Jamie Smith 0:0c3532738887 788 writeRegister(ExtRegister::FS_DVC0,0x0F);
Jamie Smith 0:0c3532738887 789 writeRegister(ExtRegister::IFAMP,0x0D);
Jamie Smith 0:0c3532738887 790 }
Jamie Smith 0:0c3532738887 791 else
Jamie Smith 0:0c3532738887 792 {
Jamie Smith 0:0c3532738887 793 // TI doesn't make settings public for the other radio bands.
Jamie Smith 5:d22a8885800b 794 // Let's take a guess and use the 164-192MHz values.
Jamie Smith 0:0c3532738887 795 writeRegister(ExtRegister::FS_DIG0,0x50);
Jamie Smith 0:0c3532738887 796 writeRegister(ExtRegister::FS_DVC0,0x0F);
Jamie Smith 0:0c3532738887 797 writeRegister(ExtRegister::IFAMP,0x0D);
Jamie Smith 0:0c3532738887 798 }
Jamie Smith 0:0c3532738887 799
Jamie Smith 0:0c3532738887 800 // convert band to LO Divider value.
Jamie Smith 0:0c3532738887 801 // Most of the bands just multiply the register value by 2, but nooo, not BAND_136_160MHz.
Jamie Smith 0:0c3532738887 802 uint8_t loDividerValue;
Jamie Smith 0:0c3532738887 803 if(band == Band::BAND_136_160MHz)
Jamie Smith 0:0c3532738887 804 {
Jamie Smith 0:0c3532738887 805 loDividerValue = 24;
Jamie Smith 0:0c3532738887 806 }
Jamie Smith 0:0c3532738887 807 else
Jamie Smith 0:0c3532738887 808 {
Jamie Smith 0:0c3532738887 809 loDividerValue = static_cast<uint8_t>(band) * 2;
Jamie Smith 0:0c3532738887 810 }
Jamie Smith 0:0c3532738887 811
Jamie Smith 0:0c3532738887 812 // program band (also enable FS out of lock detector, which is useful for testing)
Jamie Smith 0:0c3532738887 813 writeRegister(Register::FS_CFG, (1 << FS_CFG_FS_LOCK_EN) | (static_cast<uint8_t>(band) << FS_CFG_FSD_BANDSELECT));
Jamie Smith 0:0c3532738887 814
Jamie Smith 0:0c3532738887 815 // equation derived from user guide section 9.12
Jamie Smith 5:d22a8885800b 816 float exactFreqRegValue = (twoToThe16 * frequencyHz * static_cast<float>(loDividerValue)) / CC1200_OSC_FREQ;
Jamie Smith 5:d22a8885800b 817 uint32_t actualFreqRegValue = static_cast<uint32_t>(std::min(static_cast<float>(maxValue24Bits), exactFreqRegValue));
Jamie Smith 0:0c3532738887 818
Jamie Smith 0:0c3532738887 819 // program frequency registers
Jamie Smith 0:0c3532738887 820 std::array<uint8_t, 3> freqRegisters ={
Jamie Smith 5:d22a8885800b 821 static_cast<uint8_t>((actualFreqRegValue >> 16) & 0xFF),
Jamie Smith 5:d22a8885800b 822 static_cast<uint8_t>((actualFreqRegValue >> 8) & 0xFF),
Jamie Smith 5:d22a8885800b 823 static_cast<uint8_t>((actualFreqRegValue & 0xFF))
Jamie Smith 0:0c3532738887 824 };
Jamie Smith 0:0c3532738887 825 writeRegisters(ExtRegister::FREQ2, freqRegisters);
Jamie Smith 0:0c3532738887 826
Jamie Smith 5:d22a8885800b 827 // sanity check: calculate actual frequency
Jamie Smith 5:d22a8885800b 828 radioFreqHz = (static_cast<float>(actualFreqRegValue) * CC1200_OSC_FREQ) / (twoToThe16 * static_cast<float>(loDividerValue));
Jamie Smith 5:d22a8885800b 829
Jamie Smith 0:0c3532738887 830 #if CC1200_DEBUG
Jamie Smith 0:0c3532738887 831 debugStream->printf("Setting radio frequency, requested %.00f Hz, setting FREQ = 0x%" PRIx32 "\n",
Jamie Smith 5:d22a8885800b 832 frequencyHz, actualFreqRegValue);
Jamie Smith 5:d22a8885800b 833 debugStream->printf("This yields an actual frequency of %.00f Hz\n", radioFreqHz);
Jamie Smith 0:0c3532738887 834 #endif
Jamie Smith 0:0c3532738887 835 }
Jamie Smith 0:0c3532738887 836
Jamie Smith 0:0c3532738887 837 // helper function for setRXFilterBandwidth:
Jamie Smith 0:0c3532738887 838 // calculate actual receive bandwidth from the given decimations.
Jamie Smith 0:0c3532738887 839 float calcReceiveBandwidth(uint8_t adcDecimation, uint8_t cicDecimation)
Jamie Smith 0:0c3532738887 840 {
Jamie Smith 0:0c3532738887 841 return CC1200_OSC_FREQ / (static_cast<float>(adcDecimation) * static_cast<float>(cicDecimation) * 2);
Jamie Smith 0:0c3532738887 842 }
Jamie Smith 0:0c3532738887 843
Jamie Smith 5:d22a8885800b 844 void CC1200::setRXFilterBandwidth(float bandwidthHz, bool preferHigherCICDec)
Jamie Smith 0:0c3532738887 845 {
Jamie Smith 0:0c3532738887 846 // settings that the chip supports
Jamie Smith 0:0c3532738887 847 const uint8_t possibleADCDecimations[] = {12, 24, 48}; // indexes in this array represent the register value
Jamie Smith 0:0c3532738887 848 const size_t numADCDecimations = sizeof(possibleADCDecimations) / sizeof(uint8_t);
Jamie Smith 0:0c3532738887 849 const uint8_t minBBDecimation = 1;
Jamie Smith 0:0c3532738887 850
Jamie Smith 0:0c3532738887 851 // maximum supported BB decimation based on ADC decimation varies based on chip
Jamie Smith 0:0c3532738887 852 const uint8_t maxBBDecimations1201[] = {33, 16, 8};
Jamie Smith 0:0c3532738887 853 const uint8_t maxBBDecimations1200[] = {44, 44, 44};
Jamie Smith 0:0c3532738887 854 uint8_t const * maxBBDecimations = isCC1201 ? maxBBDecimations1201 : maxBBDecimations1200;
Jamie Smith 0:0c3532738887 855
Jamie Smith 0:0c3532738887 856 // the datasheet suggests to use the highest possible ADC decimation factor that will work for the requested frequency.
Jamie Smith 0:0c3532738887 857 // 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 858
Jamie Smith 0:0c3532738887 859 uint8_t actualBBDecimations[numADCDecimations];
Jamie Smith 0:0c3532738887 860
Jamie Smith 0:0c3532738887 861 for(size_t adcDecimationIndex = 0; adcDecimationIndex < numADCDecimations; ++adcDecimationIndex)
Jamie Smith 0:0c3532738887 862 {
Jamie Smith 0:0c3532738887 863 uint8_t adcDecimation = possibleADCDecimations[adcDecimationIndex];
Jamie Smith 0:0c3532738887 864
Jamie Smith 0:0c3532738887 865 // calculate BB decimation closest to the requested frequency
Jamie Smith 0:0c3532738887 866 // derived from formula in section 6.1
Jamie Smith 0:0c3532738887 867 float exactBBDecimation = CC1200_OSC_FREQ / (2 * bandwidthHz * static_cast<float>(adcDecimation));
Jamie Smith 0:0c3532738887 868 exactBBDecimation = std::max(exactBBDecimation, static_cast<float>(minBBDecimation));
Jamie Smith 0:0c3532738887 869 exactBBDecimation = std::min(exactBBDecimation, static_cast<float>(maxBBDecimations[adcDecimationIndex]));
Jamie Smith 0:0c3532738887 870
Jamie Smith 0:0c3532738887 871 actualBBDecimations[adcDecimationIndex] = static_cast<uint8_t>(exactBBDecimation);
Jamie Smith 0:0c3532738887 872 }
Jamie Smith 0:0c3532738887 873
Jamie Smith 0:0c3532738887 874 // now, choose the best of the ones we calculated
Jamie Smith 0:0c3532738887 875 uint8_t bestDecimationIndex = 0;
Jamie Smith 0:0c3532738887 876 float bestDecimationError = std::abs(bandwidthHz - calcReceiveBandwidth(possibleADCDecimations[0], actualBBDecimations[0]));
Jamie Smith 0:0c3532738887 877
Jamie Smith 0:0c3532738887 878 for(size_t adcDecimationIndex = 1; adcDecimationIndex < numADCDecimations; ++adcDecimationIndex)
Jamie Smith 0:0c3532738887 879 {
Jamie Smith 0:0c3532738887 880 float thisDecimationError = std::abs(bandwidthHz -
Jamie Smith 0:0c3532738887 881 calcReceiveBandwidth(possibleADCDecimations[adcDecimationIndex], actualBBDecimations[adcDecimationIndex]));
Jamie Smith 5:d22a8885800b 882 if((preferHigherCICDec && thisDecimationError <= bestDecimationError) || (!preferHigherCICDec && thisDecimationError < bestDecimationError))
Jamie Smith 0:0c3532738887 883 {
Jamie Smith 0:0c3532738887 884 bestDecimationError = thisDecimationError;
Jamie Smith 0:0c3532738887 885 bestDecimationIndex = adcDecimationIndex;
Jamie Smith 0:0c3532738887 886 }
Jamie Smith 0:0c3532738887 887 }
Jamie Smith 0:0c3532738887 888
Jamie Smith 0:0c3532738887 889 // now use the best value!
Jamie Smith 0:0c3532738887 890 uint8_t chanBwValue = (bestDecimationIndex << CHAN_BW_ADC_CIC_DECFACT) | (actualBBDecimations[bestDecimationIndex] << CHAN_BW_BB_CIC_DECFACT);
Jamie Smith 0:0c3532738887 891 writeRegister(Register::CHAN_BW, chanBwValue);
Jamie Smith 0:0c3532738887 892
Jamie Smith 0:0c3532738887 893 // also set DVGA_GAIN, which depends on bandwidth
Jamie Smith 0:0c3532738887 894 uint8_t mdmCfg1Value = readRegister(Register::MDMCFG1);
Jamie Smith 0:0c3532738887 895
Jamie Smith 0:0c3532738887 896 mdmCfg1Value &= ~(0b11 << MDMCFG1_DVGA_GAIN);
Jamie Smith 0:0c3532738887 897 if(bandwidthHz >= 100000)
Jamie Smith 0:0c3532738887 898 {
Jamie Smith 0:0c3532738887 899 mdmCfg1Value |= 1 << MDMCFG1_DVGA_GAIN;
Jamie Smith 0:0c3532738887 900 }
Jamie Smith 0:0c3532738887 901
Jamie Smith 0:0c3532738887 902 writeRegister(Register::MDMCFG1, mdmCfg1Value);
Jamie Smith 0:0c3532738887 903
Jamie Smith 1:98af824b145e 904 // also set MDMCFG0.DATA_FILTER_EN, which should be 0b11 iff bandwidth / symbol rate > 10
Jamie Smith 1:98af824b145e 905 uint8_t mdmCfg0Val = readRegister(Register::MDMCFG0);
Jamie Smith 1:98af824b145e 906
Jamie Smith 1:98af824b145e 907 if(bandwidthHz / symbolRateSps > 10.0f)
Jamie Smith 1:98af824b145e 908 {
Jamie Smith 1:98af824b145e 909 mdmCfg0Val |= 0b11 << MDMCFG0_DATA_FILTER_EN;
Jamie Smith 1:98af824b145e 910 }
Jamie Smith 1:98af824b145e 911 else
Jamie Smith 1:98af824b145e 912 {
Jamie Smith 1:98af824b145e 913 mdmCfg0Val &= ~(0b11 << MDMCFG0_DATA_FILTER_EN);
Jamie Smith 1:98af824b145e 914 }
Jamie Smith 1:98af824b145e 915
Jamie Smith 1:98af824b145e 916 writeRegister(Register::MDMCFG0, mdmCfg0Val);
Jamie Smith 1:98af824b145e 917
Jamie Smith 0:0c3532738887 918 // finally, we need to set RX_CONFIG_LIMITATION. It's not exactly clear what this does, but its setting changes
Jamie Smith 0:0c3532738887 919 // based on the filter BW.
Jamie Smith 0:0c3532738887 920 uint8_t syncCfg0Value = readRegister(Register::SYNC_CFG0);
Jamie Smith 0:0c3532738887 921
Jamie Smith 0:0c3532738887 922 if(symbolRateSps < bandwidthHz / 2 || bandwidthHz > 1500000)
Jamie Smith 0:0c3532738887 923 {
Jamie Smith 0:0c3532738887 924 // clear RX_CONFIG_LIMITATION
Jamie Smith 0:0c3532738887 925 syncCfg0Value &= ~(1 << SYNC_CFG0_RX_CONFIG_LIMITATION);
Jamie Smith 0:0c3532738887 926 }
Jamie Smith 0:0c3532738887 927 else
Jamie Smith 0:0c3532738887 928 {
Jamie Smith 0:0c3532738887 929 // set RX_CONFIG_LIMITATION
Jamie Smith 0:0c3532738887 930 syncCfg0Value |= (1 << SYNC_CFG0_RX_CONFIG_LIMITATION);
Jamie Smith 0:0c3532738887 931 }
Jamie Smith 0:0c3532738887 932
Jamie Smith 0:0c3532738887 933 writeRegister(Register::SYNC_CFG0, syncCfg0Value);
Jamie Smith 0:0c3532738887 934
Jamie Smith 0:0c3532738887 935 adcCicDecimation = possibleADCDecimations[bestDecimationIndex];
Jamie Smith 5:d22a8885800b 936 currentRXFilterBW = calcReceiveBandwidth(possibleADCDecimations[bestDecimationIndex], actualBBDecimations[bestDecimationIndex]);
Jamie Smith 0:0c3532738887 937
Jamie Smith 0:0c3532738887 938 #if CC1200_DEBUG
Jamie Smith 0:0c3532738887 939 debugStream->printf("Setting BB decimation to %" PRIu8 " and ADC decimation to %" PRIu8 "\n",
Jamie Smith 0:0c3532738887 940 actualBBDecimations[bestDecimationIndex], possibleADCDecimations[bestDecimationIndex]);
Jamie Smith 5:d22a8885800b 941 debugStream->printf("This yields an actual RX filter BW of %.00f\n", currentRXFilterBW);
Jamie Smith 0:0c3532738887 942 #endif
Jamie Smith 0:0c3532738887 943 }
Jamie Smith 0:0c3532738887 944
Jamie Smith 0:0c3532738887 945 void CC1200::configureDCFilter(bool enableAutoFilter, uint8_t settlingCfg, uint8_t cutoffCfg)
Jamie Smith 0:0c3532738887 946 {
Jamie Smith 0:0c3532738887 947 uint8_t dcfiltCfg = 0;
Jamie Smith 0:0c3532738887 948
Jamie Smith 0:0c3532738887 949 if(!enableAutoFilter)
Jamie Smith 0:0c3532738887 950 {
Jamie Smith 0:0c3532738887 951 // set "freeze coeff" bit
Jamie Smith 0:0c3532738887 952 dcfiltCfg |= (1 << DCFILT_CFG_DCFILT_FREEZE_COEFF);
Jamie Smith 0:0c3532738887 953 }
Jamie Smith 0:0c3532738887 954
Jamie Smith 0:0c3532738887 955 dcfiltCfg |= settlingCfg << DCFILT_CFG_DCFILT_BW_SETTLE;
Jamie Smith 0:0c3532738887 956 dcfiltCfg |= cutoffCfg << DCFILT_CFG_DCFILT_BW;
Jamie Smith 0:0c3532738887 957
Jamie Smith 0:0c3532738887 958 writeRegister(Register::DCFILT_CFG, dcfiltCfg);
Jamie Smith 0:0c3532738887 959 }
Jamie Smith 0:0c3532738887 960
Jamie Smith 0:0c3532738887 961 void CC1200::configureSyncWord(uint32_t syncWord, CC1200::SyncMode mode, uint8_t syncThreshold)
Jamie Smith 0:0c3532738887 962 {
Jamie Smith 0:0c3532738887 963 // program sync word registers
Jamie Smith 0:0c3532738887 964 std::array<uint8_t, 4> syncWordRegisters ={
Jamie Smith 0:0c3532738887 965 static_cast<uint8_t>((syncWord >> 24) & 0xFF),
Jamie Smith 0:0c3532738887 966 static_cast<uint8_t>((syncWord >> 16) & 0xFF),
Jamie Smith 0:0c3532738887 967 static_cast<uint8_t>((syncWord >> 8) & 0xFF),
Jamie Smith 0:0c3532738887 968 static_cast<uint8_t>(syncWord & 0xFF)
Jamie Smith 0:0c3532738887 969 };
Jamie Smith 0:0c3532738887 970 writeRegisters(Register::SYNC3, syncWordRegisters);
Jamie Smith 0:0c3532738887 971
Jamie Smith 0:0c3532738887 972 // program sync word cfg
Jamie Smith 0:0c3532738887 973 writeRegister(Register::SYNC_CFG1, (static_cast<uint8_t>(mode) << SYNC_CFG1_SYNC_MODE) | (syncThreshold << SYNC_CFG1_SYNC_THR));
Jamie Smith 0:0c3532738887 974 }
Jamie Smith 0:0c3532738887 975
Jamie Smith 0:0c3532738887 976 bool CC1200::isFSLocked()
Jamie Smith 0:0c3532738887 977 {
Jamie Smith 0:0c3532738887 978 return readRegister(ExtRegister::FSCAL_CTRL) & (1 << FSCAL_CTRL_LOCK);
Jamie Smith 0:0c3532738887 979 }
Jamie Smith 0:0c3532738887 980
Jamie Smith 0:0c3532738887 981 void CC1200::configurePreamble(uint8_t preambleLengthCfg, uint8_t preambleFormatCfg)
Jamie Smith 0:0c3532738887 982 {
Jamie Smith 0:0c3532738887 983 uint8_t preambleCfg1 = 0;
Jamie Smith 0:0c3532738887 984 preambleCfg1 |= preambleLengthCfg << PREAMBLE_CFG1_NUM_PREAMBLE;
Jamie Smith 0:0c3532738887 985 preambleCfg1 |= preambleFormatCfg << PREAMBLE_CFG1_PREAMBLE_WORD;
Jamie Smith 0:0c3532738887 986 writeRegister(Register::PREAMBLE_CFG1, preambleCfg1);
Jamie Smith 5:d22a8885800b 987
Jamie Smith 5:d22a8885800b 988 #if CC1200_DEBUG
Jamie Smith 5:d22a8885800b 989 debugStream->printf("Preamble length CFG set to 0x%" PRIx8 "\n", preambleLengthCfg);
Jamie Smith 5:d22a8885800b 990 #endif
Jamie Smith 0:0c3532738887 991 }
Jamie Smith 0:0c3532738887 992
Jamie Smith 1:98af824b145e 993 void CC1200::setPARampRate(uint8_t firstRampLevel, uint8_t secondRampLevel, CC1200::RampTime rampTime)
Jamie Smith 1:98af824b145e 994 {
Jamie Smith 4:c609cc7c9ea7 995 // enable PA ramping
Jamie Smith 4:c609cc7c9ea7 996 uint8_t paCfg1Val = readRegister(Register::PA_CFG1);
Jamie Smith 4:c609cc7c9ea7 997 paCfg1Val |= 1 << PA_CFG1_PA_RAMP_SHAPE_EN;
Jamie Smith 4:c609cc7c9ea7 998 writeRegister(Register::PA_CFG1, paCfg1Val);
Jamie Smith 4:c609cc7c9ea7 999
Jamie Smith 4:c609cc7c9ea7 1000 // configure properties
Jamie Smith 1:98af824b145e 1001 uint8_t paCfg0Val = 0;
Jamie Smith 1:98af824b145e 1002 paCfg0Val |= (firstRampLevel << PA_CFG0_FIRST_IPL);
Jamie Smith 1:98af824b145e 1003 paCfg0Val |= (secondRampLevel << PA_CFG0_SECOND_IPL);
Jamie Smith 1:98af824b145e 1004 paCfg0Val |= (static_cast<uint8_t>(rampTime) << PA_CFG0_RAMP_SHAPE);
Jamie Smith 1:98af824b145e 1005
Jamie Smith 1:98af824b145e 1006 writeRegister(Register::PA_CFG0, paCfg0Val);
Jamie Smith 1:98af824b145e 1007 }
Jamie Smith 1:98af824b145e 1008
Jamie Smith 4:c609cc7c9ea7 1009 void CC1200::disablePARamping()
Jamie Smith 4:c609cc7c9ea7 1010 {
Jamie Smith 4:c609cc7c9ea7 1011 uint8_t paCfg1Val = readRegister(Register::PA_CFG1);
Jamie Smith 4:c609cc7c9ea7 1012 paCfg1Val &= ~(1 << PA_CFG1_PA_RAMP_SHAPE_EN);
Jamie Smith 4:c609cc7c9ea7 1013 writeRegister(Register::PA_CFG1, paCfg1Val);
Jamie Smith 4:c609cc7c9ea7 1014 }
Jamie Smith 4:c609cc7c9ea7 1015
Jamie Smith 1:98af824b145e 1016 void CC1200::setAGCReferenceLevel(uint8_t level)
Jamie Smith 1:98af824b145e 1017 {
Jamie Smith 1:98af824b145e 1018 writeRegister(Register::AGC_REF, level);
Jamie Smith 1:98af824b145e 1019 }
Jamie Smith 1:98af824b145e 1020
Jamie Smith 1:98af824b145e 1021 void CC1200::setAGCSyncBehavior(CC1200::SyncBehavior behavior)
Jamie Smith 1:98af824b145e 1022 {
Jamie Smith 1:98af824b145e 1023 uint8_t agcCfg3Val = readRegister(Register::AGC_CFG3);
Jamie Smith 1:98af824b145e 1024 agcCfg3Val &= ~(0b111 << AGC_CFG3_AGC_SYNC_BEHAVIOUR);
Jamie Smith 1:98af824b145e 1025 agcCfg3Val |= static_cast<uint8_t>(behavior) << AGC_CFG3_AGC_SYNC_BEHAVIOUR;
Jamie Smith 1:98af824b145e 1026 writeRegister(Register::AGC_CFG3, agcCfg3Val);
Jamie Smith 1:98af824b145e 1027 }
Jamie Smith 1:98af824b145e 1028
Jamie Smith 1:98af824b145e 1029 void CC1200::setAGCGainTable(CC1200::GainTable table, uint8_t minGainIndex, uint8_t maxGainIndex)
Jamie Smith 1:98af824b145e 1030 {
Jamie Smith 1:98af824b145e 1031 uint8_t agcCfg3Val = readRegister(Register::AGC_CFG3);
Jamie Smith 1:98af824b145e 1032 uint8_t agcCfg2Val = readRegister(Register::AGC_CFG2);
Jamie Smith 1:98af824b145e 1033
Jamie Smith 1:98af824b145e 1034 agcCfg3Val &= ~(0b11111 << AGC_CFG3_AGC_MIN_GAIN);
Jamie Smith 1:98af824b145e 1035 agcCfg2Val &= ~(0b11 << AGC_CFG2_FE_PERFORMANCE_MODE);
Jamie Smith 1:98af824b145e 1036 agcCfg2Val &= ~(0b11111 << AGC_CFG2_AGC_MAX_GAIN);
Jamie Smith 1:98af824b145e 1037
Jamie Smith 5:d22a8885800b 1038 agcCfg3Val |= minGainIndex << AGC_CFG3_AGC_MIN_GAIN;
Jamie Smith 1:98af824b145e 1039 agcCfg2Val |= static_cast<uint8_t>(table) << AGC_CFG2_FE_PERFORMANCE_MODE;
Jamie Smith 1:98af824b145e 1040 agcCfg2Val |= maxGainIndex << AGC_CFG2_AGC_MAX_GAIN;
Jamie Smith 1:98af824b145e 1041
Jamie Smith 1:98af824b145e 1042 writeRegister(Register::AGC_CFG3, agcCfg3Val);
Jamie Smith 1:98af824b145e 1043 writeRegister(Register::AGC_CFG2, agcCfg2Val);
Jamie Smith 1:98af824b145e 1044 }
Jamie Smith 1:98af824b145e 1045
Jamie Smith 1:98af824b145e 1046 void CC1200::setAGCHysteresis(uint8_t hysteresisCfg)
Jamie Smith 1:98af824b145e 1047 {
Jamie Smith 1:98af824b145e 1048 uint8_t agcCfg0Val = readRegister(Register::AGC_CFG0);
Jamie Smith 1:98af824b145e 1049 agcCfg0Val &= ~(0b11 << AGC_CFG0_AGC_HYST_LEVEL);
Jamie Smith 1:98af824b145e 1050 agcCfg0Val |= hysteresisCfg << AGC_CFG0_AGC_HYST_LEVEL;
Jamie Smith 1:98af824b145e 1051 writeRegister(Register::AGC_CFG0, agcCfg0Val);
Jamie Smith 1:98af824b145e 1052 }
Jamie Smith 1:98af824b145e 1053
Jamie Smith 1:98af824b145e 1054 void CC1200::setAGCSlewRate(uint8_t slewrateCfg)
Jamie Smith 1:98af824b145e 1055 {
Jamie Smith 1:98af824b145e 1056 uint8_t agcCfg0Val = readRegister(Register::AGC_CFG0);
Jamie Smith 1:98af824b145e 1057 agcCfg0Val &= ~(0b11 << AGC_CFG0_AGC_SLEWRATE_LIMIT);
Jamie Smith 1:98af824b145e 1058 agcCfg0Val |= slewrateCfg << AGC_CFG0_AGC_SLEWRATE_LIMIT;
Jamie Smith 1:98af824b145e 1059 writeRegister(Register::AGC_CFG0, agcCfg0Val);
Jamie Smith 1:98af824b145e 1060 }
Jamie Smith 1:98af824b145e 1061
Jamie Smith 5:d22a8885800b 1062 void CC1200::setAGCSettleWait(uint8_t settleWaitCfg)
Jamie Smith 5:d22a8885800b 1063 {
Jamie Smith 5:d22a8885800b 1064 uint8_t agcCfg1Val = readRegister(Register::AGC_CFG1);
Jamie Smith 5:d22a8885800b 1065 agcCfg1Val &= ~(0b111 << AGC_CFG1_AGC_SETTLE_WAIT);
Jamie Smith 5:d22a8885800b 1066 agcCfg1Val |= (settleWaitCfg << AGC_CFG1_AGC_SETTLE_WAIT);
Jamie Smith 5:d22a8885800b 1067 writeRegister(Register::AGC_CFG1, agcCfg1Val);
Jamie Smith 5:d22a8885800b 1068 }
Jamie Smith 5:d22a8885800b 1069
Jamie Smith 5:d22a8885800b 1070 float CC1200::getRSSIRegister()
Jamie Smith 0:0c3532738887 1071 {
Jamie Smith 5:d22a8885800b 1072 uint8_t rssi1Val = readRegister(ExtRegister::RSSI1);
Jamie Smith 5:d22a8885800b 1073 uint8_t rssi0Val = readRegister(ExtRegister::RSSI0);
Jamie Smith 5:d22a8885800b 1074
Jamie Smith 5:d22a8885800b 1075 if(!(rssi0Val & (1 << RSSI0_RSSI_VALID)))
Jamie Smith 5:d22a8885800b 1076 {
Jamie Smith 5:d22a8885800b 1077 // no valid measurement
Jamie Smith 5:d22a8885800b 1078 return NAN;
Jamie Smith 5:d22a8885800b 1079 }
Jamie Smith 5:d22a8885800b 1080
Jamie Smith 5:d22a8885800b 1081 // first convert to two's compliment number
Jamie Smith 5:d22a8885800b 1082 int16_t rssiInt = 0;
Jamie Smith 5:d22a8885800b 1083 rssiInt |= (rssi0Val >> RSSI0_RSSI_3_0) & 0b1111;
Jamie Smith 5:d22a8885800b 1084 rssiInt |= rssi1Val << 4;
Jamie Smith 5:d22a8885800b 1085
Jamie Smith 5:d22a8885800b 1086 if(rssi1Val & 0x80)
Jamie Smith 5:d22a8885800b 1087 {
Jamie Smith 5:d22a8885800b 1088 // negative number, sign extend from 12 to 16 bits
Jamie Smith 5:d22a8885800b 1089 rssiInt |= (0b1111 << 12);
Jamie Smith 5:d22a8885800b 1090 }
Jamie Smith 5:d22a8885800b 1091
Jamie Smith 5:d22a8885800b 1092 //debugStream->printf("Approx RSSI: %" PRIi8 ", exact RSSI: %f\n", static_cast<int8_t>(rssi1Val), static_cast<float>(rssiInt) * 0.0625f);
Jamie Smith 5:d22a8885800b 1093
Jamie Smith 5:d22a8885800b 1094 return static_cast<float>(rssiInt) * 0.0625f; // conversion factor given in datasheet
Jamie Smith 5:d22a8885800b 1095 }
Jamie Smith 5:d22a8885800b 1096
Jamie Smith 5:d22a8885800b 1097 void CC1200::setRSSIOffset(int8_t adjust)
Jamie Smith 5:d22a8885800b 1098 {
Jamie Smith 5:d22a8885800b 1099 writeRegister(Register::AGC_GAIN_ADJUST, static_cast<uint8_t>(adjust));
Jamie Smith 5:d22a8885800b 1100 }
Jamie Smith 5:d22a8885800b 1101
Jamie Smith 5:d22a8885800b 1102 uint8_t CC1200::getLQIRegister()
Jamie Smith 5:d22a8885800b 1103 {
Jamie Smith 5:d22a8885800b 1104 return readRegister(ExtRegister::LQI_VAL) & 0b1111111;
Jamie Smith 5:d22a8885800b 1105 }
Jamie Smith 5:d22a8885800b 1106
Jamie Smith 5:d22a8885800b 1107 void CC1200::setIFCfg(IFCfg value, bool enableIQIC)
Jamie Smith 5:d22a8885800b 1108 {
Jamie Smith 5:d22a8885800b 1109 // make sure prerequisites have been run
Jamie Smith 5:d22a8885800b 1110 MBED_ASSERT(radioFreqHz > 0);
Jamie Smith 5:d22a8885800b 1111 MBED_ASSERT(adcCicDecimation > 0 && currentRXFilterBW > 0);
Jamie Smith 5:d22a8885800b 1112
Jamie Smith 0:0c3532738887 1113 uint8_t ifMixCfg = readRegister(ExtRegister::IF_MIX_CFG);
Jamie Smith 0:0c3532738887 1114 ifMixCfg &= ~(0b111 << IF_MIX_CFG_CMIX_CFG);
Jamie Smith 5:d22a8885800b 1115 ifMixCfg |= (static_cast<uint8_t>(value) << IF_MIX_CFG_CMIX_CFG);
Jamie Smith 0:0c3532738887 1116 writeRegister(ExtRegister::IF_MIX_CFG, ifMixCfg);
Jamie Smith 5:d22a8885800b 1117
Jamie Smith 5:d22a8885800b 1118 float effectiveIF;
Jamie Smith 5:d22a8885800b 1119
Jamie Smith 5:d22a8885800b 1120 // calculate effective IF value
Jamie Smith 5:d22a8885800b 1121 if(value == IFCfg::ZERO)
Jamie Smith 5:d22a8885800b 1122 {
Jamie Smith 5:d22a8885800b 1123 effectiveIF = radioFreqHz;
Jamie Smith 5:d22a8885800b 1124 }
Jamie Smith 5:d22a8885800b 1125 else
Jamie Smith 5:d22a8885800b 1126 {
Jamie Smith 5:d22a8885800b 1127 int32_t dividerValue = 0;
Jamie Smith 5:d22a8885800b 1128 switch(value)
Jamie Smith 5:d22a8885800b 1129 {
Jamie Smith 5:d22a8885800b 1130 case IFCfg::NEGATIVE_DIV_4: dividerValue = -4; break;
Jamie Smith 5:d22a8885800b 1131 case IFCfg::NEGATIVE_DIV_6: dividerValue = -6; break;
Jamie Smith 5:d22a8885800b 1132 case IFCfg::NEGATIVE_DIV_8: dividerValue = -8; break;
Jamie Smith 5:d22a8885800b 1133 case IFCfg::POSITIVE_DIV_4: dividerValue = 4; break;
Jamie Smith 5:d22a8885800b 1134 case IFCfg::POSITIVE_DIV_6: dividerValue = 6; break;
Jamie Smith 5:d22a8885800b 1135 case IFCfg::POSITIVE_DIV_8: dividerValue = 8; break;
Jamie Smith 5:d22a8885800b 1136 default: break;
Jamie Smith 5:d22a8885800b 1137 }
Jamie Smith 5:d22a8885800b 1138
Jamie Smith 5:d22a8885800b 1139 // formula from IF_MIX_CFG register description
Jamie Smith 5:d22a8885800b 1140 effectiveIF = (CC1200_OSC_FREQ / static_cast<float>(adcCicDecimation * dividerValue)) * 1000;
Jamie Smith 5:d22a8885800b 1141 }
Jamie Smith 5:d22a8885800b 1142
Jamie Smith 5:d22a8885800b 1143 uint8_t iqicValue = readRegister(Register::IQIC);
Jamie Smith 5:d22a8885800b 1144 if(enableIQIC && effectiveIF > currentRXFilterBW)
Jamie Smith 5:d22a8885800b 1145 {
Jamie Smith 5:d22a8885800b 1146 iqicValue |= (1 << IQIC_IQIC_EN);
Jamie Smith 5:d22a8885800b 1147 }
Jamie Smith 5:d22a8885800b 1148 else
Jamie Smith 5:d22a8885800b 1149 {
Jamie Smith 5:d22a8885800b 1150 iqicValue &= ~(1 << IQIC_IQIC_EN);
Jamie Smith 5:d22a8885800b 1151 }
Jamie Smith 5:d22a8885800b 1152 writeRegister(Register::IQIC, iqicValue);
Jamie Smith 5:d22a8885800b 1153
Jamie Smith 5:d22a8885800b 1154 #if CC1200_DEBUG
Jamie Smith 5:d22a8885800b 1155 debugStream->printf("Setting IF Mix Cfg to 0x%" PRIx8 " and IQIC_EN to %d\n", static_cast<uint8_t>(value),
Jamie Smith 5:d22a8885800b 1156 !!(iqicValue & (1 << IQIC_IQIC_EN))); // note: double ! used to convert boolean to either 1 or 0.
Jamie Smith 5:d22a8885800b 1157 debugStream->printf("This yields an actual IF of %.00f\n", effectiveIF);
Jamie Smith 5:d22a8885800b 1158 #endif
Jamie Smith 0:0c3532738887 1159 }
Jamie Smith 0:0c3532738887 1160
Jamie Smith 0:0c3532738887 1161 uint8_t CC1200::readRegister(CC1200::Register reg)
Jamie Smith 0:0c3532738887 1162 {
Jamie Smith 0:0c3532738887 1163 spi.select();
Jamie Smith 0:0c3532738887 1164 loadStatusByte(spi.write(CC1200_READ | static_cast<uint8_t>(reg)));
Jamie Smith 0:0c3532738887 1165 uint8_t regValue = spi.write(0);
Jamie Smith 0:0c3532738887 1166 spi.deselect();
Jamie Smith 0:0c3532738887 1167
Jamie Smith 0:0c3532738887 1168 #if CC1200_REGISTER_LEVEL_DEBUG
Jamie Smith 0:0c3532738887 1169 debugStream->printf("Read register 0x%" PRIx8 " -> 0x%" PRIx8 "\n", static_cast<uint8_t>(reg), regValue);
Jamie Smith 0:0c3532738887 1170 #endif
Jamie Smith 0:0c3532738887 1171
Jamie Smith 0:0c3532738887 1172 return regValue;
Jamie Smith 0:0c3532738887 1173 }
Jamie Smith 0:0c3532738887 1174
Jamie Smith 0:0c3532738887 1175 void CC1200::writeRegister(Register reg, uint8_t value)
Jamie Smith 0:0c3532738887 1176 {
Jamie Smith 0:0c3532738887 1177 spi.select();
Jamie Smith 0:0c3532738887 1178 loadStatusByte(spi.write(CC1200_WRITE | static_cast<uint8_t>(reg)));
Jamie Smith 0:0c3532738887 1179 spi.write(value);
Jamie Smith 0:0c3532738887 1180 spi.deselect();
Jamie Smith 0:0c3532738887 1181
Jamie Smith 0:0c3532738887 1182 #if CC1200_REGISTER_LEVEL_DEBUG
Jamie Smith 0:0c3532738887 1183 debugStream->printf("Wrote register 0x%" PRIx8 " <- 0x%" PRIx8 "\n", static_cast<uint8_t>(reg), value);
Jamie Smith 0:0c3532738887 1184 #endif
Jamie Smith 0:0c3532738887 1185 }
Jamie Smith 0:0c3532738887 1186
Jamie Smith 0:0c3532738887 1187 void CC1200::writeRegisters(CC1200::Register startReg, uint8_t const *values, size_t numRegisters)
Jamie Smith 0:0c3532738887 1188 {
Jamie Smith 0:0c3532738887 1189 spi.select();
Jamie Smith 0:0c3532738887 1190 loadStatusByte(spi.write(CC1200_WRITE | CC1200_BURST | static_cast<uint8_t>(startReg)));
Jamie Smith 0:0c3532738887 1191
Jamie Smith 0:0c3532738887 1192 for(size_t byteIndex = 0; byteIndex < numRegisters; ++byteIndex)
Jamie Smith 0:0c3532738887 1193 {
Jamie Smith 0:0c3532738887 1194 spi.write(values[byteIndex]);
Jamie Smith 0:0c3532738887 1195 }
Jamie Smith 0:0c3532738887 1196 spi.deselect();
Jamie Smith 0:0c3532738887 1197
Jamie Smith 0:0c3532738887 1198 #if CC1200_REGISTER_LEVEL_DEBUG
Jamie Smith 0:0c3532738887 1199 for(size_t byteIndex = 0; byteIndex < numRegisters; ++byteIndex)
Jamie Smith 0:0c3532738887 1200 {
Jamie Smith 0:0c3532738887 1201 debugStream->printf("Wrote register 0x%" PRIx8 " <- 0x%" PRIx8 "\n",
Jamie Smith 0:0c3532738887 1202 static_cast<uint8_t>(static_cast<uint8_t>(startReg) + byteIndex),
Jamie Smith 0:0c3532738887 1203 values[byteIndex]);
Jamie Smith 0:0c3532738887 1204 }
Jamie Smith 0:0c3532738887 1205 #endif
Jamie Smith 0:0c3532738887 1206 }
Jamie Smith 0:0c3532738887 1207
Jamie Smith 0:0c3532738887 1208 void CC1200::loadStatusByte(uint8_t status)
Jamie Smith 0:0c3532738887 1209 {
Jamie Smith 0:0c3532738887 1210 chipReady = !(status >> 7);
Jamie Smith 0:0c3532738887 1211 state = static_cast<State>((status >> 4) & 0x7);
Jamie Smith 0:0c3532738887 1212
Jamie Smith 0:0c3532738887 1213 #if CC1200_REGISTER_LEVEL_DEBUG
Jamie Smith 0:0c3532738887 1214 debugStream->printf("Updated status, state = 0x%" PRIx8 " ready = %s\n", static_cast<uint8_t>(state), chipReady ? "true" : "false");
Jamie Smith 0:0c3532738887 1215 #endif
Jamie Smith 0:0c3532738887 1216 }
Jamie Smith 0:0c3532738887 1217
Jamie Smith 0:0c3532738887 1218 uint8_t CC1200::readRegister(CC1200::ExtRegister reg)
Jamie Smith 0:0c3532738887 1219 {
Jamie Smith 0:0c3532738887 1220 spi.select();
Jamie Smith 0:0c3532738887 1221 loadStatusByte(spi.write(CC1200_READ | CC1200_EXT_ADDR));
Jamie Smith 0:0c3532738887 1222 spi.write(static_cast<uint8_t>(reg));
Jamie Smith 0:0c3532738887 1223 uint8_t regValue = spi.write(0);
Jamie Smith 0:0c3532738887 1224 spi.deselect();
Jamie Smith 0:0c3532738887 1225
Jamie Smith 0:0c3532738887 1226 #if CC1200_REGISTER_LEVEL_DEBUG
Jamie Smith 0:0c3532738887 1227 debugStream->printf("Read ext register 0x%" PRIx8 " -> 0x%" PRIx8 "\n", static_cast<uint8_t>(reg), regValue);
Jamie Smith 0:0c3532738887 1228 #endif
Jamie Smith 0:0c3532738887 1229
Jamie Smith 0:0c3532738887 1230 return regValue;
Jamie Smith 0:0c3532738887 1231 }
Jamie Smith 0:0c3532738887 1232
Jamie Smith 0:0c3532738887 1233 void CC1200::writeRegister(CC1200::ExtRegister reg, uint8_t value)
Jamie Smith 0:0c3532738887 1234 {
Jamie Smith 0:0c3532738887 1235 spi.select();
Jamie Smith 0:0c3532738887 1236 loadStatusByte(spi.write(CC1200_WRITE | CC1200_EXT_ADDR));
Jamie Smith 0:0c3532738887 1237 spi.write(static_cast<uint8_t>(reg));
Jamie Smith 0:0c3532738887 1238 spi.write(value);
Jamie Smith 0:0c3532738887 1239 spi.deselect();
Jamie Smith 0:0c3532738887 1240
Jamie Smith 0:0c3532738887 1241 #if CC1200_REGISTER_LEVEL_DEBUG
Jamie Smith 0:0c3532738887 1242 debugStream->printf("Wrote ext register 0x%" PRIx8 " <- 0x%" PRIx8 "\n", static_cast<uint8_t>(reg), value);
Jamie Smith 0:0c3532738887 1243 #endif
Jamie Smith 0:0c3532738887 1244 }
Jamie Smith 0:0c3532738887 1245
Jamie Smith 0:0c3532738887 1246 void CC1200::writeRegisters(CC1200::ExtRegister startReg, uint8_t const *values, size_t numRegisters)
Jamie Smith 0:0c3532738887 1247 {
Jamie Smith 0:0c3532738887 1248 spi.select();
Jamie Smith 0:0c3532738887 1249 loadStatusByte(spi.write(CC1200_WRITE | CC1200_BURST | CC1200_EXT_ADDR));
Jamie Smith 0:0c3532738887 1250 spi.write(static_cast<uint8_t>(startReg));
Jamie Smith 0:0c3532738887 1251
Jamie Smith 0:0c3532738887 1252 for(size_t byteIndex = 0; byteIndex < numRegisters; ++byteIndex)
Jamie Smith 0:0c3532738887 1253 {
Jamie Smith 0:0c3532738887 1254 spi.write(values[byteIndex]);
Jamie Smith 0:0c3532738887 1255 }
Jamie Smith 0:0c3532738887 1256 spi.deselect();
Jamie Smith 0:0c3532738887 1257
Jamie Smith 0:0c3532738887 1258 #if CC1200_REGISTER_LEVEL_DEBUG
Jamie Smith 0:0c3532738887 1259 for(size_t byteIndex = 0; byteIndex < numRegisters; ++byteIndex)
Jamie Smith 0:0c3532738887 1260 {
Jamie Smith 0:0c3532738887 1261 debugStream->printf("Wrote extended register 0x%" PRIx8 " <- 0x%" PRIx8 "\n",
Jamie Smith 0:0c3532738887 1262 static_cast<uint8_t>(static_cast<uint8_t>(startReg) + byteIndex),
Jamie Smith 0:0c3532738887 1263 values[byteIndex]);
Jamie Smith 0:0c3532738887 1264 }
Jamie Smith 0:0c3532738887 1265 #endif
Jamie Smith 0:0c3532738887 1266 }
Jamie Smith 0:0c3532738887 1267
Jamie Smith 0:0c3532738887 1268 void CC1200::sendCommand(CC1200::Command command)
Jamie Smith 0:0c3532738887 1269 {
Jamie Smith 0:0c3532738887 1270 spi.select();
Jamie Smith 0:0c3532738887 1271 loadStatusByte(spi.write(static_cast<uint8_t>(command)));
Jamie Smith 0:0c3532738887 1272 spi.deselect();
Jamie Smith 0:0c3532738887 1273
Jamie Smith 0:0c3532738887 1274 #if CC1200_REGISTER_LEVEL_DEBUG
Jamie Smith 0:0c3532738887 1275 debugStream->printf("Sent SPI command 0x%" PRIx8 "\n", static_cast<uint8_t>(command));
Jamie Smith 0:0c3532738887 1276 #endif
Jamie Smith 0:0c3532738887 1277 }
Jamie Smith 0:0c3532738887 1278
Jamie Smith 0:0c3532738887 1279 uint8_t CC1200::readRXFIFOByte(uint8_t address)
Jamie Smith 0:0c3532738887 1280 {
Jamie Smith 0:0c3532738887 1281 spi.select();
Jamie Smith 0:0c3532738887 1282 loadStatusByte(spi.write(CC1200_READ | CC1200_MEM_ACCESS));
Jamie Smith 2:2a447e8e50b8 1283 spi.write(CC1200_RX_FIFO | address);
Jamie Smith 2:2a447e8e50b8 1284 int value = spi.write(0);
Jamie Smith 0:0c3532738887 1285 spi.deselect();
Jamie Smith 0:0c3532738887 1286
Jamie Smith 0:0c3532738887 1287 #if CC1200_REGISTER_LEVEL_DEBUG
Jamie Smith 2:2a447e8e50b8 1288 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 1289 #endif
Jamie Smith 0:0c3532738887 1290
Jamie Smith 0:0c3532738887 1291 return value;
Jamie Smith 0:0c3532738887 1292 }