From b30e0d2f2683a809ae393dd402aad89a62a22df3 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 10 Apr 2018 22:25:55 +1000 Subject: [PATCH] stm32/dac: Add buffering argument to constructor and init() method. This can be used to select the output buffer behaviour of the DAC. The default values are chosen to retain backwards compatibility with existing behaviour. Thanks to @peterhinch for the initial idea to add this feature. --- docs/library/pyb.DAC.rst | 21 ++++++++++++++++++--- ports/stm32/dac.c | 24 ++++++++++++++++++++---- tests/pyb/dac.py | 4 ++++ 3 files changed, 42 insertions(+), 7 deletions(-) diff --git a/docs/library/pyb.DAC.rst b/docs/library/pyb.DAC.rst index fd786b63b6..3e236a3da9 100644 --- a/docs/library/pyb.DAC.rst +++ b/docs/library/pyb.DAC.rst @@ -49,7 +49,7 @@ To output a continuous sine-wave at 12-bit resolution:: Constructors ------------ -.. class:: pyb.DAC(port, bits=8) +.. class:: pyb.DAC(port, bits=8, \*, buffering=None) Construct a new DAC object. @@ -60,12 +60,27 @@ Constructors The maximum value for the write and write_timed methods will be 2\*\*``bits``-1. + The *buffering* parameter selects the behaviour of the DAC op-amp output + buffer, whose purpose is to reduce the output impedance. It can be + ``None`` to select the default (buffering enabled for :meth:`DAC.noise`, + :meth:`DAC.triangle` and :meth:`DAC.write_timed`, and disabled for + :meth:`DAC.write`), ``False`` to disable buffering completely, or ``True`` + to enable output buffering. + + When buffering is enabled the DAC pin can drive loads down to 5KΩ. + Otherwise it has an output impedance of 15KΩ maximum: consequently + to achieve a 1% accuracy without buffering requires the applied load + to be less than 1.5MΩ. Using the buffer incurs a penalty in accuracy, + especially near the extremes of range. + Methods ------- -.. method:: DAC.init(bits=8) +.. method:: DAC.init(bits=8, \*, buffering=None) - Reinitialise the DAC. ``bits`` can be 8 or 12. + Reinitialise the DAC. *bits* can be 8 or 12. *buffering* can be + ``None``, ``False`` or ``True`; see above constructor for the meaning + of this parameter. .. method:: DAC.deinit() diff --git a/ports/stm32/dac.c b/ports/stm32/dac.c index bce30dbc7e..04acfb8aa1 100644 --- a/ports/stm32/dac.c +++ b/ports/stm32/dac.c @@ -143,11 +143,14 @@ typedef struct _pyb_dac_obj_t { uint16_t pin; // GPIO_PIN_4 or GPIO_PIN_5 uint8_t bits; // 8 or 12 uint8_t state; + uint8_t outbuf_single; + uint8_t outbuf_waveform; } pyb_dac_obj_t; STATIC mp_obj_t pyb_dac_init_helper(pyb_dac_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { static const mp_arg_t allowed_args[] = { { MP_QSTR_bits, MP_ARG_INT, {.u_int = 8} }, + { MP_QSTR_buffering, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, }; // parse args @@ -194,6 +197,19 @@ STATIC mp_obj_t pyb_dac_init_helper(pyb_dac_obj_t *self, size_t n_args, const mp mp_raise_ValueError("unsupported bits"); } + // set output buffer config + if (args[1].u_obj == mp_const_none) { + // due to legacy, default values differ for single and waveform outputs + self->outbuf_single = DAC_OUTPUTBUFFER_DISABLE; + self->outbuf_waveform = DAC_OUTPUTBUFFER_ENABLE; + } else if (mp_obj_is_true(args[1].u_obj)) { + self->outbuf_single = DAC_OUTPUTBUFFER_ENABLE; + self->outbuf_waveform = DAC_OUTPUTBUFFER_ENABLE; + } else { + self->outbuf_single = DAC_OUTPUTBUFFER_DISABLE; + self->outbuf_waveform = DAC_OUTPUTBUFFER_DISABLE; + } + // reset state of DAC self->state = DAC_STATE_RESET; @@ -289,7 +305,7 @@ STATIC mp_obj_t pyb_dac_noise(mp_obj_t self_in, mp_obj_t freq) { // configure DAC to trigger via TIM6 DAC_ChannelConfTypeDef config; config.DAC_Trigger = DAC_TRIGGER_T6_TRGO; - config.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE; + config.DAC_OutputBuffer = self->outbuf_waveform; HAL_DAC_ConfigChannel(&DAC_Handle, &config, self->dac_channel); self->state = DAC_STATE_BUILTIN_WAVEFORM; } @@ -319,7 +335,7 @@ STATIC mp_obj_t pyb_dac_triangle(mp_obj_t self_in, mp_obj_t freq) { // configure DAC to trigger via TIM6 DAC_ChannelConfTypeDef config; config.DAC_Trigger = DAC_TRIGGER_T6_TRGO; - config.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE; + config.DAC_OutputBuffer = self->outbuf_waveform; HAL_DAC_ConfigChannel(&DAC_Handle, &config, self->dac_channel); self->state = DAC_STATE_BUILTIN_WAVEFORM; } @@ -342,7 +358,7 @@ STATIC mp_obj_t pyb_dac_write(mp_obj_t self_in, mp_obj_t val) { if (self->state != DAC_STATE_WRITE_SINGLE) { DAC_ChannelConfTypeDef config; config.DAC_Trigger = DAC_TRIGGER_NONE; - config.DAC_OutputBuffer = DAC_OUTPUTBUFFER_DISABLE; + config.DAC_OutputBuffer = self->outbuf_single; HAL_DAC_ConfigChannel(&DAC_Handle, &config, self->dac_channel); self->state = DAC_STATE_WRITE_SINGLE; } @@ -454,7 +470,7 @@ mp_obj_t pyb_dac_write_timed(size_t n_args, const mp_obj_t *pos_args, mp_map_t * if (self->state != DAC_STATE_DMA_WAVEFORM + dac_trigger) { DAC_ChannelConfTypeDef config; config.DAC_Trigger = dac_trigger; - config.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE; + config.DAC_OutputBuffer = self->outbuf_waveform; HAL_DAC_ConfigChannel(&DAC_Handle, &config, self->dac_channel); self->state = DAC_STATE_DMA_WAVEFORM + dac_trigger; } diff --git a/tests/pyb/dac.py b/tests/pyb/dac.py index 6f03bbc64d..ca68ec7098 100644 --- a/tests/pyb/dac.py +++ b/tests/pyb/dac.py @@ -12,3 +12,7 @@ dac.write(0) dac.write_timed(bytearray(10), 100, mode=pyb.DAC.NORMAL) pyb.delay(20) dac.write(0) + +# test buffering arg +dac = pyb.DAC(1, buffering=True) +dac.write(0)