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

Dependents:   CC1200-MorseEncoder CC1200-Examples

CC1200 Driver

by Jamie Smith / USC Rocket Propulsion Lab

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

Features

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

Not Supported

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

Examples

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

Changelog

Version 1.2 May 3 2021

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

Version 1.1 Aug 28 2020

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

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

Version 1.0 Aug 10 2020

Initial Release

Committer:
Jamie Smith
Date:
Mon Aug 10 01:30:40 2020 -0700
Revision:
2:2a447e8e50b8
Parent:
1:98af824b145e
Child:
3:f464b14ce62f
Update to Mbed OS 6.  Also fix CC1200::hasReceivedPacket, which has never actually worked until now (whoops)

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