From: asterix Date: Fri, 15 Jul 2011 16:34:48 +0000 (+0000) Subject: Clean up and write the first implementation of i2s module for sam3x. X-Git-Url: https://codewiz.org/gitweb?a=commitdiff_plain;h=96be1ede92aff695163ee31f12b9a01a4198a826;p=bertos.git Clean up and write the first implementation of i2s module for sam3x. git-svn-id: https://src.develer.com/svnoss/bertos/trunk@4972 38d2e660-2303-0410-9eaa-f027e97ec537 --- diff --git a/bertos/cpu/cortex-m3/drv/i2s_sam3.c b/bertos/cpu/cortex-m3/drv/i2s_sam3.c index 8a35c581..129c9494 100644 --- a/bertos/cpu/cortex-m3/drv/i2s_sam3.c +++ b/bertos/cpu/cortex-m3/drv/i2s_sam3.c @@ -54,67 +54,27 @@ #include + + #define DATALEN (15 & SSC_DATLEN_MASK) -// FIXME: this is not correct for 16 <= DATALEN < 24 -#define PDC_DIV ((DATALEN / 8) + 1) -/* - * PDC_DIV must be 1, 2 or 4, which are the bytes that are transferred - * each time the PDC reads from memory. - */ -STATIC_ASSERT(PDC_DIV % 2 == 0); -#define PDC_COUNT (CONFIG_PLAY_BUF_LEN / PDC_DIV) +#define BITS_PER_CHANNEL 16 +#define N_OF_CHANNEL 2 +// TODO: check the computed value? +/* The last parameter (2) is due to the hadware on at91sam7s. */ +#define MCK_DIV (CPU_FREQ / (44100 * BITS_PER_CHANNEL * N_OF_CHANNEL* 2)) -static uint8_t play_buf1[CONFIG_PLAY_BUF_LEN]; -static uint8_t play_buf2[CONFIG_PLAY_BUF_LEN]; +#define CONFIG_DELAY 0 +#define CONFIG_PERIOD 15 +#define CONFIG_DATNB 1 +#define CONFIG_FSLEN 15 -// the buffer in PDC next is play_buf2 -volatile bool is_second_buf_next; -uint8_t *i2s_getBuffer(unsigned buf_num) -{ - LOG_INFO("getBuffer start\n"); - - if (i2s_isPlaying()) - { - ASSERT(0); - return 0; - } - - if (buf_num == I2S_SECOND_BUF) - return play_buf2; - else if (buf_num == I2S_FIRST_BUF) - return play_buf1; - else - return 0; -} +#define DELAY ((CONFIG_DELAY << SSC_STTDLY_SHIFT) & SSC_STTDLY_MASK) +#define PERIOD ((CONFIG_PERIOD << (SSC_PERIOD_SHIFT)) & SSC_PERIOD_MASK) +#define DATNB ((CONFIG_DATNB << SSC_DATNB_SHIFT) & SSC_DATNB_MASK) +#define FSLEN ((CONFIG_FSLEN << SSC_FSLEN_SHIFT) & SSC_FSLEN_MASK) + -uint8_t *i2s_getFreeBuffer(void) -{ - // wait PDC transmission end - if (!(SSC_SR & BV(SSC_ENDTX))) - return 0; - - uint8_t *ret_buf = 0; - // the last time we got called, the second buffer was in PDC next - if (is_second_buf_next) - { - is_second_buf_next = false; - ret_buf = play_buf1; - } - // the last time the first buffer was in PDC next - else - { - is_second_buf_next = true; - ret_buf = play_buf2; - } - - if (ret_buf) - { - SSC_TNPR = (reg32_t) ret_buf; - SSC_TNCR = PDC_COUNT; - } - return ret_buf; -} void i2s_stop(void) { @@ -124,22 +84,6 @@ void i2s_stop(void) bool i2s_start(void) { - /* Some time must pass between disabling and enabling again the transmission - * on SSC. A good empirical value seems >15 us. We try to avoid putting an - * explicit delay, instead we disable the transmitter when a sound finishes - * and hope that the delay has passed before we enter here again. - */ - SSC_CR = BV(SSC_TXDIS); - timer_delay(10); - - SSC_PTCR = BV(PDC_PTCR_TXTDIS); - SSC_TPR = (reg32_t)play_buf1; - SSC_TCR = PDC_COUNT; - SSC_TNPR = (reg32_t)play_buf2; - SSC_TNCR = PDC_COUNT; - is_second_buf_next = true; - - SSC_PTCR = BV(PDC_PTSR_TXTEN); /* enable output */ SSC_CR = BV(SSC_TXEN); @@ -147,24 +91,6 @@ bool i2s_start(void) return true; } -#define BITS_PER_CHANNEL 16 -#define N_OF_CHANNEL 2 -// TODO: check the computed value? -/* The last parameter (2) is due to the hadware on at91sam7s. */ -#define MCK_DIV (CPU_FREQ / CONFIG_SAMPLE_FREQ / BITS_PER_CHANNEL / N_OF_CHANNEL / 2) - -#define CONFIG_DELAY 1 -#define CONFIG_PERIOD 15 -#define CONFIG_DATNB 1 -#define CONFIG_FSLEN 15 - -#define DELAY ((CONFIG_DELAY << SSC_STTDLY_SHIFT) & SSC_STTDLY_MASK) -#define PERIOD ((CONFIG_PERIOD << (SSC_PERIOD_SHIFT)) & SSC_PERIOD_MASK) -#define DATNB ((CONFIG_DATNB << SSC_DATNB_SHIFT) & SSC_DATNB_MASK) -#define FSLEN ((CONFIG_FSLEN << SSC_FSLEN_SHIFT) & SSC_FSLEN_MASK) - -#define SSC_DMA_IRQ_PRIORITY 5 - static DECLARE_ISR(irq_ssc) { @@ -172,11 +98,12 @@ static DECLARE_ISR(irq_ssc) void i2s_init(void) { - SSC_PIO_PDR = BV(SSC_TK) | BV(SSC_TF) | BV(SSC_TD); - PIO_PERIPH_SEL(SSC_PORT, BV(SSC_TK) | BV(SSC_TF) | BV(SSC_TD), SSC_TRAN_PERIPH); + PIOA_PDR = BV(SSC_TK) | BV(SSC_TF) | BV(SSC_TD); + PIO_PERIPH_SEL(SSC_PORT, BV(SSC_TK) | BV(SSC_TF) | BV(SSC_TD), PIO_PERIPH_B); + pmc_periphEnable(SSC_ID); /* reset device */ - SSC_CR = BV(SSC_SWRST); + SSC_CR = BV(SSC_SWRST) | BV(SSC_TXDIS) | BV(SSC_RXDIS); /* Set transmission clock */ SSC_CMR = MCK_DIV & SSC_DIV_MASK; @@ -188,7 +115,7 @@ void i2s_init(void) * - generate frame sync each 2*(PERIOD + 1) tramit clock * - Receive start on falling edge RF */ - SSC_TCMR = SSC_CKS_DIV | SSC_CKO_TRAN | SSC_CKG_NONE | DELAY | PERIOD | SSC_START_FALL_F; + SSC_TCMR = SSC_CKS_DIV | SSC_CKO_CONT | SSC_CKG_NONE | DELAY | PERIOD | SSC_START_FALL_F; /* Set the transmission frame mode: * - data len DATALEN + 1 * - word per frame DATNB + 1 @@ -197,14 +124,5 @@ void i2s_init(void) * - MSB * - Frame sync output selection negative */ - SSC_TFMR = DATALEN | DATNB | FSLEN | BV(SSC_MSBF) | SSC_FSOS_NEGATIVE; - - SSC_IDR = 0xFFFFFFFF; - sysirq_setHandler(INT_SSC, irq_ssc); - - /* Clock DAC peripheral */ - pmc_periphEnable(SSC_ID); - - /* Enable SSC */ - SSC_CR = BV(SSC_TXEN); + SSC_TFMR = DATALEN | DATNB | FSLEN | BV(SSC_MSBF) | SSC_FSOS_POSITIVE; }