diff options
author | Patricio Whittingslow <[email protected]> | 2024-12-18 15:36:30 -0300 |
---|---|---|
committer | GitHub <[email protected]> | 2024-12-18 19:36:30 +0100 |
commit | 37f35f8c910b05e2040433448546f41b34535b32 (patch) | |
tree | 32bdf01b1c2b8d75e9a7f1a24e5c62be9d432ce0 /src/machine/machine_rp2_adc.go | |
parent | 0d13e61d0cbe7aa82678a6dec7dda0115db82397 (diff) | |
download | tinygo-37f35f8c910b05e2040433448546f41b34535b32.tar.gz tinygo-37f35f8c910b05e2040433448546f41b34535b32.zip |
Add RP2350 support (#4459)
machine/rp2350: add support
* add linker scripts for rp2350
* add bootloader
* begin melding rp2040 and rp2350 APIs
* add UART
* add rp2350 boot patching
* Fix RP2350 memory layout (#4626)
* Remove rp2040-style second stage bootloader.
* Add 'minimum viable' IMAGE_DEF embedded block
* Create a pico2 specific target
* Implement rp2350 init, clock, and uart support
* Merge rp2 reset code back together
* Separate chip-specific clock definitions
* Clear pad isolation bit on rp2350
* Init UART in rp2350 runtime
* Correct usb/serial initialization order
* Implement jump-to-bootloader
* test: add pico2 to smoketests
---------
Signed-off-by: deadprogram <[email protected]>
Co-authored-by: Matthew Mets <[email protected]>
Co-authored-by: Matt Mets <[email protected]>
Co-authored-by: deadprogram <[email protected]>
Diffstat (limited to 'src/machine/machine_rp2_adc.go')
-rw-r--r-- | src/machine/machine_rp2_adc.go | 146 |
1 files changed, 146 insertions, 0 deletions
diff --git a/src/machine/machine_rp2_adc.go b/src/machine/machine_rp2_adc.go new file mode 100644 index 000000000..13504d719 --- /dev/null +++ b/src/machine/machine_rp2_adc.go @@ -0,0 +1,146 @@ +//go:build rp2040 || rp2350 + +package machine + +import ( + "device/rp" + "errors" + "sync" +) + +// ADCChannel is the ADC peripheral mux channel. 0-4. +type ADCChannel uint8 + +// ADC channels. Only ADC_TEMP_SENSOR is public. The other channels are accessed via Machine.ADC objects +const ( + adc0_CH ADCChannel = iota + adc1_CH + adc2_CH + adc3_CH // Note: GPIO29 not broken out on pico board + adcTempSensor // Internal temperature sensor channel +) + +// Used to serialise ADC sampling +var adcLock sync.Mutex + +// ADC peripheral reference voltage (mV) +var adcAref uint32 + +// InitADC resets the ADC peripheral. +func InitADC() { + 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) + adcAref = 3300 + waitForReady() +} + +// Configure sets the ADC pin to analog input mode. +func (a ADC) Configure(config ADCConfig) error { + c, err := a.GetADCChannel() + if err != nil { + return err + } + return c.Configure(config) +} + +// Get returns a one-shot ADC sample reading. +func (a ADC) Get() uint16 { + if c, err := a.GetADCChannel(); err == nil { + return c.getOnce() + } + // Not an ADC pin! + return 0 +} + +// GetADCChannel returns the channel associated with the ADC pin. +func (a ADC) GetADCChannel() (c ADCChannel, err error) { + err = nil + switch a.Pin { + case ADC0: + c = adc0_CH + case ADC1: + c = adc1_CH + case ADC2: + c = adc2_CH + case ADC3: + c = adc3_CH + default: + err = errors.New("no ADC channel for pin value") + } + return c, err +} + +// Configure sets the channel's associated pin to analog input mode. +// The powered on temperature sensor increases ADC_AVDD current by approximately 40 μA. +func (c ADCChannel) Configure(config ADCConfig) error { + if config.Reference != 0 { + adcAref = config.Reference + } + p, err := c.Pin() + if err != nil { + return err + } + p.Configure(PinConfig{Mode: PinAnalog}) + return nil +} + +// getOnce returns a one-shot ADC sample reading from an ADC channel. +func (c ADCChannel) getOnce() uint16 { + // Make it safe to sample multiple ADC channels in separate go routines. + adcLock.Lock() + rp.ADC.CS.ReplaceBits(uint32(c), 0b111, rp.ADC_CS_AINSEL_Pos) + rp.ADC.CS.SetBits(rp.ADC_CS_START_ONCE) + + waitForReady() + adcLock.Unlock() + + // rp2040 is a 12-bit ADC, scale raw reading to 16-bits. + return uint16(rp.ADC.RESULT.Get()) << 4 +} + +// getVoltage does a one-shot sample and returns a millivolts reading. +// Integer portion is stored in the high 16 bits and fractional in the low 16 bits. +func (c ADCChannel) getVoltage() uint32 { + return (adcAref << 16) / (1 << 12) * uint32(c.getOnce()>>4) +} + +// ReadTemperature does a one-shot sample of the internal temperature sensor and returns a milli-celsius reading. +func ReadTemperature() (millicelsius int32) { + if rp.ADC.CS.Get()&rp.ADC_CS_EN == 0 { + InitADC() + } + + // Enable temperature sensor bias source + rp.ADC.CS.SetBits(rp.ADC_CS_TS_EN) + + // T = 27 - (ADC_voltage - 0.706)/0.001721 + return (27000<<16 - (int32(adcTempSensor.getVoltage())-706<<16)*581) >> 16 +} + +// waitForReady spins waiting for the ADC peripheral to become ready. +func waitForReady() { + for !rp.ADC.CS.HasBits(rp.ADC_CS_READY) { + } +} + +// The Pin method returns the GPIO Pin associated with the ADC mux channel, if it has one. +func (c ADCChannel) Pin() (p Pin, err error) { + err = nil + switch c { + case adc0_CH: + p = ADC0 + case adc1_CH: + p = ADC1 + case adc2_CH: + p = ADC2 + case adc3_CH: + p = ADC3 + default: + err = errors.New("no associated pin for channel") + } + return p, err +} |