• Not Answered

CC2430, Simpliciti, and sleep mode

I'm writing a simple Simpliciti application where an end device samples an A/D channel once per second, then sends the data to an access point and then sleeps in between sampling.  I read DN106 and included the code from that app note.  What happens is that the end device goes to sleep, then wakes up once, then goes back to sleep and never wakes up again.  Here's the relavent code:

#pragma vector=ST_VECTOR
__interrupt void ST_IRQ (void)
{
   unsigned short sample=0;

   // Clear IRCON.STIF (Sleep Timer CPU interrupt flag)
   IRCON &= 0x7F;

   sample = AdcRead(0); // P0_0

   data_buffer[0] = LO_UINT16( sample );
   data_buffer[1] = HI_UINT16( sample );
   SMPL_Send(sLinkID1,data_buffer,BUFFER_LENGTH);

  // Set SLEEP.MODE according to desired PM, e.g. PM1.
  SLEEP = (SLEEP & 0xFC) | 0x01;
  // Apply three NOPs to allow the corresponding interrupt blocking to take
  // effect, before verifying the SLEEP.MODE bits below. Note that all
  // interrupts are blocked when SLEEP.MODE ‚ 0, thus the time between
  // setting SLEEP.MODE ‚ 0, and asserting PCON.IDLE should be as short as
  // possible. If an interrupt occurs before the NOPs have completed, then
  // the enabled ISR shall clear the SLEEP.MODE bits, according to the code
  // in Figure 7.
  asm("NOP");
  asm("NOP");
  asm("NOP");
  // If no interrupt was executed in between the above NOPs, then all
  // interrupts are effectively blocked when reaching this code position.
  // If the SLEEP.MODE bits have been cleared at this point, which means
  // that an ISR has indeed executed in between the above NOPs, then the
  // application will not enter PM{1 . 3} !
  if (SLEEP & 0x03)
  {
  // Set PCON.IDLE to enter the selected PM, e.g. PM1.
  PCON |= 0x01;
  // The SoC is now in PM and will only wake up upon Sleep Timer interrupt
  // or external Port interrupt.
  // First instruction upon exiting PM.
  asm("NOP");
  }

   // Clear the SLEEP.MODE bits, because an interrupt can also occur before
   // the SoC has actually entered PM. If this interrupt occurs in between the
   // three NOPs (that is; before the corresponding interrupt blocking has
   // actually taken effect) in Figure 2, then this clearing of the SLEEP.MODE
   // bits will ensure that the application does not enter PM{1 – 3}.
   SLEEP &= 0xFC; // Not required when resuming from PM0 }

void main(void)
{
  addr_t addr = {0x7A,0x56,0x34,MODULE_ADDR};

  // Set first byte of the buffer to the module address, don't overwrite.
  // MS bit, if set, used to indicate low battery
  data_buffer[0] = MODULE_ADDR;

  BSP_Init();

  ///////////// Code section #1 begin: Switch to [HS RCOSC] ////////////
  // Power up [HS RCOSC] (SLEEP.OSC_PD = 0)
  SLEEP &= ~0x04;
  // Wait until [HS RCOSC] is stable (SLEEP.HFRC_STB = 1)
  while ( ! (SLEEP & 0x20) );
  // Switch system clock source to HS RCOSC (CLKCON.OSC = 1)
  CLKCON |= 0x40;
  // Wait until system clock source has actually changed (CLKCON.OSC = 1)
  while ( !(CLKCON & 0x40) );
  // Power down [HS XOSC] (SLEEP.OSC_PD = 1)
  SLEEP |= 0x04;

 /* set device address before the
   * call to SMPL_Init(). If the address is set here the ROM value will not
   * be used. If SMPL_Init() runs before this IOCTL is used the IOCTL call
   * will not take effect. One shot only. The IOCTL call below is conformal.
   */

  SMPL_Ioctl(IOCTL_OBJ_ADDR, IOCTL_ACT_SET, &addr);

  /* Keep trying to join until successful. Toggle LEDs to indicate that
   * joining has not occurred.
   */
  while (SMPL_SUCCESS != SMPL_Init(sCB))
  {
    toggleLED(1);
    SPIN_ABOUT_A_SECOND;
  }

  // LEDs on solid to indicate successful join.
  if (!BSP_LED1_IS_ON())
  {
    toggleLED(1);
  }

  // Keep trying to link...
  while (SMPL_SUCCESS != SMPL_Link(&sLinkID1))
  {
    toggleLED(1);
    SPIN_ABOUT_A_SECOND;
  }

  // wake up radio. we need it to listen for broad cast messages.
  SMPL_Ioctl( IOCTL_OBJ_RADIO, IOCTL_ACT_RADIO_AWAKE, 0);

  // turn on RX. default is RX off.
  SMPL_Ioctl( IOCTL_OBJ_RADIO, IOCTL_ACT_RADIO_RXON, 0);

  // 24 bit register that sets when the wakeup timer triggers
  // uses 34 khz clock.  All 0xff's would be 8.2 min.
  ST2 = 0x00;
  ST1 = 0xFF;
  ST0 = 0xFF;

  IRCON &= 0x7F;  // Clear IRCON.STIF (Sleep Timer CPU interrupt flag)

  STIE = 1;
  EA = 1;

  // Set SLEEP.MODE according to desired PM, e.g. PM1.
  SLEEP = (SLEEP & 0xFC) | 0x01;
  // Apply three NOPs to allow the corresponding interrupt blocking to take
  // effect, before verifying the SLEEP.MODE bits below. Note that all
  // interrupts are blocked when SLEEP.MODE ‚ 0, thus the time between
  // setting SLEEP.MODE ‚ 0, and asserting PCON.IDLE should be as short as
  // possible. If an interrupt occurs before the NOPs have completed, then
  // the enabled ISR shall clear the SLEEP.MODE bits, according to the code
  // in Figure 7.
  asm("NOP");
  asm("NOP");
  asm("NOP");
  // If no interrupt was executed in between the above NOPs, then all
  // interrupts are effectively blocked when reaching this code position.
  // If the SLEEP.MODE bits have been cleared at this point, which means
  // that an ISR has indeed executed in between the above NOPs, then the
  // application will not enter PM{1 . 3} !
  if (SLEEP & 0x03)
  {
  // Set PCON.IDLE to enter the selected PM, e.g. PM1.
  PCON |= 0x01;
  // The SoC is now in PM and will only wake up upon Sleep Timer interrupt
  // or external Port interrupt.
  // First instruction upon exiting PM.
  asm("NOP");
  }

  while (1);
}

Any ideas?

3 Replies