eCos Product
RedBoot Product
Supported Hardware |
![]() RedBoot TimerRedBoot 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 implementationvoid 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 implementationexternC 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 implementationvoid 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 } |