CC1120: CC1120 Interrupt on GPIO reset issue

Part Number: CC1120

Tool/software:

Hi.

I am burning the candle at both ends with this, as I need to get this fixed straight away due to a critical problem overseas. So if anyone can help, it would be appreciated.

Using the CC1120 connected to an STM32L151 (I would have preferred an MSP430, but I had not much choice in the matter). TX/RX on 868MHz, FSK is 5kbps. RX filter is 20kHz, deviation around 5kHz. Anyway the SPI works perfectly, reading and writing registers and the strobe are all good.I can transmit fine and the range is excellent on my custom made boards.

I have set up GPIO2 to assert a pulse upon RX data (I used rising edge, but maybe falling edge is better).

There is two problems:

Problem #1

I am Txing 5 bytes from board A to board B: Board A TX: 0x31, 0x32, 0x33, 0X34 and 0x35.

If I just poll the received data. Board B RX: I get 0x31, 0x32, 0x33, 0x33 and 0x33.

It looks like a sync problem. Registers are the same on both boards. This problem I will need to fix, but it is not as urgent of Problem #2 below...

Problem #2

This problem is most urgent and is a blocker. Polling works to some extent (as above in Problem #1). However, it I use a polling routine, every time to send data from board A to board B, board B interrupts nicely via CC1120 GPIO2. But if I don't use the polling routine elsewhere in code, interrupt occurs only once and never again. I read that I might need to flush the RX buffer and enable the FIFO RX buffer. But these don't fix the problem. 

This sounds like a silly question, but it is for demo purposes: Is there a way to simply reset the operation of the GPIO2 pulse on RX data even without reading the data? So that every time a packet is being received the interrupt is triggered?

More to the point, what am I doing wrong? It appears I am missing something. 

Essential code is here. Sorry about it all being bunched up. It is nicely formatted on the STM32cubeIDE. But it is still readable.

Definitions:

/* REGISTER ADDRESSES AND VALUES FOR WRITING */

/* REGISTER ADDR,VALUE COMMENT */

//#define CONFIG_IOCFG3 0x0000,0xB0 //GPIO3 IO Pin Configuration

#define CONFIG_IOCFG3 0x0000,0x06 //GPIO3 IO Pin Configuration

#define CONFIG_IOCFG2 0x0001,0x06 //GPIO2 IO Pin Configuration

#define CONFIG_IOCFG1 0x0002,0xB0 //GPIO1 IO Pin Configuration

#define CONFIG_IOCFG0 0x0003,0x40 //GPIO0 IO Pin Configuration

#define CONFIG_SYNC3 0x0004,0x55 //Sync Word Configuration [31:24]

#define CONFIG_SYNC2 0x0005,0x55 //Sync Word Configuration [23:16]

#define CONFIG_SYNC1 0x0006,0x7A //Sync Word Configuration [15:8]

#define CONFIG_SYNC0 0x0007,0x0E //Sync Word Configuration [7:0]

#define CONFIG_SYNC_CFG1 0x0008,0x08 //Sync Word Detection Configuration Reg. 1

#define CONFIG_SYNC_CFG0 0x0009,0x0B //Sync Word Length Configuration Reg. 0

#define CONFIG_DEVIATION_M 0x000A,0x48 //Frequency Deviation Configuration

#define CONFIG_MODCFG_DEV_E 0x000B,0x0B //Modulation Format and Frequency Deviation Configur..

#define CONFIG_DCFILT_CFG 0x000C,0x15 //Digital DC Removal Configuration

#define CONFIG_PREAMBLE_CFG1 0x000D,0x18 //Preamble Length Configuration Reg. 1

#define CONFIG_FREQ_IF_CFG 0x000F,0x3A //RX Mixer Frequency Configuration

#define CONFIG_IQIC 0x0010,0x80 //Digital Image Channel Compensation Configuration

#define CONFIG_CHAN_BW 0x0011,0x0A //Channel Filter Configuration

#define CONFIG_MDMCFG0 0x0013,0x05 //General Modem Parameter Configuration Reg. 0

#define CONFIG_SYMBOL_RATE2 0x0014,0x64 //Symbol Rate Configuration Exponent and Mantissa [1..

#define CONFIG_SYMBOL_RATE1 0x0015,0x7A //Symbol Rate Configuration Mantissa [15:8]

#define CONFIG_SYMBOL_RATE0 0x0016,0xE1 //Symbol Rate Configuration Mantissa [7:0]

#define CONFIG_AGC_REF 0x0017,0x3C //AGC Reference Level Configuration

#define CONFIG_AGC_CS_THR 0x0018,0xEF //Carrier Sense Threshold Configuration

#define CONFIG_AGC_CFG1 0x001C,0xA9 //Automatic Gain Control Configuration Reg. 1

#define CONFIG_AGC_CFG0 0x001D,0xC0 //Automatic Gain Control Configuration Reg. 0

#define CONFIG_FIFO_CFG 0x001E,0x00 //FIFO Configuration

#define CONFIG_FS_CFG 0x0021,0x12 //Frequency Synthesizer Configuration

#define CONFIG_PKT_CFG0 0x0028,0x20 //Packet Configuration Reg. 0

#define CONFIG_PA_CFG2 0x002B,0x74 //Power Amplifier Configuration Reg. 2

#define CONFIG_PA_CFG0 0x002D,0x7E //Power Amplifier Configuration Reg. 0

#define CONFIG_PKT_LEN 0x002E,0xFF //Packet Length Configuration

#define CONFIG_IF_MIX_CFG 0x2F00,0x00 //IF Mix Configuration

#define CONFIG_TOC_CFG 0x2F02,0x0A //Timing Offset Correction Configuration

#define CONFIG_FREQ2 0x2F0C,0x6C //Frequency Configuration [23:16]

#define CONFIG_FREQ1 0x2F0D,0x80 //Frequency Configuration [15:8]

#define CONFIG_FS_DIG1 0x2F12,0x00 //Frequency Synthesizer Digital Reg. 1

#define CONFIG_FS_DIG0 0x2F13,0x5F //Frequency Synthesizer Digital Reg. 0

#define CONFIG_FS_CAL1 0x2F16,0x40 //Frequency Synthesizer Calibration Reg. 1

#define CONFIG_FS_CAL0 0x2F17,0x0E //Frequency Synthesizer Calibration Reg. 0

#define CONFIG_FS_DIVTWO 0x2F19,0x03 //Frequency Synthesizer Divide by 2

#define CONFIG_FS_DSM0 0x2F1B,0x33 //FS Digital Synthesizer Module Configuration Reg. 0

#define CONFIG_FS_DVC0 0x2F1D,0x17 //Frequency Synthesizer Divider Chain Configuration ..

#define CONFIG_FS_PFD 0x2F1F,0x50 //Frequency Synthesizer Phase Frequency Detector Con..

#define CONFIG_FS_PRE 0x2F20,0x6E //Frequency Synthesizer Prescaler Configuration

#define CONFIG_FS_REG_DIV_CML 0x2F21,0x14 //Frequency Synthesizer Divider Regulator Configurat..

#define CONFIG_FS_SPARE 0x2F22,0xAC //Frequency Synthesizer Spare

#define CONFIG_FS_VCO0 0x2F27,0xB4 //FS Voltage Controlled Oscillator Configuration Reg..

#define CONFIG_XOSC5 0x2F32,0x0E //Crystal Oscillator Configuration Reg. 5

#define CONFIG_XOSC1 0x2F36,0x03 //Crystal Oscillator Configuration Reg. 1

/************************************

* CC1120 STROBE COMMANDS

************************************/

#define CC1120_CMD_SRES 0x30 // Reset chip

#define CC1120_CAL 0x33 // Calibrate

#define CC1120_CMD_SRX 0x34 // Enable RX

#define CC1120_CMD_STX 0x35 // Enable TX

#define CC1120_REG_IOCFG3 0x00 // GDO3 output configuration

#define CC1120_REG_IOCFG2 0x01 // GDO2 output configuration

#define CC1120_REG_IOCFG1 0x02 // GDO1 output configuration

#define CC1120_REG_IOCFG0 0x03 // GDO0 output configuration

#define CC1120_REG_SYNC1 0x04 // Sync word, high byte

#define CC1120_REG_SYNC0 0x05 // Sync word, low byte

#define CC1120_REG_PKTLEN 0x06 // Packet length

#define CC1120_WRITE_BURST 0x40

#define CC1120_EXTENDED_ADDR 0x2F

#define CC1120_CMD_SFRX 0x3A // Flush the RX FIFO

#define CC1120_CMD_SFTX 0x3B // Flush the TX FIFO

#define CC1120_FIFO 0x3F

Interrupt handler (note: I would not normally put the strobes in an interrupt handler; this was just experimnnting to see if it allowed new pulsed from GPIO2) LEDs are used to prove the interrupt is being triggered. 

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)

{

/* Prevent unused argument(s) compilation warning */

UNUSED(GPIO_Pin);

if (GPIO_Pin == BUTTON_Pin)

{

if (button == YES)

button = NO;

else

(button = YES);

}

else if (GPIO_Pin == IR1_P_Pin)

{

if (!HAL_GPIO_ReadPin(IR1_N))

ir1Triggered = YES;

}

else if (GPIO_Pin == IR2_P_Pin)

{

if (!HAL_GPIO_ReadPin(IR2_N))

ir2Triggered = YES;

}

else if (GPIO_Pin == CC1120_GPIO2_Pin)

{

rxDataDetected = YES;

CC1120_Strobe(CC1120_CMD_SFRX); // Clear FIFO. This has to be done to get the interrupt to recur.

CC1120_Strobe(0x34); // SRX command strobe. This has to be done to get the interrupt to recur.

if (tempFlag == 0)

{

tempFlag = 1;

SwitchLedOn(LED1, BLUE);

}

else

{

tempFlag = 0;

SwitchLedOn(LED1, RED);

}

}

}

Receive data functions here...

/********************************************************************************************

* Function: CC1120_TxTest

* Purpose: Test the RF on TX

*********************************************************************************************/

void CC1120_TxTest()

{ u8 data[] =

{ 0x31, 0x32, 0x33, 0x34, 0x35 }; // Five bytes

CC1120_SendData(data);

}

/********************************************************************************************

* Function: CC1120_RxTest

* Purpose: Test the RF on TX

*********************************************************************************************/

void CC1120_RxTest(void)

{

u8 data[5] =

{ 0 };

CC1120_ReceiveData(data, 5);

}

/**********************************************************************************************

* Function: CC1120_CheckIfRxData

* Purpose: Top level function to check if there is any RX data present

**********************************************************************************************/

u8 CC1120_CheckIfRxData(void)

{

u8 response = 0;

response = CC1120_ReadRegister(0x2FD9); // Read the number of bytes in the FIFO register

return (response);

}

/**********************************************************************************************

* Function: CC1120_SendData

* Purpose: Top level function to send FSK data on the CC1120

**********************************************************************************************/

void CC1120_SendData(u8 *data)

{

CC1120_Strobe(CC1120_CMD_SFTX);

uint8_t length = sizeof(data);

PrintHexChar("length", length);

Print("CC1120 TX...\r\n", RED);

CC1120_WriteBurst(CC1120_FIFO, data, length);

CC1120_Strobe(CC1120_CMD_STX); // STX command strobe

}

/**********************************************************************************************

* Function: CC1120_ReceiveData

* Purpose: Top level function to receive FSK data on the CC1120

**********************************************************************************************/

void CC1120_ReceiveData(u8 *data, u8 length)

{

uint8_t buffer[length];

u8 response = 0;

CC1120_Strobe(CC1120_CMD_SFRX); // Clear FIFO

CC1120_Strobe(0x34); // SRX command strobe

Println("Polling for received messages", BLUE);

if (CC1120_CheckRxFifoOverflow())

{

Println("RX FIFO Overflow detected", RED);

}

while (response == 0) // Wait for data to be received

{

response = CC1120_CheckIfRxData();

}

Println("Data RX!", YELLOW);

CC1120_ReadBurst(CC1120_FIFO, buffer, 5);

PrintHexChar("Byte RX1", buffer[0]); // Testing only at this stage.

PrintHexChar("Byte RX2", buffer[1]);

PrintHexChar("Byte RX3", buffer[2]);

PrintHexChar("Byte RX4", buffer[3]);

PrintHexChar("Byte RX5", buffer[4]);

}

Any help appreciated. It is past midnight and I have been working on this since 7am, so excuse any spelling mistakes..

regards,

David

  • For 1:

    - Have you played with the sync threshold (CONFIG_SYNC_CFG1) 

    - If looks like you are using the default setting for  FREQOFF_CFG. If so, could you try to set this to 0x23? 

    For 2: 

    Someone with more FW experience needs to look into the code. But: Polling is not recommended since this generate constant traffic on the SPI bus which will impact sensitivity. Have you tried to base your code on the code examples that uses interrupt based RX? Also, have you checked the setting for RXOFF_MODE? 

  • Hi. Thanks for the response.

    I tried the FREQOFF_CFG suggestion, no effect. I stopped there due to time restrictions. But I am working on the more urgent second problem. I agree polling is not preferred, although the RF performance seems pretty good. I will double check the code examples, even if they are for the MSP430 which I am familiar with.

    Also, the RF Studio 7 I have been using seems a little limited in the number of controls. It does not generate a full list of registers, but what I do like about it is one can modify the output to produce C code one-liners, such as #defines or construct function calls.

  • Hi. Thanks for the response.

    I tried the FREQOFF_CFG suggestion, no effect. I stopped there due to time restrictions. But I am working on the more urgent second problem. I agree polling is not preferred, although the RF performance seems pretty good. I will double check the code examples, even if they are for the MSP430 which I am familiar with.

    Also, the RF Studio 7 I have been using seems a little limited in the number of controls. It does not generate a full list of registers, but what I do like about it is one can modify the output to produce C code one-liners, such as #defines or construct function calls.

    STOP PRESS! I have have interrupt working perfectly. The cause was I had triggered the interrupt on the rising edge, rather than the falling edge of the GPIO2 output. How simple was that! I could not see the forest for the trees.

    Problem one still remains, albeit slightly different. Packet of 5 bytes tx'ed are 0x31, 0x32, 0x33, 0x34, 0x35 eveery button press. Received the first packet as 0x31, 0x32, 0x33, 0x3F, 0xCF; then next packet is 0x13,  0x13,  0x13,  0x13,  0x13, then the next is 0x14, 0x14,0x14,0x14,0x14, and then the next is 0x18, 0x18,0x18,0x18,0x18 and then other random same byes in each packet. Sync problem most likely. Happens are near of far distance betwene the TXer and Rxer.

    Code is now very simple:

    Interrupt handler. The bottom elseif is the statement of interest that works.:

    void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)

    {

    /* Prevent unused argument(s) compilation warning */

    UNUSED(GPIO_Pin);

    if (GPIO_Pin == BUTTON_Pin)

    {

    if (button == YES)

    button = NO;

    else

    (button = YES);

    }

    else if (GPIO_Pin == IR_P_Pin)

    {

    if (!HAL_GPIO_ReadPin(IR_N))

    irTriggered = YES;

    }

    else if (GPIO_Pin == CC1120_GPIO2_Pin)

    {

    rxDataInt = YES;

    PrintNumber("RF packet detected", ++packetCounter);

    }

    }

    Main loop. Could not be simpler...

    while (1)

    {

    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */

    if (rxDataInt == YES)

    {

    CC1120_Receive(rxBuffer, 5);

    }

    }

    CC1120_Receive() function. Note I clear the RX buffer at the end...

    /**********************************************************************************************

    * Function: CC1120_Receive

    * Purpose:

    **********************************************************************************************/

    extern u8 rxDataInt;

    u8 CC1120_Receive(u8 *message, u8 length)

    {

    u8 buffer[10] =

    { 0 };

    CC1120_ReadBurst(CC1120_FIFO, buffer, length);

    PrintHexChar("Byte RX1", buffer[0]); // Testing only at this stage.

    PrintHexChar("Byte RX2", buffer[1]);

    PrintHexChar("Byte RX3", buffer[2]);

    PrintHexChar("Byte RX4", buffer[3]);

    PrintHexChar("Byte RX5", buffer[4]);

    Print(CRLF);

    CC1120_Strobe(CC1120_CMD_SFRX); // Clear FIFO. This has to be done to get the next interrupt to recur.

    rxDataInt = NO;

    return 0;

    }

  • I wrote my answer without weeing your last post, but I still think it will fix you issues:

    There are weaknesses in your code, and I will try to address them.

    First of all, you are configuring the radio for variable packet length mode (PKT_CFG0 = 0x20), but you are not sending the length in the TX Packet.

    If you want to transmit 5 bytes without length, you need to configure the radio for fixed packet length mode (PKT_CFG0 = 0x00), and set the PKTLEN = 5.

    Also, you cannot do the testing of flushing the RX FIFO in the ISR. The FIFO should NEVER be flush other than if it is in the state of RX_FIFO_ERR (overflow) or IDLE

    In your RX routine, not sure what you do in your CC1120_CheckRxFifoOverflow routine, but afterwards, you use the CC1120_CheckIfRxData() routine, and if it for example return 2, you continue and read 5 byte from the FIFO. You CANNOT read more data than what is there. That will mess up the FIFO pointers.

    I recommend you to simplify your code, and follow the following steps:

    • Select settings in SmartRF Studio. Choose the one closest to the data rate you want to use.
      • Start by testing with one of the default settings (you can change the RF parameters afterwards when you have everything up and running)
    • If you want to use fixed packet length and have the length set to 5, set PKT_CTRL0 = 0x00 and PKTLEN = 0x05
    • Reset the CC1120
    • Configure the radio with the register exported from SmartRF studio
    • Configure you MCU for a falling interrupt on GPIO2
    • Strobe SRX
    • Wait for falling interrupt
    • Read 7 bytes from the RX FIFO (5 bytes packet due to fixed length + 2 status bytes (you have APPEND_STATUS set to 1)
    • Repeat from 6)

    Siri