diff --git a/apps/plugins/SOURCES b/apps/plugins/SOURCES index d89b0b6..16ed6d7 100644 --- a/apps/plugins/SOURCES +++ b/apps/plugins/SOURCES @@ -34,10 +34,12 @@ rockbox_flash.c crypt_firmware.c #endif +#if (LCD_DEPTH > 1) /* Needs to be adapted for Clip */ #if (CONFIG_CODEC == SWCODEC) && defined(HAVE_RECORDING) && \ (defined(HAVE_LINE_IN) || defined(HAVE_MIC_IN)) pitch_detector.c #endif +#endif #if (CONFIG_CODEC == SWCODEC) || !defined(SIMULATOR) metronome.c diff --git a/firmware/export/as3525.h b/firmware/export/as3525.h index d2b5a4f..8dc7508 100644 --- a/firmware/export/as3525.h +++ b/firmware/export/as3525.h @@ -507,4 +507,15 @@ interface */ #define USB_NUM_ENDPOINTS 4 #define USB_DEVBSS_ATTR IBSS_ATTR +/* I2SIN registers */ + +#define I2SIN_CONTROL (*(volatile unsigned char*)(I2SIN_BASE+0x00)) +#define I2SIN_MASK (*(volatile unsigned char*)(I2SIN_BASE+0x04)) +#define I2SIN_RAW_STATUS (*(volatile unsigned char*)(I2SIN_BASE+0x08)) +#define I2SIN_STATUS (*(volatile unsigned char*)(I2SIN_BASE+0x0C)) +#define I2SIN_CLEAR (*(volatile unsigned char*)(I2SIN_BASE+0x10)) +#define I2SIN_DATA (volatile unsigned long*)(I2SIN_BASE+0x14) +#define I2SIN_SPDIF_STATUS (*(volatile unsigned long*)(I2SIN_BASE+0x18)) + + #endif /*__AS3525_H__*/ diff --git a/firmware/export/config-c200v2.h b/firmware/export/config-c200v2.h index d6c2159..3641a7f 100644 --- a/firmware/export/config-c200v2.h +++ b/firmware/export/config-c200v2.h @@ -9,8 +9,6 @@ #define FIRMWARE_OFFSET_FILE_DATA 8 #define FIRMWARE_OFFSET_FILE_CRC 0 -#if 0 - #define HW_SAMPR_CAPS (SAMPR_CAP_44) /* define this if you have recording possibility */ @@ -20,8 +18,6 @@ #define REC_FREQ_DEFAULT REC_FREQ_22 /* Default is not 44.1kHz */ #define REC_SAMPR_DEFAULT SAMPR_22 -#endif - /* Define bitmask of input sources - recordable bitmask can be defined explicitly if different */ #define INPUT_SRC_CAPS (SRC_CAP_MIC | SRC_CAP_FMRADIO) diff --git a/firmware/export/config-clip.h b/firmware/export/config-clip.h index 3b82a25..594fd23 100644 --- a/firmware/export/config-clip.h +++ b/firmware/export/config-clip.h @@ -9,8 +9,6 @@ #define FIRMWARE_OFFSET_FILE_DATA 8 #define FIRMWARE_OFFSET_FILE_CRC 0 -#if 0 /* disabled since there is no driver (yet) */ - #define HW_SAMPR_CAPS (SAMPR_CAP_44) /* define this if you have recording possibility */ @@ -20,8 +18,6 @@ #define REC_FREQ_DEFAULT REC_FREQ_22 /* Default is not 44.1kHz */ #define REC_SAMPR_DEFAULT SAMPR_22 -#endif - /* Define bitmask of input sources - recordable bitmask can be defined explicitly if different */ #define INPUT_SRC_CAPS (SRC_CAP_MIC | SRC_CAP_FMRADIO) diff --git a/firmware/export/config-e200v2.h b/firmware/export/config-e200v2.h index b108dec..90092e0 100644 --- a/firmware/export/config-e200v2.h +++ b/firmware/export/config-e200v2.h @@ -9,7 +9,6 @@ #define HW_SAMPR_CAPS (SAMPR_CAP_44) -#if 0 /* define this if you have recording possibility */ #define HAVE_RECORDING @@ -17,7 +16,6 @@ #define REC_FREQ_DEFAULT REC_FREQ_22 /* Default is not 44.1kHz */ #define REC_SAMPR_DEFAULT SAMPR_22 -#endif /* Define bitmask of input sources - recordable bitmask can be defined explicitly if different */ #define INPUT_SRC_CAPS (SRC_CAP_MIC | SRC_CAP_FMRADIO) diff --git a/firmware/export/config-fuze.h b/firmware/export/config-fuze.h index def343c..019716d 100644 --- a/firmware/export/config-fuze.h +++ b/firmware/export/config-fuze.h @@ -9,7 +9,6 @@ #define HW_SAMPR_CAPS (SAMPR_CAP_44) -#if 0 /* define this if you have recording possibility */ #define HAVE_RECORDING @@ -24,7 +23,6 @@ /* Define bitmask of input sources - recordable bitmask can be defined explicitly if different */ -#endif #define INPUT_SRC_CAPS (SRC_CAP_MIC | SRC_CAP_FMRADIO) /* define this if you have a bitmap LCD display */ diff --git a/firmware/target/arm/as3525/audio-as3525.c b/firmware/target/arm/as3525/audio-as3525.c index 410fdfa..f575f74 100644 --- a/firmware/target/arm/as3525/audio-as3525.c +++ b/firmware/target/arm/as3525/audio-as3525.c @@ -25,41 +25,65 @@ #include "audiohw.h" #include "sound.h" -int audio_channels = 2; -int audio_output_source = AUDIO_SRC_PLAYBACK; +//int audio_channels = 2; void audio_set_output_source(int source) { +#if 0 if ((unsigned)source >= AUDIO_NUM_SOURCES) source = AUDIO_SRC_PLAYBACK; +#else + (void)source; +#endif - audio_output_source = source; } /* audio_set_output_source */ void audio_input_mux(int source, unsigned flags) { static int last_source = AUDIO_SRC_PLAYBACK; - - (void)flags; + static bool last_recording = false; + const bool recording = flags & SRCF_RECORDING; switch (source) { default: /* playback - no recording */ source = AUDIO_SRC_PLAYBACK; case AUDIO_SRC_PLAYBACK: - audio_channels = 2; + //audio_channels = 2; + if (source != last_source) + { + audiohw_set_monitor(false); + audiohw_disable_recording(); + } + break; + + case AUDIO_SRC_MIC: /* recording only */ + //audio_channels = 1; if (source != last_source) { audiohw_set_monitor(false); + audiohw_enable_recording(true); /* source mic */ } break; case AUDIO_SRC_FMRADIO: /* recording and playback */ - audio_channels = 2; - if (source == last_source) + //audio_channels = 2; + + if (source == last_source && recording == last_recording) break; - audiohw_set_monitor(true); + last_recording = recording; + + if (recording) + { + audiohw_set_monitor(false); + audiohw_enable_recording(false); + } + else + { + audiohw_disable_recording(); + audiohw_set_monitor(true); /* line 2 analog audio path */ + } break; } /* end switch */ diff --git a/firmware/target/arm/as3525/debug-as3525.c b/firmware/target/arm/as3525/debug-as3525.c index d8d3e01..14e0c60 100644 --- a/firmware/target/arm/as3525/debug-as3525.c +++ b/firmware/target/arm/as3525/debug-as3525.c @@ -310,7 +310,8 @@ bool __dbg_hw_info(void) lcd_putsf(0, line++, "Icache:%s Dcache:%s", (read_cp15() & CP15_IC) ? " on" : "off", (read_cp15() & CP15_DC) ? " on" : "off"); - + lcd_putsf(0, line++,"I2SOUT_CONTROL :%8x", (unsigned int)(I2SOUT_CONTROL)); + lcd_putsf(0, line++,"I2SIN_CONTROL :%8x", (unsigned int)(I2SIN_CONTROL)); lcd_update(); int btn = button_get_w_tmo(HZ/10); if(btn == (DEBUG_CANCEL|BUTTON_REL)) @@ -375,6 +376,7 @@ bool __dbg_ports(void) while(1) { line = 0; +#if 0 lcd_puts(0, line++, "[GPIO Values and Directions]"); lcd_putsf(0, line++, "GPIOA: %2x DIR: %2x", GPIOA_DATA, GPIOA_DIR); lcd_putsf(0, line++, "GPIOB: %2x DIR: %2x", GPIOB_DATA, GPIOB_DIR); @@ -388,6 +390,14 @@ bool __dbg_ports(void) line++; lcd_puts(0, line++, "[CP15]"); lcd_putsf(0, line++, "CP15: 0x%8x", read_cp15()); +#else + lcd_putsf(0, line++,"I2SIN_RAW_STATUS: 0x%8x", I2SIN_RAW_STATUS&255); + line++; + extern int i2si_interrupts; + extern int i2si_words; + lcd_putsf(0, line++,"I2SIN : %d interrupts", i2si_interrupts); + lcd_putsf(0, line++,"I2SIN : %d words transfers", i2si_words); +#endif lcd_update(); if (button_get_w_tmo(HZ/10) == (DEBUG_CANCEL|BUTTON_REL)) break; diff --git a/firmware/target/arm/as3525/pcm-as3525.c b/firmware/target/arm/as3525/pcm-as3525.c index 2057980..ca291c0 100644 --- a/firmware/target/arm/as3525/pcm-as3525.c +++ b/firmware/target/arm/as3525/pcm-as3525.c @@ -68,6 +68,8 @@ static void play_start_pcm(void) dma_start_addr += size; CGU_PERI |= CGU_I2SOUT_APB_CLOCK_ENABLE; + CGU_PERI &= ~CGU_I2SIN_APB_CLOCK_ENABLE; + CGU_AUDIO &=~(1<<23); CGU_AUDIO |= (1<<11); clean_dcache_range((void*)addr, size); /* force write back */ @@ -130,8 +132,8 @@ void pcm_play_dma_init(void) /* clock source PLLA, minimal frequency */ CGU_AUDIO |= (511<<2) | (1<<0); - I2SOUT_CONTROL |= (1<<6) ; /* enable dma */ - I2SOUT_CONTROL |= (1<<3) ; /* stereo */ + I2SOUT_CONTROL |= (1<<6) ; /* enable dma */ + I2SOUT_CONTROL |= (1<<3) ; /* stereo */ I2SOUT_CONTROL &= ~(1<<2); /* 16 bit samples */ audiohw_preinit(); @@ -153,10 +155,8 @@ void pcm_dma_apply_settings(void) int cgu_audio = CGU_AUDIO; /* read register */ cgu_audio &= ~(511 << 2); /* clear i2sout divider */ cgu_audio |= divider << 2; /* set new i2sout divider */ -#if 0 cgu_audio &= ~(511 << 14); /* clear i2sin divider */ cgu_audio |= divider << 14; /* set new i2sin divider */ -#endif CGU_AUDIO = cgu_audio; /* write back register */ } @@ -185,43 +185,201 @@ void * pcm_dma_addr(void *addr) ** Recording DMA transfer **/ #ifdef HAVE_RECORDING + +//#define I2SI_DMA + +static int rec_locked = 0; +static unsigned int *dma_rec_start_addr; +static size_t dma_rec_size; /* in 4*32 bits */ +#ifdef I2SI_DMA +static void dma_rec_callback(void); +#endif + +#define show_fn() lcd_puts(0,13,__func__);lcd_update(); + void pcm_rec_lock(void) { + if(++rec_locked == 1) +#ifdef I2SI_DMA + VIC_INT_EN_CLEAR = INTERRUPT_DMAC; +#else + VIC_INT_EN_CLEAR = INTERRUPT_I2SIN; +#endif } void pcm_rec_unlock(void) { + if(--rec_locked == 0) +#ifdef I2SI_DMA + VIC_INT_ENABLE |= INTERRUPT_DMAC; +#else + VIC_INT_ENABLE |= INTERRUPT_I2SIN; + + // CGU_AUDIO |= (1<<23); +#endif } void pcm_record_more(void *start, size_t size) { - (void)start; - (void)size; + dma_rec_start_addr = start; + dma_rec_size = size; } void pcm_rec_dma_stop(void) { +#ifdef I2SI_DMA + dma_disable_channel(1); + dma_rec_size = 0; + + dma_release(); +#else + VIC_INT_EN_CLEAR = INTERRUPT_I2SIN; +#endif + //CGU_PERI &= ~CGU_I2SIN_APB_CLOCK_ENABLE; + CGU_AUDIO &= ~(1<<23); + CGU_AUDIO |= (1<<11); } +#ifdef I2SI_DMA +static void start_recording(void) +{ + size_t size = dma_rec_size; + void* addr = dma_rec_start_addr; + + if(size > MAX_TRANSFER) + size = MAX_TRANSFER; + + dma_rec_size -= size; + dma_rec_start_addr += size; + + dump_dcache_range((void*)dma_rec_start_addr, size); + //we might want to use a buffer aligned on cache line size (32 bytes) + dma_enable_channel(1, (void*)I2SIN_DATA, addr, DMA_PERI_I2SIN, + DMAC_FLOWCTRL_DMAC_PERI_TO_MEM, false, true, size >> 2, DMA_S4, + dma_rec_callback); +} +#endif + +int i2si_interrupts = 0; +int i2si_words = 0; + +#ifndef I2SI_DMA +void INT_I2SIN(void) +{ + register int status; + register pcm_more_callback_type2 more_ready; + i2si_interrupts++; + + status = I2SIN_STATUS; + + if ( status & ((1<<6)|(1<<0)) ) /* errors */ + panicf("i2sin error: 0x%x", status); + + while (((I2SIN_RAW_STATUS & (1<<5)) == 0) && dma_rec_size) + { + *dma_rec_start_addr++ = *I2SIN_DATA; + dma_rec_size -= 4; + i2si_words++; + } + + I2SIN_CLEAR = status; + + if(!dma_rec_size) + { + more_ready = pcm_callback_more_ready; + if(!more_ready || more_ready(0) < 0) + { + /* Finished recording */ + pcm_rec_dma_stop(); + pcm_rec_dma_stopped_callback(); + } + } +} +#endif + void pcm_rec_dma_start(void *addr, size_t size) { - (void)addr; - (void)size; + + dma_rec_start_addr = addr; + dma_rec_size = size; + + if((unsigned int)addr & 3) + panicf("unaligned pointer!"); + CGU_PERI &=~(CGU_I2SOUT_APB_CLOCK_ENABLE); + CGU_PERI |= CGU_I2SIN_APB_CLOCK_ENABLE|CGU_I2C_AUDIO_MASTER_CLOCK_ENABLE; +sleep(HZ/4); + CGU_AUDIO |= (1<<23); + CGU_AUDIO &=~(1<<11); + I2SOUT_CONTROL = 4; + I2SIN_CONTROL = 0 + #if 0 /* spdif */ + | (0<<5) /* 24 bits samples */ + | (2<<8) /* i2c clk src = from spdif */ + | (2<<6) /* sdata src = from spdif */ + #else + | (1<<5) /* 14 bits samples */ + | (0<<8) /* i2c clk src = from I2SOUTIF (with AFE) */ + | (0<<6) /* sdata src = from AFE*/ + #endif + ; + +#ifdef I2SI_DMA + dma_retain(); + + start_recording(); + + I2SIN_CONTROL |= (1<<11); /* dma request enable */ +#else + unsigned long tmp; + while ( ( I2SIN_RAW_STATUS & ( 1<<5 ) ) == 0 ) + tmp = *I2SIN_DATA; /* FLUSH FIFO */ + I2SIN_CLEAR = 0x41; + I2SIN_MASK = 0x47; /* ERRORS, FULL, ALMOST FULL */ + + VIC_INT_ENABLE |= INTERRUPT_I2SIN; +#endif +} + +#ifdef I2SI_DMA +static void dma_rec_callback(void) +{ + panicf("rec callback"); + + register pcm_more_callback_type2 more_ready = pcm_callback_more_ready; + + if(dma_rec_size || (more_ready && more_ready(0) >= 0)) + { + start_recording(); + return; + } + + pcm_rec_dma_stop(); + pcm_rec_dma_stopped_callback(); } +#endif void pcm_rec_dma_close(void) { + pcm_rec_dma_stop(); } void pcm_rec_dma_init(void) { + pcm_dma_apply_settings(); } const void * pcm_rec_dma_get_peak_buffer(int *count) { - (void)count; + const void *peak_buffer; + + pcm_rec_lock(); + *count = dma_rec_size >> 2; + peak_buffer = (const void*)dma_rec_start_addr; + pcm_rec_unlock(); + + return peak_buffer; } #endif /* HAVE_RECORDING */ diff --git a/firmware/target/arm/as3525/system-as3525.c b/firmware/target/arm/as3525/system-as3525.c index dc335df..701dc1d 100644 --- a/firmware/target/arm/as3525/system-as3525.c +++ b/firmware/target/arm/as3525/system-as3525.c @@ -113,6 +113,7 @@ struct vec_int_src vec_int_srcs[] = { INT_SRC_MCI0, INT_MCI0 }, { INT_SRC_GPIOA, INT_GPIOA, }, { INT_SRC_GPIOB, INT_GPIOB, }, + { INT_SRC_I2SIN, INT_I2SIN, }, }; static void setup_vic(void)