X-Git-Url: https://codewiz.org/gitweb?a=blobdiff_plain;f=bertos%2Fcpu%2Fcortex-m3%2Fdrv%2Fdac_sam3.c;h=b10ff62c9e56c7991a9d10c5418d3289f8d28bb6;hb=f725c29420c27b7e094f09480013dd1ce2d87ec4;hp=e4e7e9a94f4376ceeaae3431e96424560d833b00;hpb=5bf1dca59b570a3ffead03860301abc5e14e41e0;p=bertos.git diff --git a/bertos/cpu/cortex-m3/drv/dac_sam3.c b/bertos/cpu/cortex-m3/drv/dac_sam3.c index e4e7e9a9..b10ff62c 100644 --- a/bertos/cpu/cortex-m3/drv/dac_sam3.c +++ b/bertos/cpu/cortex-m3/drv/dac_sam3.c @@ -35,6 +35,7 @@ * \author Daniele Basile */ +#include "dac_sam3.h" #include "cfg/cfg_dac.h" @@ -47,29 +48,191 @@ #include #include +#include + +#include + #include -int dac_write(int ch, buf, len) +#include + +struct DacHardware +{ + uint16_t channels; + uint32_t rate; + bool end; +}; + +struct DacHardware dac_hw; + +#if CONFIG_DAC_TIMER == DACC_TRGSEL_TIO_CH0 /* Select Timer counter TIO Channel 0 */ + #define DAC_TC_ID TC0_ID + #define DAC_TC_CCR TC0_CCR0 + #define DAC_TC_IDR TC0_IDR0 + #define DAC_TC_CMR TC0_CMR0 + #define DAC_TC_SR TC0_SR0 + #define DAC_TC_RA TC0_RA0 + #define DAC_TC_RC TC0_RC0 +#elif CONFIG_DAC_TIMER == DACC_TRGSEL_TIO_CH1 /* Select Timer counter TIO Channel 1 */ + #define DAC_TC_ID TC1_ID + #define DAC_TC_CCR TC0_CCR1 + #define DAC_TC_IDR TC0_IDR1 + #define DAC_TC_CMR TC0_CMR1 + #define DAC_TC_SR TC0_SR1 + #define DAC_TC_RA TC0_RA1 + #define DAC_TC_RC TC0_RC1 +#elif CONFIG_DAC_TIMER == DACC_TRGSEL_TIO_CH2 /* Select Timer counter TIO Channel 2 */ + #define DAC_TC_ID TC2_ID + #define DAC_TC_CCR TC0_CCR2 + #define DAC_TC_IDR TC0_IDR2 + #define DAC_TC_CMR TC0_CMR2 + #define DAC_TC_SR TC0_SR2 + #define DAC_TC_RA TC0_RA2 + #define DAC_TC_RC TC0_RC2 +#elif CONFIG_DAC_TIMER == DACC_TRGSEL_PWM0 || CONFIG_DAC_TIMER == DACC_TRGSEL_PWM1 + #error unimplemented pwm triger select. +#endif + +INLINE void tc_setup(uint32_t freq, size_t n_sample) +{ + pmc_periphEnable(DAC_TC_ID); + + /* Disable TC clock */ + DAC_TC_CCR = TC_CCR_CLKDIS; + /* Disable interrupts */ + DAC_TC_IDR = 0xFFFFFFFF; + /* Clear status register */ + volatile uint32_t dummy = DAC_TC_SR; + (void)dummy; + + /* + * Setup the timer counter: + * - select clock TCLK1 (MCK/2) + * - enable wave form mode + * - RA compare effect SET + * - RC compare effect CLEAR + * - UP mode with automatic trigger on RC Compare + */ + DAC_TC_CMR = TC_TIMER_CLOCK1 | BV(TC_CMR_WAVE) | TC_CMR_ACPA_SET | TC_CMR_ACPC_CLEAR | BV(TC_CMR_CPCTRG); + + /* + * Compute the sample frequency + * the RC counter will update every MCK/2 (see above) + * so to convert one sample at the user freq we generate + * the trigger every TC_CLK / (numer_of_sample * user_freq) + * where TC_CLK = MCK / 2. + */ + uint32_t rc = DIV_ROUND((CPU_FREQ / 2), n_sample * freq); + DAC_TC_RC = rc; + /* generate the square wave with duty = 50% */ + DAC_TC_RA = DIV_ROUND(50 * rc, 100); + + PIOB_PDR = BV(25); + PIO_PERIPH_SEL(PIOB_BASE, BV(25), PIO_PERIPH_B); +} + +INLINE void tc_start(void) +{ + DAC_TC_CCR = BV(TC_CCR_CLKEN)| BV(TC_CCR_SWTRG); +} + +INLINE void tc_stop(void) +{ + DAC_TC_CCR = BV(TC_CCR_CLKDIS); +} + +static int sam3x_dac_write(struct Dac *dac, unsigned channel, uint16_t sample) +{ + (void)dac; + + ASSERT(channel <= DAC_MAXCH); + + DACC_MR |= (channel << DACC_USER_SEL_SHIFT) & DACC_USER_SEL_MASK; + DACC_CHER |= BV(channel); + + DACC_CDR = sample ; + + return 0; +} + +static void sam3x_dac_setCh(struct Dac *dac, uint32_t mask) +{ + /* we have only the ch0 and ch1 */ + ASSERT(mask < BV(3)); + dac->hw->channels = mask; +} + +static void sam3x_dac_setSampleRate(struct Dac *dac, uint32_t rate) +{ + (void)dac; + + /* Eneble hw trigger */ + DACC_MR |= BV(DACC_TRGEN) | (CONFIG_DAC_TIMER << DACC_TRGSEL_SHIFT); + dac->hw->rate = rate; +} + +static void sam3x_dac_conversion(struct Dac *dac, void *buf, size_t len) +{ + if (dac->hw->channels & BV(DACC_CH0)) + DACC_MR |= (DACC_CH0 << DACC_USER_SEL_SHIFT) & DACC_USER_SEL_MASK; + + if (dac->hw->channels & BV(DACC_CH1)) + DACC_MR |= (DACC_CH1 << DACC_USER_SEL_SHIFT) & DACC_USER_SEL_MASK; + + DACC_CHER |= dac->hw->channels; + + /* setup timer and start it */ + tc_setup(dac->hw->rate, len); + tc_start(); + + /* Setup dma and start it */ + DACC_TPR = (uint32_t)buf ; + DACC_TCR = len; + DACC_PTCR |= BV(DACC_PTCR_TXTEN); +} + +static bool sam3x_dac_isFinished(struct Dac *dac) { + (void)dac; return 0; } -void dac_init(void) +static void sam3x_dac_start(struct Dac *dac, void *buf, size_t len, size_t slice_len) { - /* Clock ADC peripheral */ + (void)dac; + (void)buf; + (void)len; + (void)slice_len; +} + +static void sam3x_dac_stop(struct Dac *dac) +{ + (void)dac; +} + + +void dac_init(struct Dac *dac) +{ + + /* Fill the virtual table */ + dac->ctx.write = sam3x_dac_write; + dac->ctx.setCh = sam3x_dac_setCh; + dac->ctx.setSampleRate = sam3x_dac_setSampleRate; + dac->ctx.conversion = sam3x_dac_conversion; + dac->ctx.isFinished = sam3x_dac_isFinished; + dac->ctx.start = sam3x_dac_start; + dac->ctx.stop = sam3x_dac_stop; + dac->ctx._type = DAC_SAM3X; + dac->hw = &dac_hw; + + /* Clock DAC peripheral */ pmc_periphEnable(DACC_ID); + /* Reset hw */ DACC_CR |= BV(DACC_SWRST); DACC_MR = 0; - /* Refresh period */ - DACC_MR |= (16 << DACC_REFRESH_SHIFT) & DACC_REFRESH_MASK; - /* Select channel */ - DACC_MR |= (DACC_CH1 << DACC_USER_SEL_SHIFT) & DACC_USER_SEL_MASK; - /* Start up */ - DACC_MR |= (DACC_MR_STARTUP_0 << DACC_STARTUP_SHIFT) & DACC_STARTUP_MASK; - - kprintf("mr: %08lx\n", DACC_MR); - /* Register and enable irq for adc. */ - sysirq_setHandler(INT_DACC, dac); + /* Configure the dac */ + DACC_MR |= (CONFIG_DAC_REFRESH << DACC_REFRESH_SHIFT) & DACC_REFRESH_MASK; + DACC_MR |= (CONFIG_DAC_STARTUP << DACC_STARTUP_SHIFT) & DACC_STARTUP_MASK; }