• I am trying to read from a i2c connect sensor. I managed to get my schematic and code working for arduino leonardo but not when I interface with the puck. I suck at bytes and low level stuff, so I am wondering if I understand what I am doing.

    var i2c = new I2C();
    i2c.setup({ scl : D31, sda: D30 });
    const TMP117_Address = '0x48';
    const Temp_Reg = '0x00';
    
    setInterval(() => {
      i2c.writeTo(TMP117_Address, Temp_Reg);
      let a = i2c.writeTo(TMP117_Address, 1);
      
      setTimeout(() => {
        let b = i2c.readFrom(TMP117_Address, 2);
        console.log(b);
        let datac = ((b[0] << 8) | b[1]); 
        console.log(datac*0.0078125);
      }, 500);
    }, 2000);
    

    trying to imitate this:

    /*********************** Read Temperature Sensor Function **************************/
    double ReadTempSensor(void){
         
      // Data array to store 2-bytes from I2C line
      uint8_t data[2]; 
      // Combination of 2-byte data into 16-bit data
      int16_t datac;   
    
      // Points to device & begins transmission
      Wire.beginTransmission(TMP117_Address); 
      // Points to temperature register to read/write data
      Wire.write(Temp_Reg); 
      // Ends data transfer and transmits data from register
      Wire.endTransmission(); 
    
      // Delay to allow sufficient conversion time
      delay(10); 
    
      // Requests 2-byte temperature data from device
      Wire.requestFrom(TMP117_Address,2); 
    
      // Checks if data received matches the requested 2-bytes
      if(Wire.available() <= 2){  
        // Stores each byte of data from temperature register
        data[0] = Wire.read(); 
        data[1] = Wire.read(); 
    
        // Combines data to make 16-bit binary number
        datac = ((data[0] << 8) | data[1]); 
    
        // Convert to Celcius (7.8125 mC resolution) and return
        return datac*0.0078125; 
        
      }
    }
    

    i am getting a senseless value, i wonder what am I doing wrong? I find it hard to understand how to map these i2c operations to the pucks i2c api.

  • Fri 2019.07.26

    Hello @user101989,

    'I suck at bytes and low level stuff, so I am wondering if I understand what I am doing.'

    It appears you understand your situation accurately!! wink, wink

    But seriously now, would you please post the output, that is generated from the code segment above, from the left-hand side of the WebIDE so that we may get an idea of what 'i am getting a senseless value' actually means to us.

    So far nothing stands out. Code segment appears okay.

    Puck flashed to latest firmware? What ver please. process.env

    'but not when I interface with the puck'

    Is there a common ground between the two devices? How was the sensor grounded on your Arduino setup? If the sensor is floating, might explain the erroneous values.

    Any chance you could post an image of the wiring and the schematic link to see if there is a I2C setup or wiring issue? e.g. sda scl backwards -

    recommend changing code first before making a un-solder attempt



    Do you have access to a logic analyzer and protocol decoder? I highly recommend (eventually~$20USD) getting one. Has saved me multiple times. See this image I recently posted.

    http://forum.espruino.com/comments/14832785/

  • Thanks for your input I will next time do all this checklist you suggest because it all makes sense to try, specially the analyzer and decoder thing. !!!

    I figured it out by bruteforcing trial and error attempts. In the end I had to change the 1 in line 8 for a 0. Doing that did the trick. I have no clue why!

  • 'had to change the 1 in line 8 for a 0. Doing that did the trick. I have no clue why!'

    No clue without the sensor command set, which wasn't in #1

    Maybe argument 2 in L8 should be Temp_Reg?   e.g. I2C writing a command of sensor give me the temp?

    Sometimes brute force does work. ;-) Glad you got it working!

  • Just a code snipped:

    var addr = 0x76; //chip addr
    read = function(reg, len) {
      i2c.writeTo(addr, reg);
      return i2c.readFrom(addr, len);
    };
    write = function(reg, data) {
      i2c.writeTo(addr, [reg, data]);
    };
    
    var register = 0x12
    var length = 8
    var data = new Uint8Array(length);
    data.set(read(register, length));
    var a1 =  (data[0] << 12) | (data[1] << 4) | (data[2] >> 4);
    

    I didn't try/check your code in detail, but I'd suggest to define data (or b) as Uint8Array.

  • Assuming that's a TI TMP117 (providing a link to the chip and / or the library you try to port sometimes helps, or saves a couple of seconds), the Arduino code simply reads two bytes from register 0.

    At line 17 that delay

      // Delay to allow sufficient conversion time
      delay(10); 
    

    I don't think its necessary for two reasons:

    1. the datasheet doesn't say it's necessary :) (If I read the datasheet correctly, in continuous mode - and that's the default - you can just read the temperature values. Maybe you would have to wait before the first, but see the second point:
    2. Espruino is slow, so usually you can just ignore < 1ms delays. :) But always test it...

    I think @maze1980 is pretty close, this probably works:

    var addr = 0x48; //chip addr
    read = function(reg, len) {
      i2c.writeTo(addr, reg);
      return i2c.readFrom(addr, len);
    };
    write = function(reg, data) {
      i2c.writeTo(addr, [reg, data]);
    };
    
    // read two bytes from register `0`
    var b = read(0, 2));
    // and calculate the temperature:
    var temperature = ((b[0] << 8) | b[1]) * 0.0078125; 
    console.log('temperature:', temperature );
    
  • Looks like I2C.readFrom already returns an Uint8Array, so I think you are doing a double allocation.
    Not sure, but I think your memory usage might be smaller with just:

    var data = read(register, length);
    

    Or not, or might not even be measurable, if that allocation is just in a small function, and the GC frees up memory...

  • As I said in my previous post. I managed to fix it by changing line 8 in which I write 1 to instead write 0, this seems to clear the previous measurement or something in the TMP117 and then the next reading works flawless.

    I adaparted the Espruino Data Collection example to store the temp measurement of the TMP117 and the magnetometer of the puck.js board every 30seconds in memory and then export it out via bluetooth using a site to connect and download the logs.

    var i2c = new I2C();
    i2c.setup({ scl : D31, sda: D30 });
    const TMP117_Address = '0x48';
    const Temp_Reg = '0x00';
    var log = new Float32Array(2000); // our logged data
    var magLog = new Float32Array(2000); // our logged data
    var logIndex = 0; // index of last logged data item
    var magLogIndex = 0; // index of last logged data item
    var timePeriod = 30*1000; // every 30 secs
    var lastReadingTime; // time of last reading
    
    // Store data into RAM
    function storeMyData(data) {
      logIndex++;
      if (logIndex>=log.length) logIndex=0;
      log[logIndex] = data;
      
      let mag = Puck.mag();
      magLogIndex++;
      if (magLogIndex>=magLog.length) magLogIndex=0;
      magLog[magLogIndex] = data;
    }
    
    // Get Data and store it in RAM
    function getData() {
      i2c.writeTo(TMP117_Address, Temp_Reg);
      let a = i2c.writeTo(TMP117_Address, 0);
    
      setTimeout(() => {
        let b = i2c.readFrom(TMP117_Address, 2);
        let datac = ((b[0] << 8) | b[1]);
        let temp = datac*0.0078125;
        console.log(temp);
        storeMyData(temp);
        lastReadingTime = Date.now();
      }, 500);
    }
    
    // Dump our data in a human-readable format
    function exportData() {
      for (var i=1;i<=log.length;i++) {
        var time = new Date(lastReadingTime - (log.length-i)*timePeriod);
        var data = log[(i+logIndex)%log.length];
        console.log(Math.floor(time/1000)+" "+data);
      }
    
      for (var y=1;y<=magLog.length;y++) {
        var time2 = new Date(lastReadingTime - (magLog.length-y)*timePeriod);
        var data2 = magLog[(y+magLogIndex)%magLog.length];
        console.log(Math.floor(time2/1000)+" "+data2);
      }
    }
    
    function startLight () {
      digitalWrite(LED2,1);
      setTimeout(() => {
        digitalWrite(LED2,0);
      }, 1000);
    }
    
    function stopLight () {
      digitalWrite(LED1,1);
      setTimeout(() => {
        digitalWrite(LED1,0);
      }, 1000);
    }
    
    var recording = true;
    var interval = setInterval(getData, timePeriod);
    
    setWatch(function() {
      console.log("Pressed");
      if (recording) { 
        recording = false;
        clearInterval(interval);
        stopLight();
      } else {
        recording = true;
        interval = setInterval(getData, timePeriod);
        startLight();
      }
    }, BTN, {edge:"rising", debounce:50, repeat:true});
    
    */
    
    
    
    
    
    

    sorry for variable names :/
    I also added a start green led and stop red led if you press the button to start and stop recording temps

  • Fri 2019.07.26

    @user101989, Clever to adapt the Espruino Data Collection example adding data logging, visual feedback and use Bluetooth as a delivery means. A working complete solution nicely done!

    This is not necessary, and I am being real picky here, are L26 & L27 both needed, as it appears to be the same instruction, and I'm guessing one or the other isn't providing any use? In one, a string representation of hex zero is sent, the other a decimal representation.

    Did the Arduino documentation or sensor docs have any detail on what the argument for the write parameter should be? Normally, hex values are sent and not a string representation.

    It might be that const Temp_Reg = '0x00'; should really be const Temp_Reg = 0x00; making the request only require one write. i.e. L27 isn't really needed? Same for L3

    One could spend hours attempting to 'fine tune' but it is really up to you. Nice project concept, and a complete project solution. Be proud that you were able to conquer and solve yourself.

  • is the same size as 
    

    var data; data.set(read(register, length));```

    This function is used quite often in the examples:
    https://www.espruino.com/Reference#l_ArrayBufferView_set

  •                i2c.writeTo(TMP117_Address, Temp_Reg);
      let a = i2c.writeTo(TMP117_Address, 0);
    

    Is there any specific reason to write twice to the register 0 / Temp_Reg?

    I'd say for this device it should be only one line, like this

    i2c.writeTo({address:TMP117_Address, stop:false}, Temp_Reg);
    
  • Glad you got this sorted!

    I'd definitely look at @maze1980's suggestions about using I2C though - it's much cleaner.

    It might be that const Temp_Reg = '0x00'; should really be const Temp_Reg = 0x00;

    It'd be a great idea to add this suggestion from @Robin (and to also change TMP117_Address).

    What you're actually doing there is defining a string of text rather than a number, so it'll behave quite differently if you do anything with it. As chance would have it JavaScript will convert this to a number properly for you, but if you try to use it in any other way you'll hit big issues.

    For instance Temp_Reg = '0x00'; print(1+Temp_Reg) won't print 1 as you expect - so while it works now I can pretty much guarantee that if you define numbers as strings in the future it'll cause you a lot of headaches :)

  • Hej @Gordon @Robin @AkosLukacs and @maze1980, thanks for taking the time to review my code and also for helping me improving it. I took the time to edit my code and include the suggestions, feel free to double check.

    This should store up to 2000 readings of the high accuracy TI TMP117 sensor into an array.

    const i2c = new I2C();
    const tmp117Address = 0x48;
    const temperatureAddress = 0x00;
    const timePeriod = 30 * 1000; // every 30 secs
    const log = new Float32Array(2000); // our logged data
    let logIndex = 0; // index of last logged data item
    let lastReadingTime; // time of last reading
    
    // Store data into RAM
    const storeMyData = (data) => {
      logIndex++;
      if (logIndex >= log.length) logIndex = 0;
      log[logIndex] = data;
    };
    
    // Get Data and store it in RAM
    const getData = () => {
      i2c.writeTo({address: tmp117Address, stop: false}, temperatureAddress);
      
      setTimeout(() => {
        let reading = i2c.readFrom(tmp117Address, 2);
        let dataBytes = ((reading[0] << 8) | reading[1]);
        let dataCentigrades = dataBytes * 0.0078125;
        storeMyData(dataCentigrades);
        console.log(dataCentigrades);
        lastReadingTime = Date.now();
      }, 500);
    };
    
    // Dump our data in a human-readable format
    const exportData = () => {
      for (let i = 1; i <= log.length; i++) {
        let time = new Date(lastReadingTime - (log.length - i) * timePeriod);
        let data = log[(i + logIndex) % log.length];
        console.log(Math.floor(time / 1000) + ' ' + data);
      }
    };
    
    const startLight = () => {
      digitalWrite(LED2, 1);
      setTimeout(() => {
        digitalWrite(LED2, 0);
      }, 1000);
    };
    
    const stopLight = () => {
      digitalWrite(LED1, 1);
      setTimeout(() => {
        digitalWrite(LED1, 0);
      }, 1000);
    };
    
    i2c.setup({ scl : D31, sda: D30 });
    let recording = true;
    let interval = setInterval(getData, timePeriod);
    
    setWatch(() => {
      console.log("Pressed");
      if (recording) { 
        recording = false;
        clearInterval(interval);
        stopLight();
      } else {
        recording = true;
        interval = setInterval(getData, timePeriod);
        startLight();
      }
    }, BTN, {edge:"rising", debounce: 50, repeat: true});
    
      
    

    Then you can download this data from the puck using a site with this code

    <html>
     <head>
     </head>
     <body>
      <script src="https://www.puck-js.com/puck.js"></script>
      <button id="myButton">On!</button>
      <script type="text/javascript">
      // Create WebSocket connection.
        const socket = new WebSocket('ws://localhost:8080');
        const button = document.getElementById("myButton");
    
        function onLine(data) {
          // CSV data is received here
          socket.send(data);
          console.log(data);
        }
    
        var connection;
        button.addEventListener("click", function() {
          if (connection) {
            connection.close();
            connection = undefined;
          }
          Puck.connect(function(c) {
            if (!c) {
              alert("Couldn't connect!");
              return;
            }
            connection = c;
            // Handle the data we get back, and call 'onLine'
            // whenever we get a line
            var buf = "";
            connection.on("data", function(d) {
              buf += d;
              var i = buf.indexOf("\n");
              while (i>=0) {
                onLine(buf.substr(0,i));
                buf = buf.substr(i+1);
                i = buf.indexOf("\n");
              }
            });
            // Request data from Puck.js
            connection.write("\x10exportData()\n");
          });
        });
      </script>
     </body>
    </html>
    
    

    but before make sure you are running a node process with this code, it will listen to socket data and use Winston to dump it into the file system.

    const winston = require('winston');
    const logger = winston.createLogger({
      transports: [
        new winston.transports.Console(),
        new winston.transports.File({ filename: `${new Date().toISOString()}.txt` })
      ]
    });
    
    const WebSocket = require('ws')
    const wss = new WebSocket.Server({ port: 8080 })
     
    wss.on('connection', ws => {
      ws.on('message', message => {
        const msg = message.trim();
        const timestamp = msg.split(" ")[0];
        const temp = msg.split(" ")[1];
        logger.info(`${timestamp} ${temp}`);
      })
      ws.send('Server ready')
    })
    
    
  • Let me know if you want pics/help with connecting the TMP117 with the puck in the physical world.

  • Mon 2019.07.29

    Very nicely done @user101989 and web page access bonus too!!

    As you have put quite a bit of effort into this project, and others would surely benefit, as it appears images could be part of the presentation, would you like to create a tutorial or a presentation and upload that to either the Tutorials or Projects headings?

    Home >> Projects

  • Yeah Ill do that.

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

How to process output of a i2c sensor to get proper values.

Posted by Avatar for user101989 @user101989

Actions