Firmware SDK
twr_dac.c
1 #include <twr_dac.h>
2 #include <twr_scheduler.h>
3 #include <twr_system.h>
4 #include <stm32l0xx.h>
5 
6 // Approximate voltage to code constant
7 #define _TWR_DAC_VOLTAGE_TO_CODE_CONSTANT 19961
8 
9 typedef struct
10 {
11  bool is_initialized;
12  bool is_in_progress;
13  void (*event_handler)(twr_dac_channel_t, twr_dac_event_t, void *);
14  void *event_param;
15 
16  struct
17  {
18  uint8_t *u8;
19  uint16_t *u16;
20 
21  } dac_register;
22 
23  twr_dma_channel_t dma_channel;
24  twr_dma_channel_config_t dma_config;
25 
26  TIM_TypeDef *tim;
27  twr_dac_sample_rate_t sample_rate;
28 
30 
31 static struct
32 {
33  twr_dac_channel_setup_t channel[2];
34 
35 } _twr_dac;
36 
37 static const twr_dac_channel_setup_t _twr_dac_channel_0_setup_default;
38 
39 static const twr_dac_channel_setup_t _twr_dac_channel_1_setup_default;
40 
41 static void _twr_dac_dma_handler(twr_dma_channel_t channel, twr_dma_event_t event, void *event_param);
42 
44 {
45  if (_twr_dac.channel[channel].is_initialized)
46  {
47  return;
48  }
49 
50  RCC->APB1ENR |= RCC_APB1ENR_DACEN;
51 
52  // Errata workaround
53  RCC->AHBENR;
54 
55  if (channel == TWR_DAC_DAC0)
56  {
57  _twr_dac.channel[TWR_DAC_DAC0] = _twr_dac_channel_0_setup_default;
58 
59  // Enable DAC channel 0
60  DAC->CR |= DAC_CR_EN1;
61  }
62  else if (channel == TWR_DAC_DAC1)
63  {
64  _twr_dac.channel[TWR_DAC_DAC1] = _twr_dac_channel_1_setup_default;
65 
66  // Enable DAC channel 1
67  DAC->CR |= DAC_CR_EN2;
68  }
69 
70  _twr_dac.channel[channel].is_initialized = true;
71 }
72 
74 {
75  if (!_twr_dac.channel[channel].is_initialized)
76  {
77  return;
78  }
79 
80  if (_twr_dac.channel[channel].is_in_progress)
81  {
82  twr_dac_async_stop(channel);
83  }
84 
85  if (channel == TWR_DAC_DAC0)
86  {
87  // Disable DAC channel 0
88  DAC->CR &= ~DAC_CR_EN1_Msk;
89  }
90  else if (channel == TWR_DAC_DAC1)
91  {
92  // Disable DAC channel 1
93  DAC->CR &= ~DAC_CR_EN2_Msk;
94  }
95 
96  _twr_dac.channel[channel].is_initialized = false;
97 
98  if (!_twr_dac.channel[TWR_DAC_DAC0].is_initialized && !_twr_dac.channel[TWR_DAC_DAC1].is_initialized)
99  {
100  RCC->APB1ENR &= ~RCC_APB1ENR_DACEN;
101  }
102 }
103 
104 void twr_dac_set_output(twr_dac_channel_t channel, const void *raw, twr_dac_format_t format)
105 {
106  if (_twr_dac.channel[channel].is_in_progress)
107  {
108  return;
109  }
110 
111  uint16_t *dac_value = _twr_dac.channel[channel].dac_register.u16;
112 
113  switch (format)
114  {
116  {
117  *_twr_dac.channel[channel].dac_register.u8 = *(uint8_t *) raw;
118  break;
119  }
121  {
122  *dac_value = *(uint16_t *) raw;
123  break;
124  }
126  {
127  *dac_value = *(float *) raw * _TWR_DAC_VOLTAGE_TO_CODE_CONSTANT;
128  break;
129  }
130  default:
131  {
132  return;
133  }
134  }
135 }
136 
137 void twr_dac_set_event_handler(twr_dac_channel_t channel, void (*event_handler)(twr_dac_channel_t, twr_dac_event_t, void *), void *event_param)
138 {
139  _twr_dac.channel[channel].event_handler = event_handler;
140  _twr_dac.channel[channel].event_param = event_param;
141 }
142 
144 {
145  if (_twr_dac.channel[channel].is_in_progress)
146  {
147  return false;
148  }
149 
150  twr_dma_channel_config_t *dac_dma_config = &_twr_dac.channel[channel].dma_config;
151 
152  // Set peripheral address according to data size
153  if (config->data_size == TWR_DAC_DATA_SIZE_8)
154  {
155  dac_dma_config->address_peripheral = _twr_dac.channel[channel].dac_register.u8;
156  }
157  else if (config->data_size == TWR_DAC_DATA_SIZE_16)
158  {
159  dac_dma_config->address_peripheral = _twr_dac.channel[channel].dac_register.u16;
160  }
161 
162  // Set data-size
163  if (config->data_size == TWR_DAC_DATA_SIZE_8)
164  {
165  dac_dma_config->data_size_memory = TWR_DMA_SIZE_1;
166  }
167  else if (config->data_size == TWR_DAC_DATA_SIZE_16)
168  {
169  dac_dma_config->data_size_memory = TWR_DMA_SIZE_2;
170  }
171 
172  // Set DMA channel mode
173  if (config->mode == TWR_DAC_MODE_SINGLE)
174  {
175  dac_dma_config->mode = TWR_DMA_MODE_STANDARD;
176  }
177  else if (config->mode == TWR_DAC_MODE_CIRCULAR)
178  {
179  dac_dma_config->mode = TWR_DMA_MODE_CIRCULAR;
180  }
181 
182  dac_dma_config->length = config->length;
183 
184  dac_dma_config->address_memory = config->buffer;
185 
186  _twr_dac.channel[channel].sample_rate = config->sample_rate;
187 
188  return true;
189 }
190 
192 {
193  twr_dac_channel_setup_t *dac_channel_setup = &_twr_dac.channel[channel];
194 
195  if (dac_channel_setup->is_in_progress)
196  {
197  return false;
198  }
199 
200  twr_system_pll_enable();
201 
202  if (channel == TWR_DAC_DAC0)
203  {
204  DAC->CR &= ~(DAC_CR_TSEL1_Msk);
205 
206  // DMA transfer with timer 6 TRGO event as a trigger
207  DAC->CR |= DAC_CR_DMAEN1 | DAC_CR_TEN1;
208 
209  // Enable time-base timer clock
210  RCC->APB1ENR |= RCC_APB1ENR_TIM6EN;
211  }
212  else if (channel == TWR_DAC_DAC1)
213  {
214  DAC->CR &= ~(DAC_CR_TSEL2_Msk);
215 
216  // DMA transfer with timer 7 TRGO event as a trigger
217  DAC->CR |= DAC_CR_DMAEN2 | DAC_CR_TEN2 | DAC_CR_TSEL2_0 | DAC_CR_TSEL2_2 | DAC_CR_WAVE1_0;
218 
219  // Enable time-base timer clock
220  RCC->APB1ENR |= RCC_APB1ENR_TIM7EN;
221  }
222 
223  // Errata workaround
224  RCC->AHBENR;
225 
226  TIM_TypeDef *tim = _twr_dac.channel[channel].tim;
227 
228  // Set prescaler - Tout 0.5us
229  tim->PSC = 16 - 1;
230 
231  // Configure auto-reload register according to desired sample rate (125us or 62.5us)
232  if (dac_channel_setup->sample_rate == TWR_DAC_SAMPLE_RATE_8K)
233  {
234  tim->ARR = 250 - 1;
235  }
236  else if (dac_channel_setup->sample_rate == TWR_DAC_SAMPLE_RATE_16K)
237  {
238  tim->ARR = 125 - 1;
239  }
240 
241  // Enable update event generation
242  tim->EGR = TIM_EGR_UG;
243 
244  // Set the update event as a trigger output (TRGO)
245  tim->CR2 = TIM_CR2_MMS_1;
246 
247  twr_dma_init();
248 
249  // Update DMA channel with image of DAC DMA channel
250  twr_dma_channel_config(dac_channel_setup->dma_channel, &dac_channel_setup->dma_config);
251 
252  twr_dma_set_event_handler(dac_channel_setup->dma_channel, _twr_dac_dma_handler, (void *)channel);
253 
254  twr_dma_channel_run(dac_channel_setup->dma_channel);
255 
256  // Start timer
257  tim->CR1 |= TIM_CR1_CEN;
258 
259  dac_channel_setup->is_in_progress = true;
260 
261  return true;
262 }
263 
265 {
266  twr_dac_channel_setup_t *dac_channel_setup = &_twr_dac.channel[channel];
267 
268  if (!dac_channel_setup->is_in_progress)
269  {
270  return;
271  }
272 
273  // Stop timer
274  dac_channel_setup->tim->CR1 &= ~TIM_CR1_CEN;
275 
276  twr_dma_channel_stop(dac_channel_setup->dma_channel);
277 
278  if (channel == TWR_DAC_DAC0)
279  {
280  DAC->CR &= ~(DAC_CR_DMAEN1_Msk | DAC_CR_TEN1_Msk | DAC_CR_TSEL1_Msk);
281 
282  // Disable time-base timer clock
283  RCC->APB1ENR &= ~RCC_APB1ENR_TIM6EN;
284  }
285  else if (channel == TWR_DAC_DAC1)
286  {
287  DAC->CR &= ~(DAC_CR_DMAEN2_Msk | DAC_CR_TEN2_Msk | DAC_CR_TSEL2_Msk);
288 
289  // Disable time-base timer clock
290  RCC->APB1ENR &= ~RCC_APB1ENR_TIM7EN;
291  }
292 
293  dac_channel_setup->is_in_progress = false;
294 
295  twr_system_pll_disable();
296 }
297 
298 static void _twr_dac_dma_handler(twr_dma_channel_t channel, twr_dma_event_t event, void *event_param)
299 {
300  (void) channel;
301 
302  twr_dac_channel_t dac_channel = (twr_dac_channel_t) event_param;
303  twr_dac_channel_setup_t *dac_channel_setup = &_twr_dac.channel[dac_channel];
304 
305  if (event == TWR_DMA_EVENT_HALF_DONE)
306  {
307  if (dac_channel_setup->event_handler != NULL)
308  {
309  dac_channel_setup->event_handler(dac_channel, TWR_DAC_EVENT_HALF_DONE, dac_channel_setup->event_param);
310  }
311  }
312  else if (event == TWR_DMA_EVENT_DONE)
313  {
314  if (dac_channel_setup->event_handler != NULL)
315  {
316  dac_channel_setup->event_handler(dac_channel, TWR_DAC_EVENT_DONE, dac_channel_setup->event_param);
317  }
318 
319  if (dac_channel_setup->dma_config.mode != TWR_DMA_MODE_CIRCULAR)
320  {
321  twr_dac_async_stop(dac_channel);
322  }
323  }
324  else if (event == TWR_DMA_EVENT_ERROR)
325  {
326  // TODO Do something
327  }
328 }
329 
330 static const twr_dac_channel_setup_t _twr_dac_channel_0_setup_default =
331 {
332  .is_initialized = false,
333  .is_in_progress = false,
334  .event_handler = NULL,
335  .event_param = NULL,
336 
337  .dac_register =
338  {
339  .u8 = (void *)&DAC->DHR8R1,
340  .u16 = (void *)&DAC->DHR12L1
341  },
342 
343  .dma_channel = TWR_DMA_CHANNEL_2,
344 
345  .dma_config =
346  {
347  .request = TWR_DMA_REQUEST_9,
348  .direction = TWR_DMA_DIRECTION_TO_PERIPHERAL,
349  .data_size_peripheral = TWR_DMA_SIZE_2,
350  .priority = TWR_DMA_PRIORITY_LOW
351  },
352  .tim = TIM6,
353  .sample_rate = TWR_DAC_SAMPLE_RATE_8K
354 };
355 
356 static const twr_dac_channel_setup_t _twr_dac_channel_1_setup_default =
357 {
358  .is_initialized = false,
359  .is_in_progress = false,
360  .event_handler = NULL,
361  .event_param = NULL,
362 
363  .dac_register =
364  {
365  .u8 = (void *)&DAC->DHR8R2,
366  .u16 = (void *)&DAC->DHR12L2
367  },
368 
369  .dma_channel = TWR_DMA_CHANNEL_4,
370  {
371  .request = TWR_DMA_REQUEST_15,
372  .direction = TWR_DMA_DIRECTION_TO_PERIPHERAL,
373  .data_size_peripheral = TWR_DMA_SIZE_2,
374  .priority = TWR_DMA_PRIORITY_LOW
375  },
376  .tim = TIM7,
377  .sample_rate = TWR_DAC_SAMPLE_RATE_8K
378 };
twr_dac_format_t
Raw value format.
Definition: twr_dac.h:26
void twr_dac_deinit(twr_dac_channel_t channel)
Deitialize DAC channel.
Definition: twr_dac.c:73
twr_dac_channel_t
DAC channel.
Definition: twr_dac.h:14
void twr_dac_async_stop(twr_dac_channel_t channel)
Stop asynchronous DAC channel operation.
Definition: twr_dac.c:264
void twr_dac_init(twr_dac_channel_t channel)
Initialize DAC channel.
Definition: twr_dac.c:43
twr_dac_event_t
DAC channel event.
Definition: twr_dac.h:77
bool twr_dac_async_config(twr_dac_channel_t channel, twr_dac_config_t *config)
Configure image of DAC DMA channel.
Definition: twr_dac.c:143
void twr_dac_set_output(twr_dac_channel_t channel, const void *raw, twr_dac_format_t format)
Set DAC channel output as raw value.
Definition: twr_dac.c:104
bool twr_dac_async_run(twr_dac_channel_t channel)
Start asynchronous DAC channel operation.
Definition: twr_dac.c:191
void twr_dac_set_event_handler(twr_dac_channel_t channel, void(*event_handler)(twr_dac_channel_t, twr_dac_event_t, void *), void *event_param)
Set callback function.
Definition: twr_dac.c:137
twr_dac_sample_rate_t
Sample rate.
Definition: twr_dac.h:41
@ TWR_DAC_FORMAT_16_BIT
Raw value format is 16-bit.
Definition: twr_dac.h:31
@ TWR_DAC_FORMAT_VOLTAGE
Raw value format is float.
Definition: twr_dac.h:34
@ TWR_DAC_FORMAT_8_BIT
Raw value format is 8-bit.
Definition: twr_dac.h:28
@ TWR_DAC_DAC0
DAC channel DAC0.
Definition: twr_dac.h:16
@ TWR_DAC_DAC1
DAC channel DAC1.
Definition: twr_dac.h:19
@ TWR_DAC_EVENT_DONE
Event is done.
Definition: twr_dac.h:82
@ TWR_DAC_EVENT_HALF_DONE
Event is done.
Definition: twr_dac.h:79
@ TWR_DAC_DATA_SIZE_8
Data size is 8b.
Definition: twr_dac.h:55
@ TWR_DAC_DATA_SIZE_16
Data size is 16b.
Definition: twr_dac.h:58
@ TWR_DAC_MODE_SINGLE
Mode single.
Definition: twr_dac.h:67
@ TWR_DAC_MODE_CIRCULAR
Mode circular (repeate playing buffer)
Definition: twr_dac.h:70
@ TWR_DAC_SAMPLE_RATE_16K
Data sample-rate is 16kHz.
Definition: twr_dac.h:46
@ TWR_DAC_SAMPLE_RATE_8K
Data sample-rate is 8kHz.
Definition: twr_dac.h:43
void twr_dma_channel_config(twr_dma_channel_t channel, twr_dma_channel_config_t *config)
Configure DMA channel.
Definition: twr_dma.c:95
void twr_dma_channel_run(twr_dma_channel_t channel)
Start DMA channel.
Definition: twr_dma.c:179
void twr_dma_set_event_handler(twr_dma_channel_t channel, void(*event_handler)(twr_dma_channel_t, twr_dma_event_t, void *), void *event_param)
Set callback function.
Definition: twr_dma.c:173
twr_dma_event_t
DMA channel event.
Definition: twr_dma.h:133
void twr_dma_init(void)
Initialize DMA.
Definition: twr_dma.c:56
twr_dma_channel_t
DMA channels.
Definition: twr_dma.h:13
void twr_dma_channel_stop(twr_dma_channel_t channel)
Stop DMA channel.
Definition: twr_dma.c:184
@ TWR_DMA_REQUEST_9
DMA request 9.
Definition: twr_dma.h:69
@ TWR_DMA_REQUEST_15
DMA request 15.
Definition: twr_dma.h:87
@ TWR_DMA_EVENT_DONE
DMA channel event done.
Definition: twr_dma.h:141
@ TWR_DMA_EVENT_HALF_DONE
DMA channel event half done.
Definition: twr_dma.h:138
@ TWR_DMA_EVENT_ERROR
DMA channel event error.
Definition: twr_dma.h:135
@ TWR_DMA_SIZE_2
DMA channel data size 2B.
Definition: twr_dma.h:111
@ TWR_DMA_SIZE_1
DMA channel data size 1B.
Definition: twr_dma.h:108
@ TWR_DMA_DIRECTION_TO_PERIPHERAL
DMA channel direction from RAM to peripheral.
Definition: twr_dma.h:96
@ TWR_DMA_PRIORITY_LOW
DMA channel priority is low.
Definition: twr_dma.h:150
@ TWR_DMA_CHANNEL_2
DMA channel 2.
Definition: twr_dma.h:18
@ TWR_DMA_CHANNEL_4
DMA channel 4.
Definition: twr_dma.h:24
@ TWR_DMA_MODE_CIRCULAR
DMA channel mode circular.
Definition: twr_dma.h:126
@ TWR_DMA_MODE_STANDARD
DMA channel mode standard.
Definition: twr_dma.h:123
DAC channel event.
Definition: twr_dac.h:89
DMA channel configuration.
Definition: twr_dma.h:166
twr_dma_mode_t mode
DMA channel mode.
Definition: twr_dma.h:183
void * address_peripheral
Peripheral address.
Definition: twr_dma.h:189
twr_dma_size_t data_size_memory
DMA channel memory data size.
Definition: twr_dma.h:174
size_t length
DMA channel data length.
Definition: twr_dma.h:180
void * address_memory
RAM memory address.
Definition: twr_dma.h:186