diff --git a/ports/samd/machine_adc.c b/ports/samd/machine_adc.c index b64d53a43f..854260927b 100644 --- a/ports/samd/machine_adc.c +++ b/ports/samd/machine_adc.c @@ -351,6 +351,7 @@ static void mp_machine_adc_deinit(machine_adc_obj_t *self) { #if defined(MCU_SAMD51) if (self->dma_channel == device_mgmt[self->adc_config.device].dma_channel) { device_mgmt[self->adc_config.device].dma_channel = -1; + device_mgmt[self->adc_config.device].busy = 0; } #endif dac_stop_dma(self->dma_channel, true); @@ -363,6 +364,12 @@ static void mp_machine_adc_deinit(machine_adc_obj_t *self) { } } +// busy() : Report, if the ADC device is busy +static mp_int_t machine_adc_busy(mp_obj_t self_in) { + machine_adc_obj_t *self = MP_OBJ_TO_PTR(self_in); + return device_mgmt[self->adc_config.device].busy ? true : false; +} + void adc_deinit_all(void) { ch_busy_flags = 0; device_mgmt[0].init = 0; diff --git a/ports/samd/machine_dac.c b/ports/samd/machine_dac.c index d350205459..a8fa4a0e8c 100644 --- a/ports/samd/machine_dac.c +++ b/ports/samd/machine_dac.c @@ -31,6 +31,8 @@ #include #include "py/obj.h" +#include "py/runtime.h" +#include "py/mperrno.h" #include "py/mphal.h" #include "sam.h" @@ -48,6 +50,7 @@ typedef struct _dac_obj_t { uint8_t vref; int8_t dma_channel; int8_t tc_index; + bool busy; uint32_t count; mp_obj_t callback; } dac_obj_t; @@ -57,19 +60,23 @@ static mp_obj_t dac_deinit(mp_obj_t self_in); #if defined(MCU_SAMD21) -static dac_obj_t dac_obj[] = { - {{&machine_dac_type}, 0, 0, PIN_PA02}, -}; - #define MAX_DAC_VALUE (1023) #define DEFAULT_DAC_VREF (1) #define MAX_DAC_VREF (2) +static dac_obj_t dac_obj[] = { + {{&machine_dac_type}, 0, 0, PIN_PA02, DEFAULT_DAC_VREF, -1, -1, false, 1, NULL}, +}; + #elif defined(MCU_SAMD51) +#define MAX_DAC_VALUE (4095) +#define DEFAULT_DAC_VREF (2) +#define MAX_DAC_VREF (3) + static dac_obj_t dac_obj[] = { - {{&machine_dac_type}, 0, 0, PIN_PA02, 2, -1, -1, 1, NULL}, - {{&machine_dac_type}, 1, 0, PIN_PA05, 2, -1, -1, 1, NULL}, + {{&machine_dac_type}, 0, 0, PIN_PA02, DEFAULT_DAC_VREF, -1, -1, false, 1, NULL}, + {{&machine_dac_type}, 1, 0, PIN_PA05, DEFAULT_DAC_VREF, -1, -1, false, 1, NULL}, }; // According to Errata 2.9.2, VDDANA as ref value is not available. However it worked // in tests. So I keep the selection here but set the default to Aref, which is usually @@ -78,9 +85,6 @@ static uint8_t dac_vref_table[] = { DAC_CTRLB_REFSEL_INTREF_Val, DAC_CTRLB_REFSEL_VDDANA_Val, DAC_CTRLB_REFSEL_VREFPU_Val, DAC_CTRLB_REFSEL_VREFPB_Val }; -#define MAX_DAC_VALUE (4095) -#define DEFAULT_DAC_VREF (2) -#define MAX_DAC_VREF (3) #endif // defined SAMD21 or SAMD51 @@ -96,6 +100,7 @@ void dac_irq_handler(int dma_channel) { dma_desc[self->dma_channel].BTCTRL.reg |= DMAC_BTCTRL_VALID; DMAC->CHCTRLA.reg |= DMAC_CHCTRLA_ENABLE; } else { + self->busy = false; if (self->callback != MP_OBJ_NULL) { mp_sched_schedule(self->callback, self); } @@ -113,6 +118,7 @@ void dac_irq_handler(int dma_channel) { dma_desc[self->dma_channel].BTCTRL.reg |= DMAC_BTCTRL_VALID; DMAC->Channel[self->dma_channel].CHCTRLA.reg |= DMAC_CHCTRLA_ENABLE; } else { + self->busy = false; if (self->callback != MP_OBJ_NULL) { mp_sched_schedule(self->callback, self); } @@ -136,10 +142,10 @@ static mp_obj_t dac_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_ uint8_t id = args[ARG_id].u_int; dac_obj_t *self = NULL; - if (0 <= id && id <= MP_ARRAY_SIZE(dac_obj)) { + if (0 <= id && id < MP_ARRAY_SIZE(dac_obj)) { self = &dac_obj[id]; } else { - mp_raise_ValueError(MP_ERROR_TEXT("invalid Pin for DAC")); + mp_raise_ValueError(MP_ERROR_TEXT("invalid DAC ID")); } uint8_t vref = args[ARG_vref].u_int; @@ -192,9 +198,18 @@ static void dac_init(dac_obj_t *self, Dac *dac) { MCLK->APBDMASK.reg |= MCLK_APBDMASK_DAC; GCLK->PCHCTRL[DAC_GCLK_ID].reg = GCLK_PCHCTRL_GEN_GCLK5 | GCLK_PCHCTRL_CHEN; - // Reset DAC registers - dac->CTRLA.bit.SWRST = 1; - while (dac->CTRLA.bit.SWRST) { + // If the DAC is enabled it was already reset + // In that case just disable it. + if (dac->CTRLA.bit.ENABLE) { + // Enable DAC and wait to be ready + dac->CTRLA.bit.ENABLE = 0; + while (dac->SYNCBUSY.bit.ENABLE) { + } + } else { + // Reset DAC registers + dac->CTRLA.bit.SWRST = 1; + while (dac->CTRLA.bit.SWRST) { + } } dac->CTRLB.reg = DAC_CTRLB_REFSEL(dac_vref_table[self->vref]); dac->DACCTRL[self->id].reg = DAC_DACCTRL_ENABLE | DAC_DACCTRL_REFRESH(2) | DAC_DACCTRL_CCTRL_CC12M; @@ -217,6 +232,10 @@ static void dac_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t static mp_obj_t dac_write(mp_obj_t self_in, mp_obj_t value_in) { Dac *dac = dac_bases[0]; // Just one DAC dac_obj_t *self = self_in; + if (self->busy != false) { + mp_raise_OSError(MP_EBUSY); + } + int value = mp_obj_get_int(value_in); if (value < 0 || value > MAX_DAC_VALUE) { @@ -259,6 +278,8 @@ static mp_obj_t dac_write_timed(size_t n_args, const mp_obj_t *args) { } // Configure TC; no need to check the return value configure_tc(self->tc_index, freq, 0); + self->busy = true; + // Configure DMA for halfword output to the DAC #if defined(MCU_SAMD21) @@ -337,10 +358,18 @@ static mp_obj_t dac_deinit(mp_obj_t self_in) { self->tc_index = -1; } self->callback = MP_OBJ_NULL; + self->busy = false; return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_1(dac_deinit_obj, dac_deinit); +// busy() : Report, if the DAC device is busy +static mp_obj_t machine_dac_busy(mp_obj_t self_in) { + dac_obj_t *self = MP_OBJ_TO_PTR(self_in); + return self->busy ? mp_const_true : mp_const_false; +} +static MP_DEFINE_CONST_FUN_OBJ_1(machine_dac_busy_obj, machine_dac_busy); + // Clear the DMA channel entry in the DAC object. void dac_deinit_channel(void) { dac_obj[0].dma_channel = -1; @@ -350,6 +379,7 @@ void dac_deinit_channel(void) { } static const mp_rom_map_elem_t dac_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_busy), MP_ROM_PTR(&machine_dac_busy_obj) }, { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&dac_deinit_obj) }, { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&dac_write_obj) }, { MP_ROM_QSTR(MP_QSTR_write_timed), MP_ROM_PTR(&dac_write_timed_obj) },