10000 stmhal: Allow to set bits resolution for DAC; 8 is default, can have 12. · micropython/micropython@b5c43be · GitHub
[go: up one dir, main page]

Skip to content

Commit b5c43be

Browse files
committed
stmhal: Allow to set bits resolution for DAC; 8 is default, can have 12.
This patch allows to configure the DAC resolution in the constructor and in the init function, eg: dac = DAC(1, bits=12). The default resolution is 8 bits for backwards compatibility. The bits sets the maximum value accepted by write and write_timed methods, being 2**bits - 1. When using write_timed with 12-bit resolution, the input buffer is treated as an unsigned half-word array, typecode 'H'. See PR #1130 for discussion.
1 parent b8f9ac5 commit b5c43be

File tree

2 files changed

+104
-32
lines changed

2 files changed

+104
-32
lines changed

docs/library/pyb.DAC.rst

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ Example usage::
1515
dac = DAC(1) # create DAC 1 on pin X5
1616
dac.write(128) # write a value to the DAC (makes X5 1.65V)
1717

18+
dac = DAC(1, bits=12) # use 12 bit resolution
19+
dac.write(4095) # output maximum value, 3.3V
20+
1821
To output a continuous sine-wave::
1922

2023
import math
@@ -29,21 +32,40 @@ To output a continuous sine-wave::
2932
dac = DAC(1)
3033
dac.write_timed(buf, 400 \* len(buf), mode=DAC.CIRCULAR)
3134

35+
To output a continuous sine-wave at 12-bit resolution::
36+
37+
import math
38+
from array import array
39+
from pyb import DAC
40+
41+
# create a buffer containing a sine-wave, using half-word samples
42+
buf = array('H', 2048 + int(2047 * math.sin(2 * math.pi * i / 128)) for i in range(128))
43+
44+
# output the sine-wave at 400Hz
45+
dac = DAC(1, bits=12)
46+
dac.write_timed(buf, 400 \* len(buf), mode=DAC.CIRCULAR)
3247

3348
Constructors
3449
------------
3550

36-
.. class:: pyb.DAC(port)
51+
.. class:: pyb.DAC(port, bits=8)
3752

3853
Construct a new DAC object.
39-
54+
4055
``port`` can be a pin object, or an integer (1 or 2).
4156
DAC(1) is on pin X5 and DAC(2) is on pin X6.
4257

58+
``bits`` is an integer specifying the resolution, and can be 8 or 12.
59+
The maximum value for the write and write_timed methods will be
60+
2\*\*``bits``-1.
4361

4462
Methods
4563
-------
4664

65+
.. method:: dac.init(bits=8)
66+
67+
Reinitialise the DAC. ``bits`` can be 8 or 12.
68+
4769
.. method:: dac.noise(freq)
4870

4971
Generate a pseudo-random noise signal. A new random sample is written
@@ -57,13 +79,16 @@ Methods
5779

5880
.. method:: dac.write(value)
5981

60-
Direct access to the DAC output (8 bit only at the moment).
82+
Direct access to the DAC output. The minimum value is 0. The maximum
83+
value is 2\*\*``bits``-1, where ``bits`` is set when creating the DAC
84+
object or by using the ``init`` method.
6185

6286
.. method:: dac.write_timed(data, freq, \*, mode=DAC.NORMAL)
6387

6488
Initiates a burst of RAM to DAC using a DMA transfer.
65-
The input data is treated as an array of bytes (8 bit data).
66-
89+
The input data is treated as an array of bytes in 8-bit mode, and
90+
an array of unsigned half-words (array typecode 'H') in 12-bit mode.
91+
6792
``freq`` can be an integer specifying the frequency to write the DAC
6893
samples at, using Timer(6). Or it can be an already-initialised
6994
Timer object which is used to trigger the DAC sample. Valid timers

stmhal/dac.c

Lines changed: 74 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -139,9 +139,50 @@ typedef struct _pyb_dac_obj_t {
139139
mp_obj_base_t base;
140140
uint32_t dac_channel; // DAC_CHANNEL_1 or DAC_CHANNEL_2
141141
DMA_Stream_TypeDef *dma_stream; // DMA1_Stream5 or DMA1_Stream6
142-
pyb_dac_state_t state;
142+
uint16_t pin; // GPIO_PIN_4 or GPIO_PIN_5
143+
uint8_t bits; // 8 or 12
144+
uint8_t state;
143145
} pyb_dac_obj_t;
144146

147+
STATIC mp_obj_t pyb_dac_init_helper(pyb_dac_obj_t *self, mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
148+
static const mp_arg_t allowed_args[] = {
149+
{ MP_QSTR_bits, MP_ARG_INT, {.u_int = 8} },
150+
};
151+
152+
// parse args
153+
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
154+
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
155+
156+
// GPIO configuration
157+
GPIO_InitTypeDef GPIO_InitStructure;
158+
GPIO_InitStructure.Pin = self->pin;
159+
GPIO_InitStructure.Mode = GPIO_MODE_ANALOG;
160+
GPIO_InitStructure.Pull = GPIO_NOPULL;
161+
HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
162+
163+
// DAC peripheral clock
164+
__DAC_CLK_ENABLE();
165+
166+
// stop anything already going on
167+
HAL_DAC_Stop(&DAC_Handle, self->dac_channel);
168+
if ((self->dac_channel == DAC_CHANNEL_1 && DAC_Handle.DMA_Handle1 != NULL)
169+
|| (self->dac_channel == DAC_CHANNEL_2 && DAC_Handle.DMA_Handle2 != NULL)) {
170+
HAL_DAC_Stop_DMA(&DAC_Handle, self->dac_channel);
171+
}
172+
173+
// set bit resolution
174+
if (args[0].u_int == 8 || args[0].u_int == 12) {
175+
self->bits = args[0].u_int;
176+
} else {
177+
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "unsupported bits"));
178+
}
179+
180+
// reset state of DAC
181+
self->state = DAC_STATE_RESET;
182+
183+
return mp_const_none;
184+
}
185+
145186
// create the dac object
146187
// currently support either DAC1 on X5 (id = 1) or DAC2 on X6 (id = 2)
147188

@@ -152,7 +193,7 @@ typedef struct _pyb_dac_obj_t {
152193
/// DAC(1) is on pin X5 and DAC(2) is on pin X6.
153194
STATIC mp_obj_t pyb_dac_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) {
154195
// check arguments
155-
mp_arg_check_num(n_args, n_kw, 1, 1, false);
196+
mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true);
156197

157198
// get pin/channel to output on
158199
mp_int_t dac_id;
@@ -172,42 +213,32 @@ STATIC mp_obj_t pyb_dac_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n
172213
pyb_dac_obj_t *dac = m_new_obj(pyb_dac_obj_t);
173214
dac->base.type = &pyb_dac_type;
174215

175-
uint32_t pin;
176216
if (dac_id == 1) {
177-
pin = GPIO_PIN_4;
217+
dac->pin = GPIO_PIN_4;
178218
dac->dac_channel = DAC_CHANNEL_1;
179219
dac->dma_stream = DMA1_Stream5;
180220
} else if (dac_id == 2) {
181-
pin = GPIO_PIN_5;
221+
dac->pin = GPIO_PIN_5;
182222
dac->dac_channel = DAC_CHANNEL_2;
183223
dac->dma_stream = DMA1_Stream6;
184224
} else {
185225
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "DAC %d does not exist", dac_id));
186226
}
187227

188-
// GPIO configuration
189-
GPIO_InitTypeDef GPIO_InitStructure;
190-
GPIO_InitStructure.Pin = pin;
191-
GPIO_InitStructure.Mode = GPIO_MODE_ANALOG;
192-
GPIO_InitStructure.Pull = GPIO_NOPULL;
193-
HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
194-
195-
// DAC peripheral clock
196-
__DAC_CLK_ENABLE();
197-
198-
// stop anything already going on
199-
HAL_DAC_Stop(&DAC_Handle, dac->dac_channel);
200-
if ((dac->dac_channel == DAC_CHANNEL_1 && DAC_Handle.DMA_Handle1 != NULL)
201-
|| (dac->dac_channel == DAC_CHANNEL_2 && DAC_Handle.DMA_Handle2 != NULL)) {
202-
HAL_DAC_Stop_DMA(&DAC_Handle, dac->dac_channel);
203-
}
204-
205-
dac->state = DAC_STATE_RESET;
228+
// configure the peripheral
229+
mp_map_t kw_args;
230+
mp_map_init_fixed_table(&kw_args, n_kw, args + n_args);
231+
pyb_dac_init_helper(dac, n_args - 1, args + 1, &kw_args);
206232

207233
// return object
208234
return dac;
209235
}
210236

237+
STATIC mp_obj_t pyb_dac_init(mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
238+
return pyb_dac_init_helper(args[0], n_args - 1, args + 1, kw_args);
239+
}
240+
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_dac_init_obj, 1, pyb_dac_init);
241+
211242
#if defined(TIM6)
212243
/// \method noise(freq)
213244
/// Generate a pseudo-random noise signal. A new random sample is written
@@ -280,7 +311,11 @@ STATIC mp_obj_t pyb_dac_write(mp_obj_t self_in, mp_obj_t val) {
280311
self->state = DAC_STATE_WRITE_SINGLE;
281312
}
282313

283-
HAL_DAC_SetValue(&DAC_Handle, self->dac_channel, DAC_ALIGN_8B_R, mp_obj_get_int(val));
314+
// DAC output is always 12-bit at the hardware level, and we provide support
315+
// for multiple bit "resolutions" simply by shifting the input value.
316+
HAL_DAC_SetValue(&DAC_Handle, self->dac_channel, DAC_ALIGN_12B_R,
317+
mp_obj_get_int(val) << (12 - self->bits));
318+
284319
HAL_DAC_Start(&DAC_Handle, self->dac_channel);
285320

286321
return mp_const_none;
@@ -365,8 +400,13 @@ mp_obj_t pyb_dac_write_timed(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_
365400
DMA_Handle.Init.Direction = DMA_MEMORY_TO_PERIPH;
366401
DMA_Handle.Init.PeriphInc = DMA_PINC_DISABLE;
367402
DMA_Handle.Init.MemInc = DMA_MINC_ENABLE;
368-
DMA_Handle.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
369-
DMA_Handle.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
403+
if (self->bits == 8) {
404+
DMA_Handle.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
405+
DMA_Handle.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
406+
} else {
407+
DMA_Handle.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
408+
DMA_Handle.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
409+
}
370410
DMA_Handle.Init.Mode = args[2].u_int;
371411
DMA_Handle.Init.Priority = DMA_PRIORITY_HIGH;
372412
DMA_Handle.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
@@ -393,7 +433,13 @@ mp_obj_t pyb_dac_write_timed(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_
393433
self->state = DAC_STATE_DMA_WAVEFORM + dac_trigger;
394434
}
395435

396-
HAL_DAC_Start_DMA(&DAC_Handle, self->dac_channel, (uint32_t*)bufinfo.buf, bufinfo.len, DAC_ALIGN_8B_R);
436+
if (self->bits == 8) {
437+
HAL_DAC_Start_DMA(&DAC_Handle, self->dac_channel,
438+
(uint32_t*)bufinfo.buf, bufinfo.len, DAC_ALIGN_8B_R);
439+
} else {
440+
HAL_DAC_Start_DMA(&DAC_Handle, self->dac_channel,
441+
(uint32_t*)bufinfo.buf, bufinfo.len / 2, DAC_ALIGN_12B_R);
442+
}
397443

398444
/*
399445
// enable DMA stream
@@ -417,6 +463,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_dac_write_timed_obj, 1, pyb_dac_write_time
417463

418464
STATIC const mp_map_elem_t pyb_dac_locals_dict_table[] = {
419465
// instance methods
466+
{ MP_OBJ_NEW_QSTR(MP_QSTR_init), (mp_obj_t)&pyb_dac_init_obj },
420467
{ MP_OBJ_NEW_QSTR(MP_QSTR_write), (mp_obj_t)&pyb_dac_write_obj },
421468
#if defined(TIM6)
422469
{ MP_OBJ_NEW_QSTR(MP_QSTR_noise), (mp_obj_t)&pyb_dac_noise_obj },

0 commit comments

Comments
 (0)
0