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.

CC1110-CC1111: power mode 2 with a sleep timer implementation

Part Number: CC1110-CC1111

Hi Experts,

A customer has been trying to make an application on the CC1110 chip but something is not working as intended.

They are trying to implement the power mode 2 for the device with a sleep timer. they use a code from the examples provided by TI and, for some reason, the device stays idle after the sleep timer interrupt triggers.

The program ends after leaving the interrupt and, by checking the registers, the IDLE bit is always active ('1')

I searched in the forums about this, but unfortunately, I was unable to find a solution.

powermode2.zip

Can you help? Thank you in advance

Regards,

Marvin

  • I am not sure I understand what the actual problem is. Are they not entering PM2 or are they not waking up from PM2? 

    First of all I would try to run the original PM2 example from the web where you run everything in a while(1) loop.

    Also note that debugging of PM2 and PM3 is not supported. this is stated in the data sheet.

    Siri

  • Hi Siri,

    Thanks for the response. Kindly refer to the customer response below:

    "the problem that I'm facing is that I can not send any messages through the radio after I leave PM2 (I know that the device leaves PM2 with the LEDS). So instead of using the radio, I tried using a simple printf operation at the start of the whole cycle. When I run the program, it only prints the message on the terminal io once, just like when using the radio. So I tried a program where the device goes to sleep, wakes up, and finishes and I check the registers after the program ends.

    When using PM2 and PM3, after the program ends (without the while loop) the CPU IDLE bit stays active and I don't understand why.

    In short, I can not do the operations I need (send radio frames or print messages after entering PM2).
    Note: I tried using the same code (send TX message) without entering PM2 and my other device correctly receives the messages, so I just don't know what to do."

    Kindly refer to the codes below provided by the customer:

    powermode2 (2).zip

    I hope this helps.

    Regards,

    Marvin

  • It is still not clear to me how they know the status of the IDLE bit, as you cannot run the debugger when entering PM2.

    I took the default PowerMode 2 example from here:

    http://www.ti.com/lit/zip/swrc117

    and modified the powermode2.c file so that a packet is transmitted every time the device wakes up from PM2.

    Modified code:

    /***********************************************************************************
    * INCLUDES
    */
    #include <hal_types.h>
    #include <hal_defs.h>
    #include <hal_cc8051.h>
    #include <ioCCxx10_bitdef.h>
    
    #if (chip == 2510)
    #include <ioCC2510.h>
    #endif
    #if (chip == 1110)
    #include <ioCC1110.h>
    #endif
    #if (chip == 2511)
    #include <ioCC2511.h>
    #endif
    #if (chip == 1111)
    #include <ioCC1111.h>
    #endif
    
    /***********************************************************************************
    * CONSTANTS
    */
    
    // Wait time in Active mode
    #define ACT_MODE_TIME           10000
    
    // Packet length
    #define N                       10
    
    #define OSC_BIT                 0x40
    #define OSC_PD_BIT              0x04
    #define STX                     0x03 
    
    
    /***********************************************************************************
    * LOCAL VARIABLES
    */
    
    // Variable for active mode duration
    static uint32 __xdata activeModeCnt = 0;
    
    // Initialization of source buffers and DMA descriptor for the DMA transfer
    // (ref. CC111xFx/CC251xFx Errata Note)
    static uint8 __xdata PM2_BUF[7] = {0x06,0x06,0x06,0x06,0x06,0x06,0x04};
    static uint8 __xdata dmaDesc[8] = {0x00,0x00,0xDF,0xBE,0x00,0x07,0x20,0x42};
    
    static int8 EVENT0_HIGH = 0xFF;
    static int8 EVENT0_LOW = 0xFF;
    
    static uint8 txBuffer[N + 1];
    
    void setup_sleep_interrupt(void)
    {
        // Clear Sleep Timer CPU Interrupt flag (IRCON.STIF = 0)
        STIF = 0;
    
        // Clear Sleep Timer Module Interrupt Flag (WORIRQ.EVENT0_FLAG = 0)
        WORIRQ &= ~WORIRQ_EVENT0_FLAG;
    
        // Enable Sleep Timer Module Interrupt (WORIRQ.EVENT0_MASK = 1)
        WORIRQ |= WORIRQ_EVENT0_MASK;
    
        // Enable Sleep Timer CPU Interrupt (IEN0.STIE = 1)
        STIE = 1;
    
        // Enable Global Interrupt (IEN0.EA = 1)
        EA = 1;
    }
    
    #pragma vector = ST_VECTOR
    __interrupt void sleep_timer_isr(void)
    {
        // Clear Sleep Timer CPU interrupt flag (IRCON.STIF = 0)
        STIF = 0;
    
        // Clear Sleep Timer Module Interrupt Flag (WORIRQ.EVENT0_FLAG = 0)
        WORIRQ &= ~WORIRQ_EVENT0_FLAG;
    
        // Clear the [SLEEP.MODE] bits, because an interrupt can also occur
        // before the SoC has actually entered Power Mode 2.
        SLEEP &= ~SLEEP_MODE;
    
        // Set SRF04EB LED1 to indicate Power Mode 2 exit
        P1_0 = 0;
    }
    
    void main(void)
    {
        volatile uint8 storedDescHigh = DMA0CFGH;
        volatile uint8 storedDescLow = DMA0CFGL;
        volatile int8 temp;
        
        PKTCTRL0    = 0x05; //Packet Automation Control 
        FSCTRL1     = 0x06; //Frequency Synthesizer Control 
        FREQ2       = 0x10; //Frequency Control Word, High Byte 
        FREQ1       = 0xA7; //Frequency Control Word, Middle Byte 
        FREQ0       = 0x62; //Frequency Control Word, Low Byte 
        MDMCFG4     = 0xCA; //Modem configuration 
        MDMCFG3     = 0x83; //Modem Configuration 
        MDMCFG2     = 0x13; //Modem Configuration 
        DEVIATN     = 0x35; //Modem Deviation Setting 
        MCSM0       = 0x18; //Main Radio Control State Machine Configuration 
        FOCCFG      = 0x16; //Frequency Offset Compensation Configuration 
        AGCCTRL2    = 0x43; //AGC Control 
        FSCAL3      = 0xE9; //Frequency Synthesizer Calibration 
        FSCAL2      = 0x2A; //Frequency Synthesizer Calibration 
        FSCAL1      = 0x00; //Frequency Synthesizer Calibration 
        FSCAL0      = 0x1F; //Frequency Synthesizer Calibration 
        TEST1       = 0x31;  //Various Test Settings 
        TEST0       = 0x09; //Various Test Settings 
        PA_TABLE0   = 0x60; //PA Power Setting 0 
        IOCFG0      = 0x06; //Radio Test Signal Configuration (P1_5) 
        LQI         = 0x02; //Demodulator Estimate for Link Quality 
        PKTLEN      = N;
      
        RFIF = 0;
        RFTXRXIF = 0;
    
        // Initialize P1_1/3 for SRF04EB LED1/3
        P1SEL &= ~(BIT3 | BIT0);
        P1_0 = 1; P1_3 = 1;
        P1DIR |= (BIT3 | BIT0);
    
        // Setup + enable the Sleep Timer Interrupt, which is
        // intended to wake-up the SoC from Power Mode 2.
        setup_sleep_interrupt();
    
        // Infinite loop:
        // Transmit a packet and enter PM2. Exit on Sleep timer inteerupt, and repeat.
        
        while(1)
        {
            // Choose the crystal oscillator as the system clock and set 
            // system clock speed = fRef (fxosc)
            CLKCON &= ~OSC_BIT;           // request switch to crystal oscillator
            while (CLKCON & OSC_BIT);     // wait until the clock switch has occured (=stable)
            SLEEP |= OSC_PD_BIT;          // power down unused oscillator  
          
            // Create packet
            txBuffer[0] = N;
            for (uint8 i = 1; i <= N; i++)
            {
                txBuffer[i] = i;
            }
          
            RFST = STX;
            while (!RFTXRXIF);
            RFTXRXIF = 0;
            RFD = txBuffer[0];
        
            for (uint8 m = 1; m <= N; m++)
            {
                while (!RFTXRXIF); 
                RFTXRXIF = 0;
                RFD = txBuffer[m];
            }  
            while ((RFIF & 0x10) == 0); // Wait for IRQ_DONE
            RFIF &= ~0x10;
            RFTXRXIF = 0;
    
            // Switch system clock source to HS RCOSC and max CPU speed:
            // Note that this is critical for Power Mode 2. After reset or
            // exiting Power Mode 2 the system clock source is HS RCOSC,
            // but to emphasize the requirement we choose to be explicit here.
            SLEEP &= ~SLEEP_OSC_PD;
            while( !(SLEEP & SLEEP_HFRC_S) );
            CLKCON = (CLKCON & ~CLKCON_CLKSPD) | CLKCON_OSC | CLKSPD_DIV_2;
            while ( !(CLKCON & CLKCON_OSC) ) ;
            SLEEP |= SLEEP_OSC_PD;
    
            // Set LS XOSC as the Sleep Timer clock source (CLKCON.OSC32 = 0)
            CLKCON &= ~CLKCON_OSC32;
    
            // Wait some time in Active Mode, and set SRF04EB LED1 before
            // entering Power Mode 2
            for(activeModeCnt = 0; activeModeCnt < ACT_MODE_TIME; activeModeCnt++);
            P1_0 = 1;
    
            ///////////////////////////////////////////////////////////////////////
            ////////// CC111xFx/CC251xFx Errata Note Code section Begin ///////////
            ///////////////////////////////////////////////////////////////////////
    
            // Store current DMA channel 0 descriptor and abort any ongoing transfers,
            // if the channel is in use.
            storedDescHigh = DMA0CFGH;
            storedDescLow = DMA0CFGL;
            DMAARM |= (DMAARM_ABORT | DMAARM0);
    
            // Update descriptor with correct source.
            dmaDesc[0] = (uint16)&PM2_BUF >> 8;
            dmaDesc[1] = (uint16)&PM2_BUF;
            // Associate the descriptor with DMA channel 0 and arm the DMA channel
            DMA0CFGH = (uint16)&dmaDesc >> 8;
            DMA0CFGL = (uint16)&dmaDesc;
            DMAARM = DMAARM0;
    
            // NOTE! At this point, make sure all interrupts that will not be used to
            // wake from PM are disabled as described in the "Power Management Control"
            // chapter of the data sheet.
    
            // The following code is timing critical and should be done in the
            // order as shown here with no intervening code.
    
            // Align with positive 32 kHz clock edge as described in the
            // "Sleep Timer and Power Modes" chapter of the data sheet.
            temp = WORTIME0;
            while(temp == WORTIME0);
    
            // Set Sleep Timer Interval
            WOREVT0 = EVENT0_HIGH;
            WOREVT1 = EVENT0_LOW;
    
            // Make sure HS XOSC is powered down when entering PM{2 - 3} and that
            // the flash cache is disabled.
            MEMCTR |= MEMCTR_CACHD;
            SLEEP = 0x06;
    
            // Enter power mode as described in chapter "Power Management Control"
            // in the data sheet. Make sure DMA channel 0 is triggered just before
            // setting [PCON.IDLE].
            asm("NOP");
            asm("NOP");
            asm("NOP");
            if(SLEEP & 0x03)
            {
                asm("MOV 0xD7,#0x01");      // DMAREQ = 0x01;
                asm("NOP");                 // Needed to perfectly align the DMA transfer.
                asm("ORL 0x87,#0x01");      // PCON |= 0x01 -- Now in PM2;
                asm("NOP");                 // First call when awake
            }
            // End of timing critical code
    
            // Enable Flash Cache.
            MEMCTR &= ~MEMCTR_CACHD;
    
            // Update DMA channel 0 with original descriptor and arm channel if it was
            // in use before PM was entered.
            DMA0CFGH = storedDescHigh;
            DMA0CFGL = storedDescLow;
            DMAARM = DMAARM0;
    
            ///////////////////////////////////////////////////////////////////////
            /////////// CC111xFx/CC251xFx Errata Note Code section End ////////////
            ///////////////////////////////////////////////////////////////////////
    
            // Wait until HS RCOSC is stable
            while( !(SLEEP & SLEEP_HFRC_S) );
    
            // Set LS XOSC as the clock oscillator for the Sleep Timer (CLKCON.OSC32 = 0)
            CLKCON &= ~CLKCON_OSC32;
        }
    }

    I have tested the code on the Smart6RF04EM (+CC1110EM) and used SmartRF Studio as the receiver.

    Everything worked as it should.

    What is happening if they run the default PM2 example without the debugger connect3d. Are not the Green LED toggling?

    It is hard for me to debug this as I am not able to see any problems on my side.

    BR

    Siri