//go:build rp2040 || rp2350 package machine import ( "device/rp" "errors" "sync" ) // ADCChannel is the ADC peripheral mux channel. 0-4. type ADCChannel uint8 // Used to serialise ADC sampling var adcLock sync.Mutex // ADC peripheral reference voltage (mV) var adcAref uint32 // InitADC resets the ADC peripheral. func InitADC() { resetBlock(rp.RESETS_RESET_ADC) unresetBlockWait(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) { if a.Pin < ADC0 { return 0, errors.New("no ADC channel for pin value") } return ADCChannel(a.Pin - ADC0), nil } // 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)<>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() } thermChan, _ := ADC{Pin: thermADC}.GetADCChannel() // Enable temperature sensor bias source rp.ADC.CS.SetBits(rp.ADC_CS_TS_EN) // T = 27 - (ADC_voltage - 0.706)/0.001721 // 1/0.001721 ≈ 581 return int32(((int64(27000) << 16) - ((int64(thermChan.getVoltage()) - (int64(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) { return Pin(c) + ADC0, nil }