Jamie Smith / CC1200

Dependents:   CC1200-MorseEncoder CC1200-Examples

Revision:
4:c609cc7c9ea7
Parent:
3:f464b14ce62f
Child:
5:d22a8885800b
diff -r f464b14ce62f -r c609cc7c9ea7 CC1200.cpp
--- a/CC1200.cpp	Mon Aug 10 01:47:24 2020 -0700
+++ b/CC1200.cpp	Fri Aug 28 15:39:31 2020 -0700
@@ -135,13 +135,6 @@
 	// enable CRC but disable status bytes
 	writeRegister(Register::PKT_CFG1, (0b01 << PKT_CFG1_CRC_CFG));
 
-	// configure packet length to adjustable
-	writeRegister(Register::PKT_CFG0, (0b01 << PKT_CFG0_LENGTH_CONFIG));
-
-	// set max packet length
-	writeRegister(Register::PKT_LEN, MAX_PACKET_LENGTH);
-
-
 	return true;
 }
 
@@ -175,7 +168,10 @@
 	// burst write to TX FIFO
 	spi.select();
 	loadStatusByte(spi.write(CC1200_ENQUEUE_TX_FIFO | CC1200_BURST));
-	spi.write(len);
+	if(_packetMode == PacketMode::VARIABLE_LENGTH)
+	{
+		spi.write(len);
+	}
 	for(size_t byteIndex = 0; byteIndex < len; ++byteIndex)
 	{
 		spi.write(data[byteIndex]);
@@ -183,10 +179,14 @@
 	spi.deselect();
 
 #if CC1200_REGISTER_LEVEL_DEBUG
-	debugStream->printf("Wrote packet of data length %zu: %" PRIx8, len, static_cast<uint8_t>(len));
+	debugStream->printf("Wrote packet of data length %zu:", len);
+	if(_packetMode == PacketMode::VARIABLE_LENGTH)
+	{
+		debugStream->printf(" %02" PRIx8, static_cast<uint8_t>(len));
+	}
 	for(size_t byteIndex = 0; byteIndex < len; ++byteIndex)
 	{
-		debugStream->printf(" %" PRIx8, data[byteIndex]);
+		debugStream->printf(" %02" PRIx8, data[byteIndex]);
 	}
 	debugStream->printf("\n");
 #endif
@@ -203,16 +203,23 @@
 		return false;
 	}
 
-	// get value of first byte of the packet, which is the length.
+	if(_packetMode == PacketMode::FIXED_LENGTH)
+	{
+		return bytesReceived >= _packetTotalLength;
+	}
+	else // _packetMode == PacketMode::VARIABLE_LENGTH
+	{
+		// get value of first byte of the packet, which is the length.
 
-	// The datasheet is wrong about this!  It says that the first byte in the RX FIFO can
-	// be found by accessing address RXFIRST via direct fifo access.
-	// However, in my own testing, RXFIRST points to the second entry in the FIFO, and
-	// the first entry must be accessed through RXFIFO_PRE_BUF.
-	uint8_t packetLen = readRegister(ExtRegister::RXFIFO_PRE_BUF);
+		// The datasheet is wrong about this!  It says that the first byte in the RX FIFO can
+		// be found by accessing address RXFIRST via direct fifo access.
+		// However, in my own testing, RXFIRST points to the second entry in the FIFO, and
+		// the first entry must be accessed through RXFIFO_PRE_BUF.
+		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
+		// 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
+	}
 }
 
 size_t CC1200::receivePacket(char *buffer, size_t bufferLen)
@@ -221,8 +228,16 @@
 	spi.select();
 	loadStatusByte(spi.write(CC1200_DEQUEUE_RX_FIFO | CC1200_BURST));
 
-	// first read length byte
-	uint8_t dataLen = spi.write(0);
+	uint8_t dataLen;
+	if(_packetMode == PacketMode::VARIABLE_LENGTH)
+	{
+		// first read length byte
+		dataLen = spi.write(0);
+	}
+	else // _packetMode == PacketMode::FIXED_LENGTH)
+	{
+		dataLen = _packetTotalLength;
+	}
 
 	for(size_t byteIndex = 0; byteIndex < dataLen; ++byteIndex)
 	{
@@ -337,11 +352,65 @@
 	writeRegister(Register::MDMCFG0, mdmCfg0);
 }
 
+void CC1200::setPacketMode(PacketMode mode)
+{
+	_packetMode = mode;
+
+	uint8_t pktCfg0 = readRegister(Register::PKT_CFG0);
+	// set length config field
+	pktCfg0 &= ~(0b11 << PKT_CFG0_LENGTH_CONFIG);
+	pktCfg0 |= static_cast<uint8_t>(mode) << PKT_CFG0_LENGTH_CONFIG;
+	writeRegister(Register::PKT_CFG0, pktCfg0);
+
+	if(mode == PacketMode::VARIABLE_LENGTH)
+	{
+		// disable packet length limit
+		writeRegister(Register::PKT_LEN, MAX_PACKET_LENGTH);
+	}
+	else
+	{
+		// reset to selected fixed lengths
+		setPacketLength(_packetByteLength, _packetBitLength);
+	}
+}
+
+void CC1200::setPacketLength(uint8_t length, uint8_t bitLength)
+{
+	_packetByteLength = length;
+	_packetBitLength = bitLength;
+	_packetTotalLength = _packetByteLength;
+
+	if(bitLength > 0)
+	{
+		// tell the driver to read the extra bits into another byte
+		_packetTotalLength++;
+	}
+
+	writeRegister(Register::PKT_LEN, _packetByteLength);
+
+	uint8_t pktCfg0 = readRegister(Register::PKT_CFG0);
+	pktCfg0 &= ~(0b111 << PKT_CFG0_PKT_BIT_LEN);
+	pktCfg0 |= _packetBitLength << PKT_CFG0_PKT_BIT_LEN;
+	writeRegister(Register::PKT_CFG0, pktCfg0);
+
+#if CC1200_DEBUG
+	debugStream->printf("Set total length to %zu, byte length = %zu, bit length = %" PRIu8 "\n", _packetTotalLength, _packetByteLength, _packetBitLength);
+#endif
+}
+
+void CC1200::setCRCEnabled(bool enabled)
+{
+	uint8_t pktCfg1 = readRegister(Register::PKT_CFG1);
+	pktCfg1 &= ~(0b11 << PKT_CFG1_CRC_CFG);
+	pktCfg1 |= (enabled ? 0b01 : 0b00) << PKT_CFG1_CRC_CFG;
+	writeRegister(Register::PKT_CFG1, pktCfg1);
+}
+
 void CC1200::setModulationFormat(CC1200::ModFormat format)
 {
 	uint8_t modcfgDevE = readRegister(Register::MODCFG_DEV_E);
 	modcfgDevE &= ~(0b111 << MODCFG_DEV_E_MOD_FORMAT);
-	modcfgDevE |= static_cast<uint8_t>(format) << MODCFG_DEV_E_DEV_E;
+	modcfgDevE |= static_cast<uint8_t>(format) << MODCFG_DEV_E_MOD_FORMAT;
 	writeRegister(Register::MODCFG_DEV_E, modcfgDevE);
 }
 
@@ -408,7 +477,6 @@
 	float exactExponent = std::log2(symbolRateSps) - CC1200_OSC_FREQ_LOG2 + 19;
 	// note: 19 comes from log2(2^39) - 20
 	uint8_t actualExponent = static_cast<uint8_t>(std::min(static_cast<float>(maxValue4Bits), exactExponent));
-	// note: 15 comes from the largest number storable in 4 bits
 
 	float exactMantissa;
 	if(actualExponent >= 1)
@@ -433,10 +501,13 @@
 	};
 	writeRegisters(Register::SYMBOL_RATE2, symbolRateRegisters);
 
-	// Calculate upsampler value according to the forumula in its register description
-	float upsamplingFactor = CC1200_OSC_FREQ / (64 * symbolRateSps);
+	// Calculate upsampler value according to the formula in its register description
+	float upsamplingFactor = CC1200_OSC_FREQ / (64 * symbolRateSps); // 2^upsamplerPVal needs to be less than this value
 	uint8_t upsamplerPVal = std::floor(std::log2(upsamplingFactor));
 
+	// prevent low sampling rates from choosing a nonexistent upsampling
+	upsamplerPVal = std::min<uint8_t>(upsamplerPVal, 0b110);
+
 	uint8_t mdmcfg2 = readRegister(ExtRegister::MDMCFG2);
 	mdmcfg2 &= ~(0b111 << MDMCFG2_UPSAMPLER_P);
 	mdmcfg2 |= (upsamplerPVal << MDMCFG2_UPSAMPLER_P);
@@ -444,31 +515,32 @@
 	writeRegister(ExtRegister::MDMCFG2, mdmcfg2);
 
 #if CC1200_DEBUG
-	debugStream->printf("Setting symbol rate, requested %.00f Hz, setting SRATE_E = 0x%" PRIx8 " SRATE_M = 0x%" PRIx32 "\n",
+	debugStream->printf("Setting symbol rate, requested %.03f Hz, setting SRATE_E = 0x%" PRIx8 " SRATE_M = 0x%" PRIx32 "\n",
 						symbolRateHz, actualExponent, actualMantissa);
 
 	// sanity check: calculate actual symbol rate
-	float actualSymbolRateKsps;
+	float actualSymbolRateSps;
 	if(actualExponent == 0)
 	{
-		actualSymbolRateKsps = (static_cast<float>(actualMantissa) * CC1200_OSC_FREQ) / twoToThe38;
+		actualSymbolRateSps = (static_cast<float>(actualMantissa) * CC1200_OSC_FREQ) / twoToThe38;
 	}
 	else
 	{
 
-		actualSymbolRateKsps = ((static_cast<float>(actualMantissa) + twoToThe20) *
-				pow(2.0f,static_cast<float>(actualExponent)) * CC1200_OSC_FREQ)
-				/ twoToThe39;
+		actualSymbolRateSps = ((static_cast<float>(actualMantissa) + twoToThe20) *
+							   pow(2.0f,static_cast<float>(actualExponent)) * CC1200_OSC_FREQ)
+							  / twoToThe39;
 	}
 
-	debugStream->printf("This yields an actual symbol rate of %.00f Hz\n", actualSymbolRateKsps * 1000.0f);
+	debugStream->printf("This yields an actual symbol rate of %.02f Hz\n", actualSymbolRateSps);
 
 	uint8_t actualUpsampling = static_cast<uint8_t>(pow(2.0f, static_cast<float>(upsamplerPVal)));
 	debugStream->printf("Also setting upsampling factor to %" PRIu8 " via UPSAMPLER_P = %" PRIx8 "\n", actualUpsampling, upsamplerPVal);
 #endif
 }
 
-void CC1200::setOutputPower(float outPower)
+// helper function for power setting
+inline uint8_t dBPowerToRegValue(float powerDB)
 {
 	const float minOutputPower = -16.0f;
 
@@ -477,12 +549,17 @@
 	const float maxOutputPower = 14.0f;
 
 	// clamp output power into correct range
-	outPower = std::min(outPower, maxOutputPower);
-	outPower = std::max(outPower, minOutputPower);
+	powerDB = std::min(powerDB, maxOutputPower);
+	powerDB = std::max(powerDB, minOutputPower);
 
 	// this equation derived from user guide section 7.1
-	float exactPowerRamp = (2 * outPower) + 35;
-	uint8_t actualPowerRamp = static_cast<uint8_t>(exactPowerRamp); // round to nearest
+	float exactPowerRamp = (2 * powerDB) + 35;
+	return static_cast<uint8_t>(exactPowerRamp); // round to nearest
+}
+
+void CC1200::setOutputPower(float outPower)
+{
+	uint8_t actualPowerRamp = dBPowerToRegValue(outPower);
 
 	uint8_t paCfg1 = readRegister(Register::PA_CFG1);
 	paCfg1 &= ~(0b111111 << PA_CFG1_PA_POWER_RAMP);
@@ -490,6 +567,30 @@
 	writeRegister(Register::PA_CFG1, paCfg1);
 }
 
+const float CC1200::ASK_MIN_POWER_OFF = -17.5f;
+
+void CC1200::setASKPowers(float maxPower, float minPower)
+{
+	uint8_t maxPowerValue = dBPowerToRegValue(maxPower);
+
+	minPower = std::min(minPower, maxPower);
+	minPower = std::max(minPower, -17.5f);
+
+	// calculate min power using formula derived from manual
+	uint8_t minPowerValue = static_cast<uint8_t>((maxPower - minPower) * 2);
+
+	// write registers
+	uint8_t paCfg1 = readRegister(Register::PA_CFG1);
+	paCfg1 &= ~(0b111111 << PA_CFG1_PA_POWER_RAMP);
+	paCfg1 |= maxPowerValue << PA_CFG1_PA_POWER_RAMP;
+	writeRegister(Register::PA_CFG1, paCfg1);
+
+	uint8_t askCfg = readRegister(Register::ASK_CFG);
+	askCfg &= ~(0b111111 << ASK_CFG_ASK_DEPTH);
+	askCfg |= minPowerValue << ASK_CFG_ASK_DEPTH;
+	writeRegister(Register::ASK_CFG, askCfg);
+}
+
 void CC1200::setRadioFrequency(CC1200::Band band, float frequencyHz)
 {
 	// Frequency synthesizer configuration.  This is completely opaque and it is unknown what these bits do --
@@ -739,6 +840,12 @@
 
 void CC1200::setPARampRate(uint8_t firstRampLevel, uint8_t secondRampLevel, CC1200::RampTime rampTime)
 {
+	// enable PA ramping
+	uint8_t paCfg1Val = readRegister(Register::PA_CFG1);
+	paCfg1Val |= 1 << PA_CFG1_PA_RAMP_SHAPE_EN;
+	writeRegister(Register::PA_CFG1, paCfg1Val);
+
+	// configure properties
 	uint8_t paCfg0Val = 0;
 	paCfg0Val |= (firstRampLevel << PA_CFG0_FIRST_IPL);
 	paCfg0Val |= (secondRampLevel << PA_CFG0_SECOND_IPL);
@@ -747,6 +854,13 @@
 	writeRegister(Register::PA_CFG0, paCfg0Val);
 }
 
+void CC1200::disablePARamping()
+{
+	uint8_t paCfg1Val = readRegister(Register::PA_CFG1);
+	paCfg1Val &= ~(1 << PA_CFG1_PA_RAMP_SHAPE_EN);
+	writeRegister(Register::PA_CFG1, paCfg1Val);
+}
+
 void CC1200::setAGCReferenceLevel(uint8_t level)
 {
 	writeRegister(Register::AGC_REF, level);
@@ -935,4 +1049,5 @@
 }
 
 
-#pragma clang diagnostic pop
\ No newline at end of file
+
+