Skip to content

Commit

Permalink
samd/ADC_DAC: Make adc.read_timed() and dac.write_timed() configurable.
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
robert-hh committed Sep 22, 2024
1 parent d5ae190 commit caad75c
Show file tree
Hide file tree
Showing 6 changed files with 84 additions and 11 deletions.
4 changes: 4 additions & 0 deletions ports/samd/dma_manager.c
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -129,3 +131,5 @@ void dac_stop_dma(int dma_channel, bool wait) {
}
#endif
}

#endif
39 changes: 31 additions & 8 deletions ports/samd/machine_adc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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];
Expand All @@ -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)

Expand All @@ -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) {
Expand Down Expand Up @@ -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;
Expand All @@ -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.
Expand Down Expand Up @@ -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);

Expand All @@ -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];
Expand Down Expand Up @@ -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;
Expand All @@ -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
Expand Down
33 changes: 30 additions & 3 deletions ports/samd/machine_dac.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -126,14 +129,18 @@ 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) {

enum { ARG_id, ARG_vref, ARG_callback };
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.
Expand All @@ -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
Expand Down Expand Up @@ -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);

Expand All @@ -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];
Expand Down Expand Up @@ -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);
Expand Down
4 changes: 4 additions & 0 deletions ports/samd/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
11 changes: 11 additions & 0 deletions ports/samd/mpconfigport.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 4 additions & 0 deletions ports/samd/tc_manager.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -179,3 +181,5 @@ void tc_deinit(void) {
instance_flag[0] = instance_flag[1] = true;
#endif
}

#endif

0 comments on commit caad75c

Please sign in to comment.