dRonin  adbada4
dRonin firmware
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
pios_dac.c
Go to the documentation of this file.
1 
15 /*
16  * This program is free software; you can redistribute it and/or modify
17  * it under the terms of the GNU General Public License as published by
18  * the Free Software Foundation; either version 3 of the License, or
19  * (at your option) any later version.
20  *
21  * This program is distributed in the hope that it will be useful, but
22  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
23  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
24  * for more details.
25  *
26  * You should have received a copy of the GNU General Public License along
27  * with this program; if not, write to the Free Software Foundation, Inc.,
28  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29  *
30  * Additional note on redistribution: The copyright and license notices above
31  * must be maintained in each individual source file that is a derivative work
32  * of this source file; otherwise redistribution is prohibited.
33  */
34 
35 #include "pios_config.h"
36 
37 #if defined(PIOS_INCLUDE_DAC)
38 
39 #include "pios.h"
40 #include <pios_stm32.h>
41 #include "stm32f4xx_tim.h"
42 #include "pios_tim_priv.h"
43 
44 #include "misc_math.h"
45 
46 #include "pios_dac.h"
47 
48 // Sample rate we'll generally use is 24KHz; this is both good enough for audio,
49 // and results in 4800bps smartaudio being 5 samples per bit. 1200 BFSK
50 // telemetry is a luxurious 20 samples/bit.
51 //
52 // Samples are 16 bits wide, so a 120 sample buffer is 240 bytes long (480b
53 // double buffered), carries 6 bits, and results in an interrupt rate of 200Hz
54 #define DAC_DMA_SAMPLE_COUNT 120
55 
56 typedef bool (*fill_dma_cb)(void *ctx, uint16_t *buf, int len);
57 
58 struct dac_dev_s {
59 #define DAC_MAGIC 0x61434144 /* 'DACa' */
60  uint32_t magic;
61 
62  const struct pios_dac_cfg *cfg;
63 
64  // These are the double buffered bufs.
65  uint16_t dma_buf_0[DAC_DMA_SAMPLE_COUNT];
66  uint16_t dma_buf_1[DAC_DMA_SAMPLE_COUNT];
67 
68  // Updated from, but only read from, interrupt handler.
69  bool cur_buf;
70 
71  volatile bool in_progress;
72 
73  volatile uint8_t priority;
74  volatile fill_dma_cb dma_cb;
75  volatile void *ctx;
76 
77  uint16_t phase_accum; // XXX tmp
78 };
79 
80 static void dac_cue_dma(dac_dev_t dev);
81 
82 int PIOS_DAC_init(dac_dev_t *dev_out, const struct pios_dac_cfg *cfg)
83 {
84  dac_dev_t dev = PIOS_malloc(sizeof(*dev));
85 
86  if (!dev) {
87  return -1;
88  }
89 
90  *dev = (struct dac_dev_s) {
91  .magic = DAC_MAGIC,
92  .cfg = cfg,
93  };
94 
95  TIM_DeInit(cfg->timer);
96  TIM_Cmd(cfg->timer, DISABLE);
97 
98  TIM_TimeBaseInit(cfg->timer,
99  (TIM_TimeBaseInitTypeDef *) &cfg->clock_cfg);
100 
101  // Disable all timer interrupts, in case someone inited this timer
102  // before.
103  TIM_ITConfig(cfg->timer, TIM_IT_Update | TIM_IT_CC1 | TIM_IT_CC2 |
104  TIM_IT_CC3 | TIM_IT_CC4 | TIM_IT_COM | TIM_IT_Trigger |
105  TIM_IT_Break, DISABLE);
106 
107  // Setup a trigger output, get the timer spinning
108  TIM_SelectOutputTrigger(cfg->timer, TIM_TRGOSource_Update);
109 
110  TIM_Cmd(cfg->timer, ENABLE);
111 
112  // Set up the DMA interrupt
113  NVIC_Init((NVIC_InitTypeDef *)(&dev->cfg->interrupt));
114 
115  *dev_out = dev;
116 
117  return 0;
118 }
119 
120 bool PIOS_DAC_install_callback(dac_dev_t dev, uint8_t priority, fill_dma_cb cb,
121  void *ctx) {
122  PIOS_Assert(dev->magic == DAC_MAGIC);
123 
125 
126  if (dev->in_progress) {
127  bool ret_val = false;
128 
129  if (dev->priority < priority) {
130  // Preempt existing transmitter
131 
132  dev->dma_cb = cb;
133  dev->ctx = ctx;
134  dev->priority = priority;
135  ret_val = true;
136  }
137 
138  PIOS_IRQ_Enable();
139 
140  return ret_val;
141  }
142 
143  dev->dma_cb = cb;
144  dev->ctx = ctx;
145  dev->priority = priority;
146 
147  /* Fill initial sample buffers with half-scale */
148  for (int i = 0; i < DAC_DMA_SAMPLE_COUNT; i++) {
149  dev->dma_buf_0[i] = 32767;
150  dev->dma_buf_1[i] = 32767;
151  }
152 
153  /* Establish DMA */
154  dac_cue_dma(dev);
155 
156  dev->in_progress = true;
157 
158  PIOS_IRQ_Enable();
159 
160  return true;
161 }
162 
163 static void dac_cue_dma(dac_dev_t dev) {
164  /* We init / seize the GPIO here, because it's possible someone else has
165  * been running the port the other way for bidir types of things. */
166  GPIO_InitTypeDef gpio_cfg = {
167  .GPIO_Pin = dev->cfg->gpio_pin,
168  .GPIO_Mode = GPIO_Mode_AN,
169  .GPIO_PuPd = GPIO_PuPd_NOPULL,
170  };
171 
172  GPIO_Init(dev->cfg->gpio, &gpio_cfg);
173 
174  DAC_InitTypeDef dac_cfg = {
175  .DAC_Trigger = dev->cfg->dac_trigger,
176  .DAC_WaveGeneration = DAC_WaveGeneration_None,
177  .DAC_OutputBuffer = DAC_OutputBuffer_Enable,
178  };
179 
180  DAC_Init(dev->cfg->dac_channel, &dac_cfg);
181  DAC_Cmd(dev->cfg->dac_channel, ENABLE);
182  DAC_DMACmd(dev->cfg->dac_channel, ENABLE);
183 
184  dev->cur_buf = false;
185  dev->in_progress = true;
186 
187  DMA_Cmd(dev->cfg->dma_stream, DISABLE);
188 
189  DMA_DeInit(dev->cfg->dma_stream);
190 
191  DMA_InitTypeDef dma_init;
192 
193  DMA_StructInit(&dma_init);
194 
195  dma_init.DMA_Channel = dev->cfg->dma_channel;
196  dma_init.DMA_PeripheralBaseAddr = (uintptr_t) dev->cfg->dac_outreg;
197  dma_init.DMA_Memory0BaseAddr = (uintptr_t) dev->dma_buf_0;
198  dma_init.DMA_DIR = DMA_DIR_MemoryToPeripheral;
199  dma_init.DMA_MemoryInc = DMA_MemoryInc_Enable;
200  dma_init.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
201  dma_init.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
202  dma_init.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
203 
204  dma_init.DMA_BufferSize = DAC_DMA_SAMPLE_COUNT;
205  dma_init.DMA_Mode = DMA_Mode_Circular;
206  dma_init.DMA_Priority = DMA_Priority_High;
207  dma_init.DMA_FIFOMode = DMA_FIFOMode_Enable;
208  dma_init.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
209  dma_init.DMA_MemoryBurst = DMA_MemoryBurst_INC4;
210  dma_init.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
211 
212  /* Now the tricky one-- set up the double-buffered DMA, to blit to
213  * BSRRH and clear bits at the appropriate time */
214 
215  DMA_Init(dev->cfg->dma_stream, &dma_init);
216 
217  DMA_DoubleBufferModeConfig(dev->cfg->dma_stream,
218  (uintptr_t) dev->dma_buf_1,
219  DMA_Memory_0);
220 
221  DMA_DoubleBufferModeCmd(dev->cfg->dma_stream, ENABLE);
222 
223  DMA_ClearITPendingBit(dev->cfg->dma_stream,
224  dev->cfg->dma_tcif);
225 
226  DMA_ITConfig(dev->cfg->dma_stream,
227  DMA_IT_TC, ENABLE);
228 
229  DMA_Cmd(dev->cfg->dma_stream, ENABLE);
230 }
231 
233 {
235 
236  DMA_ClearITPendingBit(dev->cfg->dma_stream, dev->cfg->dma_tcif);
237  dev->cur_buf = DMA_GetCurrentMemoryTarget(dev->cfg->dma_stream);
238 
239  uint16_t *buf = dev->cur_buf ? dev->dma_buf_0 : dev->dma_buf_1;
240 
241  bool in_prog;
242 
243  in_prog = dev->dma_cb((void *)dev->ctx, buf, DAC_DMA_SAMPLE_COUNT);
244 
245  if (!in_prog) {
246  // When a callback declares completion, something between the
247  // last 2 to last 0 buffers is lost / not blitted
248  DMA_Cmd(dev->cfg->dma_stream, DISABLE);
249  dev->in_progress = false;
250  }
251 
253 }
254 
255 #endif /* PIOS_INCLUDE_DAC */
Types that are specific to the STM32 peripherals.
int32_t PIOS_IRQ_Enable(void)
Definition: pios_irq.c:53
Main PiOS header to include all the compiled in PiOS options.
bool PIOS_DAC_install_callback(dac_dev_t dev, uint8_t priority, fill_dma_cb cb, void *ctx)
#define PIOS_IRQ_Epilogue()
Definition: pios_irq.h:46
void * PIOS_malloc(size_t size)
Definition: pios_heap.c:125
static struct flyingpicmd_cfg_fa cfg
Definition: main.c:49
int PIOS_DAC_init(dac_dev_t *dev_out, const struct pios_dac_cfg *cfg)
Allocate and initialise DAC device.
uint8_t i
Definition: msp_messages.h:97
uint32_t magic
int32_t PIOS_IRQ_Disable(void)
Definition: pios_irq.c:40
bool(* fill_dma_cb)(void *ctx, uint16_t *buf, int len)
Definition: pios_dac.h:76
struct dac_dev_s * dac_dev_t
Definition: pios_dac.h:40
#define PIOS_IRQ_Prologue()
Definition: pios_irq.h:45
TIM_TypeDef * timer
Definition: pios_dac.h:43
#define PIOS_Assert(test)
Definition: pios_debug.h:52
TIM_TimeBaseInitTypeDef clock_cfg
Definition: pios_dac.h:44
void PIOS_DAC_dma_interrupt_handler(dac_dev_t dev)
Handles a DMA completion interrupt on dma_stream.