eCos Product

eCos Net Distribution


RedBoot Product
 
RedBoot Net Distribution


Supported Hardware

Downloading and Installation

Documentation

FAQ

Keeping in Touch

Problems

Licensing

Anonymous CVS

Contributions and Third Party Projects

Red Hat eCos

RedBoot Timer


RedBoot requires a microsecond delay function in order to provide timeouts in scripts, ethernet driver and elsewhere. Without a properly defined delay function, RedBoot may behave erratic.

The platform should define HAL_DELAY_US() so it can be seen in the HAL common file hal_if.c. If the platform does not provide the macro, a simple delay loop will be used instead.

Below are three examples of delay function implementations.

MIPS architecture implementation

void 
hal_delay_us(int us)
{
    cyg_uint32 val1, val2;
    int diff;
    long usticks;
    long ticks;

    // Calculate the number of counter register ticks per microsecond.
    
    usticks = (CYGNUM_HAL_RTC_PERIOD * CYGNUM_HAL_RTC_DENOMINATOR) / 1000000;

    // Make sure that the value is not zero. This will only happen if the
    // CPU is running at < 2MHz.
    if( usticks == 0 ) usticks = 1;
    
    while( us > 0 )
    {
        int us1 = us;

        // Wait in bursts of less than 10000us to avoid any overflow
        // problems in the multiply.
        if( us1 > 10000 )
            us1 = 10000;

        us -= us1;

        ticks = us1 * usticks;

        asm volatile("mfc0 %0,$9;" : "=r"(val1));
        while (ticks > 0) {
            do {
                asm volatile("mfc0 %0,$9;" : "=r"(val2));
            } while (val1 == val2);
            diff = val2 - val1;
            if (diff < 0) diff += CYGNUM_HAL_RTC_PERIOD;
            ticks -= diff;
            val1 = val2;
        }
    }
}

PowerPC architecture implementation

externC void 
hal_delay_us(int us)
{
    cyg_int32 old_dec, new_dec;
    long ticks;
    int diff;

    // Note: the system constant CYGNUM_HAL_RTC_PERIOD corresponds to 10,000us
    // Scale the desired number of microseconds to be a number of decrementer ticks
    // Note: this test says "if there is more than one decrementer tick / us"
    if (CYGNUM_HAL_RTC_PERIOD > 10000) {
        ticks = ((long long)us * (CYGNUM_HAL_RTC_PERIOD * 100)) / 1000000;
    } else {
        ticks = us / (CYGNUM_HAL_RTC_PERIOD * 100) / 1000000;
    }
    asm volatile("mfdec  %0;" : "=r"(old_dec) : );
    while (ticks > 0) {
        do {
            asm volatile("mfdec  %0;" : "=r"(new_dec) : );        
        } while (old_dec == new_dec);
        if (new_dec < 0) {
            HAL_CLOCK_RESET(0, CYGNUM_HAL_RTC_PERIOD);
        }
        diff = (old_dec - new_dec);
        if (diff < 1) diff = 1;
        old_dec = new_dec;
        ticks -= diff;
    }
}

SH architecture implementation

void
hal_delay_us(int usecs)
{
    unsigned char _tstr;  // Current clock control
    volatile unsigned char *tstr = (volatile unsigned char *)CYGARC_REG_TSTR;
    volatile unsigned long *tcnt = (volatile unsigned long *)CYGARC_REG_TCNT1;
    volatile unsigned long *tcor = (volatile unsigned long *)CYGARC_REG_TCOR1;
    unsigned long clocks_per_us =
      ((CYGHWR_HAL_SH_ONCHIP_PERIPHERAL_SPEED+(CYGHWR_HAL_SH_TMU_PRESCALE_0-1))
       / CYGHWR_HAL_SH_TMU_PRESCALE_0);  // Rounded up
    int diff, diff2;
    cyg_uint32 val1, val2;

    _tstr = *tstr;
    *tstr |= CYGARC_REG_TSTR_STR1;  // Enable channel 1
    while (usecs-- > 0) {
        diff = 0;
        while (diff < clocks_per_us) {
            val1 = *tcnt;
            while ((val2 = *tcnt) == val1) ;
            diff2 = val2 - val1;
            if (diff2 < 0) diff2 += *tcor;
            diff += diff2;
        }
    }
    *tstr = _tstr;                  // Restore timer to previous state
}