diff --git a/firmware/target/arm/s5l8702/debug-s5l8702.c b/firmware/target/arm/s5l8702/debug-s5l8702.c index 30d97d9203..471eae8acd 100644 --- a/firmware/target/arm/s5l8702/debug-s5l8702.c +++ b/firmware/target/arm/s5l8702/debug-s5l8702.c @@ -29,6 +29,7 @@ #include "storage.h" #include "power.h" #include "pmu-target.h" +#include "pcm-target.h" /* Skeleton for adding target specific debug info to the debug menu */ @@ -40,7 +41,7 @@ bool __dbg_hw_info(void) int line; int i; unsigned int state = 0; - const unsigned int max_states=2; + const unsigned int max_states=3; lcd_clear_display(); lcd_setfont(FONT_SYSFIXED); @@ -81,6 +82,16 @@ bool __dbg_hw_info(void) _DEBUG_PRINTF("backlight: %s", pmu_read(0x29) ? "on" : "off"); _DEBUG_PRINTF("brightness value: %d", pmu_read(0x28)); } + else if(state==2) + { + _DEBUG_PRINTF("Audio DMA:"); + _DEBUG_PRINTF(">%08X %08X %08X %08X %08X", DMAC0C0CONFIG, DMAC0C0SRCADDR, + DMAC0C0DESTADDR, DMAC0C0NEXTLLI, DMAC0C0CONTROL); + for(i = 0; i < PCM_LLICOUNT; i++) + _DEBUG_PRINTF("%08X: %08X %08X %08X %08X", &pcm_lli[i], pcm_lli[i].srcaddr, + pcm_lli[i].dstaddr, pcm_lli[i].nextlli, pcm_lli[i].control); + _DEBUG_PRINTF("chunk: %08X %08X", pcm_chunksize, pcm_remaining); + } else { state=0; diff --git a/firmware/target/arm/s5l8702/pcm-s5l8702.c b/firmware/target/arm/s5l8702/pcm-s5l8702.c index 9fc241b9a1..c0498a9ce2 100644 --- a/firmware/target/arm/s5l8702/pcm-s5l8702.c +++ b/firmware/target/arm/s5l8702/pcm-s5l8702.c @@ -29,21 +29,17 @@ #include "pcm.h" #include "pcm_sampr.h" #include "mmu-arm.h" - -/* S5L8702 PCM driver tunables: */ -#define LLIMAX (2047) /* Maximum number of samples per LLI */ -#define CHUNKSIZE (8700) /* Maximum number of samples to handle with one IRQ */ - /* (bigger chunks will be segmented internally) */ -#define WATERMARK (512) /* Number of remaining samples to schedule IRQ at */ +#include "pcm-target.h" static volatile int locked = 0; static const int zerosample = 0; -static unsigned char dblbuf[WATERMARK * 4] IBSS_ATTR; -struct dma_lli lli[(CHUNKSIZE - WATERMARK + LLIMAX - 1) / LLIMAX + 1] - __attribute__((aligned(16))); -struct dma_lli* lastlli; +static unsigned char dblbuf[2][PCM_WATERMARK * 4]; +static int active_dblbuf; +struct dma_lli pcm_lli[PCM_LLICOUNT] __attribute__((aligned(16))); +static struct dma_lli* lastlli; static const unsigned char* dataptr; -static size_t remaining; +size_t pcm_remaining; +size_t pcm_chunksize; /* Mask the DMA interrupt */ void pcm_play_lock(void) @@ -66,54 +62,63 @@ void INT_DMAC0C0(void) ICODE_ATTR; void INT_DMAC0C0(void) { DMAC0INTTCCLR = 1; - if (!remaining) pcm_play_get_more_callback((void**)&dataptr, &remaining); - if (!remaining) + if (!pcm_remaining) { - lli->nextlli = NULL; - lli->control = 0x75249000; + pcm_play_get_more_callback((void**)&dataptr, &pcm_remaining); + pcm_chunksize = pcm_remaining; + } + if (!pcm_remaining) + { + pcm_lli->nextlli = NULL; + pcm_lli->control = 0x75249000; clean_dcache(); return; } - uint32_t lastsize = MIN(WATERMARK * 4, remaining); - remaining -= lastsize; - if (remaining) lastlli = &lli[ARRAYLEN(lli) - 1]; - else lastlli = lli; - uint32_t chunksize = MIN(CHUNKSIZE * 4 - lastsize, remaining); - if (remaining > chunksize && chunksize > remaining - WATERMARK * 4) - chunksize = remaining - WATERMARK * 4; - remaining -= chunksize; + uint32_t lastsize = MIN(PCM_WATERMARK * 4, pcm_remaining / 2 + 1) & ~1; + pcm_remaining -= lastsize; + if (pcm_remaining) lastlli = &pcm_lli[ARRAYLEN(pcm_lli) - 1]; + else lastlli = pcm_lli; + uint32_t chunksize = MIN(PCM_CHUNKSIZE * 4 - lastsize, pcm_remaining); + if (pcm_remaining > chunksize && chunksize > pcm_remaining - PCM_WATERMARK * 8) + chunksize = pcm_remaining - PCM_WATERMARK * 8; + pcm_remaining -= chunksize; bool last = !chunksize; int i = 0; while (chunksize) { - uint32_t thislli = MIN(LLIMAX * 4, chunksize); + uint32_t thislli = MIN(PCM_LLIMAX * 4, chunksize); chunksize -= thislli; - lli[i].srcaddr = (void*)dataptr; - lli[i].dstaddr = (void*)((int)&I2STXDB0); - lli[i].nextlli = chunksize ? &lli[i + 1] : lastlli; - lli[i].control = (chunksize ? 0x75249000 : 0xf5249000) | (thislli / 2); + pcm_lli[i].srcaddr = (void*)dataptr; + pcm_lli[i].dstaddr = (void*)((int)&I2STXDB0); + pcm_lli[i].nextlli = chunksize ? &pcm_lli[i + 1] : lastlli; + pcm_lli[i].control = (chunksize ? 0x75249000 : 0xf5249000) | (thislli / 2); dataptr += thislli; i++; } - if (!remaining) memcpy(dblbuf, dataptr, lastsize); - lastlli->srcaddr = remaining ? dataptr : dblbuf; + if (!pcm_remaining) + { + memcpy(dblbuf[active_dblbuf], dataptr, lastsize); + lastlli->srcaddr = dblbuf[active_dblbuf]; + active_dblbuf ^= 1; + } + else lastlli->srcaddr = dataptr; lastlli->dstaddr = (void*)((int)&I2STXDB0); - lastlli->nextlli = last ? NULL : lli; + lastlli->nextlli = last ? NULL : pcm_lli; lastlli->control = (last ? 0xf5249000 : 0x75249000) | (lastsize / 2); dataptr += lastsize; clean_dcache(); - if (!(DMAC0C0CONFIG & 1) && (lli[0].control & 0xfff)) + if (!(DMAC0C0CONFIG & 1) && (pcm_lli[0].control & 0xfff)) { - DMAC0C0LLI = lli[0]; + DMAC0C0LLI = pcm_lli[0]; DMAC0C0CONFIG = 0x8a81; } - else DMAC0C0NEXTLLI = lli; + else DMAC0C0NEXTLLI = pcm_lli; } void pcm_play_dma_start(const void* addr, size_t size) { dataptr = (const unsigned char*)addr; - remaining = size; + pcm_remaining = size; I2STXCOM = 0xe; DMAC0CONFIG |= 4; INT_DMAC0C0(); @@ -155,7 +160,7 @@ void pcm_dma_apply_settings(void) size_t pcm_get_bytes_waiting(void) { - int bytes = remaining; + int bytes = pcm_remaining; const struct dma_lli* lli = (const struct dma_lli*)((int)&DMAC0C0LLI); while (lli) { diff --git a/firmware/target/arm/s5l8702/pcm-target.h b/firmware/target/arm/s5l8702/pcm-target.h new file mode 100644 index 0000000000..1b149a6e0b --- /dev/null +++ b/firmware/target/arm/s5l8702/pcm-target.h @@ -0,0 +1,40 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id: system-target.h 28791 2010-12-11 09:39:33Z Buschel $ + * + * Copyright (C) 2010 by Michael Sparmann + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#ifndef __PCM_TARGET_H__ +#define __PCM_TARGET_H__ + + +/* S5L8702 PCM driver tunables: */ +#define PCM_LLIMAX (2047) /* Maximum number of samples per LLI */ +#define PCM_CHUNKSIZE (10747) /* Maximum number of samples to handle with one IRQ */ + /* (bigger chunks will be segmented internally) */ +#define PCM_WATERMARK (512) /* Number of remaining samples to schedule IRQ at */ + + +#define PCM_LLICOUNT ((PCM_CHUNKSIZE - PCM_WATERMARK + PCM_LLIMAX - 1) / PCM_LLIMAX + 1) + + +extern struct dma_lli pcm_lli[PCM_LLICOUNT]; +extern size_t pcm_remaining; +extern size_t pcm_chunksize; + + +#endif /* __PCM_TARGET_H__ */