• Hi all, I have no idea how to get my PCA9685 to respond to any kind of input from my NODEMCU ESP-12E. I know both boards work as I've already tried with a program written in C.

    For now, all I'm trying to do is make a single servo move on channel 0, here is my code. You might notice its pretty much just the Adafruit library with a few modifications. Nothing seems to happen with the servo :/

    
    function I2CWRAPPER(address, _ref) {
        var device = _ref.device,
        debug = _ref.debug;
    
        var i2c = new I2C(address);
        i2c.setup({ scl: NodeMCU.D2, sda: NodeMCU.D1 });
    
        var readBytes = function readBytes(cmd, length) {
            return new Promise(function (resolve, reject) {
                i2c.readFrom(cmd, length);
            });
        };
    
        var writeBytes = function writeBytes(cmd, buf) {
            if (!(buf instanceof Array)) {
                buf = [buf];
            }
            if (debug) {
                console.log('cmd ' + cmd.toString(16) + ' values ' + buf);
            }
            return new Promise(function (resolve, reject) {
                i2c.writeTo(cmd, buf);
            });
        };
    
        return {
            readBytes: readBytes,
            writeBytes: writeBytes
        };
    }
    
    function sleep(seconds) {
        return new Promise(function (resolve, reject) {
           
            var t = setTimeout(function (x) {
                return resolve(seconds);
            }, seconds);
            clearTimeout(t);
        });
    }
    
    
    function makePwmDriver(options) {
      
      
        // Registers/etc.
        var MODE1 = 0x00;
        var MODE2 = 0x01;
        var SUBADR1 = 0x02;
        var SUBADR2 = 0x03;
        var SUBADR3 = 0x04;
        var PRESCALE = 0xFE;
        var LED0_ON_L = 0x06;
        var LED0_ON_H = 0x07;
        var LED0_OFF_L = 0x08;
        var LED0_OFF_H = 0x09;
        var ALL_LED_ON_L = 0xFA;
        var ALL_LED_ON_H = 0xFB;
        var ALL_LED_OFF_L = 0xFC;
        var ALL_LED_OFF_H = 0xFD;
    
        // Bits:
        var RESTART = 0x80;
        var SLEEP = 0x10;
        var ALLCALL = 0x01;
        var INVRT = 0x10;
        var OUTDRV = 0x04;
    
        var defaults = {
            address: 0x40,
            device: '/dev/i2c-1',
            debug: false
        };
    
        var _Object$assign = Object.assign({}, defaults, options),
            address = _Object$assign.address,
            device = _Object$assign.device,
            debug = _Object$assign.debug;
    
        var i2c = I2CWRAPPER(address, { device: device, debug: debug });
        var prescale = void 0;
      
    
        var init = function init() {
            if (debug) {
                console.log('device //{device}, adress:' + address + ', debug:' + debug);
                console.log('Reseting PCA9685, mode1: ' + MODE1);
            }
            i2c.writeBytes(MODE2, OUTDRV);
            i2c.writeBytes(MODE1, ALLCALL);
        };
    
        var setPWMFreq = function setPWMFreq(freq) {
            // "Sets the PWM frequency"
            var prescaleval = 25000000.0; // 25MHz
            prescaleval /= 4096.0; // 12-bit
            prescaleval /= freq;
            prescaleval -= 1.0;
    
            if (debug) {
                console.log('Setting PWM frequency to ' + freq + ' Hz');
                console.log('Estimated pre-scale: ' + prescaleval);
            }
            prescale = Math.floor(prescaleval + 0.5);
            if (debug) {
                console.log('Final pre-scale: ' + prescale);
            }
    
            return i2c.readBytes(MODE1, 1).then(function (data) {
                var oldmode = data[0];
                var newmode = oldmode & 0x7F | 0x10; // sleep
                if (debug) {
                    console.log('prescale ' + Math.floor(prescale) + ', newMode: newmode.toString(16)');
                }
                i2c.writeBytes(MODE1, newmode); // go to sleep
                i2c.writeBytes(PRESCALE, Math.floor(prescale));
                i2c.writeBytes(MODE1, oldmode);
                (0, _sleep.usleep)(5000).then(function (x) {
                    return i2c.writeBytes(MODE1, oldmode | 0x80);
                });
            });
        };
    
        // Sets a single PWM channel
        var setPWM = function setPWM(channel, on, off) {
      
            if (debug) {
                console.log('Setting PWM channel, channel: ' + channel + ', on : ' + on + ' off ' + off);
            }
            i2c.writeBytes(LED0_ON_L + 4 * channel, on);
            i2c.writeBytes(LED0_ON_H + 4 * channel, on);
            i2c.writeBytes(LED0_OFF_L + 4 * channel, off);
            i2c.writeBytes(LED0_OFF_H + 4 * channel, off);
        };
    
        var setAllPWM = function setAllPWM(on, off) {
            i2c.writeBytes(ALL_LED_ON_L, on & 0xFF);
            i2c.writeBytes(ALL_LED_ON_H, on >> 8);
            i2c.writeBytes(ALL_LED_OFF_L, off & 0xFF);
            i2c.writeBytes(ALL_LED_OFF_H, off >> 8);
        };
    
        var stop = function stop() {
            return i2c.writeBytes(ALL_LED_OFF_H, 0x01);
        };
    
        // actual init
        init();
    
        return {
            setPWM: setPWM,
            setAllPWM: setAllPWM,
            setPWMFreq: setPWMFreq,
            stop: stop
        };
    }
    
    
    setTimeout(() => {
       const pwm = makePwmDriver({ address: 0x40, device: '/dev/i2c-1', debug: false });
     
        const servo_min = 1000;
        const servo_max = 2000; 
    
        pwm.setPWMFreq(50);
    });
    
  • Hi @jameslouiz

    with the Espruino implementation for ESP8266 you can use I2C1, which is a c-code implementation of a I2C master

    I2C1.setup({ scl: NodeMCU.D2, sda: NodeMCU.D1 });
    
    // read
    I2C1.readFrom(address, quantity);
    // write
    I2C1.writeTo(address, data, ...);
    

    Maybe you like to check some modules using i2c to get a better understanding for I2C on this page.

    You can also try the Espruino servo motor module .

  • Thanks for your reply @MaBe, but when I use I2C1, I get a strange "NO ACK" error.

    Also, could the following be incorrect in any way?

  • You should try one of these i2c device scanner to be sure about your wires and pullup resistors are ok. If the list does not show your device, start checking used pins and cable. Or maybe you are just using the wrong address ;-)

  • @MaBe thanks again. I used the last example on that page and it returned [64, 112]. I'm assuming this is a good thing as changing the SDA or SDL parameters returns an empty array. Do I need to do anything with these numbers?

  • I get I2CWrite: No ACK 0 when trying i2c.writeTo(n, 1000) where n is an integer between 0 and 200. I assumed it would work on channel 1-16?

  • I've tried some code @Gordon posted a few weeks ago but don't seem to be having any luck with that either :/

    var C = {
    PCA9685_SUBADR1 : 0x2,
    PCA9685_SUBADR2 : 0x3,
    PCA9685_SUBADR3 : 0x4,
    PCA9685_MODE1 : 0x0,
    PCA9685_PRESCALE : 0xFE,
    LED0_ON_L : 0x6,
    LED0_ON_H : 0x7,
    LED0_OFF_L : 0x8,
    LED0_OFF_H : 0x9,
    ALLLED_ON_L : 0xFA,
    ALLLED_ON_H : 0xFB,
    ALLLED_OFF_L : 0xFC,
    ALLLED_OFF_H : 0xFD
    };
    function PWMServoDriver(i2c) {
      this.i2c = i2c;
      this.addr = 0x40;  
      this.reset(()=>{
        this.setPWMFreq(1000);
      });
    }
    PWMServoDriver.prototype.write = function(r,d) {
      this.i2c.writeTo(this.addr,r,d);
    };
    PWMServoDriver.prototype.read = function(r) {
      this.i2c.writeTo(this.addr,r);
      return this.i2c.readFrom(this.addr,1)[0];
    };
    PWMServoDriver.prototype.reset = function(callback) {
      this.write(C.PCA9685_MODE1, 0x80);
      if (callback) setTimeout(callback,10);
    };
    PWMServoDriver.prototype.setPWM = function(num,on,off) {
      this.i2c.writeTo(this.addr,
                       C.LED0_ON_L+4*num,
                       on, on>>8,
                       off,off>>8 );
    };
    PWMServoDriver.prototype.setPWMFreq = function(freq) {
     // "Sets the PWM frequency"
      var prescaleval = 25000000.0; // 25MHz
      prescaleval /= 4096.0; // 12-bit
      prescaleval /= freq;
      prescaleval -= 1.0;
      prescale = Math.floor(prescaleval + 0.5);
    
      var data = this.i2c.readFrom(C.PCA9685_MODE1, 1);
    
      var oldmode = data[0];
      var newmode = oldmode & 0x7F | 0x10; // sleep
    
      this.i2c.writeTo(C.PCA9685_MODE1, newmode); // go to sleep
      this.i2c.writeTo(C.PCA9685_PRESCALE, Math.floor(prescale));
      this.i2c.writeTo(C.PCA9685_MODE1, oldmode);
      setTimeout(() => {
        return this.i2c.writeTo(C.PCA9685_MODE1, oldmode | 0x80);
      }, 5000);
    };
    const connect = function(i2c) {
      return new PWMServoDriver(i2c);
    };
    
    
    
    
    
    setTimeout(() => {
    var i2c = new I2C(); // software I2C
    i2c.setup({sda:NodeMCU.D1, scl:NodeMCU.D2});
    var pwm = connect(i2c);
      pwm.setPWMFreq(60);
      var SERVOMIN = 150;
      var SERVOMAX = 600;
    
      setInterval(() => {
        for (let pulselen = SERVOMIN; pulselen < SERVOMAX; pulselen++) {
          pwm.setPWM(0, 0, pulselen);
        }
      }, 1);
    
     
    }, 200);
    
  • each number is a i2c address of a device. Looks like you have two devices attached to this bus, a device with address 64 and another with 112.

    Use this address as first parameter for writeTo and readFrom.

    The code above is using Espruino i2c software solution and is talking to a device address 0x40 which is 64 decimal.

    Looks like you are not using this.read() eg in line 48 and this.write() eg in line 53 in the code. changing this in all lines might solve the issue.

  • My I2C instance is currently using 0x40 (64) for the address but I'm not sure what address I should use for channel 0 in the i2c.writeTo(address, data) method.

  • this is what I mean

    sample for line 48

    var data = this.i2c.readFrom(C.PCA9685_MODE1, 1);

    to

    var data = this.read(C.PCA9685_MODE1, 1);

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

No response from PCA9685 using NODEMCU - Whats wrong with my code?

Posted by Avatar for jameslouiz @jameslouiz

Actions