If you’ve worked with the TI-RTOS (SYS/BIOS), you probably used Task_sleep() function
for delays. It works fine on LaunchPads… until you move to a custom board. Suddenly, Task_sleep()
does not behave correctly your delays are off (Time delays not working), the system doesn’t respond at all and the board will reset loop with watchdog reset.
Here’s why:Task_sleep()
depends on the RTOS clock source (like the 32 kHz crystal). On LaunchPads have this ready to go. But on custom boards, if the LF clock isn’t there or isn’t configured, Task_sleep()
won’t behave.
✅ Solution: Use the TI Timer Driver for delays.
It gives you hardware-backed, reliable timing that works on any board.
How It Works
- Timer Initialization
TheinitDelayTimer()
function are creates and configures a hardware timer (CONFIG_TIMER_0
) in one-shot mode with a callback. - Starting the Delay
Thedelay_ms()
function configures the timer period in microseconds and starts the timer. - Callback Execution
When the timer is expires,delayTimerCallback()
is invoked. It sets a flag (delayDone = 1
) and stops the timer. - Busy Wait
The calling code waits until the flag is set, effectively creating a blocking delay. - Wrapper for Seconds
Thedelay()
function is just a convenience wrapper for thedelay_ms()
.
Why this is better than Task_sleep()
:
- Works even without LF clock setup.
- Exact hardware timing
- Portable for LaunchPads and custom boards
- Flexible for both short and long delays
⚠️ Note: Uses a busy-wait loop. For the short delays, it is fine but long delays (especially in low-power devices), replace the loop with a semaphore or event so the CPU can sleep while waiting.
Here is the implementation (Creating a delay.c for portable access):
(delay.c)
#include "delay.h"
#include <ti/drivers/Timer.h>
#include "ti_drivers_config.h" // CONFIG_TIMER_0
static volatile uint8_t delayDone = 0;
static Timer_Handle timerHandle = NULL;
// Callback when timer expires
static void delayTimerCallback(Timer_Handle handle, int_fast16_t status)
{
delayDone = 1;
Timer_stop(handle);
}
// Initialize the timer (runs once)
static void initDelayTimer(void)
{
if(timerHandle) return; // already initialized
Timer_Params tParams;
Timer_Params_init(&tParams);
tParams.timerMode = Timer_ONESHOT_CALLBACK;
tParams.timerCallback = delayTimerCallback;
timerHandle = Timer_open(CONFIG_TIMER_0, &tParams);
if(!timerHandle) while(1); // trap if timer creation fails
}
// Millisecond delay
void delay_ms(int milliseconds)
{
initDelayTimer();
delayDone = 0;
Timer_setPeriod(timerHandle, Timer_PERIOD_US, (uint32_t)milliseconds * 1000);
Timer_start(timerHandle);
while(!delayDone); // Busy-wait until callback
}
// Second delay
void delay(int seconds)
{
delay_ms(seconds * 1000);
}
(Delay.h)
#ifndef DELAY_H
#define DELAY_H
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Delay for a number of seconds
*
* @param seconds Number of seconds to delay
*/
void delay(int seconds);
/**
* @brief Delay for a number of milliseconds
*
* @param milliseconds Number of milliseconds to delay
*/
void delay_ms(int milliseconds);
#ifdef __cplusplus
}
#endif
#endif // DELAY_H
✅ Now you created a self-contained delay library:
- Include
delay.h
wherever you need to create delay. - Add
delay.c
to your project sources. - Ensure the Timer (
CONFIG_TIMER_0
) is configured in SysConfig.
Now you are got a rock-solid delays – no more surprises when moving from eval boards to the production board!.
Conclusion
While Task_sleep()
works on the TI evaluation kits like LaunchPads (MSP, CC1310, CC1354, CC1653…), it often fails on custom boards due to the clock source dependencies, In my case we are using the CC1354P10-1 LaunchPad to Custom Board to facing the issue on clock source while using Task_sleep functions. The solution is to implement your own delay functions using the Timer Driver, which ensures accurate and reliable delays across all the hardware platforms.
This approach gives you full control over timing and eliminates reliance on RTOS (SYS/BIOS) tick configurations, The preferred method is for robust embedded applications :).