diff --git a/ports/atmel-samd/Makefile b/ports/atmel-samd/Makefile
index bd01f174ed..e38cac224a 100644
--- a/ports/atmel-samd/Makefile
+++ b/ports/atmel-samd/Makefile
@@ -168,7 +168,9 @@ endif
SRC_ASF := \
gcc/gcc/startup_$(CHIP_FAMILY).c \
gcc/system_$(CHIP_FAMILY).c \
+ hal/src/hal_adc_sync.c \
hal/src/hal_atomic.c \
+ hal/src/hal_dac_sync.c \
hal/src/hal_delay.c \
hal/src/hal_flash.c \
hal/src/hal_i2c_m_sync.c \
@@ -177,7 +179,9 @@ SRC_ASF := \
hal/src/hal_spi_m_sync.c \
hal/src/hal_timer.c \
hal/src/hal_usb_device.c \
+ hpl/adc/hpl_adc.c \
hpl/core/hpl_init.c \
+ hpl/dac/hpl_dac.c \
hpl/gclk/hpl_gclk.c \
hpl/nvmctrl/hpl_nvmctrl.c \
hpl/pm/hpl_pm.c \
@@ -265,10 +269,10 @@ SRC_COMMON_HAL = \
os/__init__.c \
storage/__init__.c \
time/__init__.c \
-# analogio/__init__.c \
+ analogio/__init__.c \
analogio/AnalogIn.c \
analogio/AnalogOut.c \
- audiobusio/__init__.c \
+# audiobusio/__init__.c \
audiobusio/PDMIn.c \
audioio/__init__.c \
audioio/AudioOut.c \
diff --git a/ports/atmel-samd/asf4_conf/samd21/hpl_adc_config.h b/ports/atmel-samd/asf4_conf/samd21/hpl_adc_config.h
new file mode 100644
index 0000000000..627f4e9bd4
--- /dev/null
+++ b/ports/atmel-samd/asf4_conf/samd21/hpl_adc_config.h
@@ -0,0 +1,296 @@
+/* Auto-generated config file hpl_adc_config.h */
+#ifndef HPL_ADC_CONFIG_H
+#define HPL_ADC_CONFIG_H
+
+// <<< Use Configuration Wizard in Context Menu >>>
+
+#ifndef CONF_ADC_0_ENABLE
+#define CONF_ADC_0_ENABLE 1
+#endif
+
+// Basic Configuration
+
+// Conversion resolution
+// <0x0=>12-bit
+// <0x1=>16-bit (averaging must be enabled)
+// <0x2=>10-bit
+// <0x3=>8-bit
+// Defines the bit resolution for the ADC sample values (RESSEL)
+// adc_resolution
+#ifndef CONF_ADC_0_RESSEL
+#define CONF_ADC_0_RESSEL 0x0
+#endif
+
+// Reference Selection
+// <0x0=>1.0V voltage reference
+// <0x1=>1/1.48 VDDANA
+// <0x2=>1/2 VDDANA (only for VDDANA > 2.0V)
+// <0x3=>External reference A
+// <0x4=>External reference B
+// Select the reference for the ADC (REFSEL)
+// adc_reference
+#ifndef CONF_ADC_0_REFSEL
+#define CONF_ADC_0_REFSEL 0x2
+#endif
+
+// Prescaler configuration
+// <0x0=>Peripheral clock divided by 4
+// <0x1=>Peripheral clock divided by 8
+// <0x2=>Peripheral clock divided by 16
+// <0x3=>Peripheral clock divided by 32
+// <0x4=>Peripheral clock divided by 64
+// <0x5=>Peripheral clock divided by 128
+// <0x6=>Peripheral clock divided by 256
+// <0x7=>Peripheral clock divided by 512
+// These bits define the ADC clock relative to the peripheral clock (PRESCALER)
+// adc_prescaler
+#ifndef CONF_ADC_0_PRESCALER
+#define CONF_ADC_0_PRESCALER 0x3
+#endif
+
+// Free Running Mode
+// When enabled, the ADC is in free running mode and a new conversion will be initiated when a previous conversion completes. (FREERUN)
+// adc_freerunning_mode
+#ifndef CONF_ADC_0_FREERUN
+#define CONF_ADC_0_FREERUN 0
+#endif
+
+// Differential Mode
+// In differential mode, the voltage difference between the MUXPOS and MUXNEG inputs will be converted by the ADC. (DIFFMODE)
+// adc_differential_mode
+#ifndef CONF_ADC_0_DIFFMODE
+#define CONF_ADC_0_DIFFMODE 0
+#endif
+
+// Positive Mux Input Selection
+// <0x00=>ADC AIN0 pin
+// <0x01=>ADC AIN1 pin
+// <0x02=>ADC AIN2 pin
+// <0x03=>ADC AIN3 pin
+// <0x04=>ADC AIN4 pin
+// <0x05=>ADC AIN5 pin
+// <0x06=>ADC AIN6 pin
+// <0x07=>ADC AIN7 pin
+// <0x08=>ADC AIN8 pin
+// <0x09=>ADC AIN9 pin
+// <0x0A=>ADC AIN10 pin
+// <0x0B=>ADC AIN11 pin
+// <0x0C=>ADC AIN12 pin
+// <0x0D=>ADC AIN13 pin
+// <0x0E=>ADC AIN14 pin
+// <0x0F=>ADC AIN15 pin
+// <0x10=>ADC AIN16 pin
+// <0x11=>ADC AIN17 pin
+// <0x12=>ADC AIN18 pin
+// <0x13=>ADC AIN19 pin
+// <0x18=>Temperature reference
+// <0x19=>Bandgap voltage
+// <0x1A=>1/4 scaled core supply
+// <0x1B=>1/4 scaled I/O supply
+// <0x1C=>DAC output
+// These bits define the Mux selection for the positive ADC input. (MUXPOS)
+// adc_pinmux_positive
+#ifndef CONF_ADC_0_MUXPOS
+#define CONF_ADC_0_MUXPOS 0x02
+#endif
+
+// Negative Mux Input Selection
+// <0x00=>ADC AIN0 pin
+// <0x01=>ADC AIN1 pin
+// <0x02=>ADC AIN2 pin
+// <0x03=>ADC AIN3 pin
+// <0x04=>ADC AIN4 pin
+// <0x05=>ADC AIN5 pin
+// <0x06=>ADC AIN6 pin
+// <0x07=>ADC AIN7 pin
+// <0x18=>Internal ground
+// <0x19=>I/O ground
+// These bits define the Mux selection for the negative ADC input. (MUXNEG)
+// adc_pinmux_negative
+#ifndef CONF_ADC_0_MUXNEG
+#define CONF_ADC_0_MUXNEG 0x18
+#endif
+
+//
+
+// Advanced Configuration
+// adc_advanced_settings
+#ifndef CONF_ADC_0_ADVANCED_CONFIG
+#define CONF_ADC_0_ADVANCED_CONFIG 0
+#endif
+
+// Run in standby
+// Indicates whether the ADC will continue running in standby sleep mode or not (RUNSTDBY)
+// adc_arch_runstdby
+#ifndef CONF_ADC_0_RUNSTDBY
+#define CONF_ADC_0_RUNSTDBY 0
+#endif
+
+// Debug Run
+// If enabled, the ADC is running if the CPU is halted by an external debugger. (DBGRUN)
+// adc_arch_dbgrun
+#ifndef CONF_ADC_0_DBGRUN
+#define CONF_ADC_0_DBGRUN 0
+#endif
+
+// Left-Adjusted Result
+// When enabled, the ADC conversion result is left-adjusted in the RESULT register. The high byte of the 12-bit result will be present in the upper part of the result register. (LEFTADJ)
+// adc_arch_leftadj
+#ifndef CONF_ADC_0_LEFTADJ
+#define CONF_ADC_0_LEFTADJ 0
+#endif
+
+// Reference Buffer Offset Compensation Enable
+// The accuracy of the gain stage can be increased by enabling the reference buffer offset compensation. This will decrease the input impedance and thus increase the start-up time of the reference. (REFCOMP)
+// adc_arch_refcomp
+#ifndef CONF_ADC_0_REFCOMP
+#define CONF_ADC_0_REFCOMP 0
+#endif
+
+// Digital Correction Logic Enabled
+// When enabled, the ADC conversion result in the RESULT register is then corrected for gain and offset based on the values in the GAINCAL and OFFSETCAL registers. (CORREN)
+// adc_arch_corren
+#ifndef CONF_ADC_0_CORREN
+#define CONF_ADC_0_CORREN 0
+#endif
+
+// Offset Correction Value <0-4095>
+// If the digital correction logic is enabled (CTRLB.CORREN = 1), these bits define how the ADC conversion result is compensated for offset error before being written to the Result register. (OFFSETCORR)
+// adc_arch_offsetcorr
+#ifndef CONF_ADC_0_OFFSETCORR
+#define CONF_ADC_0_OFFSETCORR 0
+#endif
+
+// Gain Correction Value <0-4095>
+// If the digital correction logic is enabled (CTRLB.CORREN = 1), these bits define how the ADC conversion result is compensated for gain error before being written to the result register. (GAINCORR)
+// adc_arch_gaincorr
+#ifndef CONF_ADC_0_GAINCORR
+#define CONF_ADC_0_GAINCORR 0
+#endif
+
+// Gain Factor Selection
+// <0x0=>1x
+// <0x1=>2x
+// <0x2=>4x
+// <0x3=>8x
+// <0x4=>16x
+// <0xF=>1/2x
+// These bits set the gain factor of the ADC gain stage. (GAIN)
+// adc_arch_gain
+#ifndef CONF_ADC_0_GAIN
+#define CONF_ADC_0_GAIN 0x0
+#endif
+
+// Adjusting Result / Division Coefficient <0-7>
+// These bits define the division coefficient in 2n steps. (ADJRES)
+// adc_arch_adjres
+#ifndef CONF_ADC_0_ADJRES
+#define CONF_ADC_0_ADJRES 0x0
+#endif
+
+// Number of Samples to be Collected
+// <0x0=>1 sample
+// <0x1=>2 samples
+// <0x2=>4 samples
+// <0x3=>8 samples
+// <0x4=>16 samples
+// <0x5=>32 samples
+// <0x6=>64 samples
+// <0x7=>128 samples
+// <0x8=>256 samples
+// <0x9=>512 samples
+// <0xA=>1024 samples
+// Define how many samples should be added together.The result will be available in the Result register (SAMPLENUM)
+// adc_arch_samplenum
+#ifndef CONF_ADC_0_SAMPLENUM
+#define CONF_ADC_0_SAMPLENUM 0x0
+#endif
+
+// Sampling Time Length <0-63>
+// These bits control the ADC sampling time in number of half CLK_ADC cycles, depending of the prescaler value, thus controlling the ADC input impedance. (SAMPLEN)
+// adc_arch_samplen
+#ifndef CONF_ADC_0_SAMPLEN
+#define CONF_ADC_0_SAMPLEN 0
+#endif
+
+// Window Monitor Mode
+// <0x0=>No window mode
+// <0x1=>Mode 1: RESULT above lower threshold
+// <0x2=>Mode 2: RESULT beneath upper threshold
+// <0x3=>Mode 3: RESULT inside lower and upper threshold
+// <0x4=>Mode 4: RESULT outside lower and upper threshold
+// These bits enable and define the window monitor mode. (WINMODE)
+// adc_arch_winmode
+#ifndef CONF_ADC_0_WINMODE
+#define CONF_ADC_0_WINMODE 0x0
+#endif
+
+// Window Monitor Lower Threshold <0-65535>
+// If the window monitor is enabled, these bits define the lower threshold value. (WINLT)
+// adc_arch_winlt
+#ifndef CONF_ADC_0_WINLT
+#define CONF_ADC_0_WINLT 0
+#endif
+
+// Window Monitor Upper Threshold <0-65535>
+// If the window monitor is enabled, these bits define the lower threshold value. (WINUT)
+// adc_arch_winut
+#ifndef CONF_ADC_0_WINUT
+#define CONF_ADC_0_WINUT 0
+#endif
+
+// Number of Input Channels Included in Scan <0-15>
+// This register gives the number of input sources included in pin scan. The number of input sources included is INPUTSCAN + 1. 0 disables the input scan feature. (INPUTSCAN)
+// adc_arch_inputscan
+#ifndef CONF_ADC_0_INPUTSCAN
+#define CONF_ADC_0_INPUTSCAN 0
+#endif
+
+// Positive Mux Setting Offset <0-15>
+// When inputscan is enabled this value define the pin offset, which means that the actual input pin sampled is the muxpos pin + input offset. (INPUTOFFSET)
+// adc_arch_inputoffset
+#ifndef CONF_ADC_0_INPUTOFFSET
+#define CONF_ADC_0_INPUTOFFSET 0
+#endif
+
+//
+
+// Event Control
+// adc_arch_event_settings
+#ifndef CONF_ADC_0_EVENT_CONFIG
+#define CONF_ADC_0_EVENT_CONFIG 0
+#endif
+
+// Window Monitor Event Out
+// Enables event output on window event (WINMONEO)
+// adc_arch_winmoneo
+#ifndef CONF_ADC_0_WINMONEO
+#define CONF_ADC_0_WINMONEO 0
+#endif
+
+// Result Ready Event Out
+// Enables event output on result ready event (RESRDEO)
+// adc_arch_resrdyeo
+#ifndef CONF_ADC_0_RESRDYEO
+#define CONF_ADC_0_RESRDYEO 0
+#endif
+
+// Trigger Synchronization On Event
+// Trigger a flush operation and a new conversion on event in (SYNCEI)
+// adc_arch_syncei
+#ifndef CONF_ADC_0_SYNCEI
+#define CONF_ADC_0_SYNCEI 0
+#endif
+
+// Trigger Conversion On Event
+// Trigger a conversion on event. (STARTEI)
+// adc_arch_startei
+#ifndef CONF_ADC_0_STARTEI
+#define CONF_ADC_0_STARTEI 0
+#endif
+
+//
+
+// <<< end of configuration section >>>
+
+#endif // HPL_ADC_CONFIG_H
diff --git a/ports/atmel-samd/asf4_conf/samd21/hpl_dac_config.h b/ports/atmel-samd/asf4_conf/samd21/hpl_dac_config.h
new file mode 100644
index 0000000000..42b893a359
--- /dev/null
+++ b/ports/atmel-samd/asf4_conf/samd21/hpl_dac_config.h
@@ -0,0 +1,86 @@
+/* Auto-generated config file hpl_dac_config.h */
+#ifndef HPL_DAC_CONFIG_H
+#define HPL_DAC_CONFIG_H
+
+// <<< Use Configuration Wizard in Context Menu >>>
+
+// Basic configuration
+// Reference Selection
+// <0x00=> Internal 1.0v reference
+// <0x01=> AVCC
+// <0x02=> External reference
+// dac_arch_refsel
+#ifndef CONF_DAC_REFSEL
+#define CONF_DAC_REFSEL 1
+#endif
+//
+
+// Advanced Configuration
+// dac_advanced_settings
+#ifndef CONF_DAC_ADVANCED_CONFIG
+#define CONF_DAC_ADVANCED_CONFIG 0
+#endif
+
+// Run in standby
+// Indicates whether the DAC will continue running in standby sleep mode or not
+// dac_arch_runstdby
+#ifndef CONF_DAC_RUNSTDBY
+#define CONF_DAC_RUNSTDBY 0
+#endif
+
+// Bypass DATABUF Write Protection
+// Indicate whether DATABUF write protection is bypass
+// dac_arch_bdwp
+#ifndef CONF_DAC_BDWP
+#define CONF_DAC_BDWP 0
+#endif
+
+// Voltage Pump Disable
+// Indicate whether voltage pump is disable or not
+// dac_arch_vpd
+#ifndef CONF_DAC_VPD
+#define CONF_DAC_VPD 0
+#endif
+
+// Left Adjusted Data
+// Indicate how the data is adjusted in the Data and Data Buffer register
+// dac_arch_leftadj
+#ifndef CONF_DAC_LEFTADJ
+#define CONF_DAC_LEFTADJ 1
+#endif
+
+// Internal Output Enable
+// Indicate whether internal output is enable or not
+// dac_arch_ioen
+#ifndef CONF_DAC_IOEN
+#define CONF_DAC_IOEN 0
+#endif
+
+// External Output Enable
+// Indicate whether external output is enable or not
+// dac_arch_eoen
+#ifndef CONF_DAC_EOEN
+#define CONF_DAC_EOEN 1
+#endif
+
+//
+
+// Event configuration
+// Data Buffer Empty Event Output
+// Indicate whether Data Buffer Empty Event is enabled and generated when the Data Buffer register is empty or not
+// dac_arch_emptyeo
+#ifndef CONF_DAC_EMPTYEO
+#define CONF_DAC_EMPTYEO 0
+#endif
+
+// Start Conversion on Event Input
+// Indicate whether Start Conversion is enabled and data are loaded from the Data Buffer register to the Data register upon event reception or not
+// dac_arch_startei
+#ifndef CONF_DAC_STARTEI
+#define CONF_DAC_STARTEI 0
+#endif
+//
+
+// <<< end of configuration section >>>
+
+#endif // HPL_DAC_CONFIG_H
diff --git a/ports/atmel-samd/asf4_conf/samd51/hpl_adc_config.h b/ports/atmel-samd/asf4_conf/samd51/hpl_adc_config.h
new file mode 100644
index 0000000000..13d8151028
--- /dev/null
+++ b/ports/atmel-samd/asf4_conf/samd51/hpl_adc_config.h
@@ -0,0 +1,303 @@
+/* Auto-generated config file hpl_adc_config.h */
+#ifndef HPL_ADC_CONFIG_H
+#define HPL_ADC_CONFIG_H
+
+// <<< Use Configuration Wizard in Context Menu >>>
+
+#ifndef CONF_ADC_0_ENABLE
+#define CONF_ADC_0_ENABLE 1
+#endif
+
+// Basic Configuration
+
+// Conversion Result Resolution
+// <0x0=>12-bit
+// <0x1=>16-bit (averaging must be enabled)
+// <0x2=>10-bit
+// <0x3=>8-bit
+// Defines the bit resolution for the ADC sample values (RESSEL)
+// adc_resolution
+#ifndef CONF_ADC_0_RESSEL
+#define CONF_ADC_0_RESSEL 0x0
+#endif
+
+// Reference Selection
+// <0x0=>Internal bandgap reference
+// <0x2=>1/2 VDDANA (only for VDDANA > 2.0V)
+// <0x3=>VDDANA
+// <0x4=>External reference A
+// <0x5=>External reference B
+// <0x6=>External reference C
+// Select the reference for the ADC (REFSEL)
+// adc_reference
+#ifndef CONF_ADC_0_REFSEL
+#define CONF_ADC_0_REFSEL 0x0
+#endif
+
+// Prescaler configuration
+// <0x0=>Peripheral clock divided by 2
+// <0x1=>Peripheral clock divided by 4
+// <0x2=>Peripheral clock divided by 8
+// <0x3=>Peripheral clock divided by 16
+// <0x4=>Peripheral clock divided by 32
+// <0x5=>Peripheral clock divided by 64
+// <0x6=>Peripheral clock divided by 128
+// <0x7=>Peripheral clock divided by 256
+// These bits define the ADC clock relative to the peripheral clock (PRESCALER)
+// adc_prescaler
+#ifndef CONF_ADC_0_PRESCALER
+#define CONF_ADC_0_PRESCALER 0x3
+#endif
+
+// Free Running Mode
+// When enabled, the ADC is in free running mode and a new conversion will be initiated when a previous conversion completes. (FREERUN)
+// adc_freerunning_mode
+#ifndef CONF_ADC_0_FREERUN
+#define CONF_ADC_0_FREERUN 0
+#endif
+
+// Differential Mode
+// In differential mode, the voltage difference between the MUXPOS and MUXNEG inputs will be converted by the ADC. (DIFFMODE)
+// adc_differential_mode
+#ifndef CONF_ADC_0_DIFFMODE
+#define CONF_ADC_0_DIFFMODE 0
+#endif
+
+// Positive Mux Input Selection
+// <0x00=>ADC AIN0 pin
+// <0x01=>ADC AIN1 pin
+// <0x02=>ADC AIN2 pin
+// <0x03=>ADC AIN3 pin
+// <0x04=>ADC AIN4 pin
+// <0x05=>ADC AIN5 pin
+// <0x06=>ADC AIN6 pin
+// <0x07=>ADC AIN7 pin
+// <0x08=>ADC AIN8 pin
+// <0x09=>ADC AIN9 pin
+// <0x0A=>ADC AIN10 pin
+// <0x0B=>ADC AIN11 pin
+// <0x0C=>ADC AIN12 pin
+// <0x0D=>ADC AIN13 pin
+// <0x0E=>ADC AIN14 pin
+// <0x0F=>ADC AIN15 pin
+// <0x18=>1/4 scaled core supply
+// <0x19=>1/4 Scaled VBAT Supply
+// <0x1A=>1/4 scaled I/O supply
+// <0x1B=>Bandgap voltage
+// <0x1C=>Temperature reference (PTAT)
+// <0x1D=>Temperature reference (CTAT)
+// <0x1E=>DAC Output
+// These bits define the Mux selection for the positive ADC input. (MUXPOS)
+// adc_pinmux_positive
+#ifndef CONF_ADC_0_MUXPOS
+#define CONF_ADC_0_MUXPOS 0x0
+#endif
+
+// Negative Mux Input Selection
+// <0x00=>ADC AIN0 pin
+// <0x01=>ADC AIN1 pin
+// <0x02=>ADC AIN2 pin
+// <0x03=>ADC AIN3 pin
+// <0x04=>ADC AIN4 pin
+// <0x05=>ADC AIN5 pin
+// <0x06=>ADC AIN6 pin
+// <0x07=>ADC AIN7 pin
+// <0x18=>Internal ground
+// <0x19=>I/O ground
+// These bits define the Mux selection for the negative ADC input. (MUXNEG)
+// adc_pinmux_negative
+#ifndef CONF_ADC_0_MUXNEG
+#define CONF_ADC_0_MUXNEG 0x0
+#endif
+
+//
+
+// Advanced Configuration
+// adc_advanced_settings
+#ifndef CONF_ADC_0_ADVANCED
+#define CONF_ADC_0_ADVANCED 0
+#endif
+
+// Run in standby
+// Indicates whether the ADC will continue running in standby sleep mode or not (RUNSTDBY)
+// adc_arch_runstdby
+#ifndef CONF_ADC_0_RUNSTDBY
+#define CONF_ADC_0_RUNSTDBY 0
+#endif
+
+// Debug Run
+// If enabled, the ADC is running if the CPU is halted by an external debugger. (DBGRUN)
+// adc_arch_dbgrun
+#ifndef CONF_ADC_0_DBGRUN
+#define CONF_ADC_0_DBGRUN 0
+#endif
+
+// On Demand Control
+// Will keep the ADC peripheral running if requested by other peripherals (ONDEMAND)
+// adc_arch_ondemand
+#ifndef CONF_ADC_0_ONDEMAND
+#define CONF_ADC_0_ONDEMAND 0
+#endif
+
+// Left-Adjusted Result
+// When enabled, the ADC conversion result is left-adjusted in the RESULT register. The high byte of the 12-bit result will be present in the upper part of the result register. (LEFTADJ)
+// adc_arch_leftadj
+#ifndef CONF_ADC_0_LEFTADJ
+#define CONF_ADC_0_LEFTADJ 0
+#endif
+
+// Reference Buffer Offset Compensation Enable
+// The accuracy of the gain stage can be increased by enabling the reference buffer offset compensation. This will decrease the input impedance and thus increase the start-up time of the reference. (REFCOMP)
+// adc_arch_refcomp
+#ifndef CONF_ADC_0_REFCOMP
+#define CONF_ADC_0_REFCOMP 0
+#endif
+
+// Comparator Offset Compensation Enable
+// This bit indicates whether the Comparator Offset Compensation is enabled or not (OFFCOMP)
+// adc_arch_offcomp
+#ifndef CONF_ADC_0_OFFCOMP
+#define CONF_ADC_0_OFFCOMP 0
+#endif
+
+// Digital Correction Logic Enabled
+// When enabled, the ADC conversion result in the RESULT register is then corrected for gain and offset based on the values in the GAINCAL and OFFSETCAL registers. (CORREN)
+// adc_arch_corren
+#ifndef CONF_ADC_0_CORREN
+#define CONF_ADC_0_CORREN 0
+#endif
+
+// Offset Correction Value <0-4095>
+// If the digital correction logic is enabled (CTRLB.CORREN = 1), these bits define how the ADC conversion result is compensated for offset error before being written to the Result register. (OFFSETCORR)
+// adc_arch_offsetcorr
+#ifndef CONF_ADC_0_OFFSETCORR
+#define CONF_ADC_0_OFFSETCORR 0
+#endif
+
+// Gain Correction Value <0-4095>
+// If the digital correction logic is enabled (CTRLB.CORREN = 1), these bits define how the ADC conversion result is compensated for gain error before being written to the result register. (GAINCORR)
+// adc_arch_gaincorr
+#ifndef CONF_ADC_0_GAINCORR
+#define CONF_ADC_0_GAINCORR 0
+#endif
+
+// Adjusting Result / Division Coefficient <0-7>
+// These bits define the division coefficient in 2n steps. (ADJRES)
+// adc_arch_adjres
+#ifndef CONF_ADC_0_ADJRES
+#define CONF_ADC_0_ADJRES 0x0
+#endif
+
+// Number of Samples to be Collected
+// <0x0=>1 sample
+// <0x1=>2 samples
+// <0x2=>4 samples
+// <0x3=>8 samples
+// <0x4=>16 samples
+// <0x5=>32 samples
+// <0x6=>64 samples
+// <0x7=>128 samples
+// <0x8=>256 samples
+// <0x9=>512 samples
+// <0xA=>1024 samples
+// Define how many samples should be added together.The result will be available in the Result register (SAMPLENUM)
+// adc_arch_samplenum
+#ifndef CONF_ADC_0_SAMPLENUM
+#define CONF_ADC_0_SAMPLENUM 0x0
+#endif
+
+// Sampling Time Length <0-63>
+// These bits control the ADC sampling time in number of half CLK_ADC cycles, depending of the prescaler value, thus controlling the ADC input impedance. (SAMPLEN)
+// adc_arch_samplen
+#ifndef CONF_ADC_0_SAMPLEN
+#define CONF_ADC_0_SAMPLEN 0
+#endif
+
+// Window Monitor Mode
+// <0x0=>No window mode
+// <0x1=>Mode 1: RESULT above lower threshold
+// <0x2=>Mode 2: RESULT beneath upper threshold
+// <0x3=>Mode 3: RESULT inside lower and upper threshold
+// <0x4=>Mode 4: RESULT outside lower and upper threshold
+// These bits enable and define the window monitor mode. (WINMODE)
+// adc_arch_winmode
+#ifndef CONF_ADC_0_WINMODE
+#define CONF_ADC_0_WINMODE 0x0
+#endif
+
+// Window Monitor Lower Threshold <0-65535>
+// If the window monitor is enabled, these bits define the lower threshold value. (WINLT)
+// adc_arch_winlt
+#ifndef CONF_ADC_0_WINLT
+#define CONF_ADC_0_WINLT 0
+#endif
+
+// Window Monitor Upper Threshold <0-65535>
+// If the window monitor is enabled, these bits define the lower threshold value. (WINUT)
+// adc_arch_winut
+#ifndef CONF_ADC_0_WINUT
+#define CONF_ADC_0_WINUT 0
+#endif
+
+// Bitmask for positive input sequence <0-4294967295>
+// Use this parameter to input the bitmask for positive input sequence control (refer to datasheet for the device).
+// adc_arch_seqen
+#ifndef CONF_ADC_0_SEQEN
+#define CONF_ADC_0_SEQEN 0x0
+#endif
+
+//
+
+// Event Control
+// adc_arch_event_settings
+#ifndef CONF_ADC_0_EVENT_CONTROL
+#define CONF_ADC_0_EVENT_CONTROL 0
+#endif
+
+// Window Monitor Event Out
+// Enables event output on window event (WINMONEO)
+// adc_arch_winmoneo
+#ifndef CONF_ADC_0_WINMONEO
+#define CONF_ADC_0_WINMONEO 0
+#endif
+
+// Result Ready Event Out
+// Enables event output on result ready event (RESRDEO)
+// adc_arch_resrdyeo
+#ifndef CONF_ADC_0_RESRDYEO
+#define CONF_ADC_0_RESRDYEO 0
+#endif
+
+// Invert flush Event Signal
+// Invert the flush event input signal (FLUSHINV)
+// adc_arch_flushinv
+#ifndef CONF_ADC_0_FLUSHINV
+#define CONF_ADC_0_FLUSHINV 0
+#endif
+
+// Trigger Flush On Event
+// Trigger an ADC pipeline flush on event (FLUSHEI)
+// adc_arch_flushei
+#ifndef CONF_ADC_0_FLUSHEI
+#define CONF_ADC_0_FLUSHEI 0
+#endif
+
+// Invert Start Conversion Event Signal
+// Invert the start conversion event input signal (STARTINV)
+// adc_arch_startinv
+#ifndef CONF_ADC_0_STARTINV
+#define CONF_ADC_0_STARTINV 0
+#endif
+
+// Trigger Conversion On Event
+// Trigger a conversion on event. (STARTEI)
+// adc_arch_startei
+#ifndef CONF_ADC_0_STARTEI
+#define CONF_ADC_0_STARTEI 0
+#endif
+
+//
+
+// <<< end of configuration section >>>
+
+#endif // HPL_ADC_CONFIG_H
diff --git a/ports/atmel-samd/asf4_conf/samd51/hpl_dac_config.h b/ports/atmel-samd/asf4_conf/samd51/hpl_dac_config.h
new file mode 100644
index 0000000000..6e530941e7
--- /dev/null
+++ b/ports/atmel-samd/asf4_conf/samd51/hpl_dac_config.h
@@ -0,0 +1,169 @@
+/* Auto-generated config file hpl_dac_config.h */
+#ifndef HPL_DAC_CONFIG_H
+#define HPL_DAC_CONFIG_H
+
+// <<< Use Configuration Wizard in Context Menu >>>
+
+// Basic configuration
+// Reference Selection
+// <0x00=> Unbuffered external voltage reference
+// <0x01=> Voltage supply
+// <0x02=> Buffered external voltage reference
+// <0x03=> Internal bandgap reference
+// dac_arch_refsel
+#ifndef CONF_DAC_REFSEL
+#define CONF_DAC_REFSEL 0
+#endif
+
+// Differential mode
+// Indicates whether the differential mode is enabled or not
+// dac_arch_diff
+#ifndef CONF_DAC_DIFF
+#define CONF_DAC_DIFF 0
+#endif
+//
+
+// Advanced Configuration
+// dac_advanced_settings
+#ifndef CONF_DAC_ADVANCED_CONFIG
+#define CONF_DAC_ADVANCED_CONFIG 0
+#endif
+
+// Debug Run
+// Indicate whether running when CPU is halted
+// adc_arch_dbgrun
+#ifndef CONF_DAC_DBGRUN
+#define CONF_DAC_DBGRUN 1
+#endif
+
+// Channel 0 configuration
+// Left Adjusted Data
+// Indicate how the data is adjusted in the Data and Data Buffer register
+// dac0_arch_leftadj
+#ifndef CONF_DAC0_LEFTADJ
+#define CONF_DAC0_LEFTADJ 1
+#endif
+
+// Current control
+// <0=> GCLK_DAC <= 1.2MHz (100kSPS)
+// <1=> 1.2MHz < GCLK_DAC <= 6MHz (500kSPS)
+// <2=> 6MHz < GCLK_DAC <= 12MHz (1MSPS)
+// This defines the current in output buffer according to conversion rate
+// dac0_arch_cctrl
+#ifndef CONF_DAC0_CCTRL
+#define CONF_DAC0_CCTRL 1
+#endif
+
+// Run in standby
+// Indicates whether the DAC channel will continue running in standby sleep mode or not
+// dac0_arch_runstdby
+#ifndef CONF_DAC0_RUNSTDBY
+#define CONF_DAC0_RUNSTDBY 0
+#endif
+
+// Dithering Mode
+// Indicate whether dithering mode is enabled
+// dac0_arch_ditrher
+#ifndef CONF_DAC0_DITHER
+#define CONF_DAC0_DITHER 0
+#endif
+
+// Refresh period <0x00-0xFF>
+// This defines the refresh period. If it is 0, the refresh mode is disabled, else the refresh period is: value * 500us
+// dac0_arch_refresh
+#ifndef CONF_DAC0_REFRESH
+#define CONF_DAC0_REFRESH 0
+#endif
+//
+// Channel 1 configuration
+// Left Adjusted Data
+// Indicate how the data is adjusted in the Data and Data Buffer register
+// dac1_arch_leftadj
+#ifndef CONF_DAC1_LEFTADJ
+#define CONF_DAC1_LEFTADJ 1
+#endif
+
+// Current control
+// <0=> GCLK_DAC <= 1.2MHz (100kSPS)
+// <1=> 1.2MHz < GCLK_DAC <= 6MHz (500kSPS)
+// <2=> 6MHz < GCLK_DAC <= 12MHz (1MSPS)
+// This defines the current in output buffer according to conversion rate
+// dac1_arch_cctrl
+#ifndef CONF_DAC1_CCTRL
+#define CONF_DAC1_CCTRL 1
+#endif
+
+// Run in standby
+// Indicates whether the DAC channel will continue running in standby sleep mode or not
+// dac1_arch_runstdby
+#ifndef CONF_DAC1_RUNSTDBY
+#define CONF_DAC1_RUNSTDBY 0
+#endif
+
+// Dithering Mode
+// Indicate whether dithering mode is enabled
+// dac1_arch_ditrher
+#ifndef CONF_DAC1_DITHER
+#define CONF_DAC1_DITHER 0
+#endif
+
+// Refresh period <0x00-0xFF>
+// This defines the refresh period. If it is 0, the refresh mode is disabled, else the refresh period is: value * 500us
+// dac1_arch_refresh
+#ifndef CONF_DAC1_REFRESH
+#define CONF_DAC1_REFRESH 0
+#endif
+//
+
+// Event configuration
+// Inversion of DAC 0 event
+// <0=> Detection on rising edge pf the input event
+// <1=> Detection on falling edge pf the input event
+// This defines the edge detection of the input event
+// dac_arch_invei0
+#ifndef CONF_DAC_INVEI0
+#define CONF_DAC_INVEI0 0
+#endif
+
+// Data Buffer of DAC 0 Empty Event Output
+// Indicate whether Data Buffer Empty Event is enabled and generated when the Data Buffer register is empty or not
+// dac_arch_emptyeo_0
+#ifndef CONF_DAC_EMPTYEO0
+#define CONF_DAC_EMPTYEO0 0
+#endif
+
+// Start Conversion Event Input DAC 0
+// Indicate whether Start input event is enabled
+// dac_arch_startei_0
+#ifndef CONF_DAC_STARTEI0
+#define CONF_DAC_STARTEI0 0
+#endif
+// Inversion of DAC 1 event
+// <0=> Detection on rising edge pf the input event
+// <1=> Detection on falling edge pf the input event
+// This defines the edge detection of the input event
+// dac_arch_invei1
+#ifndef CONF_DAC_INVEI1
+#define CONF_DAC_INVEI1 0
+#endif
+
+// Data Buffer of DAC 1 Empty Event Output
+// Indicate whether Data Buffer Empty Event is enabled and generated when the Data Buffer register is empty or not
+// dac_arch_emptyeo_1
+#ifndef CONF_DAC_EMPTYEO1
+#define CONF_DAC_EMPTYEO1 0
+#endif
+
+// Start Conversion Event Input DAC 1
+// Indicate whether Start input event is enabled
+// dac_arch_startei_1
+#ifndef CONF_DAC_STARTEI1
+#define CONF_DAC_STARTEI1 0
+#endif
+
+//
+//
+
+// <<< end of configuration section >>>
+
+#endif // HPL_DAC_CONFIG_H
diff --git a/ports/atmel-samd/common-hal/analogio/AnalogIn.c b/ports/atmel-samd/common-hal/analogio/AnalogIn.c
index cbb9f5de51..c27d17f558 100644
--- a/ports/atmel-samd/common-hal/analogio/AnalogIn.c
+++ b/ports/atmel-samd/common-hal/analogio/AnalogIn.c
@@ -33,19 +33,40 @@
#include "py/runtime.h"
#include "py/binary.h"
#include "py/mphal.h"
+
#include "shared-bindings/analogio/AnalogIn.h"
-#include "asf/sam0/drivers/adc/adc.h"
-#include "samd21_pins.h"
+#include "atmel_start_pins.h"
+#include "hal/include/hal_adc_sync.h"
+#include "hpl/gclk/hpl_gclk_base.h"
+
+#ifdef SAMD21
+#include "hpl/pm/hpl_pm_base.h"
+#endif
void common_hal_analogio_analogin_construct(analogio_analogin_obj_t* self,
const mcu_pin_obj_t *pin) {
- if (!pin->has_adc) {
+ uint8_t adc_index;
+ uint8_t adc_channel = 0xff;
+ for (adc_index = 0; adc_index < NUM_ADC_PER_PIN; adc_index++) {
+ // TODO(tannewt): Only use ADC0 on the SAMD51 when touch isn't being
+ // used.
+ if (pin->adc_input[adc_index] != 0xff) {
+ adc_channel = pin->adc_input[adc_index];
+ break;
+ }
+ }
+ if (adc_channel == 0xff) {
// No ADC function on that pin
mp_raise_ValueError("Pin does not have ADC capabilities");
}
claim_pin(pin);
+ gpio_set_pin_function(pin->pin, GPIO_PIN_FUNCTION_B);
+
+ static Adc* adc_insts[] = ADC_INSTS;
+ self->instance = adc_insts[adc_index];
+ self->channel = adc_channel;
self->pin = pin;
}
@@ -68,21 +89,62 @@ uint16_t common_hal_analogio_analogin_get_value(analogio_analogin_obj_t *self) {
// Something else might have used the ADC in a different way,
// so we completely re-initialize it.
- struct adc_config config_adc;
- adc_get_config_defaults(&config_adc);
+ // Turn the clocks on.
+ #ifdef SAMD51
+ if (self->instance == ADC0) {
+ hri_mclk_set_APBDMASK_ADC0_bit(MCLK);
+ hri_gclk_write_PCHCTRL_reg(GCLK, ADC0_GCLK_ID, GCLK_PCHCTRL_GEN_GCLK1_Val | (1 << GCLK_PCHCTRL_CHEN_Pos));
+ } else if (self->instance == ADC1) {
+ hri_mclk_set_APBDMASK_ADC1_bit(MCLK);
+ hri_gclk_write_PCHCTRL_reg(GCLK, ADC1_GCLK_ID, GCLK_PCHCTRL_GEN_GCLK1_Val | (1 << GCLK_PCHCTRL_CHEN_Pos));
+ }
+ #endif
- config_adc.reference = ADC_REFERENCE_INTVCC1;
- config_adc.gain_factor = ADC_GAIN_FACTOR_DIV2;
- config_adc.positive_input = self->pin->adc_input;
- config_adc.resolution = ADC_RESOLUTION_12BIT;
- // Default input clock is GCLK0 (48 MHz)
- // 48Mhz / 32 = 1.5MHz. Max ADC clock is 2.1MHz
- config_adc.clock_prescaler = ADC_CLOCK_PRESCALER_DIV32;
+ #ifdef SAMD21
+ _pm_enable_bus_clock(PM_BUS_APBC, ADC);
+ _gclk_enable_channel(ADC_GCLK_ID, GCLK_CLKCTRL_GEN_GCLK0_Val);
+ #endif
- struct adc_module adc_instance;
- // ADC must have been disabled before adc_init() is called.
- adc_init(&adc_instance, ADC, &config_adc);
- adc_enable(&adc_instance);
+ struct adc_sync_descriptor adc;
+ adc_sync_init(&adc, self->instance, (void *)NULL);
+ adc_sync_set_reference(&adc, ADC_REFCTRL_REFSEL_INTVCC1_Val);
+ adc_sync_set_resolution(&adc, ADC_CTRLB_RESSEL_12BIT_Val);
+
+ #ifdef SAMD21
+ adc_sync_set_channel_gain(&adc, self->channel, ADC_INPUTCTRL_GAIN_DIV2_Val);
+
+ // Load the factory calibration
+ hri_adc_set_CALIB_BIAS_CAL_bf(ADC, (*((uint32_t*) ADC_FUSES_BIASCAL_ADDR) & ADC_FUSES_BIASCAL_Msk) >> ADC_FUSES_BIASCAL_Pos);
+ // Bits 7:5
+ uint16_t linearity = ((*((uint32_t*) ADC_FUSES_LINEARITY_1_ADDR) & ADC_FUSES_LINEARITY_1_Msk) >> ADC_FUSES_LINEARITY_1_Pos) << 5;
+ // Bits 4:0
+ linearity |= (*((uint32_t*) ADC_FUSES_LINEARITY_0_ADDR) & ADC_FUSES_LINEARITY_0_Msk) >> ADC_FUSES_LINEARITY_0_Pos;
+ hri_adc_set_CALIB_LINEARITY_CAL_bf(ADC, linearity);
+ #endif
+
+ // SAMD51 has a CALIB register but doesn't have documented fuses for them.
+ #ifdef SAMD51
+ uint8_t biasrefbuf;
+ uint8_t biasr2r;
+ uint8_t biascomp;
+ if (self->instance == ADC0) {
+ biasrefbuf = ((*(uint32_t*) ADC0_FUSES_BIASREFBUF_ADDR) & ADC0_FUSES_BIASREFBUF_Msk) >> ADC0_FUSES_BIASREFBUF_Pos;
+ biasr2r = ((*(uint32_t*) ADC0_FUSES_BIASR2R_ADDR) & ADC0_FUSES_BIASR2R_Msk) >> ADC0_FUSES_BIASR2R_Pos;
+ biascomp = ((*(uint32_t*) ADC0_FUSES_BIASCOMP_ADDR) & ADC0_FUSES_BIASCOMP_Msk) >> ADC0_FUSES_BIASCOMP_Pos;
+ } else {
+ biasrefbuf = ((*(uint32_t*) ADC1_FUSES_BIASREFBUF_ADDR) & ADC1_FUSES_BIASREFBUF_Msk) >> ADC1_FUSES_BIASREFBUF_Pos;
+ biasr2r = ((*(uint32_t*) ADC1_FUSES_BIASR2R_ADDR) & ADC1_FUSES_BIASR2R_Msk) >> ADC1_FUSES_BIASR2R_Pos;
+ biascomp = ((*(uint32_t*) ADC1_FUSES_BIASCOMP_ADDR) & ADC1_FUSES_BIASCOMP_Msk) >> ADC1_FUSES_BIASCOMP_Pos;
+ }
+ hri_adc_set_CALIB_BIASREFBUF_bf(self->instance, biasrefbuf);
+ hri_adc_set_CALIB_BIASR2R_bf(self->instance, biasr2r);
+ hri_adc_set_CALIB_BIASCOMP_bf(self->instance, biascomp);
+ #endif
+
+ adc_sync_enable_channel(&adc, self->channel);
+
+ // We need to set the inputs because the above channel enable only enables the ADC.
+ adc_sync_set_inputs(&adc, self->channel, ADC_INPUTCTRL_MUXNEG_GND_Val, self->channel);
// Read twice and discard first result, as recommended in section 14 of
// http://www.atmel.com/images/Atmel-42645-ADC-Configurations-with-Examples_ApplicationNote_AT11481.pdf
@@ -90,28 +152,13 @@ uint16_t common_hal_analogio_analogin_get_value(analogio_analogin_obj_t *self) {
// like voltage reference / ADC channel change"
// Empirical observation shows the first reading is quite different than subsequent ones.
- uint16_t data;
- enum status_code status;
+ uint16_t value;
+ adc_sync_read_channel(&adc, self->channel, ((uint8_t*) &value), 2);
+ adc_sync_read_channel(&adc, self->channel, ((uint8_t*) &value), 2);
- adc_start_conversion(&adc_instance);
- do {
- status = adc_read(&adc_instance, &data);
- } while (status == STATUS_BUSY);
- if (status == STATUS_ERR_OVERFLOW) {
- mp_raise_RuntimeError("ADC result overwritten before reading");
- }
-
- adc_start_conversion(&adc_instance);
- do {
- status = adc_read(&adc_instance, &data);
- } while (status == STATUS_BUSY);
- if (status == STATUS_ERR_OVERFLOW) {
- mp_raise_RuntimeError("ADC result overwritten before reading");
- }
-
- adc_disable(&adc_instance);
- // Scale to 16 bits. In the future we might make this be this be under API control.
- return data * 16;
+ adc_sync_deinit(&adc);
+ // Shift the value to be 16 bit.
+ return value << 4;
}
float common_hal_analogio_analogin_get_reference_voltage(analogio_analogin_obj_t *self) {
diff --git a/ports/atmel-samd/common-hal/analogio/AnalogIn.h b/ports/atmel-samd/common-hal/analogio/AnalogIn.h
index 36fb14a92c..0b13ba7e14 100644
--- a/ports/atmel-samd/common-hal/analogio/AnalogIn.h
+++ b/ports/atmel-samd/common-hal/analogio/AnalogIn.h
@@ -34,6 +34,8 @@
typedef struct {
mp_obj_base_t base;
const mcu_pin_obj_t * pin;
+ Adc* instance;
+ uint8_t channel;
} analogio_analogin_obj_t;
void analogin_reset(void);
diff --git a/ports/atmel-samd/common-hal/analogio/AnalogOut.c b/ports/atmel-samd/common-hal/analogio/AnalogOut.c
index d547873918..1d53781b16 100644
--- a/ports/atmel-samd/common-hal/analogio/AnalogOut.c
+++ b/ports/atmel-samd/common-hal/analogio/AnalogOut.c
@@ -31,32 +31,72 @@
#include "py/runtime.h"
#include "shared-bindings/analogio/AnalogOut.h"
+#include "shared-bindings/microcontroller/Pin.h"
-#include "asf/sam0/drivers/dac/dac.h"
-#include "samd21_pins.h"
+#include "atmel_start_pins.h"
+#include "hal/include/hal_dac_sync.h"
+#include "hpl/gclk/hpl_gclk_base.h"
+
+#ifdef SAMD21
+#include "hpl/pm/hpl_pm_base.h"
+#endif
+
+#ifdef SAMD51
+#include "samd51_pins.h"
+#endif
void common_hal_analogio_analogout_construct(analogio_analogout_obj_t* self,
const mcu_pin_obj_t *pin) {
- if (pin->pin != PIN_PA02) {
+ if (pin->pin != PIN_PA02
+ #ifdef SAMD51
+ && pin->pin != PIN_PA05
+ #endif
+ ) {
mp_raise_ValueError("AnalogOut not supported on given pin");
return;
}
- struct dac_config config_dac;
- dac_get_config_defaults(&config_dac);
- config_dac.reference = DAC_REFERENCE_AVCC;
- enum status_code status = dac_init(&self->dac_instance, DAC, &config_dac);
- if (status != STATUS_OK) {
+
+ self->channel = 0;
+ #ifdef SAMD51
+ if (pin->pin == PIN_PA05) {
+ self->channel = 1;
+ }
+ #endif
+
+ #ifdef SAMD51
+ hri_mclk_set_APBDMASK_DAC_bit(MCLK);
+ hri_gclk_write_PCHCTRL_reg(GCLK, DAC_GCLK_ID, GCLK_PCHCTRL_GEN_GCLK5_Val | (1 << GCLK_PCHCTRL_CHEN_Pos));
+ #endif
+
+ #ifdef SAMD21
+ _pm_enable_bus_clock(PM_BUS_APBC, DAC);
+ _gclk_enable_channel(DAC_GCLK_ID, GCLK_CLKCTRL_GEN_GCLK0_Val);
+ #endif
+
+ // Don't double init the DAC on the SAMD51 when both outputs are in use. We use the free state
+ // of each output pin to determine DAC state.
+ int32_t result = ERR_NONE;
+ #ifdef SAMD51
+ if (!common_hal_mcu_pin_is_free(&pin_PA02) || !common_hal_mcu_pin_is_free(&pin_PA05)) {
+ #endif
+ // Fake the descriptor if the DAC is already initialized.
+ self->descriptor.device.hw = DAC;
+ #ifdef SAMD51
+ } else {
+ #endif
+ result = dac_sync_init(&self->descriptor, DAC);
+ #ifdef SAMD51
+ }
+ #endif
+ if (result != ERR_NONE) {
mp_raise_OSError(MP_EIO);
return;
}
claim_pin(pin);
- struct dac_chan_config config_analogout_chan;
- dac_chan_get_config_defaults(&config_analogout_chan);
- dac_chan_set_config(&self->dac_instance, DAC_CHANNEL_0, &config_analogout_chan);
- dac_chan_enable(&self->dac_instance, DAC_CHANNEL_0);
+ gpio_set_pin_function(pin->pin, GPIO_PIN_FUNCTION_B);
- dac_enable(&self->dac_instance);
+ dac_sync_enable_channel(&self->descriptor, self->channel);
}
bool common_hal_analogio_analogout_deinited(analogio_analogout_obj_t *self) {
@@ -67,14 +107,35 @@ void common_hal_analogio_analogout_deinit(analogio_analogout_obj_t *self) {
if (common_hal_analogio_analogout_deinited(self)) {
return;
}
- dac_disable(&self->dac_instance);
- dac_chan_disable(&self->dac_instance, DAC_CHANNEL_0);
+ dac_sync_disable_channel(&self->descriptor, self->channel);
reset_pin(PIN_PA02);
+ // Only deinit the DAC on the SAMD51 if both outputs are free.
+ #ifdef SAMD51
+ if (common_hal_mcu_pin_is_free(&pin_PA02) && common_hal_mcu_pin_is_free(&pin_PA05)) {
+ #endif
+ dac_sync_deinit(&self->descriptor);
+ #ifdef SAMD51
+ }
+ #endif
self->deinited = true;
+ // TODO(tannewt): Turn off the DAC clocks to save power.
}
void common_hal_analogio_analogout_set_value(analogio_analogout_obj_t *self,
uint16_t value) {
- // Input is 16 bit but we only support 10 bit so we shift the input.
- dac_chan_write(&self->dac_instance, DAC_CHANNEL_0, value >> 6);
+ // Input is 16 bit so make sure and set LEFTADJ to 1 to it takes the top
+ // bits. This is currently done in asf4_conf/*/hpl_dac_config.h.
+ dac_sync_write(&self->descriptor, self->channel, &value, 1);
+}
+
+void analogout_reset(void) {
+ #ifdef SAMD21
+ while (DAC->STATUS.reg & DAC_STATUS_SYNCBUSY) {}
+ #endif
+ #ifdef SAMD51
+ while (DAC->SYNCBUSY.reg & DAC_SYNCBUSY_SWRST) {}
+ #endif
+ DAC->CTRLA.reg |= DAC_CTRLA_SWRST;
+
+ // TODO(tannewt): Turn off the DAC clocks to save power.
}
diff --git a/ports/atmel-samd/common-hal/analogio/AnalogOut.h b/ports/atmel-samd/common-hal/analogio/AnalogOut.h
index b60658da69..3710a7211a 100644
--- a/ports/atmel-samd/common-hal/analogio/AnalogOut.h
+++ b/ports/atmel-samd/common-hal/analogio/AnalogOut.h
@@ -29,14 +29,17 @@
#include "common-hal/microcontroller/Pin.h"
-#include "asf/sam0/drivers/dac/dac.h"
+#include "hal/include/hal_dac_sync.h"
#include "py/obj.h"
typedef struct {
mp_obj_base_t base;
- struct dac_module dac_instance;
+ struct dac_sync_descriptor descriptor;
+ uint8_t channel;
bool deinited;
} analogio_analogout_obj_t;
+void analogout_reset(void);
+
#endif // MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_ANALOGIO_ANALOGOUT_H
diff --git a/ports/atmel-samd/mpconfigport.h b/ports/atmel-samd/mpconfigport.h
index 2c8a66a88f..a78210a566 100644
--- a/ports/atmel-samd/mpconfigport.h
+++ b/ports/atmel-samd/mpconfigport.h
@@ -212,14 +212,13 @@ extern const struct _mp_obj_module_t usb_hid_module;
// Disabled for now.
// { MP_OBJ_NEW_QSTR(MP_QSTR_touchio), (mp_obj_t)&touchio_module },
-// { MP_OBJ_NEW_QSTR(MP_QSTR_analogio), (mp_obj_t)&analogio_module },
-
// { MP_OBJ_NEW_QSTR(MP_QSTR_gamepad),(mp_obj_t)&gamepad_module },
// { MP_OBJ_NEW_QSTR(MP_QSTR__stage), (mp_obj_t)&stage_module },
// { MP_OBJ_NEW_QSTR(MP_QSTR_usb_hid),(mp_obj_t)&usb_hid_module },
#define MICROPY_PORT_BUILTIN_MODULES \
+ { MP_OBJ_NEW_QSTR(MP_QSTR_analogio), (mp_obj_t)&analogio_module }, \
{ MP_OBJ_NEW_QSTR(MP_QSTR_board), (mp_obj_t)&board_module }, \
{ MP_OBJ_NEW_QSTR(MP_QSTR_busio), (mp_obj_t)&busio_module }, \
{ MP_OBJ_NEW_QSTR(MP_QSTR_digitalio), (mp_obj_t)&digitalio_module }, \
diff --git a/ports/atmel-samd/supervisor/port.c b/ports/atmel-samd/supervisor/port.c
index 8c8045c001..5d483b7bf4 100644
--- a/ports/atmel-samd/supervisor/port.c
+++ b/ports/atmel-samd/supervisor/port.c
@@ -43,7 +43,8 @@
#include "hri/hri_rstc_d51.h"
#endif
-
+#include "common-hal/analogio/AnalogIn.h"
+#include "common-hal/analogio/AnalogOut.h"
#include "common-hal/microcontroller/Pin.h"
#include "tick.h"
@@ -207,16 +208,14 @@ void reset_port(void) {
// pulseout_reset();
// pwmout_reset();
// #endif
-//
-// analogin_reset();
-//
+
+ analogin_reset();
+
// #ifdef CIRCUITPY_GAMEPAD_TICKS
// gamepad_reset();
// #endif
//
-// // Wait for the DAC to sync then reset.
-// while (DAC->STATUS.reg & DAC_STATUS_SYNCBUSY) {}
-// DAC->CTRLA.reg |= DAC_CTRLA_SWRST;
+ analogout_reset();
reset_all_pins();
//
@@ -276,9 +275,9 @@ void reset_port(void) {
*/
__attribute__((used)) void HardFault_Handler(void)
{
- while (true) {
+ while (true) {
asm("");
- }
+ }
for (uint32_t i = 0; i < 100000; i++) {
asm("noop;");
}