github.com/tinygo-org/tinygo@v0.31.3-0.20240404173401-90b0bf646c27/src/runtime/runtime_esp8266.go (about)

     1  //go:build esp8266
     2  
     3  package runtime
     4  
     5  import (
     6  	"device"
     7  	"device/esp"
     8  	"machine"
     9  	"unsafe"
    10  )
    11  
    12  type timeUnit int64
    13  
    14  var currentTime timeUnit = 0
    15  
    16  func putchar(c byte) {
    17  	machine.Serial.WriteByte(c)
    18  }
    19  
    20  func getchar() byte {
    21  	for machine.Serial.Buffered() == 0 {
    22  		Gosched()
    23  	}
    24  	v, _ := machine.Serial.ReadByte()
    25  	return v
    26  }
    27  
    28  func buffered() int {
    29  	return machine.Serial.Buffered()
    30  }
    31  
    32  // Write to the internal control bus (using I2C?).
    33  // Signature found here:
    34  // https://github.com/espressif/ESP8266_RTOS_SDK/blob/14171de0/components/esp8266/include/esp8266/rom_functions.h#L54
    35  //
    36  //export rom_i2c_writeReg
    37  func rom_i2c_writeReg(block, host_id, reg_add, data uint8)
    38  
    39  //export main
    40  func main() {
    41  	// Clear .bss section. .data has already been loaded by the ROM bootloader.
    42  	preinit()
    43  
    44  	// Initialize PLL.
    45  	// I'm not quite sure what this magic incantation means, but it does set the
    46  	// esp8266 to the right clock speed. Without this, it is running too slow.
    47  	rom_i2c_writeReg(103, 4, 1, 136)
    48  	rom_i2c_writeReg(103, 4, 2, 145)
    49  
    50  	// Initialize UART.
    51  	machine.InitSerial()
    52  
    53  	// Initialize timer. Bits:
    54  	//  ENABLE:   timer enable
    55  	//  ROLLOVER: automatically reload when hitting 0
    56  	//  PRESCALE: divide by 256
    57  	esp.TIMER.FRC1_CTRL.Set(
    58  		esp.TIMER_FRC1_CTRL_TIMER_ENABLE | esp.TIMER_FRC1_CTRL_ROLLOVER | esp.TIMER_FRC1_CTRL_PRESCALE_DIVIDER_DEVIDED_BY_256<<esp.TIMER_FRC1_CTRL_PRESCALE_DIVIDER_Pos)
    59  	esp.TIMER.FRC1_LOAD.Set(0x3fffff)  // set all 22 bits to 1
    60  	esp.TIMER.FRC1_COUNT.Set(0x3fffff) // set all 22 bits to 1
    61  
    62  	run()
    63  
    64  	// Fallback: if main ever returns, hang the CPU.
    65  	exit(0)
    66  }
    67  
    68  //go:extern _sbss
    69  var _sbss [0]byte
    70  
    71  //go:extern _ebss
    72  var _ebss [0]byte
    73  
    74  func preinit() {
    75  	// Initialize .bss: zero-initialized global variables.
    76  	ptr := unsafe.Pointer(&_sbss)
    77  	for ptr != unsafe.Pointer(&_ebss) {
    78  		*(*uint32)(ptr) = 0
    79  		ptr = unsafe.Add(ptr, 4)
    80  	}
    81  }
    82  
    83  func ticks() timeUnit {
    84  	// Get the counter value of the timer. It is 22 bits and starts with all
    85  	// ones (0x3fffff). To make it easier to work with, let it count upwards.
    86  	count := 0x3fffff - esp.TIMER.FRC1_COUNT.Get()
    87  
    88  	// Replace the lowest 22 bits of the current time with the counter.
    89  	newTime := (currentTime &^ 0x3fffff) | timeUnit(count)
    90  
    91  	// If there was an overflow, the new time will be lower than the current
    92  	// time, so will need to add (1<<22).
    93  	if newTime < currentTime {
    94  		newTime += 0x400000
    95  	}
    96  
    97  	// Update the timestamp for the next call to ticks().
    98  	currentTime = newTime
    99  
   100  	return currentTime
   101  }
   102  
   103  const tickNanos = 3200 // time.Second / (80MHz / 256)
   104  
   105  func ticksToNanoseconds(ticks timeUnit) int64 {
   106  	return int64(ticks) * tickNanos
   107  }
   108  
   109  func nanosecondsToTicks(ns int64) timeUnit {
   110  	return timeUnit(ns / tickNanos)
   111  }
   112  
   113  // sleepTicks busy-waits until the given number of ticks have passed.
   114  func sleepTicks(d timeUnit) {
   115  	sleepUntil := ticks() + d
   116  	for ticks() < sleepUntil {
   117  	}
   118  }
   119  
   120  func exit(code int) {
   121  	abort()
   122  }
   123  
   124  func abort() {
   125  	for {
   126  		device.Asm("waiti 0")
   127  	}
   128  }