Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: CC1200-MorseEncoder CC1200-Examples
Revision 5:d22a8885800b, committed 2021-05-03
- Comitter:
- Jamie Smith
- Date:
- Mon May 03 02:41:34 2021 -0700
- Parent:
- 4:c609cc7c9ea7
- Commit message:
- Update to v1.2
Changed in this revision
--- a/CC1200.cpp Fri Aug 28 15:39:31 2020 -0700 +++ b/CC1200.cpp Mon May 03 02:41:34 2021 -0700 @@ -12,7 +12,7 @@ #include <array> // change to 1 to print debug info -#define CC1200_DEBUG 0 +#define CC1200_DEBUG 1 // change to 1 to print register read/write level debug info #define CC1200_REGISTER_LEVEL_DEBUG 0 @@ -53,6 +53,9 @@ // requires streaming bytes in during the transmission, which would make things complicated. #define MAX_PACKET_LENGTH 128 +// Length of the status bytes that can be appended to packets +#define PACKET_STATUS_LEN 2U + // utility function: compile-time power calculator. // Works on all signed and unsigned integer types for T. // from: http://prosepoetrycode.potterpcs.net/2015/07/a-simple-constexpr-power-function-c/ @@ -109,7 +112,7 @@ if(timeoutTimer.elapsed_time() > resetTimeout) { debugStream->printf("Timeout waiting for ready response from CC1200\n"); - return false; + break; } } @@ -205,7 +208,12 @@ if(_packetMode == PacketMode::FIXED_LENGTH) { - return bytesReceived >= _packetTotalLength; + return bytesReceived >= _packetTotalLength + (appendStatusEnabled ? PACKET_STATUS_LEN : 0); + } + else if(_packetMode == PacketMode::INFINITE_LENGTH) + { + // Any amount of bytes constitutes a packet. + return bytesReceived > 0; } else // _packetMode == PacketMode::VARIABLE_LENGTH { @@ -218,7 +226,7 @@ uint8_t packetLen = readRegister(ExtRegister::RXFIFO_PRE_BUF); // if we have received a full packet's worth of bytes, then we have received a full packet. - return bytesReceived >= static_cast<size_t>(packetLen + 1); // Add one because length field does not include itself + return bytesReceived >= static_cast<size_t>(packetLen + 1 /* Add one because length field does not include itself */) + (appendStatusEnabled ? PACKET_STATUS_LEN : 0); } } @@ -247,6 +255,19 @@ buffer[byteIndex] = currByte; } } + + if(appendStatusEnabled) + { + uint8_t statusBytes[PACKET_STATUS_LEN]; + for(size_t byteIndex = 0; byteIndex < PACKET_STATUS_LEN; ++byteIndex) + { + statusBytes[byteIndex] = spi.write(0); + } + + lastRSSI = statusBytes[0]; + lastLQI = statusBytes[1] & 0b01111111; + } + spi.deselect(); #if CC1200_REGISTER_LEVEL_DEBUG @@ -261,6 +282,115 @@ return dataLen; } +size_t CC1200::writeStream(const char *buffer, size_t count) +{ + size_t freeBytes = CC1200_FIFO_SIZE - getTXFIFOLen(); + + /*if(state == State::TX) + { + if(freeBytes > 0) + { + freeBytes--; + } + }*/ + + size_t bytesToWrite = std::min(freeBytes, count); + + if(bytesToWrite == 0) + { + return 0; + } + + spi.select(); + loadStatusByte(spi.write(CC1200_ENQUEUE_TX_FIFO | CC1200_BURST)); + for(size_t byteIndex = 0; byteIndex < bytesToWrite; ++byteIndex) + { + spi.write(buffer[byteIndex]); + } + spi.deselect(); + +#if CC1200_REGISTER_LEVEL_DEBUG + debugStream->printf("%zu bytes were free, wrote stream of data length %zu:", freeBytes, bytesToWrite); + for(size_t byteIndex = 0; byteIndex < bytesToWrite; ++byteIndex) + { + debugStream->printf(" %02" PRIx8, buffer[byteIndex]); + } + debugStream->printf("\n"); +#endif + + return bytesToWrite; +} + +bool CC1200::writeStreamBlocking(const char *buffer, size_t count) +{ + //size_t origCount = count; + size_t bufferOffset = 0; + while(state == State::TX && count > 0) + { + size_t bytesWritten = writeStream(buffer + bufferOffset, count); + count -= bytesWritten; + bufferOffset += bytesWritten; + } + + //debugStream->printf("Read stream of data length %zu\n:", origCount); + + return count == 0; +} + +size_t CC1200::readStream(char *buffer, size_t maxLen) +{ + size_t bytesToRead = std::min(maxLen, getRXFIFOLen()); + if(bytesToRead == 0) + { + return 0; + } + + // burst read from RX FIFO + spi.select(); + loadStatusByte(spi.write(CC1200_DEQUEUE_RX_FIFO | CC1200_BURST)); + for(size_t byteIndex = 0; byteIndex < bytesToRead; ++byteIndex) + { + buffer[byteIndex] = spi.write(0); + } + spi.deselect(); + +#if CC1200_REGISTER_LEVEL_DEBUG + debugStream->printf("Read stream of data length %zu:", bytesToRead); + for(size_t byteIndex = 0; byteIndex < bytesToRead; ++byteIndex) + { + debugStream->printf(" %" PRIx8, buffer[byteIndex]); + } + debugStream->printf("\n"); +#endif + + return bytesToRead; +} + +bool CC1200::readStreamBlocking(char *buffer, size_t count, std::chrono::microseconds timeout) +{ + //size_t origCount = count; + Timer timeoutTimer; + + if(timeout > 0us) + { + timeoutTimer.start(); + } + + size_t bufferOffset = 0; + while((timeoutTimer.elapsed_time() < timeout || timeout == 0us) && state == State::RX && count > 0) + { + size_t bytesRead = readStream(buffer + bufferOffset, count); + count -= bytesRead; + bufferOffset += bytesRead; + } + + //debugStream->printf("Read stream of data length %zu, first %" PRIx8 " last %" PRIx8 "\n:", origCount, + // buffer[0], buffer[origCount - 1]); + + return count == 0; +} + + // helper function: convert a state to the bits for RXOFF_MODE and TXOFF_MODE inline uint8_t getOffModeBits(CC1200::State state) { @@ -352,7 +482,7 @@ writeRegister(Register::MDMCFG0, mdmCfg0); } -void CC1200::setPacketMode(PacketMode mode) +void CC1200::setPacketMode(PacketMode mode, bool appendStatus) { _packetMode = mode; @@ -367,14 +497,31 @@ // disable packet length limit writeRegister(Register::PKT_LEN, MAX_PACKET_LENGTH); } - else + else if(mode == PacketMode::FIXED_LENGTH) { // reset to selected fixed lengths setPacketLength(_packetByteLength, _packetBitLength); } + else + { + // Infinite length packets, PKT_LEN register is a don't care. + } + + // set append status + appendStatusEnabled = appendStatus; + uint8_t pktCfg1 = readRegister(Register::PKT_CFG1); + if(appendStatus) + { + pktCfg1 |= 1 << PKT_CFG1_APPEND_STATUS; + } + else + { + pktCfg1 &= ~(1 << PKT_CFG1_APPEND_STATUS); + } + writeRegister(Register::PKT_CFG1, pktCfg1); } -void CC1200::setPacketLength(uint8_t length, uint8_t bitLength) +void CC1200::setPacketLength(uint16_t length, uint8_t bitLength) { _packetByteLength = length; _packetBitLength = bitLength; @@ -386,7 +533,15 @@ _packetTotalLength++; } - writeRegister(Register::PKT_LEN, _packetByteLength); + if(_packetTotalLength == 256) + { + // Length byte of 0 indicates 256 bytes + writeRegister(Register::PKT_LEN, 0); + } + else + { + writeRegister(Register::PKT_LEN, _packetByteLength); + } uint8_t pktCfg0 = readRegister(Register::PKT_CFG0); pktCfg0 &= ~(0b111 << PKT_CFG0_PKT_BIT_LEN); @@ -565,6 +720,10 @@ paCfg1 &= ~(0b111111 << PA_CFG1_PA_POWER_RAMP); paCfg1 |= actualPowerRamp << PA_CFG1_PA_POWER_RAMP; writeRegister(Register::PA_CFG1, paCfg1); + +#if CC1200_DEBUG + debugStream->printf("Output power set to %.01f dBm\n", outPower); +#endif } const float CC1200::ASK_MIN_POWER_OFF = -17.5f; @@ -617,7 +776,13 @@ writeRegister(ExtRegister::FS_DVC0,0x17); writeRegister(ExtRegister::IFAMP,0x09); } - else if(band == Band::BAND_410_480MHz || band == Band::BAND_164_192MHz) + else if(band == Band::BAND_410_480MHz) + { + writeRegister(ExtRegister::FS_DIG0,0xA3); + writeRegister(ExtRegister::FS_DVC0,0x0F); + writeRegister(ExtRegister::IFAMP,0x0D); + } + else if(band == Band::BAND_164_192MHz) { writeRegister(ExtRegister::FS_DIG0,0x50); writeRegister(ExtRegister::FS_DVC0,0x0F); @@ -626,7 +791,7 @@ else { // TI doesn't make settings public for the other radio bands. - // Let's take a guess and use the 480-164MHz values. + // Let's take a guess and use the 164-192MHz values. writeRegister(ExtRegister::FS_DIG0,0x50); writeRegister(ExtRegister::FS_DVC0,0x0F); writeRegister(ExtRegister::IFAMP,0x0D); @@ -648,25 +813,24 @@ writeRegister(Register::FS_CFG, (1 << FS_CFG_FS_LOCK_EN) | (static_cast<uint8_t>(band) << FS_CFG_FSD_BANDSELECT)); // equation derived from user guide section 9.12 - float exactFreqValue = (twoToThe16 * frequencyHz * static_cast<float>(loDividerValue)) / CC1200_OSC_FREQ; - uint32_t actualFreqValue = static_cast<uint32_t>(std::min(static_cast<float>(maxValue24Bits), exactFreqValue)); + float exactFreqRegValue = (twoToThe16 * frequencyHz * static_cast<float>(loDividerValue)) / CC1200_OSC_FREQ; + uint32_t actualFreqRegValue = static_cast<uint32_t>(std::min(static_cast<float>(maxValue24Bits), exactFreqRegValue)); // program frequency registers std::array<uint8_t, 3> freqRegisters ={ - static_cast<uint8_t>((actualFreqValue >> 16) & 0xFF), - static_cast<uint8_t>((actualFreqValue >> 8) & 0xFF), - static_cast<uint8_t>((actualFreqValue & 0xFF)) + static_cast<uint8_t>((actualFreqRegValue >> 16) & 0xFF), + static_cast<uint8_t>((actualFreqRegValue >> 8) & 0xFF), + static_cast<uint8_t>((actualFreqRegValue & 0xFF)) }; writeRegisters(ExtRegister::FREQ2, freqRegisters); + // sanity check: calculate actual frequency + radioFreqHz = (static_cast<float>(actualFreqRegValue) * CC1200_OSC_FREQ) / (twoToThe16 * static_cast<float>(loDividerValue)); + #if CC1200_DEBUG debugStream->printf("Setting radio frequency, requested %.00f Hz, setting FREQ = 0x%" PRIx32 "\n", - frequencyHz, actualFreqValue); - - // sanity check: calculate actual frequency - float actualFrequency = (static_cast<float>(actualFreqValue) * CC1200_OSC_FREQ) / (twoToThe16 * static_cast<float>(loDividerValue)); - - debugStream->printf("This yields an actual frequency of %.00f Hz\n", actualFrequency); + frequencyHz, actualFreqRegValue); + debugStream->printf("This yields an actual frequency of %.00f Hz\n", radioFreqHz); #endif } @@ -677,7 +841,7 @@ return CC1200_OSC_FREQ / (static_cast<float>(adcDecimation) * static_cast<float>(cicDecimation) * 2); } -void CC1200::setRXFilterBandwidth(float bandwidthHz) +void CC1200::setRXFilterBandwidth(float bandwidthHz, bool preferHigherCICDec) { // settings that the chip supports const uint8_t possibleADCDecimations[] = {12, 24, 48}; // indexes in this array represent the register value @@ -715,7 +879,7 @@ { float thisDecimationError = std::abs(bandwidthHz - calcReceiveBandwidth(possibleADCDecimations[adcDecimationIndex], actualBBDecimations[adcDecimationIndex])); - if(thisDecimationError <= bestDecimationError) + if((preferHigherCICDec && thisDecimationError <= bestDecimationError) || (!preferHigherCICDec && thisDecimationError < bestDecimationError)) { bestDecimationError = thisDecimationError; bestDecimationIndex = adcDecimationIndex; @@ -769,12 +933,12 @@ writeRegister(Register::SYNC_CFG0, syncCfg0Value); adcCicDecimation = possibleADCDecimations[bestDecimationIndex]; + currentRXFilterBW = calcReceiveBandwidth(possibleADCDecimations[bestDecimationIndex], actualBBDecimations[bestDecimationIndex]); #if CC1200_DEBUG debugStream->printf("Setting BB decimation to %" PRIu8 " and ADC decimation to %" PRIu8 "\n", actualBBDecimations[bestDecimationIndex], possibleADCDecimations[bestDecimationIndex]); - debugStream->printf("This yields an actual RX filter BW of %.00f\n", - calcReceiveBandwidth(possibleADCDecimations[bestDecimationIndex], actualBBDecimations[bestDecimationIndex])); + debugStream->printf("This yields an actual RX filter BW of %.00f\n", currentRXFilterBW); #endif } @@ -794,22 +958,6 @@ writeRegister(Register::DCFILT_CFG, dcfiltCfg); } -void CC1200::setIQMismatchCompensationEnabled(bool enabled) -{ - uint8_t iqicValue = readRegister(Register::IQIC); - - if(enabled) - { - iqicValue |= (1 << IQIC_IQIC_EN); - } - else - { - iqicValue &= ~(1 << IQIC_IQIC_EN); - } - - writeRegister(Register::IQIC, iqicValue); -} - void CC1200::configureSyncWord(uint32_t syncWord, CC1200::SyncMode mode, uint8_t syncThreshold) { // program sync word registers @@ -836,6 +984,10 @@ preambleCfg1 |= preambleLengthCfg << PREAMBLE_CFG1_NUM_PREAMBLE; preambleCfg1 |= preambleFormatCfg << PREAMBLE_CFG1_PREAMBLE_WORD; writeRegister(Register::PREAMBLE_CFG1, preambleCfg1); + +#if CC1200_DEBUG + debugStream->printf("Preamble length CFG set to 0x%" PRIx8 "\n", preambleLengthCfg); +#endif } void CC1200::setPARampRate(uint8_t firstRampLevel, uint8_t secondRampLevel, CC1200::RampTime rampTime) @@ -883,7 +1035,7 @@ agcCfg2Val &= ~(0b11 << AGC_CFG2_FE_PERFORMANCE_MODE); agcCfg2Val &= ~(0b11111 << AGC_CFG2_AGC_MAX_GAIN); - agcCfg3Val |= maxGainIndex << AGC_CFG3_AGC_MIN_GAIN; + agcCfg3Val |= minGainIndex << AGC_CFG3_AGC_MIN_GAIN; agcCfg2Val |= static_cast<uint8_t>(table) << AGC_CFG2_FE_PERFORMANCE_MODE; agcCfg2Val |= maxGainIndex << AGC_CFG2_AGC_MAX_GAIN; @@ -907,12 +1059,103 @@ writeRegister(Register::AGC_CFG0, agcCfg0Val); } -void CC1200::setIFMixCFG(uint8_t value) +void CC1200::setAGCSettleWait(uint8_t settleWaitCfg) +{ + uint8_t agcCfg1Val = readRegister(Register::AGC_CFG1); + agcCfg1Val &= ~(0b111 << AGC_CFG1_AGC_SETTLE_WAIT); + agcCfg1Val |= (settleWaitCfg << AGC_CFG1_AGC_SETTLE_WAIT); + writeRegister(Register::AGC_CFG1, agcCfg1Val); +} + +float CC1200::getRSSIRegister() { + uint8_t rssi1Val = readRegister(ExtRegister::RSSI1); + uint8_t rssi0Val = readRegister(ExtRegister::RSSI0); + + if(!(rssi0Val & (1 << RSSI0_RSSI_VALID))) + { + // no valid measurement + return NAN; + } + + // first convert to two's compliment number + int16_t rssiInt = 0; + rssiInt |= (rssi0Val >> RSSI0_RSSI_3_0) & 0b1111; + rssiInt |= rssi1Val << 4; + + if(rssi1Val & 0x80) + { + // negative number, sign extend from 12 to 16 bits + rssiInt |= (0b1111 << 12); + } + + //debugStream->printf("Approx RSSI: %" PRIi8 ", exact RSSI: %f\n", static_cast<int8_t>(rssi1Val), static_cast<float>(rssiInt) * 0.0625f); + + return static_cast<float>(rssiInt) * 0.0625f; // conversion factor given in datasheet +} + +void CC1200::setRSSIOffset(int8_t adjust) +{ + writeRegister(Register::AGC_GAIN_ADJUST, static_cast<uint8_t>(adjust)); +} + +uint8_t CC1200::getLQIRegister() +{ + return readRegister(ExtRegister::LQI_VAL) & 0b1111111; +} + +void CC1200::setIFCfg(IFCfg value, bool enableIQIC) +{ + // make sure prerequisites have been run + MBED_ASSERT(radioFreqHz > 0); + MBED_ASSERT(adcCicDecimation > 0 && currentRXFilterBW > 0); + uint8_t ifMixCfg = readRegister(ExtRegister::IF_MIX_CFG); ifMixCfg &= ~(0b111 << IF_MIX_CFG_CMIX_CFG); - ifMixCfg |= (value << IF_MIX_CFG_CMIX_CFG); + ifMixCfg |= (static_cast<uint8_t>(value) << IF_MIX_CFG_CMIX_CFG); writeRegister(ExtRegister::IF_MIX_CFG, ifMixCfg); + + float effectiveIF; + + // calculate effective IF value + if(value == IFCfg::ZERO) + { + effectiveIF = radioFreqHz; + } + else + { + int32_t dividerValue = 0; + switch(value) + { + case IFCfg::NEGATIVE_DIV_4: dividerValue = -4; break; + case IFCfg::NEGATIVE_DIV_6: dividerValue = -6; break; + case IFCfg::NEGATIVE_DIV_8: dividerValue = -8; break; + case IFCfg::POSITIVE_DIV_4: dividerValue = 4; break; + case IFCfg::POSITIVE_DIV_6: dividerValue = 6; break; + case IFCfg::POSITIVE_DIV_8: dividerValue = 8; break; + default: break; + } + + // formula from IF_MIX_CFG register description + effectiveIF = (CC1200_OSC_FREQ / static_cast<float>(adcCicDecimation * dividerValue)) * 1000; + } + + uint8_t iqicValue = readRegister(Register::IQIC); + if(enableIQIC && effectiveIF > currentRXFilterBW) + { + iqicValue |= (1 << IQIC_IQIC_EN); + } + else + { + iqicValue &= ~(1 << IQIC_IQIC_EN); + } + writeRegister(Register::IQIC, iqicValue); + +#if CC1200_DEBUG + debugStream->printf("Setting IF Mix Cfg to 0x%" PRIx8 " and IQIC_EN to %d\n", static_cast<uint8_t>(value), + !!(iqicValue & (1 << IQIC_IQIC_EN))); // note: double ! used to convert boolean to either 1 or 0. + debugStream->printf("This yields an actual IF of %.00f\n", effectiveIF); +#endif } uint8_t CC1200::readRegister(CC1200::Register reg) @@ -1047,7 +1290,3 @@ return value; } - - - -
--- a/CC1200.h Fri Aug 28 15:39:31 2020 -0700 +++ b/CC1200.h Mon May 03 02:41:34 2021 -0700 @@ -125,6 +125,11 @@ XOSC1 = 0x36, XOSC0 = 0x37, //... + RSSI1 = 0x71, + RSSI0 = 0x72, + MARCSTATE = 0x73, + LQI_VAL = 0x74, + //... FREQOFF_EST1 = 0x77, FREQOFF_EST2 = 0x78, //... @@ -185,8 +190,13 @@ // current symbol rate of the radio float symbolRateSps = 0; - // current ADC CIC decimation of the radio + // current RX filter params uint8_t adcCicDecimation = 0; + float currentRXFilterBW = 0; + + // current RF params + float radioFreqHz; + public: @@ -241,6 +251,8 @@ * * In fixed length mode, the length should be the fixed packet length. * + * The function is not for use with infinite-length mode, use writeStream() instead. + * * Also reads the radio's state. * * @param data @@ -253,6 +265,7 @@ /** * Check whether there is at least one complete packet in the RX FIFO. + * In infinite length mode, this returns true if any data is present at all. * NOTE: An alternate way to do this using hardware is to configure one * of the CC1200's GPIOs as PKT_SYNC_RXTX, then set a falling edge interrupt to receive a packet. * @return @@ -268,6 +281,8 @@ * in the FIFO, *undefined behavior* can occur. An arbitrary amount of data will be read from * the FIFO and garbage may be returned. * + * The function is not for use with infinite-length mode, use readStream() instead. + * * NOTE: A null terminator is NOT added unless it was present in the transmitted data. * Be careful when treating the returned data as a string! * @@ -278,6 +293,78 @@ */ size_t receivePacket(char * buffer, size_t bufferLen); + // Infinite length tx & rx functions + // ------------------------------------------------------------------------------ + + /* + * How to use infinite length from the TX side: + * 1. Place up to 128 bytes of data in the TX FIFO for transmission using writeStream(). + * 2. Enable TX mode using startTX() + * 3. Keep streaming in data using writeStream() writeStreamBlocking() or at least as fast as it is transmitted. + * 4. Disable TX mode when done using idle(). + * + * Take care that the TX fifo never runs completely out of data, or the chip will go into TX FIFO ERROR state. + */ + + /* + * How to use infinite length from the RX side: + * 1. Enable RX mode using startRX(). I'm pretty sure that if sync words are enabled, you must start RX before the transmitter starts transmitting. + * 2. Wait for data to arrive using hasReceivedPacket(). + * 3. Start streaming out data using readStream() or readStreamBlocking(). + * 4. Disable RX mode when done using idle(). + * + * Take care that the RX fifo doesn't become full, or the chip will go into RX FIFO ERROR state. + */ + + /** + * Write a stream of data to the chip. This function is only for use in infinite-length mode. + * As many bytes from the given buffer will be written as can fit in the chip's FIFO. + * If the FIFO is full, this function does nothing. + * + * @param buffer + * @param count + * @return Number of bytes written. + */ + size_t writeStream(const char* buffer, size_t count); + + /** + * Write a stream of data to the chip. This function is only for use in infinite-length mode. + * Will block until all bytes in the given buffer have been written to the TX FIFO, or an error has been + * detected (the radio switches to any state other than TX). + * + * @param buffer + * @param count + * @return True if successful, false if there was an error. + */ + bool writeStreamBlocking(const char* buffer, size_t count); + + /** + * Read up to maxLen bytes into buffer. + * @param buffer + * @param maxLen + * @return How many bytes were actually read. 0 if the RX FIFO was empty. + */ + size_t readStream(char* buffer, size_t maxLen); + + /** + * Read a stream of data from the chip. This function is only for use in infinite-length mode. + * Will block until the buffer was filled, an error has been + * detected (the radio switches to any state other than RX), or the timeout expires. + * + * If false is returned, some data may have been written to the buffer, and the rest will not have been modified. + * + * Note: if using a zero timeout, this function could cause a hang if the transmitter stops transmitting. + * + * @param buffer + * @param count + * @param timeout Timeout, or 0us to disable timeout. + * @return True iff the buffer was completely filled. + */ + bool readStreamBlocking(char* buffer, size_t count, std::chrono::microseconds timeout=0us); + + // State transition configuration + // ------------------------------------------------------------------------------ + /** * Set what state the radio will enter when a packet is received. * @param goodPacket State when a good (CRC pass) packet is received. @@ -349,6 +436,8 @@ enum class PacketMode : uint8_t { + /// Use infinite length transmissions (streaming mode). + INFINITE_LENGTH = 0b10, /// Use fixed length packets. VARIABLE_LENGTH = 0b1, /// Use variable length packets, the length is encoded in the first byte of the packet. @@ -356,10 +445,12 @@ }; /** - * Set the packet mode that the system will use + * Set the packet mode that the system will use. * @param mode + * @param appendStatus Have the radio append a status byte to each packet received. This takes up + * 2 bytes per packet in the RX FIFO, but provides status information about each packet. */ - void setPacketMode(PacketMode mode); + void setPacketMode(PacketMode mode, bool appendStatus = false); /** * Set the packet length when in fixed length packet mode. @@ -367,19 +458,24 @@ * For example, if your packets are 20 bits long, you should set length to 2 bytes and bitLength to * 4 bytes, so that 2 complete bytes + 4 extra bits are transmitted. Buffers used for sending and receiving packets * should then be 3 bytes long. + * + * When appendStatus is disabled, the max length is 256 bytes. When it is enabled, the max length is 254 bytes. * @param length */ - void setPacketLength(uint8_t length, uint8_t bitLength = 0); + void setPacketLength(uint16_t length, uint8_t bitLength = 0); private: // current packet mode PacketMode _packetMode; // current packet length when in fixed length packet mode - uint8_t _packetTotalLength = 0; // length in bytes including final partial byte - uint8_t _packetByteLength = 0; // length in whole bytes + uint16_t _packetTotalLength = 0; // length in bytes including final partial byte + uint16_t _packetByteLength = 0; // length in whole bytes uint8_t _packetBitLength = 0; // extra bit length at end + // Whether the two status bytes are included in each received packet + bool appendStatusEnabled = true; + public: /** @@ -480,8 +576,10 @@ * - SYNC_CFG0.RX_CONFIG_LIMITATION * * @param bandwidthHz the bandwidth in Hz + * @param preferHigherCICDec If there are multiple register value choices, prefer the one with higher CIC decimation + * and lower BB decimation. This is the recommendation of the datasheet but it actually causes transmission to fail in some cases. */ - void setRXFilterBandwidth(float bandwidthHz); + void setRXFilterBandwidth(float bandwidthHz, bool preferHigherCICDec = true); /** * Get the ADC CIC decimation that was calculated by the most recent setRXFilterBandwidth() call. @@ -491,7 +589,7 @@ uint8_t getADCCICDecimation() { return adcCicDecimation; } /** - * Configure the radio's automatic DC offset removal algorithm is enabled. + * Configure the radio's automatic DC offset removal algorithm as enabled. * DC offset correction must be enabled when using zero IF mode, and in my testing * it seems to be important when staying in TX mode for a long time at * higher sample rates. @@ -506,17 +604,32 @@ void configureDCFilter(bool enableAutoFilter, uint8_t settlingCfg, uint8_t cutoffCfg); /** - * Set the IF mixing configuration. + * Possible intermediate frequency values. + * For right now it seems like you have to get these from SmartRF. * See the user guide section on IF_MIX_CFG.CMIX_CFG for details. */ - void setIFMixCFG(uint8_t value); + enum class IFCfg : uint8_t + { + ZERO = 0, // Zero IF. From what I can find, this means samples are taken at the radio frequency. + NEGATIVE_DIV_4 = 0b001, + NEGATIVE_DIV_6 = 0b010, + NEGATIVE_DIV_8 = 0b011, + POSITIVE_DIV_4 = 0b101, + POSITIVE_DIV_6 = 0b110, + POSITIVE_DIV_8 = 0b111 + }; /** - * Set whether the ImageExtinct IQ mismatch compensation logic is enabled. - * This should be disabled if IF < RX filter bandwidth - * @param enabled + * Set the receiver IF mixing configuration. + * See the user guide section on IF_MIX_CFG.CMIX_CFG for details. + * + * You must call *both* setRXFilterBandwidth() and setRadioFrequency() before calling this function. + * + * @param value Divider value to use, or zero-IF + * @param enableIQIC Whether to enable the ImageExtinct IQ mismatch compensation when supported + * (when if IF > RX filter bandwidth). */ - void setIQMismatchCompensationEnabled(bool enabled); + void setIFCfg(IFCfg value, bool enableIQIC); /** * Mode describing the size and setup of the sync word. @@ -654,6 +767,62 @@ */ void setAGCSlewRate(uint8_t slewrateCfg); + /** + * Configure the time that the AGC takes to settle. + * See the register description for AGC_CFG1.AGC_SETTLE_WAIT + * @param settleWaitCfg bytes to write to AGC_CFG1.AGC_SETTLE_WAIT + */ + void setAGCSettleWait(uint8_t settleWaitCfg); + + // Received Signal Strength Indicator (RSSI) and Link Quality Indicator (LQI) functions + // ------------------------------------------------------------------------------ + +private: + // data from packet status bytes + int8_t lastRSSI; + uint8_t lastLQI; + +public: + + /** + * Get the RSSI as of the last packet received. + * Only provides valid data if appendStatus is enabled. + * @return RSSI in dBm, or -128 if no valid RSSI measurement exists. + */ + int8_t getLastRSSI() {return lastRSSI;} + + /** + * Get the current RSSI from the RSSI register. Note: I think + * this might only work while the radio is actively receiving. + * + * @return RSSI in dBm, or NaN if no valid RSSI measurement exists. + */ + float getRSSIRegister(); + + /** + * Set the RSSI gain adjustment. This value is added to the reported RSSI, and also used + * in the calculation of the Carrier Sense (CS) line. + * You have to calibrate this in a lab by feeding in a known amplitude signal, + * see the user manual section 6.9 for details. + */ + void setRSSIOffset(int8_t adjust); + + /** + * Get the LQI from the LQI_VAL register. + * This is a qualitative estimate from 1-128 of how easily a packet can be demodulated. + * Lower is better, but 0 indicates invalid. + * @return + */ + uint8_t getLQIRegister(); + + /** + * Get the LQI as of the last packet received. + * Only provides valid data if appendStatus is enabled. + * This is a qualitative estimate from 1-128 of how easily a packet can be demodulated. + * Lower is better, but 0 indicates invalid. + */ + uint8_t getLastLQI() {return lastLQI;} + // Register level functions // ------------------------------------------------------------------------------
--- a/CC1200Bits.h Fri Aug 28 15:39:31 2020 -0700 +++ b/CC1200Bits.h Mon May 03 02:41:34 2021 -0700 @@ -54,7 +54,7 @@ #define PKT_CFG1_PN9_SWAP_EN 5 #define PKT_CFG1_ADDR_CHECK_CFG 3 #define PKT_CFG1_CRC_CFG 1 -#define PKT_CFG1_APPEND_STATUS +#define PKT_CFG1_APPEND_STATUS 0 #define PKT_CFG0_LENGTH_CONFIG 5 #define PKT_CFG0_PKT_BIT_LEN 2 @@ -127,4 +127,13 @@ #define ASK_CFG_AGC_ASK_BW 6 #define ASK_CFG_ASK_DEPTH 0 +#define RSSI0_RSSI_3_0 3 +#define RSSI0_CARRIER_SENSE 2 +#define RSSI0_CARRIER_SENSE_VALID 1 +#define RSSI0_RSSI_VALID 0 + +#define AGC_CFG1_RSSI_STEP_THR 6 +#define AGC_CFG1_AGC_WIN_SIZE 3 +#define AGC_CFG1_AGC_SETTLE_WAIT 0 + #endif //LIGHTSPEEDRANGEFINDER_CC1200BITS_H