kopia lustrzana https://github.com/micropython/micropython
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
rodzic
7197c8adc0
commit
53c640c0ce
|
@ -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;
|
||||
|
|
|
@ -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) },
|
||||
|
|
Ładowanie…
Reference in New Issue