I'm working on a project that involves the optical sensor from a mouse. I've got the original control PCB (still populated, save for the optical sensor itself), and I've got the optical sensor on my custom PCB, supposed to be controlled by an nrf51822. I've wired the clock + data pins (it's a two-wire interface) to both boards, driven by the original control board (I've set my clock and data pins as inputs with no pulling resistors).

I'm trying to capture traffic to determine what signals are being sent, but I'm not having a lot of luck - I suspect my clock rate is too low. As quickly as possible (just inside a while true loop), I'm scanning my clock pin and my data pin, then printing them both to my console output over UART at 1M baud. Running this loop empty for 5 seconds results in ~4000 cycles, meaning I'm getting >1ms run time for each loop - which I think is my main problem.

As it is, I capture (in roughly 700 scans) 100 groups of alternating "clock 1 and data 1" and "clock 0 and data 0" - each group is 4-9 items (that is, 4-9 "1s" on both, followed by 4-9 "0s" on both). Then, about 400 scans later (~0.5 seconds) I get the same thing, but 54 groups. At that point I stopped scanning.

Is there any way to either: A) Speed up my scan cycle so I can capture the traffic more accurately? or B) Decode what I already have (doubtful)?

Do I need to consider an alternate route? I haven't found any access to an oscilloscope, which is... unfortunate.

I'd appreciate any advice. Thanks.

  • \$\begingroup\$ What MCU or processor are you using to read the pseudo-SPI CLK and DATA? You're really working blind without an oscilloscope. USB o'scopes have gotten quite cheap and might be in your price range (e.g. Digilent Analog Discovery 2, two-channel, 100 Msps, $159 with student discount). This is not a recommendation site so just Google USB oscilloscope and you'll find a ton. If you do need to bit-bang this protocol, you're best off using a dedicated microcontroller running bare metal (C or assembler). Might even have to interrupt on the CLK edge, store the state of DATA and post process after. \$\endgroup\$ Aug 21, 2017 at 17:11
  • 3
    \$\begingroup\$ You don't need an oscilloscope for this, what you probably want is a logic analyzer. Those based on USB fifo chips are quite cheap, and can feed something like sigrok for analysis. But also consider that you are probably looking at ps/2 mouse protocol which is well documented and doesn't need to be reverse engineered. \$\endgroup\$ Aug 21, 2017 at 17:21
  • \$\begingroup\$ Thanks for the comments so far, guys! I'm using a Nordic nrf51822, which operates at 16MHz - so I should have down to ~62.5ns precision, though only if what I'm trying to do can be accomplished in 1 instruction (which reading... may be able to?) I'll set up an interrupt and try processing later, so the loop isn't slowed down by sending the UART message. I'll also see if there are any local hackerspaces or something that might have an oscilloscope... \$\endgroup\$
    – Helpful
    Aug 21, 2017 at 18:01
  • \$\begingroup\$ @ChrisStratton, I may yet try a logic analyzer, but I'm reasonably confident that the protocol used on this chip is proprietary. Having looked at PS/2 spec, I don't THINK it would be implemented on this chip - it was scavenged from a wireless mouse, and the wireless module in the mouse took care of communication with the host computer. The pinout seems similar to the ADNS2620, but I will look through the PS/2 spec more and see if it's possible. \$\endgroup\$
    – Helpful
    Aug 21, 2017 at 18:07
  • 1
    \$\begingroup\$ Actually, it would be quite logical for a wireless mouse to be PS/2 internally. That lets them use an everyday wired mouse chip, and a distinct radio/MCU chip, neither part needing to be custom / specific to this purpose, which can help keep costs down. \$\endgroup\$ Aug 21, 2017 at 18:08

2 Answers 2


As Chris Stratton indicated in his comments to the other answer you need to change the way your software works.

There are two options:

Option 1:
Run in a tight loop polling the pins and recording a timestamp into a buffer when they change state. If the value hasn't changed don't do anything.
Once the buffer is full output the times recorded over the serial link.

Option 2:
Use the serial and clock line inputs as interrupts. When the pins change record to a buffer a timestamp for the transition and the new state of the pin.
Have a background loop send the logged data out on the serial port keeping up with the data as best it can while indicating if the buffer has overflowed.

Both of them solve the big issue that you have that you are trying to output serial data from within a time critical piece of code, printf is slow and serial ports run at a glacial pace, never do them in a section of code that you need to run quickly. Option 1 is simpler and will probably cope with slightly higher frequencies but will only record for as long as you have space to buffer and could possibly report two edges very close together as being in the wrong order. Option 2 outputs while it's running and so should be able to run for longer (whether it's 1 edge more or keeps up and runs indefinably depends on the speeds of the edges and the serial port) but due to the interrupt overhead will have a lower top speed and is more complex to code.

The other obvious solution is to borrow / rent an oscilloscope or logic analyser from someone.

  • \$\begingroup\$ I'm marking this as the accepted answer as it makes sense - I kind of suspected it was the UART debugging that was taking forever. Do you think an array would be a fast enough buffer, or should I just use some bitwise operators with a uint64_t or something? \$\endgroup\$
    – Helpful
    Aug 22, 2017 at 14:36
  • \$\begingroup\$ A uint32_t array should be fine. You can use a timer to give you the current time as a 32 bit value, that should be fairly fast to read. Depending on the time resolution used you could possible use the top bit of the 32 bit value to represent to direction. \$\endgroup\$
    – Andrew
    Aug 22, 2017 at 15:05
  • \$\begingroup\$ Thinking about it if you know the clock polarity then you can set an interrupt to read the data on the appropriate edge of the clock and log only that. That wouldn't give you the timing but would give you the data sent in a very compact form. And never use 64 bit values in a 32 bit cpu unless you absolutely have to. \$\endgroup\$
    – Andrew
    Aug 22, 2017 at 15:11

The NRF51822 uses an ARM Cortex M0, which seems singularly unsuitable for your capture task. The Cortex M0 uses anything from 1-4 cycles for the basic instructions and much longer if you use things like multiply. The processor cannot be interrupted within a basic instruction decode.

If you want to capture data it would be much better with a small 8 bit 1 cycle per instruction processor such as the ATMega328. You should be able to wire up a $3 Arduino Nano to serialize the data and output via the serial port.

Since the protocol is synchronous you should be able to use the SPI in Slave mode to receive the data. You should read Nick Gammons excellent coverage of SPI to get started.

If you use an SPI slave, then you effectively have to stuff 8 bits into the UART queue every 8 cycles of your device clock. Just remember that this method of capture will not capture gaps (with no clocks) so what you get is a dense dump (no whitespace) of the data.

To understand why the ARM Cortex M0 is poor at either interrupt speed or bit bashing ports read this and this.

  • 1
    \$\begingroup\$ This is highly misleading advice. The CPU should be fast enough if the code is written intelligently, the problem is that the poster is trying to generate printable output in real time - that, and the USB backing it, are what is limiting the sample rate on the order of a thousand per second. With a little care, 100 times faster is probably achievable without changing the hardware. That said, if the BLE soft device or equivalent or any other scheduler or interrupts are running, they will case pauses in the sampling. \$\endgroup\$ Aug 21, 2017 at 19:29
  • \$\begingroup\$ @ChrisStratton. I added some extra to my answer, but I stand by the fact that the M0 is not a good processor for what the op wants to do. We also have no idea what if anything NordicSemi have changed or modified in using the M0 IP. Did they use a sealed implementation or did they have a full license and have rolled their own additions? \$\endgroup\$ Aug 21, 2017 at 23:13
  • 3
    \$\begingroup\$ If the poster were stressing over the difference between 100 KSPS and 1 MSPS you could have a point - but a 1 KSPS the problem is not the chip selection, but rather a poorly designed program and reporting scheme. It's a really poor programmer who insists on new hardware to fix a glaring software design error. \$\endgroup\$ Aug 21, 2017 at 23:18
  • \$\begingroup\$ @ChrisStratton. Since the OP did not provide a single line of code, it's hard to judge his software abilities. However any decent hardware engineer would know that the M0 was poor choice for this type of task. ....If your having a go at MY ability to program, then that's different. I would start by understanding both the software and hardware limitations of the processor I want to use. But perhaps you are different and would never consider hardware limitations....... \$\endgroup\$ Aug 22, 2017 at 4:41
  • \$\begingroup\$ The M0 should be capable of something on the order of 100 times the performance the poster has achieved. The general shape of the reason that's not being realized is evident in the question and something I've already pointed out: trying to generate serial output, apparently in human readable form, per sample, at the time the samples are taken. What they should be doing is a short fast, triggered capture to a memory buffer to get a sense of the timing, and then using that understanding to clock in words sampled on the correct edge of the provided clock. \$\endgroup\$ Aug 22, 2017 at 5:16

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.