diff options
-rw-r--r-- | apps/plugins/pitch_detector.c | 2 | ||||
-rw-r--r-- | apps/recorder/pcm_record.c | 2 | ||||
-rw-r--r-- | firmware/export/as3525.h | 1 | ||||
-rw-r--r-- | firmware/export/config/sansac200v2.h | 9 | ||||
-rw-r--r-- | firmware/export/config/sansaclip.h | 9 | ||||
-rw-r--r-- | firmware/export/config/sansaclipplus.h | 9 | ||||
-rw-r--r-- | firmware/export/config/sansaclipv2.h | 9 | ||||
-rw-r--r-- | firmware/export/config/sansaclipzip.h | 9 | ||||
-rw-r--r-- | firmware/export/config/sansae200v2.h | 9 | ||||
-rw-r--r-- | firmware/export/config/sansafuze.h | 9 | ||||
-rw-r--r-- | firmware/export/config/sansafuzev2.h | 9 | ||||
-rw-r--r-- | firmware/export/config/sansam200v4.h | 9 | ||||
-rw-r--r-- | firmware/export/pcm_sampr.h | 5 | ||||
-rw-r--r-- | firmware/pcm.c | 9 | ||||
-rw-r--r-- | firmware/target/arm/as3525/audio-as3525.c | 52 | ||||
-rw-r--r-- | firmware/target/arm/as3525/pcm-as3525.c | 295 | ||||
-rw-r--r-- | firmware/target/arm/sandisk/audio-c200_e200.c | 31 |
17 files changed, 269 insertions, 209 deletions
diff --git a/apps/plugins/pitch_detector.c b/apps/plugins/pitch_detector.c index ec208268ab..c30d48a025 100644 --- a/apps/plugins/pitch_detector.c +++ b/apps/plugins/pitch_detector.c @@ -1078,7 +1078,7 @@ static void record_and_get_pitch(void) } } rb->pcm_close_recording(); - rb->pcm_set_frequency(REC_SAMPR_DEFAULT | SAMPR_TYPE_REC); + rb->pcm_set_frequency(HW_SAMPR_RESET | SAMPR_TYPE_REC); #ifdef HAVE_SCHEDULER_BOOSTCTRL rb->cancel_cpu_boost(); #endif diff --git a/apps/recorder/pcm_record.c b/apps/recorder/pcm_record.c index e83db0f418..30b681ab45 100644 --- a/apps/recorder/pcm_record.c +++ b/apps/recorder/pcm_record.c @@ -290,7 +290,7 @@ static void pcm_rec_have_more(int status, void **start, size_t *size) static void reset_hardware(void) { /* reset pcm to defaults */ - pcm_set_frequency(REC_SAMPR_DEFAULT | SAMPR_TYPE_REC); + pcm_set_frequency(HW_SAMPR_RESET | SAMPR_TYPE_REC); audio_set_output_source(AUDIO_SRC_PLAYBACK); pcm_apply_settings(); } diff --git a/firmware/export/as3525.h b/firmware/export/as3525.h index 87e3fc43d7..c5e01d5bc8 100644 --- a/firmware/export/as3525.h +++ b/firmware/export/as3525.h @@ -526,7 +526,6 @@ CE lines /* PCM addresses for obtaining buffers will be what DMA is using (physical) */ #define HAVE_PCM_DMA_ADDRESS -#define HAVE_PCM_REC_DMA_ADDRESS /* Timer frequency */ #define TIMER_FREQ (24000000 / 16) diff --git a/firmware/export/config/sansac200v2.h b/firmware/export/config/sansac200v2.h index 4223d41b92..a5b857fe81 100644 --- a/firmware/export/config/sansac200v2.h +++ b/firmware/export/config/sansac200v2.h @@ -14,7 +14,14 @@ /* define this if you have recording possibility */ #define HAVE_RECORDING -#define REC_SAMPR_CAPS SAMPR_CAP_ALL +#define REC_SAMPR_CAPS (SAMPR_CAP_48 | SAMPR_CAP_44 | SAMPR_CAP_32 | \ + SAMPR_CAP_24 | SAMPR_CAP_22 | SAMPR_CAP_16 | \ + SAMPR_CAP_12 | SAMPR_CAP_11 | SAMPR_CAP_8) + +/* because the samplerates don't match at each point, we must be able to + * tell PCM which set of rates to use. not needed if recording rates are + * a simple subset of playback rates and are equal values. */ +#define CONFIG_SAMPR_TYPES /* Define bitmask of input sources - recordable bitmask can be defined explicitly if different */ diff --git a/firmware/export/config/sansaclip.h b/firmware/export/config/sansaclip.h index 7427d623fb..4e214669b1 100644 --- a/firmware/export/config/sansaclip.h +++ b/firmware/export/config/sansaclip.h @@ -14,7 +14,14 @@ /* define this if you have recording possibility */ #define HAVE_RECORDING -#define REC_SAMPR_CAPS SAMPR_CAP_ALL +#define REC_SAMPR_CAPS (SAMPR_CAP_48 | SAMPR_CAP_44 | SAMPR_CAP_32 | \ + SAMPR_CAP_24 | SAMPR_CAP_22 | SAMPR_CAP_16 | \ + SAMPR_CAP_12 | SAMPR_CAP_11 | SAMPR_CAP_8) + +/* because the samplerates don't match at each point, we must be able to + * tell PCM which set of rates to use. not needed if recording rates are + * a simple subset of playback rates and are equal values. */ +#define CONFIG_SAMPR_TYPES /* Define bitmask of input sources - recordable bitmask can be defined explicitly if different */ diff --git a/firmware/export/config/sansaclipplus.h b/firmware/export/config/sansaclipplus.h index 8a0a0403f3..0ae67b70d0 100644 --- a/firmware/export/config/sansaclipplus.h +++ b/firmware/export/config/sansaclipplus.h @@ -21,7 +21,14 @@ /* define this if you have recording possibility */ #define HAVE_RECORDING -#define REC_SAMPR_CAPS SAMPR_CAP_ALL +#define REC_SAMPR_CAPS (SAMPR_CAP_48 | SAMPR_CAP_44 | SAMPR_CAP_32 | \ + SAMPR_CAP_24 | SAMPR_CAP_22 | SAMPR_CAP_16 | \ + SAMPR_CAP_12 | SAMPR_CAP_11 | SAMPR_CAP_8) + +/* because the samplerates don't match at each point, we must be able to + * tell PCM which set of rates to use. not needed if recording rates are + * a simple subset of playback rates and are equal values. */ +#define CONFIG_SAMPR_TYPES /* Define bitmask of input sources - recordable bitmask can be defined explicitly if different */ diff --git a/firmware/export/config/sansaclipv2.h b/firmware/export/config/sansaclipv2.h index a39fe3e12c..d7a50afa20 100644 --- a/firmware/export/config/sansaclipv2.h +++ b/firmware/export/config/sansaclipv2.h @@ -14,7 +14,14 @@ /* define this if you have recording possibility */ #define HAVE_RECORDING -#define REC_SAMPR_CAPS SAMPR_CAP_ALL +#define REC_SAMPR_CAPS (SAMPR_CAP_48 | SAMPR_CAP_44 | SAMPR_CAP_32 | \ + SAMPR_CAP_24 | SAMPR_CAP_22 | SAMPR_CAP_16 | \ + SAMPR_CAP_12 | SAMPR_CAP_11 | SAMPR_CAP_8) + +/* because the samplerates don't match at each point, we must be able to + * tell PCM which set of rates to use. not needed if recording rates are + * a simple subset of playback rates and are equal values. */ +#define CONFIG_SAMPR_TYPES /* Define bitmask of input sources - recordable bitmask can be defined explicitly if different */ diff --git a/firmware/export/config/sansaclipzip.h b/firmware/export/config/sansaclipzip.h index 3df9ed57fd..e0f39afcf1 100644 --- a/firmware/export/config/sansaclipzip.h +++ b/firmware/export/config/sansaclipzip.h @@ -21,7 +21,14 @@ /* define this if you have recording possibility */ #define HAVE_RECORDING -#define REC_SAMPR_CAPS SAMPR_CAP_ALL +#define REC_SAMPR_CAPS (SAMPR_CAP_48 | SAMPR_CAP_44 | SAMPR_CAP_32 | \ + SAMPR_CAP_24 | SAMPR_CAP_22 | SAMPR_CAP_16 | \ + SAMPR_CAP_12 | SAMPR_CAP_11 | SAMPR_CAP_8) + +/* because the samplerates don't match at each point, we must be able to + * tell PCM which set of rates to use. not needed if recording rates are + * a simple subset of playback rates and are equal values. */ +#define CONFIG_SAMPR_TYPES /* Define bitmask of input sources - recordable bitmask can be defined explicitly if different */ diff --git a/firmware/export/config/sansae200v2.h b/firmware/export/config/sansae200v2.h index 34c2cd98ad..a03dfe05a6 100644 --- a/firmware/export/config/sansae200v2.h +++ b/firmware/export/config/sansae200v2.h @@ -12,7 +12,14 @@ /* define this if you have recording possibility */ #define HAVE_RECORDING -#define REC_SAMPR_CAPS SAMPR_CAP_ALL +#define REC_SAMPR_CAPS (SAMPR_CAP_48 | SAMPR_CAP_44 | SAMPR_CAP_32 | \ + SAMPR_CAP_24 | SAMPR_CAP_22 | SAMPR_CAP_16 | \ + SAMPR_CAP_12 | SAMPR_CAP_11 | SAMPR_CAP_8) + +/* because the samplerates don't match at each point, we must be able to + * tell PCM which set of rates to use. not needed if recording rates are + * a simple subset of playback rates and are equal values. */ +#define CONFIG_SAMPR_TYPES /* Define bitmask of input sources - recordable bitmask can be defined explicitly if different */ diff --git a/firmware/export/config/sansafuze.h b/firmware/export/config/sansafuze.h index 8563664cb8..2e9c261a04 100644 --- a/firmware/export/config/sansafuze.h +++ b/firmware/export/config/sansafuze.h @@ -12,7 +12,14 @@ /* define this if you have recording possibility */ #define HAVE_RECORDING -#define REC_SAMPR_CAPS SAMPR_CAP_ALL +#define REC_SAMPR_CAPS (SAMPR_CAP_48 | SAMPR_CAP_44 | SAMPR_CAP_32 | \ + SAMPR_CAP_24 | SAMPR_CAP_22 | SAMPR_CAP_16 | \ + SAMPR_CAP_12 | SAMPR_CAP_11 | SAMPR_CAP_8) + +/* because the samplerates don't match at each point, we must be able to + * tell PCM which set of rates to use. not needed if recording rates are + * a simple subset of playback rates and are equal values. */ +#define CONFIG_SAMPR_TYPES /* Default recording levels */ #define DEFAULT_REC_MIC_GAIN 23 diff --git a/firmware/export/config/sansafuzev2.h b/firmware/export/config/sansafuzev2.h index 1c0f8a99dc..7465010166 100644 --- a/firmware/export/config/sansafuzev2.h +++ b/firmware/export/config/sansafuzev2.h @@ -12,7 +12,14 @@ /* define this if you have recording possibility */ #define HAVE_RECORDING -#define REC_SAMPR_CAPS SAMPR_CAP_ALL +#define REC_SAMPR_CAPS (SAMPR_CAP_48 | SAMPR_CAP_44 | SAMPR_CAP_32 | \ + SAMPR_CAP_24 | SAMPR_CAP_22 | SAMPR_CAP_16 | \ + SAMPR_CAP_12 | SAMPR_CAP_11 | SAMPR_CAP_8) + +/* because the samplerates don't match at each point, we must be able to + * tell PCM which set of rates to use. not needed if recording rates are + * a simple subset of playback rates and are equal values. */ +#define CONFIG_SAMPR_TYPES /* Default recording levels */ #define DEFAULT_REC_MIC_GAIN 23 diff --git a/firmware/export/config/sansam200v4.h b/firmware/export/config/sansam200v4.h index 88679c1a78..52b10a4431 100644 --- a/firmware/export/config/sansam200v4.h +++ b/firmware/export/config/sansam200v4.h @@ -16,7 +16,14 @@ /* define this if you have recording possibility */ #define HAVE_RECORDING -#define REC_SAMPR_CAPS SAMPR_CAP_ALL +#define REC_SAMPR_CAPS (SAMPR_CAP_48 | SAMPR_CAP_44 | SAMPR_CAP_32 | \ + SAMPR_CAP_24 | SAMPR_CAP_22 | SAMPR_CAP_16 | \ + SAMPR_CAP_12 | SAMPR_CAP_11 | SAMPR_CAP_8) + +/* because the samplerates don't match at each point, we must be able to + * tell PCM which set of rates to use. not needed if recording rates are + * a simple subset of playback rates and are equal values. */ +#define CONFIG_SAMPR_TYPES /* Define bitmask of input sources - recordable bitmask can be defined explicitly if different */ diff --git a/firmware/export/pcm_sampr.h b/firmware/export/pcm_sampr.h index 62bfd0068b..01a8ed428e 100644 --- a/firmware/export/pcm_sampr.h +++ b/firmware/export/pcm_sampr.h @@ -305,6 +305,8 @@ enum rec_freq_indexes #define REC_SAMPR_DEFAULT SAMPR_44 #endif +#define HW_SAMPR_RESET 0 + #define REC_FREQ_CFG_VAL_LIST &REC_HAVE_96_(",96") REC_HAVE_88_(",88") \ REC_HAVE_64_(",64") REC_HAVE_48_(",48") \ REC_HAVE_44_(",44") REC_HAVE_32_(",32") \ @@ -324,7 +326,8 @@ extern const unsigned long rec_freq_sampr[REC_NUM_FREQ]; #define SAMPR_TYPE_REC (0x01 << 24) #endif -unsigned int pcm_sampr_type_rec_to_play(unsigned int samplerate); +unsigned int pcm_sampr_to_hw_sampr(unsigned int samplerate, + unsigned int type); #else /* ndef CONFIG_SAMPR_TYPES */ diff --git a/firmware/pcm.c b/firmware/pcm.c index f5efb4f84e..d1a897dcab 100644 --- a/firmware/pcm.c +++ b/firmware/pcm.c @@ -393,21 +393,14 @@ void pcm_set_frequency(unsigned int samplerate) int index; #ifdef CONFIG_SAMPR_TYPES -#ifdef HAVE_RECORDING unsigned int type = samplerate & SAMPR_TYPE_MASK; -#endif samplerate &= ~SAMPR_TYPE_MASK; -#ifdef HAVE_RECORDING -#if SAMPR_TYPE_REC != 0 /* For now, supported targets have direct conversion when configured with * CONFIG_SAMPR_TYPES. * Some hypothetical target with independent rates would need slightly * different handling throughout this source. */ - if (type == SAMPR_TYPE_REC) - samplerate = pcm_sampr_type_rec_to_play(samplerate); -#endif -#endif /* HAVE_RECORDING */ + samplerate = pcm_sampr_to_hw_sampr(samplerate, type); #endif /* CONFIG_SAMPR_TYPES */ index = round_value_to_list32(samplerate, hw_freq_sampr, diff --git a/firmware/target/arm/as3525/audio-as3525.c b/firmware/target/arm/as3525/audio-as3525.c index 10c6161881..e4bb39b406 100644 --- a/firmware/target/arm/as3525/audio-as3525.c +++ b/firmware/target/arm/as3525/audio-as3525.c @@ -24,16 +24,33 @@ #include "audio.h" #include "audiohw.h" #include "sound.h" +#include "general.h" int audio_channels = 2; +#if CONFIG_CPU == AS3525 +int audio_output_source = AUDIO_SRC_PLAYBACK; +#endif + void audio_set_output_source(int source) { bitset32(&CGU_PERI, CGU_I2SOUT_APB_CLOCK_ENABLE); - if (source == AUDIO_SRC_PLAYBACK) - I2SOUT_CONTROL &= ~(1<<5); + + if ((unsigned)source >= AUDIO_NUM_SOURCES) + source = AUDIO_SRC_PLAYBACK; + + bool loopback = source != AUDIO_SRC_PLAYBACK; + +#if CONFIG_CPU == AS3525 + loopback = loopback && audio_channels > 1; + + audio_output_source = source; +#endif + + if (loopback) + I2SOUT_CONTROL |= (1<<5); /* loopback from i2sin fifo */ else - I2SOUT_CONTROL |= 1<<5; /* source = loopback from i2sin fifo */ + I2SOUT_CONTROL &= ~(1<<5); /* normal i2sout */ } void audio_input_mux(int source, unsigned flags) @@ -108,4 +125,33 @@ void audio_input_mux(int source, unsigned flags) } last_source = source; + +#if CONFIG_CPU == AS3525 + /* Sync on behalf of change in number of channels */ + audio_set_output_source(audio_output_source); +#endif } + +#ifdef CONFIG_SAMPR_TYPES +unsigned int pcm_sampr_to_hw_sampr(unsigned int samplerate, + unsigned int type) +{ +#ifdef HAVE_RECORDING + if (samplerate != HW_SAMPR_RESET && type == SAMPR_TYPE_REC) + { + /* Check if the samplerate is in the list of recordable rates. + * Fail to default if not */ + int index = round_value_to_list32(samplerate, rec_freq_sampr, + REC_NUM_FREQ, false); + if (samplerate != rec_freq_sampr[index]) + samplerate = REC_SAMPR_DEFAULT; + + samplerate *= 2; /* Recording rates are 1/2 the codec clock */ + } +#endif /* HAVE_RECORDING */ + + return samplerate; + (void)type; +} +#endif /* CONFIG_SAMPR_TYPES */ + diff --git a/firmware/target/arm/as3525/pcm-as3525.c b/firmware/target/arm/as3525/pcm-as3525.c index f82b373ade..8b42bbd5b2 100644 --- a/firmware/target/arm/as3525/pcm-as3525.c +++ b/firmware/target/arm/as3525/pcm-as3525.c @@ -43,9 +43,14 @@ static size_t dma_rem_size; /* Remaining size - in 4*32 bits */ static size_t play_sub_size; /* size of current subtransfer */ static void dma_callback(void); static int locked = 0; -static bool is_playing = false; +static bool volatile is_playing = false; static bool play_callback_pending = false; +#ifdef HAVE_RECORDING +/* Stopping playback gates clock if not recording */ +static bool volatile is_recording = false; +#endif + /* Mask the DMA interrupt */ void pcm_play_lock(void) { @@ -116,26 +121,27 @@ static void dma_callback(void) void pcm_play_dma_start(const void *addr, size_t size) { + is_playing = true; + dma_start_addr = (void*)addr; dma_start_size = size; dma_sub_addr = dma_start_addr; dma_rem_size = size; - bitset32(&CGU_PERI, CGU_I2SOUT_APB_CLOCK_ENABLE); - CGU_AUDIO |= (1<<11); - dma_retain(); - is_playing = true; - /* force writeback */ clean_dcache_range(dma_start_addr, dma_start_size); + + bitset32(&CGU_AUDIO, (1<<11)); + play_start_pcm(); } void pcm_play_dma_stop(void) { is_playing = false; + dma_disable_channel(1); /* Ensure byte counts read back 0 */ @@ -146,8 +152,10 @@ void pcm_play_dma_stop(void) dma_release(); - bitclr32(&CGU_PERI, CGU_I2SOUT_APB_CLOCK_ENABLE); - CGU_AUDIO &= ~(1<<11); +#ifdef HAVE_RECORDING + if (!is_recording) + bitclr32(&CGU_AUDIO, (1<<11)); +#endif play_callback_pending = false; } @@ -175,10 +183,10 @@ void pcm_play_dma_pause(bool pause) void pcm_play_dma_init(void) { bitset32(&CGU_PERI, CGU_I2SOUT_APB_CLOCK_ENABLE); - - I2SOUT_CONTROL = (1<<6)|(1<<3) /* enable dma, stereo */; + I2SOUT_CONTROL = (1<<6) | (1<<3); /* enable dma, stereo */ audiohw_preinit(); + pcm_dma_apply_settings(); } void pcm_play_dma_postinit(void) @@ -209,14 +217,15 @@ static inline unsigned char mclk_divider(void) void pcm_dma_apply_settings(void) { - int cgu_audio = CGU_AUDIO; /* read register */ - cgu_audio &= ~(3 << 0); /* clear i2sout MCLK_SEL */ - cgu_audio |= (AS3525_MCLK_SEL << 0); /* set i2sout MCLK_SEL */ - cgu_audio &= ~(0x1ff << 2); /* clear i2sout divider */ - cgu_audio |= mclk_divider() << 2; /* set new i2sout divider */ - cgu_audio &= ~(1 << 23); /* clear I2SI_MCLK_EN */ - cgu_audio &= ~(1 << 24); /* clear I2SI_MCLK2PAD_EN */ - CGU_AUDIO = cgu_audio; /* write back register */ + bitmod32(&CGU_AUDIO, + (0<<24) | /* I2SI_MCLK2PAD_EN = disabled */ + (0<<23) | /* I2SI_MCLK_EN = disabled */ + (0<<14) | /* I2SI_MCLK_DIV_SEL = unused */ + (0<<12) | /* I2SI_MCLK_SEL = clk_main */ + /* I2SO_MCLK_EN = unchanged */ + (mclk_divider() << 2) | /* I2SO_MCLK_DIV_SEL */ + (AS3525_MCLK_SEL << 0), /* I2SO_MCLK_SEL */ + 0x01fff7ff); } size_t pcm_get_bytes_waiting(void) @@ -258,220 +267,158 @@ void * pcm_dma_addr(void *addr) #ifdef HAVE_RECORDING static int rec_locked = 0; -static bool is_recording = false; -static bool rec_callback_pending = false; -static void *rec_dma_start_addr; -static size_t rec_dma_size, rec_dma_transfer_size; -static void rec_dma_callback(void); -#if CONFIG_CPU == AS3525 -/* points to the samples which need to be duplicated into the right channel */ -static int16_t *mono_samples; -#endif - +static uint32_t *rec_dma_addr; +static size_t rec_dma_size; void pcm_rec_lock(void) { - ++rec_locked; -} - + int oldlevel = disable_irq_save(); -void pcm_rec_unlock(void) -{ - if(--rec_locked == 0 && is_recording) + if (++rec_locked == 1) { - int old = disable_irq_save(); - if(rec_callback_pending) - { - rec_callback_pending = false; - rec_dma_callback(); - } - restore_irq(old); + bitset32(&CGU_PERI, CGU_I2SIN_APB_CLOCK_ENABLE); + VIC_INT_EN_CLEAR = INTERRUPT_I2SIN; + I2SIN_MASK = 0; /* disables all interrupts */ } -} - -static void rec_dma_start(void) -{ - rec_dma_transfer_size = rec_dma_size; - - /* We are limited to 8188 DMA transfers, and the recording core asks for - * 8192 bytes. Avoid splitting 8192 bytes transfers in 8188 + 4 */ - if(rec_dma_transfer_size > 4096) - rec_dma_transfer_size = 4096; - - dma_enable_channel(1, (void*)I2SIN_DATA, rec_dma_start_addr, DMA_PERI_I2SIN, - DMAC_FLOWCTRL_DMAC_PERI_TO_MEM, false, true, - rec_dma_transfer_size >> 2, DMA_S4, rec_dma_callback); + restore_irq(oldlevel); } -#if CONFIG_CPU == AS3525 -/* if needed, duplicate samples of the working channel until the given bound */ -static inline void mono2stereo(int16_t *end) -{ - if(audio_channels != 1) /* only for microphone */ - return; -#if 0 - /* load pointer in a register and avoid updating it in each loop */ - register int16_t *samples = mono_samples; - - do { - int16_t left = *samples++; // load 1 sample of the left-channel - *samples++ = left; // copy it in the right-channel - } while(samples != end); - - mono_samples = samples; /* update pointer */ -#else - /* gcc doesn't use pre indexing : let's save 1 cycle */ - int16_t left; - asm ( - "1: ldrh %0, [%1], #2 \n" // load 1 sample of the left-channel - " strh %0, [%1], #2 \n" // copy it in the right-channel - " cmp %1, %2 \n" // are we finished? - " bne 1b \n" - : "=&r"(left), "+r"(mono_samples) - : "r"(end) - : "memory" - ); -#endif /* C / ASM */ -} -#endif /* CONFIG_CPU == AS3525 */ - -#if CONFIG_CPU == AS3525v2 -/* scale microphone audio by 2 bits due to 14 bit ADC */ -static inline void scalevolume(int16_t *end, int size) +void pcm_rec_unlock(void) { - if(audio_channels != 1) /* only for microphone */ - return; - - /* load pointer in a register and avoid updating it in each loop */ - register int16_t *samples = end; - - do { - *samples++ <<=2; - - } while(samples != end+size); - -} -#endif /* CONFIG_CPU == AS3525v2 */ + int oldlevel = disable_irq_save(); -static void rec_dma_callback(void) -{ - if(rec_dma_transfer_size) + if (--rec_locked == 0 && is_recording) { + VIC_INT_ENABLE = INTERRUPT_I2SIN; + I2SIN_MASK = (1<<2); /* I2SIN_MASK_POAF */ + } -#if CONFIG_CPU == AS3525v2 - scalevolume(AS3525_UNCACHED_ADDR((int16_t*)rec_dma_start_addr), rec_dma_transfer_size); -#endif - rec_dma_size -= rec_dma_transfer_size; - rec_dma_start_addr += rec_dma_transfer_size; + restore_irq(oldlevel); +} - /* don't act like we just transferred data when we are called from - * pcm_rec_unlock() */ - rec_dma_transfer_size = 0; +void INT_I2SIN(void) +{ #if CONFIG_CPU == AS3525 - /* the 2nd channel is silent when recording microphone on as3525v1 */ - mono2stereo(AS3525_UNCACHED_ADDR((int16_t*)rec_dma_start_addr)); -#endif - - if(locked) + if (audio_channels == 1) + { + /* RX is left-channel-only mono */ + while (rec_dma_size > 0) { - rec_callback_pending = is_recording; - return; + if (I2SIN_RAW_STATUS & (1<<5)) + return; /* empty */ + + /* Discard every other sample since ADC clock is 1/2 LRCK */ + uint32_t value = *I2SIN_DATA; + *I2SIN_DATA; + + /* Data is in left channel only - copy to right channel + 14-bit => 16-bit samples */ + value = (uint16_t)(value << 2) | (value << 18); + + if (audio_output_source != AUDIO_SRC_PLAYBACK && !is_playing) + { + /* In this case, loopback is manual so that both output + channels have audio */ + if (I2SOUT_RAW_STATUS & (1<<5)) + { + /* 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; + } + + *rec_dma_addr++ = value; + rec_dma_size -= 4; } } - - if(!rec_dma_size) + else +#endif /* CONFIG_CPU == AS3525 */ { - pcm_rec_more_ready_callback(0, &rec_dma_start_addr, - &rec_dma_size); + /* RX is stereo */ + while (rec_dma_size > 0) + { + if (I2SIN_RAW_STATUS & (1<<5)) + return; /* empty */ - if(rec_dma_size == 0) - return; + /* Discard every other sample since ADC clock is 1/2 LRCK */ + uint32_t value = *I2SIN_DATA; + *I2SIN_DATA; - dump_dcache_range(rec_dma_start_addr, rec_dma_size); -#if CONFIG_CPU == AS3525 - mono_samples = AS3525_UNCACHED_ADDR((int16_t*)rec_dma_start_addr); -#endif + /* Loopback is in I2S hardware */ + + /* 14-bit => 16-bit samples */ + *rec_dma_addr++ = (value << 2) & ~0x00030000; + rec_dma_size -= 4; + } } - rec_dma_start(); + pcm_rec_more_ready_callback(0, (void *)&rec_dma_addr, &rec_dma_size); } + void pcm_rec_dma_stop(void) { is_recording = false; - dma_disable_channel(1); - dma_release(); - rec_dma_size = 0; - I2SIN_CONTROL &= ~(1<<11); /* disable dma */ + VIC_INT_EN_CLEAR = INTERRUPT_I2SIN; + I2SIN_MASK = 0; /* disables all interrupts */ + + rec_dma_addr = NULL; + rec_dma_size = 0; - CGU_AUDIO &= ~(1<<11); - bitclr32(&CGU_PERI, CGU_I2SIN_APB_CLOCK_ENABLE | - CGU_I2SOUT_APB_CLOCK_ENABLE); + if (!is_playing) + bitclr32(&CGU_AUDIO, (1<<11)); - rec_callback_pending = false; + bitclr32(&CGU_PERI, CGU_I2SIN_APB_CLOCK_ENABLE); } void pcm_rec_dma_start(void *addr, size_t size) { - dump_dcache_range(addr, size); - rec_dma_start_addr = addr; -#if CONFIG_CPU == AS3525 - mono_samples = AS3525_UNCACHED_ADDR(addr); -#endif - rec_dma_size = size; - - dma_retain(); + is_recording = true; - bitset32(&CGU_PERI, CGU_I2SIN_APB_CLOCK_ENABLE | - CGU_I2SOUT_APB_CLOCK_ENABLE); - CGU_AUDIO |= (1<<11); + bitset32(&CGU_AUDIO, (1<<11)); - I2SIN_CONTROL |= (1<<11)|(1<<5); /* enable dma, 14bits samples */ + rec_dma_addr = addr; + rec_dma_size = size; - is_recording = true; + /* ensure empty FIFO */ + while (!(I2SIN_RAW_STATUS & (1<<5))) + *I2SIN_DATA; - rec_dma_start(); + I2SIN_CLEAR = (1<<6) | (1<<0); /* push error, pop error */ } void pcm_rec_dma_close(void) { + bitset32(&CGU_PERI, CGU_I2SIN_APB_CLOCK_ENABLE); + pcm_rec_dma_stop(); } void pcm_rec_dma_init(void) { - /* i2c clk src = I2SOUTIF, sdata src = AFE, - * data valid at positive edge of SCLK */ - I2SIN_CONTROL = (1<<2); + bitset32(&CGU_PERI, CGU_I2SIN_APB_CLOCK_ENABLE); + I2SIN_MASK = 0; /* disables all interrupts */ + + /* 14 bits samples, i2c clk src = I2SOUTIF, sdata src = AFE, + * data valid at positive edge of SCLK */ + I2SIN_CONTROL = (1<<5) | (1<<2); } const void * pcm_rec_dma_get_peak_buffer(void) { -#if CONFIG_CPU == AS3525 - /* - * We need to prevent the DMA callback from kicking in while we are - * faking the right channel with data from left channel. - */ - - int old = disable_irq_save(); - int16_t *addr = AS3525_UNCACHED_ADDR((int16_t *)DMAC_CH_DST_ADDR(1)); - mono2stereo(addr); - restore_irq(old); - - return addr; - -#else - /* Microphone recording is stereo on as3525v2 */ - return AS3525_UNCACHED_ADDR((int16_t *)DMAC_CH_DST_ADDR(1)); -#endif + return rec_dma_addr; } #endif /* HAVE_RECORDING */ diff --git a/firmware/target/arm/sandisk/audio-c200_e200.c b/firmware/target/arm/sandisk/audio-c200_e200.c index 2f6bde1b98..4de7aa62c3 100644 --- a/firmware/target/arm/sandisk/audio-c200_e200.c +++ b/firmware/target/arm/sandisk/audio-c200_e200.c @@ -186,16 +186,25 @@ void audiohw_set_sampr_dividers(int fsel) IISDIV = (IISDIV & ~0xc000003f) | regvals[fsel].iisdiv; } -#ifdef HAVE_RECORDING -unsigned int pcm_sampr_type_rec_to_play(unsigned int samplerate) +#ifdef CONFIG_SAMPR_TYPES +unsigned int pcm_sampr_to_hw_sampr(unsigned int samplerate, + unsigned int type) { - /* Check if the samplerate is in the list of recordable rates. - * Fail to default if not */ - int index = round_value_to_list32(samplerate, rec_freq_sampr, - REC_NUM_FREQ, false); - if (samplerate != rec_freq_sampr[index]) - return HW_SAMPR_DEFAULT; - - return samplerate * 2; /* Recording rates are 1/2 the codec clock */ +#ifdef HAVE_RECORDING + if (samplerate != HW_SAMPR_RESET && type == SAMPR_TYPE_REC) + { + /* Check if the samplerate is in the list of recordable rates. + * Fail to default if not */ + int index = round_value_to_list32(samplerate, rec_freq_sampr, + REC_NUM_FREQ, false); + if (samplerate != rec_freq_sampr[index]) + samplerate = REC_SAMPR_DEFAULT; + + samplerate *= 2; /* Recording rates are 1/2 the codec clock */ + } +#endif /* HAVE_RECORDING */ + + return samplerate; + (void)type; } -#endif +#endif /* CONFIG_SAMPR_TYPES */ |