4 * This file is part of BeRTOS.
6 * Bertos is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 * As a special exception, you may use this file as part of a free software
21 * library without restriction. Specifically, if other files instantiate
22 * templates or use macros or inline functions from this file, or you compile
23 * this file and link it with other files to produce an executable, this
24 * file does not by itself cause the resulting executable to be covered by
25 * the GNU General Public License. This exception does not however
26 * invalidate any other reasons why the executable file might be covered by
27 * the GNU General Public License.
29 * Copyright 2011 Develer S.r.l. (http://www.develer.com/)
33 * \brief DAC hardware-specific implementation
35 * \author Daniele Basile <asterix@develer.com>
40 #include "cfg/cfg_dac.h"
42 #include <cfg/macros.h>
43 #include <cfg/compiler.h>
45 // Define log settings for cfg/log.h.
46 #define LOG_LEVEL DAC_LOG_LEVEL
47 #define LOG_FORMAT DAC_LOG_FORMAT
52 #include <drv/irq_cm3.h>
54 #include <cpu/types.h>
56 #include <mware/event.h>
69 struct DacHardware dac_hw;
72 /* We use event to signal the end of conversion */
73 static Event buff_emtpy;
75 #if CONFIG_DAC_TIMER == DACC_TRGSEL_TIO_CH0 /* Select Timer counter TIO Channel 0 */
76 #define DAC_TC_ID TC0_ID
77 #define DAC_TC_CCR TC0_CCR0
78 #define DAC_TC_IDR TC0_IDR0
79 #define DAC_TC_CMR TC0_CMR0
80 #define DAC_TC_SR TC0_SR0
81 #define DAC_TC_RA TC0_RA0
82 #define DAC_TC_RC TC0_RC0
83 #elif CONFIG_DAC_TIMER == DACC_TRGSEL_TIO_CH1 /* Select Timer counter TIO Channel 1 */
84 #define DAC_TC_ID TC1_ID
85 #define DAC_TC_CCR TC0_CCR1
86 #define DAC_TC_IDR TC0_IDR1
87 #define DAC_TC_CMR TC0_CMR1
88 #define DAC_TC_SR TC0_SR1
89 #define DAC_TC_RA TC0_RA1
90 #define DAC_TC_RC TC0_RC1
91 #elif CONFIG_DAC_TIMER == DACC_TRGSEL_TIO_CH2 /* Select Timer counter TIO Channel 2 */
92 #define DAC_TC_ID TC2_ID
93 #define DAC_TC_CCR TC0_CCR2
94 #define DAC_TC_IDR TC0_IDR2
95 #define DAC_TC_CMR TC0_CMR2
96 #define DAC_TC_SR TC0_SR2
97 #define DAC_TC_RA TC0_RA2
98 #define DAC_TC_RC TC0_RC2
99 #elif CONFIG_DAC_TIMER == DACC_TRGSEL_PWM0 || CONFIG_DAC_TIMER == DACC_TRGSEL_PWM1
100 #error unimplemented pwm triger select.
104 INLINE void tc_init(void)
106 pmc_periphEnable(DAC_TC_ID);
108 /* Disable TC clock */
109 DAC_TC_CCR = BV(TC_CCR_CLKDIS);
110 /* Disable interrupts */
111 DAC_TC_IDR = 0xFFFFFFFF;
112 /* Clear status register */
113 volatile uint32_t dummy = DAC_TC_SR;
117 * Setup the timer counter:
118 * - select clock TCLK1 (MCK/2)
119 * - enable wave form mode
120 * - RA compare effect SET
121 * - RC compare effect CLEAR
122 * - UP mode with automatic trigger on RC Compare
124 DAC_TC_CMR = TC_TIMER_CLOCK1 | BV(TC_CMR_WAVE) | TC_CMR_ACPA_SET | TC_CMR_ACPC_CLEAR | BV(TC_CMR_CPCTRG);
127 /* Setup the pio: TODO: fix for more generic */
129 PIO_PERIPH_SEL(PIOB_BASE, BV(25), PIO_PERIPH_B);
132 INLINE void tc_setup(uint32_t freq, size_t n_sample)
135 * Compute the sample frequency
136 * the RC counter will update every MCK/2 (see above)
137 * so to convert one sample at the user freq we generate
138 * the trigger every TC_CLK / (numer_of_sample * user_freq)
139 * where TC_CLK = MCK / 2.
141 uint32_t rc = DIV_ROUND((CPU_FREQ / 2), n_sample * freq);
143 /* generate the square wave with duty = 50% */
144 DAC_TC_RA = DIV_ROUND(50 * rc, 100);
147 INLINE void tc_start(void)
149 DAC_TC_CCR = BV(TC_CCR_CLKEN)| BV(TC_CCR_SWTRG);
152 INLINE void tc_stop(void)
154 DAC_TC_CCR = BV(TC_CCR_CLKDIS);
157 static int sam3x_dac_write(struct Dac *dac, unsigned channel, uint16_t sample)
161 ASSERT(channel <= DAC_MAXCH);
163 DACC_MR |= (channel << DACC_USER_SEL_SHIFT) & DACC_USER_SEL_MASK;
164 DACC_CHER |= BV(channel);
171 static void sam3x_dac_setCh(struct Dac *dac, uint32_t mask)
173 /* we have only the ch0 and ch1 */
174 ASSERT(mask < BV(3));
175 dac->hw->channels = mask;
177 if (mask & BV(DACC_CH0))
178 DACC_MR |= (DACC_CH0 << DACC_USER_SEL_SHIFT) & DACC_USER_SEL_MASK;
180 if (mask & BV(DACC_CH1))
181 DACC_MR |= (DACC_CH1 << DACC_USER_SEL_SHIFT) & DACC_USER_SEL_MASK;
187 static void sam3x_dac_setSampleRate(struct Dac *dac, uint32_t rate)
189 /* Eneble hw trigger */
190 DACC_MR |= BV(DACC_TRGEN) | (CONFIG_DAC_TIMER << DACC_TRGSEL_SHIFT);
191 dac->hw->rate = rate;
194 static void sam3x_dac_conversion(struct Dac *dac, void *buf, size_t len)
196 /* setup timer and start it */
197 tc_setup(dac->hw->rate, len);
200 /* Setup dma and start it */
201 DACC_TPR = (uint32_t)buf;
203 DACC_PTCR |= BV(DACC_PTCR_TXTEN);
206 static uint16_t *sample_buff;
207 static size_t next_idx = 0;
208 static size_t chunk_size = 0;
209 static size_t remaing_size = 0;
211 static DECLARE_ISR(irq_dac)
213 if (DACC_ISR & BV(DACC_ENDTX))
215 if (remaing_size > 0)
217 DACC_TNPR = (uint32_t)&sample_buff[next_idx];
218 DACC_TNCR = chunk_size;
220 remaing_size -= chunk_size;
221 next_idx += chunk_size;
224 /* Clear the pending irq when the dma ends the conversion */
227 event_do(&buff_emtpy);
231 static bool sam3x_dac_isFinished(struct Dac *dac)
236 static void sam3x_dac_start(struct Dac *dac, void *_buf, size_t len, size_t slice_len)
239 ASSERT(len >= slice_len);
241 /* Reset the previous status. */
242 dac->hw->end = false;
244 sample_buff = (uint16_t *)_buf;
246 chunk_size = slice_len;
250 /* Program the dma with the first and second chunk of samples and update counter */
251 dac->ctx.callback(dac, &sample_buff[0], chunk_size);
252 DACC_TPR = (uint32_t)&sample_buff[0];
253 DACC_TCR = chunk_size;
254 remaing_size -= chunk_size;
255 next_idx += chunk_size;
257 if (chunk_size <= remaing_size)
259 dac->ctx.callback(dac, &sample_buff[next_idx], chunk_size);
261 DACC_TNPR = (uint32_t)&sample_buff[next_idx];
262 DACC_TNCR = chunk_size;
264 remaing_size -= chunk_size;
265 next_idx += chunk_size;
269 DACC_PTCR |= BV(DACC_PTCR_TXTEN);
270 DACC_IER = BV(DACC_ENDTX);
272 /* Set up timer and trig the conversions */
273 tc_setup(dac->hw->rate, len);
278 event_wait(&buff_emtpy);
282 remaing_size -= chunk_size;
283 next_idx += chunk_size;
285 if (remaing_size <= 0)
291 dac->ctx.callback(dac, &sample_buff[next_idx], chunk_size);
295 static void sam3x_dac_stop(struct Dac *dac)
297 dac->hw->end = false;
302 /* Disable the irq, timer and channel */
303 DACC_IDR = BV(DACC_ENDTX);
304 DACC_PTCR |= BV(DACC_PTCR_TXTDIS);
305 DAC_TC_CCR = BV(TC_CCR_CLKDIS);
307 event_do(&buff_emtpy);
311 void dac_init(struct Dac *dac)
313 /* Initialize the dataready event */
314 event_initGeneric(&buff_emtpy);
316 /* Fill the virtual table */
317 dac->ctx.write = sam3x_dac_write;
318 dac->ctx.setCh = sam3x_dac_setCh;
319 dac->ctx.setSampleRate = sam3x_dac_setSampleRate;
320 dac->ctx.conversion = sam3x_dac_conversion;
321 dac->ctx.isFinished = sam3x_dac_isFinished;
322 dac->ctx.start = sam3x_dac_start;
323 dac->ctx.stop = sam3x_dac_stop;
324 DB(dac->ctx._type = DAC_SAM3X;)
327 /* Clock DAC peripheral */
328 pmc_periphEnable(DACC_ID);
331 DACC_CR |= BV(DACC_SWRST);
334 /* Configure the dac */
335 DACC_MR |= (CONFIG_DAC_REFRESH << DACC_REFRESH_SHIFT) & DACC_REFRESH_MASK;
336 DACC_MR |= (CONFIG_DAC_STARTUP << DACC_STARTUP_SHIFT) & DACC_STARTUP_MASK;
338 DACC_IDR = 0xFFFFFFFF;
339 sysirq_setHandler(INT_DACC, irq_dac);