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!

TestCC1200.cpp

Committer:
MultipleMonomials
Date:
2021-05-03
Revision:
3:2d1f7e1cd3d4
Parent:
2:ff257762763e

File content as of revision 3:2d1f7e1cd3d4:

//
// 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.printf("4.  915MHz 100ksps 2-GFSK DEV=50kHz CHF=208kHz Fixed Length\n");


	pc.scanf("%d", &config);
	printf("Running test with config %d:\n\n", config);

	CC1200::PacketMode mode = CC1200::PacketMode::VARIABLE_LENGTH;
	CC1200::Band band = CC1200::Band::BAND_820_960MHz;
	float frequency = 915e6;
	const float txPower = 0;
	float fskDeviation;
	float symbolRate;
	float rxFilterBW;
	CC1200::ModFormat modFormat;
	CC1200::IFCfg ifCfg = CC1200::IFCfg::POSITIVE_DIV_8;
	bool imageCompEnabled = true;
	bool dcOffsetCorrEnabled = true;
	uint8_t agcRefLevel;

	uint8_t dcFiltSettingCfg = 1; // default chip setting
	uint8_t dcFiltCutoffCfg = 4; // default chip setting
    uint8_t agcSettleWaitCfg = 2;

	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 = CC1200::IFCfg::ZERO;
		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;
        agcSettleWaitCfg = 1;
	}
	else if(config == 4)
	{
		fskDeviation = 49896;
		symbolRate = 100000;
		rxFilterBW = 208300;
		modFormat = CC1200::ModFormat::GFSK_2;
		agcRefLevel = 0x2A;
		mode = CC1200::PacketMode::FIXED_LENGTH;
	}
	else
	{
		pc.printf("Invalid config number!");
		return;
	}

	for(CC1200 & radio : {std::ref(txRadio), std::ref(rxRadio)})
	{

		radio.configureFIFOMode();
		radio.setPacketMode(mode);
		radio.setModulationFormat(modFormat);
		radio.setFSKDeviation(fskDeviation);
		radio.setSymbolRate(symbolRate);
		radio.setOutputPower(txPower);
		radio.setRadioFrequency(band, frequency);
		radio.setIFCfg(ifCfg, imageCompEnabled);
		radio.configureDCFilter(dcOffsetCorrEnabled, dcFiltSettingCfg, dcFiltCutoffCfg);
		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);
        radio.setAGCSettleWait(agcSettleWaitCfg);
		if(ifCfg == CC1200::IFCfg::ZERO)
		{
			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)];

	if(mode == CC1200::PacketMode::FIXED_LENGTH)
	{
		txRadio.setPacketLength(sizeof(message) - 1);
		rxRadio.setPacketLength(sizeof(message) - 1);
	}

	while(true)
	{
		ThisThread::sleep_for(1s);

		pc.printf("\n---------------------------------\n");

		pc.printf("<<SENDING: %s\n", message);
		txRadio.enqueuePacket(message, sizeof(message) - 1);


		// 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) - 1);
			receiveBuffer[sizeof(message)-1] = '\0';
			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;

}