From 9912dd6db1496eefd806d9cceb9527b6478b7485 Mon Sep 17 00:00:00 2001 From: deadprogram Date: Sat, 5 Jun 2021 13:15:43 +0200 Subject: [PATCH] machine/rp2040: add basic support for ADC Signed-off-by: deadprogram --- src/machine/board_pico.go | 6 +++ src/machine/machine_rp2040_adc.go | 61 ++++++++++++++++++++++++++++++ src/machine/machine_rp2040_gpio.go | 17 +++++++-- 3 files changed, 80 insertions(+), 4 deletions(-) create mode 100644 src/machine/machine_rp2040_adc.go diff --git a/src/machine/board_pico.go b/src/machine/board_pico.go index b1be4b91..6ab32c39 100644 --- a/src/machine/board_pico.go +++ b/src/machine/board_pico.go @@ -38,6 +38,12 @@ const ( // Onboard LED LED Pin = GP25 + // Analog pins + ADC0 = GP26 + ADC1 = GP27 + ADC2 = GP28 + ADC3 = GP29 + // Onboard crystal oscillator frequency, in MHz. xoscFreq = 12 // MHz ) diff --git a/src/machine/machine_rp2040_adc.go b/src/machine/machine_rp2040_adc.go new file mode 100644 index 00000000..2101abba --- /dev/null +++ b/src/machine/machine_rp2040_adc.go @@ -0,0 +1,61 @@ +// +build rp2040 + +package machine + +import ( + "device/rp" +) + +func InitADC() { + // reset ADC + rp.RESETS.RESET.SetBits(rp.RESETS_RESET_ADC) + rp.RESETS.RESET.ClearBits(rp.RESETS_RESET_ADC) + for !rp.RESETS.RESET_DONE.HasBits(rp.RESETS_RESET_ADC) { + } + + // enable ADC + rp.ADC.CS.Set(rp.ADC_CS_EN) + + waitForReady() +} + +// Configure configures a ADC pin to be able to be used to read data. +func (a ADC) Configure(config ADCConfig) { + switch a.Pin { + case GP26, GP27, GP28, GP29: + a.Pin.Configure(PinConfig{Mode: PinAnalog}) + default: + // invalid ADC + return + } +} + +func (a ADC) Get() uint16 { + rp.ADC.CS.SetBits(uint32(a.getADCChannel()) << rp.ADC_CS_AINSEL_Pos) + rp.ADC.CS.SetBits(rp.ADC_CS_START_ONCE) + + waitForReady() + + // rp2040 uses 12-bit sampling, so scale to 16-bit + return uint16(rp.ADC.RESULT.Get() << 4) +} + +func waitForReady() { + for !rp.ADC.CS.HasBits(rp.ADC_CS_READY) { + } +} + +func (a ADC) getADCChannel() uint8 { + switch a.Pin { + case GP26: + return 0 + case GP27: + return 1 + case GP28: + return 2 + case GP29: + return 3 + default: + return 0 + } +} diff --git a/src/machine/machine_rp2040_gpio.go b/src/machine/machine_rp2040_gpio.go index b82e0435..62c6c335 100644 --- a/src/machine/machine_rp2040_gpio.go +++ b/src/machine/machine_rp2040_gpio.go @@ -66,6 +66,7 @@ const ( PinInput PinInputPulldown PinInputPullup + PinAnalog ) // set drives the pin high @@ -109,6 +110,11 @@ func (p Pin) pulldown() { p.padCtrl().ClearBits(rp.PADS_BANK0_GPIO0_PUE) } +func (p Pin) pulloff() { + p.padCtrl().ClearBits(rp.PADS_BANK0_GPIO0_PDE) + p.padCtrl().ClearBits(rp.PADS_BANK0_GPIO0_PUE) +} + // setFunc will set pin function to fn. func (p Pin) setFunc(fn pinFunc) { // Set input enable, Clear output disable @@ -125,7 +131,6 @@ func (p Pin) init() { mask := uint32(1) << p rp.SIO.GPIO_OE_CLR.Set(mask) p.clr() - p.setFunc(fnSIO) } // Configure configures the gpio pin as per mode. @@ -134,15 +139,19 @@ func (p Pin) Configure(config PinConfig) { mask := uint32(1) << p switch config.Mode { case PinOutput: + p.setFunc(fnSIO) rp.SIO.GPIO_OE_SET.Set(mask) case PinInput: - rp.SIO.GPIO_OE_CLR.Set(mask) + p.setFunc(fnSIO) case PinInputPulldown: - rp.SIO.GPIO_OE_CLR.Set(mask) + p.setFunc(fnSIO) p.pulldown() case PinInputPullup: - rp.SIO.GPIO_OE_CLR.Set(mask) + p.setFunc(fnSIO) p.pullup() + case PinAnalog: + p.setFunc(fnNULL) + p.pulloff() } }