I did a couple of quick tests and looks like I can get away with a 6x4 grid with pixel step 0 (yes, zero) if I only use two cells and mask everything else out (could be even >2 cells, but I only tried "no mask" and "mask all but two cells").
This might be a good time to document one of the less known features in mx3's motion detector code...:

Instructions for checking MD measurement time:
MD scripts have a bunch of parameters to control how the LCD image is calculated. The current MD code cannot run fast enough on our cameras to check for each and every pixel for changes during the 10 ms keyboard poll interval (note that both Canon code and CHDK code do things other than the motion detector during this period, so it's not really 10 ms that we can waste in MD).
MD works fine even if you exceed the keyboard poll interval (Canon calls them ticks) -- at least if you don't exceed it TOO much (pixel step 0 without a mask will make things look very sluggish). But when optimizing for minimum response time, it's essential to make sure we poll the display each and every tick.
That's why we usually want to skip most LCD pixels and only monitor every Nth pixel (the pixel step parameter). Also, the number of cells (horizontal and vertical) can be specified by the user and a too high value may slow MD down. A mask will limit the number of pixels that are evaluated, use it if you know where the movement will be happening.
How can you tell you're using just one tick? Well, mx3 included some debug/benchmark features in MD we can use for this.
MD logs the first 2048 comparison calls. With 10 ms keyboard poll this should mean 20.48 seconds of data (btw this debug storage occupies 4096 words of RAM and most of it is not really necessary IMO).
This debug data can be dumped to a file MD_INFO.TXT in camera root directory by setting the MD_MAKE_DEBUG_LOG_FILE bit in the "parameters" argument, i.e. by adding 2 to the parameters argument. For the default MDFB fast mode this parameters argument is 9, change it to 11 by editing the script.
This file is not updated during MD. Instead, it's written (only) when md_detect_motion timeouts. So, set the MD timeout
parameter to a short value. With timeout of >=21 seconds you get all the data MD will log. But 10 seconds is more than enough to check for speed, so in MDFB, set Timeout to 1 (1 seconds).
Then start the script and make sure there is no motion in front of the camera. Wait for MD to timeout and stop the script by
pressing the shutter after the file has been writte. How to tell when MD timeouts, you ask...? Well, MD prints something about writing to a file on the console...just interrupt the script after the camera refocuses.
Then, read the file MD_INFO.TXT (using CHDK built-in text file reader or your computer). It has some information about CHDK and script settings in the beginning, and after that a long list with two numbers on each line. The first number is the index of the md comparison call (0 to at most 2047, or about 1000 if you used 10 second timeout) and beside it the CHDK get_tick_count value for this particular call. This value is the camera's time from startup in milliseconds. It will increase in 10 ms steps. So, if the value increases by 10 every line, you're doing great.
If it increases by more than 10 between any two lines, you are comparing too many pixels or cells and you are not achieving optimal reaction time.
Of course you should set compare interval is 10 ms or less for all of this, otherwise you're deliberately asking the MD to slow down. Note that this debug md info does not take compare interval into account. So even if you set a compare interval of 50 ms, the file will still list comparisons with 10 ms intervals. Someone could consider this a bug, but then again it's just a debug feature.
I believe moving this bit in motion_detector.c:
if(motion_detector.comp_calls_cnt < MD_REC_CALLS_CNT) {
motion_detector.comp_calls[motion_detector.comp_calls_cnt]=tick;
}
motion_detector.comp_calls_cnt++;
down after this:
if(motion_detector.last_measure_time + motion_detector.measure_interval > tick){
// wait for the next time
return 1;
}
Would fix it.