Demo of how to use CC1200 radios to send data.

Dependencies:   CC1200

CC1200 Example Project

This project shows how to use my Mbed OS CC1200 driver to send messages over the air. It connects to the radio chips, configures them (using a couple of different configurations converted from SmartRF), and sends a message from a transmitter chip to a receiver.

Hardware Setup

This program assumes that two CC1200s are connected to your processor's SPI bus. The CC1200s' circuit boards must be configured for the 900MHz band. Also, if you are connecting the two radios together directly with a cable, make sure to include an attenuator (-20dB should work) to prevent overloading the radios' RX inputs.

I used a custom circuit board for my testing, but you should also be able to use an Mbed board connected to two CC1200 eval kits to run the program.

Note: License free transmission on the 900MHz band is only legal in Region 2 countries (North and South America). Make sure to follow all local regulations covering radio transmissions!

Revision:
0:ea2678a73bde
Child:
1:7e7812669c9c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/TestCC1200.cpp	Mon Aug 10 01:57:54 2020 -0700
@@ -0,0 +1,236 @@
+//
+// Test suite for the CC1200 radio driver.
+// Provides a menu to configure radio options, and
+// attempts to send and receive a signal using two radios connected
+// to the processor.
+//
+
+#include <mbed.h>
+#include <SerialStream.h>
+
+#include <CC1200.h>
+#include <cinttypes>
+
+// Pin definitions
+// change these to match your board setup
+#define PIN_SPI_MOSI P0_9
+#define PIN_SPI_MISO P0_8
+#define PIN_SPI_SCLK P0_7
+
+#define PIN_TX_CS P0_6
+#define PIN_TX_RST P0_29
+
+#define PIN_RX_CS P0_4
+#define PIN_RX_RST P0_30
+
+BufferedSerial serial(USBTX, USBRX, 115200);
+SerialStream<BufferedSerial> pc(serial);
+
+CC1200 txRadio(PIN_SPI_MOSI, PIN_SPI_MISO, PIN_SPI_SCLK, PIN_TX_CS, PIN_TX_RST, &pc);
+CC1200 rxRadio(PIN_SPI_MOSI, PIN_SPI_MISO, PIN_SPI_SCLK, PIN_RX_CS, PIN_RX_RST, &pc);
+
+void checkExistance()
+{
+	pc.printf("Checking TX radio.....\n");
+	bool txSuccess = txRadio.begin();
+	pc.printf("TX radio initialized: %s\n", txSuccess ? "true" : "false");
+
+	pc.printf("Checking RX radio.....\n");
+	bool rxSuccess = rxRadio.begin();
+	pc.printf("RX radio initialized: %s\n", rxSuccess ? "true" : "false");
+}
+
+void checkSignalTransmit()
+{
+	pc.printf("Initializing CC1200s.....\n");
+	txRadio.begin();
+	rxRadio.begin();
+
+	pc.printf("Configuring RF settings.....\n");
+
+	int config=-1;
+	//MENU. ADD AN OPTION FOR EACH TEST.
+	pc.printf("Select a config: \n");
+	// This is similar to the SmartRF "100ksps ARIB Standard" configuration, except it doesn't use zero-if
+	pc.printf("1.  915MHz 100ksps 2-GFSK DEV=50kHz CHF=208kHz\n");
+	// This should be identical to the SmartRF "500ksps 4-GFSK Max Throughput ARIB Standard" configuration
+	pc.printf("2.  915MHz 500ksps 4-GFSK DEV=400kHz CHF=1666kHz Zero-IF\n");
+	pc.printf("3.  915MHz 38.4ksps 2-GFSK DEV=20kHz CHF=833kHz\n");
+
+	pc.scanf("%d", &config);
+	printf("Running test with config %d:\n\n", config);
+
+	CC1200::Band band = CC1200::Band::BAND_820_960MHz;
+	float frequency = 915e6;
+	const float txPower = 0;
+	float fskDeviation;
+	float symbolRate;
+	float rxFilterBW;
+	CC1200::ModFormat modFormat;
+	uint8_t ifCfg = 0b101; // max IF
+	bool imageCompEnabled = true;
+	bool dcOffsetCorrEnabled = true;
+	uint8_t agcRefLevel;
+
+	uint8_t dcFiltSettingCfg = 1; // default chip setting
+	uint8_t dcFiltCutoffCfg = 4; // default chip setting
+
+	CC1200::SyncMode syncMode = CC1200::SyncMode::SYNC_32_BITS;
+	uint32_t syncWord = 0x930B51DE; // default sync word
+	uint8_t syncThreshold = 8; // TI seems to recommend this threshold for most configs above 100ksps
+
+	uint8_t preableLengthCfg = 5; // default chip setting
+	uint8_t preambleFormatCfg = 0; // default chip setting
+
+	if(config == 1)
+	{
+		fskDeviation = 49896;
+		symbolRate = 100000;
+		rxFilterBW = 208300;
+		modFormat = CC1200::ModFormat::GFSK_2;
+		agcRefLevel = 0x2A;
+	}
+	else if(config == 2)
+	{
+		// SmartRF "500ksps 4-GFSK ARIB standard" config
+		fskDeviation = 399169;
+		symbolRate = 500000;
+		rxFilterBW = 1666700;
+		ifCfg = 0;
+		imageCompEnabled = false;
+		dcOffsetCorrEnabled = true;
+		modFormat = CC1200::ModFormat::GFSK_4;
+		agcRefLevel = 0x2F;
+	}
+	else if(config == 3)
+	{
+		fskDeviation = 19989;
+		symbolRate = 38400;
+		rxFilterBW = 104200;
+		modFormat = CC1200::ModFormat::GFSK_2;
+		agcRefLevel = 0x27;
+	}
+	else
+	{
+		pc.printf("Invalid config number!");
+		return;
+	}
+
+	for(CC1200 & radio : {std::ref(txRadio), std::ref(rxRadio)})
+	{
+
+		radio.configureFIFOMode();
+		radio.setModulationFormat(modFormat);
+		radio.setFSKDeviation(fskDeviation);
+		radio.setSymbolRate(symbolRate);
+		radio.setOutputPower(txPower);
+		radio.setRadioFrequency(band, frequency);
+		radio.setIFMixCFG(ifCfg);
+		radio.configureDCFilter(dcOffsetCorrEnabled, dcFiltSettingCfg, dcFiltCutoffCfg);
+		radio.setIQMismatchCompensationEnabled(imageCompEnabled);
+		radio.setRXFilterBandwidth(rxFilterBW);
+		radio.configureSyncWord(syncWord, syncMode, syncThreshold);
+		radio.configurePreamble(preableLengthCfg, preambleFormatCfg);
+
+		// AGC configuration (straight from SmartRF)
+		radio.setAGCReferenceLevel(agcRefLevel);
+		radio.setAGCSyncBehavior(CC1200::SyncBehavior::FREEZE_NONE);
+		if(ifCfg == 0)
+		{
+			radio.setAGCGainTable(CC1200::GainTable::ZERO_IF, 11, 0);
+		}
+		else
+		{
+			// enable all AGC steps for NORMAL mode
+			radio.setAGCGainTable(CC1200::GainTable::NORMAL, 17, 0);
+		}
+		radio.setAGCHysteresis(0b10);
+		radio.setAGCSlewRate(0);
+	}
+
+	// configure on-transmit actions
+	txRadio.setOnTransmitState(CC1200::State::TX);
+	rxRadio.setOnReceiveState(CC1200::State::RX, CC1200::State::RX);
+
+	pc.printf("Starting transmission.....\n");
+
+	txRadio.startTX();
+	rxRadio.startRX();
+
+	const char message[] = "Hello world!";
+	char receiveBuffer[sizeof(message) + 1];
+
+	// make sure there's a null terminator even if data is corrupted
+	receiveBuffer[sizeof(receiveBuffer) - 1] = '\0';
+
+	while(true)
+	{
+		ThisThread::sleep_for(1s);
+
+		pc.printf("\n---------------------------------\n");
+
+		pc.printf("<<SENDING: %s\n", message);
+		txRadio.enqueuePacket(message, sizeof(message));
+
+
+		// update TX radio
+		pc.printf("TX radio: state = 0x%" PRIx8 ", TX FIFO len = %zu, FS lock = 0x%u\n",
+				  static_cast<uint8_t>(txRadio.getState()), txRadio.getTXFIFOLen(), txRadio.readRegister(CC1200::ExtRegister::FSCAL_CTRL) & 1);
+
+		// wait a while for the packet to come in.
+		ThisThread::sleep_for(10ms);
+
+		// wait the time we expect the message to take, with a safety factor of 2
+		auto timeoutTime = std::chrono::microseconds(static_cast<int64_t>((1/symbolRate) * 1e-6f * sizeof(message) * 2));
+
+		Timer packetReceiveTimeout;
+		packetReceiveTimeout.start();
+		bool hasPacket;
+		do
+		{
+			hasPacket = rxRadio.hasReceivedPacket();
+		}
+		while(packetReceiveTimeout.elapsed_time() < timeoutTime && !hasPacket);
+
+		pc.printf("RX radio: state = 0x%" PRIx8 ", RX FIFO len = %zu\n",
+				  static_cast<uint8_t>(rxRadio.getState()), rxRadio.getRXFIFOLen());
+		if(hasPacket)
+		{
+			rxRadio.receivePacket(receiveBuffer, sizeof(message));
+			pc.printf(">>RECEIVED: %s\n", receiveBuffer);
+		}
+		else
+		{
+			pc.printf(">>No packet received!\n");
+		}
+	}
+}
+
+
+int main()
+{
+	pc.printf("\nCC1200 Radio Test Suite:\n");
+
+	while(1){
+		int test=-1;
+		//MENU. ADD AN OPTION FOR EACH TEST.
+		pc.printf("Select a test: \n");
+		pc.printf("1.  Exit Test Suite\n");
+		pc.printf("2.  Check Existence\n");
+		pc.printf("3.  Check Transmitting Signal\n");
+
+		pc.scanf("%d", &test);
+		printf("Running test %d:\n\n", test);
+		//SWITCH. ADD A CASE FOR EACH TEST.
+		switch(test) {
+			case 1:         pc.printf("Exiting test suite.\n");    return 0;
+			case 2:         checkExistance();              break;
+			case 3:         checkSignalTransmit();              break;
+			default:        pc.printf("Invalid test number. Please run again.\n"); continue;
+		}
+		pc.printf("done.\r\n");
+	}
+
+	return 0;
+
+}