From: Craig C. <cra...@gm...> - 2005-12-01 00:19:54
|
Hello everyone, I'm interested in using my gumstix for a realtime audio application. To ge= t the required functionality, all I really need is to have a realtime IRQ (an interrupt that cannot be disabled by the gumstix kernel). I've used RTLinu= x to get this working before, but I'd like to get this working on the kernel supplied with the gumstix. Does anyone know anything about how to get this done on this hardware? It seems to me that I need to modify local_irq_disable() and local_irq_save() to not mask out the interrupt on for the pxa audio card. (The audio driver then needs to be modified as well). I was just wondering if anyone had done anything realtime on the gumstix before, or needs functionality like this in the future. Thanks, CCasey |
From: Dave H. <dhy...@gm...> - 2005-12-01 03:03:56
|
Hi Craig, > I'm interested in using my gumstix for a realtime audio application. To = get > the required functionality, all I really need is to have a realtime IRQ (= an > interrupt that cannot be disabled by the gumstix kernel). I've used RTLi= nux > to get this working before, but I'd like to get this working on the kerne= l > supplied with the gumstix. Does anyone know anything about how to get th= is > done on this hardware? It seems to me that I need to modify > local_irq_disable() and local_irq_save() to not mask out the interrupt on > for the pxa audio card. (The audio driver then needs to be modified as > well). > > I was just wondering if anyone had done anything realtime on the gumstix > before, or needs functionality like this in the future. There are a couple of different types of interrupt disables. The local_irq_save/restore messes with the global one. Then there are a bunch of other irq sources that all feed into that one. So, in theory, you could have local_irq_disable do: disable the global interrtupts, save off the interrupt mask register (ICMR) and set it to zero, restore global interrupts. Then local_irq_restore would do: disable the global interrupts restore the mask register restore global interrupts. Another option to consider is to use FIQ for your audio interrupts. If I remember correctly, local_irq_disable doesn't disable the FIQ, and nothing in the amr linux currently uses the FIQ. -- Dave Hylands Vancouver, BC, Canada http://www.DaveHylands.com/ |
From: Craig C. <cra...@gm...> - 2005-12-01 13:46:14
|
Hi Dave, Thanks for your response. Both of your thoughts are very much inline with my current ideas about how to get this job done. I'm not entirely sure about what your saying for the local_irq_disable()-and _enables() though. Wouldn't I want to set the interrupt mask register (ICMR) to be ( 0 | IRQ_AC97 ) where IRQ_AC97 is the interrupt for the realtime audio? Maybe I am misunderstanding the purpose of that register. Do you know if this is the same as the cpsr seen in local_irq_disable? local_irq_disable boils down to these three assembly instructions: mrs (temp), cpsr orr (temp), (temp), #128 msr (cpsr_c), (temp) It seems that if I change the #128 in the orr to include the ac97 interrupt in it's bitmask, it should never disable the audio interrupt. I tried this last night and it failed to compile, though I'm not certain why. The compiler says: "/tmp/ccysOjJB.s:1481: Error: invalid constant -- `orr r3,r7,#73856'" a bunch of times. I'm thinking that 73856 is probably not the right consta= nt. Currently, I'm looking at using an FIQ. I'm not entirely sure how to make the pxa-audio's irq show up as a FIQ. According to the Intel manual on the PXA255, I should need to only change a few bits in the ICLR register, though I'm not sure if this will interfere with something else going on in linux. I don't see a request_fiq() function, or anything quite the same. Does anyone have an example of setting up an FIQ handler in linux?=20 This would be invaluable. Thanks, CCasey > > There are a couple of different types of interrupt disables. The > local_irq_save/restore messes with the global one. > > Then there are a bunch of other irq sources that all feed into that > one. So, in theory, you could have local_irq_disable do: > > disable the global interrtupts, > save off the interrupt mask register (ICMR) and set it to zero, > restore global interrupts. > > Then local_irq_restore would do: > > disable the global interrupts > restore the mask register > restore global interrupts. > > Another option to consider is to use FIQ for your audio interrupts. If > I remember correctly, local_irq_disable doesn't disable the FIQ, and > nothing in the amr linux currently uses the FIQ. > > -- > Dave Hylands > Vancouver, BC, Canada > http://www.DaveHylands.com/ > > > ------------------------------------------------------- > This SF.net email is sponsored by: Splunk Inc. Do you grep through log fi= les > for problems? Stop! Download the new AJAX search engine that makes > searching your log files as easy as surfing the web. DOWNLOAD SPLUNK! > http://ads.osdn.com/?ad_idv37&alloc_id=16865&opclick > _______________________________________________ > gumstix-users mailing list > gum...@li... > https://lists.sourceforge.net/lists/listinfo/gumstix-users > |
From: Dave H. <dhy...@gm...> - 2005-12-01 15:12:14
|
Hi Craig, > Both of your thoughts are very much inline with my current ideas about > how to get this job done. I'm not entirely sure about what your > saying for the local_irq_disable()-and _enables() though. Wouldn't I > want to set the interrupt mask register (ICMR) to be ( 0 | IRQ_AC97 ) > where IRQ_AC97 is the interrupt for the realtime audio? Almost. ICMR uses bitmasks. IRQ_AC97 is a bit number, not a bit mask. You'll want to take a close look at arch/arm/mach-pxa/irq.c and notice the use of PXA_IRQ_SKIP. > Maybe I am > misunderstanding the purpose of that register. Do you know if this is > the same as the cpsr seen in local_irq_disable? The CPSR register contains the global interrupt disable. The ICMR register is the mask which determines which interrupt sources are actually enabled. You'll need to disable global interrupts while you're messing with this register or you'll have race conditions (which will probably eventually lead to a kernel crash). > local_irq_disable boils down to these three assembly instructions: > mrs (temp), cpsr > orr (temp), (temp), #128 > msr (cpsr_c), (temp) 128 =3D 0x80 =3D the one bit which is the global interrupt enable flag. > It seems that if I change the #128 in the orr to include the ac97 > interrupt in it's bitmask, it should never disable the audio > interrupt. These are in different registers. > Currently, I'm looking at using an FIQ. I'm not entirely sure how to > make the pxa-audio's irq show up as a FIQ. According to the Intel > manual on the PXA255, I should need to only change a few bits in the > ICLR register, though I'm not sure if this will interfere with > something else going on in linux. I don't see a request_fiq() > function, or anything quite the same. There's a set_fiq_handler function (in the linux arch/arm/kernel/fiq.c file), but from looking at it it would appear that you need to write the FIQ entry in assembler. There are lots of gotchas with using FIQs since you can't interact with the rest of the kernel in a safe way (because FIQs interrupt IRQs), and FIQ handlers can't reside in modules (because the paging mechanism relies in interrupt saftey and you don't get that with FIQs). So tread VERY carefully. > Does anyone have an example of setting up an FIQ handler in linux? > This would be invaluable. There was a message in the archives from about 4 weeks ago: http://sourceforge.net/mailarchive/message.php?msg_id=3D13697997 -- Dave Hylands Vancouver, BC, Canada http://www.DaveHylands.com/ |
From: Craig C. <cra...@gm...> - 2005-12-02 16:40:44
|
Hey Dave, Thanks again for your thoughts. You've cleared a few things up for me. I'm currently working on implementing the selective interrupt toggling from inside disable_irq_local and what not. I'm a bit new at the whole assembly thing on ARM, but the ideas themselves are not difficult. > There's a set_fiq_handler function (in the linux arch/arm/kernel/fiq.c > file), but from looking at it it would appear that you need to write > the FIQ entry in assembler. I had considered this for a while. The FIQ is really exactly what I need, but I'd have to figure out some way to be able to program C from within the FIQ. I think this should be the same code as handles interrupts at the very lowest level, but I'm not really sure where to find it. It should be in .../entry.S someplace, but I'm not really sure. Would this approach work, or am I missing something alltogether? > There are lots of gotchas with using FIQs since you can't interact > with the rest of the kernel in a safe way (because FIQs interrupt > IRQs), and FIQ handlers can't reside in modules (because the paging > mechanism relies in interrupt saftey and you don't get that with > FIQs). > > So tread VERY carefully. > > > Does anyone have an example of setting up an FIQ handler in linux? > > This would be invaluable. > > There was a message in the archives from about 4 weeks ago: > http://sourceforge.net/mailarchive/message.php?msg_id=3D13697997 > Thanks for the pointer to the example. That's a great starting point to implementing a useful FIQ handler. FIQ's really have the same semantics as realtime IRQ's in RTLinux (www.fsmlabs.com). I've got a small library of audio processing tools that work in that context, but I must admit it is a pain making everything work without the C library -or- the kernel. Anyway, Thanks again for your help. CCasey. |
From: Pascal A. B. <pas...@wa...> - 2005-12-02 18:14:37
|
Craig Casey writes: > need, but I'd have to figure out some way to be able to program C from > within the FIQ. I wrote this small stub which saves registers, sets up a stack, then calls a regular C function. Consider it a quick-and-dirty solution; the proper way is to link a .S file as you suggest. Note that r8-r14 are shadowed in FIQ mode. -- Pascal | void fiq_handler(void) { | static struct pt_regs fiq_saved_regs; | static unsigned char fiq_stack[256]; | __asm__ volatile ( | "@ Save OSCR asap for profiling \n\ | mov r9, #0xf2000000 \n\ | eor r9, r9, #0x00a00000 \n\ | ldr r9, [r9, #0x10] \n\ | @ Save registers \n\ | ldr r8, %0 \n\ | stmia r8, {r0-r3,lr} \n\ | @ Invoke the regular IRQ handler \n\ | ldr sp, %1 \n\ | @ Can't use a relative branch-and-link since this \n\ | @ handler will be relocated to fiq_vector. \n\ | @ bl mpwm_irq_handler \n\ | mov lr, pc \n\ | ldr pc, %2 \n\ | @ Restore registers and return \n\ | ldr r8, %0 \n\ | ldmia r8, {r0-r3,lr} \n\ | subs pc, lr, #4" | : | : "im"(&fiq_saved_regs.ARM_r0), "im"(&fiq_stack[256]), | "im"(irq_handler)); | } | void fiq_handler_end(void) { } | static unsigned long *const fiq_vector = (unsigned long*)0xffff001c; | memcpy(fiq_vector, fiq_handler+12, fiq_handler_end-fiq_handler-12); | flush_icache_range((long)fiq_vector, | (long)fiq_vector+fiq_handler_end-fiq_handler-12); |
From: Craig C. <cra...@gm...> - 2005-12-02 18:30:11
|
Pascal, Incredible. This is exactly what I need. Thanks!!! Craig On 12/2/05, Pascal A. Brisset <pas...@wa...> wrote: > > Craig Casey writes: > > need, but I'd have to figure out some way to be able to program C from > > within the FIQ. > > I wrote this small stub which saves registers, sets up a stack, > then calls a regular C function. Consider it a quick-and-dirty > solution; the proper way is to link a .S file as you suggest. > > Note that r8-r14 are shadowed in FIQ mode. > > -- Pascal > > | void fiq_handler(void) { > | static struct pt_regs fiq_saved_regs; > | static unsigned char fiq_stack[256]; > | __asm__ volatile ( > | "@ Save OSCR asap for profiling \n\ > | mov r9, #0xf2000000 \n\ > | eor r9, r9, #0x00a00000 \n\ > | ldr r9, [r9, #0x10] \n\ > | @ Save registers \n\ > | ldr r8, %0 \n\ > | stmia r8, {r0-r3,lr} \n\ > | @ Invoke the regular IRQ handler \n\ > | ldr sp, %1 \n\ > | @ Can't use a relative branch-and-link since this \n\ > | @ handler will be relocated to fiq_vector. \n\ > | @ bl mpwm_irq_handler \n\ > | mov lr, pc \n\ > | ldr pc, %2 \n\ > | @ Restore registers and return \n\ > | ldr r8, %0 \n\ > | ldmia r8, {r0-r3,lr} \n\ > | subs pc, lr, #4" > | : > | : "im"(&fiq_saved_regs.ARM_r0), "im"(&fiq_stack[256]), > | "im"(irq_handler)); > | } > | void fiq_handler_end(void) { } > > | static unsigned long *const fiq_vector =3D (unsigned long*)0xffff001c; > | memcpy(fiq_vector, fiq_handler+12, fiq_handler_end-fiq_handler-12); > | flush_icache_range((long)fiq_vector, > | (long)fiq_vector+fiq_handler_end-fiq_handler-12); > > > > ------------------------------------------------------- > This SF.net email is sponsored by: Splunk Inc. Do you grep through log > files > for problems? Stop! Download the new AJAX search engine that makes > searching your log files as easy as surfing the web. DOWNLOAD SPLUNK! > http://ads.osdn.com/?ad_id=3D7637&alloc_id=3D16865&op=3Dclick > _______________________________________________ > gumstix-users mailing list > gum...@li... > https://lists.sourceforge.net/lists/listinfo/gumstix-users > |
From: Jonathan B. <jbr...@ea...> - 2005-12-03 19:25:58
|
On Fri, 2005-12-02 at 19:14 +0100, Pascal A.Brisset wrote: > Craig Casey writes: > > need, but I'd have to figure out some way to be able to program C from > > within the FIQ. > > I wrote this small stub which saves registers, sets up a stack, > then calls a regular C function. Consider it a quick-and-dirty > solution; the proper way is to link a .S file as you suggest. > > Note that r8-r14 are shadowed in FIQ mode. How much of this work is done by the GCC function __attribute__((interrupt("FIQ")))? Thanks, -Jonathan |
From: Pascal A. B. <pas...@wa...> - 2005-12-03 20:02:33
|
Jonathan Brandmeyer writes: > How much of this work is done by the GCC function > __attribute__((interrupt("FIQ")))? Interesting, thanks. It seems to save registers and return as required. You'd need to initialize pt_regs.ARM_sp with set_fiq_regs() first. Some people used to say it was broken, but hopefully it has been fixed since then ( http://gcc.gnu.org/ml/gcc/2003-01/msg00985.html ). Note that it writes 9 registers to the stack before your code has a chance to run. So I'll keep using assembly code whenever latency is critical (for instance, to read a timestamp as soon as possible). -- Pascal 0000049c <rtstub2>: 49c: e52dc004 str ip, [sp, #-4]! 4a0: e1a0c00d mov ip, sp 4a4: e92dd80f stmdb sp!, {r0, r1, r2, r3, fp, ip, lr, pc} 4a8: e24cb004 sub fp, ip, #4 ; 0x4 4ac: e3a00000 mov r0, #0 ; 0x0 4b0: ebfffffe bl 4b0 <rtstub2+0x14> 4b4: e2800001 add r0, r0, #1 ; 0x1 4b8: e89d680f ldmia sp, {r0, r1, r2, r3, fp, sp, lr} 4bc: e8bd1000 ldmia sp!, {ip} 4c0: e25ef004 subs pc, lr, #4 ; 0x4 |
From: Jonathan B. <jbr...@ea...> - 2005-12-04 19:59:20
|
On Fri, 2005-12-02 at 19:14 +0100, Pascal A.Brisset wrote: > Craig Casey writes: > > need, but I'd have to figure out some way to be able to program C from > > within the FIQ. > > I wrote this small stub which saves registers, sets up a stack, > then calls a regular C function. Consider it a quick-and-dirty > solution; the proper way is to link a .S file as you suggest. > > Note that r8-r14 are shadowed in FIQ mode. > > -- Pascal > > | void fiq_handler(void) { > | static struct pt_regs fiq_saved_regs; > | static unsigned char fiq_stack[256]; > | __asm__ volatile ( > | "@ Save OSCR asap for profiling \n\ > | mov r9, #0xf2000000 \n\ > | eor r9, r9, #0x00a00000 \n\ > | ldr r9, [r9, #0x10] \n\ I'm not an assembly programmer, and I'm trying to understand what's going on here. What is the benefit of constructing the virtual address of OSCR using an XOR and offset, rather than just mov r9, #0xf2a00010 ldr r9, [r9] Why is the first insn of this function located at &fiq_handler + 12? Is that true for all GCC-generated C functions, or is it something specific to this function? Thanks, -Jonathan |
From: Dave H. <dhy...@gm...> - 2005-12-04 20:41:15
|
Hi Jonathan, > > | "@ Save OSCR asap for profiling \n\ > > | mov r9, #0xf2000000 \n\ > > | eor r9, r9, #0x00a00000 \n\ > > | ldr r9, [r9, #0x10] \n\ > > I'm not an assembly programmer, and I'm trying to understand what's > going on here. What is the benefit of constructing the virtual address > of OSCR using an XOR and offset, rather than just > mov r9, #0xf2a00010 > ldr r9, [r9] It's one of the weird idosynchracies of ARM assembler. The ARM can load any 8 bit constant, shifted by an arbitrary amount, into a register. To load anything bigger requires loading some register with the address of a memory location (either PC relative or relative to some other register) which is slighty more complicated to setup. > Why is the first insn of this function located at &fiq_handler + 12? Is > that true for all GCC-generated C functions, or is it something specific > to this function? It's skipping the GCC generated prolog information. It's particular to the function and optimization settings used at the time, and isn't a recommend way of doing things. At the very least, I'd change the name of the function to be a dummy and introduce the fiq_handler and end_handler labels as part of the inline assembly. -- Dave Hylands Vancouver, BC, Canada http://www.DaveHylands.com/ |
From: Pascal A. B. <pas...@wa...> - 2005-12-04 22:08:05
|
Dave Hylands writes: > It's skipping the GCC generated prolog information. It's particular to > the function and optimization settings used at the time, and isn't a > recommend way of doing things. Indeed it depends on whether -fomit-frame-pointer is used, on which registers the function trashes, etc. Again, the proper approach is to write a separate .S file and find how to feed everything into the kernel build system. And __attribute__((interrupt("FIQ"))) is probably fine for most purposes. > At the very least, I'd change the name of the function to be a dummy > and introduce the fiq_handler and end_handler labels as part of the > inline assembly. Will do that for the start label. But you'd still need to make assumptions about where gcc stores the three __asm__ arguments. If you move end_handler into the inline asm, you'll need to use end_handler+16 later (skipping the ldmia and the three longs)... A related issue is how to pack several functions together so that I can lock them into the instruction cache. __attribute__((section(".packed.text"))) works, but I don't know how to reference the start and end of the section, so I'm assuming again that gcc won't reorder the functions. -- Pascal |