This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

CC1201: CC1201: sniff-mode - receiving and calibration

Part Number: CC1201

Hello everybody,

In my application, a battery-operated transponder (slave) should communicate with a wired remote station (master) via radio. The CC1201 is used as the RF chip on both sides.

In order to be able to work in an energy-saving manner, the slave should be operated in sniff mode for approx. 500 ms after each message sent in order to be able to receive the acknowledgment or a command. The master sends with a preamble of 30 bytes.

Question 1.)
How must the sniff mode be set on the slave so that every message can be received?

When changing from transmit mode to sniff mode, the synthesizer (SCAL) and the rc oscillator (WOR_CFG0.RC_MODE = 0x02) are always calibrated. The calibration of the synthesizer often fails because the marcstate "IDLE" is not established. Instead, the marcstate 0x11 (RX_FIFO_ERROR) is read out.

Question 2.)
Why doesn't the calibration run without errors?

Question 3.)
Does the master answer too early under certain circumstances?

Register settings (default):

/* default register set */
CC1201_REG_ENTRY(PREAMBLE_CFG1    , 0x14),
CC1201_REG_ENTRY(PREAMBLE_CFG0    , 0x8A),
CC1201_REG_ENTRY(IQIC             , 0xD8),
CC1201_REG_ENTRY(CHAN_BW          , 0x08),
CC1201_REG_ENTRY(MDMCFG1          , 0x40),
CC1201_REG_ENTRY(MDMCFG0          , 0x05),
CC1201_REG_ENTRY(SYMBOL_RATE2     , 0xA4),
CC1201_REG_ENTRY(SYMBOL_RATE1     , 0x7A),
CC1201_REG_ENTRY(SYMBOL_RATE0     , 0xE1),
CC1201_REG_ENTRY(AGC_REF          , 0x2A),
CC1201_REG_ENTRY(AGC_CS_THR       , 0xF6),
CC1201_REG_ENTRY(AGC_GAIN_ADJUST  , 0x00),
CC1201_REG_ENTRY(AGC_CFG3         , 0xB1),
CC1201_REG_ENTRY(AGC_CFG2         , 0x20),
CC1201_REG_ENTRY(AGC_CFG1         , 0x12),
CC1201_REG_ENTRY(AGC_CFG0         , 0x80),
CC1201_REG_ENTRY(FIFO_CFG         , 0x00),
CC1201_REG_ENTRY(DEV_ADDR         , 0x00),
CC1201_REG_ENTRY(SETTLING_CFG     , 0x0B),
CC1201_REG_ENTRY(FS_CFG           , 0x12),
CC1201_REG_ENTRY(WOR_CFG1         , 0x08),
CC1201_REG_ENTRY(WOR_CFG0         , 0x21),
CC1201_REG_ENTRY(WOR_EVENT0_MSB   , 0x00),
CC1201_REG_ENTRY(WOR_EVENT0_LSB   , 0x00),
CC1201_REG_ENTRY(RXDCM_TIME       , 0x00),
CC1201_REG_ENTRY(PKT_CFG2         , 0x00),
CC1201_REG_ENTRY(PKT_CFG1         , 0x42),
CC1201_REG_ENTRY(PKT_CFG0         , 0x20),
CC1201_REG_ENTRY(RFEND_CFG1       , 0x0F),
CC1201_REG_ENTRY(RFEND_CFG0       , 0x00),

Here my current code:

void EnterSniffMode(void)
{
    cc1201.timeoutCalib = false;  // flag: calibration timeout
    TimerStart(&TimeoutCalib, OnSignalTimeoutCalib, 10, TIMER_TYPE_ONESHOT, TIMER_CONTEXT_MAINLOOP);

    cc1201.sniff_state = STATE_SNIFF_WAIT_CALIB_SYNTH;


    /* set sniff-mode configuration */
    SetRegisterValue(CC1201_REG_WOR_CFG0_RC_PD,                   0);
    SetRegisterValue(CC1201_REG_WOR_EVENT0_MSB_EVENT0_15_8,       0x00);
    SetRegisterValue(CC1201_REG_WOR_EVENT0_LSB_EVENT0_7_0,        0x54);

    SetRegisterValue(CC1201_REG_SETTLING_CFG_FS_AUTOCAL,          0);
    SetRegisterValue(CC1201_REG_AGC_CS_THR_AGC_CS_TH,             8);
    SetRegisterValue(CC1201_REG_AGC_CFG1_AGC_WIN_SIZE,            0);
    SetRegisterValue(CC1201_REG_AGC_CFG1_AGC_SETTLE_WAIT,         0);
    SetRegisterValue(CC1201_REG_RFEND_CFG0_TERM_ON_BAD_PACKET_EN, 1);
    SetRegisterValue(CC1201_REG_RFEND_CFG0_ANT_DIV_RX_TERM_CFG,   1);
    SetRegisterValue(CC1201_REG_FS_DIG1_FS_DIG1_RESERVED5_0,      7);
    SetRegisterValue(CC1201_REG_FS_DSM1_FS_DSM1_RESERVED2_0,      2);
    SetRegisterValue(CC1201_REG_FS_DVC1_FS_DVC1_RESERVED7_0,      0xF3);
    SetRegisterValue(CC1201_REG_FS_DVC0_FS_DVC0_RESERVED4_0,      0x13);
    SetRegisterValue(CC1201_REG_FS_VCO0_FS_VCO0_RESERVED7_0,      0xB8);

    ChipConfigurate();

    /* start calibration of synthesizer */
    Cc1201Strobe(CC1201_STROBE_SCAL);
    cc1201.sniff_state = STATE_SNIFF_WAIT_CALIB_SYNTH;
}

void ExecuteSniffMode(void)
{
    switch (cc1201.sniff_state)
    {
        case STATE_SNIFF_WAIT_CALIB_SYNTH:
        {
            /* wait for calibration of synthesizer */
            if (CheckMarcstate(CC1201_MARCSTATE_IDLE))
            {
                /* start calibration of rc osc (SWRA428A, page 6) */
                uint8_t tmp = 0;

                Cc1201Read(CC1201_REG_WOR_CFG0, &tmp, sizeof(tmp));
                tmp &= ~(0x03 << Cc1201RegDescTab[CC1201_REG_WOR_CFG0_RC_MODE].pos);    // RC_MODE = 0
                tmp |= (0x02 << Cc1201RegDescTab[CC1201_REG_WOR_CFG0_RC_MODE].pos);     // RC_MODE = 2
                Cc1201Write(CC1201_REG_WOR_CFG0, &tmp, sizeof(tmp));

                Cc1201Strobe(CC1201_STROBE_SIDLE);

                tmp &= ~(0x03 << Cc1201RegDescTab[CC1201_REG_WOR_CFG0_RC_MODE].pos);    // RC_MODE = 0
                Cc1201Write(CC1201_REG_WOR_CFG0, &tmp, sizeof(tmp));

                cc1201.sniff_state = STATE_SNIFF_WAIT_CALIB_RCOSC;

                cc1201.timeoutCalib = 0;
                TimerStart(&TimeoutCalib, OnSignalTimeoutCalib, 10, TIMER_TYPE_ONESHOT, TIMER_CONTEXT_MAINLOOP);
            }
            else if (cc1201.timeoutCalib)
            {

                /* ignore calibration */

/* **************************** */
/* this case enters very often! */
/* **************************** */


                cc1201.timeoutCalib = 0;
                TimerStart(&TimeoutCalib, OnSignalTimeoutCalib, 10, TIMER_TYPE_ONESHOT, TIMER_CONTEXT_MAINLOOP);
            }
        }
        break;

        case STATE_SNIFF_WAIT_CALIB_RCOSC:
        {
            /* wait for calibration of rc osc */
            if (CheckMarcstate(CC1201_MARCSTATE_IDLE))
            {
                /* clear previous reception */
                ClearEvent(CC1201_EVENT_RECEIVED);

                /* start rx for sniff mode */
                Cc1201Strobe(CC1201_STROBE_SWOR);

                cc1201.sniff_state = STATE_SNIFF_WAIT_RX;
            }
            else if (cc1201.timeoutCalib)
            {
                /* ignore calibration */
                Cc1201Strobe(CC1201_STROBE_SWOR);
                cc1201.sniff_state = STATE_SNIFF_WAIT_RX;
            }
        }
        break;

        case STATE_SNIFF_WAIT_RX:
        {
            /* wait for reception */
            if (Machine.EventMask & CC1201_EVENT_RECEIVED)
            {
                ClearEvent(CC1201_EVENT_RECEIVED);

                HandleReception();

                Cc1201Strobe(CC1201_STROBE_SCAL);
                cc1201.sniff_state = STATE_SNIFF_WAIT_CALIB_SYNTH;
            }
            else if (cc1201.txqueue.busy)
            {
                // go to machine state STATE_SEND
            }
        }
    }
}

Can someone help me? Thank you very much

  • It sounds like you have entered an RX FIFO error that you have not handled correctly. You always need to respond to a FIFO error by flushing the FIFO (SFRX and/or SFTX).

    Also, I do not understand why you need to change the registers every time you enter Sniff mode, as you can use the same settings in TX.

    Another thing is that it should not be necessary to have any timeout on the calibration, as there is nothing that can prevent this from finishing.

    To configure sniff mode correctly you should use SmartRF Studio, select the setting you want to use and the “RX Sniff Mode” tab. Here you can configure RSSI threshold, preamble length etc.

    You code should do something like this:

    // Init MCU
    // Unit Radio with sniff mode settings from SmartRF Studio
    
    while(1)
    {
        // Calibrate radio
        trxSpiCmdStrobe(CC120X_SCAL);
        
        // Wait for calibration to be done (radio back in IDLE state)
        do {
            cc120xSpiReadReg(CC120X_MARCSTATE, &marcState, 1);
        } while (marcState != 0x41);
        
        // Calibrate the RCOSC
        calibrateRCOsc();
    
    	// Write a packet to the TX FIFO 
    
        // Enter TX Mode
        trxSpiCmdStrobe(CC120X_STX);
        
        // Wait for packet to be sent (Packet sent interrupt)
        
        // Enter Sniff mode
        trxSpiCmdStrobe(CC120X_SWOR);
        
        // Wait for packet to be received or for a 500 ms timeout
        
        // If packet received, read packet from RX FIFO. 
        // Here you should also check for RX FIFO errors, 
        // and flush the RX FIFO if an error has occurred
    }
    
    

    BR

    Siri

  • Hello Siri,

    thank you for your response.

    Also, I do not understand why you need to change the registers every time you enter Sniff mode, as you can use the same settings in TX.

    I wrote a state machine arround the cc1201, which should be a copy of the internal state machine of the chip. So I couldn't send in STATE_SNIFF. I have changed my state machine, so that I could send also in a "receiving state". This also eliminates the need to (cyclically) write the complete configuration between sending and receiving.

    Another thing is that it should not be necessary to have any timeout on the calibration, as there is nothing that can prevent this from finishing.

    I also eliminated the timeout handling. I had included this because of not reaching MARCSTATE_IDLE. The reason for this was entering the MARC_STATE_RX_FIFO_ERR. This i have handled now by strobe SFRX.

    My source code looks currently like that:

    static void OnEnterSniff(struct SStateMachine *sm)
    {
        /* set sniff-mode configuration */
        AGC_CS_THR    = 0xF7;   /* -90dBm (value from SmartRF-Studio) */
        AGC_CFG1      = 0x00;   /* value from SmartRF-Studio */
        WOR_CFG0      = 0x20;   /* value from SmartRF-Studio */
        WOR_EVENT0    = 0x0054; /* value from SmartRF-Studio */
        SETTLING_CFG  = 0x03;   /* value from SmartRF-Studio */
        RFEND_CFG0    = 0x09;   /* value from SmartRF-Studio */
        FS_DIG1       = 0x07;   /* value from SmartRF-Studio */
        FS_DSM1       = 0x00;   /* value from SmartRF-Studio */
        FS_DVC1       = 0xFF;   /* value from SmartRF-Studio */
        FS_DVC0       = 0x17;   /* value from SmartRF-Studio */
        FS_VCO0       = 0xB5;   /* value from SmartRF-Studio */
    
        ChipConfigurate();
    
        cc1201.sniff_state = STATE_SNIFF_CALIB_SYNTH_START;    /* start calibration of synthesizer */
    }
    
    static void OnExecuteSniff(struct SStateMachine *sm)
    {
        switch (cc1201.sniff_state)
        {
            case STATE_SNIFF_CALIB_SYNTH_START:        /* start calibration of synthesizer */
                OnExecuteSniff_CalibSynthStart();
                //break;
    
            case STATE_SNIFF_CALIB_SYNTH_WAIT:         /* wait for calibration of synthesizer */
                OnExecuteSniff_CalibSynthWait();
                //break;
    
            case STATE_SNIFF_CALIB_RCOSC_START:        /* start calibration of rc oscillator */
                OnExecuteSniff_CalibRcoscStart();
                //break;
    
            case STATE_SNIFF_CALIB_RCOSC_WAIT:         /* wait for calibration of rc oscillator */
                OnExecuteSniff_CalibRcoscWait();
                //break;
    
            case STATE_SNIFF_RX_WAIT:                  /* wait for reception */
                OnExecuteSniff_RxWait();
                break;
        }
    }
    
    static void OnExecuteSniff_CalibSynthStart(void)
    {
        Cc1201Strobe(CC1201_STROBE_SCAL);
    }
    
    static void OnExecuteSniff_CalibSynthWait(void)
    {
        uint8_t marcstate = 0;
    
        Cc1201Read(Cc1201RegAddrTab[CC1201_REG_MARCSTATE].addr, &marcstate, sizeof(marcstate));
        marcstate &= 0x1F;
    
        switch (marcstate)
        {
            case CC1201_MARCSTATE_IDLE:
    			cc1201.sniff_state = STATE_SNIFF_CALIB_RCOSC_START;
    			break;
    
            case CC1201_MARCSTATE_TX_FIFO_ERR:
    			Cc1201Strobe(CC1201_STROBE_SFTX);
    			break;
    
            case CC1201_MARCSTATE_RX_FIFO_ERR:
    			Cc1201Strobe(CC1201_STROBE_SFRX);
    			break;
    
            case CC1201_MARCSTATE_REG_SETTLE_MC:
    			/* nothing to be done! (still calibrating) */
    			break;
        }
    }
    
    static void OnExecuteSniff_CalibRcoscStart(void)
    {
        /* start calibration of rc osc (SWRA428A, page 6) */
        uint8_t tmp = 0;
    
        Cc1201Read(CC1201_REG_WOR_CFG0, &tmp, sizeof(tmp));
        tmp &= ~(0x03 << Cc1201RegDescTab[CC1201_REG_WOR_CFG0_RC_MODE].pos);    // RC_MODE = 0
        tmp |= (0x02 << Cc1201RegDescTab[CC1201_REG_WOR_CFG0_RC_MODE].pos);     // RC_MODE = 2
        Cc1201Write(CC1201_REG_WOR_CFG0, &tmp, sizeof(tmp));
    
        Cc1201Strobe(CC1201_STROBE_SIDLE);
    
        tmp &= ~(0x03 << Cc1201RegDescTab[CC1201_REG_WOR_CFG0_RC_MODE].pos);    // RC_MODE = 0
        Cc1201Write(CC1201_REG_WOR_CFG0, &tmp, sizeof(tmp));
    
        cc1201.sniff_state = STATE_SNIFF_CALIB_RCOSC_WAIT;
    }
    
    static void OnExecuteSniff_CalibRcoscWait(void)
    {
        uint8_t marcstate = 0;
    
        Cc1201Read(Cc1201RegAddrTab[CC1201_REG_MARCSTATE].addr, &marcstate, sizeof(marcstate));
        marcstate &= 0x1F;
    
        switch (marcstate)
        {
            case CC1201_MARCSTATE_IDLE:
                cc1201.sniff_state = STATE_SNIFF_RX_WAIT;
    
                ClearEvent(CC1201_EVENT_RECEIVED);
                Cc1201Strobe(CC1201_STROBE_SWOR);
                break;
    
            case CC1201_MARCSTATE_TX_FIFO_ERR:
                Cc1201Strobe(CC1201_STROBE_SFTX);
                break;
    
            case CC1201_MARCSTATE_RX_FIFO_ERR:
                Cc1201Strobe(CC1201_STROBE_SFRX);
                break;
        }
    }
    
    static void OnExecuteSniff_RxWait(void)
    {
        if (DataReceived())    /* wait for reception */
        {
            HandleReception();
            cc1201.sniff_state = STATE_SNIFF_CALIB_SYNTH_START;
        }
        else if (cc1201.isSending)    /* waiting for finish transmission ? */
        {
            OnUpdateSending();
        }
        else if (cc1201.txqueue.busy)    /* waiting for data to be sent ? */
        {
            OnSendData();
        }
    }
    
    /**
     * @brief OnExitSniff exits machine state STATE_SNIFF
     * @param sm          pointer to state machine instance
     */
    static void OnExitSniff(struct SStateMachine *sm)
    {
        /* restore default configuration */
    }

    Unfortunatelly I do not receive every message. Please see following scope:

    yello: antenna signal at sender
    red: GPIO0 (PKT_SYNC_RXTX)
    blue: GPIO2 (PQT_VALID)
    green: GPIO3 (WOR_EVENT0)

    Why doesn't cc1201 not set GPIO0  (PKT_SYNC_RXTX) in marked situation? EVENT0 rises in middle of preamble (sending 30 byte).
    To doublecheck the situation, i have a picture from a logic analizer, which triggered the identical situation:

    CC1201_GPIO0 is the signal at the RF chip (identical to the scope above, red channel)
    Channel 9 is the same signal from an cc1201 evaluation board, driven by SmartRF-Studio. (bottom line)

    As you can see, the eval board signals reception of "response" with GPIO0, my application board doesn't!

    Is there any explanation?

    Regards,
    Andy

  • Hi Andy

    If I understand correctly, you have made your own HW, and with this HW you are not able to receive packets, but using the same SW on HW from TI, you are able to receive. Is that correct?

    If you have made your own HW, I would strongly recommend that you verify that the HW is OK, before starting to build a complex SW using Sniff mode etc.

    You should set up a transmitter with SmartRF Studio to transmit packets forever using one of the default settings.

    On your HW, you should make a really easy test doing the following:

    • Init MCU
    • Init Radio with the same settings as used by SMartRF Studio
    • Strobe SRX

    Monitor the PKT_SYNC_RXTX. Are you able to receive anything at all with this approach?

    If you are, continue to change the settings, both in SmartRF Studio and in your code, until you have the RF settings you want to use in your application.

    If you still are able to receive all packets, start implementing Sniff mode.

    When debugging, you should set up a transmitter in continuous TX, and then read the RSSI in RX both on your board and on the TI HW. If there is something wrong with your design, it might be that the RSSI is lower than expected, and because of that you will not receive anything when using Sniff mode.

    BR

    Siri

  • Hi Siri,

    that's right: I have my own designed HW. In parallel I'm using TI's CC1201EM-868-930 (Rev. 1.1.1) with SmartRF Studio.

    Monitor the PKT_SYNC_RXTX. Are you able to receive anything at all with this approach?

    This test I have done already and I can receive every message send by the master. Just in "sniff mode" I have some trouble.

    Since yesterday it seems that CC1201 on my HW is receiving every message also. There was a timing problem while SCAL was running. But there seems to be an issue in my SW also, which I'm searching for actually.

    The master shell send with maximum preamble (PREAMBLE_CFG1.NUM_PREAMBLE = 30 byte). If I'm correct, the slave should be configured

    • WOR_EVENT0: 0x5B (= 30 byte (240 bit) - PQT_VALID_TIMEOUT (11 symbols))
    • WOR_CFG1.EVENT1: 4 (= 100µs)

    Which settings arround sniff mode do you recommend?

    Regards,
    Andy

  • As stated earlier, I recommend that you use the settings given to you by SmartRF Studio for sniff mode. There is no need for you to set this up yourselves.

    I notice that your Cs threshold is very high. are you sure that your RSSI is above -73 dBm when receiving from your transmitter?

  • Hi Siri,

    thank you for all assistence. Sniff mode is now "up and running". I have to test it and (perhabs) to do some fine adjustments, but in general it is doing! Thumbsup

    I notice that your Cs threshold is very high. are you sure that your RSSI is above -73 dBm when receiving from your transmitter?

    SmartRF-Studio's template "100kbps, 2-GFSK, ETSI Standard (868MHz)" suggest -90 dBm in sniff mode. The user manual says:

    The  CS  threshold  should  be  set  high enough so that CS is de-asserted when only background noise is present and low enough so that CS is asserted when a wanted signal is present.

    So, I think I have to play with this parameter.

    Regards,
    Andy