package delay import ( "machine" "time" ) /* #include #include bool tinygo_drivers_sleep(uint32_t ticks); */ import "C" // Sleep for a very precise short duration by busy-waiting for the given time. // This is not an efficient way to sleep: it will needlessly burn cycles while // sleeping. But it is useful for sleeping for a very short duration, for // example for bit-banged protocols. // // Longer durations (longer than a few milliseconds) will be handled by calling // time.Sleep instead. // // This function should be called with a constant duration value, in which case // the call will typically be fully inlined and only take up around nine // instructions for the entire loop. // //go:inline func Sleep(duration time.Duration) { if time.Duration(uint32(duration)&0xff_ffff) != duration { // This is a long duration (more than 16ms) which shouldn't be done by // busy-waiting. time.Sleep(duration) return } // Calculate the number of cycles we should sleep: // cycles = duration * freq / 1e9 // Avoiding a 64-bit division: // cycles = duration * (freq/1000_000) / 1000 // // This assumes: // * The CPU frequency is a constant and can trivially be // const-propagated, therefore the divide by 1000_000 is done at compile // time. // * The CPU frequency is a multiple of 1000_000, which is true for most // chips (examples: 16MHz, 48MHz, 120MHz, etc). // * The division by 1000 can be done efficiently (Cortex-M3 and up), or // can be fully const-propagated. // * The CPU frequency is lower than 256MHz. If it is higher, long sleep // times (1-16ms) may not work correctly. cycles := uint32(duration) * (machine.CPUFrequency() / 1000_000) / 1000 slept := C.tinygo_drivers_sleep(C.uint32_t(cycles)) if !slept { // Fallback for platforms without inline assembly support. time.Sleep(duration) } }