summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRafaël Carré <rafael.carre@gmail.com>2010-06-01 09:39:08 +0000
committerRafaël Carré <rafael.carre@gmail.com>2010-06-01 09:39:08 +0000
commitdc32a5b14ccad55ce1f1848a16d5605b9019ae87 (patch)
treeea4d735549d3e85f1ed76bf1713c79f79730c790
parent9b935b2888738ed7228ac75863b0d0ac195629cc (diff)
downloadrockbox-dc32a5b14ccad55ce1f1848a16d5605b9019ae87.tar.gz
rockbox-dc32a5b14ccad55ce1f1848a16d5605b9019ae87.zip
as3525 PCM: implement locking like done for the gigabeats in r26341
this removes workaround for spurious interrupts added in r26316 side effect: make keyclicks work correctly when used intensively (with the scrollwheel for example), the clicks should be inserted fast enough for the PCM fifo to not become empty. PL190 can cause spurious interrupts if an interrupt is triggered by a peripheral shortly before the interrupt for this peripheral is cleared from VIC registers. As an effect we should only write in VIC_INT_EN_CLEAR after having disabled the source of the interrupt in the peripheral. references on PL190 spurious interrupts: - http://www.embeddedrelated.com/groups/lpc2000/show/14599.php - http://water.cse.unsw.edu.au/esdk/lpc2/spurious-irq.html git-svn-id: svn://svn.rockbox.org/rockbox/trunk@26444 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--firmware/target/arm/as3525/pcm-as3525.c72
1 files changed, 57 insertions, 15 deletions
diff --git a/firmware/target/arm/as3525/pcm-as3525.c b/firmware/target/arm/as3525/pcm-as3525.c
index 5a403bad83..9f31d623fe 100644
--- a/firmware/target/arm/as3525/pcm-as3525.c
+++ b/firmware/target/arm/as3525/pcm-as3525.c
@@ -39,21 +39,28 @@ static unsigned char *dma_start_addr;
39static size_t dma_size; /* in 4*32 bits */ 39static size_t dma_size; /* in 4*32 bits */
40static void dma_callback(void); 40static void dma_callback(void);
41static int locked = 0; 41static int locked = 0;
42 42static bool is_playing = false;
43static int play_irq_state; 43static bool play_callback_pending = false;
44 44
45/* Mask the DMA interrupt */ 45/* Mask the DMA interrupt */
46void pcm_play_lock(void) 46void pcm_play_lock(void)
47{ 47{
48 if(++locked == 1) 48 ++locked;
49 play_irq_state = disable_irq_save();
50} 49}
51 50
52/* Unmask the DMA interrupt if enabled */ 51/* Unmask the DMA interrupt if enabled */
53void pcm_play_unlock(void) 52void pcm_play_unlock(void)
54{ 53{
55 if(--locked == 0) 54 if(--locked == 0 && is_playing)
56 restore_irq(play_irq_state); 55 {
56 int old = disable_irq_save();
57 if(play_callback_pending)
58 {
59 play_callback_pending = false;
60 dma_callback();
61 }
62 restore_irq(old);
63 }
57} 64}
58 65
59static void play_start_pcm(void) 66static void play_start_pcm(void)
@@ -74,6 +81,12 @@ static void play_start_pcm(void)
74 81
75static void dma_callback(void) 82static void dma_callback(void)
76{ 83{
84 if(locked)
85 {
86 play_callback_pending = is_playing;
87 return;
88 }
89
77 if(!dma_size) 90 if(!dma_size)
78 { 91 {
79 pcm_play_get_more_callback((void **)&dma_start_addr, &dma_size); 92 pcm_play_get_more_callback((void **)&dma_start_addr, &dma_size);
@@ -95,11 +108,14 @@ void pcm_play_dma_start(const void *addr, size_t size)
95 108
96 dma_retain(); 109 dma_retain();
97 110
111 is_playing = true;
112
98 play_start_pcm(); 113 play_start_pcm();
99} 114}
100 115
101void pcm_play_dma_stop(void) 116void pcm_play_dma_stop(void)
102{ 117{
118 is_playing = false;
103 dma_disable_channel(1); 119 dma_disable_channel(1);
104 dma_size = 0; 120 dma_size = 0;
105 121
@@ -111,6 +127,8 @@ void pcm_play_dma_stop(void)
111 127
112void pcm_play_dma_pause(bool pause) 128void pcm_play_dma_pause(bool pause)
113{ 129{
130 is_playing = !pause;
131
114 if(pause) 132 if(pause)
115 dma_disable_channel(1); 133 dma_disable_channel(1);
116 else 134 else
@@ -192,6 +210,8 @@ void * pcm_dma_addr(void *addr)
192#ifdef HAVE_RECORDING 210#ifdef HAVE_RECORDING
193 211
194static int rec_locked = 0; 212static int rec_locked = 0;
213static bool is_recording = false;
214static bool rec_callback_pending = false;
195static unsigned char *rec_dma_start_addr; 215static unsigned char *rec_dma_start_addr;
196static size_t rec_dma_size, rec_dma_transfer_size; 216static size_t rec_dma_size, rec_dma_transfer_size;
197static void rec_dma_callback(void); 217static void rec_dma_callback(void);
@@ -200,19 +220,25 @@ static void rec_dma_callback(void);
200static int16_t *mono_samples; 220static int16_t *mono_samples;
201#endif 221#endif
202 222
203static int rec_irq_state;
204 223
205void pcm_rec_lock(void) 224void pcm_rec_lock(void)
206{ 225{
207 if(++rec_locked == 1) 226 ++rec_locked;
208 rec_irq_state = disable_irq_save();
209} 227}
210 228
211 229
212void pcm_rec_unlock(void) 230void pcm_rec_unlock(void)
213{ 231{
214 if(--rec_locked == 0) 232 if(--rec_locked == 0 && is_recording)
215 restore_irq(rec_irq_state); 233 {
234 int old = disable_irq_save();
235 if(rec_callback_pending)
236 {
237 rec_callback_pending = false;
238 rec_dma_callback();
239 }
240 restore_irq(old);
241 }
216} 242}
217 243
218 244
@@ -268,11 +294,24 @@ static inline void mono2stereo(int16_t *end)
268 294
269static void rec_dma_callback(void) 295static void rec_dma_callback(void)
270{ 296{
271 rec_dma_size -= rec_dma_transfer_size; 297 if(rec_dma_transfer_size)
272 rec_dma_start_addr += rec_dma_transfer_size; 298 {
299 rec_dma_size -= rec_dma_transfer_size;
300 rec_dma_start_addr += rec_dma_transfer_size;
301
302 /* don't act like we just transferred data when we are called from
303 * pcm_rec_unlock() */
304 rec_dma_transfer_size = 0;
273 305
274 /* the 2nd channel is silent when recording microphone on as3525v1 */ 306 /* the 2nd channel is silent when recording microphone on as3525v1 */
275 mono2stereo(AS3525_UNCACHED_ADDR((int16_t*)rec_dma_start_addr)); 307 mono2stereo(AS3525_UNCACHED_ADDR((int16_t*)rec_dma_start_addr));
308
309 if(locked)
310 {
311 rec_callback_pending = is_recording;
312 return;
313 }
314 }
276 315
277 if(!rec_dma_size) 316 if(!rec_dma_size)
278 { 317 {
@@ -293,6 +332,7 @@ static void rec_dma_callback(void)
293 332
294void pcm_rec_dma_stop(void) 333void pcm_rec_dma_stop(void)
295{ 334{
335 is_recording = false;
296 dma_disable_channel(1); 336 dma_disable_channel(1);
297 dma_release(); 337 dma_release();
298 rec_dma_size = 0; 338 rec_dma_size = 0;
@@ -320,6 +360,8 @@ void pcm_rec_dma_start(void *addr, size_t size)
320 360
321 I2SIN_CONTROL |= (1<<11)|(1<<5); /* enable dma, 14bits samples */ 361 I2SIN_CONTROL |= (1<<11)|(1<<5); /* enable dma, 14bits samples */
322 362
363 is_recording = true;
364
323 rec_dma_start(); 365 rec_dma_start();
324} 366}
325 367