samd51: fix ADC multisampling
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.
Этот коммит содержится в:
родитель
1bba5f5d7b
коммит
64957c5254
1 изменённых файлов: 45 добавлений и 29 удалений
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче