Driver for TI's CC1200 radio ICs. Forget hardcoded register settings -- this driver calculates everything from scratch!
Dependents: CC1200-MorseEncoder CC1200-Examples
CC1200.cpp
00001 #pragma clang diagnostic push 00002 #pragma ide diagnostic ignored "readability-magic-numbers" 00003 // 00004 // Created by jamie on 3/27/2020. 00005 // 00006 00007 #include "CC1200.h" 00008 #include "CC1200Bits.h" 00009 00010 #include <cinttypes> 00011 #include <cmath> 00012 #include <array> 00013 00014 // change to 1 to print debug info 00015 #define CC1200_DEBUG 1 00016 00017 // change to 1 to print register read/write level debug info 00018 #define CC1200_REGISTER_LEVEL_DEBUG 0 00019 00020 // miscellaneous constants 00021 #define CC1200_READ (1 << 7) // SPI initial byte flag indicating read 00022 #define CC1200_WRITE 0 // SPI initial byte flag indicating write 00023 #define CC1200_BURST (1 << 6) // SPI initial byte flag indicating burst access 00024 00025 // SPI commands to access data buffers. Can be used with CC1200_BURST. 00026 #define CC1200_ENQUEUE_TX_FIFO 0x3F 00027 #define CC1200_DEQUEUE_RX_FIFO 0xBF 00028 00029 // SPI command to access FIFO memory (or several other areas depending on mode) 00030 #define CC1200_MEM_ACCESS 0x3E 00031 00032 #define CC1200_RX_FIFO (1 << 7) // address flag to access RX FIFO 00033 #define CC1200_TX_FIFO 0 // address flag to access TX FIFO 00034 00035 00036 #define CC1200_PART_NUMBER ((uint8_t)0x20) // part number we expect the chip to read 00037 #define CC1201_PART_NUMBER ((uint8_t)0x21) 00038 #define CC1200_EXT_ADDR 0x2F // SPI initial byte address indicating extended register space 00039 00040 #define SPI_MODE 0 00041 #define SPI_FREQ 5000000 // hz 00042 // NOTE: the chip supports a higher frequency for most operations but reads to extended registers require a lower frequency 00043 00044 // frequency of the chip's crystal oscillator 00045 #define CC1200_OSC_FREQ 40000000 // hz 00046 #define CC1200_OSC_FREQ_LOG2 25.253496f // log2 of above number 00047 00048 // length of the TX and RX FIFOS 00049 #define CC1200_FIFO_SIZE 128 00050 00051 // maximum length of the packets we can send, including the length byte which we add. 00052 // Since the TX and RX FIFOs are 128 bytes, supporting packet lengths longer than 128 bytes 00053 // requires streaming bytes in during the transmission, which would make things complicated. 00054 #define MAX_PACKET_LENGTH 128 00055 00056 // Length of the status bytes that can be appended to packets 00057 #define PACKET_STATUS_LEN 2U 00058 00059 // utility function: compile-time power calculator. 00060 // Works on all signed and unsigned integer types for T. 00061 // from: http://prosepoetrycode.potterpcs.net/2015/07/a-simple-constexpr-power-function-c/ 00062 template <typename T> 00063 constexpr T constexpr_pow(T num, unsigned int pow) 00064 { 00065 return pow == 0 ? 1 : num * constexpr_pow(num, pow-1); 00066 } 00067 00068 // power of two constants 00069 const float twoToThe16 = constexpr_pow(2.0f, 16); 00070 const float twoToThe20 = constexpr_pow(2.0f, 20); 00071 const float twoToThe21 = constexpr_pow(2.0f, 21); 00072 const float twoToThe22 = constexpr_pow(2.0f, 22); 00073 const float twoToThe38 = constexpr_pow(2.0f, 38); 00074 const float twoToThe39 = constexpr_pow(2.0f, 39); 00075 00076 // binary value size constants 00077 const size_t maxValue3Bits = constexpr_pow(2, 3) - 1; 00078 const size_t maxValue4Bits = constexpr_pow(2, 4) - 1; 00079 const size_t maxValue8Bits = constexpr_pow(2, 8) - 1; 00080 const size_t maxValue20Bits = constexpr_pow(2, 20) - 1; 00081 const size_t maxValue24Bits = constexpr_pow(2, 24) - 1; 00082 00083 CC1200::CC1200(PinName mosiPin, PinName misoPin, PinName sclkPin, PinName csPin, PinName rstPin, Stream * _debugStream, bool _isCC1201): 00084 spi(mosiPin, misoPin, sclkPin, csPin, use_gpio_ssel), 00085 rst(rstPin, 1), 00086 debugStream(_debugStream), 00087 isCC1201(_isCC1201) 00088 { 00089 spi.format(8, SPI_MODE); 00090 spi.frequency(SPI_FREQ); 00091 } 00092 00093 bool CC1200::begin() 00094 { 00095 chipReady = false; 00096 00097 // reset 00098 rst.write(0); 00099 wait_us(100); 00100 rst.write(1); 00101 00102 const auto resetTimeout = 10ms; 00103 Timer timeoutTimer; 00104 timeoutTimer.start(); 00105 00106 while(!chipReady) 00107 { 00108 // datasheet specifies 240us reset time 00109 wait_us(250); 00110 updateState(); 00111 00112 if(timeoutTimer.elapsed_time() > resetTimeout) 00113 { 00114 debugStream->printf("Timeout waiting for ready response from CC1200\n"); 00115 break; 00116 } 00117 } 00118 00119 // read ID register 00120 uint8_t partNumber = readRegister(ExtRegister::PARTNUMBER); 00121 uint8_t partVersion = readRegister(ExtRegister::PARTVERSION); 00122 00123 uint8_t expectedPartNumber = isCC1201 ? CC1201_PART_NUMBER : CC1200_PART_NUMBER; 00124 if(partNumber != expectedPartNumber) 00125 { 00126 debugStream->printf("Read incorrect part number 0x%" PRIx8 " from CC1200, expected 0x%" PRIx8 "\n", partNumber, expectedPartNumber); 00127 return false; 00128 } 00129 00130 #if CC1200_DEBUG 00131 debugStream->printf("Detected CC1200, Part Number 0x%" PRIx8 ", Hardware Version %" PRIx8 "\n", partNumber, partVersion); 00132 #endif 00133 00134 00135 // Set packet format settings for this driver 00136 // ------------------------------------------------------------------------ 00137 00138 // enable CRC but disable status bytes 00139 writeRegister(Register::PKT_CFG1, (0b01 << PKT_CFG1_CRC_CFG)); 00140 00141 return true; 00142 } 00143 00144 size_t CC1200::getTXFIFOLen() 00145 { 00146 return readRegister(ExtRegister::NUM_TXBYTES); 00147 } 00148 00149 size_t CC1200::getRXFIFOLen() 00150 { 00151 return readRegister(ExtRegister::NUM_RXBYTES); 00152 } 00153 00154 bool CC1200::enqueuePacket(char const * data, size_t len) 00155 { 00156 uint8_t totalLength = len + 1; // add one byte for length byte 00157 00158 if(totalLength > MAX_PACKET_LENGTH) 00159 { 00160 // packet too big 00161 return false; 00162 } 00163 00164 uint8_t txFreeBytes = CC1200_FIFO_SIZE - getTXFIFOLen(); 00165 if(totalLength > txFreeBytes) 00166 { 00167 // packet doesn't fit in TX FIFO 00168 return false; 00169 } 00170 00171 // burst write to TX FIFO 00172 spi.select(); 00173 loadStatusByte(spi.write(CC1200_ENQUEUE_TX_FIFO | CC1200_BURST)); 00174 if(_packetMode == PacketMode::VARIABLE_LENGTH) 00175 { 00176 spi.write(len); 00177 } 00178 for(size_t byteIndex = 0; byteIndex < len; ++byteIndex) 00179 { 00180 spi.write(data[byteIndex]); 00181 } 00182 spi.deselect(); 00183 00184 #if CC1200_REGISTER_LEVEL_DEBUG 00185 debugStream->printf("Wrote packet of data length %zu:", len); 00186 if(_packetMode == PacketMode::VARIABLE_LENGTH) 00187 { 00188 debugStream->printf(" %02" PRIx8, static_cast<uint8_t>(len)); 00189 } 00190 for(size_t byteIndex = 0; byteIndex < len; ++byteIndex) 00191 { 00192 debugStream->printf(" %02" PRIx8, data[byteIndex]); 00193 } 00194 debugStream->printf("\n"); 00195 #endif 00196 return true; 00197 } 00198 00199 bool CC1200::hasReceivedPacket() 00200 { 00201 size_t bytesReceived = getRXFIFOLen(); 00202 00203 if(bytesReceived < 1) 00204 { 00205 // no bytes at all, can't check the length 00206 return false; 00207 } 00208 00209 if(_packetMode == PacketMode::FIXED_LENGTH) 00210 { 00211 return bytesReceived >= _packetTotalLength + (appendStatusEnabled ? PACKET_STATUS_LEN : 0); 00212 } 00213 else if(_packetMode == PacketMode::INFINITE_LENGTH) 00214 { 00215 // Any amount of bytes constitutes a packet. 00216 return bytesReceived > 0; 00217 } 00218 else // _packetMode == PacketMode::VARIABLE_LENGTH 00219 { 00220 // get value of first byte of the packet, which is the length. 00221 00222 // The datasheet is wrong about this! It says that the first byte in the RX FIFO can 00223 // be found by accessing address RXFIRST via direct fifo access. 00224 // However, in my own testing, RXFIRST points to the second entry in the FIFO, and 00225 // the first entry must be accessed through RXFIFO_PRE_BUF. 00226 uint8_t packetLen = readRegister(ExtRegister::RXFIFO_PRE_BUF); 00227 00228 // if we have received a full packet's worth of bytes, then we have received a full packet. 00229 return bytesReceived >= static_cast<size_t>(packetLen + 1 /* Add one because length field does not include itself */) + (appendStatusEnabled ? PACKET_STATUS_LEN : 0); 00230 } 00231 } 00232 00233 size_t CC1200::receivePacket(char *buffer, size_t bufferLen) 00234 { 00235 // burst read from RX FIFO 00236 spi.select(); 00237 loadStatusByte(spi.write(CC1200_DEQUEUE_RX_FIFO | CC1200_BURST)); 00238 00239 uint8_t dataLen; 00240 if(_packetMode == PacketMode::VARIABLE_LENGTH) 00241 { 00242 // first read length byte 00243 dataLen = spi.write(0); 00244 } 00245 else // _packetMode == PacketMode::FIXED_LENGTH) 00246 { 00247 dataLen = _packetTotalLength; 00248 } 00249 00250 for(size_t byteIndex = 0; byteIndex < dataLen; ++byteIndex) 00251 { 00252 uint8_t currByte = spi.write(0); 00253 if(byteIndex < bufferLen) 00254 { 00255 buffer[byteIndex] = currByte; 00256 } 00257 } 00258 00259 if(appendStatusEnabled) 00260 { 00261 uint8_t statusBytes[PACKET_STATUS_LEN]; 00262 for(size_t byteIndex = 0; byteIndex < PACKET_STATUS_LEN; ++byteIndex) 00263 { 00264 statusBytes[byteIndex] = spi.write(0); 00265 } 00266 00267 lastRSSI = statusBytes[0]; 00268 lastLQI = statusBytes[1] & 0b01111111; 00269 } 00270 00271 spi.deselect(); 00272 00273 #if CC1200_REGISTER_LEVEL_DEBUG 00274 debugStream->printf("Read packet of data length %" PRIu8 ": %" PRIx8, dataLen, static_cast<uint8_t>(dataLen)); 00275 for(size_t byteIndex = 0; byteIndex < dataLen; ++byteIndex) 00276 { 00277 debugStream->printf(" %" PRIx8, buffer[byteIndex]); 00278 } 00279 debugStream->printf("\n"); 00280 #endif 00281 00282 return dataLen; 00283 } 00284 00285 size_t CC1200::writeStream(const char *buffer, size_t count) 00286 { 00287 size_t freeBytes = CC1200_FIFO_SIZE - getTXFIFOLen(); 00288 00289 /*if(state == State::TX) 00290 { 00291 if(freeBytes > 0) 00292 { 00293 freeBytes--; 00294 } 00295 }*/ 00296 00297 size_t bytesToWrite = std::min(freeBytes, count); 00298 00299 if(bytesToWrite == 0) 00300 { 00301 return 0; 00302 } 00303 00304 spi.select(); 00305 loadStatusByte(spi.write(CC1200_ENQUEUE_TX_FIFO | CC1200_BURST)); 00306 for(size_t byteIndex = 0; byteIndex < bytesToWrite; ++byteIndex) 00307 { 00308 spi.write(buffer[byteIndex]); 00309 } 00310 spi.deselect(); 00311 00312 #if CC1200_REGISTER_LEVEL_DEBUG 00313 debugStream->printf("%zu bytes were free, wrote stream of data length %zu:", freeBytes, bytesToWrite); 00314 for(size_t byteIndex = 0; byteIndex < bytesToWrite; ++byteIndex) 00315 { 00316 debugStream->printf(" %02" PRIx8, buffer[byteIndex]); 00317 } 00318 debugStream->printf("\n"); 00319 #endif 00320 00321 return bytesToWrite; 00322 } 00323 00324 bool CC1200::writeStreamBlocking(const char *buffer, size_t count) 00325 { 00326 //size_t origCount = count; 00327 size_t bufferOffset = 0; 00328 while(state == State::TX && count > 0) 00329 { 00330 size_t bytesWritten = writeStream(buffer + bufferOffset, count); 00331 count -= bytesWritten; 00332 bufferOffset += bytesWritten; 00333 } 00334 00335 //debugStream->printf("Read stream of data length %zu\n:", origCount); 00336 00337 return count == 0; 00338 } 00339 00340 size_t CC1200::readStream(char *buffer, size_t maxLen) 00341 { 00342 size_t bytesToRead = std::min(maxLen, getRXFIFOLen()); 00343 if(bytesToRead == 0) 00344 { 00345 return 0; 00346 } 00347 00348 // burst read from RX FIFO 00349 spi.select(); 00350 loadStatusByte(spi.write(CC1200_DEQUEUE_RX_FIFO | CC1200_BURST)); 00351 for(size_t byteIndex = 0; byteIndex < bytesToRead; ++byteIndex) 00352 { 00353 buffer[byteIndex] = spi.write(0); 00354 } 00355 spi.deselect(); 00356 00357 #if CC1200_REGISTER_LEVEL_DEBUG 00358 debugStream->printf("Read stream of data length %zu:", bytesToRead); 00359 for(size_t byteIndex = 0; byteIndex < bytesToRead; ++byteIndex) 00360 { 00361 debugStream->printf(" %" PRIx8, buffer[byteIndex]); 00362 } 00363 debugStream->printf("\n"); 00364 #endif 00365 00366 return bytesToRead; 00367 } 00368 00369 bool CC1200::readStreamBlocking(char *buffer, size_t count, std::chrono::microseconds timeout) 00370 { 00371 //size_t origCount = count; 00372 Timer timeoutTimer; 00373 00374 if(timeout > 0us) 00375 { 00376 timeoutTimer.start(); 00377 } 00378 00379 size_t bufferOffset = 0; 00380 while((timeoutTimer.elapsed_time() < timeout || timeout == 0us) && state == State::RX && count > 0) 00381 { 00382 size_t bytesRead = readStream(buffer + bufferOffset, count); 00383 count -= bytesRead; 00384 bufferOffset += bytesRead; 00385 } 00386 00387 //debugStream->printf("Read stream of data length %zu, first %" PRIx8 " last %" PRIx8 "\n:", origCount, 00388 // buffer[0], buffer[origCount - 1]); 00389 00390 return count == 0; 00391 } 00392 00393 00394 // helper function: convert a state to the bits for RXOFF_MODE and TXOFF_MODE 00395 inline uint8_t getOffModeBits(CC1200::State state) 00396 { 00397 uint8_t offBits = 0b0; 00398 if(state == CC1200::State::IDLE) 00399 { 00400 offBits = 0b0; 00401 } 00402 else if(state == CC1200::State::FAST_ON) 00403 { 00404 offBits = 0b1; 00405 } 00406 else if(state == CC1200::State::TX) 00407 { 00408 offBits = 0b10; 00409 } 00410 else if(state == CC1200::State::RX) 00411 { 00412 offBits = 0b11; 00413 } 00414 return offBits; 00415 } 00416 00417 void CC1200::setOnReceiveState(CC1200::State goodPacket, CC1200::State badPacket) 00418 { 00419 // configure good packet action via RXOFF_MODE 00420 uint8_t rfendCfg1 = readRegister(Register::RFEND_CFG1); 00421 rfendCfg1 &= ~(0b11 << RFEND_CFG1_RXOFF_MODE); 00422 rfendCfg1 |= getOffModeBits(goodPacket) << RFEND_CFG1_RXOFF_MODE; 00423 writeRegister(Register::RFEND_CFG1, rfendCfg1); 00424 00425 // configure bad packet action via TERM_ON_BAD_PACKET_EN 00426 uint8_t rfendCfg0 = readRegister(Register::RFEND_CFG0); 00427 if(badPacket == State::RX) 00428 { 00429 rfendCfg0 &= ~(1 << RFEND_CFG0_TERM_ON_BAD_PACKET_EN); 00430 } 00431 else 00432 { 00433 rfendCfg0 |= 1 << RFEND_CFG1_RXOFF_MODE; 00434 } 00435 writeRegister(Register::RFEND_CFG0, rfendCfg0); 00436 } 00437 00438 void CC1200::setOnTransmitState(CC1200::State txState) 00439 { 00440 uint8_t rfendCfg0 = readRegister(Register::RFEND_CFG0); 00441 rfendCfg0 &= ~(0b11 << RFEND_CFG0_TXOFF_MODE); 00442 rfendCfg0 |= getOffModeBits(txState) << RFEND_CFG0_TXOFF_MODE; 00443 writeRegister(Register::RFEND_CFG0, rfendCfg0); 00444 } 00445 00446 void CC1200::setFSCalMode(FSCalMode mode) 00447 { 00448 uint8_t settlingCfg = readRegister(Register::SETTLING_CFG); 00449 settlingCfg &= ~(0b11 << SETTLING_CFG_FS_AUTOCAL); 00450 settlingCfg |= static_cast<uint8_t>(mode) << SETTLING_CFG_FS_AUTOCAL; 00451 writeRegister(Register::SETTLING_CFG, settlingCfg); 00452 } 00453 00454 void CC1200::configureGPIO(uint8_t gpioNumber, CC1200::GPIOMode mode, bool outputInvert) 00455 { 00456 // gpio 3 is the first register, then it goes down to 0 00457 Register gpioReg = static_cast<Register>(static_cast<uint8_t>(Register::IOCFG3) + (3 - gpioNumber)); 00458 00459 uint8_t gpioCfgVal = static_cast<uint8_t>(mode); 00460 if(outputInvert) 00461 { 00462 gpioCfgVal |= (1 << GPIO_INV); 00463 } 00464 writeRegister(gpioReg, gpioCfgVal); 00465 } 00466 00467 void CC1200::configureFIFOMode() 00468 { 00469 // configure packet format 00470 uint8_t pktCfg2 = readRegister(Register::PKT_CFG2); 00471 pktCfg2 &= ~(0b11 << PKT_CFG2_PKT_FORMAT); 00472 writeRegister(Register::PKT_CFG2, pktCfg2); 00473 00474 // enable fifo 00475 uint8_t mdmCfg1 = readRegister(Register::MDMCFG1); 00476 mdmCfg1 |= 1 << MDMCFG1_FIFO_EN; 00477 writeRegister(Register::MDMCFG1, mdmCfg1); 00478 00479 // make sure transparent mode is disabled 00480 uint8_t mdmCfg0 = readRegister(Register::MDMCFG0); 00481 mdmCfg0 &= ~(1 << MDMCFG0_TRANSPARENT_MODE_EN); 00482 writeRegister(Register::MDMCFG0, mdmCfg0); 00483 } 00484 00485 void CC1200::setPacketMode(PacketMode mode, bool appendStatus) 00486 { 00487 _packetMode = mode; 00488 00489 uint8_t pktCfg0 = readRegister(Register::PKT_CFG0); 00490 // set length config field 00491 pktCfg0 &= ~(0b11 << PKT_CFG0_LENGTH_CONFIG); 00492 pktCfg0 |= static_cast<uint8_t>(mode) << PKT_CFG0_LENGTH_CONFIG; 00493 writeRegister(Register::PKT_CFG0, pktCfg0); 00494 00495 if(mode == PacketMode::VARIABLE_LENGTH) 00496 { 00497 // disable packet length limit 00498 writeRegister(Register::PKT_LEN, MAX_PACKET_LENGTH); 00499 } 00500 else if(mode == PacketMode::FIXED_LENGTH) 00501 { 00502 // reset to selected fixed lengths 00503 setPacketLength(_packetByteLength, _packetBitLength); 00504 } 00505 else 00506 { 00507 // Infinite length packets, PKT_LEN register is a don't care. 00508 } 00509 00510 // set append status 00511 appendStatusEnabled = appendStatus; 00512 uint8_t pktCfg1 = readRegister(Register::PKT_CFG1); 00513 if(appendStatus) 00514 { 00515 pktCfg1 |= 1 << PKT_CFG1_APPEND_STATUS; 00516 } 00517 else 00518 { 00519 pktCfg1 &= ~(1 << PKT_CFG1_APPEND_STATUS); 00520 } 00521 writeRegister(Register::PKT_CFG1, pktCfg1); 00522 } 00523 00524 void CC1200::setPacketLength(uint16_t length, uint8_t bitLength) 00525 { 00526 _packetByteLength = length; 00527 _packetBitLength = bitLength; 00528 _packetTotalLength = _packetByteLength; 00529 00530 if(bitLength > 0) 00531 { 00532 // tell the driver to read the extra bits into another byte 00533 _packetTotalLength++; 00534 } 00535 00536 if(_packetTotalLength == 256) 00537 { 00538 // Length byte of 0 indicates 256 bytes 00539 writeRegister(Register::PKT_LEN, 0); 00540 } 00541 else 00542 { 00543 writeRegister(Register::PKT_LEN, _packetByteLength); 00544 } 00545 00546 uint8_t pktCfg0 = readRegister(Register::PKT_CFG0); 00547 pktCfg0 &= ~(0b111 << PKT_CFG0_PKT_BIT_LEN); 00548 pktCfg0 |= _packetBitLength << PKT_CFG0_PKT_BIT_LEN; 00549 writeRegister(Register::PKT_CFG0, pktCfg0); 00550 00551 #if CC1200_DEBUG 00552 debugStream->printf("Set total length to %zu, byte length = %zu, bit length = %" PRIu8 "\n", _packetTotalLength, _packetByteLength, _packetBitLength); 00553 #endif 00554 } 00555 00556 void CC1200::setCRCEnabled(bool enabled) 00557 { 00558 uint8_t pktCfg1 = readRegister(Register::PKT_CFG1); 00559 pktCfg1 &= ~(0b11 << PKT_CFG1_CRC_CFG); 00560 pktCfg1 |= (enabled ? 0b01 : 0b00) << PKT_CFG1_CRC_CFG; 00561 writeRegister(Register::PKT_CFG1, pktCfg1); 00562 } 00563 00564 void CC1200::setModulationFormat(CC1200::ModFormat format) 00565 { 00566 uint8_t modcfgDevE = readRegister(Register::MODCFG_DEV_E); 00567 modcfgDevE &= ~(0b111 << MODCFG_DEV_E_MOD_FORMAT); 00568 modcfgDevE |= static_cast<uint8_t>(format) << MODCFG_DEV_E_MOD_FORMAT; 00569 writeRegister(Register::MODCFG_DEV_E, modcfgDevE); 00570 } 00571 00572 void CC1200::setFSKDeviation(float deviation) 00573 { 00574 // Deviation is set as two values, an exponent register from 0-3 and a mantissa register from 0-256. 00575 // See user guide page 81 for the original equation, this function was worked out from that 00576 00577 // First assume mantissa is zero and calculate the needed exponent 00578 float exactExponent = std::log2(deviation) - CC1200_OSC_FREQ_LOG2 + 14; 00579 uint8_t actualExponent = static_cast<uint8_t>(std::min(static_cast<float>(maxValue3Bits), exactExponent)); 00580 // note: 14 comes from log2(2^22) - log2(256) 00581 00582 float exactMantissa; 00583 if(actualExponent >= 1) 00584 { 00585 exactMantissa = (std::pow(2.0f, static_cast<float>(22 - actualExponent)) * deviation) 00586 / CC1200_OSC_FREQ - 256; 00587 } 00588 else 00589 { 00590 // use alternate high-resolution formula for case where exponent = 0 00591 exactMantissa = deviation * twoToThe21 / CC1200_OSC_FREQ; 00592 } 00593 00594 // now calculate closest mantissa 00595 uint8_t actualMantissa = static_cast<uint8_t>(std::min(static_cast<float>(maxValue8Bits), exactMantissa)); 00596 00597 // set exponent and mantissa 00598 writeRegister(Register::DEVIATION_M, actualMantissa); 00599 00600 uint8_t modcfgDevE = readRegister(Register::MODCFG_DEV_E); 00601 modcfgDevE &= ~(0b111 << MODCFG_DEV_E_DEV_E); 00602 modcfgDevE |= actualExponent << MODCFG_DEV_E_DEV_E; 00603 writeRegister(Register::MODCFG_DEV_E, modcfgDevE); 00604 00605 #if CC1200_DEBUG 00606 debugStream->printf("Setting FSK deviation, requested +-%.00f Hz, setting DEV_E = 0x%" PRIx8 " DEV_M = 0x%" PRIx8 "\n", 00607 deviation, actualExponent, actualMantissa); 00608 00609 float actualDeviation; 00610 if(actualExponent == 0) 00611 { 00612 actualDeviation = CC1200_OSC_FREQ * actualMantissa / twoToThe21; 00613 } 00614 else 00615 { 00616 actualDeviation = (CC1200_OSC_FREQ / twoToThe22) * (256.0f + static_cast<float>(actualMantissa)) * pow(2.0f, static_cast<float>(actualExponent)); 00617 } 00618 // sanity check: calculate actual deviation 00619 debugStream->printf("This yields an actual deviation of +-%.00f Hz\n", actualDeviation); 00620 #endif 00621 } 00622 00623 void CC1200::setSymbolRate(float symbolRateHz) 00624 { 00625 // Datasheet says that the cc1200 works in ksps, but testing with SmartRF studio 00626 // shows that it actually is sps. 00627 00628 symbolRateSps = symbolRateHz; 00629 00630 // Note: these equations are given on page 29 of the user guide 00631 00632 float exactExponent = std::log2(symbolRateSps) - CC1200_OSC_FREQ_LOG2 + 19; 00633 // note: 19 comes from log2(2^39) - 20 00634 uint8_t actualExponent = static_cast<uint8_t>(std::min(static_cast<float>(maxValue4Bits), exactExponent)); 00635 00636 float exactMantissa; 00637 if(actualExponent >= 1) 00638 { 00639 exactMantissa = (std::pow(2.0f, static_cast<float>(39 - actualExponent)) * symbolRateSps) 00640 / CC1200_OSC_FREQ - twoToThe20; 00641 } 00642 else 00643 { 00644 // use alternate high-resolution formula for case where exponent = 0 00645 exactMantissa = symbolRateSps * twoToThe38 / CC1200_OSC_FREQ; 00646 } 00647 00648 // mantissa is a 20 bit number, so restrict it to that domain 00649 uint32_t actualMantissa = static_cast<uint32_t>(std::min(static_cast<float>(maxValue20Bits), exactMantissa)); 00650 00651 // program symbol rate registers 00652 std::array<uint8_t, 3> symbolRateRegisters ={ 00653 static_cast<uint8_t>((actualExponent << SYMBOL_RATE2_SRATE_E) | (static_cast<uint8_t>((actualMantissa >> 16) & 0xFF) << SYMBOL_RATE2_SRATE_M_19_16)), 00654 static_cast<uint8_t>((actualMantissa >> 8) & 0xFF), 00655 static_cast<uint8_t>((actualMantissa & 0xFF)) 00656 }; 00657 writeRegisters(Register::SYMBOL_RATE2, symbolRateRegisters); 00658 00659 // Calculate upsampler value according to the formula in its register description 00660 float upsamplingFactor = CC1200_OSC_FREQ / (64 * symbolRateSps); // 2^upsamplerPVal needs to be less than this value 00661 uint8_t upsamplerPVal = std::floor(std::log2(upsamplingFactor)); 00662 00663 // prevent low sampling rates from choosing a nonexistent upsampling 00664 upsamplerPVal = std::min<uint8_t>(upsamplerPVal, 0b110); 00665 00666 uint8_t mdmcfg2 = readRegister(ExtRegister::MDMCFG2); 00667 mdmcfg2 &= ~(0b111 << MDMCFG2_UPSAMPLER_P); 00668 mdmcfg2 |= (upsamplerPVal << MDMCFG2_UPSAMPLER_P); 00669 00670 writeRegister(ExtRegister::MDMCFG2, mdmcfg2); 00671 00672 #if CC1200_DEBUG 00673 debugStream->printf("Setting symbol rate, requested %.03f Hz, setting SRATE_E = 0x%" PRIx8 " SRATE_M = 0x%" PRIx32 "\n", 00674 symbolRateHz, actualExponent, actualMantissa); 00675 00676 // sanity check: calculate actual symbol rate 00677 float actualSymbolRateSps; 00678 if(actualExponent == 0) 00679 { 00680 actualSymbolRateSps = (static_cast<float>(actualMantissa) * CC1200_OSC_FREQ) / twoToThe38; 00681 } 00682 else 00683 { 00684 00685 actualSymbolRateSps = ((static_cast<float>(actualMantissa) + twoToThe20) * 00686 pow(2.0f,static_cast<float>(actualExponent)) * CC1200_OSC_FREQ) 00687 / twoToThe39; 00688 } 00689 00690 debugStream->printf("This yields an actual symbol rate of %.02f Hz\n", actualSymbolRateSps); 00691 00692 uint8_t actualUpsampling = static_cast<uint8_t>(pow(2.0f, static_cast<float>(upsamplerPVal))); 00693 debugStream->printf("Also setting upsampling factor to %" PRIu8 " via UPSAMPLER_P = %" PRIx8 "\n", actualUpsampling, upsamplerPVal); 00694 #endif 00695 } 00696 00697 // helper function for power setting 00698 inline uint8_t dBPowerToRegValue(float powerDB) 00699 { 00700 const float minOutputPower = -16.0f; 00701 00702 // note: datasheet says this is 14.5, but that must be a mistake: 14.5 would produce a number 00703 // too large to fit into 6 bits. 00704 const float maxOutputPower = 14.0f; 00705 00706 // clamp output power into correct range 00707 powerDB = std::min(powerDB, maxOutputPower); 00708 powerDB = std::max(powerDB, minOutputPower); 00709 00710 // this equation derived from user guide section 7.1 00711 float exactPowerRamp = (2 * powerDB) + 35; 00712 return static_cast<uint8_t>(exactPowerRamp); // round to nearest 00713 } 00714 00715 void CC1200::setOutputPower(float outPower) 00716 { 00717 uint8_t actualPowerRamp = dBPowerToRegValue(outPower); 00718 00719 uint8_t paCfg1 = readRegister(Register::PA_CFG1); 00720 paCfg1 &= ~(0b111111 << PA_CFG1_PA_POWER_RAMP); 00721 paCfg1 |= actualPowerRamp << PA_CFG1_PA_POWER_RAMP; 00722 writeRegister(Register::PA_CFG1, paCfg1); 00723 00724 #if CC1200_DEBUG 00725 debugStream->printf("Output power set to %.01f dBm\n", outPower); 00726 #endif 00727 } 00728 00729 const float CC1200::ASK_MIN_POWER_OFF = -17.5f; 00730 00731 void CC1200::setASKPowers(float maxPower, float minPower) 00732 { 00733 uint8_t maxPowerValue = dBPowerToRegValue(maxPower); 00734 00735 minPower = std::min(minPower, maxPower); 00736 minPower = std::max(minPower, -17.5f); 00737 00738 // calculate min power using formula derived from manual 00739 uint8_t minPowerValue = static_cast<uint8_t>((maxPower - minPower) * 2); 00740 00741 // write registers 00742 uint8_t paCfg1 = readRegister(Register::PA_CFG1); 00743 paCfg1 &= ~(0b111111 << PA_CFG1_PA_POWER_RAMP); 00744 paCfg1 |= maxPowerValue << PA_CFG1_PA_POWER_RAMP; 00745 writeRegister(Register::PA_CFG1, paCfg1); 00746 00747 uint8_t askCfg = readRegister(Register::ASK_CFG); 00748 askCfg &= ~(0b111111 << ASK_CFG_ASK_DEPTH); 00749 askCfg |= minPowerValue << ASK_CFG_ASK_DEPTH; 00750 writeRegister(Register::ASK_CFG, askCfg); 00751 } 00752 00753 void CC1200::setRadioFrequency(CC1200::Band band, float frequencyHz) 00754 { 00755 // Frequency synthesizer configuration. This is completely opaque and it is unknown what these bits do -- 00756 // they are only generated by SmartRF studio. 00757 // I manually deduplicated them since only a few change based on frequency. 00758 writeRegister(ExtRegister::IF_ADC1,0xEE); 00759 writeRegister(ExtRegister::IF_ADC0,0x10); 00760 writeRegister(ExtRegister::FS_DIG1,0x04); 00761 writeRegister(ExtRegister::FS_CAL1,0x40); 00762 writeRegister(ExtRegister::FS_CAL0,0x0E); 00763 writeRegister(ExtRegister::FS_DIVTWO,0x03); 00764 writeRegister(ExtRegister::FS_DSM0,0x33); 00765 writeRegister(ExtRegister::FS_DVC1,0xF7); 00766 writeRegister(ExtRegister::FS_PFD,0x00); 00767 writeRegister(ExtRegister::FS_PRE,0x6E); 00768 writeRegister(ExtRegister::FS_REG_DIV_CML,0x1C); 00769 writeRegister(ExtRegister::FS_SPARE,0xAC); 00770 writeRegister(ExtRegister::FS_VCO0,0xB5); 00771 writeRegister(ExtRegister::XOSC5,0x0E); 00772 writeRegister(ExtRegister::XOSC1,0x03); 00773 if(band == Band::BAND_820_960MHz) 00774 { 00775 writeRegister(ExtRegister::FS_DIG0,0x55); 00776 writeRegister(ExtRegister::FS_DVC0,0x17); 00777 writeRegister(ExtRegister::IFAMP,0x09); 00778 } 00779 else if(band == Band::BAND_410_480MHz) 00780 { 00781 writeRegister(ExtRegister::FS_DIG0,0xA3); 00782 writeRegister(ExtRegister::FS_DVC0,0x0F); 00783 writeRegister(ExtRegister::IFAMP,0x0D); 00784 } 00785 else if(band == Band::BAND_164_192MHz) 00786 { 00787 writeRegister(ExtRegister::FS_DIG0,0x50); 00788 writeRegister(ExtRegister::FS_DVC0,0x0F); 00789 writeRegister(ExtRegister::IFAMP,0x0D); 00790 } 00791 else 00792 { 00793 // TI doesn't make settings public for the other radio bands. 00794 // Let's take a guess and use the 164-192MHz values. 00795 writeRegister(ExtRegister::FS_DIG0,0x50); 00796 writeRegister(ExtRegister::FS_DVC0,0x0F); 00797 writeRegister(ExtRegister::IFAMP,0x0D); 00798 } 00799 00800 // convert band to LO Divider value. 00801 // Most of the bands just multiply the register value by 2, but nooo, not BAND_136_160MHz. 00802 uint8_t loDividerValue; 00803 if(band == Band::BAND_136_160MHz) 00804 { 00805 loDividerValue = 24; 00806 } 00807 else 00808 { 00809 loDividerValue = static_cast<uint8_t>(band) * 2; 00810 } 00811 00812 // program band (also enable FS out of lock detector, which is useful for testing) 00813 writeRegister(Register::FS_CFG, (1 << FS_CFG_FS_LOCK_EN) | (static_cast<uint8_t>(band) << FS_CFG_FSD_BANDSELECT)); 00814 00815 // equation derived from user guide section 9.12 00816 float exactFreqRegValue = (twoToThe16 * frequencyHz * static_cast<float>(loDividerValue)) / CC1200_OSC_FREQ; 00817 uint32_t actualFreqRegValue = static_cast<uint32_t>(std::min(static_cast<float>(maxValue24Bits), exactFreqRegValue)); 00818 00819 // program frequency registers 00820 std::array<uint8_t, 3> freqRegisters ={ 00821 static_cast<uint8_t>((actualFreqRegValue >> 16) & 0xFF), 00822 static_cast<uint8_t>((actualFreqRegValue >> 8) & 0xFF), 00823 static_cast<uint8_t>((actualFreqRegValue & 0xFF)) 00824 }; 00825 writeRegisters(ExtRegister::FREQ2, freqRegisters); 00826 00827 // sanity check: calculate actual frequency 00828 radioFreqHz = (static_cast<float>(actualFreqRegValue) * CC1200_OSC_FREQ) / (twoToThe16 * static_cast<float>(loDividerValue)); 00829 00830 #if CC1200_DEBUG 00831 debugStream->printf("Setting radio frequency, requested %.00f Hz, setting FREQ = 0x%" PRIx32 "\n", 00832 frequencyHz, actualFreqRegValue); 00833 debugStream->printf("This yields an actual frequency of %.00f Hz\n", radioFreqHz); 00834 #endif 00835 } 00836 00837 // helper function for setRXFilterBandwidth: 00838 // calculate actual receive bandwidth from the given decimations. 00839 float calcReceiveBandwidth(uint8_t adcDecimation, uint8_t cicDecimation) 00840 { 00841 return CC1200_OSC_FREQ / (static_cast<float>(adcDecimation) * static_cast<float>(cicDecimation) * 2); 00842 } 00843 00844 void CC1200::setRXFilterBandwidth(float bandwidthHz, bool preferHigherCICDec) 00845 { 00846 // settings that the chip supports 00847 const uint8_t possibleADCDecimations[] = {12, 24, 48}; // indexes in this array represent the register value 00848 const size_t numADCDecimations = sizeof(possibleADCDecimations) / sizeof(uint8_t); 00849 const uint8_t minBBDecimation = 1; 00850 00851 // maximum supported BB decimation based on ADC decimation varies based on chip 00852 const uint8_t maxBBDecimations1201[] = {33, 16, 8}; 00853 const uint8_t maxBBDecimations1200[] = {44, 44, 44}; 00854 uint8_t const * maxBBDecimations = isCC1201 ? maxBBDecimations1201 : maxBBDecimations1200; 00855 00856 // the datasheet suggests to use the highest possible ADC decimation factor that will work for the requested frequency. 00857 // 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 00858 00859 uint8_t actualBBDecimations[numADCDecimations]; 00860 00861 for(size_t adcDecimationIndex = 0; adcDecimationIndex < numADCDecimations; ++adcDecimationIndex) 00862 { 00863 uint8_t adcDecimation = possibleADCDecimations[adcDecimationIndex]; 00864 00865 // calculate BB decimation closest to the requested frequency 00866 // derived from formula in section 6.1 00867 float exactBBDecimation = CC1200_OSC_FREQ / (2 * bandwidthHz * static_cast<float>(adcDecimation)); 00868 exactBBDecimation = std::max(exactBBDecimation, static_cast<float>(minBBDecimation)); 00869 exactBBDecimation = std::min(exactBBDecimation, static_cast<float>(maxBBDecimations[adcDecimationIndex])); 00870 00871 actualBBDecimations[adcDecimationIndex] = static_cast<uint8_t>(exactBBDecimation); 00872 } 00873 00874 // now, choose the best of the ones we calculated 00875 uint8_t bestDecimationIndex = 0; 00876 float bestDecimationError = std::abs(bandwidthHz - calcReceiveBandwidth(possibleADCDecimations[0], actualBBDecimations[0])); 00877 00878 for(size_t adcDecimationIndex = 1; adcDecimationIndex < numADCDecimations; ++adcDecimationIndex) 00879 { 00880 float thisDecimationError = std::abs(bandwidthHz - 00881 calcReceiveBandwidth(possibleADCDecimations[adcDecimationIndex], actualBBDecimations[adcDecimationIndex])); 00882 if((preferHigherCICDec && thisDecimationError <= bestDecimationError) || (!preferHigherCICDec && thisDecimationError < bestDecimationError)) 00883 { 00884 bestDecimationError = thisDecimationError; 00885 bestDecimationIndex = adcDecimationIndex; 00886 } 00887 } 00888 00889 // now use the best value! 00890 uint8_t chanBwValue = (bestDecimationIndex << CHAN_BW_ADC_CIC_DECFACT) | (actualBBDecimations[bestDecimationIndex] << CHAN_BW_BB_CIC_DECFACT); 00891 writeRegister(Register::CHAN_BW, chanBwValue); 00892 00893 // also set DVGA_GAIN, which depends on bandwidth 00894 uint8_t mdmCfg1Value = readRegister(Register::MDMCFG1); 00895 00896 mdmCfg1Value &= ~(0b11 << MDMCFG1_DVGA_GAIN); 00897 if(bandwidthHz >= 100000) 00898 { 00899 mdmCfg1Value |= 1 << MDMCFG1_DVGA_GAIN; 00900 } 00901 00902 writeRegister(Register::MDMCFG1, mdmCfg1Value); 00903 00904 // also set MDMCFG0.DATA_FILTER_EN, which should be 0b11 iff bandwidth / symbol rate > 10 00905 uint8_t mdmCfg0Val = readRegister(Register::MDMCFG0); 00906 00907 if(bandwidthHz / symbolRateSps > 10.0f) 00908 { 00909 mdmCfg0Val |= 0b11 << MDMCFG0_DATA_FILTER_EN; 00910 } 00911 else 00912 { 00913 mdmCfg0Val &= ~(0b11 << MDMCFG0_DATA_FILTER_EN); 00914 } 00915 00916 writeRegister(Register::MDMCFG0, mdmCfg0Val); 00917 00918 // finally, we need to set RX_CONFIG_LIMITATION. It's not exactly clear what this does, but its setting changes 00919 // based on the filter BW. 00920 uint8_t syncCfg0Value = readRegister(Register::SYNC_CFG0); 00921 00922 if(symbolRateSps < bandwidthHz / 2 || bandwidthHz > 1500000) 00923 { 00924 // clear RX_CONFIG_LIMITATION 00925 syncCfg0Value &= ~(1 << SYNC_CFG0_RX_CONFIG_LIMITATION); 00926 } 00927 else 00928 { 00929 // set RX_CONFIG_LIMITATION 00930 syncCfg0Value |= (1 << SYNC_CFG0_RX_CONFIG_LIMITATION); 00931 } 00932 00933 writeRegister(Register::SYNC_CFG0, syncCfg0Value); 00934 00935 adcCicDecimation = possibleADCDecimations[bestDecimationIndex]; 00936 currentRXFilterBW = calcReceiveBandwidth(possibleADCDecimations[bestDecimationIndex], actualBBDecimations[bestDecimationIndex]); 00937 00938 #if CC1200_DEBUG 00939 debugStream->printf("Setting BB decimation to %" PRIu8 " and ADC decimation to %" PRIu8 "\n", 00940 actualBBDecimations[bestDecimationIndex], possibleADCDecimations[bestDecimationIndex]); 00941 debugStream->printf("This yields an actual RX filter BW of %.00f\n", currentRXFilterBW); 00942 #endif 00943 } 00944 00945 void CC1200::configureDCFilter(bool enableAutoFilter, uint8_t settlingCfg, uint8_t cutoffCfg) 00946 { 00947 uint8_t dcfiltCfg = 0; 00948 00949 if(!enableAutoFilter) 00950 { 00951 // set "freeze coeff" bit 00952 dcfiltCfg |= (1 << DCFILT_CFG_DCFILT_FREEZE_COEFF); 00953 } 00954 00955 dcfiltCfg |= settlingCfg << DCFILT_CFG_DCFILT_BW_SETTLE; 00956 dcfiltCfg |= cutoffCfg << DCFILT_CFG_DCFILT_BW; 00957 00958 writeRegister(Register::DCFILT_CFG, dcfiltCfg); 00959 } 00960 00961 void CC1200::configureSyncWord(uint32_t syncWord, CC1200::SyncMode mode, uint8_t syncThreshold) 00962 { 00963 // program sync word registers 00964 std::array<uint8_t, 4> syncWordRegisters ={ 00965 static_cast<uint8_t>((syncWord >> 24) & 0xFF), 00966 static_cast<uint8_t>((syncWord >> 16) & 0xFF), 00967 static_cast<uint8_t>((syncWord >> 8) & 0xFF), 00968 static_cast<uint8_t>(syncWord & 0xFF) 00969 }; 00970 writeRegisters(Register::SYNC3, syncWordRegisters); 00971 00972 // program sync word cfg 00973 writeRegister(Register::SYNC_CFG1, (static_cast<uint8_t>(mode) << SYNC_CFG1_SYNC_MODE) | (syncThreshold << SYNC_CFG1_SYNC_THR)); 00974 } 00975 00976 bool CC1200::isFSLocked() 00977 { 00978 return readRegister(ExtRegister::FSCAL_CTRL) & (1 << FSCAL_CTRL_LOCK); 00979 } 00980 00981 void CC1200::configurePreamble(uint8_t preambleLengthCfg, uint8_t preambleFormatCfg) 00982 { 00983 uint8_t preambleCfg1 = 0; 00984 preambleCfg1 |= preambleLengthCfg << PREAMBLE_CFG1_NUM_PREAMBLE; 00985 preambleCfg1 |= preambleFormatCfg << PREAMBLE_CFG1_PREAMBLE_WORD; 00986 writeRegister(Register::PREAMBLE_CFG1, preambleCfg1); 00987 00988 #if CC1200_DEBUG 00989 debugStream->printf("Preamble length CFG set to 0x%" PRIx8 "\n", preambleLengthCfg); 00990 #endif 00991 } 00992 00993 void CC1200::setPARampRate(uint8_t firstRampLevel, uint8_t secondRampLevel, CC1200::RampTime rampTime) 00994 { 00995 // enable PA ramping 00996 uint8_t paCfg1Val = readRegister(Register::PA_CFG1); 00997 paCfg1Val |= 1 << PA_CFG1_PA_RAMP_SHAPE_EN; 00998 writeRegister(Register::PA_CFG1, paCfg1Val); 00999 01000 // configure properties 01001 uint8_t paCfg0Val = 0; 01002 paCfg0Val |= (firstRampLevel << PA_CFG0_FIRST_IPL); 01003 paCfg0Val |= (secondRampLevel << PA_CFG0_SECOND_IPL); 01004 paCfg0Val |= (static_cast<uint8_t>(rampTime) << PA_CFG0_RAMP_SHAPE); 01005 01006 writeRegister(Register::PA_CFG0, paCfg0Val); 01007 } 01008 01009 void CC1200::disablePARamping() 01010 { 01011 uint8_t paCfg1Val = readRegister(Register::PA_CFG1); 01012 paCfg1Val &= ~(1 << PA_CFG1_PA_RAMP_SHAPE_EN); 01013 writeRegister(Register::PA_CFG1, paCfg1Val); 01014 } 01015 01016 void CC1200::setAGCReferenceLevel(uint8_t level) 01017 { 01018 writeRegister(Register::AGC_REF, level); 01019 } 01020 01021 void CC1200::setAGCSyncBehavior(CC1200::SyncBehavior behavior) 01022 { 01023 uint8_t agcCfg3Val = readRegister(Register::AGC_CFG3); 01024 agcCfg3Val &= ~(0b111 << AGC_CFG3_AGC_SYNC_BEHAVIOUR); 01025 agcCfg3Val |= static_cast<uint8_t>(behavior) << AGC_CFG3_AGC_SYNC_BEHAVIOUR; 01026 writeRegister(Register::AGC_CFG3, agcCfg3Val); 01027 } 01028 01029 void CC1200::setAGCGainTable(CC1200::GainTable table, uint8_t minGainIndex, uint8_t maxGainIndex) 01030 { 01031 uint8_t agcCfg3Val = readRegister(Register::AGC_CFG3); 01032 uint8_t agcCfg2Val = readRegister(Register::AGC_CFG2); 01033 01034 agcCfg3Val &= ~(0b11111 << AGC_CFG3_AGC_MIN_GAIN); 01035 agcCfg2Val &= ~(0b11 << AGC_CFG2_FE_PERFORMANCE_MODE); 01036 agcCfg2Val &= ~(0b11111 << AGC_CFG2_AGC_MAX_GAIN); 01037 01038 agcCfg3Val |= minGainIndex << AGC_CFG3_AGC_MIN_GAIN; 01039 agcCfg2Val |= static_cast<uint8_t>(table) << AGC_CFG2_FE_PERFORMANCE_MODE; 01040 agcCfg2Val |= maxGainIndex << AGC_CFG2_AGC_MAX_GAIN; 01041 01042 writeRegister(Register::AGC_CFG3, agcCfg3Val); 01043 writeRegister(Register::AGC_CFG2, agcCfg2Val); 01044 } 01045 01046 void CC1200::setAGCHysteresis(uint8_t hysteresisCfg) 01047 { 01048 uint8_t agcCfg0Val = readRegister(Register::AGC_CFG0); 01049 agcCfg0Val &= ~(0b11 << AGC_CFG0_AGC_HYST_LEVEL); 01050 agcCfg0Val |= hysteresisCfg << AGC_CFG0_AGC_HYST_LEVEL; 01051 writeRegister(Register::AGC_CFG0, agcCfg0Val); 01052 } 01053 01054 void CC1200::setAGCSlewRate(uint8_t slewrateCfg) 01055 { 01056 uint8_t agcCfg0Val = readRegister(Register::AGC_CFG0); 01057 agcCfg0Val &= ~(0b11 << AGC_CFG0_AGC_SLEWRATE_LIMIT); 01058 agcCfg0Val |= slewrateCfg << AGC_CFG0_AGC_SLEWRATE_LIMIT; 01059 writeRegister(Register::AGC_CFG0, agcCfg0Val); 01060 } 01061 01062 void CC1200::setAGCSettleWait(uint8_t settleWaitCfg) 01063 { 01064 uint8_t agcCfg1Val = readRegister(Register::AGC_CFG1); 01065 agcCfg1Val &= ~(0b111 << AGC_CFG1_AGC_SETTLE_WAIT); 01066 agcCfg1Val |= (settleWaitCfg << AGC_CFG1_AGC_SETTLE_WAIT); 01067 writeRegister(Register::AGC_CFG1, agcCfg1Val); 01068 } 01069 01070 float CC1200::getRSSIRegister() 01071 { 01072 uint8_t rssi1Val = readRegister(ExtRegister::RSSI1); 01073 uint8_t rssi0Val = readRegister(ExtRegister::RSSI0); 01074 01075 if(!(rssi0Val & (1 << RSSI0_RSSI_VALID))) 01076 { 01077 // no valid measurement 01078 return NAN; 01079 } 01080 01081 // first convert to two's compliment number 01082 int16_t rssiInt = 0; 01083 rssiInt |= (rssi0Val >> RSSI0_RSSI_3_0) & 0b1111; 01084 rssiInt |= rssi1Val << 4; 01085 01086 if(rssi1Val & 0x80) 01087 { 01088 // negative number, sign extend from 12 to 16 bits 01089 rssiInt |= (0b1111 << 12); 01090 } 01091 01092 //debugStream->printf("Approx RSSI: %" PRIi8 ", exact RSSI: %f\n", static_cast<int8_t>(rssi1Val), static_cast<float>(rssiInt) * 0.0625f); 01093 01094 return static_cast<float>(rssiInt) * 0.0625f; // conversion factor given in datasheet 01095 } 01096 01097 void CC1200::setRSSIOffset(int8_t adjust) 01098 { 01099 writeRegister(Register::AGC_GAIN_ADJUST, static_cast<uint8_t>(adjust)); 01100 } 01101 01102 uint8_t CC1200::getLQIRegister() 01103 { 01104 return readRegister(ExtRegister::LQI_VAL) & 0b1111111; 01105 } 01106 01107 void CC1200::setIFCfg(IFCfg value, bool enableIQIC) 01108 { 01109 // make sure prerequisites have been run 01110 MBED_ASSERT(radioFreqHz > 0); 01111 MBED_ASSERT(adcCicDecimation > 0 && currentRXFilterBW > 0); 01112 01113 uint8_t ifMixCfg = readRegister(ExtRegister::IF_MIX_CFG); 01114 ifMixCfg &= ~(0b111 << IF_MIX_CFG_CMIX_CFG); 01115 ifMixCfg |= (static_cast<uint8_t>(value) << IF_MIX_CFG_CMIX_CFG); 01116 writeRegister(ExtRegister::IF_MIX_CFG, ifMixCfg); 01117 01118 float effectiveIF; 01119 01120 // calculate effective IF value 01121 if(value == IFCfg::ZERO) 01122 { 01123 effectiveIF = radioFreqHz; 01124 } 01125 else 01126 { 01127 int32_t dividerValue = 0; 01128 switch(value) 01129 { 01130 case IFCfg::NEGATIVE_DIV_4: dividerValue = -4; break; 01131 case IFCfg::NEGATIVE_DIV_6: dividerValue = -6; break; 01132 case IFCfg::NEGATIVE_DIV_8: dividerValue = -8; break; 01133 case IFCfg::POSITIVE_DIV_4: dividerValue = 4; break; 01134 case IFCfg::POSITIVE_DIV_6: dividerValue = 6; break; 01135 case IFCfg::POSITIVE_DIV_8: dividerValue = 8; break; 01136 default: break; 01137 } 01138 01139 // formula from IF_MIX_CFG register description 01140 effectiveIF = (CC1200_OSC_FREQ / static_cast<float>(adcCicDecimation * dividerValue)) * 1000; 01141 } 01142 01143 uint8_t iqicValue = readRegister(Register::IQIC); 01144 if(enableIQIC && effectiveIF > currentRXFilterBW) 01145 { 01146 iqicValue |= (1 << IQIC_IQIC_EN); 01147 } 01148 else 01149 { 01150 iqicValue &= ~(1 << IQIC_IQIC_EN); 01151 } 01152 writeRegister(Register::IQIC, iqicValue); 01153 01154 #if CC1200_DEBUG 01155 debugStream->printf("Setting IF Mix Cfg to 0x%" PRIx8 " and IQIC_EN to %d\n", static_cast<uint8_t>(value), 01156 !!(iqicValue & (1 << IQIC_IQIC_EN))); // note: double ! used to convert boolean to either 1 or 0. 01157 debugStream->printf("This yields an actual IF of %.00f\n", effectiveIF); 01158 #endif 01159 } 01160 01161 uint8_t CC1200::readRegister(CC1200::Register reg) 01162 { 01163 spi.select(); 01164 loadStatusByte(spi.write(CC1200_READ | static_cast<uint8_t>(reg))); 01165 uint8_t regValue = spi.write(0); 01166 spi.deselect(); 01167 01168 #if CC1200_REGISTER_LEVEL_DEBUG 01169 debugStream->printf("Read register 0x%" PRIx8 " -> 0x%" PRIx8 "\n", static_cast<uint8_t>(reg), regValue); 01170 #endif 01171 01172 return regValue; 01173 } 01174 01175 void CC1200::writeRegister(Register reg, uint8_t value) 01176 { 01177 spi.select(); 01178 loadStatusByte(spi.write(CC1200_WRITE | static_cast<uint8_t>(reg))); 01179 spi.write(value); 01180 spi.deselect(); 01181 01182 #if CC1200_REGISTER_LEVEL_DEBUG 01183 debugStream->printf("Wrote register 0x%" PRIx8 " <- 0x%" PRIx8 "\n", static_cast<uint8_t>(reg), value); 01184 #endif 01185 } 01186 01187 void CC1200::writeRegisters(CC1200::Register startReg, uint8_t const *values, size_t numRegisters) 01188 { 01189 spi.select(); 01190 loadStatusByte(spi.write(CC1200_WRITE | CC1200_BURST | static_cast<uint8_t>(startReg))); 01191 01192 for(size_t byteIndex = 0; byteIndex < numRegisters; ++byteIndex) 01193 { 01194 spi.write(values[byteIndex]); 01195 } 01196 spi.deselect(); 01197 01198 #if CC1200_REGISTER_LEVEL_DEBUG 01199 for(size_t byteIndex = 0; byteIndex < numRegisters; ++byteIndex) 01200 { 01201 debugStream->printf("Wrote register 0x%" PRIx8 " <- 0x%" PRIx8 "\n", 01202 static_cast<uint8_t>(static_cast<uint8_t>(startReg) + byteIndex), 01203 values[byteIndex]); 01204 } 01205 #endif 01206 } 01207 01208 void CC1200::loadStatusByte(uint8_t status) 01209 { 01210 chipReady = !(status >> 7); 01211 state = static_cast<State>((status >> 4) & 0x7); 01212 01213 #if CC1200_REGISTER_LEVEL_DEBUG 01214 debugStream->printf("Updated status, state = 0x%" PRIx8 " ready = %s\n", static_cast<uint8_t>(state), chipReady ? "true" : "false"); 01215 #endif 01216 } 01217 01218 uint8_t CC1200::readRegister(CC1200::ExtRegister reg) 01219 { 01220 spi.select(); 01221 loadStatusByte(spi.write(CC1200_READ | CC1200_EXT_ADDR)); 01222 spi.write(static_cast<uint8_t>(reg)); 01223 uint8_t regValue = spi.write(0); 01224 spi.deselect(); 01225 01226 #if CC1200_REGISTER_LEVEL_DEBUG 01227 debugStream->printf("Read ext register 0x%" PRIx8 " -> 0x%" PRIx8 "\n", static_cast<uint8_t>(reg), regValue); 01228 #endif 01229 01230 return regValue; 01231 } 01232 01233 void CC1200::writeRegister(CC1200::ExtRegister reg, uint8_t value) 01234 { 01235 spi.select(); 01236 loadStatusByte(spi.write(CC1200_WRITE | CC1200_EXT_ADDR)); 01237 spi.write(static_cast<uint8_t>(reg)); 01238 spi.write(value); 01239 spi.deselect(); 01240 01241 #if CC1200_REGISTER_LEVEL_DEBUG 01242 debugStream->printf("Wrote ext register 0x%" PRIx8 " <- 0x%" PRIx8 "\n", static_cast<uint8_t>(reg), value); 01243 #endif 01244 } 01245 01246 void CC1200::writeRegisters(CC1200::ExtRegister startReg, uint8_t const *values, size_t numRegisters) 01247 { 01248 spi.select(); 01249 loadStatusByte(spi.write(CC1200_WRITE | CC1200_BURST | CC1200_EXT_ADDR)); 01250 spi.write(static_cast<uint8_t>(startReg)); 01251 01252 for(size_t byteIndex = 0; byteIndex < numRegisters; ++byteIndex) 01253 { 01254 spi.write(values[byteIndex]); 01255 } 01256 spi.deselect(); 01257 01258 #if CC1200_REGISTER_LEVEL_DEBUG 01259 for(size_t byteIndex = 0; byteIndex < numRegisters; ++byteIndex) 01260 { 01261 debugStream->printf("Wrote extended register 0x%" PRIx8 " <- 0x%" PRIx8 "\n", 01262 static_cast<uint8_t>(static_cast<uint8_t>(startReg) + byteIndex), 01263 values[byteIndex]); 01264 } 01265 #endif 01266 } 01267 01268 void CC1200::sendCommand(CC1200::Command command) 01269 { 01270 spi.select(); 01271 loadStatusByte(spi.write(static_cast<uint8_t>(command))); 01272 spi.deselect(); 01273 01274 #if CC1200_REGISTER_LEVEL_DEBUG 01275 debugStream->printf("Sent SPI command 0x%" PRIx8 "\n", static_cast<uint8_t>(command)); 01276 #endif 01277 } 01278 01279 uint8_t CC1200::readRXFIFOByte(uint8_t address) 01280 { 01281 spi.select(); 01282 loadStatusByte(spi.write(CC1200_READ | CC1200_MEM_ACCESS)); 01283 spi.write(CC1200_RX_FIFO | address); 01284 int value = spi.write(0); 01285 spi.deselect(); 01286 01287 #if CC1200_REGISTER_LEVEL_DEBUG 01288 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); 01289 #endif 01290 01291 return value; 01292 }
Generated on Wed Jul 13 2022 05:17:38 by 1.7.2