tinygo.org/x/drivers@v0.27.1-0.20240509133757-7dbca2a54349/delay/sleep.go (about)

     1  package delay
     2  
     3  import (
     4  	"machine"
     5  	"time"
     6  )
     7  
     8  /*
     9  #include <stdint.h>
    10  #include <stdbool.h>
    11  bool tinygo_drivers_sleep(uint32_t ticks);
    12  */
    13  import "C"
    14  
    15  // Sleep for a very precise short duration by busy-waiting for the given time.
    16  // This is not an efficient way to sleep: it will needlessly burn cycles while
    17  // sleeping. But it is useful for sleeping for a very short duration, for
    18  // example for bit-banged protocols.
    19  //
    20  // Longer durations (longer than a few milliseconds) will be handled by calling
    21  // time.Sleep instead.
    22  //
    23  // This function should be called with a constant duration value, in which case
    24  // the call will typically be fully inlined and only take up around nine
    25  // instructions for the entire loop.
    26  //
    27  //go:inline
    28  func Sleep(duration time.Duration) {
    29  	if time.Duration(uint32(duration)&0xff_ffff) != duration {
    30  		// This is a long duration (more than 16ms) which shouldn't be done by
    31  		// busy-waiting.
    32  		time.Sleep(duration)
    33  		return
    34  	}
    35  
    36  	// Calculate the number of cycles we should sleep:
    37  	//   cycles = duration * freq / 1e9
    38  	// Avoiding a 64-bit division:
    39  	//   cycles = duration * (freq/1000_000) / 1000
    40  	//
    41  	// This assumes:
    42  	//   * The CPU frequency is a constant and can trivially be
    43  	//     const-propagated, therefore the divide by 1000_000 is done at compile
    44  	//     time.
    45  	//   * The CPU frequency is a multiple of 1000_000, which is true for most
    46  	//     chips (examples: 16MHz, 48MHz, 120MHz, etc).
    47  	//   * The division by 1000 can be done efficiently (Cortex-M3 and up), or
    48  	//     can be fully const-propagated.
    49  	//   * The CPU frequency is lower than 256MHz. If it is higher, long sleep
    50  	//     times (1-16ms) may not work correctly.
    51  	cycles := uint32(duration) * (machine.CPUFrequency() / 1000_000) / 1000
    52  	slept := C.tinygo_drivers_sleep(C.uint32_t(cycles))
    53  	if !slept {
    54  		// Fallback for platforms without inline assembly support.
    55  		time.Sleep(duration)
    56  	}
    57  }