beagleboard / bonescript

Scripting tools for the BeagleBoard and BeagleBone
http://beagleboard.org
MIT License
32 stars 9 forks source link

Using I2C functions #28

Open jadonk opened 6 years ago

jadonk commented 6 years ago

From @colinbes on July 1, 2014 19:11

Maybe I am misunderstanding correct usage of I2C functions provided by bonescript but from what I understand, the correct usage is along the lines of

b.i2cOpen(PORT, PWR_CHIP);
b.i2cReadBytes(PORT, STATUS, 1, function(data){...})

I assume the thinking is that the ReadBytes is always preceded by the i2cOpen function within the same function scope. If the i2cOpen function was, for example, in static part of code, and the ReadBytes was in a function then you could end up with wrong results.

Example.

i2cOpen('/dev/i2c-1', 0x20);

function func1() {
  i2cReadBytes .....
}

In this case if any other function anywhere called i2cOpen and then you called func1() you'd be reading bytes of the last i2cOpen function.

Is there a way to use these functions similar to the way it is used in i2c which is basis for bonescript i2c functions? Where method returned by i2cOpen is used as 'parent' (sorry, can't think of right word to use) to ReadBytes call?

Just looking for direction, thanks

Copied from original issue: jadonk/bonescript#90

jadonk commented 6 years ago

From @colinbes on July 1, 2014 19:48

I am needing to periodically scan a particular i2c device (monitoring for powerfail). Per my above question I have call to i2cOpen just before i2cReadBytes in timer function. On running the code for a short period of time I get possible EventEmitter memory leak detected message. Seems to be caused by the i2cOpen function call. If I move this out the timer interval function then I don't get the error - looks like I need to close i2c somehow? Moving i2cOpen outside of the interval function would not be a solution as I am reading i2c devices in other areas of code.

var timer = setInterval(function() {
        b.i2cOpen(PORT, PWR_CHIP);
        b.i2cReadBytes(PORT, STATUS, 1, function(data){
  ...}, 2000);

Full error message

(node) warning: possible EventEmitter memory leak detected. 11 listeners added. Use emitter.setMaxListeners() to increase limit.
Trace
    at process.EventEmitter.addListener (events.js:160:15)
    at process.on.process.addListener (node.js:769:26)
    at new i2c (/usr/local/lib/node_modules/bonescript/node_modules/i2c/lib/i2c.coffee:32:15)
    at Object.m.doOpen (/usr/local/lib/node_modules/bonescript/iic.js:18:20)
    at Object.newFunction [as i2cOpen] (/usr/local/lib/node_modules/bonescript/my.js:234:31)
    at null.<anonymous> (/mnt/nfs/code/testpower.js:21:5)
    at wrapper [as _onTimeout] (timers.js:252:14)
    at Timer.listOnTimeout [as ontimeout] (timers.js:110:15)

Appreciate your help. Colin

jadonk commented 6 years ago

From @Findus1 on September 16, 2014 11:16

I'm having the same problem. Did you find a solution? The problem is trivially easy to produce:

var b = require('bonescript');
var port = '/dev/i2c-1';

for(var i = 0; i< 11; i++){
    b.i2cOpen(port, 0x70, {});
}

This produces a warning after 11 loops. That means I can a use only 10 addresses on my I2C bus!

jadonk commented 6 years ago

From @Findus1 on September 16, 2014 11:30

An update to that last post: it's not okay to just handle the warning. You get a warning after 11 i2cOpen operations, then an error after 1012 operations. Here's the test case:

var b = require('bonescript');
var port = '/dev/i2c-1';

for(var i = 0; i< 10000; i++){
    b.i2cOpen(port, 0x70, {});
    console.log("handles:", i);
}

Note that putting delays between i2cOpen() functions does not fix it. Is there not an i2cClose() function in Bonescript, like there is for other I2c libraries?

jadonk commented 6 years ago

From @Findus1 on September 16, 2014 16:1

If anyone else is banging up against this issue, the solution I found is to directly use the i2c library that Bonescript uses for i2c: https://github.com/kelly/node-i2c That lets you create an object for each device

var wire = new i2c(LED_ADDRESS, {device : '/dev/i2c-2'});

and write bytes to an address on it

wire.writeBytes(LED_BRIGHTNESS_ADDRESS, [0xFF], function(err) {});

as a bonus, it also numbers the i2c devices properly, so where Bonescript calls i2c-2 "i2c-1", the Kelly I2C library calls it "i2c-2"

jadonk commented 6 years ago

From @colinbes on September 16, 2014 16:39

I have yet to find a solution, presently in order to move forward I am using an exec call to read i2c but would much prefer to not have to do this. I did try to use the i2c library but didn't come right.

How did you install and require i2c - I recall having an issue with one of these steps.

I actually prefer i2c implementation as the i2c object, 'wire' in your code above is bound to a physical device - I think this is much safer.

jadonk commented 6 years ago

From @Findus1 on September 16, 2014 19:4

To install i2c, I followed the Beaglebone installation instructions on NPM. https://www.npmjs.org/package/i2c The Python installation produces errors, but the module installed without problems.

Like you, I also prefer the way i2c binds each instance to a device object. It is better than the way Bonescript's "open" command needs to be called before each device access (which means that if you are addressing several devices, you very soon exceed 11 "opens" to cause a warning, and eventually it crashes after 1012)

It's worth noting that the NPM i2c library also causes a warning when you create more than 11 devices - but unlike Bonescript, you don't need to open a new instance each time you send to a different device, because you can reuse device objects.

If anyone knows how to get around the 11 device limit in the i2c library, I'd like to know how. Edit: I've found that the I2C library doesn't set up the cape manager properly. After power-up, you need to issue a Bonescript Open, otherwise you get a cape manager error. After Bonescript has Opened the I2c port, you can use it with the i2c library. I just put a Bonescript Open before each new i2c object. e.g.:

var b = require('bonescript');
var i2c = require('i2c');

b.i2cOpen('/dev/i2c-1', DEVICE_ADDRESS, {});    //needed to open the cape manager port
var wire = new i2c(DEVICE_ADDRESS, {device : '/dev/i2c-2', debug: false});
//note that Bonescript's '/dev/i2c-1' == i2c's '/dev/i2c-2'