Intro[]
FPS and shutter speeds in LiveView mode are driven by some timers (clocks).
By changing these values it's possible to get arbitrary FPS and/or shutter speeds.
Timing math[]
Canon encodes shutter speed in 1/8 EV steps internally (for exposure computations, auto ISO stuff etc). That is, 1/50 is encoded internally as 1/48 (and so on).
Before configuring the hardware (that is, setting up some timers and clocks), they do some rounding to avoid flicker. That is:
- in PAL, 1/30 is rounded to 1/33.333. Also, 1/50 and 1/100 are exact.
- in NTSC, 1/60 and 1/120 are exact in 60D. In 5D2, only 1/60 is exact. 1/120 is 120.183.
For 1/60, Canon configures the timer at 655 ticks, for 1/120 at 327 in 5D2. From this it's easy to do the math for all other shutter speeds:
655*60000 = 39300000. That's the frequency of the shutter speed clock in NTSC mode.
So, at 327, the exact shutter speed is 39300000/327 = 120.183 (that is, 1/120.183 seconds).
Other odd things:
- in NTSC mode there are two clocks. One for FPS (to get 29.97 and so on) and one for shutter (to get 1/60). In PAL, the same clock frequency is used for both.
Values for 60D:
#define TG_FREQ_PAL 50000000 #define TG_FREQ_NTSC_FPS 52747200 #define TG_FREQ_NTSC_SHUTTER 49440000
Values for 5D2:
#define TG_FREQ_PAL 40000000 #define TG_FREQ_NTSC_FPS 41328630 #define TG_FREQ_NTSC_SHUTTER 39300000
- In exposure override mode, Canon code may configure the timer for shutter speeds slower than 1/fps. When this happens, actual shutter speed is fixed (probably very close to 1/fps) and there's no change in the image.
Table at 0x406CEAC0 (600D v1.0.1)[]
This is the table that contains timer/timeout values for sampling images in video mode.
Depending on the current modes (fps, zoomed, ...) and timer kind there are different setups. Zeroed lines were skipped. Timer values are based on a ~20µs timer. The calculated "timer=" fps are calculated based on timer value and the guessed 20µs. Not sure why the calculated fps are off that much. [see above for calculations]
The EV_* timer values are always lower than the "sensor drive speed" values. I guess, "sensor drive speed" gives the timer period and the EV_* get raised with the same frequency at given offset. First comes SETPARAM, then READOUTDONE with 50 or 53 timer ticks delay most of the time. The timers are also called HEAD2, HEAD3 and HEAD4 with their interrupts set up using RegisterHDInterruptCBR. The registers are listed in Register Map.
+--------------------------------- 22?fps (mode 5) timer=20.86 fps? | +---------------------------- 30 fps (mode 2) timer=28.41 fps? | | +----------------------- empty (mode 6) timer= | | | +------------------ 60 fps (mode 0) timer=56.82 fps? | | | | +------------- 24 fps (mode 4) timer=22.73 fps? | | | | | +-------- 25 fps (mode 3) timer=25.00 fps? | | | | | | +--- 50 fps (mode 1) timer=50.00 fps? | | | | | | | ______________________________________ Timer values for normal mode 00 095d 06e0 0000 0370 0898 07d0 03e8 \ 0000 051d 0000 0000 0000 0000 0000 > sensor drive speed 0000 051d 0000 0000 0000 0000 0000 / 03 049f 049f 0000 02d1 049f 049f 02d1 \ 0000 0453 0000 0000 0000 0000 0000 > EV_READOUTDONE_INTERRUPT_EVF (HEAD4) 0000 0453 0000 0000 0000 0000 0000 / 06 0406 046a 0000 029c 046d 046d 029f \ 0000 042b 0000 0000 0000 0000 0000 > EV_SETPARAM_INTERRUPT_EVF (HEAD3) 0000 042b 0000 0000 0000 0000 0000 / ______________________________________ Timer values for unknown mode (what about EOS remote?) 10 0000 0000 0000 0483 0000 0000 0500 -- sensor drive speed 13 0000 0000 0000 03a2 0000 0000 035c -- EV_READOUTDONE_INTERRUPT_EVF 16 0000 0000 0000 035c 0000 0000 031c -- EV_SETPARAM_INTERRUPT_EVF ______________________________________ Timer values for zoom mode 18 0000 0690 0000 0000 0834 07d0 0000 -- sensor drive speed 21 0000 0419 0000 0000 0419 0419 0000 -- EV_READOUTDONE_INTERRUPT_EVF 24 0000 03e6 0000 0000 03e8 03e8 0000 -- EV_SETPARAM_INTERRUPT_EVF ______________________________________
READOUTDONE timing seems to be pretty much critical, and dictates the maximum theoretical fps. Decreasing it by a small amount stops the video, increasing it results in lowering the max fps.
Here is some code (untested, just a reverse engineering product) that reads the table entries on 600D v1.0.1
/* which = 0 for "[VRAM]VRAM_SDV_SetSenserDriveParameter" which = 1 for "sdrv_registerHdInterruptCBR" this is timer value of handler that posts EV_READOUTDONE_INTERRUPT_EVF the handler gets called by HEAD4 interrupt which = 2 for "sdrv_registerHdInterruptCBR" this is timer value of handler that posts EV_SETPARAM_INTERRUPT_EVF the handler gets called by HEAD3 interrupt there is also a HEAD1 interrupt handler. but this one is not configured. on 600D v1.0.1 the list of handlers and their context are stored at 0x73770. the interrupt handler lists are at 0x00073720 intTable_VDInterruptHigherPriCBR 0x00073748 intTable_VDInterruptCBR 0x00073770 intTable_HeadInterruptCBR */ unsigned short get_timer_value(int which) { unsigned int fps_offset_map[] = { 3, 6, 1, 5, 4, 0, 2 }; unsigned short *timer_table = (unsigned short *)0x406CEAC0; unsigned int mode_0x08 = *((unsigned int *)(0x0729d0 + 0x08)); unsigned int mode_0x0c = *((unsigned int *)(0x0729d0 + 0x0c)); unsigned int mode_0x14 = *((unsigned int *)(0x0729d0 + 0x14)); unsigned short fps_mode = fps_offset_map[mode_0x08]; unsigned short table_offset = 0; unsigned short ret[3]; switch(mode_0x14) { case 0xA0000: table_offset = 2; break; case 0x50000: table_offset = 1; break; default: table_offset = 0; break; } switch(mode_0x0c) { case 4: ret[0] = timer_table[(10 * 7) + fps_mode]; ret[1] = timer_table[(13 * 7) + fps_mode]; ret[2] = timer_table[(16 * 7) + fps_mode]; break; case 6: ret[0] = timer_table[(18 * 7) + fps_mode]; ret[1] = timer_table[(21 * 7) + fps_mode]; ret[2] = timer_table[(24 * 7) + fps_mode]; break; default: ret[0] = timer_table[((0 + table_offset) * 7) + fps_mode]; ret[1] = timer_table[((3 + table_offset) * 7) + fps_mode]; ret[2] = timer_table[((6 + table_offset) * 7) + fps_mode]; break; } return ret[which]; }
BR,
g3gg0
indy = 600d 1.0.1 : FF3ACB14 VRAM_SDV_SetSenserDriveParameter FF281D50 sdrv_registerHdInterruptCBR