BeRTOS
|
00001 00038 /* 00039 * TODO: Revise the public api of this module to be more generic. Evalutate to 00040 * implement the more generic layer to be common to all I2S BeRTOS drivers. 00041 */ 00042 #include "i2s_at91.h" 00043 #include "cfg/cfg_i2s.h" 00044 00045 // Define log settings for cfg/log.h. 00046 #define LOG_LEVEL I2S_LOG_LEVEL 00047 #define LOG_FORMAT I2S_LOG_FORMAT 00048 #include <cfg/log.h> 00049 00050 #include <drv/timer.h> 00051 #include <io/arm.h> 00052 00053 #define DATALEN (15 & SSC_DATLEN_MASK) 00054 // FIXME: this is not correct for 16 <= DATALEN < 24 00055 #define PDC_DIV ((DATALEN / 8) + 1) 00056 /* 00057 * PDC_DIV must be 1, 2 or 4, which are the bytes that are transferred 00058 * each time the PDC reads from memory. 00059 */ 00060 STATIC_ASSERT(PDC_DIV % 2 == 0); 00061 #define PDC_COUNT (CONFIG_PLAY_BUF_LEN / PDC_DIV) 00062 00063 static uint8_t play_buf1[CONFIG_PLAY_BUF_LEN]; 00064 static uint8_t play_buf2[CONFIG_PLAY_BUF_LEN]; 00065 00066 // the buffer in PDC next is play_buf2 00067 volatile bool is_second_buf_next; 00068 00069 uint8_t *i2s_getBuffer(unsigned buf_num) 00070 { 00071 LOG_INFO("getBuffer start\n"); 00072 00073 if (i2s_isPlaying()) 00074 { 00075 ASSERT(0); 00076 return 0; 00077 } 00078 00079 if (buf_num == I2S_SECOND_BUF) 00080 return play_buf2; 00081 else if (buf_num == I2S_FIRST_BUF) 00082 return play_buf1; 00083 else 00084 return 0; 00085 } 00086 00087 uint8_t *i2s_getFreeBuffer(void) 00088 { 00089 if (!i2s_isPlaying()) 00090 { 00091 ASSERT(0); 00092 return 0; 00093 } 00094 00095 // wait PDC transmission end 00096 if (!(SSC_SR & BV(SSC_ENDTX))) 00097 return 0; 00098 00099 uint8_t *ret_buf = 0; 00100 // the last time we got called, the second buffer was in PDC next 00101 if (is_second_buf_next) 00102 { 00103 is_second_buf_next = false; 00104 ret_buf = play_buf1; 00105 } 00106 // the last time the first buffer was in PDC next 00107 else 00108 { 00109 is_second_buf_next = true; 00110 ret_buf = play_buf2; 00111 } 00112 00113 if (ret_buf) 00114 { 00115 SSC_TNPR = (reg32_t) ret_buf; 00116 SSC_TNCR = PDC_COUNT; 00117 } 00118 return ret_buf; 00119 } 00120 00121 bool i2s_start(void) 00122 { 00123 /* Some time must pass between disabling and enabling again the transmission 00124 * on SSC. A good empirical value seems >15 us. We try to avoid putting an 00125 * explicit delay, instead we disable the transmitter when a sound finishes 00126 * and hope that the delay has passed before we enter here again. 00127 */ 00128 SSC_CR = BV(SSC_TXDIS); 00129 timer_delay(10); 00130 00131 SSC_PTCR = BV(PDC_TXTDIS); 00132 SSC_TPR = (reg32_t)play_buf1; 00133 SSC_TCR = PDC_COUNT; 00134 SSC_TNPR = (reg32_t)play_buf2; 00135 SSC_TNCR = PDC_COUNT; 00136 is_second_buf_next = true; 00137 00138 SSC_PTCR = BV(PDC_TXTEN); 00139 00140 /* enable output */ 00141 SSC_CR = BV(SSC_TXEN); 00142 00143 return true; 00144 } 00145 00146 #define BITS_PER_CHANNEL 16 00147 #define N_OF_CHANNEL 2 00148 // TODO: check the computed value? 00149 /* The last parameter (2) is due to the hadware on at91sam7s. */ 00150 #define MCK_DIV (CPU_FREQ / CONFIG_SAMPLE_FREQ / BITS_PER_CHANNEL / N_OF_CHANNEL / 2) 00151 00152 #define CONFIG_DELAY 1 00153 #define CONFIG_PERIOD 15 00154 #define CONFIG_DATNB 1 00155 #define CONFIG_FSLEN 15 00156 00157 #define DELAY ((CONFIG_DELAY << SSC_STTDLY_SHIFT) & SSC_STTDLY_MASK) 00158 #define PERIOD ((CONFIG_PERIOD << (SSC_PERIOD_SHIFT)) & SSC_PERIOD_MASK) 00159 #define DATNB ((CONFIG_DATNB << SSC_DATNB_SHIFT) & SSC_DATNB_MASK) 00160 #define FSLEN ((CONFIG_FSLEN << SSC_FSLEN_SHIFT) & SSC_FSLEN_MASK) 00161 00162 #define SSC_DMA_IRQ_PRIORITY 5 00163 00164 void i2s_init(void) 00165 { 00166 PIOA_PDR = BV(SSC_TK) | BV(SSC_TF) | BV(SSC_TD); 00167 /* reset device */ 00168 SSC_CR = BV(SSC_SWRST); 00169 00170 SSC_CMR = MCK_DIV & SSC_DIV_MASK; 00171 SSC_TCMR = SSC_CKS_DIV | SSC_CKO_CONT | SSC_CKG_NONE | DELAY | PERIOD | SSC_START_FALL_F; 00172 SSC_TFMR = DATALEN | DATNB | FSLEN | BV(SSC_MSBF) | SSC_FSOS_NEGATIVE; 00173 00174 /* Disable all irqs */ 00175 SSC_IDR = 0xFFFFFFFF; 00176 00177 /* Enable the SSC IRQ */ 00178 AIC_IECR = BV(SSC_ID); 00179 00180 /* enable i2s */ 00181 PMC_PCER = BV(SSC_ID); 00182 00183 /* Enable SSC */ 00184 SSC_CR = BV(SSC_TXEN); 00185 }