summaryrefslogtreecommitdiff
path: root/firmware/target/arm/as3525/pcm-as3525.c
diff options
context:
space:
mode:
authorMichael Sevakis <jethead71@rockbox.org>2011-12-12 20:12:22 +0000
committerMichael Sevakis <jethead71@rockbox.org>2011-12-12 20:12:22 +0000
commit184459fa54f1d3f1a6c13c6e729fa116689f225c (patch)
tree968dcda6fc2ad82e945f2ee7f750eb6873c0cc63 /firmware/target/arm/as3525/pcm-as3525.c
parent5c1e9365928592a3b54b07e008ccfb5a0656932e (diff)
downloadrockbox-184459fa54f1d3f1a6c13c6e729fa116689f225c.tar.gz
rockbox-184459fa54f1d3f1a6c13c6e729fa116689f225c.zip
Deal with a complication when transferring recording method from PP5024: since the FIFO POP is always read until empty, keep track of sample parity instead of always saving the first one in the FIFO upon entering the ISR or else the first of a duplicate that is also the last in the FIFO would get duplicated. Also, give top priority to audio interrupts in all cases.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@31218 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware/target/arm/as3525/pcm-as3525.c')
-rw-r--r--firmware/target/arm/as3525/pcm-as3525.c73
1 files changed, 42 insertions, 31 deletions
diff --git a/firmware/target/arm/as3525/pcm-as3525.c b/firmware/target/arm/as3525/pcm-as3525.c
index 8b42bbd5b2..b33ea2af84 100644
--- a/firmware/target/arm/as3525/pcm-as3525.c
+++ b/firmware/target/arm/as3525/pcm-as3525.c
@@ -81,7 +81,7 @@ static void play_start_pcm(void)
81 81
82 play_sub_size = size; 82 play_sub_size = size;
83 83
84 dma_enable_channel(1, (void*)addr, (void*)I2SOUT_DATA, DMA_PERI_I2SOUT, 84 dma_enable_channel(0, (void*)addr, (void*)I2SOUT_DATA, DMA_PERI_I2SOUT,
85 DMAC_FLOWCTRL_DMAC_MEM_TO_PERI, true, false, size >> 2, 85 DMAC_FLOWCTRL_DMAC_MEM_TO_PERI, true, false, size >> 2,
86 DMA_S1, dma_callback); 86 DMA_S1, dma_callback);
87} 87}
@@ -142,10 +142,10 @@ void pcm_play_dma_stop(void)
142{ 142{
143 is_playing = false; 143 is_playing = false;
144 144
145 dma_disable_channel(1); 145 dma_disable_channel(0);
146 146
147 /* Ensure byte counts read back 0 */ 147 /* Ensure byte counts read back 0 */
148 DMAC_CH_SRC_ADDR(1) = 0; 148 DMAC_CH_SRC_ADDR(0) = 0;
149 dma_start_addr = NULL; 149 dma_start_addr = NULL;
150 dma_start_size = 0; 150 dma_start_size = 0;
151 dma_rem_size = 0; 151 dma_rem_size = 0;
@@ -166,7 +166,7 @@ void pcm_play_dma_pause(bool pause)
166 166
167 if(pause) 167 if(pause)
168 { 168 {
169 dma_pause_channel(1); 169 dma_pause_channel(0);
170 170
171 /* if producer's buffer finished, upper layer starts anew */ 171 /* if producer's buffer finished, upper layer starts anew */
172 if (dma_rem_size == 0) 172 if (dma_rem_size == 0)
@@ -175,7 +175,7 @@ void pcm_play_dma_pause(bool pause)
175 else 175 else
176 { 176 {
177 if (play_sub_size != 0) 177 if (play_sub_size != 0)
178 dma_resume_channel(1); 178 dma_resume_channel(0);
179 /* else unlock calls the callback if sub buffers remain */ 179 /* else unlock calls the callback if sub buffers remain */
180 } 180 }
181} 181}
@@ -231,7 +231,7 @@ void pcm_dma_apply_settings(void)
231size_t pcm_get_bytes_waiting(void) 231size_t pcm_get_bytes_waiting(void)
232{ 232{
233 int oldstatus = disable_irq_save(); 233 int oldstatus = disable_irq_save();
234 size_t addr = DMAC_CH_SRC_ADDR(1); 234 size_t addr = DMAC_CH_SRC_ADDR(0);
235 size_t start_addr = (size_t)dma_start_addr; 235 size_t start_addr = (size_t)dma_start_addr;
236 size_t start_size = dma_start_size; 236 size_t start_size = dma_start_size;
237 restore_interrupt(oldstatus); 237 restore_interrupt(oldstatus);
@@ -242,7 +242,7 @@ size_t pcm_get_bytes_waiting(void)
242const void * pcm_play_dma_get_peak_buffer(int *count) 242const void * pcm_play_dma_get_peak_buffer(int *count)
243{ 243{
244 int oldstatus = disable_irq_save(); 244 int oldstatus = disable_irq_save();
245 size_t addr = DMAC_CH_SRC_ADDR(1); 245 size_t addr = DMAC_CH_SRC_ADDR(0);
246 size_t start_addr = (size_t)dma_start_addr; 246 size_t start_addr = (size_t)dma_start_addr;
247 size_t start_size = dma_start_size; 247 size_t start_size = dma_start_size;
248 restore_interrupt(oldstatus); 248 restore_interrupt(oldstatus);
@@ -269,6 +269,7 @@ void * pcm_dma_addr(void *addr)
269static int rec_locked = 0; 269static int rec_locked = 0;
270static uint32_t *rec_dma_addr; 270static uint32_t *rec_dma_addr;
271static size_t rec_dma_size; 271static size_t rec_dma_size;
272static int keep_sample = 0; /* In nonzero, keep the sample; else, discard it */
272 273
273void pcm_rec_lock(void) 274void pcm_rec_lock(void)
274{ 275{
@@ -310,32 +311,36 @@ void INT_I2SIN(void)
310 if (I2SIN_RAW_STATUS & (1<<5)) 311 if (I2SIN_RAW_STATUS & (1<<5))
311 return; /* empty */ 312 return; /* empty */
312 313
313 /* Discard every other sample since ADC clock is 1/2 LRCK */
314 uint32_t value = *I2SIN_DATA; 314 uint32_t value = *I2SIN_DATA;
315 *I2SIN_DATA;
316 315
317 /* Data is in left channel only - copy to right channel 316 /* Discard every other sample since ADC clock is 1/2 LRCK */
318 14-bit => 16-bit samples */ 317 keep_sample ^= 1;
319 value = (uint16_t)(value << 2) | (value << 18);
320 318
321 if (audio_output_source != AUDIO_SRC_PLAYBACK && !is_playing) 319 if (keep_sample)
322 { 320 {
323 /* In this case, loopback is manual so that both output 321 /* Data is in left channel only - copy to right channel
324 channels have audio */ 322 14-bit => 16-bit samples */
325 if (I2SOUT_RAW_STATUS & (1<<5)) 323 value = (uint16_t)(value << 2) | (value << 18);
324
325 if (audio_output_source != AUDIO_SRC_PLAYBACK && !is_playing)
326 { 326 {
327 /* Sync output fifo so it goes empty not before input is 327 /* In this case, loopback is manual so that both output
328 filled */ 328 channels have audio */
329 for (unsigned i = 0; i < 4; i++) 329 if (I2SOUT_RAW_STATUS & (1<<5))
330 *I2SOUT_DATA = 0; 330 {
331 /* Sync output fifo so it goes empty not before input is
332 filled */
333 for (unsigned i = 0; i < 4; i++)
334 *I2SOUT_DATA = 0;
335 }
336
337 *I2SOUT_DATA = value;
338 *I2SOUT_DATA = value;
331 } 339 }
332 340
333 *I2SOUT_DATA = value; 341 *rec_dma_addr++ = value;
334 *I2SOUT_DATA = value; 342 rec_dma_size -= 4;
335 } 343 }
336
337 *rec_dma_addr++ = value;
338 rec_dma_size -= 4;
339 } 344 }
340 } 345 }
341 else 346 else
@@ -347,15 +352,19 @@ void INT_I2SIN(void)
347 if (I2SIN_RAW_STATUS & (1<<5)) 352 if (I2SIN_RAW_STATUS & (1<<5))
348 return; /* empty */ 353 return; /* empty */
349 354
350 /* Discard every other sample since ADC clock is 1/2 LRCK */
351 uint32_t value = *I2SIN_DATA; 355 uint32_t value = *I2SIN_DATA;
352 *I2SIN_DATA;
353 356
354 /* Loopback is in I2S hardware */ 357 /* Discard every other sample since ADC clock is 1/2 LRCK */
358 keep_sample ^= 1;
359
360 if (keep_sample)
361 {
362 /* Loopback is in I2S hardware */
355 363
356 /* 14-bit => 16-bit samples */ 364 /* 14-bit => 16-bit samples */
357 *rec_dma_addr++ = (value << 2) & ~0x00030000; 365 *rec_dma_addr++ = (value << 2) & ~0x00030000;
358 rec_dma_size -= 4; 366 rec_dma_size -= 4;
367 }
359 } 368 }
360 } 369 }
361 370
@@ -389,6 +398,8 @@ void pcm_rec_dma_start(void *addr, size_t size)
389 rec_dma_addr = addr; 398 rec_dma_addr = addr;
390 rec_dma_size = size; 399 rec_dma_size = size;
391 400
401 keep_sample = 0;
402
392 /* ensure empty FIFO */ 403 /* ensure empty FIFO */
393 while (!(I2SIN_RAW_STATUS & (1<<5))) 404 while (!(I2SIN_RAW_STATUS & (1<<5)))
394 *I2SIN_DATA; 405 *I2SIN_DATA;