samd/ADC_DAC: Make adc.read_timed() and dac.write_timed() configurable.

Both together require ~1.9k of flash space, including the DMA-manager
and the TC-manager. adc.read_timed() uses ~700 bytes, dac.write_timed()
~600 bytes.

Signed-off-by: robert-hh <robert@hammelrath.com>
pull/9624/head
robert-hh 2023-03-25 16:41:21 +01:00
rodzic f5fd6fbe94
commit 0bc34e70ae
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 32EC5F755D5A3A93
6 zmienionych plików z 84 dodań i 11 usunięć

Wyświetl plik

@ -30,6 +30,8 @@
#include "dma_manager.h"
#include "samd_soc.h"
#if MICROPY_HW_DMA_MANAGER
// Set a number of dma channels managed here. samd21 has 21 dma channels, samd51
// has 32 channels, as defined by the lib macro DMAC_CH_NUM.
// At first, we use a smaller number here to save RAM. May be increased as needed.
@ -129,3 +131,5 @@ void dac_stop_dma(int dma_channel, bool wait) {
}
#endif
}
#endif

Wyświetl plik

@ -50,8 +50,10 @@ typedef struct _machine_adc_obj_t {
uint8_t avg;
uint8_t bits;
uint8_t vref;
#if MICROPY_PY_MACHINE_ADC_TIMED
int8_t dma_channel;
int8_t tc_index;
#endif
} machine_adc_obj_t;
#define DEFAULT_ADC_BITS 12
@ -74,9 +76,11 @@ static uint8_t adc_vref_table[] = {
typedef struct _device_mgmt_t {
bool init;
#if MICROPY_PY_MACHINE_ADC_TIMED
bool busy;
mp_obj_t callback;
mp_obj_t self;
#endif
} device_mgmt_t;
device_mgmt_t device_mgmt[ADC_INST_NUM];
@ -103,10 +107,7 @@ typedef struct _device_mgmt_t {
mp_obj_t self;
} device_mgmt_t;
device_mgmt_t device_mgmt[ADC_INST_NUM] = {
{ 0, 0, -1, MP_OBJ_NULL, MP_OBJ_NULL},
{ 0, 0, -1, MP_OBJ_NULL, MP_OBJ_NULL}
};
device_mgmt_t device_mgmt[ADC_INST_NUM];
#endif // defined(MCU_SAMD21)
@ -123,6 +124,8 @@ static void adc_init(machine_adc_obj_t *self);
extern mp_int_t log2i(mp_int_t num);
#if MICROPY_PY_MACHINE_ADC_TIMED
// Active just for SAMD21, stops the freerun mode
// For SAMD51, just the INT flag is reset.
void adc_irq_handler(int dma_channel) {
@ -152,6 +155,7 @@ void adc_irq_handler(int dma_channel) {
}
#endif
}
#endif
static void mp_machine_adc_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
(void)kind;
@ -171,7 +175,9 @@ static mp_obj_t adc_obj_make_new(const mp_obj_type_t *type, size_t n_args, size_
{ MP_QSTR_bits, MP_ARG_INT, {.u_int = DEFAULT_ADC_BITS} },
{ MP_QSTR_average, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = DEFAULT_ADC_AVG} },
{ MP_QSTR_vref, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = DEFAULT_ADC_VREF} },
#if MICROPY_PY_MACHINE_ADC_TIMED
{ MP_QSTR_callback, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
#endif
};
// Parse the arguments.
@ -199,18 +205,20 @@ static mp_obj_t adc_obj_make_new(const mp_obj_type_t *type, size_t n_args, size_
if (0 <= vref && vref <= MAX_ADC_VREF) {
self->vref = vref;
}
// flag the device/channel as being in use.
ch_busy_flags |= (1 << (self->adc_config.device * 16 + self->adc_config.channel));
device_mgmt[self->adc_config.device].init = false;
#if MICROPY_PY_MACHINE_ADC_TIMED
device_mgmt[adc_config.device].callback = args[ARG_callback].u_obj;
if (device_mgmt[adc_config.device].callback == mp_const_none) {
device_mgmt[adc_config.device].callback = MP_OBJ_NULL;
} else {
device_mgmt[adc_config.device].self = self;
}
// flag the device/channel as being in use.
ch_busy_flags |= (1 << (self->adc_config.device * 16 + self->adc_config.channel));
device_mgmt[self->adc_config.device].init = false;
self->dma_channel = -1;
self->tc_index = -1;
#endif
adc_init(self);
@ -222,9 +230,12 @@ static mp_int_t mp_machine_adc_read_u16(machine_adc_obj_t *self) {
Adc *adc = adc_bases[self->adc_config.device];
// Set the reference voltage. Default: external AREFA.
adc->REFCTRL.reg = adc_vref_table[self->vref];
#if MICROPY_PY_MACHINE_ADC_TIMED
if (device_mgmt[self->adc_config.device].busy != 0) {
mp_raise_OSError(MP_EBUSY);
}
#endif
// Set the reference voltage. Default: external AREFA.
adc->REFCTRL.reg = adc_vref_table[self->vref];
@ -375,6 +386,9 @@ static mp_int_t machine_adc_busy(mp_obj_t self_in) {
return device_mgmt[self->adc_config.device].busy ? true : false;
}
#endif
#if MICROPY_PY_MACHINE_ADC_TIMED
void adc_deinit_all(void) {
ch_busy_flags = 0;
device_mgmt[0].init = 0;
@ -384,6 +398,15 @@ void adc_deinit_all(void) {
device_mgmt[1].dma_channel = -1;
#endif
}
#else
void adc_deinit_all(void) {
ch_busy_flags = 0;
device_mgmt[0].init = 0;
#if defined(MCU_SAMD51)
device_mgmt[1].init = 0;
#endif
}
#endif
static void adc_init(machine_adc_obj_t *self) {
// ADC & clock init is done only once per ADC

Wyświetl plik

@ -48,15 +48,16 @@ typedef struct _dac_obj_t {
bool initialized;
uint8_t vref;
mp_hal_pin_obj_t gpio_id;
#if MICROPY_PY_MACHINE_DAC_TIMED
int8_t dma_channel;
int8_t tc_index;
bool busy;
uint32_t count;
mp_obj_t callback;
#endif
} dac_obj_t;
Dac *const dac_bases[] = DAC_INSTS;
static void dac_init(dac_obj_t *self);
static mp_obj_t dac_deinit(mp_obj_t self_in);
#if defined(MCU_SAMD21)
@ -88,6 +89,8 @@ static uint8_t dac_vref_table[] = {
#endif // defined SAMD21 or SAMD51
#if MICROPY_PY_MACHINE_DAC_TIMED
void dac_irq_handler(int dma_channel) {
dac_obj_t *self;
@ -126,6 +129,8 @@ void dac_irq_handler(int dma_channel) {
#endif
}
#endif
static mp_obj_t dac_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw,
const mp_obj_t *all_args) {
@ -133,7 +138,9 @@ static mp_obj_t dac_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_id, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} },
{ MP_QSTR_vref, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = DEFAULT_DAC_VREF} },
#if MICROPY_PY_MACHINE_DAC_TIMED
{ MP_QSTR_callback, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
#endif
};
// Parse the arguments.
@ -153,15 +160,17 @@ static mp_obj_t dac_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_
self->vref = vref;
}
#if MICROPY_PY_MACHINE_DAC_TIMED
self->callback = args[ARG_callback].u_obj;
if (self->callback == mp_const_none) {
self->callback = MP_OBJ_NULL;
}
self->dma_channel = -1;
self->tc_index = -1;
self->initialized = false;
self->busy = false;
#endif
self->initialized = false;
dac_init(self);
// Set the port as given in self->gpio_id as DAC
@ -238,9 +247,11 @@ static mp_obj_t dac_write(mp_obj_t self_in, mp_obj_t value_in) {
if (self->initialized == false) {
mp_raise_OSError(MP_ENODEV);
}
#if MICROPY_PY_MACHINE_DAC_TIMED
if (self->busy != false) {
mp_raise_OSError(MP_EBUSY);
}
#endif
int value = mp_obj_get_int(value_in);
@ -257,6 +268,8 @@ static mp_obj_t dac_write(mp_obj_t self_in, mp_obj_t value_in) {
}
MP_DEFINE_CONST_FUN_OBJ_2(dac_write_obj, dac_write);
#if MICROPY_PY_MACHINE_DAC_TIMED
static mp_obj_t dac_write_timed(size_t n_args, const mp_obj_t *args) {
Dac *dac = dac_bases[0]; // Just one DAC used
dac_obj_t *self = args[0];
@ -386,12 +399,26 @@ static mp_obj_t machine_dac_busy(mp_obj_t 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);
#else
void dac_deinit_all(void) {
// Reset the DAC to lower the current consumption as SAMD21
dac_bases[0]->CTRLA.bit.SWRST = 1;
dac_obj[0].initialized = false;
#if defined(MCU_SAMD51)
dac_obj[1].initialized = false;
#endif
}
#endif
static const mp_rom_map_elem_t dac_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&dac_write_obj) },
#if MICROPY_PY_MACHINE_DAC_TIMED
{ 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_timed), MP_ROM_PTR(&dac_write_timed_obj) },
#endif
};
static MP_DEFINE_CONST_DICT(dac_locals_dict, dac_locals_dict_table);

Wyświetl plik

@ -90,8 +90,12 @@ void samd_main(void) {
soft_reset_exit:
mp_printf(MP_PYTHON_PRINTER, "MPY: soft reboot\n");
#if MICROPY_HW_DMA_MANAGER
dma_deinit();
#endif
#if MICROPY_HW_TC_MANAGER
tc_deinit();
#endif
#if MICROPY_PY_MACHINE_ADC
adc_deinit_all();
#endif

Wyświetl plik

@ -128,6 +128,17 @@
#define MICROPY_PY_MACHINE_WDT_TIMEOUT_MS (1)
#define MICROPY_PLATFORM_VERSION "ASF4"
#ifndef MICROPY_PY_MACHINE_DAC_TIMED
#define MICROPY_PY_MACHINE_DAC_TIMED (1)
#endif
#ifndef MICROPY_PY_MACHINE_ADC_TIMED
#define MICROPY_PY_MACHINE_ADC_TIMED (1)
#endif
#if MICROPY_PY_MACHINE_DAC_TIMED || MICROPY_PY_MACHINE_ADC_TIMED
#define MICROPY_HW_DMA_MANAGER (1)
#define MICROPY_HW_TC_MANAGER (1)
#endif
#define MP_STATE_PORT MP_STATE_VM
// Miscellaneous settings

Wyświetl plik

@ -29,6 +29,8 @@
#include "sam.h"
#include "tc_manager.h"
#if MICROPY_HW_TC_MANAGER
// List of channel flags: true: channel used, false: channel available
// Two Tc instances are used by the usec counter and cannot be assigned.
#if defined(MCU_SAMD21)
@ -179,3 +181,5 @@ void tc_deinit(void) {
instance_flag[0] = instance_flag[1] = true;
#endif
}
#endif