I gather this was discussed and resolved on IRC, but it's an important point a lot of people don't seem to realize offhand:
you can't just throw C function call (whether as a BL in the asm, or outside) somewhere in the canon asm and expect it to work.
GCC assumes you are adhering to some variant of the arm calling convention, which leave subroutines free to modify r0-r3 and the flags register (or return a value in r0 and modify the rest). See "Using the Procedure Call Standard" in
http://infocenter.arm.com/help/topic/com.arm.doc.dui0056d/DUI0056.pdf
This means that when you do something like
...
"MOV R0, SP\n"
"MOV R2, #0\n"
);
d_my_blink_green(); //6
...
You are going to get in trouble.
There are several ways you can avoid this:
- write your sub in ASM (or with ASM that saves and restores the regs that gcc doesn't do automatically)
- place your call somewhere that you know it won't have undesired side effects. This is what most of the CHDK code does. Typically, if you call your function directly after an existing subroutine call, the firmware code already assumes r1-r3 are trashed, and you can preserve r0 by making your code accept one argument and return it unchanged.
Somewhat related, there are GCC inline asm features that let your inform the compiler about what registers are changed etc
ARM GCC Inline Assembler Cookbook