Magic Lantern Firmware Wiki
Advertisement

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
Advertisement