samd/ADC_DAC: Add adc.busy() and dac.busy() methods.

These return True, while a timed action is ongoing.

Side change:
Reorder some code in machine_dac.c and do not reset DAC twice.

Signed-off-by: robert-hh <robert@hammelrath.com>
pull/9624/head
robert-hh 2022-10-14 12:18:28 +02:00
rodzic 7197c8adc0
commit 53c640c0ce
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 32EC5F755D5A3A93
2 zmienionych plików z 51 dodań i 14 usunięć

Wyświetl plik

@ -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;

Wyświetl plik

@ -31,6 +31,8 @@
#include <stdint.h>
#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) },