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
CC1200