I've successfully managed to override the fps on my sx220 100a.
Most of the information I needed was found here:
http://magiclantern.wikia.com/wiki/VideoTimerhttp://groups.google.com/group/ml-develhttp://magiclantern.wikia.com/wiki/Register_Maptheir source fps_engio.c
and what srsa_4c posted here
http://chdk.wikia.com/wiki/User:Srsa_4c/Sensor_%26_LiveView_setupLimits:
-we can only decrease FPS
-we must have a way disable the audio in video mode or go into a movie mode where audio is disabled (such as slowmotion or miniature mode on sx220)
The fps can be overridden by modifying the head timer values in registers 0xC0F0600C, 0xC0F06014 and writing 1 to 0xC0F06000 to apply changes.
The math is simple:
For example the default values for regA and regB for 30 fps:
regA=0x473
regB=0x6db+1
fps=30000
frequency=regA*regB*fps==~60,000,000,000 (0x3938700*1000)
fps=frequency/regA/regB
we can find the default values struct by looking at where the ram address points in FldSpec.c (0xBBDC).
for 30fps looks like this:
ff446e00: 000298f1
ff446e04: 03938700 frequency
ff446e08: 04740474
ff446e0c: 04740474 regA
ff446e10: 00000474
ff446e14: 000006dc regB
ff446e18: 000006dc
...
ff446e24: 00090008
ff446e28: 00000000
ff446e2c: 00000003
...
ff446e80: 002d0000
ff446e84: 00000000
ff446e88: 000a06af
...
ff446ecc: 00000001
If we want 10fps we can calculate a new value for example: regA=60,000,000,000/10000/0x6dc=0xD58
In my tests I could go as low as 0.45fps, maybe lower is still possible.
To write to the registers we can use a function found in EngDrvOut, looks like this:
FF025808 MOV R2, R0,LSL#14
FF02580C MOV R2, R2,LSR#14
FF025810 ORR R2, R2, #0x400000
FF025814 STR R1, [R2]
FF025818 STR R1, [R0]
FF02581C BX LR
Or just rewrite it and simply SHIFT and OR the values and poke the addresses.
All this function does is converts the digic register address to a ram address 0xC0F06014->0X00406014 and stores the new value in both locations. To monitor what’s going on we can simply look at 0X004060C and 0X00406014 in the memory browser.
Disabling audio
The slow motion video mode on sx220 is limited to 640x480 so I needed to find a way to disable the audio to be able to use higher resolutions with fps overrides. This was the hardest part but I got lucky.
To do it we have to:
-modify a ram location(*(0xC2E3C+0x8)=0) in the right place in movie_rec.c task to prevent the audio being written.
-start recording and call a function that effectively disables the AudioIC and prevents a crash after the recording stops.
"loc_FF1879E8:\n"
"LDR R1, =0x777\n"
"LDR R0, =0xFF186114\n"
"BL sub_FF00EC88\n"
"loc_FF1879F4:\n"
);
if( (int)conf.disable_audio == 1)
{
asm volatile("BL disable_audio\n");
}
asm volatile(
"LDR R2, =0x8552\n"
"LDR R0, [R6, #0xB8]\n"
"MOV R3, #2\n"
"MOV R1, #0xAA\n"
"BL sub_FF08AD7C\n"
void __attribute__((naked,noinline)) disable_audio( ) {
asm volatile (
"STMFD SP!, {R0-R1,LR}\n"
"LDR R0, =0xC2E3C\n"
"MOV R1, #0\n"
"STR R1, [R0,#8]\n"
"LDMFD SP!, {R0-R1,PC}\n"
);
}
"loc_FF1883F4:\n"
);
extern short movie_status;
if( (int)conf.disable_audio == 1 && movie_status==4 && *(int*)0x85B8==1) //if recording_started && is_first_frame
{
asm volatile(
"BL sub_FF05BA94\n" //function that disables the AudioIC.
);
}
asm volatile (
"LDR R1, [R4,#0xF0]\n"
"BLX R1\n"
I found the function by backtracing 0xC0920000+0x118(audio on/off flag) to the movie record task.
I also wrote a lua script to play with it, I guess it could work on other cameras with a video mode where audio is disabled.
Use at your own risk.