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.

CC2543 Radio reset problem (RESET_N seems to only affect CPU)

Other Parts Discussed in Thread: CC2543

Hi,

I have a product working well using basic mode at 2 Mbps sending back to back packets.  The packets are sent every 1.25 milliseconds, synchronized with timer 2.  The problem I have is with the reset sequence.  If the power (+3.3 volts) to the module comes up very fast, the system works great.  If it comes up slowly, by simply turning on my Agilent power supply, then the radio seems to loose its ability to sync to timer 2.  I have tried hard resets (pulling RESET_N low) and it makes no difference.  I have tried having the firmware detect the situation and had it do a complete power up reset and initialization of the system, and that doesn't work.  The only way to get the radio to work again is to power it off (yes, remove the +3.3 volt supply), and then bring the supply up quickly with a switch.  I do this by placing a switch between the supply and the target so that I can have the supply at full voltage before I connect the target, causing the target to power up very quickly.

Is there some way to reset the radio portion other than a power cycle?

Thanks,

 -David

  • This is a strange problem. Pulling RESET_N low should reset the entire digital part of the chip and almost all of the analog part as well. I didn't understand your problem description. What do you mean by "the radio seems to loose its ability to sync to timer 2"? Could you give some more detail on what you are trying to do and what you observe? Do you see any other problems than this?

  • I have more information today.  The setup is as follows:

    1) TX is set to trigger the start of packet based on timer 2, which is set to have a period of 1.25 milliseconds  (40000 clock periods or 32 MHz)

    2) The 8051 sends CMD_TX, then fills in the first 8 bytes of RF data into the FIFO.

    3) The 8051 then waits till the packet starts (by waiting for RFTXFLEN<3).

    4) The 8051 turns on SPI data, and copies data from SPI to the RF buffer for the rest of the packet.

    5) The 8051 waits for the packet TX to finish, the goes back to step #2 and continues with next packet.

    Basically, a packet is intended to be sent every 1.25 milliseconds continuously.  However, sometimes the system fails to wait for timer 2, and sends the packets faster than 1.25 milliseconds.  The problem occurs when the 3.3 volt power supply coming into the CC2543 does not come up very quickly.

    The power is supplied from an LDO that is fed by incoming 5 volts.  If I switch the 5 volt supply directly (with a switch downstream from the power supply), the +3.3 volts comes up in about 2 milliseconds, and the problem does not occur.  If I turn on the 5 volt supply using the switch on the power supply, it takes about 80 milliseconds to reach +3.3 volts, and the problem occurs.

    When the problem occurs, the radio TX thinks that timer 2 has triggered immediately, all the time.  In other words, it seems to ignore timer 2 altogether, and always transmits immediately when CMD_TX is given.  Once in this mode, the only way I have found that can get it to work again is to power off, then power on with the 2 millisecond rise time.  Resetting the processor with RESET_N simply causes it to come back up with the same problem, no matter how many times you reset it.

    With further experimentation, I tried the same setup without using the SPI port to provide the data.  If I don't read the SPI port register, then the problem does not occur, TX works fine, and timer2 works fine, everything seems OK (except that I am not sending the data I want, since I am not reading the SPI port!).

    Here is a code excerpt that shows where I have narrowed down the problem.  This is the section of code that transfers the data from the SPI port to the RF transmit buffer.  If the #define USE_SPI_FOR_DATA (1) is as shown, it fails with the slow powerup.  If it is set to (0), then it works great, syncing to timer 2 just like it should.

    for( i=6; i; i-- )
    {
         unsigned char j;
         RFD = SYNC1; RFD = SYNC2; // SYNC at start of a group
         for( j=36; j; j-- )
         {
    #define USE_SPI_FOR_DATA (1)
    #if USE_SPI_FOR_DATA

              // This version does not reliably sync to timer2, based on rate of original rise of Vcc
              for (to=255; to && (U0CSR & U0CSR_RX_BYTE) == 0; to--) {}
              RFD = U0DBUF; // Read the byte, send to RF

    #else

              // This version always works, syncs with timer 2, etc.  However, it is just sending dummy data, not the data I want!
              while (RFTXFLEN > 2) {}
              RFD = j; // Just send a dummy byte
    #endif
         }
    }

    Also of note is that if I power up with the power supply switch, the failure occurs, even if I reload with the debugger or reset with RESET_N.  Also, if I reload the code with define set to (0), the problem goes away, again without cycling power.  It appears to be some kind of interaction where reading U0CSR and U0DBUF causes the radio to think that timer 2 has triggered.

     -David

  • From your description of the problem, I doubt  that the root cause of your problem is connected to neither the reset source nor the SPI. I guess that the problem has to do with the initialization of Timer 2 and the LLE, and that small differences in timing give the differences between the scenarios that you describe.

    If you configure the radio to start on Timer 2 event 1 and it actually starts immediately, this is probably caused by an event 1 already being captured by the LLE. An event 1 that has been captured by the LLE is only cleared if it is used to start a task or if the LLE is reset (LLECTRL being set to 0, then back to 1). To avoid an unexpected event 1, the following sequence should be followed when starting the system for the first time after boot:

    1. Set T2EVTCFG to 0x77 (or 0xFF)  to turn off all events to LLE
    2. Take LLE out of reset by setting LLECTRL = 1
    3. Configure and start Timer 2, then set T2EVTCFG as needed. Make sure to write bit 1 of T2CTRL to 0 when starting Timer 2. (Item 3 may alternatively be done before item 2)

    If Timer 2 has been running and generating event 1 while the radio has not been started, the LLE should be reset before issuing a CMD_TX again. Alternatively, set T2EVTCFG to 0x77 while the radio is not being used.

    If you follow the advice above and still see issues, please provide more of your code. I am particularly interested in the setup of Timer 2 (including updates done after the initial setup), enabling of the LLE, and issuing of CMD_TX commands (preferably including setting of the RAM-based registers for the LLE).

  • I checked my code based on your input, and I am doing what you suggest above.  I had thought of the pending event issue, but I don't believe that is the case.  The packet transmit takes less time than the 1.25 ms period, so if one were pending, the transmits would catch up and sync to the timer within a few packets.  Also, I implemented another test that shows the problem, which I will describe next.

    I modified my code so that the small portion that fills the data into the FIFO looks at a packet counter.  For the first 1024 packets, it uses SPI input data to fill the FIFO.  For the second 1024 packets, it ignores the SPI data and fills the FIFO with dummy data (the loop index).  The cycle repeats.  All other code in the loop is identical.  When running this code, the problem is easy to see.  The packet spacing is exactly 1.25 ms when sending dummy data, and about 940 microseconds when using the SPI data.  I can reset using RESET_N and it keeps showing the same problem.  However, if I power cycle it, and make sure the power comes up very fast (< 2 ms), the problem goes away.  If I power cycle with a slower Vcc rise (> 2 ms), the problem comes back.  Loading code using the CCDebugger, which I assume also does a reset, doesn't fix the problem either.

    I can provide the code for you to look at, it is not very long.  I have made a version that shows the problem that has most of the other parts removed, so you don't have to look at it.  The code in in a zip file at:  https://www.dropbox.com/s/89uax2x7e6ubrp9/CC2543_timer2_test_code_dlp.zip     Look in tx_t2.c, line 193 and you will see the part where it alternates the method for filling the buffer every 1024 packets.  The first half ignores timer 2, the second half uses timer 2.

  • I think the reason for the problem could be that you are somehow not getting data from the SPI. That situation does not look as if it is properly handled. You do have a timeout, but it looks as it is chosen rather arbitrarily, and with repeated cases of no SPI data, you will use a long time entering data into the FIFO. If you use too much time, you will get a FIFO underflow. This is signaled by the RF error interrupt. After this happens, the radio will read zeros out of the FIFO until the FIFO is reset, so the packet will be transmitted, but with incorrect contents. I suggest that you check for this, either by checking bit 0 of the RFERRF register in the loop or by servicing the interrupt. In case of an underflow, the data loop may take more than 1.25 ms, and after this has happened you will thus have an event 1 pending when you start the next Tx.

    To prevent problems with the loop taking too long, you could also check for TASKDONE in the loop and break out if you see it. It is also possible to use the Timer 2 period interrupt flag or the Timer 2 overflow counter to check that you have not used more than 1 period for the transmit operation.

    If the problem is indeed lack of SPI data, the next step is of course figuring out why. It could be a problem with the way you handle SPI Rx in CC2543 (I haven't looked into details on that), or a problem with your SPI master. When you control power to the CC2543, will this also impact the SPI master? In that case, I suppose the differences you see could have to do with that device. Even if you power the two devices individually, the I/O of the CC2543 will behave differently during reset depending on the reset method used, which I suppose could affect the SPI master.

  • I had a check for TASKDONE in the loop before, and took it out because it didn't work reliably, due to this exact problem.  So I added it back now.  The results are as follows:

    1) If we power up very quickly, everything works great just as expected.  If we hit RESET_N or reload with CCdebugger, it still works great.  All is good.

    2) If we power up not so quickly, the loop always terminates on the first check with a PRF_ENDCAUSE = 6 (TASK_ABORT).  If we hit RESET_N, still bad.  If we reload with CCdebugger, still bad.  The only thing I found that can make it work again is a power cycle.

    3) In case #2, if I don't read the SPI port, then sometimes it works perfectly.  Once it starts sending a legitimate packet, it keeps working perfectly forever, as long as I don't read the SPI port.  However, if I read the SPI port, it fails with TASK_ABORT every time.  If I again stop reading the SPI port, then it sometimes continues to fail for a short time, but eventually starts working fine again, and once it does start working, it works reliably (till I read the SPI again).

    Note that the code never sends a TASK_ABORT command.  The only commands sent are CMD_TXFIFO_RESET followed by CMD_TX.

    As a possible solution, we may have to add a separate switch to the power supply on the CC2543 that is controlled by the FPGA.  Then when we see that we are getting TASK_ABORT responses, we can command the FPGA to power cycle the CC2543 in the hopes that it will bring the radio back to sanity.

    In answer to your comment about the SPI, it is not missing any data from the SPI.  The data to SPI is comes from the FPGA at 2 Mbps and starts immediately after SPI_SS goes low.  The TXFIFO will not underflow from this, there will always be between 2 and 14 bytes in the TXFIFO.  When the problem occurs, it can't be that the data loop takes to long, the SPI port is providing a byte every 4 microseconds.  Also, the packet repeat period gets shorter, not longer.  The problem is that the radio is aborting immediately after CMD_TX with a result code of TASK_ABORT without any command requesting that it do so.

  • Thanks so much for your suggestions!  I think I found the problem.  The FPGA has a PLL that generates its clock frequency, and it seems to have a startup problem.  When it fails, the SPI frequency is almost 3 Mbps instead of 2 Mbps.  With that fixed, it seems to work much more reliably now.

  • David Paulsen said:
    2) If we power up not so quickly, the loop always terminates on the first check with a PRF_ENDCAUSE = 6 (TASK_ABORT).  If we hit RESET_N, still bad.  If we reload with CCdebugger, still bad.  The only thing I found that can make it work again is a power cycle.

    You will get at TASK_ABORT if you try to start a new command while another one is running. In this case, the old command gets aborted and the new one gets started. So it seems that sometimes you start the next command before the previous one has ended.

    David Paulsen said:
    As a possible solution, we may have to add a separate switch to the power supply on the CC2543 that is controlled by the FPGA.  Then when we see that we are getting TASK_ABORT responses, we can command the FPGA to power cycle the CC2543 in the hopes that it will bring the radio back to sanity.

    This should not be necessary. I still believe that you are on a wrong track when you try to blame differences on the reset sequence inside the CC2543. Any form of reset will reset the entire digital domain. There are some possible sources of the problem you see in your code, and you should get rid of those before trying stunts like this.

    David Paulsen said:
    In answer to your comment about the SPI, it is not missing any data from the SPI.

    Have you verified that this is true as seen from inside the CC2543? I understand that your design is such that this problem should not happen, but I am still not convinced that it does not in fact happen. It could even be that the SPI traffic somehow gets missed by the CC2543.There could be other problems as well, but given that the code works without the SPI, I think the problems are shomehow coming from the SPI.

    David Paulsen said:
    The data to SPI is comes from the FPGA at 2 Mbps and starts immediately after SPI_SS goes low.  

    I noted that SPI_SS is pin P1.1 on the CC2543. Note that this pin does not have a pull-up, so during reset it will float, meaning that your FPGA may see either level. It also seems that you wait until clock initialization is done before setting it as an output, which adds more time for this pin to be floating. Are you sure that this could not trigger your FPGA to start sending, thus getting out of sync? I does look like you reset the FPGA, though, so if this works as it should, I guess this situation could be handled.

    I have enclosed an updated version of one of your C files where I added some more sanity checks. I also created an error and a warning function. I am not sure what debug capabilities you have, so I used LED 3 which you were apparently already using for testing. The error function traps, the warning function does not. Of course you can modify these functions to fit your needs. Could you run the code with these changes in a situation that you have observed to fail and see if you see any warnings or errors. If so, which one(s)? (I have not had a chance to test the code, so there might be errors.)

    0726.tx_t2.c
    /****************************************************************************
      @file     tx_t2.c
    
      @brief    TX test procedure to check power up problem with timer2.
    
    
      @NOTE     
    
    
      @WARNING  Test code only!
    
    ******************************************************************************/
    #include "ioCC2543.h"
    #include "timer2.h"
    #include "hal_types.h"
    #include "hal_rf.h"
    #include "hal.h"
    #include "prop_regs.h"
    
    /* Phase lock adjustment delta for timer2 */
    #define T2_PHASE_ADJUST (2)
    
    /* Status bit in U0CSR: */
    #define U0CSR_RX_BYTE   (0x04)
    
    /* IO bits in P0: */
    #define P0_PKT_SYNC     (0x01)
    #define P0_RESET        (0x02)
    
    #define HIGHBYTE(x) ((unsigned char)((x)>>8))
    #define LOWBYTE(x)  ((unsigned char)(x))
    
    #define IN_DATA __data
    
    unsigned IN_DATA packetCounter;
    unsigned char lastT2Movf0;
    unsigned char numWarning, lastError, lastWarning;
    
    /* Storage for aux bytes: */
    union
    {
        struct aux_bytes_struct
        {
            uint8 channel;
        };
    } IN_DATA aux;
    
    /*
     * Macros for debug outputs.
     * We use port 0, bits 2 to 7 for debug outputs
     */
    #define ledSet(n)   \
        if      (2==n)  P0_2 = 1;\
        else if (3==n)  P0_3 = 1;\
        else if (4==n)  P0_4 = 1;\
        else if (5==n)  P0_5 = 1;\
        else if (6==n)  P0_6 = 1;\
        else if (7==n)  P0_7 = 1
    
    #define ledClear(n)   \
        if      (2==n)  P0_2 = 0;\
        else if (3==n)  P0_3 = 0;\
        else if (4==n)  P0_4 = 0;\
        else if (5==n)  P0_5 = 0;\
        else if (6==n)  P0_6 = 0;\
        else if (7==n)  P0_7 = 0
    
    #define FPGA_RESET_OFF()    P0 &= ~P0_RESET
    #define FPGA_RESET_ON()     P0 |=  P0_RESET
    #define SPI_SS_LOW()        P1_1 = 0
    #define SPI_SS_HIGH()       P1_1 = 1
    #define SPI_SS_OUTPUT()     P1DIR = 2
    
    /*
     * Initialize the TX channel to send a packet every 1.25 milliseconds using timer2:
     */
    void initTx( void )
    {
        // P0.0 is PKT_SYNC input, rest are outputs (bit 1 is reset to FPGA)
        P0DIR = 0xfe;   // bit 0 is input: PKT_SYNC
        P0 = 0;     // Start all low.
        SPI_SS_OUTPUT();
        SPI_SS_HIGH();
    
        FPGA_RESET_ON();
    
        /* Initialize the SPI port for RX */
        // Use SPI on USART 1 alternative 2
        PERCFG = (PERCFG & ~2) | 1;     /* Set SPI on UART 0 alternative 2 */
        P1SEL |= 0x1c;  /* Use pins 4,3,2 on port 1 */
    
        // Configure peripheral
        U0UCR  = 0x80;      // Flush and goto IDLE state. 8-N-1.
        U0CSR  = 0x20;      // SPI mode, slave.
    
        // Set SPI speed to 2 MHz (baud really doesn't matter, since use slave mode)
        U0GCR  = SPI_TRANSFER_MSB_FIRST | SPI_CLOCK_PHA_0 | SPI_CLOCK_POL_LO | 15;
        U0BAUD = 83;
    
        /* Setup static aux channel data: */
        aux.channel = 2420 - 2379;    /* frequency-->channel */
    
        // Added these lines based on post by "per":
        // Make sure events are off (timer should be disabled anyway, but try it)
        T2CTRL = 0;         // Stop timer 2.
        T2EVTCFG = 0x77;
    
        // Start the TX portion:
        halRfDisableRadio();            // Reset LLE.
    
        halRfInit( 1 /* TX */ );
        PRF_CHAN = aux.channel;   // The hal has a bug, set to correct value...
        PRF_TASK_CONF |= 8; // Start each receive/transmit on Timer 2 event 1.    
    
        // Enable the radio.
        halRfEnableRadio();
    
        // 200 ms delay to wait for ADC to start.
        halMcuWaitMs(200);
    
        // HEC: Set to a undefined value in enum type end cause.
        PRF_ENDCAUSE = TASK_UNDEF;
        
        // Make sure semaphores are released!
        SEMAPHORE0;
        SEMAPHORE1;
        SEMAPHORE0 = 1;
        SEMAPHORE1 = 1;
    
        // Set timer 2 for the 1.25 ms base period minus T2_PHASE_ADJUST for phase lock
        // To start close, we want the TX time to be about 500 microseconds after FPGA reset.
        // Note that the packet prep time is about 180 microseconds, so adjust for that.
        // This time doesn't need to be perfect, it just sets how fast it locks.
        Timer2Setup(PACKET_PERIOD_CLKS-T2_PHASE_ADJUST, HIGHBYTE(PACKET_PERIOD_CLKS-((500-180)*CPU_CLK_MHZ)));
    
        FPGA_RESET_OFF();   // Start the FPGA recording data
    }
    
    // HEC: Error function
    static void error(unsigned char errno)
    {
        lastError = errno;
        while(1) {
          ledSet(3);
          halMcuWaitMs(250);
          ledClear(3);
          halMcuWaitMs(250);
        }
    }
    // HEC: Warning function
    static void warning(unsigned char errno)
    {
        lastWarning = errno;
        numWarning++;
        ledSet(3);
    }
    
      
    /*
     * ----------------------------------------------------------------------------
     * @fn          main
     *
     * @brief       Main program
     *
     * @param       void
     *
     * @return      int (does not return)
     * ----------------------------------------------------------------------------
     */
    int main(void)
    {
        // Initialize Clock Source (32 Mhz Xtal), global interrupt (EA=1),  I/O ports and pheripherals(LCD).
        halClockInit();
    
        initTx();
        
        // HEC:
        packetCounter = 0;
        // HEC: Select timer value and overflow for T2
        T2MSEL = 0x00;
        
        for(;;)
        {
            unsigned char i, to, p0sync;
    
            // HEC: Verify that LLE is idle
            if (LLESTAT != 0x04) {
              error(1);
            }
            
            // HEC: Check that only one overflow period has passed since the last packet
            if (packetCounter > 0) {
              unsigned char tmp = T2MOVF0;
              if (++lastT2Movf0 != tmp) {
                warning(1);
                lastT2Movf0 = tmp;
              }
            }
            
            while (RFST != 0);  // Reset TXFIFO to clear any remaining data in buffer.
            RFST = CMD_TXFIFO_RESET;
    
            // HEC: Place length in FIFO now so that something is present when starting
            RFD = TEST_PACKET_LEN;      // Enter length field in Tx FIFO (for next packet)    
            
            while (RFST != 0);  // Start transmitter, pipelined with loading data.
            RFST = CMD_TX; 
    
            //RFD = TEST_PACKET_LEN;      // Enter length field in Tx FIFO (for next packet)    
    
            // Put the 10 bytes of SYNC pattern in the front:
            RFD = SYNC1; RFD = SYNC2;
            RFD = SYNC1; RFD = SYNC2;
            RFD = SYNC1; RFD = SYNC2;
            RFD = SYNC1; RFD = SYNC2;
    
            // Capture value of packet sync for later phase lock
            p0sync = 0;
    
            // Flush the SPI port to make sure it is in sync:
            U0UCR = 0x80;   // Flush and goto IDLE state.
    
            // Wait till the RF channel starts sending for phase lock
            // Each loop takes 52 clocks = 1.625 us.
            // Timeout = 1.625*255 = 414 us.
            // Testing shows we are here for about 308 us normally.
            for (to=255; to && RFTXFLEN > 2; to--)
            {
                p0sync <<= 1;
                if ((P0 & P0_PKT_SYNC) != 0)
                {
                    p0sync++;
                }
                ledSet(4);      // LED 1 during wait for start of TX
                ledClear(4);    // This takes 5 cycles to set+clear
            }
    
            ledSet(2);   // LED 2 during TX
    
            if ((packetCounter & 0x400) == 0)
            {
                //--- U0DBUF = 0; // Give it a send byte (this doesn't seem to be necessary)
    
                // Start the data coming in.
                SPI_SS_LOW();
    
                // This code demonstrates that there is an interaction between the SPI
                // port and timer 2.  If the radio is powered up using the switch on
                // the power supply, so that the supply comes up fairly slowly
                // (about 80 ms on my E3610A supply), then reading from the SPI port
                // will cause the radio to ignore timer 2, and start immediately.
                for( i=6; i; i-- )
                {
                    unsigned char j;
                    RFD = SYNC1; RFD = SYNC2;   // SYNC at start of a group
                    for( j=36; j; j-- )
                    {
                        for (to=255; to && (U0CSR & U0CSR_RX_BYTE) == 0; to--) {}
                        RFD = U0DBUF;   // Read the byte
                        // HEC: Check for timeout
                        if (to==0) {
                          // HEC: Timeout observed
                          error(2);
                        }
                        //--- U0DBUF = 0; // Give it the next send byte (this doesn't seem to be necessary)
                    }
                }
            }
            else
            {
                // Start the data coming in.
                SPI_SS_LOW();
    
                // This code just sends dummy data, so that we can demonstrate
                // the problem with the SPI port.  It doesn't read the SPI port,
                // and doesn't have the problem with timer 2.
                for( i=6; i; i-- )
                {
                    unsigned char j;
                    RFD = SYNC1; RFD = SYNC2;   // SYNC at start of a group
                    for( j=36; j; j-- )
                    {
                        for (to=255; to && RFTXFLEN > 2; to--) {}
                        RFD = j;    // Just send a dummy byte
                    }
                }
            }
            // HEC: Check for Tx FIFO underflow
            if (RFERRF & 0x01) {
              error(3);
            }
            
            RFD = 0;    // Send last AUX byte
    
            SPI_SS_HIGH();
    
            // Wait for TASKDONE
            for (to=255; to && (RFIRQF1 & RFIRQF1_TASKDONE) == 0; to--);
            ledClear(2);   // LED 2 during TX
    
            // HEC: Check for timeout
            if (to == 0) {
              warning(2);
              // HEC: Send shutdown command to really stop radio
              while (RFST != 0); 
              RFST = CMD_SHUTDOWN;
              // HEC: Wait for TASKDONE again
              for (to=255; to && (RFIRQF1 & RFIRQF1_TASKDONE) == 0; to--);
              if (to == 0) {
                error(4);
              }
            }
              
               
            // Check if TX was OK:
            if(PRF_ENDCAUSE != TASK_ENDOK)
            {
              warning(3); //HEC
                //ledSet(3);
            }
    
            // Clear interrupt and continue as master.
            RFIRQF1 = 0;
    
            // Set to a undefined value in enum type end cause.
            PRF_ENDCAUSE = TASK_UNDEF;
    
            ++packetCounter;
        }
    }
    

  • David Paulsen said:
    Thanks so much for your suggestions!  I think I found the problem.  The FPGA has a PLL that generates its clock frequency, and it seems to have a startup problem.  When it fails, the SPI frequency is almost 3 Mbps instead of 2 Mbps.  With that fixed, it seems to work much more reliably now.

    I didn't see this follow-up when I posted the previous reply (I had started writing it some hours ago).  I am glad you found the issue!