accept configuration struct for ADC parameters (#1533)

Этот коммит содержится в:
ardnew 2020-12-15 17:31:13 -06:00
родитель 3d6921b0e1
коммит 06f231468d
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 695575CCC8816281
8 изменённых файлов: 371 добавлений и 64 удалений

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

@ -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()

12
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)
}

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

@ -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<<sam.ADC_CTRLB_RESSEL_Pos))
// Sampling Time Length
sam.ADC.SAMPCTRL.Set(5)
@ -325,18 +342,44 @@ func InitADC() {
sam.ADC.INPUTCTRL.Set(sam.ADC_INPUTCTRL_MUXNEG_GND << sam.ADC_INPUTCTRL_MUXNEG_Pos)
// Averaging (see datasheet table in AVGCTRL register description)
sam.ADC.AVGCTRL.Set((sam.ADC_AVGCTRL_SAMPLENUM_1 << sam.ADC_AVGCTRL_SAMPLENUM_Pos) |
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:
samples = sam.ADC_AVGCTRL_SAMPLENUM_1
}
sam.ADC.AVGCTRL.Set(uint8(samples<<sam.ADC_AVGCTRL_SAMPLENUM_Pos) |
(0x0 << sam.ADC_AVGCTRL_ADJRES_Pos))
// TODO: use config.Reference to set AREF level
// Analog Reference is AREF pin (3.3v)
sam.ADC.INPUTCTRL.SetBits(sam.ADC_INPUTCTRL_GAIN_DIV2 << sam.ADC_INPUTCTRL_GAIN_Pos)
// 1/2 VDDANA = 0.5 * 3V3 = 1.65V
sam.ADC.REFCTRL.SetBits(sam.ADC_REFCTRL_REFSEL_INTVCC1 << sam.ADC_REFCTRL_REFSEL_Pos)
}
// Configure configures a ADCPin to be able to be used to read data.
func (a ADC) Configure() {
a.Pin.Configure(PinConfig{Mode: PinAnalog})
return
}

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

@ -720,65 +720,83 @@ func InitADC() {
// calibrate ADC1
sam.ADC1.CALIB.Set(uint16((biascomp | biasr2r | biasref) >> 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<<sam.ADC_AVGCTRL_SAMPLENUM_Pos) |
(0 << sam.ADC_AVGCTRL_ADJRES_Pos))
for adc.SYNCBUSY.HasBits(sam.ADC_SYNCBUSY_AVGCTRL) {
} // wait for sync
for adc.SYNCBUSY.HasBits(sam.ADC_SYNCBUSY_REFCTRL) {
} // wait for sync
// TODO: use config.Reference to set AREF level
// default is 3V3 reference voltage
adc.REFCTRL.SetBits(sam.ADC_REFCTRL_REFSEL_INTVCC1)
}
a.Pin.Configure(PinConfig{Mode: PinAnalog})
}

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

@ -118,7 +118,7 @@ func InitADC() {
}
// Configure configures a ADCPin to be able to be used to read data.
func (a ADC) Configure() {
func (a ADC) Configure(ADCConfig) {
return // no pin specific setup on AVR machine.
}

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

@ -73,7 +73,7 @@ func InitADC() {
}
// Configure configures an ADC pin to be able to be used to read data.
func (adc ADC) Configure() {
func (adc ADC) Configure(ADCConfig) {
}
// Get reads the current analog value from this ADC peripheral.

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

@ -4,6 +4,7 @@ package machine
import (
"device/nrf"
"unsafe"
)
// Hardware pins
@ -61,6 +62,122 @@ func (i2c I2C) setPins(scl, sda Pin) {
i2c.Bus.PSELSDA.Set(uint32(sda))
}
// SPI
func (spi SPI) setPins(sck, sdo, sdi Pin) {
if sck == 0 {
sck = SPI0_SCK_PIN
}
if sdo == 0 {
sdo = SPI0_SDO_PIN
}
if sdi == 0 {
sdi = SPI0_SDI_PIN
}
spi.Bus.PSEL.SCK.Set(uint32(sck))
spi.Bus.PSEL.MOSI.Set(uint32(sdo))
spi.Bus.PSEL.MISO.Set(uint32(sdi))
}
// InitADC initializes the registers needed for ADC.
func InitADC() {
return // no specific setup on nrf52 machine.
}
// Configure configures an ADC pin to be able to read analog data.
func (a ADC) Configure(ADCConfig) {
return // no pin specific setup on nrf52 machine.
}
// Get returns the current value of a ADC pin in the range 0..0xffff.
func (a ADC) Get() uint16 {
var pwmPin uint32
var value int16
switch a.Pin {
case 2:
pwmPin = nrf.SAADC_CH_PSELP_PSELP_AnalogInput0
case 3:
pwmPin = nrf.SAADC_CH_PSELP_PSELP_AnalogInput1
case 4:
pwmPin = nrf.SAADC_CH_PSELP_PSELP_AnalogInput2
case 5:
pwmPin = nrf.SAADC_CH_PSELP_PSELP_AnalogInput3
case 28:
pwmPin = nrf.SAADC_CH_PSELP_PSELP_AnalogInput4
case 29:
pwmPin = nrf.SAADC_CH_PSELP_PSELP_AnalogInput5
case 30:
pwmPin = nrf.SAADC_CH_PSELP_PSELP_AnalogInput6
case 31:
pwmPin = nrf.SAADC_CH_PSELP_PSELP_AnalogInput7
default:
return 0
}
nrf.SAADC.RESOLUTION.Set(nrf.SAADC_RESOLUTION_VAL_12bit)
// Enable ADC.
nrf.SAADC.ENABLE.Set(nrf.SAADC_ENABLE_ENABLE_Enabled << nrf.SAADC_ENABLE_ENABLE_Pos)
for i := 0; i < 8; i++ {
nrf.SAADC.CH[i].PSELN.Set(nrf.SAADC_CH_PSELP_PSELP_NC)
nrf.SAADC.CH[i].PSELP.Set(nrf.SAADC_CH_PSELP_PSELP_NC)
}
// Configure ADC.
nrf.SAADC.CH[0].CONFIG.Set(((nrf.SAADC_CH_CONFIG_RESP_Bypass << nrf.SAADC_CH_CONFIG_RESP_Pos) & nrf.SAADC_CH_CONFIG_RESP_Msk) |
((nrf.SAADC_CH_CONFIG_RESP_Bypass << nrf.SAADC_CH_CONFIG_RESN_Pos) & nrf.SAADC_CH_CONFIG_RESN_Msk) |
((nrf.SAADC_CH_CONFIG_GAIN_Gain1_5 << nrf.SAADC_CH_CONFIG_GAIN_Pos) & nrf.SAADC_CH_CONFIG_GAIN_Msk) |
((nrf.SAADC_CH_CONFIG_REFSEL_Internal << nrf.SAADC_CH_CONFIG_REFSEL_Pos) & nrf.SAADC_CH_CONFIG_REFSEL_Msk) |
((nrf.SAADC_CH_CONFIG_TACQ_3us << nrf.SAADC_CH_CONFIG_TACQ_Pos) & nrf.SAADC_CH_CONFIG_TACQ_Msk) |
((nrf.SAADC_CH_CONFIG_MODE_SE << nrf.SAADC_CH_CONFIG_MODE_Pos) & nrf.SAADC_CH_CONFIG_MODE_Msk))
// Set pin to read.
nrf.SAADC.CH[0].PSELN.Set(pwmPin)
nrf.SAADC.CH[0].PSELP.Set(pwmPin)
// Destination for sample result.
nrf.SAADC.RESULT.PTR.Set(uint32(uintptr(unsafe.Pointer(&value))))
nrf.SAADC.RESULT.MAXCNT.Set(1) // One sample
// Start tasks.
nrf.SAADC.TASKS_START.Set(1)
for nrf.SAADC.EVENTS_STARTED.Get() == 0 {
}
nrf.SAADC.EVENTS_STARTED.Set(0x00)
// Start the sample task.
nrf.SAADC.TASKS_SAMPLE.Set(1)
// Wait until the sample task is done.
for nrf.SAADC.EVENTS_END.Get() == 0 {
}
nrf.SAADC.EVENTS_END.Set(0x00)
// Stop the ADC
nrf.SAADC.TASKS_STOP.Set(1)
for nrf.SAADC.EVENTS_STOPPED.Get() == 0 {
}
nrf.SAADC.EVENTS_STOPPED.Set(0)
// Disable the ADC.
nrf.SAADC.ENABLE.Set(nrf.SAADC_ENABLE_ENABLE_Disabled << nrf.SAADC_ENABLE_ENABLE_Pos)
if value < 0 {
value = 0
}
// Return 16-bit result from 12-bit value.
return uint16(value << 4)
}
// PWM
var (
pwmChannelPins = [3]uint32{0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF}

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

@ -4,6 +4,7 @@ package machine
import (
"device/nrf"
"unsafe"
)
// Hardware pins
@ -77,6 +78,122 @@ func (i2c I2C) setPins(scl, sda Pin) {
i2c.Bus.PSEL.SDA.Set(uint32(sda))
}
// SPI
func (spi SPI) setPins(sck, sdo, sdi Pin) {
if sck == 0 {
sck = SPI0_SCK_PIN
}
if sdo == 0 {
sdo = SPI0_SDO_PIN
}
if sdi == 0 {
sdi = SPI0_SDI_PIN
}
spi.Bus.PSEL.SCK.Set(uint32(sck))
spi.Bus.PSEL.MOSI.Set(uint32(sdo))
spi.Bus.PSEL.MISO.Set(uint32(sdi))
}
// InitADC initializes the registers needed for ADC.
func InitADC() {
return // no specific setup on nrf52840 machine.
}
// Configure configures an ADC pin to be able to read analog data.
func (a ADC) Configure(ADCConfig) {
return // no pin specific setup on nrf52840 machine.
}
// Get returns the current value of a ADC pin in the range 0..0xffff.
func (a ADC) Get() uint16 {
var pwmPin uint32
var value int16
switch a.Pin {
case 2:
pwmPin = nrf.SAADC_CH_PSELP_PSELP_AnalogInput0
case 3:
pwmPin = nrf.SAADC_CH_PSELP_PSELP_AnalogInput1
case 4:
pwmPin = nrf.SAADC_CH_PSELP_PSELP_AnalogInput2
case 5:
pwmPin = nrf.SAADC_CH_PSELP_PSELP_AnalogInput3
case 28:
pwmPin = nrf.SAADC_CH_PSELP_PSELP_AnalogInput4
case 29:
pwmPin = nrf.SAADC_CH_PSELP_PSELP_AnalogInput5
case 30:
pwmPin = nrf.SAADC_CH_PSELP_PSELP_AnalogInput6
case 31:
pwmPin = nrf.SAADC_CH_PSELP_PSELP_AnalogInput7
default:
return 0
}
nrf.SAADC.RESOLUTION.Set(nrf.SAADC_RESOLUTION_VAL_12bit)
// Enable ADC.
nrf.SAADC.ENABLE.Set(nrf.SAADC_ENABLE_ENABLE_Enabled << nrf.SAADC_ENABLE_ENABLE_Pos)
for i := 0; i < 8; i++ {
nrf.SAADC.CH[i].PSELN.Set(nrf.SAADC_CH_PSELP_PSELP_NC)
nrf.SAADC.CH[i].PSELP.Set(nrf.SAADC_CH_PSELP_PSELP_NC)
}
// Configure ADC.
nrf.SAADC.CH[0].CONFIG.Set(((nrf.SAADC_CH_CONFIG_RESP_Bypass << nrf.SAADC_CH_CONFIG_RESP_Pos) & nrf.SAADC_CH_CONFIG_RESP_Msk) |
((nrf.SAADC_CH_CONFIG_RESP_Bypass << nrf.SAADC_CH_CONFIG_RESN_Pos) & nrf.SAADC_CH_CONFIG_RESN_Msk) |
((nrf.SAADC_CH_CONFIG_GAIN_Gain1_5 << nrf.SAADC_CH_CONFIG_GAIN_Pos) & nrf.SAADC_CH_CONFIG_GAIN_Msk) |
((nrf.SAADC_CH_CONFIG_REFSEL_Internal << nrf.SAADC_CH_CONFIG_REFSEL_Pos) & nrf.SAADC_CH_CONFIG_REFSEL_Msk) |
((nrf.SAADC_CH_CONFIG_TACQ_3us << nrf.SAADC_CH_CONFIG_TACQ_Pos) & nrf.SAADC_CH_CONFIG_TACQ_Msk) |
((nrf.SAADC_CH_CONFIG_MODE_SE << nrf.SAADC_CH_CONFIG_MODE_Pos) & nrf.SAADC_CH_CONFIG_MODE_Msk))
// Set pin to read.
nrf.SAADC.CH[0].PSELN.Set(pwmPin)
nrf.SAADC.CH[0].PSELP.Set(pwmPin)
// Destination for sample result.
nrf.SAADC.RESULT.PTR.Set(uint32(uintptr(unsafe.Pointer(&value))))
nrf.SAADC.RESULT.MAXCNT.Set(1) // One sample
// Start tasks.
nrf.SAADC.TASKS_START.Set(1)
for nrf.SAADC.EVENTS_STARTED.Get() == 0 {
}
nrf.SAADC.EVENTS_STARTED.Set(0x00)
// Start the sample task.
nrf.SAADC.TASKS_SAMPLE.Set(1)
// Wait until the sample task is done.
for nrf.SAADC.EVENTS_END.Get() == 0 {
}
nrf.SAADC.EVENTS_END.Set(0x00)
// Stop the ADC
nrf.SAADC.TASKS_STOP.Set(1)
for nrf.SAADC.EVENTS_STOPPED.Get() == 0 {
}
nrf.SAADC.EVENTS_STOPPED.Set(0)
// Disable the ADC.
nrf.SAADC.ENABLE.Set(nrf.SAADC_ENABLE_ENABLE_Disabled << nrf.SAADC_ENABLE_ENABLE_Pos)
if value < 0 {
value = 0
}
// Return 16-bit result from 12-bit value.
return uint16(value << 4)
}
// PWM
var (
pwmChannelPins = [4]uint32{0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF}