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.

Implement a micro second delay using SYSBIOS

Other Parts Discussed in Thread: SYSBIOS

DSP = C6748
SYSBIOS = V6.37.5.35
Code Composer = V5.5

What is the best way to implement a micro second delay, that doesn't yield, using SYSBIOS?  I've done millisecond delays (see code below), but don't know the best way to implement a micro second delay.

/********************************************************************************************************************************/

/* void MilliSecDelayWithoutYield(U32 mSDelay) */

/* */

/* Delay for xx milliseconds WITHOUT yielding (no TASK switch). This function provides a MINIMUM delay. The actual delay */

/* using this function may be more than you requested (due to HWI/SWI still running and getting to close to roll over). */

/* */

/* Parameters: */

/* - mSDelay: number of milliseconds to delay */

/* */

/* Returns: none */

/* */

/* Notes: Public API function that can be called from the TASK level. */

/********************************************************************************************************************************/

void MilliSecDelayWithoutYield(U32 mSDelay)

{

UInt restore_key = Task_disable(); /* Disable TASKS so our checking of Clock_getTicks() is accurate. */

U32 Timestamp = Clock_getTicks();

U64 OverflowCheck = Timestamp + mSDelay; /* How close are we to rolling over the U32 system clock? */

/* Check if we are close to a roll over. If we are too close, then just wait for the roll over to happen, then do the delay.

This adds more time than what was expected, but this routine is designed to provide a MINIMUM delay, not an exact delay.

This way we don't have to worry about a delay spanning the roll over, or a rare edge condition that exists if the delay

plus the current time is close to 0xFFFFFFFF. In that case we could be miss seeing the 0xFFFFFFFF because maybe we got

interrupted by a HWI/SWI combo, and we would be stuck here for 49.7 days. */

if( OverflowCheck >= 0x00000000FFFFFFF0 )

{

/* We are 1mS to 16mS from rolling the clock over. Just wait for that to happen before doing the real requested delay. */

while( Clock_getTicks() > 0x00000100 )

{

/* Do nothing while we wait for the clock to roll over. */

}

}

Timestamp = Clock_getTicks();

while( Clock_getTicks() < (Timestamp + mSDelay) )

{

/* Do nothing while we wait for the delay to expire. */

}

Task_restore(restore_key); /* Restore TASK's to their previous state. */

}

  • Dean,

    I believe this is in the works right now. Let me talk to my colleague on Monday and get the scoop on it.

    Steve
  • Dean,

    I spoke to my coworker about this.  Would the following work for you?

        #include <xdc/runtime/System.h>
        #include <xdc/runtime/Types.h>
        #include <xdc/runtime/Timestamp.h>
    
        Types_FreqHz freq;
        UInt32 ticksPerUsec;
        UInt32 startTicks, endTicks, ticks;
    
        /* freq is timestamp counts per second */
        Timestamp_getFreq(&freq);
    
        ticksPerUsec = freq.lo / 1000000;
        if (ticksPerUsec == 0) {
            // Wait at least one tick
            ticksPerUsec = 1;
        }
    
        startTicks = ticks = Timestamp_get32();
        endTicks = startTicks + ticksPerUsec;
        while (ticks < endTicks) {
            ticks = Timestamp_get32();
        }
    

    Steve

  • That code has the potential to hang indefinitely if endTicks happens to be close to 2^32-1 (and UInt32 is exactly 32 bits wide).

  • I agree with Markus that your example doesn't account for the 32bit roll over. I believe the code below does want I want. Please review and let me know if you see something wrong. By the way, when you enable the TimeStamp module in the config file, what hardware piece inside the C6748 does it use? The ROV tool didn't tell me.

    /********************************************************************************************************************************/
    /* void MicroSecDelayWithoutYield(U32 uSDelay) */
    /* */
    /* Delay for xx microseconds WITHOUT yielding (no TASK switch). This function provides a MINIMUM delay. The actual delay */
    /* using this function may be more than you requested (due to HWI/SWI still running). */
    /* */
    /* Parameters: */
    /* - uSDelay: number of microseconds to delay */
    /* */
    /* Returns: none */
    /* */
    /* Notes: Public API function that can be called from the TASK level. */
    /********************************************************************************************************************************/
    void MicroSecDelayWithoutYield( U32 uSDelay )
    {
    UInt task_restore_key = Task_disable(); /* Disable TASKS so we can't get preempted by a higher TASK. */
    U64 usec_delay_in_ticks = 0;
    U64 StartTicks = 0;
    U64 CurrentTicks = 0;
    Types_FreqHz freq;
    Types_Timestamp64 BigTicksStamp;

    if( uSDelay != 0 )
    {
    /* Figure out how many ticks it takes to equal 1uS. */
    Timestamp_getFreq(&freq);
    usec_delay_in_ticks = (U64)((freq.lo / 1000000) * uSDelay);

    /* We don't have to worry about checking for a roll over. Our max DSP frequency is 375MHz, or 2.66nS per "tick". A U64
    variable is 1.8 x 10 to the 19th power (really f'ing big). It will take over 1500 years for the Timestamp to roll over. */
    Timestamp_get64(&BigTicksStamp);
    StartTicks = BigTicksStamp.hi;
    StartTicks = StartTicks << 32;
    StartTicks = StartTicks | BigTicksStamp.lo;
    while( CurrentTicks < (StartTicks + usec_delay_in_ticks) )
    {
    /* Do nothing while we wait for the delay to expire. */
    Timestamp_get64(&BigTicksStamp);
    CurrentTicks = BigTicksStamp.hi;
    CurrentTicks = CurrentTicks << 32;
    CurrentTicks = CurrentTicks | BigTicksStamp.lo;
    }
    }

    Task_restore(task_restore_key); /* Restore TASK's to their previous state. */
    }
  • Hi Dean,

    You are correct that the example code does not take into account rollover.  You could modify it as follows:

    UInt32 ticksPerUsec;
    UInt32 endTicks, ticks;
    endTicks = Timestamp_get32() + ticksPerUsec;
    do () {
        ticks = Timestamp_get32();
    } while (endTicks - ticks < ticksPerUsec);
    The 674 Timestamp uses TSCL and TSCH.
    Best regards,
    Janet
  • Janet,

    I don't believe your modification takes into account a MINIMUM delay. For example, lets say ticksPerUsec = 400 and endTicks = 1. endTicks could equal 1 if the Timestamp was close to the roll over point and adding the 400 caused it to roll over. Move to the dowhile loop, and ticks may now equal 0xFFFFFFF0 (hasn't rolled over yet). Your while loop will exit early and not give you the delay you want.

    I'm looking for a routine where I can pass in xxx number of microsecond to delay, and that routine will provide that delay (at a minimum) without yielding to other tasks. I believe my code that I posted above achieves that (using the 64bit Timestamp). I'm just looking for someone (you, Steve, Bueller, anyone) to agree.

    By the way, my product runs for months without rebooting or restarting, so I have to take into account timers rolling over.

    Thanks, Dean
  • Hi Dean,

    Your code looks correct, and you do need the Task_disable() / Task_restore() if you want to prevent preemption by a higher priority task.  In the rollover case, by using UInt32 for ticks and endTicks, I think my loop should still be ok.  According to my calculator, 1 - 0xFFFFFFF0 = 0x11 < 400.

    Best regards,

        Janet

  • Janet,

    That is what I get for trying to focus on a Friday. I believe your code modification does work since all variables are unsigned. Thanks for verifying my code looks OK. I like that solution better (easier to understand in my mind), so I hit the Verify Answer on that post. Thanks again for your help.

    - Dean