To get an interval of N units, you write N-1 in the hardware timer register. That means, the timer will count from 0 to N-1, giving a periodic signal every N units. When doing the math, I use N, that is, value read from the hardware register (as displayed by adtg_gui) + 1. So, 25.6e6 / 640 / 2 = 20000 => fastest shutter is, indeed, 1/20000.
Timer A is incremented once by the main clock (so, 25.6 million times per second). When it reaches the value programmed in that register, it goes back to 0 and the image capture hardware moves on to read out the next line. If timer A is "too fast", at first you get some black columns on the right side (line readout does not finish), then the image breaks completely. If timer A is larger than needed, it works fine, you just get some more rolling shutter.
Every time timer A fires, the second timer (B) also gets incremented. When timer B reaches its programmed value, it goes back to 0 and the next frame is read out. Timer B needs to be large enough to read out all the lines (but can be larger).
Things are a bit more complex than that, there are also 4 HEAD timers that
I don't fully understand yet, but for "simple" FPS adjustment, that's basically how it works.
Back to exposure time. For the ADTG register, you no longer measure the time in microseconds; you use timer A ticks for that. That is, time within one frame goes from 0 to timerB - 1. That's the unit you use to program the various timers (HEAD timers, exposure time, powersave timing etc).
Blanking = how much time the sensor is not capturing anything. So, frame_duration = exposure_time + blanking_time (or, exposure_time = frame_duration - blanking_time). That's what the hardware expects: you program how much time the sensor stays "off", rather than "on".
If you have an older model, FPS override at low frame rates will overexpose quite a bit. Why it's that? If you only override the timer registers and leave the ADTG stuff unchanged, the "shutter blanking" register will stay the same. However, the frame duration (aka timer B) will increase, so the exposure time will also increase.
For example, if you cut the FPS in half by doubling timer B, the old method will not be able to get a shutter speed faster than 1 / (FPS/2), even if you dial 1/8000 in Canon menu. Why? Canon code will set the blanking register close to the original timer B, but the frame duration is now double.
If you do the same thing by doubling timer A, the exposure time (and the rolling shutter) will just double (from what you dial in Canon menu). In this case, timer B will not change, so the ratio between blanking and exposure will stay the same, but one unit will now be twice as many microseconds.
BTW, before knowing this stuff, the following was found by writing down shutter values and trying to find an explanation:
// FPS override will alter shutter speed (exposure time)
// FPS "difference" from C0F06014 will be added as a constant term to exposure time
// FPS factor from C0F06008 will multiply the exposure time (as scalar gain)
// TG = base timer (28.8 MHz on most cams)
// Ta = current value from C0F06008
// Tb = current value from C0F06014
// Ta0, Tb0 = original values
//
// FC = current fps = TG / Ta / Tb
// F0 = factory fps = TG / Ta0 / Tb0
//
// E0 = exposure time (shutter speed) as indicated by Canon user interface
// EA = actual exposure time, after FPS modifications (usually higher)
//
// If we only change Tb => Fb = TG / Ta0 / Tb
//
// delta_fps = 1/Fb - 1/F0 => this quantity is added to exposure time
//
// If we only change Ta => exposure time is multiplied by Ta/Ta0.
//
// If we change both, Tb "effect" is applied first, then Ta.
//
// So...
// EA = (E0 + (1/Fb - 1/F0)) * Ta / Ta0
Now it seems to match the above theory.