Skip to content

Commit

Permalink
rp2040: support dormant mode
Browse files Browse the repository at this point in the history
  • Loading branch information
kenbell committed Jul 31, 2022
1 parent 25c8d3e commit ded9651
Show file tree
Hide file tree
Showing 4 changed files with 108 additions and 0 deletions.
19 changes: 19 additions & 0 deletions src/machine/machine_rp2040.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,3 +97,22 @@ func CurrentCore() int {

// NumCores returns number of cores available on the device.
func NumCores() int { return 2 }

func Sleep(pin Pin, change PinChange) error {
if pin > 31 {
return ErrInvalidInputPin
}

base := &ioBank0.dormantWakeIRQctrl
pin.ctrlSetInterrupt(change, true, base) // gpio_set_dormant_irq_enabled

clocks.deinit() // Reconfigure clocks, disable PLLs etc

xosc.Dormant() // Execution stops here until woken up

clocks.init() // Re-initialize clocks

// Clear the irq so we can go back to dormant mode again if we want
pin.acknowledgeInterrupt(change)
return nil
}
70 changes: 70 additions & 0 deletions src/machine/machine_rp2040_clocks.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ import (
"unsafe"
)

const (
// XOSC_MHZ is the frequency of the external crystal
XOSC_MHZ = 12
)

const (
KHz = 1000
MHz = 1000000
Expand Down Expand Up @@ -183,6 +188,13 @@ func (clk *clock) configure(src, auxsrc, srcFreq, freq uint32) {

}

// stop the clock (usually used before going dormant)
func (clk *clock) stop() {
// Disable clock. On clkRef and clkSys this does nothing,
// all other clocks have the ENABLE bit in the same position.
clk.ctrl.ClearBits(rp.CLOCKS_CLK_GPOUT0_CTRL_ENABLE)
}

// init initializes the clock hardware.
//
// Must be called before any other clock function.
Expand All @@ -193,6 +205,10 @@ func (clks *clocksType) init() {
// Disable resus that may be enabled from previous software
clks.resus.ctrl.Set(0)

// Ensure ROSC is initialized since clock setup sequence assumes ROSC available.
// It may have been disabled (e.g. after being dormant)
rp.ROSC.CTRL.ReplaceBits(rp.ROSC_CTRL_ENABLE_ENABLE<<rp.ROSC_CTRL_ENABLE_Pos, rp.ROSC_CTRL_ENABLE_Msk, 0)

// Enable the xosc
xosc.init()

Expand Down Expand Up @@ -257,3 +273,57 @@ func (clks *clocksType) init() {
125*MHz,
125*MHz)
}

// Turn off clocks & PLLs in preparation for going dormant. After
// awakening, need to call init() to re-initialize.
func (clks *clocksType) deinit() {
// For now, hard-coded to use external oscillator to go dormant
const src_hz = XOSC_MHZ * MHz
const clk_ref_src = rp.CLOCKS_CLK_REF_CTRL_SRC_XOSC_CLKSRC
const clk_rtc_src = rp.CLOCKS_CLK_RTC_CTRL_AUXSRC_XOSC_CLKSRC

// Configure clocks
// clkRef = xosc (12MHz) / 1 = 12MHz
clkref := clks.clock(clkRef)
clkref.configure(clk_ref_src,
0, // No aux mux
src_hz,
src_hz)

// CLK SYS = CLK_REF
clksys := clks.clock(clkSys)
clksys.configure(rp.CLOCKS_CLK_SYS_CTRL_SRC_CLK_REF,
0, // Using glitchless mux
src_hz,
src_hz)

// CLK USB = 0MHz
clkusb := clks.clock(clkUSB)
clkusb.stop()

// CLK ADC = 0MHz
clkadc := clks.clock(clkADC)
clkadc.stop()

// clkRTC = XOSC (12MHz) / 256 = 46875Hz
clkrtc := clks.clock(clkRTC)
clkrtc.configure(0, // No GLMUX
clk_rtc_src,
src_hz,
46875)

// clkPeri = clkSys. Used as reference clock for Peripherals.
// No dividers so just select and enable.
clkperi := clks.clock(clkPeri)
clkperi.configure(0,
rp.CLOCKS_CLK_PERI_CTRL_AUXSRC_CLK_SYS,
src_hz,
src_hz)

// Deinitialize the PLLs
pllSys.deinit()
pllUSB.deinit()

// Disable ROSC since using XOSC
rp.ROSC.CTRL.ReplaceBits(rp.ROSC_CTRL_ENABLE_DISABLE<<rp.ROSC_CTRL_ENABLE_Pos, rp.ROSC_CTRL_ENABLE_Msk, 0)
}
8 changes: 8 additions & 0 deletions src/machine/machine_rp2040_pll.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,3 +99,11 @@ func (pll *pll) init(refdiv, vcoFreq, postDiv1, postDiv2 uint32) {
pll.pwr.ClearBits(rp.PLL_SYS_PWR_POSTDIVPD)

}

func (pll *pll) deinit() {
// from Pico SDK pll.h
const PLL_PWR_BITS = 0x0000002d

// Set bits to disable
pll.pwr.Set(PLL_PWR_BITS)
}
11 changes: 11 additions & 0 deletions src/machine/machine_rp2040_xosc.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,14 @@ func (osc *xoscType) init() {
for !osc.status.HasBits(rp.XOSC_STATUS_STABLE) {
}
}

// Dormant stops internal oscillator.
// WARNING: This stops the xosc until woken up by an irq
func (osc *xoscType) Dormant() {
const XOSC_DORMANT_VALUE_DORMANT = 0x636f6d61
osc.dormant.Set(XOSC_DORMANT_VALUE_DORMANT)

// Wait for it to become stable once woken up
for !osc.status.HasBits(rp.XOSC_STATUS_STABLE) {
}
}

0 comments on commit ded9651

Please sign in to comment.