Shop OBEX P1 Docs P2 Docs Learn Events
Help with Omron IR sensor I2C — Parallax Forums

Help with Omron IR sensor I2C

T ChapT Chap Posts: 4,223
edited 2014-07-06 22:38 in Propeller 1
I could use an extra set of eyes. The LCD works well displaying values most of the time with the code as shown, but randomly $FF will pop up in some or all locations. I put in an extra STOP at line 4 of the i2c code, this is not in the manual, but without it the display shows FF about 50% of the time.
On page 14 in the manual, it discusses a WAIT REQUEST that is required by the master. I get FF values randomly that show up at 2 seconds to 15 seconds intervals. Cycle times tested are 1/10 of a second to 1 per second.

Minimal I2c Driver

Thanks for any suggestions.

 Word irval[16], omronref 
 Byte omron[35]

PUB ReadOMron       |  u  , v   
     i2c2.i2cStart(i2cSCL2) 
     i2c2.i2cWrite(i2cSCL2, OmronWrite) '0x14 this is a write=0     1 is read
     i2c2.i2cWrite(i2cSCL2, $4C )
     i2c2.i2cStop(i2cSCL2)    'without this stop,  gets 50% $FF values
     i2c2.i2cStart(i2cSCL2)
     i2c2.i2cWrite(i2cSCL2, OmronRead)   
     u~
     repeat 34   ' get first 34 bytes
       omron[u] := i2c2.i2cRead(i2cSCL2, 0)    'Read : 15h
       u++
       w(2_000)   '2000 is almost no FF   <<<<<<<<<<<<<<<<<<<<   added this waitcnt  to see what happens,  improves greatly
     omron[35] := i2c2.i2cRead(i2cSCL2, 1)    ' read last byte

     i2c2.i2cStop(i2cSCL2)     
     omronref :=  omron[0] +  omron[1] << 8 
     cls
     go0 
     ser.hex(3, omronref, 2)
     ser.str(3, string(" "))

     u := 2
     v := 0
     repeat 8   'view only first x pixels of 16
       irval[v] := omron[u] + omron[u+1] << 8    'lsb+msb
       ser.hex(3, irval[v], 2)
       ser.str(3, string(" "))
       u := u+2
       v++



Example in product info:

tPTAT = 256*readbuff[1] + readbuff[0]; 'internal temp ref
tP[0] = 256*readbuff[3] + readbuff[2];
tP[1] = 256*readbuff[5] + readbuff[4];
tP[2] = 256*readbuff[7] + readbuff[6];
tP[3] = 256*readbuff[9] + readbuff[8];
tP[4] = 256*readbuff[11] + readbuff[10];
tP[5] = 256*readbuff[13] + readbuff[12];
tP[6] = 256*readbuff[15] + readbuff[14];
tP[7] = 256*readbuff[17] + readbuff[16];
tP[8] = 256*readbuff[19] + readbuff[18];
tP[9] = 256*readbuff[21] + readbuff[20];
tP[10] = 256*readbuff[23] + readbuff[22];
tP[11] = 256*readbuff[25] + readbuff[24];
tP[12] = 256*readbuff[27] + readbuff[26];
tP[13] = 256*readbuff[29] + readbuff[28];
tP[14] = 256*readbuff[31] + readbuff[30];
tP[15] = 256*readbuff[33] + readbuff[32];
tPEC = readbuff[34]; 'this is CRC

http://www.omron.com/ecb/products/sensor/special/mems/pdf/AN-D6T-01EN_r2.pdf
759 x 145 - 39K
«1

Comments

  • Clive WakehamClive Wakeham Posts: 152
    edited 2014-04-27 00:27
    Does the sensor stretch the timing of the I2C?

    Where is the datasheet for it??

    Is the sensor "D6T-44L / D6T-8L Thermal sensor"? Because it states that "clock stretching must be on".

    A search of the forum indicates that the minimal I2C driver doesn't support clock stretching. You will need to one of the more advanced I2C drivers that support "clock stretching".

    Of course that is if the issue is with "clock stretching".

    http://microsite.omroncomponents.com/assets/ApplicationNote_IR%20Sensor_(ES)a.pdf
  • Tracy AllenTracy Allen Posts: 6,664
    edited 2014-04-28 01:05
    It appears that the Omron device may take its sweet time to do the A2D conversion between each i2 request, and the stretching allows for that. It could well explain the FFs.

    I've run across a couple of devices that use stretching (Sensirion SHT21 RH/T, SPD610 pressure, MAX1236 ADC). For those devices, the stretching happens at a specific point in a Read operation. That point happens to be immediately after the DevID+read is sent and ACK'd, and scl has been driven low to allow the slave to set the first bit of the result. The master then releases scl but the slave holds it low. When ready with the conversion result, the slave releases scl, and that transition clocks in the first data bit. Subsequent bits and bytes are not stretched.
    [SIZE=1][FONT=courier new]PUB Read(ackbit) | ticks
      dira[scl] := DRIVELOW         ' allow slave to set the first data bit
      dira[scl] := PULLUPHIGH       ' scl back high, but have to check for clock hold
    [COLOR=#020FC0]  if ina[scl] == 0              ' allow for clock stretching
        ticks := cnt
        repeat while (ina[scl]==0) and (cnt - ticks  < timeout)  ' timeout units of clock ticks
    [/COLOR]  repeat 8                      ' Receive data from sda
          dira[scl] := PULLUPHIGH   ' scl high, continue on capture first or next bit of data
          result := (result << 1) | ina[sda]     ' data MSB first
          dira[scl] := DRIVELOW     ' scl low, allow slave to set data
      dira[sda] := !ackbit          ' Output low on sda for ACK, pulluphigh for NAK
      dira[scl] := PULLUPHIGH       ' Recognize the ACK/NAK
      ' returns result, a byte
    [/FONT][/SIZE]
    

    AFAIK, stretching protocol is not spelled out in detail in the i2c spec, so how to implement it seems to be at the discretion of the device manufacturer. The description in the Omron data sheet is okay, but left me wondering if its stretch might occur before the ACK instead of after it, and if it is needed for all bytes, or what. I recall in another thread where where Chris Gadd found an example of a port expander that had the stretch before the ACK between clocks 8 and 9.
  • T ChapT Chap Posts: 4,223
    edited 2014-04-28 05:33
    Thanks guys for the suggestions. Yesterday I tried about 5 i2c objects to see what would improve things. Unfortunately I can only use a SPIN object as there is no room for a cog/pasm object. The last one I worked on was a Basic i2c Driver TM that looks like it has stretching, I see that in the object there is a version of ReadNS and a Read. I still am seeing sporadic FF's. The ReadNS version is the No Stretch version, and the Read is:
       repeat 8                            ' Receive data from SDA
         dira[SCL]~                        ' Sample SDA when SCL is HIGH
         'waitcnt(500 + cnt)
         wait := cnt
         repeat while 0 == ina[SCL]
           if (cnt-wait) > clkfreq/I2CDelayS
             quit
    

    Since FF is never a valid response and only occurs once in a while, it is not a problem to ignore any FF response since worst case is I have to wait 250ms to get the next valid response which is not a problem.


    For future searchers looking up Omron D6T 4x4, here is my starting point test code using an LCD on port 3 to watch about half of the 16 "windows":
         repeat
            ReadOMron          
            w(20_000_000)
    
    
    PUB ReadOMron       |  u  , v,  F  
         u~
         i2c5.Initialize(0)
         i2c5.Start(0)    
         i2c5.write(0,omronwrite) 
         i2c5.Write(0, $4c)
         i2c5.stop(0)
         i2c5.Start(0)
         i2c5.write(0,omronread)  
         repeat 34   ' get first 34 bytes
           omron[u] := i2c5.Read(0,0) 
           u++
         omron[35] := i2c5.Read(0,1) 
    
         'omronref :=  omron[0] +  omron[1] << 8   'convert the reference temp to F
         'omronref := omronref / 10
         'omronref  := ((omronref * 9)  / 5)  + 32   '0_000
    
         cls
         go0 
         'ser.dec(3, omronref)   'show the reference temp 
         'ser.str(3, string(" "))  
    
         u := 2
         v := 0
         repeat 8   'view only first x pixels of 16
           irval[v] := omron[u] + omron[u+1] << 8    'lsb+msb
           F := irval[v] / 10    'convert C to F      raw data from sensor is C * 10
           F := ((F * 9 )/ 5) + 32
           ser.dec(3, F)    ' show temp for each segment in F
           ser.str(3, string(" "))
           u := u+2
           v++
    
  • Tracy AllenTracy Allen Posts: 6,664
    edited 2014-04-28 09:03
    That doesn't allow for the possibility of stretching on the 9th clock (the ACK bit). A long shot, but it could be.

    Here from the 2007 i2c spec:
    <<On the byte level, a device may be able to receive bytes of data at a fast rate, but needs more time to store a received byte or prepare another byte to be transmitted. Slaves can then hold the SCL line LOW after reception and acknowledgment of a byte to force the master into a wait state until the slave is ready for the next byte transfer in a type of handshake procedure." >>
  • T ChapT Chap Posts: 4,223
    edited 2014-04-28 14:20
    Thanks Tracy for the suggestions. It looks like someone did address the 9th clock:
    PUB Read(SCL, ackbit):data | SDA, wait
    '' Read in i2c data, Data byte is output MSB first, SDA data line is
    '' valid only while the SCL line is HIGH.  SCL and SDA left in LOW state.
    '' Requires pull-up on SCL     
    '
       SDA := SCL + 1
       data := 0
       dira[SDA]~                          ' Make SDA an input
       repeat 8                            ' Receive data from SDA
         dira[SCL]~                        ' Sample SDA when SCL is HIGH
         'waitcnt(500 + cnt)
         wait := cnt
         repeat while 0 == ina[SCL]
           if (cnt-wait) > clkfreq/I2CDelayS
             quit
         data := (data << 1) | ina[SDA]
         dira[SCL]~~
       outa[SDA] := ackbit                 ' Output ACK/NAK to SDA
       dira[SDA]~~
       dira[SCL]~                          ' Toggle SCL from LOW to HIGH to LOW
       'waitcnt(500 + cnt)
       wait := cnt
       repeat while 0 == ina[SCL]
         if (cnt-wait) > clkfreq/I2CDelayS
           quit
       dira[SCL]~~
       outa[SDA]~                          ' Leave SDA driven LOW
    

    I wonder if the wait should be extended beyond clkfreq/I2CDelayS. I2CDelayS = 10_000 'clock stretch delay

    Now that you pointed this out, I can test tomorrow by increasing the wait time. 80_000_000/10_000 = 8000 is not a very big wait.
  • Tracy AllenTracy Allen Posts: 6,664
    edited 2014-04-28 15:07
    Yeah, that's pretty short, 100µs. I'd make it 0.1 second and see what happens. There's a possibility that it could need stretching during i2c write operations too, but that seems unlikely in this case. I'm curious, 1) to add this to the bestiary of devices that need clock stretching, 2) to hear how the sensor itself works out for you. I have a couple of the Melexis 4x16 pixel IR sensors MLX90620, the ones that PhiPi brought up Propeller-based-Thermal-Imager. The products seem to be directed to quite different apps.
  • T ChapT Chap Posts: 4,223
    edited 2014-04-28 15:23
    The Melexis seems nice but for my case I can use the Omron easily, it is the first array that I was made aware. I want a tiny hole in a ceiling to evaluate the direction of traffic. My experiments with it so far seem like this will do the job nicely. I haven't yet checked to see what distances it starts to become unusable, but that doesn't seem to be a concern.
  • T ChapT Chap Posts: 4,223
    edited 2014-04-29 10:29
    I tested with various wait lengths up to clock/10 on both sections of code where there are waits built it. No change on the random FF values. I also tested a loop period of up to 1 second, .5sec, etc, still no progress. At this point unless someone has a suggestion to try, I will just bail on the issue and ignore values that would not even be real world values. The manual for the devices does not mention anything about I2C. There are a few app notes that go into some detail about I2C, and they specifically state that stretching must be enabled.
    Our sensor may require a wait request of the mast
    er. On the master side, it is necessary to deal
    with this wait process. In many I2C modules in
    the MCU, there is a feature that can do this
    automatically. However, if using the I2C software
    library, the user may have to deal with this wait
    process manually.
    461 x 515 - 59K
  • T ChapT Chap Posts: 4,223
    edited 2014-04-29 18:44
       SDA := SCL + 1
       data := 0
       dira[SDA]~                          ' Make SDA an input
       repeat 8                            ' Receive data from SDA
         dira[SCL]~                        ' Sample SDA when SCL is HIGH
         'waitcnt(500 + cnt)
         wait := cnt
         repeat while 0 == ina[SCL]
           if (cnt-wait) > clkfreq/1000  'I2CDelayS
             quit
         data := (data << 1) | ina[SDA]
         dira[SCL]~~      '<<<<<<<<<<<<<<<<<<<<<<<<<<<<< FIXED WAIT LOW? 
       outa[SDA] := ackbit                 ' Output ACK/NAK to SDA
       dira[SDA]~~
       dira[SCL]~                          ' Toggle SCL from LOW to HIGH to LOW
       'waitcnt(500 + cnt)
       wait := cnt
       repeat while 0 == ina[SCL]
         if (cnt-wait) > clkfreq/1000    'I2CDelayS
           quit
       dira[SCL]~~
       outa[SDA]~
    

    In the diagram attached in the post above, it shows a) a Fixed Wait LOW from the Master pulling down SCL at the ACK. But in the basic i2c driver, the wait time the SCL is held low is only for the next 2 instructions until the dira[SCL]~ occurs. Would this be considered long enough for the device to see the LOW and then itself drive the SCL low? I am wondering if the device does not have time to respond with it's own SCL LOW before the master releases the SCL, which is causing the glitches. Tomorrow I will test with a wait period inserted to see what happens.

    The next question is, does the Fixed Low SCL period follow the SDA ACK LOW?
  • Tracy AllenTracy Allen Posts: 6,664
    edited 2014-04-30 09:32
    Worth a try. I read that the sensor is limited to 100kHz i2c buss. Usually routines written in Spin would be quite slow enough without fixed delays. One strategy would be to throttle your Prop clkfreq back to 40 or 20 MHz and see if that makes any difference.

    waitcnt(500+cnt) would be only 6.25µs at an 80MHz clock, not enough to be unequivocal.


    I see the Digikey product page has a nice video about applications of the product, and a link to OMRON material. But I couldn't navigate to anything about the P6T on the OMRON site. I sent in an FAE support request. Can you do the same? I'lll probably purchase one of these for a hot-spot detection project.
  • T ChapT Chap Posts: 4,223
    edited 2014-04-30 10:21
    Here is an example of a reply with all 35 bytes coming back as 254. I also included a version of the working response. The values hover around 230, which is 230/10 = temp in C. You can see that one byte is typically 0, the next is around 230. On a bad read, all values including CRC are 254. I am trying to compare the two now to see if anything sticks out.
    1024 x 295 - 55K
    898 x 243 - 105K
  • T ChapT Chap Posts: 4,223
    edited 2014-04-30 10:49
    Another observation. The difference between bad1 and good1 image, is that these are the starting segments of the transaction. Something is missing on the bad versions.
    872 x 179 - 85K
    803 x 175 - 74K
  • Tracy AllenTracy Allen Posts: 6,664
    edited 2014-04-30 11:28
    Missing the repeated start (Sr). At 7ms, the good one has the high level on scl where sda goes high to low, but the bad one is missing that pulse on scl.

    Can you post the whole i2c driver?
  • T ChapT Chap Posts: 4,223
    edited 2014-04-30 11:55
    The main loop is here:
     ' _clkmode               = xtal1 + pll16x
     ' _xinfreq               = 5_000_000
    PUB Main
         repeat
            ReadOMron          
            w(20_000_000)
    
    
    PUB ReadOMron       |  u  , v, F  
         u~
         i2c5.Initialize(0)
         i2c5.Start(0)    
         i2c5.write(0,omronwrite) 
         i2c5.Write(0, $4c)
         i2c5.stop(0)
         i2c5.Start(0)
         i2c5.write(0,omronread)  
         repeat 34   ' get first 34 bytes
           omron[u] := i2c5.Read(0,0) 
           u++
         omron[34] := i2c5.Read(0,1) 
         'i2c5.stop(0)
         'omronref :=  omron[0] +  omron[1] << 8 
         'omronref := omronref / 10   'convert to F
         'omronref  := ((omronref * 9)  / 5)  + 32   '0_000
    
    
         cls
         go0 
         'ser.decf(3, omronref, 3)   'show the reference die temp
         'ser.str(3, string(" "))
    
         u := 2
         v := 0
         repeat 7   'view only first x pixels of 16
           irval[v] := omron[u] + omron[u+1] << 8    'lsb+msb
           F := irval[v]    '/ 10
           'F := ((F * 9 )/ 5) + 32
           ser.dec(3, F)
           ser.str(3, string(" "))
           u := u+2
           v++
         omroncrc := omron[34]
         ser.decf(3, omroncrc, 3)
         ser.str(3, string(" "))
         
    
    

    The object has been renamed to basic i2c driver but on the obex it was called Basic i2c Driver TM.

    This is the latest version of the basic i2c driver I have been tweaking. It will sometimes go 1 minute with no glitch, but sometimes it glitches at 5 seconds. I have tried this with all different types of waitcnt's, 10000,1000, 100. 10, and 5. It doesn't seem to make a difference.

    If you want, pm an address and I will have digi drop one in the mail today to you.
  • Tracy AllenTracy Allen Posts: 6,664
    edited 2014-04-30 13:48
    OMRON redirected me to their components division,

    Thanks for the i2c object. I hadn't looked at that one before. TM: Tim Moores' modification of James Burrows' modification of Mike Green's version 1.1. Tim mentions slowing it down for 100kHz and adding the clock stretching. For reference, it now appears in OBEX as HMC6343 i2c Driver. Tweaking these drivers can be pretty maddening, at least that's been my experience with a few specific devices!
  • T ChapT Chap Posts: 4,223
    edited 2014-04-30 19:09
    According to http://i2c.info/i2c-bus-specification
    For all data bits including the Acknowledge bit, the master must generate clock pulses.

    So is this indicative of the error being on the part of the master or device?
  • Tracy AllenTracy Allen Posts: 6,664
    edited 2014-04-30 22:08
    This is your bad.jpg with the putative missing pulse on scl faked in in red. And the associated repeated start transition on sda.

    bad1.jpg


    Yes, the clock is the responsibility of the master, but the slave can hold. I see that the modified Read and Write methods now use open logic that assumes pullup resistors on both sda and scl. So the slave could possibly be stretching the clock at that point so that a pulse generated by the Prop is not getting through. It is hard to see from the code how that could come about, but there is a lot of tweaking of code going on, I guess:innocent:. The Start and Stop methods are still driving both the sda and scl pins to outputs. The D6T document says it is going to stretch the clock, not clear whether before or after the ACK, and during all of the bytes, or at only specific ones (such as before the repeated start).
    872 x 179 - 75K
  • T ChapT Chap Posts: 4,223
    edited 2014-05-01 06:42
    Thanks a bunch Tracy for the pointers. I have a stable version now. See the waitcnt marked "required". I see no more glitches. I also posted the latest basic i2c driver with the most recent tweaks.
    Pub Main
         i2c5.Initialize(0)
         repeat
            ReadOmron          
            w(20_000_000)
    
    
    
    PUB ReadOMron       |  u  , v, F  
         u~
         'i2c5.Initialize(0)   'move to main
         i2c5.Start(0)
         'w(5000)
         i2c5.write(0,omronwrite) 
         'w(5000)
         i2c5.Write(0, $4c)
         i2c5.stop(0)
         w(1500)    '  <<< required waitcnt
         i2c5.Start(0)
         i2c5.write(0,omronread)  
         repeat 34   ' get first 34 bytes
           omron[u] := i2c5.Read(0,0) 
           u++
         omron[34] := i2c5.Read(0,1) 
         'i2c5.stop(0)
         'omronref :=  omron[0] +  omron[1] << 8 
         'omronref := omronref / 10   'convert to F
         'omronref  := ((omronref * 9)  / 5)  + 32   '0_000
    
    
         cls
         go0 
         'ser.decf(3, omronref, 3)   'show the reference die temp
         'ser.str(3, string(" "))
    
         u := 2
         v := 0
         repeat 7   'view only first x pixels of 16
           irval[v] := omron[u] + omron[u+1] << 8    'lsb+msb
           F := irval[v]    '/ 10
           'F := ((F * 9 )/ 5) + 32
           ser.dec(3, F)
           ser.str(3, string(" "))
           u := u+2
           v++
         omroncrc := omron[34]
         ser.decf(3, omroncrc, 3)
         ser.str(3, string(" "))
         
    

    When and if you start messing with this device, if you get into figuring out the CRC method please post what you come up with. There are some examples in the app notes but they are in C or some other format that I haven't been able to interpret yet.
  • Tracy AllenTracy Allen Posts: 6,664
    edited 2014-05-01 10:59
    What are the units of w(.)? Clock cycles, microseconds...?
  • T ChapT Chap Posts: 4,223
    edited 2014-05-01 11:04
    PUB w(k)
        waitcnt(k + cnt)
    
  • Tracy AllenTracy Allen Posts: 6,664
    edited 2014-05-03 21:10
    Thanks much, I received the D6T yesterday, and assembled the cable with the JST connector. Oh my, those terminals are a PITA without the right tools! I've run into that before, and the 26 gage wire I was using had too much insulation. I wonder if you have the proper official crimping tool? I did get it done and the terminals locked in place. Looking forward to try the sensor.
  • T ChapT Chap Posts: 4,223
    edited 2014-05-04 04:16
    I do have the crimp tool, but I also just assumed that you would have one. To be honest, on my omron device, I did not use that connector. I soldered 22g wire to the pins on the exposed side of the connector and put a little heat glue over the wires for strain relief. If you do not have the crimp tool, in the future then either you can cut off the crimp part of the pin and solder your wire to it, or just solder the wire to the exposed pins near where they are sitting on the solder pads on the PCB.
  • Tracy AllenTracy Allen Posts: 6,664
    edited 2014-05-08 12:24
    I do have an assortment of hand crimping tools, but nothing that small. All for much larger Molex/Tyco/Amp terminals. I looked at JST and saw that the tool they sell is a semiautomated spool-feeder with dies for each terminal type, $7800 for the base unit. Other terminal-specific tools at around $500. I did end up purchasing one hand tool from Amazon that had reasonable reviews, and it will be a good thing to have around. It has dies for 1mm, 1.4mm 1.6mm and 1.9mm, and one of those will be close enough to these 1.25mm blocks. Otherwise your soldering solutions sound good. JST connectors are increasingly popular, and I'm always happy when they come with a pre-wired connector stub.

    Thanks for the D6T sensor. I think it will be useful for a project I have here, maybe also something for other forumistas. Linking to your other thread, the interface is worked out.
  • T ChapT Chap Posts: 4,223
    edited 2014-05-08 17:21
    Tracy, your amazon link is not correct. I would be interested to see the tool you were referring to.
  • Tracy AllenTracy Allen Posts: 6,664
    edited 2014-05-08 17:52
    Corrected the link, PA-09 micro crimp tool.
  • T ChapT Chap Posts: 4,223
    edited 2014-05-09 17:44
    http://www.digikey.com/product-search/en?x=0&y=0&lang=en&site=us&KeyWords=wm9999

    I have this Molex crimp tool that works ok on the JST crimp pins.

    With the new code I am getting no errors, works perfectly.
  • T ChapT Chap Posts: 4,223
    edited 2014-05-19 22:46
    http://youtu.be/syBJf_FjkZ8

    A short video showing off the Omron sensor. Propeller driven new haven 4.3 LCD.
  • Tracy AllenTracy Allen Posts: 6,664
    edited 2014-07-04 14:06
    I see OMRON is introducing a 16 x 16 pixel version of this sensor.
  • T ChapT Chap Posts: 4,223
    edited 2014-07-05 05:06
    Good to see that. I will definitely be interested in testing it out.
  • Don MDon M Posts: 1,652
    edited 2014-07-05 06:09
    T Chap wrote: »
    http://youtu.be/syBJf_FjkZ8

    A short video showing off the Omron sensor. Propeller driven new haven 4.3 LCD.

    Seems the video isn't available anymore. Didn't get a chance to see it...
Sign In or Register to comment.