Multisampling/averaging (using the Samples configuration property) was
returning incorrect values. When I investigated this, I found that the
samd51 gives erratic values when using multisampling together with fewer
than 16 bits resolution.

I fixed this by forcing 16 bit resolution when multisampling, and
adjusting the output to account for multisampling.

Found while reading the battery value on a pybadge, which gave
non-sensible values with Samples set to a value larger than 1.
Этот коммит содержится в:
Ayke van Laethem 2023-04-18 16:39:13 +02:00 коммит произвёл Ron Evans
родитель 1bba5f5d7b
коммит 64957c5254

Просмотреть файл

@ -749,36 +749,10 @@ func (a ADC) Configure(config ADCConfig) {
for adc.SYNCBUSY.HasBits(sam.ADC_SYNCBUSY_CTRLB) { for adc.SYNCBUSY.HasBits(sam.ADC_SYNCBUSY_CTRLB) {
} // wait for sync } // 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) // Averaging (see datasheet table in AVGCTRL register description)
var resolution uint32 = sam.ADC_CTRLB_RESSEL_16BIT
var samples uint32 var samples uint32
switch config.Samples { switch config.Samples {
case 1:
samples = sam.ADC_AVGCTRL_SAMPLENUM_1
case 2: case 2:
samples = sam.ADC_AVGCTRL_SAMPLENUM_2 samples = sam.ADC_AVGCTRL_SAMPLENUM_2
case 4: case 4:
@ -800,11 +774,39 @@ func (a ADC) Configure(config ADCConfig) {
case 1024: case 1024:
samples = sam.ADC_AVGCTRL_SAMPLENUM_1024 samples = sam.ADC_AVGCTRL_SAMPLENUM_1024
default: // 1 sample only (no oversampling nor averaging), adjusting result by 0 default: // 1 sample only (no oversampling nor averaging), adjusting result by 0
// Resolutions less than 16 bits only make sense when sampling only
// once. Resulting ADC values become erratic when using both
// multi-sampling and less than 16 bits of resolution.
samples = sam.ADC_AVGCTRL_SAMPLENUM_1 samples = sam.ADC_AVGCTRL_SAMPLENUM_1
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.AVGCTRL.Set(uint8(samples<<sam.ADC_AVGCTRL_SAMPLENUM_Pos) | adc.AVGCTRL.Set(uint8(samples<<sam.ADC_AVGCTRL_SAMPLENUM_Pos) |
(0 << sam.ADC_AVGCTRL_ADJRES_Pos)) (0 << sam.ADC_AVGCTRL_ADJRES_Pos))
adc.CTRLA.SetBits(sam.ADC_CTRLA_PRESCALER_DIV32 << sam.ADC_CTRLA_PRESCALER_Pos)
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
for adc.SYNCBUSY.HasBits(sam.ADC_SYNCBUSY_AVGCTRL) { for adc.SYNCBUSY.HasBits(sam.ADC_SYNCBUSY_AVGCTRL) {
} // wait for sync } // wait for sync
for adc.SYNCBUSY.HasBits(sam.ADC_SYNCBUSY_REFCTRL) { for adc.SYNCBUSY.HasBits(sam.ADC_SYNCBUSY_REFCTRL) {
@ -871,10 +873,24 @@ func (a ADC) Get() uint16 {
val = val << 8 val = val << 8
case sam.ADC_CTRLB_RESSEL_10BIT: case sam.ADC_CTRLB_RESSEL_10BIT:
val = val << 6 val = val << 6
case sam.ADC_CTRLB_RESSEL_16BIT:
val = val << 4
case sam.ADC_CTRLB_RESSEL_12BIT: case sam.ADC_CTRLB_RESSEL_12BIT:
val = val << 4 val = val << 4
case sam.ADC_CTRLB_RESSEL_16BIT:
// Adjust for multiple samples. This is only configured when the
// resolution is 16 bits.
switch (bus.AVGCTRL.Get() & sam.ADC_AVGCTRL_SAMPLENUM_Msk) >> sam.ADC_AVGCTRL_SAMPLENUM_Pos {
case sam.ADC_AVGCTRL_SAMPLENUM_1:
val <<= 4
case sam.ADC_AVGCTRL_SAMPLENUM_2:
val <<= 3
case sam.ADC_AVGCTRL_SAMPLENUM_4:
val <<= 2
case sam.ADC_AVGCTRL_SAMPLENUM_8:
val <<= 1
default:
// These values are all shifted by the hardware so they fit exactly
// in a 16-bit integer, so they don't need to be shifted here.
}
} }
return val return val
} }