Skip to content

Commit 70b95d8

Browse files
graeme-winterrobert-hh
authored andcommitted
samd/machine_dac: Fix SAMD51 DAC for two channels.
Improvements to DAC support for SAMD51: - properly validate DAC id - correctly use dac_init flag, as a 2-ple for A0, A1 channels - disable DAC before adjusting settings, see SAMD5x data sheet §47.6.2.3 Co-authored-by: robert-hh <[email protected]> Signed-off-by: Graeme Winter <[email protected]>
1 parent 1100aa6 commit 70b95d8

File tree

1 file changed

+36
-16
lines changed

1 file changed

+36
-16
lines changed

ports/samd/machine_dac.c

Lines changed: 36 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,8 @@ static uint8_t dac_vref_table[] = {
7272
#define MAX_DAC_VALUE (4095)
7373
#define DEFAULT_DAC_VREF (2)
7474
#define MAX_DAC_VREF (3)
75-
static bool dac_init = false;
75+
static bool dac_init[2] = {false, false};
76+
7677
#endif
7778

7879

@@ -91,20 +92,21 @@ static mp_obj_t dac_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_
9192

9293
uint8_t id = args[ARG_id].u_int;
9394
dac_obj_t *self = NULL;
94-
if (0 <= id && id <= MP_ARRAY_SIZE(dac_obj)) {
95+
if (0 <= id && id < MP_ARRAY_SIZE(dac_obj)) {
9596
self = &dac_obj[id];
9697
} else {
97-
mp_raise_ValueError(MP_ERROR_TEXT("invalid Pin for DAC"));
98+
mp_raise_ValueError(MP_ERROR_TEXT("invalid id for DAC"));
9899
}
99100

100101
uint8_t vref = args[ARG_vref].u_int;
101102
if (0 <= vref && vref <= MAX_DAC_VREF) {
102103
self->vref = vref;
103104
}
104105

105-
Dac *dac = dac_bases[0]; // Just one DAC
106+
Dac *dac = dac_bases[0]; // Just one DAC register block
107+
108+
// initialize DAC
106109

107-
// Init DAC
108110
#if defined(MCU_SAMD21)
109111

110112
// Configuration SAMD21
@@ -127,21 +129,39 @@ static mp_obj_t dac_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_
127129

128130
// Configuration SAMD51
129131
// Enable APBD clocks and PCHCTRL clocks; GCLK3 at 8 MHz
130-
dac_init = true;
131-
MCLK->APBDMASK.reg |= MCLK_APBDMASK_DAC;
132-
GCLK->PCHCTRL[DAC_GCLK_ID].reg = GCLK_PCHCTRL_GEN_GCLK3 | GCLK_PCHCTRL_CHEN;
133132

134-
// Reset DAC registers
135-
dac->CTRLA.bit.SWRST = 1;
136-
while (dac->CTRLA.bit.SWRST) {
133+
if (!(dac_init[0] | dac_init[1])) {
134+
MCLK->APBDMASK.reg |= MCLK_APBDMASK_DAC;
135+
GCLK->PCHCTRL[DAC_GCLK_ID].reg = GCLK_PCHCTRL_GEN_GCLK3 | \
136+
GCLK_PCHCTRL_CHEN;
137+
138+
// Reset DAC registers
139+
dac->CTRLA.bit.SWRST = 1;
140+
while (dac->CTRLA.bit.SWRST) {
141+
}
142+
dac->CTRLB.reg = DAC_CTRLB_REFSEL(dac_vref_table[self->vref]);
143+
137144
}
138-
dac->CTRLB.reg = DAC_CTRLB_REFSEL(dac_vref_table[self->vref]);
139-
dac->DACCTRL[self->id].reg = DAC_DACCTRL_ENABLE | DAC_DACCTRL_REFRESH(2) | DAC_DACCTRL_CCTRL_CC12M;
140145

141-
// Enable DAC and wait to be ready
142-
dac->CTRLA.bit.ENABLE = 1;
143-
while (dac->SYNCBUSY.bit.ENABLE) {
146+
// Modify DAC config - requires disabling see Section 47.6.2.3 of data sheet
147+
if (!dac_init[self->id]) {
148+
// Disable DAC and wait
149+
dac->CTRLA.bit.ENABLE = 0;
150+
while (dac->SYNCBUSY.bit.ENABLE) {
151+
}
152+
153+
// Modify configuration
154+
dac->DACCTRL[self->id].reg = DAC_DACCTRL_ENABLE | \
155+
DAC_DACCTRL_REFRESH(2) | DAC_DACCTRL_CCTRL_CC12M;
156+
dac->DATA[self->id].reg = 0;
157+
dac_init[self->id] = true;
158+
159+
// Enable DAC and wait
160+
dac->CTRLA.bit.ENABLE = 1;
161+
while (dac->SYNCBUSY.bit.ENABLE) {
162+
}
144163
}
164+
145165
#endif
146166

147167
// Set the port as given in self->gpio_id as DAC

0 commit comments

Comments
 (0)