machine/samd21: implement ADC
Signed-off-by: Ron Evans <ron@hybridgroup.com>
Этот коммит содержится в:
родитель
5939729c45
коммит
9d6df2b4c7
2 изменённых файлов: 159 добавлений и 0 удалений
|
@ -188,6 +188,18 @@ func (p GPIO) Configure(config GPIOConfig) {
|
||||||
}
|
}
|
||||||
// enable port config
|
// enable port config
|
||||||
p.setPinCfg(sam.PORT_PINCFG0_PMUXEN)
|
p.setPinCfg(sam.PORT_PINCFG0_PMUXEN)
|
||||||
|
case GPIO_ANALOG:
|
||||||
|
if p.Pin&1 > 0 {
|
||||||
|
// odd pin, so save the even pins
|
||||||
|
val := p.getPMux() & sam.PORT_PMUX0_PMUXE_Msk
|
||||||
|
p.setPMux(val | (GPIO_ANALOG << sam.PORT_PMUX0_PMUXO_Pos))
|
||||||
|
} else {
|
||||||
|
// even pin, so save the odd pins
|
||||||
|
val := p.getPMux() & sam.PORT_PMUX0_PMUXO_Msk
|
||||||
|
p.setPMux(val | (GPIO_COM << sam.PORT_PMUX0_PMUXE_Pos))
|
||||||
|
}
|
||||||
|
// enable port config
|
||||||
|
p.setPinCfg(sam.PORT_PINCFG0_PMUXEN | sam.PORT_PINCFG0_DRVSTR)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -258,6 +270,141 @@ func (p GPIO) setPinCfg(val sam.RegValue8) {
|
||||||
setPinCfg(p.Pin, val)
|
setPinCfg(p.Pin, val)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// InitADC initializes the ADC.
|
||||||
|
func InitADC() {
|
||||||
|
// ADC Bias Calibration
|
||||||
|
// #define ADC_FUSES_BIASCAL_ADDR (NVMCTRL_OTP4 + 4)
|
||||||
|
// #define ADC_FUSES_BIASCAL_Pos 3 /**< \brief (NVMCTRL_OTP4) ADC Bias Calibration */
|
||||||
|
// #define ADC_FUSES_BIASCAL_Msk (0x7u << ADC_FUSES_BIASCAL_Pos)
|
||||||
|
// #define ADC_FUSES_BIASCAL(value) ((ADC_FUSES_BIASCAL_Msk & ((value) << ADC_FUSES_BIASCAL_Pos)))
|
||||||
|
// #define ADC_FUSES_LINEARITY_0_ADDR NVMCTRL_OTP4
|
||||||
|
// #define ADC_FUSES_LINEARITY_0_Pos 27 /**< \brief (NVMCTRL_OTP4) ADC Linearity bits 4:0 */
|
||||||
|
// #define ADC_FUSES_LINEARITY_0_Msk (0x1Fu << ADC_FUSES_LINEARITY_0_Pos)
|
||||||
|
// #define ADC_FUSES_LINEARITY_0(value) ((ADC_FUSES_LINEARITY_0_Msk & ((value) << ADC_FUSES_LINEARITY_0_Pos)))
|
||||||
|
// #define ADC_FUSES_LINEARITY_1_ADDR (NVMCTRL_OTP4 + 4)
|
||||||
|
// #define ADC_FUSES_LINEARITY_1_Pos 0 /**< \brief (NVMCTRL_OTP4) ADC Linearity bits 7:5 */
|
||||||
|
// #define ADC_FUSES_LINEARITY_1_Msk (0x7u << ADC_FUSES_LINEARITY_1_Pos)
|
||||||
|
// #define ADC_FUSES_LINEARITY_1(value) ((ADC_FUSES_LINEARITY_1_Msk & ((value) << ADC_FUSES_LINEARITY_1_Pos)))
|
||||||
|
|
||||||
|
biasFuse := *(*uint32)(unsafe.Pointer(uintptr(0x00806020) + 4))
|
||||||
|
bias := sam.RegValue16(uint16(biasFuse>>3) & uint16(0x7))
|
||||||
|
|
||||||
|
// ADC Linearity bits 4:0
|
||||||
|
linearity0Fuse := *(*uint32)(unsafe.Pointer(uintptr(0x00806020)))
|
||||||
|
linearity := sam.RegValue16(uint16(linearity0Fuse>>27) & uint16(0x1f))
|
||||||
|
|
||||||
|
// ADC Linearity bits 7:5
|
||||||
|
linearity1Fuse := *(*uint32)(unsafe.Pointer(uintptr(0x00806020) + 4))
|
||||||
|
linearity |= sam.RegValue16(uint16(linearity1Fuse)&uint16(0x7)) << 5
|
||||||
|
|
||||||
|
// set calibration
|
||||||
|
sam.ADC.CALIB = (bias << 8) | linearity
|
||||||
|
|
||||||
|
// Wait for synchronization
|
||||||
|
waitADCSync()
|
||||||
|
|
||||||
|
// Divide Clock by 32 with 12 bits resolution as default
|
||||||
|
sam.ADC.CTRLB = (sam.ADC_CTRLB_PRESCALER_DIV32 << sam.ADC_CTRLB_PRESCALER_Pos) |
|
||||||
|
(sam.ADC_CTRLB_RESSEL_12BIT << sam.ADC_CTRLB_RESSEL_Pos)
|
||||||
|
|
||||||
|
// Sampling Time Length
|
||||||
|
sam.ADC.SAMPCTRL = 5
|
||||||
|
|
||||||
|
// Wait for synchronization
|
||||||
|
waitADCSync()
|
||||||
|
|
||||||
|
// Use internal ground
|
||||||
|
sam.ADC.INPUTCTRL = (sam.ADC_INPUTCTRL_MUXNEG_GND << sam.ADC_INPUTCTRL_MUXNEG_Pos)
|
||||||
|
|
||||||
|
// Averaging (see datasheet table in AVGCTRL register description)
|
||||||
|
sam.ADC.AVGCTRL = (sam.ADC_AVGCTRL_SAMPLENUM_1 << sam.ADC_AVGCTRL_SAMPLENUM_Pos) |
|
||||||
|
(0x0 << sam.ADC_AVGCTRL_ADJRES_Pos)
|
||||||
|
|
||||||
|
// Analog Reference is AREF pin (3.3v)
|
||||||
|
sam.ADC.INPUTCTRL |= (sam.ADC_INPUTCTRL_GAIN_DIV2 << sam.ADC_INPUTCTRL_GAIN_Pos)
|
||||||
|
|
||||||
|
// 1/2 VDDANA = 0.5 * 3V3 = 1.65V
|
||||||
|
sam.ADC.REFCTRL |= (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() {
|
||||||
|
GPIO{a.Pin}.Configure(GPIOConfig{Mode: GPIO_ANALOG})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get returns the current value of a ADC pin, in the range 0..0xffff.
|
||||||
|
func (a ADC) Get() uint16 {
|
||||||
|
ch := a.getADCChannel()
|
||||||
|
|
||||||
|
// Selection for the positive ADC input
|
||||||
|
sam.ADC.INPUTCTRL &^= sam.ADC_INPUTCTRL_MUXPOS_Msk
|
||||||
|
waitADCSync()
|
||||||
|
sam.ADC.INPUTCTRL |= sam.RegValue(ch << sam.ADC_INPUTCTRL_MUXPOS_Pos)
|
||||||
|
waitADCSync()
|
||||||
|
|
||||||
|
// Enable ADC
|
||||||
|
sam.ADC.CTRLA |= sam.ADC_CTRLA_ENABLE
|
||||||
|
waitADCSync()
|
||||||
|
|
||||||
|
// Start conversion
|
||||||
|
sam.ADC.SWTRIG |= sam.ADC_SWTRIG_START
|
||||||
|
waitADCSync()
|
||||||
|
|
||||||
|
// Clear the Data Ready flag
|
||||||
|
sam.ADC.INTFLAG = sam.ADC_INTFLAG_RESRDY
|
||||||
|
waitADCSync()
|
||||||
|
|
||||||
|
// Start conversion again, since first conversion after reference voltage changed is invalid.
|
||||||
|
sam.ADC.SWTRIG |= sam.ADC_SWTRIG_START
|
||||||
|
waitADCSync()
|
||||||
|
|
||||||
|
// Waiting for conversion to complete
|
||||||
|
for (sam.ADC.INTFLAG & sam.ADC_INTFLAG_RESRDY) == 0 {
|
||||||
|
}
|
||||||
|
val := sam.ADC.RESULT
|
||||||
|
|
||||||
|
// Disable ADC
|
||||||
|
sam.ADC.CTRLA &^= sam.ADC_CTRLA_ENABLE
|
||||||
|
waitADCSync()
|
||||||
|
|
||||||
|
return uint16(val)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a ADC) getADCChannel() uint8 {
|
||||||
|
switch a.Pin {
|
||||||
|
case PA02:
|
||||||
|
return 0
|
||||||
|
case PB08:
|
||||||
|
return 2
|
||||||
|
case PB09:
|
||||||
|
return 3
|
||||||
|
case PA04:
|
||||||
|
return 4
|
||||||
|
case PA05:
|
||||||
|
return 5
|
||||||
|
case PA06:
|
||||||
|
return 6
|
||||||
|
case PA07:
|
||||||
|
return 7
|
||||||
|
case PB02:
|
||||||
|
return 10
|
||||||
|
case PB03:
|
||||||
|
return 11
|
||||||
|
case PA09:
|
||||||
|
return 17
|
||||||
|
case PA11:
|
||||||
|
return 19
|
||||||
|
default:
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func waitADCSync() {
|
||||||
|
for (sam.ADC.STATUS & sam.ADC_STATUS_SYNCBUSY) > 0 {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// UART on the SAMD21.
|
// UART on the SAMD21.
|
||||||
type UART struct {
|
type UART struct {
|
||||||
Buffer *RingBuffer
|
Buffer *RingBuffer
|
||||||
|
|
|
@ -24,6 +24,7 @@ func init() {
|
||||||
initRTC()
|
initRTC()
|
||||||
initSERCOMClocks()
|
initSERCOMClocks()
|
||||||
initUSBClock()
|
initUSBClock()
|
||||||
|
initADCClock()
|
||||||
|
|
||||||
// connect to USB CDC interface
|
// connect to USB CDC interface
|
||||||
machine.UART0.Configure(machine.UARTConfig{})
|
machine.UART0.Configure(machine.UARTConfig{})
|
||||||
|
@ -355,3 +356,14 @@ func initUSBClock() {
|
||||||
sam.GCLK_CLKCTRL_CLKEN)
|
sam.GCLK_CLKCTRL_CLKEN)
|
||||||
waitForSync()
|
waitForSync()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func initADCClock() {
|
||||||
|
// Turn on clock for ADC
|
||||||
|
sam.PM.APBCMASK |= sam.PM_APBCMASK_ADC_
|
||||||
|
|
||||||
|
// Put Generic Clock Generator 0 as source for Generic Clock Multiplexer for ADC.
|
||||||
|
sam.GCLK.CLKCTRL = sam.RegValue16((sam.GCLK_CLKCTRL_ID_ADC << sam.GCLK_CLKCTRL_ID_Pos) |
|
||||||
|
(sam.GCLK_CLKCTRL_GEN_GCLK0 << sam.GCLK_CLKCTRL_GEN_Pos) |
|
||||||
|
sam.GCLK_CLKCTRL_CLKEN)
|
||||||
|
waitForSync()
|
||||||
|
}
|
||||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче