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

     1  //go:build (sam && atsamd51) || (sam && atsame5x)
     2  
     3  package runtime
     4  
     5  import (
     6  	"device/arm"
     7  	"device/sam"
     8  	"machine"
     9  	"machine/usb/cdc"
    10  	"runtime/interrupt"
    11  	"runtime/volatile"
    12  )
    13  
    14  type timeUnit int64
    15  
    16  //export Reset_Handler
    17  func main() {
    18  	arm.SCB.CPACR.Set(0) // disable FPU if it is enabled
    19  	preinit()
    20  	run()
    21  	exit(0)
    22  }
    23  
    24  func init() {
    25  	initClocks()
    26  	initRTC()
    27  	initSERCOMClocks()
    28  	initUSBClock()
    29  	initADCClock()
    30  	enableCache()
    31  
    32  	cdc.EnableUSBCDC()
    33  	machine.USBDev.Configure(machine.UARTConfig{})
    34  	machine.InitSerial()
    35  }
    36  
    37  func putchar(c byte) {
    38  	machine.Serial.WriteByte(c)
    39  }
    40  
    41  func getchar() byte {
    42  	for machine.Serial.Buffered() == 0 {
    43  		Gosched()
    44  	}
    45  	v, _ := machine.Serial.ReadByte()
    46  	return v
    47  }
    48  
    49  func buffered() int {
    50  	return machine.Serial.Buffered()
    51  }
    52  
    53  func initClocks() {
    54  	// set flash wait state
    55  	sam.NVMCTRL.CTRLA.SetBits(0 << sam.NVMCTRL_CTRLA_RWS_Pos)
    56  
    57  	// software reset
    58  	sam.GCLK.CTRLA.SetBits(sam.GCLK_CTRLA_SWRST)
    59  	for sam.GCLK.SYNCBUSY.HasBits(sam.GCLK_SYNCBUSY_SWRST) {
    60  	}
    61  
    62  	// Set OSCULP32K as source of Generic Clock Generator 3
    63  	// GCLK->GENCTRL[GENERIC_CLOCK_GENERATOR_XOSC32K].reg = GCLK_GENCTRL_SRC(GCLK_GENCTRL_SRC_OSCULP32K) | GCLK_GENCTRL_GENEN; //generic clock gen 3
    64  	sam.GCLK.GENCTRL[3].Set((sam.GCLK_GENCTRL_SRC_OSCULP32K << sam.GCLK_GENCTRL_SRC_Pos) |
    65  		sam.GCLK_GENCTRL_GENEN)
    66  	for sam.GCLK.SYNCBUSY.HasBits(sam.GCLK_SYNCBUSY_GENCTRL_GCLK3) {
    67  	}
    68  
    69  	// Set OSCULP32K as source of Generic Clock Generator 0
    70  	sam.GCLK.GENCTRL[0].Set((sam.GCLK_GENCTRL_SRC_OSCULP32K << sam.GCLK_GENCTRL_SRC_Pos) |
    71  		sam.GCLK_GENCTRL_GENEN)
    72  	for sam.GCLK.SYNCBUSY.HasBits(sam.GCLK_SYNCBUSY_GENCTRL_GCLK0) {
    73  	}
    74  
    75  	// Enable DFLL48M clock
    76  	sam.OSCCTRL.DFLLCTRLA.Set(0)
    77  	sam.OSCCTRL.DFLLMUL.Set((0x1 << sam.OSCCTRL_DFLLMUL_CSTEP_Pos) |
    78  		(0x1 << sam.OSCCTRL_DFLLMUL_FSTEP_Pos) |
    79  		(0x0 << sam.OSCCTRL_DFLLMUL_MUL_Pos))
    80  	for sam.OSCCTRL.DFLLSYNC.HasBits(sam.OSCCTRL_DFLLSYNC_DFLLMUL) {
    81  	}
    82  
    83  	sam.OSCCTRL.DFLLCTRLB.Set(0)
    84  	for sam.OSCCTRL.DFLLSYNC.HasBits(sam.OSCCTRL_DFLLSYNC_DFLLCTRLB) {
    85  	}
    86  
    87  	sam.OSCCTRL.DFLLCTRLA.SetBits(sam.OSCCTRL_DFLLCTRLA_ENABLE)
    88  	for sam.OSCCTRL.DFLLSYNC.HasBits(sam.OSCCTRL_DFLLSYNC_ENABLE) {
    89  	}
    90  
    91  	sam.OSCCTRL.DFLLVAL.Set(sam.OSCCTRL.DFLLVAL.Get())
    92  	for sam.OSCCTRL.DFLLSYNC.HasBits(sam.OSCCTRL_DFLLSYNC_DFLLVAL) {
    93  	}
    94  
    95  	sam.OSCCTRL.DFLLCTRLB.Set(sam.OSCCTRL_DFLLCTRLB_WAITLOCK |
    96  		sam.OSCCTRL_DFLLCTRLB_CCDIS |
    97  		sam.OSCCTRL_DFLLCTRLB_USBCRM)
    98  	for !sam.OSCCTRL.STATUS.HasBits(sam.OSCCTRL_STATUS_DFLLRDY) {
    99  	}
   100  
   101  	// set GCLK7 to run at 2MHz, using DFLL48M as clock source
   102  	// GCLK7 = 48MHz / 24 = 2MHz
   103  	sam.GCLK.GENCTRL[7].Set((sam.GCLK_GENCTRL_SRC_DFLL << sam.GCLK_GENCTRL_SRC_Pos) |
   104  		(24 << sam.GCLK_GENCTRL_DIV_Pos) |
   105  		sam.GCLK_GENCTRL_GENEN)
   106  	for sam.GCLK.SYNCBUSY.HasBits(sam.GCLK_SYNCBUSY_GENCTRL_GCLK7) {
   107  	}
   108  
   109  	// Set up the PLLs
   110  
   111  	// Set PLL0 to run at 120MHz, using GCLK7 as clock source
   112  	sam.GCLK.PCHCTRL[1].Set(sam.GCLK_PCHCTRL_CHEN |
   113  		(sam.GCLK_PCHCTRL_GEN_GCLK7 << sam.GCLK_PCHCTRL_GEN_Pos))
   114  
   115  	// multiplier = 59 + 1 + (0/32) = 60
   116  	// PLL0 = 2MHz * 60 = 120MHz
   117  	sam.OSCCTRL.DPLL[0].DPLLRATIO.Set((0x0 << sam.OSCCTRL_DPLL_DPLLRATIO_LDRFRAC_Pos) |
   118  		(59 << sam.OSCCTRL_DPLL_DPLLRATIO_LDR_Pos))
   119  	for sam.OSCCTRL.DPLL[0].DPLLSYNCBUSY.HasBits(sam.OSCCTRL_DPLL_DPLLSYNCBUSY_DPLLRATIO) {
   120  	}
   121  
   122  	// MUST USE LBYPASS DUE TO BUG IN REV A OF SAMD51, via Adafruit lib.
   123  	sam.OSCCTRL.DPLL[0].DPLLCTRLB.Set((sam.OSCCTRL_DPLL_DPLLCTRLB_REFCLK_GCLK << sam.OSCCTRL_DPLL_DPLLCTRLB_REFCLK_Pos) |
   124  		sam.OSCCTRL_DPLL_DPLLCTRLB_LBYPASS)
   125  
   126  	sam.OSCCTRL.DPLL[0].DPLLCTRLA.Set(sam.OSCCTRL_DPLL_DPLLCTRLA_ENABLE)
   127  	for !sam.OSCCTRL.DPLL[0].DPLLSTATUS.HasBits(sam.OSCCTRL_DPLL_DPLLSTATUS_CLKRDY) ||
   128  		!sam.OSCCTRL.DPLL[0].DPLLSTATUS.HasBits(sam.OSCCTRL_DPLL_DPLLSTATUS_LOCK) {
   129  	}
   130  
   131  	// Set PLL1 to run at 100MHz, using GCLK7 as clock source
   132  	sam.GCLK.PCHCTRL[2].Set(sam.GCLK_PCHCTRL_CHEN |
   133  		(sam.GCLK_PCHCTRL_GEN_GCLK7 << sam.GCLK_PCHCTRL_GEN_Pos))
   134  
   135  	// multiplier = 49 + 1 + (0/32) = 50
   136  	// PLL1 = 2MHz * 50 = 100MHz
   137  	sam.OSCCTRL.DPLL[1].DPLLRATIO.Set((0x0 << sam.OSCCTRL_DPLL_DPLLRATIO_LDRFRAC_Pos) |
   138  		(49 << sam.OSCCTRL_DPLL_DPLLRATIO_LDR_Pos))
   139  	for sam.OSCCTRL.DPLL[1].DPLLSYNCBUSY.HasBits(sam.OSCCTRL_DPLL_DPLLSYNCBUSY_DPLLRATIO) {
   140  	}
   141  
   142  	// // MUST USE LBYPASS DUE TO BUG IN REV A OF SAMD51
   143  	sam.OSCCTRL.DPLL[1].DPLLCTRLB.Set((sam.OSCCTRL_DPLL_DPLLCTRLB_REFCLK_GCLK << sam.OSCCTRL_DPLL_DPLLCTRLB_REFCLK_Pos) |
   144  		sam.OSCCTRL_DPLL_DPLLCTRLB_LBYPASS)
   145  
   146  	sam.OSCCTRL.DPLL[1].DPLLCTRLA.Set(sam.OSCCTRL_DPLL_DPLLCTRLA_ENABLE)
   147  	// for !sam.OSCCTRL.DPLLSTATUS1.HasBits(sam.OSCCTRL_DPLLSTATUS_CLKRDY) ||
   148  	// 	!sam.OSCCTRL.DPLLSTATUS1.HasBits(sam.OSCCTRL_DPLLSTATUS_LOCK) {
   149  	// }
   150  
   151  	// Set up the peripheral clocks
   152  	// Set 48MHZ CLOCK FOR USB
   153  	sam.GCLK.GENCTRL[1].Set((sam.GCLK_GENCTRL_SRC_DFLL << sam.GCLK_GENCTRL_SRC_Pos) |
   154  		sam.GCLK_GENCTRL_IDC |
   155  		sam.GCLK_GENCTRL_GENEN)
   156  	for sam.GCLK.SYNCBUSY.HasBits(sam.GCLK_SYNCBUSY_GENCTRL_GCLK1) {
   157  	}
   158  
   159  	// // Set 100MHZ CLOCK FOR OTHER PERIPHERALS
   160  	// sam.GCLK.GENCTRL2.Set((sam.GCLK_GENCTRL_SRC_DPLL1 << sam.GCLK_GENCTRL_SRC_Pos) |
   161  	// 	sam.GCLK_GENCTRL_IDC |
   162  	// 	sam.GCLK_GENCTRL_GENEN)
   163  	// for sam.GCLK.SYNCBUSY.HasBits(sam.GCLK_SYNCBUSY_GENCTRL2) {
   164  	// }
   165  
   166  	// // Set 12MHZ CLOCK FOR DAC
   167  	sam.GCLK.GENCTRL[4].Set((sam.GCLK_GENCTRL_SRC_DFLL << sam.GCLK_GENCTRL_SRC_Pos) |
   168  		sam.GCLK_GENCTRL_IDC |
   169  		(4 << sam.GCLK_GENCTRL_DIVSEL_Pos) |
   170  		sam.GCLK_GENCTRL_GENEN)
   171  	for sam.GCLK.SYNCBUSY.HasBits(sam.GCLK_SYNCBUSY_GENCTRL_GCLK4) {
   172  	}
   173  
   174  	// // Set up main clock
   175  	sam.GCLK.GENCTRL[0].Set((sam.GCLK_GENCTRL_SRC_DPLL0 << sam.GCLK_GENCTRL_SRC_Pos) |
   176  		sam.GCLK_GENCTRL_IDC |
   177  		sam.GCLK_GENCTRL_GENEN)
   178  	for sam.GCLK.SYNCBUSY.HasBits(sam.GCLK_SYNCBUSY_GENCTRL_GCLK0) {
   179  	}
   180  
   181  	sam.MCLK.CPUDIV.Set(sam.MCLK_CPUDIV_DIV_DIV1)
   182  
   183  	// Use the LDO regulator by default
   184  	sam.SUPC.VREG.ClearBits(sam.SUPC_VREG_SEL)
   185  
   186  	// Start up the "Debug Watchpoint and Trace" unit, so that we can use
   187  	// it's 32bit cycle counter for timing.
   188  	//CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
   189  	//DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
   190  
   191  	// Disable automatic NVM write operations
   192  	sam.NVMCTRL.SetCTRLA_WMODE(sam.NVMCTRL_CTRLA_WMODE_MAN)
   193  }
   194  
   195  func initRTC() {
   196  	// turn on digital interface clock
   197  	sam.MCLK.APBAMASK.SetBits(sam.MCLK_APBAMASK_RTC_)
   198  
   199  	// disable RTC
   200  	sam.RTC_MODE0.CTRLA.ClearBits(sam.RTC_MODE0_CTRLA_ENABLE)
   201  	//sam.RTC_MODE0.CTRLA.Set(0)
   202  	for sam.RTC_MODE0.SYNCBUSY.HasBits(sam.RTC_MODE0_SYNCBUSY_ENABLE) {
   203  	}
   204  
   205  	// reset RTC
   206  	sam.RTC_MODE0.CTRLA.SetBits(sam.RTC_MODE0_CTRLA_SWRST)
   207  	for sam.RTC_MODE0.SYNCBUSY.HasBits(sam.RTC_MODE0_SYNCBUSY_SWRST) {
   208  	}
   209  
   210  	// set to use ulp 32k oscillator
   211  	sam.OSC32KCTRL.OSCULP32K.SetBits(sam.OSC32KCTRL_OSCULP32K_EN32K)
   212  	sam.OSC32KCTRL.RTCCTRL.Set(sam.OSC32KCTRL_RTCCTRL_RTCSEL_ULP32K)
   213  
   214  	// set Mode0 to 32-bit counter (mode 0) with prescaler 1 and GCLK2 is 32KHz/1
   215  	sam.RTC_MODE0.CTRLA.Set((sam.RTC_MODE0_CTRLA_MODE_COUNT32 << sam.RTC_MODE0_CTRLA_MODE_Pos) |
   216  		(sam.RTC_MODE0_CTRLA_PRESCALER_DIV1 << sam.RTC_MODE0_CTRLA_PRESCALER_Pos) |
   217  		(sam.RTC_MODE0_CTRLA_COUNTSYNC))
   218  
   219  	// re-enable RTC
   220  	sam.RTC_MODE0.CTRLA.SetBits(sam.RTC_MODE0_CTRLA_ENABLE)
   221  	for sam.RTC_MODE0.SYNCBUSY.HasBits(sam.RTC_MODE0_SYNCBUSY_ENABLE) {
   222  	}
   223  
   224  	irq := interrupt.New(sam.IRQ_RTC, func(interrupt.Interrupt) {
   225  		flags := sam.RTC_MODE0.INTFLAG.Get()
   226  		if flags&sam.RTC_MODE0_INTENSET_CMP0 != 0 {
   227  			// The timer (for a sleep) has expired.
   228  			timerWakeup.Set(1)
   229  		}
   230  		if flags&sam.RTC_MODE0_INTENSET_OVF != 0 {
   231  			// The 32-bit RTC timer has overflowed.
   232  			rtcOverflows.Set(rtcOverflows.Get() + 1)
   233  		}
   234  		// Mark this interrupt has handled for CMP0 and OVF.
   235  		sam.RTC_MODE0.INTFLAG.Set(sam.RTC_MODE0_INTENSET_CMP0 | sam.RTC_MODE0_INTENSET_OVF)
   236  	})
   237  	sam.RTC_MODE0.INTENSET.Set(sam.RTC_MODE0_INTENSET_OVF)
   238  	irq.SetPriority(0xc0)
   239  	irq.Enable()
   240  }
   241  
   242  func waitForSync() {
   243  	for sam.RTC_MODE0.SYNCBUSY.HasBits(sam.RTC_MODE0_SYNCBUSY_COUNT) {
   244  	}
   245  }
   246  
   247  var rtcOverflows volatile.Register32 // number of times the RTC wrapped around
   248  
   249  var timerWakeup volatile.Register8
   250  
   251  // ticksToNanoseconds converts RTC ticks (at 32768Hz) to nanoseconds.
   252  func ticksToNanoseconds(ticks timeUnit) int64 {
   253  	// The following calculation is actually the following, but with both sides
   254  	// reduced to reduce the risk of overflow:
   255  	//     ticks * 1e9 / 32768
   256  	return int64(ticks) * 1953125 / 64
   257  }
   258  
   259  // nanosecondsToTicks converts nanoseconds to RTC ticks (running at 32768Hz).
   260  func nanosecondsToTicks(ns int64) timeUnit {
   261  	// The following calculation is actually the following, but with both sides
   262  	// reduced to reduce the risk of overflow:
   263  	//     ns * 32768 / 1e9
   264  	return timeUnit(ns * 64 / 1953125)
   265  }
   266  
   267  // sleepTicks should sleep for d number of microseconds.
   268  func sleepTicks(d timeUnit) {
   269  	for d != 0 {
   270  		ticks := uint32(d)
   271  		if !timerSleep(ticks) {
   272  			return
   273  		}
   274  		d -= timeUnit(ticks)
   275  	}
   276  }
   277  
   278  // ticks returns the elapsed time since reset.
   279  func ticks() timeUnit {
   280  	// For some ways of capturing the time atomically, see this thread:
   281  	// https://www.eevblog.com/forum/microcontrollers/correct-timing-by-timer-overflow-count/msg749617/#msg749617
   282  	// Here, instead of re-reading the counter register if an overflow has been
   283  	// detected, we simply try again because that results in smaller code.
   284  	for {
   285  		mask := interrupt.Disable()
   286  		counter := readRTC()
   287  		overflows := rtcOverflows.Get()
   288  		hasOverflow := sam.RTC_MODE0.INTFLAG.Get()&sam.RTC_MODE0_INTENSET_OVF != 0
   289  		interrupt.Restore(mask)
   290  
   291  		if hasOverflow {
   292  			// There was an overflow while trying to capture the timer.
   293  			// Try again.
   294  			continue
   295  		}
   296  
   297  		// This is a 32-bit timer, so the number of timer overflows forms the
   298  		// upper 32 bits of this timer.
   299  		return timeUnit(overflows)<<32 + timeUnit(counter)
   300  	}
   301  }
   302  
   303  func readRTC() uint32 {
   304  	waitForSync()
   305  	return sam.RTC_MODE0.COUNT.Get()
   306  }
   307  
   308  // ticks are in microseconds
   309  // Returns true if the timer completed.
   310  // Returns false if another interrupt occured which requires an early return to scheduler.
   311  func timerSleep(ticks uint32) bool {
   312  	timerWakeup.Set(0)
   313  	if ticks < 8 {
   314  		// due to delay waiting for the register value to sync, the minimum sleep value
   315  		// for the SAMD51 is 260us.
   316  		// For related info for SAMD21, see:
   317  		// https://community.atmel.com/comment/2507091#comment-2507091
   318  		ticks = 8
   319  	}
   320  
   321  	// request read of count
   322  	waitForSync()
   323  
   324  	// set compare value
   325  	cnt := sam.RTC_MODE0.COUNT.Get()
   326  
   327  	sam.RTC_MODE0.COMP[0].Set(uint32(cnt) + ticks)
   328  
   329  	// enable IRQ for CMP0 compare
   330  	sam.RTC_MODE0.INTENSET.Set(sam.RTC_MODE0_INTENSET_CMP0)
   331  
   332  wait:
   333  	waitForEvents()
   334  	if timerWakeup.Get() != 0 {
   335  		return true
   336  	}
   337  	if hasScheduler {
   338  		// The interurpt may have awoken a goroutine, so bail out early.
   339  		// Disable IRQ for CMP0 compare.
   340  		sam.RTC_MODE0.INTENCLR.Set(sam.RTC_MODE0_INTENSET_CMP0)
   341  		return false
   342  	} else {
   343  		// This is running without a scheduler.
   344  		// The application expects this to sleep the whole time.
   345  		goto wait
   346  	}
   347  }
   348  
   349  func initUSBClock() {
   350  	// Turn on clock(s) for USB
   351  	//MCLK->APBBMASK.reg |= MCLK_APBBMASK_USB;
   352  	//MCLK->AHBMASK.reg |= MCLK_AHBMASK_USB;
   353  	sam.MCLK.APBBMASK.SetBits(sam.MCLK_APBBMASK_USB_)
   354  	sam.MCLK.AHBMASK.SetBits(sam.MCLK_AHBMASK_USB_)
   355  
   356  	// Put Generic Clock Generator 1 as source for USB
   357  	//GCLK->PCHCTRL[USB_GCLK_ID].reg = GCLK_PCHCTRL_GEN_GCLK1_Val | (1 << GCLK_PCHCTRL_CHEN_Pos);
   358  	sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_USB].Set((sam.GCLK_PCHCTRL_GEN_GCLK1 << sam.GCLK_PCHCTRL_GEN_Pos) |
   359  		sam.GCLK_PCHCTRL_CHEN)
   360  }
   361  
   362  func initADCClock() {
   363  	// Turn on clocks for ADC0/ADC1.
   364  	sam.MCLK.APBDMASK.SetBits(sam.MCLK_APBDMASK_ADC0_)
   365  	sam.MCLK.APBDMASK.SetBits(sam.MCLK_APBDMASK_ADC1_)
   366  
   367  	// Put Generic Clock Generator 1 as source for ADC0 and ADC1.
   368  	sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_ADC0].Set((sam.GCLK_PCHCTRL_GEN_GCLK1 << sam.GCLK_PCHCTRL_GEN_Pos) |
   369  		sam.GCLK_PCHCTRL_CHEN)
   370  	sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_ADC1].Set((sam.GCLK_PCHCTRL_GEN_GCLK1 << sam.GCLK_PCHCTRL_GEN_Pos) |
   371  		sam.GCLK_PCHCTRL_CHEN)
   372  }
   373  
   374  func enableCache() {
   375  	sam.CMCC.CTRL.SetBits(sam.CMCC_CTRL_CEN)
   376  }
   377  
   378  func waitForEvents() {
   379  	arm.Asm("wfe")
   380  }