From 06f231468da34a546a3f0c6c3cd1483e21b47994 Mon Sep 17 00:00:00 2001 From: ardnew Date: Tue, 15 Dec 2020 17:31:13 -0600 Subject: [PATCH] accept configuration struct for ADC parameters (#1533) --- src/examples/adc/adc.go | 2 +- src/machine/adc.go | 12 +++ src/machine/machine_atsamd21.go | 53 +++++++++++-- src/machine/machine_atsamd51.go | 130 ++++++++++++++++++-------------- src/machine/machine_avr.go | 2 +- src/machine/machine_generic.go | 2 +- src/machine/machine_nrf52.go | 117 ++++++++++++++++++++++++++++ src/machine/machine_nrf52840.go | 117 ++++++++++++++++++++++++++++ 8 files changed, 371 insertions(+), 64 deletions(-) create mode 100644 src/machine/adc.go diff --git a/src/examples/adc/adc.go b/src/examples/adc/adc.go index 9b4ddd27..de8a7f88 100644 --- a/src/examples/adc/adc.go +++ b/src/examples/adc/adc.go @@ -15,7 +15,7 @@ func main() { led.Configure(machine.PinConfig{Mode: machine.PinOutput}) sensor := machine.ADC{machine.ADC2} - sensor.Configure() + sensor.Configure(machine.ADCConfig{}) for { val := sensor.Get() diff --git a/src/machine/adc.go b/src/machine/adc.go new file mode 100644 index 00000000..739ca2ed --- /dev/null +++ b/src/machine/adc.go @@ -0,0 +1,12 @@ +package machine + +// Hardware abstraction layer for the analog-to-digital conversion (ADC) +// peripheral. + +// ADCConfig holds ADC configuration parameters. If left unspecified, the zero +// value of each parameter will use the peripheral's default settings. +type ADCConfig struct { + Reference uint32 // analog reference voltage (AREF) in millivolts + Resolution uint32 // number of bits for a single conversion (e.g., 8, 10, 12) + Samples uint32 // number of samples for a single conversion (e.g., 4, 8, 16, 32) +} diff --git a/src/machine/machine_atsamd21.go b/src/machine/machine_atsamd21.go index b40db545..f93fcf68 100644 --- a/src/machine/machine_atsamd21.go +++ b/src/machine/machine_atsamd21.go @@ -307,13 +307,30 @@ func InitADC() { // set calibration sam.ADC.CALIB.Set((bias << 8) | linearity) +} + +// Configure configures a ADC pin to be able to be used to read data. +func (a ADC) Configure(config ADCConfig) { // Wait for synchronization waitADCSync() + var resolution uint32 + switch config.Resolution { + case 8: + resolution = sam.ADC_CTRLB_RESSEL_8BIT + case 10: + resolution = sam.ADC_CTRLB_RESSEL_10BIT + case 12: + resolution = sam.ADC_CTRLB_RESSEL_12BIT + case 16: + resolution = sam.ADC_CTRLB_RESSEL_16BIT + default: + resolution = sam.ADC_CTRLB_RESSEL_12BIT + } // Divide Clock by 32 with 12 bits resolution as default sam.ADC.CTRLB.Set((sam.ADC_CTRLB_PRESCALER_DIV32 << sam.ADC_CTRLB_PRESCALER_Pos) | - (sam.ADC_CTRLB_RESSEL_12BIT << sam.ADC_CTRLB_RESSEL_Pos)) + uint16(resolution<> 16)) - - sam.ADC0.CTRLA.SetBits(sam.ADC_CTRLA_PRESCALER_DIV32 << sam.ADC_CTRLA_PRESCALER_Pos) - // adcs[i]->CTRLB.bit.RESSEL = ADC_CTRLB_RESSEL_10BIT_Val; - sam.ADC0.CTRLB.SetBits(sam.ADC_CTRLB_RESSEL_12BIT << sam.ADC_CTRLB_RESSEL_Pos) - - // wait for sync - for sam.ADC0.SYNCBUSY.HasBits(sam.ADC_SYNCBUSY_CTRLB) { - } - - // sampling Time Length - sam.ADC0.SAMPCTRL.Set(5) - - // wait for sync - for sam.ADC0.SYNCBUSY.HasBits(sam.ADC_SYNCBUSY_SAMPCTRL) { - } - - // No Negative input (Internal Ground) - sam.ADC0.INPUTCTRL.Set(sam.ADC_INPUTCTRL_MUXNEG_GND << sam.ADC_INPUTCTRL_MUXNEG_Pos) - - // wait for sync - for sam.ADC0.SYNCBUSY.HasBits(sam.ADC_SYNCBUSY_INPUTCTRL) { - } - - // Averaging (see datasheet table in AVGCTRL register description) - // 1 sample only (no oversampling nor averaging), adjusting result by 0 - sam.ADC0.AVGCTRL.Set(sam.ADC_AVGCTRL_SAMPLENUM_1 | (0 << sam.ADC_AVGCTRL_ADJRES_Pos)) - - // wait for sync - for sam.ADC0.SYNCBUSY.HasBits(sam.ADC_SYNCBUSY_AVGCTRL) { - } - - // same for ADC1, as for ADC0 - sam.ADC1.CTRLA.SetBits(sam.ADC_CTRLA_PRESCALER_DIV32 << sam.ADC_CTRLA_PRESCALER_Pos) - sam.ADC1.CTRLB.SetBits(sam.ADC_CTRLB_RESSEL_12BIT << sam.ADC_CTRLB_RESSEL_Pos) - for sam.ADC1.SYNCBUSY.HasBits(sam.ADC_SYNCBUSY_CTRLB) { - } - sam.ADC1.SAMPCTRL.Set(5) - for sam.ADC1.SYNCBUSY.HasBits(sam.ADC_SYNCBUSY_SAMPCTRL) { - } - sam.ADC1.INPUTCTRL.Set(sam.ADC_INPUTCTRL_MUXNEG_GND << sam.ADC_INPUTCTRL_MUXNEG_Pos) - for sam.ADC1.SYNCBUSY.HasBits(sam.ADC_SYNCBUSY_INPUTCTRL) { - } - sam.ADC1.AVGCTRL.Set(sam.ADC_AVGCTRL_SAMPLENUM_1 | (0 << sam.ADC_AVGCTRL_ADJRES_Pos)) - for sam.ADC1.SYNCBUSY.HasBits(sam.ADC_SYNCBUSY_AVGCTRL) { - } - - // wait for sync - for sam.ADC0.SYNCBUSY.HasBits(sam.ADC_SYNCBUSY_REFCTRL) { - } - for sam.ADC1.SYNCBUSY.HasBits(sam.ADC_SYNCBUSY_REFCTRL) { - } - - // default is 3V3 reference voltage - sam.ADC0.REFCTRL.SetBits(sam.ADC_REFCTRL_REFSEL_INTVCC1) - sam.ADC1.REFCTRL.SetBits(sam.ADC_REFCTRL_REFSEL_INTVCC1) } // Configure configures a ADCPin to be able to be used to read data. -func (a ADC) Configure() { +func (a ADC) Configure(config ADCConfig) { + + for _, adc := range []*sam.ADC_Type{sam.ADC0, sam.ADC1} { + + for adc.SYNCBUSY.HasBits(sam.ADC_SYNCBUSY_CTRLB) { + } // wait for sync + + adc.CTRLA.SetBits(sam.ADC_CTRLA_PRESCALER_DIV32 << sam.ADC_CTRLA_PRESCALER_Pos) + var resolution uint32 + switch config.Resolution { + case 8: + resolution = sam.ADC_CTRLB_RESSEL_8BIT + case 10: + resolution = sam.ADC_CTRLB_RESSEL_10BIT + case 12: + resolution = sam.ADC_CTRLB_RESSEL_12BIT + case 16: + resolution = sam.ADC_CTRLB_RESSEL_16BIT + default: + resolution = sam.ADC_CTRLB_RESSEL_12BIT + } + adc.CTRLB.SetBits(uint16(resolution << sam.ADC_CTRLB_RESSEL_Pos)) + adc.SAMPCTRL.Set(5) // sampling Time Length + + for adc.SYNCBUSY.HasBits(sam.ADC_SYNCBUSY_SAMPCTRL) { + } // wait for sync + + // No Negative input (Internal Ground) + adc.INPUTCTRL.Set(sam.ADC_INPUTCTRL_MUXNEG_GND << sam.ADC_INPUTCTRL_MUXNEG_Pos) + for adc.SYNCBUSY.HasBits(sam.ADC_SYNCBUSY_INPUTCTRL) { + } // wait for sync + + // Averaging (see datasheet table in AVGCTRL register description) + var samples uint32 + switch config.Resolution { + case 1: + samples = sam.ADC_AVGCTRL_SAMPLENUM_1 + case 2: + samples = sam.ADC_AVGCTRL_SAMPLENUM_2 + case 4: + samples = sam.ADC_AVGCTRL_SAMPLENUM_4 + case 8: + samples = sam.ADC_AVGCTRL_SAMPLENUM_8 + case 16: + samples = sam.ADC_AVGCTRL_SAMPLENUM_16 + case 32: + samples = sam.ADC_AVGCTRL_SAMPLENUM_32 + case 64: + samples = sam.ADC_AVGCTRL_SAMPLENUM_64 + case 128: + samples = sam.ADC_AVGCTRL_SAMPLENUM_128 + case 256: + samples = sam.ADC_AVGCTRL_SAMPLENUM_256 + case 512: + samples = sam.ADC_AVGCTRL_SAMPLENUM_512 + case 1024: + samples = sam.ADC_AVGCTRL_SAMPLENUM_1024 + default: // 1 sample only (no oversampling nor averaging), adjusting result by 0 + samples = sam.ADC_AVGCTRL_SAMPLENUM_1 + } + adc.AVGCTRL.Set(uint8(samples<