/*************************************************************************************************** * @fn HalLedOnOff * * @brief Turns specified LED ON or OFF * * @param leds - LED bit mask * mode - LED_ON,LED_OFF, * * @return none ***************************************************************************************************/ void HalLedOnOff (uint8 leds, uint8 mode) { if (leds & HAL_LED_1) { if (mode == HAL_LED_MODE_ON) { HAL_TURN_ON_LED1(); } else { HAL_TURN_OFF_LED1(); } } if (leds & HAL_LED_2) { if (mode == HAL_LED_MODE_ON) { HAL_TURN_ON_LED2(); } else { HAL_TURN_OFF_LED2(); } } if (leds & HAL_LED_3) { if (mode == HAL_LED_MODE_ON) { HAL_TURN_ON_LED3(); } else { HAL_TURN_OFF_LED3(); } } if (leds & HAL_LED_4) { if (mode == HAL_LED_MODE_ON) { HAL_TURN_ON_LED4(); } else { HAL_TURN_OFF_LED4(); } } /* Remember current state */ if (mode) { HalLedState |= leds; } else { HalLedState &= (leds ^ 0xFF); } }
/*************************************************************************************************** * @fn HalLedOnOff * * @brief Turns specified LED ON or OFF * * @param leds - LED bit mask * mode - LED_ON,LED_OFF, * * @return none ***************************************************************************************************/ void HalLedOnOff( uint8 leds, uint8 mode ) { if ( leds & HAL_LED_1 ) { if ( mode == HAL_LED_MODE_ON ) HAL_TURN_ON_LED1(); else HAL_TURN_OFF_LED1(); } if ( leds & HAL_LED_2 ) { if ( mode == HAL_LED_MODE_ON ) HAL_TURN_ON_LED2(); else HAL_TURN_OFF_LED2(); } if ( leds & HAL_LED_3 ) { if ( mode == HAL_LED_MODE_ON ) HAL_TURN_ON_LED3(); else HAL_TURN_OFF_LED3(); } if ( leds & HAL_LED_4 ) { if ( mode == HAL_LED_MODE_ON ) HAL_TURN_ON_LED4(); else HAL_TURN_OFF_LED4(); } // Remember current state if ( mode ) ledState |= leds; else ledState &= (0xff ^ leds); }
/************************************************************************************************** * @fn halAssertHazardLights * * @brief Blink LEDs to indicate an error. * * @param none * * @return none ************************************************************************************************** */ void halAssertHazardLights(void) { enum { DEBUG_DATA_RSTACK_HIGH_OFS, DEBUG_DATA_RSTACK_LOW_OFS, DEBUG_DATA_TX_ACTIVE_OFS, DEBUG_DATA_RX_ACTIVE_OFS, #if (defined HAL_MCU_AVR) || (defined HAL_MCU_CC2430) DEBUG_DATA_INT_MASK_OFS, #elif (defined HAL_MCU_CC2530) || (defined HAL_MCU_CC2533) DEBUG_DATA_INT_MASK0_OFS, DEBUG_DATA_INT_MASK1_OFS, #endif DEBUG_DATA_SIZE }; uint8 buttonHeld; uint8 debugData[DEBUG_DATA_SIZE]; /* disable all interrupts before anything else */ HAL_DISABLE_INTERRUPTS(); /*------------------------------------------------------------------------------- * Initialize LEDs and turn them off. */ HAL_BOARD_INIT(); HAL_TURN_OFF_LED1(); HAL_TURN_OFF_LED2(); HAL_TURN_OFF_LED3(); HAL_TURN_OFF_LED4(); /*------------------------------------------------------------------------------- * Master infinite loop. */ for (;;) { buttonHeld = 0; /*------------------------------------------------------------------------------- * "Hazard lights" loop. A held keypress will exit this loop. */ do { HAL_LED_BLINK_DELAY(); /* toggle LEDS, the #ifdefs are in case HAL has logically remapped non-existent LEDs */ #if (HAL_NUM_LEDS >= 1) HAL_TOGGLE_LED1(); #if (HAL_NUM_LEDS >= 2) HAL_TOGGLE_LED2(); #if (HAL_NUM_LEDS >= 3) HAL_TOGGLE_LED3(); #if (HAL_NUM_LEDS >= 4) HAL_TOGGLE_LED4(); #endif #endif #endif #endif /* escape hatch to continue execution, set escape to '1' to continue execution */ { static uint8 escape = 0; if (escape) { escape = 0; return; } } /* break out of loop if button is held long enough */ if (HAL_PUSH_BUTTON1()) { buttonHeld++; } else { buttonHeld = 0; } } while (buttonHeld != 10); /* loop until button is held specified number of loops */ /*------------------------------------------------------------------------------- * Just exited from "hazard lights" loop. */ /* turn off all LEDs */ HAL_TURN_OFF_LED1(); HAL_TURN_OFF_LED2(); HAL_TURN_OFF_LED3(); HAL_TURN_OFF_LED4(); /* wait for button release */ HAL_DEBOUNCE(!HAL_PUSH_BUTTON1()); /*------------------------------------------------------------------------------- * Load debug data into memory. */ #ifdef HAL_MCU_AVR { uint8 * pStack; pStack = (uint8 *) SP; pStack++; /* point to return address on stack */ debugData[DEBUG_DATA_RSTACK_HIGH_OFS] = *pStack; pStack++; debugData[DEBUG_DATA_RSTACK_LOW_OFS] = *pStack; } debugData[DEBUG_DATA_INT_MASK_OFS] = EIMSK; #endif #if (defined HAL_MCU_CC2430) debugData[DEBUG_DATA_INT_MASK_OFS] = RFIM; #elif (defined HAL_MCU_CC2530) || (defined HAL_MCU_CC2533) debugData[DEBUG_DATA_INT_MASK0_OFS] = RFIRQM0; debugData[DEBUG_DATA_INT_MASK1_OFS] = RFIRQM1; #endif #if (defined HAL_MCU_AVR) || (defined HAL_MCU_CC2430) || (defined HAL_MCU_CC2530) || \ (defined HAL_MCU_CC2533) || (defined HAL_MCU_MSP430) debugData[DEBUG_DATA_TX_ACTIVE_OFS] = macTxActive; debugData[DEBUG_DATA_RX_ACTIVE_OFS] = macRxActive; #endif /* initialize for data dump loop */ { uint8 iBit; uint8 iByte; iBit = 0; iByte = 0; /*------------------------------------------------------------------------------- * Data dump loop. A button press cycles data bits to an LED. */ while (iByte < DEBUG_DATA_SIZE) { /* wait for key press */ while(!HAL_PUSH_BUTTON1()); /* turn on all LEDs for first bit of byte, turn on three LEDs if not first bit */ HAL_TURN_ON_LED1(); HAL_TURN_ON_LED2(); HAL_TURN_ON_LED3(); if (iBit == 0) { HAL_TURN_ON_LED4(); } else { HAL_TURN_OFF_LED4(); } /* wait for debounced key release */ HAL_DEBOUNCE(!HAL_PUSH_BUTTON1()); /* turn off all LEDs */ HAL_TURN_OFF_LED1(); HAL_TURN_OFF_LED2(); HAL_TURN_OFF_LED3(); HAL_TURN_OFF_LED4(); /* output value of data bit to LED1 */ if (debugData[iByte] & (1 << (7 - iBit))) { HAL_TURN_ON_LED1(); } else { HAL_TURN_OFF_LED1(); } /* advance to next bit */ iBit++; if (iBit == 8) { iBit = 0; iByte++; } } } /* * About to enter "hazard lights" loop again. Turn off LED1 in case the last bit * displayed happened to be one. This guarantees all LEDs are off at the start of * the flashing loop which uses a toggle operation to change LED states. */ HAL_TURN_OFF_LED1(); } }
/************************************************************************************************** * @fn main * * @brief C-code main functionality. * * input parameters * * None. * * output parameters * * None. * * @return None. ************************************************************************************************** */ void main(void) { uint8 time_spent_validating; uint8 bootloaderForcedByMainApp = FALSE; uint32 mainAppCommandLocal = mainAppCommand; vddWait(VDD_MIN_RUN); mainAppCommand = MAIN_APP_CMD_NONE; if (mainAppCommandLocal == MAIN_APP_CMD_FORCE_BOOTLOADER) { bootloaderForcedByMainApp = TRUE; } else if ((mainAppCommandLocal == MAIN_APP_CMD_PASS_THROUGH) || ((SLEEPSTA & LRESET) == RESETWD)) { // If reset due to WatchDog Timer - Transfer control to the main application immediately. // WatchDog Timer reset causes the hardware to disconnect the USB. Withought this jump here, // the SBL code will try to initiaize the CDC too early, which causes undesired behavior on the host // (e.g. on beaglebone black - the host gets stuck) asm("LJMP 0x2000\n"); } sblInit(bootloaderForcedByMainApp); HAL_TURN_ON_LED1(); HAL_TURN_ON_LED2(); if ((!bootloaderForcedByMainApp) && (sbImgValid(&time_spent_validating))) { HAL_TURN_OFF_LED2(); if (sblWait(SBL_WAIT_TIME > time_spent_validating ? SBL_WAIT_TIME - time_spent_validating : 0)) { HAL_TURN_OFF_LED1(); sbReportState(SB_STATE_EXECUTING_IMAGE); while(sblIsUartTxPending()) { sbUartPoll(); } SLEEP(0x2600); //Give the last bytes in the HW TX fifo (if any) enough time to be transmitted while (SB1_PRESS || SB2_PRESS); sblUnInit(); // Simulate a reset for the Application code by an absolute jump to location 0x2000. asm("LJMP 0x2000\n"); } } HAL_TURN_OFF_LED1(); HAL_TURN_ON_LED2(); vddWait(VDD_MIN_NV); sblExec(); sblUnInit(); asm("LJMP 0x2000\n"); }
/************************************************************************************************** * @fn halSleep * * @brief This function is called from the OSAL task loop using and existing OSAL * interface. It sets the low power mode of the MAC and the CC2530. * * input parameters * * @param osal_timeout - Next OSAL timer timeout. * * output parameters * * None. * * @return None. ************************************************************************************************** */ void halSleep( uint16 osal_timeout ) { uint32 timeout; uint32 macTimeout = 0; /* get next OSAL timer expiration converted to 320 usec units */ timeout = HAL_SLEEP_MS_TO_320US(osal_timeout); if (timeout == 0) { timeout = MAC_PwrNextTimeout(); } else { /* get next MAC timer expiration */ macTimeout = MAC_PwrNextTimeout(); /* get lesser of two timeouts */ if ((macTimeout != 0) && (macTimeout < timeout)) { timeout = macTimeout; } } /* HAL_SLEEP_PM2 is entered only if the timeout is zero and * the device is a stimulated device. */ halPwrMgtMode = (timeout == 0) ? HAL_SLEEP_DEEP : HAL_SLEEP_TIMER; /* DEEP sleep can only be entered when zgPollRate == 0. * This is to eliminate any possibility of entering PM3 between * two network timers. */ #if ZG_BUILD_ENDDEVICE_TYPE && defined (NWK_AUTO_POLL) if ((timeout > HAL_SLEEP_MS_TO_320US(PM_MIN_SLEEP_TIME)) || (timeout == 0 && zgPollRate == 0)) #else if ((timeout > HAL_SLEEP_MS_TO_320US(PM_MIN_SLEEP_TIME)) || (timeout == 0)) #endif { halIntState_t ien0, ien1, ien2; HAL_ASSERT(HAL_INTERRUPTS_ARE_ENABLED()); HAL_DISABLE_INTERRUPTS(); /* always use "deep sleep" to turn off radio VREG on CC2530 */ if (halSleepPconValue != 0 && MAC_PwrOffReq(MAC_PWR_SLEEP_DEEP) == MAC_SUCCESS) { /* The PCON value is not zero. There is no interrupt overriding the * sleep decision. Also, the radio granted the sleep request. */ #if ((defined HAL_KEY) && (HAL_KEY == TRUE)) /* get peripherals ready for sleep */ HalKeyEnterSleep(); #endif #ifdef HAL_SLEEP_DEBUG_LED HAL_TURN_OFF_LED3(); #else /* use this to turn LEDs off during sleep */ HalLedEnterSleep(); #endif /* enable sleep timer interrupt */ if (timeout != 0) { if (timeout > HAL_SLEEP_MS_TO_320US( MAX_SLEEP_TIME )) { timeout -= HAL_SLEEP_MS_TO_320US( MAX_SLEEP_TIME ); halSleepSetTimer(HAL_SLEEP_MS_TO_320US( MAX_SLEEP_TIME )); } else { /* set sleep timer */ halSleepSetTimer(timeout); } /* set up sleep timer interrupt */ HAL_SLEEP_TIMER_CLEAR_INT(); HAL_SLEEP_TIMER_ENABLE_INT(); } #ifdef HAL_SLEEP_DEBUG_LED if (halPwrMgtMode == CC2530_PM1) { HAL_TURN_ON_LED1(); } else { HAL_TURN_OFF_LED1(); } #endif if (ZNP_CFG1_UART == znpCfg1) { HalUARTSuspend(); } /* Prep CC2530 power mode */ HAL_SLEEP_PREP_POWER_MODE(halPwrMgtMode); /* save interrupt enable registers and disable all interrupts */ HAL_SLEEP_IE_BACKUP_AND_DISABLE(ien0, ien1, ien2); HAL_ENABLE_INTERRUPTS(); /* set CC2530 power mode, interrupt is disabled after this function * Note that an ISR (that could wake up from power mode) which runs * between the previous instruction enabling interrupts and before * power mode is set would switch the halSleepPconValue so that * power mode shall not be entered in such a case. */ HAL_SLEEP_SET_POWER_MODE(); /* Disable interrupt immediately */ HAL_DISABLE_INTERRUPTS(); /* restore interrupt enable registers */ HAL_SLEEP_IE_RESTORE(ien0, ien1, ien2); /* disable sleep timer interrupt */ HAL_SLEEP_TIMER_DISABLE_INT(); if (ZNP_CFG1_UART == znpCfg1) { HalUARTResume(); } #ifdef HAL_SLEEP_DEBUG_LED HAL_TURN_ON_LED3(); #else /* use this to turn LEDs back on after sleep */ HalLedExitSleep(); #endif #if ((defined HAL_KEY) && (HAL_KEY == TRUE)) /* handle peripherals */ (void)HalKeyExitSleep(); #endif /* power on the MAC; blocks until completion */ MAC_PwrOnReq(); HAL_ENABLE_INTERRUPTS(); /* For CC2530, T2 interrupt won’t be generated when the current count is greater than * the comparator. The interrupt is only generated when the current count is equal to * the comparator. When the CC2530 is waking up from sleep, there is a small window * that the count may be grater than the comparator, therefore, missing the interrupt. * This workaround will call the T2 ISR when the current T2 count is greater than the * comparator. The problem only occurs when POWER_SAVING is turned on, i.e. the 32KHz * drives the chip in sleep and SYNC start is used. */ macMcuTimer2OverflowWorkaround(); } else { /* Sleep request is not granted. Check PCON value to see why the sleep is not granted. */ if (halSleepPconValue == 0) { /* An interrupt may have changed the sleep decision. Do not sleep at all. Turn on * the interrupt, exit normally, and the next sleep will be allowed. */ HAL_ENABLE_INTERRUPTS(); } else { /* PCON value is okay but Radio cannot enter power mode hence just put CPU to idle mode. * Interrupt will be enabled in halSleepEnterIdleMode(). */ halSleepEnterIdleMode(timeout); } } } else if (timeout > PM_MIN_IDLE_TIME) { /* Timeout is too close to enter power mode. Try idle mode. */ HAL_DISABLE_INTERRUPTS(); /* Interrupt will be enabled in halSleepEnterIdleMode(). */ halSleepEnterIdleMode(timeout); } }
/************************************************************************************************** * @fn halSleep * * @brief This function is called from the OSAL task loop using and existing OSAL * interface. It sets the low power mode of the MAC and the CC2530. * * input parameters * * @param osal_timeout - Next OSAL timer timeout. * * output parameters * * None. * * @return None. ************************************************************************************************** */ void halSleep( uint16 osal_timeout ) { uint32 timeout; uint32 macTimeout = 0; halAccumulatedSleepTime = 0; /* get next OSAL timer expiration converted to 320 usec units */ timeout = HAL_SLEEP_MS_TO_320US(osal_timeout); if (timeout == 0) { timeout = MAC_PwrNextTimeout(); } else { /* get next MAC timer expiration */ macTimeout = MAC_PwrNextTimeout(); /* get lesser of two timeouts */ if ((macTimeout != 0) && (macTimeout < timeout)) { timeout = macTimeout; } } /* HAL_SLEEP_PM2 is entered only if the timeout is zero and * the device is a stimulated device. */ halPwrMgtMode = (timeout == 0) ? HAL_SLEEP_DEEP : HAL_SLEEP_TIMER; /* DEEP sleep can only be entered when zgPollRate == 0. * This is to eliminate any possibility of entering PM3 between * two network timers. */ #if ZG_BUILD_ENDDEVICE_TYPE && defined (NWK_AUTO_POLL) if ((timeout > HAL_SLEEP_MS_TO_320US(PM_MIN_SLEEP_TIME)) || (timeout == 0 && zgPollRate == 0)) #else if ((timeout > HAL_SLEEP_MS_TO_320US(PM_MIN_SLEEP_TIME)) || (timeout == 0)) #endif { halIntState_t ien0, ien1, ien2; HAL_ASSERT(HAL_INTERRUPTS_ARE_ENABLED()); HAL_DISABLE_INTERRUPTS(); /* always use "deep sleep" to turn off radio VREG on CC2530 */ if (MAC_PwrOffReq(MAC_PWR_SLEEP_DEEP) == MAC_SUCCESS) { #if ((defined HAL_KEY) && (HAL_KEY == TRUE)) /* get peripherals ready for sleep */ HalKeyEnterSleep(); #endif #ifdef HAL_SLEEP_DEBUG_LED HAL_TURN_OFF_LED3(); #else /* use this to turn LEDs off during sleep */ HalLedEnterSleep(); #endif /* enable sleep timer interrupt */ if (timeout != 0) { if (timeout > HAL_SLEEP_MS_TO_320US( MAX_SLEEP_TIME )) { timeout -= HAL_SLEEP_MS_TO_320US( MAX_SLEEP_TIME ); halSleepSetTimer(HAL_SLEEP_MS_TO_320US( MAX_SLEEP_TIME )); } else { /* set sleep timer */ halSleepSetTimer(timeout); } /* set up sleep timer interrupt */ HAL_SLEEP_TIMER_CLEAR_INT(); HAL_SLEEP_TIMER_ENABLE_INT(); } #ifdef HAL_SLEEP_DEBUG_LED if (halPwrMgtMode == CC2530_PM1) { HAL_TURN_ON_LED1(); } else { HAL_TURN_OFF_LED1(); } #endif /* save interrupt enable registers and disable all interrupts */ HAL_SLEEP_IE_BACKUP_AND_DISABLE(ien0, ien1, ien2); HAL_ENABLE_INTERRUPTS(); /* set CC2530 power mode, interrupt is disabled after this function */ HAL_SLEEP_SET_POWER_MODE(halPwrMgtMode); /* the interrupt is disabled - see halSetSleepMode() */ /* restore interrupt enable registers */ HAL_SLEEP_IE_RESTORE(ien0, ien1, ien2); /* disable sleep timer interrupt */ HAL_SLEEP_TIMER_DISABLE_INT(); /* Calculate timer elasped */ halAccumulatedSleepTime += (HalTimerElapsed() / TICK_COUNT); #ifdef HAL_SLEEP_DEBUG_LED HAL_TURN_ON_LED3(); #else /* use this to turn LEDs back on after sleep */ HalLedExitSleep(); #endif #if ((defined HAL_KEY) && (HAL_KEY == TRUE)) /* handle peripherals */ (void)HalKeyExitSleep(); #endif /* power on the MAC; blocks until completion */ MAC_PwrOnReq(); HAL_ENABLE_INTERRUPTS(); /* For CC2530, T2 interrupt won’t be generated when the current count is greater than * the comparator. The interrupt is only generated when the current count is equal to * the comparator. When the CC2530 is waking up from sleep, there is a small window * that the count may be grater than the comparator, therefore, missing the interrupt. * This workaround will call the T2 ISR when the current T2 count is greater than the * comparator. The problem only occurs when POWER_SAVING is turned on, i.e. the 32KHz * drives the chip in sleep and SYNC start is used. */ macMcuTimer2OverflowWorkaround(); } else { HAL_ENABLE_INTERRUPTS(); } } }