PIM447 trackball: How to get a "clean" INT signal?

Hello!

I wrote a driver for the PIM447 trackball in polling-mode, and now I’d like to rewrite it in interrupt-mode. Sadly, it turns out the INT signal toggles during I2C transactions (whatever the value of “INT_OUT” bit in REG_INT). See first capture below.

Also, even without touching the ball, the INT signal falls (which means new data are supposed to be available, which is not the case) a couple of milliseconds after registers are read, just as if the interruption was not cleared. See second capture below.

I took a look at the official driver, but despite having the “interrupt” keyword used here and there, it actually polls the INT signal; it doesn’t use it as a trigger (comments are mine):

while not trackball.get_interrupt():
    time.sleep(0.001)
[...]

def get_interrupt(self):
    if self._interrupt_pin is not None:
        return GPIO.input(self._interrupt_pin) == 0 # poll pin level
    else:                                           # or
        value = self.i2c_rdwr([REG_INT], 1)[0]      # poll register value
        return value & MSK_INT_TRIGGERED

In order to write an interrupt-mode driver I need a clean INT signal. Please, could you tell me:

  • how not to get the INT signal toggling during I2C transactions?

  • how not to get the INT signal falling even when no new data are available?

Thanks in advance,
cdc.

2 Likes

I’m also very interested in using the trackball with the ZMK firmware that @cdc is working on. I would love to see a response from the team!

Hello there!

Were you able to get the clean INT signal? It seems like the hardware has issues because I’ve tried multiple software paths to do it. Namely, the following were tried in the interrupt handler:

  1. Reading the left, right, up, down, and button registers alone.
  2. Reading the Interrupt register alone.
  3. Reading from 2 and 3, in either orders of one before and after the other.
  4. Disabling Interrupt, then reading the 5 sensor values followed by the re-enabling of the Interrupt did not work either. From the status of the register, it can be seen that the bit zero of the Interrupt register (supposedly the bit that indicates an interrupt was generated), did not go high during such repeated interrupt reads, but did get set to 1 when the trackball had actual motion. This indicates to me this bit does as it says, but the hardware is still toggling interrupt line for some reason without any motion on the trackball.

Bump! I would love to use one of these on a wireless build I’m working on but would need it not to straight up eat the battery… Any official answer for these questions?

Another bump, I’d also like to make use of this module for a new wireless build, and I’d love to be able to use the trackball without it churning through the battery. Hopefully we can get an official response soon?

Another bump, I’d love to make use of this module but this very issue prevents me to implement this on my wireless keyboard.

Yet another bump. Also want to use it in a wireless keyboard with ZMK.

We need zmk support for the trackball asap.
This is a serious lack of feature.

There’s an issue tracking this - TL;DR is that there’s a firmware fix Coming Soon™ for interrupt woes (although quite how that firmware gets there…!)

i received a new trackball with updated firmware and it seems like the interupt part is fixed , i tested on qmk by adding this code and then testing on old and new version

#define PIMORONI_TRACKBALL_REG_INT      0xF9

void pimoroni_trackball_set_interupt(void) {
    uint8_t value = 0;
     __attribute__((unused)) i2c_status_t status = i2c_readReg(PIMORONI_TRACKBALL_ADDRESS << 1, PIMORONI_TRACKBALL_REG_INT, &value, sizeof(uint8_t), PIMORONI_TRACKBALL_TIMEOUT);

     uint8_t MSK_INT_OUT_EN    = 0b00000010;
     value &= ~MSK_INT_OUT_EN;
     value |= MSK_INT_OUT_EN;

     i2c_writeReg(PIMORONI_TRACKBALL_ADDRESS << 1, PIMORONI_TRACKBALL_REG_INT, &value, sizeof(uint8_t), PIMORONI_TRACKBALL_TIMEOUT);
}

Here are some captures on old and new firmware

this looks much more suitable for zmk

1 Like

for people interested, flashing from linux is also possible from a virtual machine (win 11 guest on vmware), the steps are :

  • ask pimoroni support for the firmware
  • acquire a nuvoton programmer , i used the cheapest one (13 Euro) on ali express named :
    NuMicro ICP programmer Nu-Link Nu Link Nuvoton ICP emulator downloader support online/offline programming M0/M4 series chips
  • Downloaded NuMicro ICP Programming Tool 3.09.7380r from here : https://www.nuvoton.com/tool-and-software/software-tool/programmer-tool/
  • install, launch, attach the programmer to the vm
  • select auto to chip detection
  • the programmer itself will be updated and this require to unplug / replug the programmer 2 times.
  • then load firmware as AROM, click start and it is flashed and fixed
1 Like