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
This commit is contained in:
Michael Sevakis 2011-12-12 20:12:22 +00:00
parent 5c1e936592
commit 184459fa54
5 changed files with 53 additions and 42 deletions

View file

@ -137,7 +137,7 @@ void INT_DMAC(void)
{ {
unsigned int channel; unsigned int channel;
/* SD channel is serviced first */ /* Lowest channel index is serviced first */
for(channel = 0; channel < 2; channel++) for(channel = 0; channel < 2; channel++)
if(DMAC_INT_STATUS & (1<<channel)) if(DMAC_INT_STATUS & (1<<channel))
{ {

View file

@ -81,7 +81,7 @@ static void play_start_pcm(void)
play_sub_size = size; play_sub_size = size;
dma_enable_channel(1, (void*)addr, (void*)I2SOUT_DATA, DMA_PERI_I2SOUT, dma_enable_channel(0, (void*)addr, (void*)I2SOUT_DATA, DMA_PERI_I2SOUT,
DMAC_FLOWCTRL_DMAC_MEM_TO_PERI, true, false, size >> 2, DMAC_FLOWCTRL_DMAC_MEM_TO_PERI, true, false, size >> 2,
DMA_S1, dma_callback); DMA_S1, dma_callback);
} }
@ -142,10 +142,10 @@ void pcm_play_dma_stop(void)
{ {
is_playing = false; is_playing = false;
dma_disable_channel(1); dma_disable_channel(0);
/* Ensure byte counts read back 0 */ /* Ensure byte counts read back 0 */
DMAC_CH_SRC_ADDR(1) = 0; DMAC_CH_SRC_ADDR(0) = 0;
dma_start_addr = NULL; dma_start_addr = NULL;
dma_start_size = 0; dma_start_size = 0;
dma_rem_size = 0; dma_rem_size = 0;
@ -166,7 +166,7 @@ void pcm_play_dma_pause(bool pause)
if(pause) if(pause)
{ {
dma_pause_channel(1); dma_pause_channel(0);
/* if producer's buffer finished, upper layer starts anew */ /* if producer's buffer finished, upper layer starts anew */
if (dma_rem_size == 0) if (dma_rem_size == 0)
@ -175,7 +175,7 @@ void pcm_play_dma_pause(bool pause)
else else
{ {
if (play_sub_size != 0) if (play_sub_size != 0)
dma_resume_channel(1); dma_resume_channel(0);
/* else unlock calls the callback if sub buffers remain */ /* else unlock calls the callback if sub buffers remain */
} }
} }
@ -231,7 +231,7 @@ void pcm_dma_apply_settings(void)
size_t pcm_get_bytes_waiting(void) size_t pcm_get_bytes_waiting(void)
{ {
int oldstatus = disable_irq_save(); int oldstatus = disable_irq_save();
size_t addr = DMAC_CH_SRC_ADDR(1); size_t addr = DMAC_CH_SRC_ADDR(0);
size_t start_addr = (size_t)dma_start_addr; size_t start_addr = (size_t)dma_start_addr;
size_t start_size = dma_start_size; size_t start_size = dma_start_size;
restore_interrupt(oldstatus); restore_interrupt(oldstatus);
@ -242,7 +242,7 @@ size_t pcm_get_bytes_waiting(void)
const void * pcm_play_dma_get_peak_buffer(int *count) const void * pcm_play_dma_get_peak_buffer(int *count)
{ {
int oldstatus = disable_irq_save(); int oldstatus = disable_irq_save();
size_t addr = DMAC_CH_SRC_ADDR(1); size_t addr = DMAC_CH_SRC_ADDR(0);
size_t start_addr = (size_t)dma_start_addr; size_t start_addr = (size_t)dma_start_addr;
size_t start_size = dma_start_size; size_t start_size = dma_start_size;
restore_interrupt(oldstatus); restore_interrupt(oldstatus);
@ -269,6 +269,7 @@ void * pcm_dma_addr(void *addr)
static int rec_locked = 0; static int rec_locked = 0;
static uint32_t *rec_dma_addr; static uint32_t *rec_dma_addr;
static size_t rec_dma_size; static size_t rec_dma_size;
static int keep_sample = 0; /* In nonzero, keep the sample; else, discard it */
void pcm_rec_lock(void) void pcm_rec_lock(void)
{ {
@ -310,32 +311,36 @@ void INT_I2SIN(void)
if (I2SIN_RAW_STATUS & (1<<5)) if (I2SIN_RAW_STATUS & (1<<5))
return; /* empty */ return; /* empty */
/* Discard every other sample since ADC clock is 1/2 LRCK */
uint32_t value = *I2SIN_DATA; uint32_t value = *I2SIN_DATA;
*I2SIN_DATA;
/* Data is in left channel only - copy to right channel /* Discard every other sample since ADC clock is 1/2 LRCK */
14-bit => 16-bit samples */ keep_sample ^= 1;
value = (uint16_t)(value << 2) | (value << 18);
if (audio_output_source != AUDIO_SRC_PLAYBACK && !is_playing) if (keep_sample)
{ {
/* In this case, loopback is manual so that both output /* Data is in left channel only - copy to right channel
channels have audio */ 14-bit => 16-bit samples */
if (I2SOUT_RAW_STATUS & (1<<5)) value = (uint16_t)(value << 2) | (value << 18);
if (audio_output_source != AUDIO_SRC_PLAYBACK && !is_playing)
{ {
/* Sync output fifo so it goes empty not before input is /* In this case, loopback is manual so that both output
filled */ channels have audio */
for (unsigned i = 0; i < 4; i++) if (I2SOUT_RAW_STATUS & (1<<5))
*I2SOUT_DATA = 0; {
/* Sync output fifo so it goes empty not before input is
filled */
for (unsigned i = 0; i < 4; i++)
*I2SOUT_DATA = 0;
}
*I2SOUT_DATA = value;
*I2SOUT_DATA = value;
} }
*I2SOUT_DATA = value; *rec_dma_addr++ = value;
*I2SOUT_DATA = value; rec_dma_size -= 4;
} }
*rec_dma_addr++ = value;
rec_dma_size -= 4;
} }
} }
else else
@ -347,15 +352,19 @@ void INT_I2SIN(void)
if (I2SIN_RAW_STATUS & (1<<5)) if (I2SIN_RAW_STATUS & (1<<5))
return; /* empty */ return; /* empty */
/* Discard every other sample since ADC clock is 1/2 LRCK */
uint32_t value = *I2SIN_DATA; uint32_t value = *I2SIN_DATA;
*I2SIN_DATA;
/* Loopback is in I2S hardware */ /* Discard every other sample since ADC clock is 1/2 LRCK */
keep_sample ^= 1;
/* 14-bit => 16-bit samples */ if (keep_sample)
*rec_dma_addr++ = (value << 2) & ~0x00030000; {
rec_dma_size -= 4; /* Loopback is in I2S hardware */
/* 14-bit => 16-bit samples */
*rec_dma_addr++ = (value << 2) & ~0x00030000;
rec_dma_size -= 4;
}
} }
} }
@ -389,6 +398,8 @@ void pcm_rec_dma_start(void *addr, size_t size)
rec_dma_addr = addr; rec_dma_addr = addr;
rec_dma_size = size; rec_dma_size = size;
keep_sample = 0;
/* ensure empty FIFO */ /* ensure empty FIFO */
while (!(I2SIN_RAW_STATUS & (1<<5))) while (!(I2SIN_RAW_STATUS & (1<<5)))
*I2SIN_DATA; *I2SIN_DATA;

View file

@ -665,7 +665,7 @@ static int sd_select_bank(signed char bank)
dma_retain(); dma_retain();
/* we don't use the uncached buffer here, because we need the /* we don't use the uncached buffer here, because we need the
* physical memory address for DMA transfers */ * physical memory address for DMA transfers */
dma_enable_channel(0, AS3525_PHYSICAL_ADDR(&aligned_buffer[0]), dma_enable_channel(1, AS3525_PHYSICAL_ADDR(&aligned_buffer[0]),
MCI_FIFO(INTERNAL_AS3525), DMA_PERI_SD, MCI_FIFO(INTERNAL_AS3525), DMA_PERI_SD,
DMAC_FLOWCTRL_PERI_MEM_TO_PERI, true, false, 0, DMA_S8, NULL); DMAC_FLOWCTRL_PERI_MEM_TO_PERI, true, false, 0, DMA_S8, NULL);
@ -809,7 +809,7 @@ static int sd_transfer_sectors(IF_MD2(int drive,) unsigned long start,
if(write) if(write)
{ {
dma_enable_channel(0, dma_buf, MCI_FIFO(drive), dma_enable_channel(1, dma_buf, MCI_FIFO(drive),
(drive == INTERNAL_AS3525) ? DMA_PERI_SD : DMA_PERI_SD_SLOT, (drive == INTERNAL_AS3525) ? DMA_PERI_SD : DMA_PERI_SD_SLOT,
DMAC_FLOWCTRL_PERI_MEM_TO_PERI, true, false, 0, DMA_S8, NULL); DMAC_FLOWCTRL_PERI_MEM_TO_PERI, true, false, 0, DMA_S8, NULL);
@ -823,7 +823,7 @@ static int sd_transfer_sectors(IF_MD2(int drive,) unsigned long start,
#endif #endif
} }
else else
dma_enable_channel(0, MCI_FIFO(drive), dma_buf, dma_enable_channel(1, MCI_FIFO(drive), dma_buf,
(drive == INTERNAL_AS3525) ? DMA_PERI_SD : DMA_PERI_SD_SLOT, (drive == INTERNAL_AS3525) ? DMA_PERI_SD : DMA_PERI_SD_SLOT,
DMAC_FLOWCTRL_PERI_PERI_TO_MEM, false, true, 0, DMA_S8, NULL); DMAC_FLOWCTRL_PERI_PERI_TO_MEM, false, true, 0, DMA_S8, NULL);
@ -846,7 +846,7 @@ static int sd_transfer_sectors(IF_MD2(int drive,) unsigned long start,
* dma channel here, otherwise there are still 4 words in the fifo * dma channel here, otherwise there are still 4 words in the fifo
* and the retried write will get corrupted. * and the retried write will get corrupted.
*/ */
dma_disable_channel(0); dma_disable_channel(1);
last_disk_activity = current_tick; last_disk_activity = current_tick;

View file

@ -890,10 +890,10 @@ sd_transfer_retry_with_reinit:
arg *= SD_BLOCK_SIZE; arg *= SD_BLOCK_SIZE;
if(write) if(write)
dma_enable_channel(0, dma_buf, MCI_FIFO, DMA_PERI_SD, dma_enable_channel(1, dma_buf, MCI_FIFO, DMA_PERI_SD,
DMAC_FLOWCTRL_PERI_MEM_TO_PERI, true, false, 0, DMA_S8, NULL); DMAC_FLOWCTRL_PERI_MEM_TO_PERI, true, false, 0, DMA_S8, NULL);
else else
dma_enable_channel(0, MCI_FIFO, dma_buf, DMA_PERI_SD, dma_enable_channel(1, MCI_FIFO, dma_buf, DMA_PERI_SD,
DMAC_FLOWCTRL_PERI_PERI_TO_MEM, false, true, 0, DMA_S8, NULL); DMAC_FLOWCTRL_PERI_PERI_TO_MEM, false, true, 0, DMA_S8, NULL);
if(!send_cmd(drive, cmd, arg, MCI_RESP, &response)) if(!send_cmd(drive, cmd, arg, MCI_RESP, &response))

View file

@ -107,15 +107,15 @@ static void UIRQ(void)
static const struct { int source; void (*isr) (void); } vec_int_srcs[] = static const struct { int source; void (*isr) (void); } vec_int_srcs[] =
{ {
/* Highest priority at the top of the list */ /* Highest priority at the top of the list */
{ INT_SRC_DMAC, INT_DMAC }, #ifdef HAVE_RECORDING
{ INT_SRC_I2SIN, INT_I2SIN }, /* For recording */
#endif
{ INT_SRC_DMAC, INT_DMAC }, /* Playback follows recording */
{ INT_SRC_NAND, INT_NAND }, { INT_SRC_NAND, INT_NAND },
#if (defined HAVE_MULTIDRIVE && CONFIG_CPU == AS3525) #if (defined HAVE_MULTIDRIVE && CONFIG_CPU == AS3525)
{ INT_SRC_MCI0, INT_MCI0 }, { INT_SRC_MCI0, INT_MCI0 },
#endif #endif
{ INT_SRC_USB, INT_USB, }, { INT_SRC_USB, INT_USB, },
#ifdef HAVE_RECORDING
{ INT_SRC_I2SIN, INT_I2SIN, },
#endif
{ INT_SRC_TIMER1, INT_TIMER1 }, { INT_SRC_TIMER1, INT_TIMER1 },
{ INT_SRC_TIMER2, INT_TIMER2 }, { INT_SRC_TIMER2, INT_TIMER2 },
{ INT_SRC_I2C_AUDIO, INT_I2C_AUDIO }, { INT_SRC_I2C_AUDIO, INT_I2C_AUDIO },