|
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 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
}
|