tl;dr: It’s not a myth. It really does affect tracking at high DPI. It is easily possible for mouse manufacturers to fix. Just change a few registers.
It is somewhat commonly reported that many mice with the PAW3950 sensor exhibit the behavior of DPI “downshifting”. The phenomenon works as follows: set your DPI to something high, above 20000. Move the mouse around very slowly, less than 1 millimeter a second. The cursor will feel “stuck”, but suddenly accelerate as you increase beyond some threshold speed. Here’s a video recording to demonstrate:
This has been reported in the community, with mixed reactions and considerable skepticism.
- An issue with the 3950 sensor: a dead zone or reduced sensor FPS/DPI at low movement speeds
- I’m done with the PAW 3950.
- wlmouse huan ‘downshifts’ below 7500 DPI
The skepticism is totally understandable, as it only affects high DPI settings that people rarely use, and it is difficult to distinguish from stick-slip effects arising from mouse feet-to-mousepad friction. But recently, I discovered a diagnostic procedure to visualize and detect DPI downshifting beyond any doubt.
How to detect DPI downshifting, irrefutably
The procedure is really simple.
- Set your mouse to use independent X/Y DPI settings. Set the X DPI to 7500 and Y DPI to 30000.
- In Paint (or jspaint.app), draw a diagonal line as slowly as you can. Keep the physical motion at a 45 degree angle.
-
- If there is DPI downshift, the line you draw will start off at 45 degrees, but the cursor will suddenly move along a more vertical path as you move faster. Slow down, and the cursor will move at 45 degrees again. If you move at the right speed, you might even see a wavy pattern as you go above and below the threshold speed.
- If there is no DPI downshift, the line you draw will always be a steep, vertical angle, no matter how slow or fast you move.
Here’s an example of two XA25s drawing in Paint according to this procedure. The left one has DPI downshifts, and the right one has the downshifting disabled.
Why this works
Let’s assume the downshifted DPI is 7500. (Later we will confirm this!) When the sensor detects that it’s moving below the threshold speed, it limits both X and Y DPIs to 7500. Since they’re equal, 45 degree physical motion gives 45 degree cursor motion. Once cursor motion goes above the threshold, the DPIs will jump to their nominal values of 7500/30000. Then, the cursor motion will deviate significantly from 45 degrees.
Finding the registers that control downshifting
I’ll simplify the details of how I arrived upon the relevant register settings. It was a combination of reading SPI data from various mice, educated guesses, and pattern recognition. In principle, all the information necessary to arrive at these is publicly available.
A quick primer on sensor operation.
For those who haven’t looked at a sensor datasheet before, here’s an extremely brief summary of how optical motion sensors operate. Sensors are chips that communicate with a mouse’s microcontroller (MCU) via SPI. When a mouse powers up, the first thing the mouse does is to send a bunch of settings to the sensor. This is done by writing particular numbers into a particular set of registers: individual bytes of memory that contain settings and/or data. Then, when the mouse actually starts running and tracking, the MCU determines motion by periodically reading the sensor’s motion count registers, which contain an accumulated count of the motion since the previous read. When you change sensor settings like DPI or lift-off distance, this is achieved by writing to the DPI and lift-off distance registers.
This manner of operation is typical for sensors and some aspects of this protocol are inherited from the original Agilent optical sensors from over 20 years ago. But a few somewhat recent developments are worth noting:
- For many generations of sensors, up to the PMW3389, the initialization procedure involved not just writing register settings, but also sending the sensor a binary blob of encrypted code called the “SROM”. 8051enthusiast made some attempts to decrypt this code, which you can read about in his blog.
- Starting from the PAW3399, the initialization no longer involves any SROM. It’s purely a long list of register settings. For example, see here.
- Also starting from the PAW3399, some registers have 16-bit addresses. Suppose you want to write 0x12 to register 0x3456. First, you write the most significant byte (MSB) of the address, 0x34 to register 0x7F. Then, you write the value 0x12 to the register 0x56. You can continue to write to other registers that share the same MSB, or switch to a register with a new MSB by writing the new MSB to 0x7F first. Other examples can be found in the PAW3395 datasheet, page 39.
You might have heard before that sensors have various operation modes such as “Corded Gaming” mode. This terminology, which arises from the sensor datasheets, has become mainstream nowadays as some mouse companies expose these modes as user-selectable options in their configuration software. These modes correspond to lengthy lists of register settings that are written to the sensor upon initialization. These settings are listed out in datasheets, but precisely what is changed is unknown because nearly all of the registers involved in these lists are undocumented.
For the PAW3950, some fellow shared all the modes and their register settings here. The first column with hex numbers is the register address, and the second hex column is the value to write. A bunch of undocumented hex numbers. What to make of it?
Well, first a small detour.
Somewhat recently, someone (honestly no idea who) discovered that the PAW3950 can run at a constant 20000 fps by using the “high dpi Corded Gaming” mode (which works perfectly fine even if dpi is set to something low like 400). The “low dpi Corded Gaming” mode would lead to the sensor running at constant 12000 fps. Pretty quickly, most mouse manufacturers figured this out and you can find many recent PAW3950 mice being advertised with 20k framerate. So, since I have full control over the XA25 firmware, I figured I’d stare at these hex numbers, compare the low and high dpi Corded Gaming modes, and swap out settings until I find the register that controls the framerate. There’s only 19 settings that differ, so it’s not that bad.
The answer: register 0x0653 controls framerate. Setting it to 0x03 results in 12k fps. Setting it to 0x02 results in 20k fps. Setting it to 0x04 or 0x05 results in lower framerate. Before I bothered to figure out the formula, I spotted something more interesting:
{ WRITE, 0x4F, 0x4F, NULL },
{ WRITE, 0x4E, 0x00, NULL },
{ WRITE, 0x52, 0x4F, NULL },
{ WRITE, 0x51, 0x00, NULL },
{ WRITE, 0x47, 0x01, NULL },
{ WRITE, 0x4F, 0x95, NULL },
{ WRITE, 0x4E, 0x00, NULL },
{ WRITE, 0x52, 0x95, NULL },
{ WRITE, 0x51, 0x00, NULL },
{ WRITE, 0x47, 0x01, NULL },
These register writes look incredibly similar to setting DPI settings. If you look at the PAW3395 datasheet, you’ll see that register 0x48 and 0x49 control X DPI, and 0x4A and 0x4B control Y DPI. Writing 0x01 to register 0x47 locks in the new DPI values. If you stick a logic analyzer onto any PAW3950 mouse’s sensor SPI pins, you can confirm for yourself that the same registers control DPI for the PAW3950. So what are the registers 0x4E, 0x4F, 0x51, 0x52? If I interpret the written values as 16-bit numbers, the low dpi Corded Gaming value of 0x004F = 79 corresponds to (79 + 1) * 50 = 4000 DPI. The high dpi Corded Gaming value of 0x0095 = 149 corresponds to (149 + 1) * 50 = 7500 DPI. Ah… there’s that 7500 number that people had floated around previously. Could this be it?
Paint as the verifier, once again
So let’s suppose that 0x4E and 0x4F control the downshifted X DPI, and 0x51 and 0x52 control the downshifted Y DPI. If I set the downshifted X DPI small and the Y big, slow cursor motion should be locked to a horizontal line, while faster motion would be normal. I modified the XA25 firmware to write 0x00 to 0x52, which, under this assumption, would result in a downshifted Y DPI of 50. The result?
Exactly as predicted. Here, the downshifted X/Y DPIs are 50/7500 and the regular DPI is 30000/30000. Slow motion would be locked in a horizontal line, and once I go beyond a threshold, drawing diagonal lines would suddenly become possible.
The fix
So to stop downshifting, simply set the downshifted DPIs to the max value of 30000 (for the uncustomized, vanilla PAW3950). As in, write 0x02 to registers 0x4E and 0x51, and write 0x57 to registers 0x4F and 0x52.
A side effect of this, however, is that even if the mouse isn’t moving, the cursor will jitter around a single pixel:
This is of course annoying and, for wireless mice, would waste power. In any case, this jitter is only present at DPIs above roughly 7000.
By sniffing the SPI settings of a Razer DeathAdder v3 and some trial and error, I also figured out the following:
- Writing 0x45 (instead of 0x05) to register 0x0544 is another way to completely disable downshifting. I’m not sure if this has any other side effects.
- In the Razer mouse, the jitter is there right after a mouse stops moving (physically), but stops after 250ms. The register that controls this is 0x066B. Writing 0x3F (instead of 0x20) enables this 250ms anti-jitter timeout.
I subjectively feel that keeping 0x066B at 0x20, so allowing the cursor to jitter, gives the best precision when making micro-adjustments and drawing things one pixel at a time. I’m not totally sure about this and I don’t have solid evidence yet, but I’ll just throw this out there in case someone else wants to try. But you would need a mouse that has software that allows you to toggle the setting of the 0x066B register.
What you can do
If you own a PAW3950 mouse and often use > 7500 DPI, try the 7500/30000 X/Y DPI Paint test. If your mouse is affected, the only thing you can do is tell your mouse’s manufacturer to update their firmware with this fix. Or at least expose the register settings as a toggle in the configuration software. Until then, unfortunately, there’s nothing most people can do themselves. Of course, if you manage to flash your own firmware onto a mouse, you can do whatever you like, but very few people do that.
It would also help the community to share the results of your mouse, whether it has a PAW3950 or another sensor, of the 7500/30000 X/Y DPI Paint test.
If you want to discuss this or any other technical matters further, or just want to learn the latest on what we’re up to in mouse development, join our Discord!