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:
Sun Aug 09 23:39:21 2020 -0700
Revision:
1:98af824b145e
Parent:
0:0c3532738887
Child:
2:2a447e8e50b8
Add a few new features, fix issue with reading from wrong FIFO

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