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.
This commit is contained in:
Damien George 2018-04-10 22:25:55 +10:00
parent aebd9701a7
commit b30e0d2f26
3 changed files with 42 additions and 7 deletions

View File

@ -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()

View File

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

View File

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