samd51,rp2040,nrf528xx,stm32: implement watchdog
Этот коммит содержится в:
		
							родитель
							
								
									756cdf44ed
								
							
						
					
					
						коммит
						f4375d0452
					
				
					 8 изменённых файлов: 291 добавлений и 12 удалений
				
			
		
							
								
								
									
										2
									
								
								Makefile
									
										
									
									
									
								
							
							
						
						
									
										2
									
								
								Makefile
									
										
									
									
									
								
							|  | @ -490,6 +490,8 @@ smoketest: | |||
| 	@$(MD5SUM) test.hex | ||||
| 	$(TINYGO) build -size short -o test.hex -target=feather-rp2040      examples/i2c-target | ||||
| 	@$(MD5SUM) test.hex | ||||
| 	$(TINYGO) build -size short -o test.hex -target=feather-rp2040      examples/watchdog | ||||
| 	@$(MD5SUM) test.hex | ||||
| 	# test simulated boards on play.tinygo.org | ||||
| ifneq ($(WASM), 0) | ||||
| 	$(TINYGO) build -size short -o test.wasm -tags=arduino              examples/blinky1 | ||||
|  |  | |||
							
								
								
									
										42
									
								
								src/examples/watchdog/main.go
									
										
									
									
									
										Обычный файл
									
								
							
							
						
						
									
										42
									
								
								src/examples/watchdog/main.go
									
										
									
									
									
										Обычный файл
									
								
							|  | @ -0,0 +1,42 @@ | |||
| package main | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"machine" | ||||
| 	"time" | ||||
| ) | ||||
| 
 | ||||
| func main() { | ||||
| 	//sleep for 2 secs for console | ||||
| 	time.Sleep(2 * time.Second) | ||||
| 
 | ||||
| 	config := machine.WatchdogConfig{ | ||||
| 		TimeoutMillis: 1000, | ||||
| 	} | ||||
| 
 | ||||
| 	println("configuring watchdog for max 1 second updates") | ||||
| 	machine.Watchdog.Configure(config) | ||||
| 
 | ||||
| 	// From this point the watchdog is running and Update must be | ||||
| 	// called periodically, per the config | ||||
| 	machine.Watchdog.Start() | ||||
| 
 | ||||
| 	// This loop should complete because watchdog update is called | ||||
| 	// every 100ms. | ||||
| 	start := time.Now() | ||||
| 	println("updating watchdog for 3 seconds") | ||||
| 	for i := 0; i < 30; i++ { | ||||
| 		time.Sleep(100 * time.Millisecond) | ||||
| 		machine.Watchdog.Update() | ||||
| 		fmt.Printf("alive @ %v\n", time.Now().Sub(start)) | ||||
| 	} | ||||
| 
 | ||||
| 	// This loop should cause a watchdog reset after 1s since | ||||
| 	// there is no update call. | ||||
| 	start = time.Now() | ||||
| 	println("entering tight loop") | ||||
| 	for { | ||||
| 		time.Sleep(100 * time.Millisecond) | ||||
| 		fmt.Printf("alive @ %v\n", time.Now().Sub(start)) | ||||
| 	} | ||||
| } | ||||
|  | @ -2299,3 +2299,52 @@ func checkFlashError() error { | |||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // Watchdog provides access to the hardware watchdog available | ||||
| // in the SAMD51. | ||||
| var Watchdog = &watchdogImpl{} | ||||
| 
 | ||||
| const ( | ||||
| 	// WatchdogMaxTimeout in milliseconds (16s) | ||||
| 	WatchdogMaxTimeout = (16384 * 1000) / 1024 // CYC16384/1024kHz | ||||
| ) | ||||
| 
 | ||||
| type watchdogImpl struct{} | ||||
| 
 | ||||
| // Configure the watchdog. | ||||
| // | ||||
| // This method should not be called after the watchdog is started and on | ||||
| // some platforms attempting to reconfigure after starting the watchdog | ||||
| // is explicitly forbidden / will not work. | ||||
| func (wd *watchdogImpl) Configure(config WatchdogConfig) error { | ||||
| 	// 1.024kHz clock | ||||
| 	cycles := int((int64(config.TimeoutMillis) * 1024) / 1000) | ||||
| 
 | ||||
| 	// period is expressed as a power-of-two, starting at 8 / 1024ths of a second | ||||
| 	period := uint8(0) | ||||
| 	cfgCycles := 8 | ||||
| 	for cfgCycles < cycles { | ||||
| 		period++ | ||||
| 		cfgCycles <<= 1 | ||||
| 
 | ||||
| 		if period >= 0xB { | ||||
| 			break | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	sam.WDT.CONFIG.Set(period << sam.WDT_CONFIG_PER_Pos) | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // Starts the watchdog. | ||||
| func (wd *watchdogImpl) Start() error { | ||||
| 	sam.WDT.CTRLA.SetBits(sam.WDT_CTRLA_ENABLE) | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // Update the watchdog, indicating that `source` is healthy. | ||||
| func (wd *watchdogImpl) Update() { | ||||
| 	// 0xA5 = magic value (see datasheet) | ||||
| 	sam.WDT.CLEAR.Set(0xA5) | ||||
| } | ||||
|  |  | |||
|  | @ -214,3 +214,46 @@ func twisError(val uint32) error { | |||
| 
 | ||||
| 	return errI2CBusError | ||||
| } | ||||
| 
 | ||||
| var ( | ||||
| 	Watchdog = &watchdogImpl{} | ||||
| ) | ||||
| 
 | ||||
| const ( | ||||
| 	// WatchdogMaxTimeout in milliseconds (approx 36h) | ||||
| 	WatchdogMaxTimeout = (0xffffffff * 1000) / 32768 | ||||
| ) | ||||
| 
 | ||||
| type watchdogImpl struct { | ||||
| } | ||||
| 
 | ||||
| // Configure the watchdog. | ||||
| // | ||||
| // This method should not be called after the watchdog is started and on | ||||
| // some platforms attempting to reconfigure after starting the watchdog | ||||
| // is explicitly forbidden / will not work. | ||||
| func (wd *watchdogImpl) Configure(config WatchdogConfig) error { | ||||
| 	// 32.768kHz counter | ||||
| 	crv := int32((int64(config.TimeoutMillis) * 32768) / 1000) | ||||
| 	nrf.WDT.CRV.Set(uint32(crv)) | ||||
| 
 | ||||
| 	// One source | ||||
| 	nrf.WDT.RREN.Set(0x1) | ||||
| 
 | ||||
| 	// Run during sleep | ||||
| 	nrf.WDT.CONFIG.Set(nrf.WDT_CONFIG_SLEEP_Run) | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // Starts the watchdog. | ||||
| func (wd *watchdogImpl) Start() error { | ||||
| 	nrf.WDT.TASKS_START.Set(nrf.WDT_TASKS_START_TASKS_START) | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // Update the watchdog, indicating that `source` is healthy. | ||||
| func (wd *watchdogImpl) Update() { | ||||
| 	// 0x6E524635 = magic value from datasheet | ||||
| 	nrf.WDT.RR[0].Set(0x6E524635) | ||||
| } | ||||
|  |  | |||
|  | @ -182,7 +182,7 @@ func (clk *clock) configure(src, auxsrc, srcFreq, freq uint32) { | |||
| // Must be called before any other clock function. | ||||
| func (clks *clocksType) init() { | ||||
| 	// Start the watchdog tick | ||||
| 	watchdog.startTick(xoscFreq) | ||||
| 	Watchdog.startTick(xoscFreq) | ||||
| 
 | ||||
| 	// Disable resus that may be enabled from previous software | ||||
| 	clks.resus.ctrl.Set(0) | ||||
|  |  | |||
|  | @ -4,24 +4,67 @@ package machine | |||
| 
 | ||||
| import ( | ||||
| 	"device/rp" | ||||
| 	"runtime/volatile" | ||||
| 	"unsafe" | ||||
| ) | ||||
| 
 | ||||
| type watchdogType struct { | ||||
| 	ctrl    volatile.Register32 | ||||
| 	load    volatile.Register32 | ||||
| 	reason  volatile.Register32 | ||||
| 	scratch [8]volatile.Register32 | ||||
| 	tick    volatile.Register32 | ||||
| // Watchdog provides access to the hardware watchdog available | ||||
| // in the RP2040. | ||||
| var Watchdog = &watchdogImpl{} | ||||
| 
 | ||||
| const ( | ||||
| 	// WatchdogMaxTimeout in milliseconds (approx 8.3s). | ||||
| 	// | ||||
| 	// Nominal 1us per watchdog tick, 24-bit counter, | ||||
| 	// but due to errata two ticks consumed per 1us. | ||||
| 	// See: Errata RP2040-E1 | ||||
| 	WatchdogMaxTimeout = (rp.WATCHDOG_LOAD_LOAD_Msk / 1000) / 2 | ||||
| ) | ||||
| 
 | ||||
| type watchdogImpl struct { | ||||
| 	// The value to reset the counter to on each Update | ||||
| 	loadValue uint32 | ||||
| } | ||||
| 
 | ||||
| var watchdog = (*watchdogType)(unsafe.Pointer(rp.WATCHDOG)) | ||||
| // Configure the watchdog. | ||||
| // | ||||
| // This method should not be called after the watchdog is started and on | ||||
| // some platforms attempting to reconfigure after starting the watchdog | ||||
| // is explicitly forbidden / will not work. | ||||
| func (wd *watchdogImpl) Configure(config WatchdogConfig) error { | ||||
| 	// x2 due to errata RP2040-E1 | ||||
| 	wd.loadValue = config.TimeoutMillis * 1000 * 2 | ||||
| 	if wd.loadValue > rp.WATCHDOG_LOAD_LOAD_Msk { | ||||
| 		wd.loadValue = rp.WATCHDOG_LOAD_LOAD_Msk | ||||
| 	} | ||||
| 
 | ||||
| 	rp.WATCHDOG.CTRL.ClearBits(rp.WATCHDOG_CTRL_ENABLE) | ||||
| 
 | ||||
| 	// Reset everything apart from ROSC and XOSC | ||||
| 	rp.PSM.WDSEL.Set(0x0001ffff &^ (rp.PSM_WDSEL_ROSC | rp.PSM_WDSEL_XOSC)) | ||||
| 
 | ||||
| 	// Pause watchdog during debug | ||||
| 	rp.WATCHDOG.CTRL.SetBits(rp.WATCHDOG_CTRL_PAUSE_DBG0 | rp.WATCHDOG_CTRL_PAUSE_DBG1 | rp.WATCHDOG_CTRL_PAUSE_JTAG) | ||||
| 
 | ||||
| 	// Load initial counter | ||||
| 	rp.WATCHDOG.LOAD.Set(wd.loadValue) | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // Starts the watchdog. | ||||
| func (wd *watchdogImpl) Start() error { | ||||
| 	rp.WATCHDOG.CTRL.SetBits(rp.WATCHDOG_CTRL_ENABLE) | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // Update the watchdog, indicating that the app is healthy. | ||||
| func (wd *watchdogImpl) Update() { | ||||
| 	rp.WATCHDOG.LOAD.Set(wd.loadValue) | ||||
| } | ||||
| 
 | ||||
| // startTick starts the watchdog tick. | ||||
| // cycles needs to be a divider that when applied to the xosc input, | ||||
| // produces a 1MHz clock. So if the xosc frequency is 12MHz, | ||||
| // this will need to be 12. | ||||
| func (wd *watchdogType) startTick(cycles uint32) { | ||||
| 	wd.tick.Set(cycles | rp.WATCHDOG_TICK_ENABLE) | ||||
| func (wd *watchdogImpl) startTick(cycles uint32) { | ||||
| 	rp.WATCHDOG.TICK.Set(cycles | rp.WATCHDOG_TICK_ENABLE) | ||||
| } | ||||
|  |  | |||
							
								
								
									
										66
									
								
								src/machine/machine_stm32_iwdg.go
									
										
									
									
									
										Обычный файл
									
								
							
							
						
						
									
										66
									
								
								src/machine/machine_stm32_iwdg.go
									
										
									
									
									
										Обычный файл
									
								
							|  | @ -0,0 +1,66 @@ | |||
| //go:build stm32 | ||||
| 
 | ||||
| package machine | ||||
| 
 | ||||
| import "device/stm32" | ||||
| 
 | ||||
| var ( | ||||
| 	Watchdog = &watchdogImpl{} | ||||
| ) | ||||
| 
 | ||||
| const ( | ||||
| 	// WatchdogMaxTimeout in milliseconds (32.768s) | ||||
| 	// | ||||
| 	// Timeout is based on 12-bit counter with /256 divider on | ||||
| 	// 32.768kHz clock.  See 21.3.3 of RM0090 for table. | ||||
| 	WatchdogMaxTimeout = ((0xfff + 1) * 256 * 1024) / 32768 | ||||
| ) | ||||
| 
 | ||||
| const ( | ||||
| 	// Enable access to PR, RLR and WINR registers (0x5555) | ||||
| 	iwdgKeyEnable = 0x5555 | ||||
| 	// Reset the watchdog value (0xAAAA) | ||||
| 	iwdgKeyReset = 0xaaaa | ||||
| 	// Start the watchdog (0xCCCC) | ||||
| 	iwdgKeyStart = 0xcccc | ||||
| 	// Divide by 256 | ||||
| 	iwdgDiv256 = 6 | ||||
| ) | ||||
| 
 | ||||
| type watchdogImpl struct { | ||||
| } | ||||
| 
 | ||||
| // Configure the watchdog. | ||||
| // | ||||
| // This method should not be called after the watchdog is started and on | ||||
| // some platforms attempting to reconfigure after starting the watchdog | ||||
| // is explicitly forbidden / will not work. | ||||
| func (wd *watchdogImpl) Configure(config WatchdogConfig) error { | ||||
| 
 | ||||
| 	// Enable configuration of IWDG | ||||
| 	stm32.IWDG.KR.Set(iwdgKeyEnable) | ||||
| 
 | ||||
| 	// Unconditionally divide by /256 since we don't really need accuracy | ||||
| 	// less than 8ms | ||||
| 	stm32.IWDG.PR.Set(iwdgDiv256) | ||||
| 
 | ||||
| 	timeout := config.TimeoutMillis | ||||
| 	if timeout > WatchdogMaxTimeout { | ||||
| 		timeout = WatchdogMaxTimeout | ||||
| 	} | ||||
| 
 | ||||
| 	// Set reload value based on /256 divider | ||||
| 	stm32.IWDG.RLR.Set(((config.TimeoutMillis*32768 + (256 * 1024) - 1) / (256 * 1024)) - 1) | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // Starts the watchdog. | ||||
| func (wd *watchdogImpl) Start() error { | ||||
| 	stm32.IWDG.KR.Set(iwdgKeyStart) | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // Update the watchdog, indicating that `source` is healthy. | ||||
| func (wd *watchdogImpl) Update() { | ||||
| 	stm32.IWDG.KR.Set(iwdgKeyReset) | ||||
| } | ||||
							
								
								
									
										34
									
								
								src/machine/watchdog.go
									
										
									
									
									
										Обычный файл
									
								
							
							
						
						
									
										34
									
								
								src/machine/watchdog.go
									
										
									
									
									
										Обычный файл
									
								
							|  | @ -0,0 +1,34 @@ | |||
| //go:build nrf52840 || nrf52833 || rp2040 || atsamd51 || atsame5x || stm32 | ||||
| 
 | ||||
| package machine | ||||
| 
 | ||||
| // WatchdogConfig holds configuration for the watchdog timer. | ||||
| type WatchdogConfig struct { | ||||
| 	// The timeout (in milliseconds) before the watchdog fires. | ||||
| 	// | ||||
| 	// If the requested timeout exceeds `MaxTimeout` it will be rounded | ||||
| 	// down. | ||||
| 	TimeoutMillis uint32 | ||||
| } | ||||
| 
 | ||||
| // watchdog must be implemented by any platform supporting watchdog functionality | ||||
| type watchdog interface { | ||||
| 	// Configure the watchdog. | ||||
| 	// | ||||
| 	// This method should not be called after the watchdog is started and on | ||||
| 	// some platforms attempting to reconfigure after starting the watchdog | ||||
| 	// is explicitly forbidden / will not work. | ||||
| 	Configure(config WatchdogConfig) error | ||||
| 
 | ||||
| 	// Starts the watchdog. | ||||
| 	Start() error | ||||
| 
 | ||||
| 	// Update the watchdog, indicating that the app is healthy. | ||||
| 	Update() | ||||
| } | ||||
| 
 | ||||
| // Ensure required public symbols var exists and meets interface spec | ||||
| var _ = watchdog(Watchdog) | ||||
| 
 | ||||
| // Ensure required public constants exist | ||||
| const _ = WatchdogMaxTimeout | ||||
		Загрузка…
	
	Создание таблицы
		
		Сослаться в новой задаче
	
	 Kenneth Bell
						Kenneth Bell