dac_sam3.c

Go to the documentation of this file.
00001 
00038 #include "dac_sam3.h"
00039 
00040 #include "cfg/cfg_dac.h"
00041 
00042 #include <cfg/macros.h>
00043 #include <cfg/compiler.h>
00044 
00045 // Define log settings for cfg/log.h.
00046 #define LOG_LEVEL         DAC_LOG_LEVEL
00047 #define LOG_FORMAT        DAC_LOG_FORMAT
00048 #include <cfg/log.h>
00049 
00050 #include <drv/dac.h>
00051 #include <cpu/irq.h>
00052 #include <drv/irq_cm3.h>
00053 
00054 #include <cpu/types.h>
00055 
00056 #include <mware/event.h>
00057 
00058 #include <io/cm3.h>
00059 
00060 #include <string.h>
00061 
00062 struct DacHardware
00063 {
00064     uint16_t channels;
00065     uint32_t rate;
00066     bool end;
00067 };
00068 
00069 struct DacHardware dac_hw;
00070 
00071 
00072 /* We use event to signal the end of conversion */
00073 static Event buff_emtpy;
00074 
00075 #if CONFIG_DAC_TIMER == DACC_TRGSEL_TIO_CH0 /* Select Timer counter TIO Channel 0 */
00076     #define DAC_TC_ID         TC0_ID
00077     #define DAC_TC_CCR        TC0_CCR0
00078     #define DAC_TC_IDR        TC0_IDR0
00079     #define DAC_TC_CMR        TC0_CMR0
00080     #define DAC_TC_SR         TC0_SR0
00081     #define DAC_TC_RA         TC0_RA0
00082     #define DAC_TC_RC         TC0_RC0
00083 #elif CONFIG_DAC_TIMER == DACC_TRGSEL_TIO_CH1 /* Select Timer counter TIO Channel 1 */
00084     #define DAC_TC_ID         TC1_ID
00085     #define DAC_TC_CCR        TC0_CCR1
00086     #define DAC_TC_IDR        TC0_IDR1
00087     #define DAC_TC_CMR        TC0_CMR1
00088     #define DAC_TC_SR         TC0_SR1
00089     #define DAC_TC_RA         TC0_RA1
00090     #define DAC_TC_RC         TC0_RC1
00091 #elif CONFIG_DAC_TIMER == DACC_TRGSEL_TIO_CH2 /* Select Timer counter TIO Channel 2 */
00092     #define DAC_TC_ID         TC2_ID
00093     #define DAC_TC_CCR        TC0_CCR2
00094     #define DAC_TC_IDR        TC0_IDR2
00095     #define DAC_TC_CMR        TC0_CMR2
00096     #define DAC_TC_SR         TC0_SR2
00097     #define DAC_TC_RA         TC0_RA2
00098     #define DAC_TC_RC         TC0_RC2
00099 #elif CONFIG_DAC_TIMER == DACC_TRGSEL_PWM0 || CONFIG_DAC_TIMER == DACC_TRGSEL_PWM1
00100     #error unimplemented pwm triger select.
00101 #endif
00102 
00103 
00104 INLINE void tc_init(void)
00105 {
00106     pmc_periphEnable(DAC_TC_ID);
00107 
00108     /*  Disable TC clock */
00109     DAC_TC_CCR = BV(TC_CCR_CLKDIS);
00110     /*  Disable interrupts */
00111     DAC_TC_IDR = 0xFFFFFFFF;
00112     /*  Clear status register */
00113     volatile uint32_t dummy = DAC_TC_SR;
00114     (void)dummy;
00115 
00116     /*
00117      * Setup the timer counter:
00118      * - select clock TCLK1 (MCK/2)
00119      * - enable wave form mode
00120      * - RA compare effect SET
00121      * - RC compare effect CLEAR
00122      * - UP mode with automatic trigger on RC Compare
00123      */
00124     DAC_TC_CMR = TC_TIMER_CLOCK1 | BV(TC_CMR_WAVE) | TC_CMR_ACPA_SET | TC_CMR_ACPC_CLEAR | BV(TC_CMR_CPCTRG);
00125 
00126 
00127     /* Setup the pio: TODO: fix for more generic */
00128     PIOB_PDR = BV(25);
00129     PIO_PERIPH_SEL(PIOB_BASE, BV(25), PIO_PERIPH_B);
00130 }
00131 
00132 INLINE void tc_setup(uint32_t freq, size_t n_sample)
00133 {
00134     /*
00135      * Compute the sample frequency
00136      * the RC counter will update every MCK/2 (see above)
00137      * so to convert one sample at the user freq we generate
00138      * the trigger every TC_CLK / (numer_of_sample * user_freq)
00139      * where TC_CLK = MCK / 2.
00140      */
00141     uint32_t rc = DIV_ROUND((CPU_FREQ / 2), n_sample * freq);
00142     DAC_TC_RC = rc;
00143     /* generate the square wave with duty = 50% */
00144     DAC_TC_RA = DIV_ROUND(50 * rc, 100);
00145 }
00146 
00147 INLINE void tc_start(void)
00148 {
00149     DAC_TC_CCR = BV(TC_CCR_CLKEN)| BV(TC_CCR_SWTRG);
00150 }
00151 
00152 INLINE void tc_stop(void)
00153 {
00154     DAC_TC_CCR =  BV(TC_CCR_CLKDIS);
00155 }
00156 
00157 static int sam3x_dac_write(struct Dac *dac, unsigned channel, uint16_t sample)
00158 {
00159     (void)dac;
00160 
00161     ASSERT(channel <= DAC_MAXCH);
00162 
00163     DACC_MR |= (channel << DACC_USER_SEL_SHIFT) & DACC_USER_SEL_MASK;
00164     DACC_CHER |= BV(channel);
00165 
00166     DACC_CDR = sample ;
00167 
00168     return 0;
00169 }
00170 
00171 static void sam3x_dac_setCh(struct Dac *dac, uint32_t mask)
00172 {
00173     /* we have only the ch0 and ch1 */
00174     ASSERT(mask < BV(3));
00175     dac->hw->channels = mask;
00176 
00177     if (mask & BV(DACC_CH0))
00178         DACC_MR |= (DACC_CH0 << DACC_USER_SEL_SHIFT) & DACC_USER_SEL_MASK;
00179 
00180     if (mask & BV(DACC_CH1))
00181         DACC_MR |= (DACC_CH1 << DACC_USER_SEL_SHIFT) & DACC_USER_SEL_MASK;
00182 
00183     DACC_CHER |= mask;
00184 
00185 }
00186 
00187 static void sam3x_dac_setSampleRate(struct Dac *dac, uint32_t rate)
00188 {
00189     /* Eneble hw trigger */
00190     DACC_MR |= BV(DACC_TRGEN) | (CONFIG_DAC_TIMER << DACC_TRGSEL_SHIFT);
00191     dac->hw->rate = rate;
00192 }
00193 
00194 static void sam3x_dac_conversion(struct Dac *dac, void *buf, size_t len)
00195 {
00196     /* setup timer and start it */
00197     tc_setup(dac->hw->rate, len);
00198     tc_start();
00199 
00200     /* Setup dma and start it */
00201     DACC_TPR = (uint32_t)buf;
00202     DACC_TCR = len;
00203     DACC_PTCR |= BV(DACC_PTCR_TXTEN);
00204 }
00205 
00206 static uint16_t *sample_buff;
00207 static size_t next_idx = 0;
00208 static size_t chunk_size = 0;
00209 static size_t remaing_size = 0;
00210 
00211 static DECLARE_ISR(irq_dac)
00212 {
00213     if (DACC_ISR & BV(DACC_ENDTX))
00214     {
00215         if (remaing_size > 0)
00216         {
00217             DACC_TNPR = (uint32_t)&sample_buff[next_idx];
00218             DACC_TNCR = chunk_size;
00219 
00220             remaing_size -= chunk_size;
00221             next_idx += chunk_size;
00222         }
00223         else
00224             /* Clear the pending irq when the dma ends the conversion */
00225             DACC_TCR = 1;
00226     }
00227     event_do(&buff_emtpy);
00228 }
00229 
00230 
00231 static bool sam3x_dac_isFinished(struct Dac *dac)
00232 {
00233     return dac->hw->end;
00234 }
00235 
00236 static void sam3x_dac_start(struct Dac *dac, void *_buf, size_t len, size_t slice_len)
00237 {
00238     ASSERT(dac);
00239     ASSERT(len >= slice_len);
00240 
00241     /* Reset the previous status. */
00242     dac->hw->end = false;
00243 
00244     sample_buff = (uint16_t *)_buf;
00245     next_idx = 0;
00246     chunk_size = slice_len;
00247     remaing_size = len;
00248 
00249 
00250     /* Program the dma with the first and second chunk of samples and update counter */
00251     dac->ctx.callback(dac, &sample_buff[0], chunk_size);
00252     DACC_TPR = (uint32_t)&sample_buff[0];
00253     DACC_TCR = chunk_size;
00254     remaing_size -= chunk_size;
00255     next_idx += chunk_size;
00256 
00257     if (chunk_size <= remaing_size)
00258     {
00259         dac->ctx.callback(dac, &sample_buff[next_idx], chunk_size);
00260 
00261         DACC_TNPR = (uint32_t)&sample_buff[next_idx];
00262         DACC_TNCR = chunk_size;
00263 
00264         remaing_size -= chunk_size;
00265         next_idx += chunk_size;
00266 
00267     }
00268 
00269     DACC_PTCR |= BV(DACC_PTCR_TXTEN);
00270     DACC_IER = BV(DACC_ENDTX);
00271 
00272     /* Set up timer and trig the conversions */
00273     tc_setup(dac->hw->rate, len);
00274     tc_start();
00275 
00276     while (1)
00277     {
00278         event_wait(&buff_emtpy);
00279         if (remaing_size <= 0)
00280         {
00281             DAC_TC_CCR = BV(TC_CCR_CLKDIS);
00282             dac->hw->end = true;
00283             next_idx = 0;
00284             chunk_size = 0;
00285             remaing_size = 0;
00286             break;
00287         }
00288 
00289         dac->ctx.callback(dac, &sample_buff[next_idx], chunk_size);
00290     }
00291 }
00292 
00293 static void sam3x_dac_stop(struct Dac *dac)
00294 {
00295     dac->hw->end = false;
00296     /* Disable the irq, timer and channel */
00297     DACC_IDR = BV(DACC_ENDTX);
00298     DACC_PTCR |= BV(DACC_PTCR_TXTDIS);
00299     DAC_TC_CCR = BV(TC_CCR_CLKDIS);
00300 }
00301 
00302 
00303 void dac_init(struct Dac *dac)
00304 {
00305     /* Initialize the dataready event */
00306     event_initGeneric(&buff_emtpy);
00307 
00308     /* Fill the virtual table */
00309     dac->ctx.write = sam3x_dac_write;
00310     dac->ctx.setCh = sam3x_dac_setCh;
00311     dac->ctx.setSampleRate = sam3x_dac_setSampleRate;
00312     dac->ctx.conversion = sam3x_dac_conversion;
00313     dac->ctx.isFinished = sam3x_dac_isFinished;
00314     dac->ctx.start = sam3x_dac_start;
00315     dac->ctx.stop = sam3x_dac_stop;
00316     DB(dac->ctx._type = DAC_SAM3X;)
00317     dac->hw = &dac_hw;
00318 
00319     /* Clock DAC peripheral */
00320     pmc_periphEnable(DACC_ID);
00321 
00322     /* Reset hw */
00323     DACC_CR |= BV(DACC_SWRST);
00324     DACC_MR = 0;
00325 
00326     /* Configure the dac */
00327     DACC_MR |= (CONFIG_DAC_REFRESH << DACC_REFRESH_SHIFT) & DACC_REFRESH_MASK;
00328     DACC_MR |= (CONFIG_DAC_STARTUP << DACC_STARTUP_SHIFT) & DACC_STARTUP_MASK;
00329 
00330     DACC_IDR = 0xFFFFFFFF;
00331     sysirq_setHandler(INT_DACC, irq_dac);
00332 
00333     tc_init();
00334 }