• Hi all!

    I'm Kacper, new here ;) I'm working on an espruino project on MDBT42Q Module.

    I'm experiencing problems running DRV2605, which I'm using to drive a small haptic motor, together with some neopixels. They work well on their own, but I can't get them to work together. I don't mean at the same time. Let me explain.

    To drive neopixels I use:

    const neopixelDataPin = D5;
    require("neopixel").write(neopixelDataPi­n, pixelBytes)
    

    This works well.

    I interface with the DRV2605 via I2C. Below you can see my test code:

    //HAPTIC
    const DRV2605 = {
      ADDR: 0x5a,
      REG_STATUS: 0x00,
      REG_MODE: 0x01,
      REG_LIBRARY: 0x03,
      REG_GO: 0x0c,
      REG_WAVESEQ1: 0x04,
      REG_WAVESEQ2: 0x05,
      REG_RTPIN: 0x02,
      REG_OVERDRIVE: 0x0d,
      REG_SUSTAINPOS: 0x0e,
      REG_SUSTAINNEG: 0x0f,
      REG_BREAK: 0x10,
    };
    
    const sclPin = D31;
    const sdaPin = D30;
    
    pinMode(sclPin, "output");
    pinMode(sdaPin, "output");
    
    const hapticPowerPin = D28;
    const hapticMultiModePin = D29;
    
    digitalWrite(hapticMultiModePin, 1);
    digitalWrite(hapticPowerPin, 1);
    
    
    const i2cHaptic = I2C1;
    i2cHaptic.setup({ scl: sclPin, sda: sdaPin});
    const haptic = { address: DRV2605.ADDR, stop: false };
    
    const prepareHaptic = () => {
      i2cHaptic.writeTo(haptic, DRV2605.REG_STATUS, 0x00);
      i2cHaptic.writeTo(haptic, DRV2605.REG_LIBRARY, 2);
      i2cHaptic.writeTo(haptic, DRV2605.REG_MODE, 0x00);
      i2cHaptic.writeTo(haptic, DRV2605.REG_RTPIN, 0x00);
      i2cHaptic.writeTo(haptic, DRV2605.REG_OVERDRIVE, 0);
      i2cHaptic.writeTo(haptic, DRV2605.REG_WAVESEQ1, 5);
      i2cHaptic.writeTo(haptic, DRV2605.REG_WAVESEQ2, 1);
      i2cHaptic.writeTo(haptic, DRV2605.REG_SUSTAINPOS, 1);
      i2cHaptic.writeTo(haptic, DRV2605.REG_SUSTAINNEG, 0);
      i2cHaptic.writeTo(haptic, DRV2605.REG_BREAK, 0);
    };
    prepareHaptic();
    
    const hapticPush = (i2c) => {
      i2c.writeTo(haptic, DRV2605.REG_MODE);
      const result = i2c.readFrom(DRV2605.ADDR, 1);
      i2c.writeTo(haptic, DRV2605.REG_GO, 1);
      console.log(result[0]);//for debugging
      return result;
    };
    
    const hapticTripple = () => {
      let index = 0;
      setInterval(() => {
        index++;
        hapticPush(i2cHaptic);
        if (index > 3) clearInterval();
      }, 250);
    };
    
    

    In the code above I use hardware I2C, but it also works with software I2C. I'm testing if it works with hapticTripple function which produces three short vibrations and prints the status read from the status register of the DRV2605 (it returns 0 if successful).

    Now, here's the problem. In the case where I setup software I2C for DRV2605 and I call my test function it works, but if after that I call the require("neopixel") , which works properly, after that call I can't communicate with DRV2605 anymore (I'm getting 255 values from the status register in the test function console logs). This persists even after a soft reset (test function returns 255). Only after hardware reset the initial state is restored.

    In the case where I set up the hardware I2C for the DRV2605 the behavior is sort of flipped. The DRV2605 functions well, but once I call the require("neopixel") function the device freezes - the console does not respond, when I reconnect the IDE there is no prompt detected, so I basically need to hard reset the board.

    I've tried communicating with the Neopixels directly via SPI. Using software SPI I could make some pixels light up, but it wasn't working well (later I've read a post by Gordon saying that software SPI is not suitable for Neopixels). But with software SPI for neopixels and I2C for DRV2605 (both software or hardware I2C), I can successfully use DRV2605 and make neopixels "do something".

    When I switch the I2C into software and the SPI to hardware and run the code, I'm getting I2C timeout errors like below when calling my DRV2605 test function:

    in function called from system
    Uncaught Error: I2C Error: Timeout (start)
     at line 1 col 37
    i2c.writeTo(haptic, DRV2605.REG_MODE);
                                        ^
    in function "hapticPush" called from line 2 col 25
        hapticPush(i2cHaptic);
                            ^
    in function called from system
    

    After I clear the intervals to stop the I2C timeout errors, I can use the hardware SPI to communicate with neopixels. It doesn't work well but at least it's not freezing. Still, since the I2C is not working, spending more time on trying to use hardware SPI to bypass the require("neopixel") makes no sense in this scenario.

    When I set both SPI and I2C as hardware, first the board disconnects right after flashing and it takes two to three attempts to reconnect with the IDE. Then, when it is connected and I try to run the DRV2605 test function it freezes, and to recover a hard reset is required. When I try to use SPI to talk to neopixels it works ("does something").

    I don't understand why after calling the require("neopixel") I'm unable to use the software I2C or even configure the hardware I2C. I couldn't understand what changes after the require("neopixel") is called that "blocks" the software I2C.

    Any Ideas? Please help :)

  • Hi! Are you definitely up to date on your Espruino firmware? 2v10?

    Is it reasonably easy for you to change pins at this point?

    I remember a while back there was an issue where someone found that on the nRF52840 chip there was a bug in the I2S hardware (used for neopixel) where the LRCK pin had to be set. code here

    I was pretty sure it was nRF52840 specific, but if it isn't then it'd have the effect of sending pulses on D31 when neopixel was used. While the pin should be back to normal after using the neopixel write, maybe there is some issue there.

    So...

    • You could try calling i2cHaptic.setup({ scl: sclPin, sda: sdaPin}); again after the neopixel write (but this is still probably not ideal).
    • If you could change D31 to something else, I bet that'd fix it
    • Potentially with a firmware update we could move the LRCK pin to another pin, but it's a matter of finding one that nobody expects to be used!
  • Hi Gordon!

    Thank you for such a quick response! This is amazing ;)

    I've just updated the firmware from 2v08 to 2v10, but the behavior persists.

    I did try calling the I2C setup after neopixel write, but that didn't help. I also tried setting I2C to other pins to "shield" the DRV2605, but also no luck. For some reason, after neopixel write, something gets "stuck". Perhaps the signal received by the haptic driver from D31 crashes it, but I can't find a way to reset it, other than resetting the whole board.

    I think that you're right that it is the neopixel write affecting the D31, because in the case when the I2C for DRV2605 is set up, the motor vibrates one last time when the neopixel write is called.

    Changing pins is a bit problematic for me at this point. I need to redesign and fabricate my PCB... so it'll take me a while :P

    Considering the change of LRCK pin to another in the new firmware - if it is difficult to guess which pin won't be used by the user, maybe it would be possible to make it exposed from espruino. Something like:

    require("neopixel").write(neopixelDataPi­n, [100,0,0], D31); //where D31 would be the LRCK pin
    //OR
    require("neopixel").set({LRCK : D31}); //called once before calling the write method
    

    I don't know if that'd be possible though.

  • Thanks - yes, that's a good point! We could make that LRCK pin configurable - however I guess most people won't even be aware of that as a possibility so ideally we'd make it so by default it affects as few people as possible.

    Are you using the bare module, or the breakout board?

    On the breakout, D12/D13 aren't broken out, so if you're not using those either it'd be easy to me to tweak the firmware to use one of those? If you want to do your own build it's just a matter of changing this line: https://github.com/espruino/Espruino/blo­b/master/boards/MDBT42Q.py#L48

    from:

         'DEFINES+=-DNEOPIXEL_SCK_PIN=23',
    

    to

         'DEFINES += -DNEOPIXEL_SCK_PIN=23 -DNEOPIXEL_LRCK_PIN=12',
    

    (or similar)

  • Yes, of course! If LRCK pin would be made configurable it should be just an option.

    I'm using the bare module, and I had D24 free. I've made the custom build with the modified line and IT WORKS - no more conflicts ;)

    I attach the custom build with the LRCK set to pin D24 - in case anyone would need a quick fix.

    Your support is incredible! Thank you so much for your help!


    1 Attachment

  • No problem - thanks for being willing to do a build yourself!

    I've filed an issue here and when things calm down I'll try and get this fixed properly

  • Post a reply
    • Bold
    • Italics
    • Link
    • Image
    • List
    • Quote
    • code
    • Preview
About

DRV2605 (I2C) and Neopixels conflict on MDBT42Q Module

Posted by Avatar for Kacper @Kacper

Actions