This is an old revision of the document!
Table of Contents
Programming CC1200
The CC1200 wireless transceiver is connected via the “Serial Peripheral Interface (SPI)” to the Beaglebone Black. Therefore, controlling the CC1200 means sending and receiving data from the SPI. The communication over the SPI is already implemented and the code can be accessed by including the file SPIv1.h
. The include-file can be found in the directory /usr/local/include
and the corresponding library libspi.so
can be found in directory /usr/local/lib
.
Controlling the SPI
int spi_init(void)
Before accessing the SPI, the function spi_init
must be called. spi_init
initializes the SPI. On success, the function will return true.
void spi_shutdown(void)
The function spi_shutdown
does the opposite of function spi_init
and disables the SPI. Therefore, for every call of function spi_init
a corresponding call of function spi_shutdown
must be called.
Writing and Reading CC1200 Registers
The functions cc1200_reg_write
and cc1200_reg_read
are provided to access the registers of the CC1200. You can see the registers in SmartRF Studio in the register view (look at Expert Mode Window). Each register has an address. The register names and its addresses can be found at page 11 to page 13 in the User’s Guide of the CC1200. The description and the structure of each register can be found at page 80ff.
It should be pointed out, that there are two types of registers: (basic) registers and extended registers. The basic registers start at address 0x00
and the extended registers start at address 0x2F
. So every time you like to access an extended register, The value 0x2F00
needs ta add to the extended register address. E.g. the address of the extended register FREQ1
(see table 5) in the “User’s Guide” is 0x2F0D
.
Writing or reading to/from the address '0x3F' will access the internal FIFO's of the CC1200. Writing will push new data to the transmission FIFO and reading will pop data drop the receive FIFO (a more extended explanation will be given later).
int cc1200_reg_write(int adr, int val)
With the function cc1200_reg_write
a single register of the CC1200 will be written. The parameter adr
must contain the register address and parameter val
must contain the register value. On return, the function will provide the written value.
int cc1200_reg_read(int adr, int *val)
Function cc1200_reg_read
will read the content of a single register. Parameter adr
must contain the register address. The content of the register will be stored in a variable given by parameter val
. In addition the return value will provide also the register value.
Controlling CC1200
Switching on the CC1200 will bring the transmitter into idle state. In idle state, only writing and reading the registers are allowed. Bringing the CC1200 in another state (e.g. receiving) a so called command strobe must be given. To issue a command strobe the function cc1200_cmd
will be used.
CC1200 Commands
For possible commands #define statements are provided:
/* command strobes */ #define SRES 0x30 /**< CC1200 in den Ausgangszustand setzen (Chip reset). */ #define SFSTXON 0x31 /**< Schalte den Frequenzsynthesizer ein und kalibriere ihn. */ #define SXOFF 0x32 /**< Gehe in den XOFF Zustand. */ #define SCAL 0x33 /**< Kalibriere Frequenzsynthesizer und schalte ihn aus. */ #define SRX 0x34 /**< Kalibriere Chip und schalte in den Empfangsmodus. */ #define STX 0x35 /**< Schalte in den Sendemodus. */ #define SIDLE 0x36 /**< Gehe in den Ruhezustand. */ #define SAFC 0x37 /**< Führe eine automatische Frequenz-Kompensation (AFC) aus. */ #define SWOR 0x38 /**< Starte die automatische RX polling Sequenz. */ #define SPWD 0x39 /**< Gehe in des SLEEP Mode. */ #define SFRX 0x3A /**< Lösche den RX FIFO. */ #define SFTX 0x3B /**< Lösche den TX FIFO. */ #define SWORRST 0x3C /**< Setze die eWOR Zeit. */ #define SNOP 0x3D /**< Kein Kommando. * Wird benutzt um den Zustand des CC1200 zu ermitteln */
If the CC1200 received a command, he will automatically enter the state or perform the command. Afterwards, he will mostly come back to idle state.
To test, if the CC1200 has entered a new state, the function get_status_cc1200
will be used. get_status_cc1200
will return the last available status of CC1200. A status update is given, by performing a command or reading/writing a register. If CC1200 changes its state between such action, the state will actual. To be sure, to get the actual state, perform a SNOP command before reading the state. The SNOP command does nothing in the chip, but it will update the status. This ensures to get the correct state. If should also be considered, that the CC1200 is very much slower compared to the program executing the get_status_cc1200
command. So, it needs some time until CC1200 has updated its status.
CC1200 status information
For possible status informations an enumeration type hs been defined:
typedef enum { IDLE = 0, /**< Ruhe-Zustand */ RX = 1, /**< im Empfangsmode */ TX = 2, /**< im Sendemode */ FSTXON = 3, /**< Schneller Sendemode ist bereit */ CALLIBRATE = 4, /**< Frequenz Synthesizer wird kalibriert */ SETTLING = 5, /**< PLL rastet ein */ RX_FIFO_ERROR = 6, /**< RX FIFO Über- bzw. Unterlauf */ TX_FIFO_ERROR = 7, /**< TX FIFO Über- bzw. Unterlauf */ UNKNOWN = -1 /**< unbekannter Status */ } CC1200_STATES;
int cc1200_cmd(int cmd)
With function cc1200_cmd
you execute a CC1200 command. Parameter cmd
determines the command. Possible commands are listed above.
int get_status_cc1200(void)
Function get_status_cc1200
returns the last available status of CC1200. To be sure to obtain the actual status, execute cc1200_cmd(SNOP) before function get_status_cc1200
.
char *get_status_cc1200_str(void)
Funktion get_status_cc1200_str
does the same as function get_status_cc1200
but returns the status information as a string.
Integrating SmartRF Studio Export Files
As described in Section Register Export), you are using SmartRF Studio to select a predefined CC1200 register setting and modify this setting to your needs. Afterwards the register settings will be exported. Now, you have to apply theses register setting to the CC1200. This is necessary, because the CC1200 will load default values to its registers after witching on the chip or preforming a reset. This registers have to be reprogrammed to obtain the desired behavior. Reprogramming is done by the use of function cc1200_reg_write
.
In the following, we will look at an example:
Open SmartRF Studio and open the device window of the CC1200. Switch to expert mode and select the predefined register setting “Symbolrate 38.4kbps, 2-GFSK, RX BW 100kHz, ETSI Standard (868MHz)”. Select the tab “Continuous RX” in the lower part of the window. Now, open the export file window and select the “SimpleTI setting” template.
Export the setting into the file smartrf_CC1200.h
. This file contains all register setting to operate CC1200 with a Symbolrate of 38.4kkbps at 868MHz … The file should look like this:
/*************************************************************** * SmartRF Studio(tm) Export * * Radio register settings specifed with C-code * compatible #define statements. * * RF device: CC1200 * ***************************************************************/ #ifndef SMARTRF_CC1200_H #define SMARTRF_CC1200_H #define SMARTRF_RADIO_CC1200 #define SMARTRF_SETTING_IOCFG2 0x08 #define SMARTRF_SETTING_IOCFG0 0x09 #define SMARTRF_SETTING_SYNC_CFG1 0xBF #define SMARTRF_SETTING_MODCFG_DEV_E 0x0B #define SMARTRF_SETTING_PREAMBLE_CFG1 0x01 #define SMARTRF_SETTING_PREAMBLE_CFG0 0x8A #define SMARTRF_SETTING_IQIC 0xC8 #define SMARTRF_SETTING_CHAN_BW 0x10 #define SMARTRF_SETTING_MDMCFG1 0x02 #define SMARTRF_SETTING_MDMCFG0 0x05 #define SMARTRF_SETTING_SYMBOL_RATE2 0x8F #define SMARTRF_SETTING_SYMBOL_RATE1 0x75 #define SMARTRF_SETTING_SYMBOL_RATE0 0x10 #define SMARTRF_SETTING_AGC_REF 0x27 #define SMARTRF_SETTING_AGC_CS_THR 0xEE #define SMARTRF_SETTING_AGC_CFG3 0x11 #define SMARTRF_SETTING_AGC_CFG1 0x11 #define SMARTRF_SETTING_AGC_CFG0 0x94 #define SMARTRF_SETTING_FIFO_CFG 0x00 #define SMARTRF_SETTING_FS_CFG 0x12 #define SMARTRF_SETTING_PKT_CFG2 0x01 #define SMARTRF_SETTING_PKT_CFG1 0x00 #define SMARTRF_SETTING_PKT_CFG0 0x20 #define SMARTRF_SETTING_PKT_LEN 0xFF #define SMARTRF_SETTING_IF_MIX_CFG 0x1C #define SMARTRF_SETTING_FREQOFF_CFG 0x22 #define SMARTRF_SETTING_TOC_CFG 0x03 #define SMARTRF_SETTING_MDMCFG2 0x02 #define SMARTRF_SETTING_FREQ2 0x56 #define SMARTRF_SETTING_FREQ1 0xCC #define SMARTRF_SETTING_FREQ0 0xCC #define SMARTRF_SETTING_IF_ADC1 0xEE #define SMARTRF_SETTING_IF_ADC0 0x10 #define SMARTRF_SETTING_FS_DIG1 0x07 #define SMARTRF_SETTING_FS_DIG0 0xAF #define SMARTRF_SETTING_FS_CAL1 0x40 #define SMARTRF_SETTING_FS_CAL0 0x0E #define SMARTRF_SETTING_FS_DIVTWO 0x03 #define SMARTRF_SETTING_FS_DSM0 0x33 #define SMARTRF_SETTING_FS_DVC0 0x17 #define SMARTRF_SETTING_FS_PFD 0x00 #define SMARTRF_SETTING_FS_PRE 0x6E #define SMARTRF_SETTING_FS_REG_DIV_CML 0x1C #define SMARTRF_SETTING_FS_SPARE 0xAC #define SMARTRF_SETTING_FS_VCO0 0xB5 #define SMARTRF_SETTING_IFAMP 0x09 #define SMARTRF_SETTING_XOSC5 0x0E #define SMARTRF_SETTING_XOSC1 0x03 #define SMARTRF_SETTING_SERIAL_STATUS 0x08 #endif
Now, modified the “SimpleTI setting”, that the register address will be exported. Save the exported file to smartrf_adr_CC1200.h
. smartrf_adr_CC1200.h
should look like this:
/*************************************************************** * SmartRF Studio(tm) Export * * Radio register settings specifed with C-code * compatible #define statements. * * RF device: CC1200 * ***************************************************************/ #ifndef SMARTRF_CC1200_ADR_H #define SMARTRF_CC1200_ADR_H #define IOCFG2_ADR 0x0001 #define IOCFG0_ADR 0x0003 #define SYNC_CFG1_ADR 0x0008 #define MODCFG_DEV_E_ADR 0x000B #define PREAMBLE_CFG1_ADR 0x000D #define PREAMBLE_CFG0_ADR 0x000E #define IQIC_ADR 0x000F #define CHAN_BW_ADR 0x0010 #define MDMCFG1_ADR 0x0011 #define MDMCFG0_ADR 0x0012 #define SYMBOL_RATE2_ADR 0x0013 #define SYMBOL_RATE1_ADR 0x0014 #define SYMBOL_RATE0_ADR 0x0015 #define AGC_REF_ADR 0x0016 #define AGC_CS_THR_ADR 0x0017 #define AGC_CFG3_ADR 0x0019 #define AGC_CFG1_ADR 0x001B #define AGC_CFG0_ADR 0x001C #define FIFO_CFG_ADR 0x001D #define FS_CFG_ADR 0x0020 #define PKT_CFG2_ADR 0x0026 #define PKT_CFG1_ADR 0x0027 #define PKT_CFG0_ADR 0x0028 #define PKT_LEN_ADR 0x002E #define IF_MIX_CFG_ADR 0x2F00 #define FREQOFF_CFG_ADR 0x2F01 #define TOC_CFG_ADR 0x2F02 #define MDMCFG2_ADR 0x2F05 #define FREQ2_ADR 0x2F0C #define FREQ1_ADR 0x2F0D #define FREQ0_ADR 0x2F0E #define IF_ADC1_ADR 0x2F10 #define IF_ADC0_ADR 0x2F11 #define FS_DIG1_ADR 0x2F12 #define FS_DIG0_ADR 0x2F13 #define FS_CAL1_ADR 0x2F16 #define FS_CAL0_ADR 0x2F17 #define FS_DIVTWO_ADR 0x2F19 #define FS_DSM0_ADR 0x2F1B #define FS_DVC0_ADR 0x2F1D #define FS_PFD_ADR 0x2F1F #define FS_PRE_ADR 0x2F20 #define FS_REG_DIV_CML_ADR 0x2F21 #define FS_SPARE_ADR 0x2F22 #define FS_VCO0_ADR 0x2F27 #define IFAMP_ADR 0x2F2F #define XOSC5_ADR 0x2F32 #define XOSC1_ADR 0x2F36 #define SERIAL_STATUS_ADR 0x2F91 #endif
Transfer these two files to the BeagleBone Black and include them into your C source code file. Following start programming the CC1200 registers:
cc1200_reg_write(IOCFG2_ADR, SMARTRF_SETTING_IOCFG2); cc1200_reg_write(IOCFG0_ADR, SMARTRF_SETTING_IOCFG0); // ... // Programm the RF frequency cc1200_reg_write(FREQ2_ADR, SMARTRF_SETTING_FREQ2); cc1200_reg_write(FREQ1_ADR, SMARTRF_SETTING_FREQ1); cc1200_reg_write(FREQ0_ADR, SMARTRF_SETTING_FREQ0); // ... cc1200_reg_write(SERIAL_STATUS_ADR, SMARTRF_SETTING_SERIAL_STATUS);
The above example is not complete, because all registers have to be reprogrammed. It should be pointed out, the reprogramming must be done in idle mode of the CC1200.
Summarize
Your program controlling the CC1200 should probably habe the following structure:
/****************************************************************************/ /* */ /* Structure of programs controlling CC1200 */ /* */ /****************************************************************************/ #include <stdio.h> #include <SPIv1.h> // necessary, otherwise CC1200 prototype are not available #include "smartrf_CC1200.h" // import register settings #include "smartrf_adr_CC1200.h" // import register addresses int main (void) { int adr; int val; // first initialize if(spi_init()){ printf("ERROR: Initialization failed\n"); return -1; // do some register reading or writing, // performance commands and get status information // reset CC1200 cc1200_cmd(SRES); // CC1200 is now in idle mode, registers have their default values // Reprogram the registers cc1200_reg_write(IOCFG2_ADR, SMARTRF_SETTING_IOCFG2); cc1200_reg_write(IOCFG0_ADR, SMARTRF_SETTING_IOCFG0); // ... reprogram the remaining registers // Programm the RF frequency cc1200_reg_write(FREQ2_ADR, SMARTRF_SETTING_FREQ2); cc1200_reg_write(FREQ1_ADR, SMARTRF_SETTING_FREQ1); cc1200_reg_write(FREQ0_ADR, SMARTRF_SETTING_FREQ0); // ... reprogram the remaining registers cc1200_reg_write(SERIAL_STATUS_ADR, SMARTRF_SETTING_SERIAL_STATUS); // get status information cc1200_cmd(SNOP); printf("INFO: Status:%s\n", get_status_cc1200_str()); adr = 0x01; // register read cc1200_reg_read(adr, &val); printf("INFO:read Adr:0x%x Val:0x%x\n", adr, val); // read extended register adr = EXT_ADR | 0x0A; cc1200_reg_read(adr, &val); // shutdown SPI spi_shutdown(); return 0; }
This structure has been used by testing the SPI in the page SPI Library.
Feel free to use this template in the directory ~/Beaglebone/SPI_test
and modify it to your needs.