diff options
Diffstat (limited to 'firmware/target/arm/as3525/pcm-as3525.c')
-rw-r--r-- | firmware/target/arm/as3525/pcm-as3525.c | 72 |
1 files changed, 60 insertions, 12 deletions
diff --git a/firmware/target/arm/as3525/pcm-as3525.c b/firmware/target/arm/as3525/pcm-as3525.c index c649acee7d..10877ecf41 100644 --- a/firmware/target/arm/as3525/pcm-as3525.c +++ b/firmware/target/arm/as3525/pcm-as3525.c | |||
@@ -193,8 +193,12 @@ void * pcm_dma_addr(void *addr) | |||
193 | 193 | ||
194 | static int rec_locked = 0; | 194 | static int rec_locked = 0; |
195 | static unsigned char *rec_dma_start_addr; | 195 | static unsigned char *rec_dma_start_addr; |
196 | static size_t rec_dma_size; | 196 | static size_t rec_dma_size, rec_dma_transfer_size; |
197 | static void rec_dma_callback(void); | 197 | static void rec_dma_callback(void); |
198 | #if CONFIG_CPU == AS3525 | ||
199 | /* points to the samples which need to be duplicated into the right channel */ | ||
200 | static int16_t *mono_samples; | ||
201 | #endif | ||
198 | 202 | ||
199 | 203 | ||
200 | void pcm_rec_lock(void) | 204 | void pcm_rec_lock(void) |
@@ -213,25 +217,58 @@ void pcm_rec_unlock(void) | |||
213 | 217 | ||
214 | static void rec_dma_start(void) | 218 | static void rec_dma_start(void) |
215 | { | 219 | { |
216 | void* addr = rec_dma_start_addr; | 220 | rec_dma_transfer_size = rec_dma_size; |
217 | size_t size = rec_dma_size; | ||
218 | 221 | ||
219 | /* We are limited to 8188 DMA transfers, and the recording core asks for | 222 | /* We are limited to 8188 DMA transfers, and the recording core asks for |
220 | * 8192 bytes. Avoid splitting 8192 bytes transfers in 8188 + 4 */ | 223 | * 8192 bytes. Avoid splitting 8192 bytes transfers in 8188 + 4 */ |
221 | if(size > 4096) | 224 | if(rec_dma_transfer_size > 4096) |
222 | size = 4096; | 225 | rec_dma_transfer_size = 4096; |
223 | |||
224 | rec_dma_size -= size; | ||
225 | rec_dma_start_addr += size; | ||
226 | 226 | ||
227 | dma_enable_channel(1, (void*)I2SIN_DATA, addr, DMA_PERI_I2SIN, | 227 | dma_enable_channel(1, (void*)I2SIN_DATA, rec_dma_start_addr, DMA_PERI_I2SIN, |
228 | DMAC_FLOWCTRL_DMAC_PERI_TO_MEM, false, true, size >> 2, DMA_S4, | 228 | DMAC_FLOWCTRL_DMAC_PERI_TO_MEM, false, true, |
229 | rec_dma_callback); | 229 | rec_dma_transfer_size >> 2, DMA_S4, rec_dma_callback); |
230 | } | 230 | } |
231 | 231 | ||
232 | 232 | ||
233 | /* if needed, duplicate samples of the working channel until the given bound */ | ||
234 | static inline void mono2stereo(int16_t *end) | ||
235 | { | ||
236 | #if CONFIG_CPU == AS3525 | ||
237 | if(audio_channels != 1) /* only for microphone */ | ||
238 | return; | ||
239 | #if 0 | ||
240 | do { | ||
241 | int16_t left = *mono_samples++; | ||
242 | *mono_samples++ = left; | ||
243 | } while(mono_samples != end); | ||
244 | #else | ||
245 | /* gcc doesn't use pre indexing and load/store mono_samples at each loop | ||
246 | * let's save some cycles with a smaller loop */ | ||
247 | int16_t tmp; | ||
248 | asm ( | ||
249 | "1: ldrh %0, [%1], #2 \n" | ||
250 | " strh %0, [%1], #2 \n" | ||
251 | " cmp %1, %2 \n" | ||
252 | " bne 1b \n" | ||
253 | : "=r"(tmp), "+r"(mono_samples) | ||
254 | : "r"(end) | ||
255 | : "memory" | ||
256 | ); | ||
257 | #endif /* C / ASM */ | ||
258 | #else | ||
259 | /* microphone recording is stereo on as3525v2 */ | ||
260 | (void)end; | ||
261 | #endif | ||
262 | } | ||
263 | |||
233 | static void rec_dma_callback(void) | 264 | static void rec_dma_callback(void) |
234 | { | 265 | { |
266 | rec_dma_size -= rec_dma_transfer_size; | ||
267 | rec_dma_start_addr += rec_dma_transfer_size; | ||
268 | |||
269 | /* the 2nd channel is silent when recording microphone on as3525v1 */ | ||
270 | mono2stereo(UNCACHED_ADDR((int16_t*)rec_dma_start_addr)); | ||
271 | |||
235 | if(!rec_dma_size) | 272 | if(!rec_dma_size) |
236 | { | 273 | { |
237 | register pcm_more_callback_type2 more_ready = pcm_callback_more_ready; | 274 | register pcm_more_callback_type2 more_ready = pcm_callback_more_ready; |
@@ -252,6 +289,9 @@ void pcm_rec_dma_record_more(void *start, size_t size) | |||
252 | { | 289 | { |
253 | dump_dcache_range(start, size); | 290 | dump_dcache_range(start, size); |
254 | rec_dma_start_addr = start; | 291 | rec_dma_start_addr = start; |
292 | #if CONFIG_CPU == AS3525 | ||
293 | mono_samples = UNCACHED_ADDR(start); | ||
294 | #endif | ||
255 | rec_dma_size = size; | 295 | rec_dma_size = size; |
256 | } | 296 | } |
257 | 297 | ||
@@ -274,6 +314,9 @@ void pcm_rec_dma_start(void *addr, size_t size) | |||
274 | { | 314 | { |
275 | dump_dcache_range(addr, size); | 315 | dump_dcache_range(addr, size); |
276 | rec_dma_start_addr = addr; | 316 | rec_dma_start_addr = addr; |
317 | #if CONFIG_CPU == AS3525 | ||
318 | mono_samples = UNCACHED_ADDR(addr); | ||
319 | #endif | ||
277 | rec_dma_size = size; | 320 | rec_dma_size = size; |
278 | 321 | ||
279 | dma_retain(); | 322 | dma_retain(); |
@@ -311,7 +354,12 @@ void pcm_rec_dma_init(void) | |||
311 | 354 | ||
312 | const void * pcm_rec_dma_get_peak_buffer(void) | 355 | const void * pcm_rec_dma_get_peak_buffer(void) |
313 | { | 356 | { |
314 | return UNCACHED_ADDR((void*)DMAC_CH_DST_ADDR(1)); | 357 | pcm_rec_lock(); |
358 | int16_t *addr = UNCACHED_ADDR((int16_t *)DMAC_CH_DST_ADDR(1)); | ||
359 | mono2stereo(addr); | ||
360 | pcm_rec_unlock(); | ||
361 | |||
362 | return addr; | ||
315 | } | 363 | } |
316 | 364 | ||
317 | #endif /* HAVE_RECORDING */ | 365 | #endif /* HAVE_RECORDING */ |