Shop OBEX P1 Docs P2 Docs Learn Events
Need help w/ TC74 — Parallax Forums

Need help w/ TC74

AGCBAGCB Posts: 327
edited 2013-12-01 14:24 in Propeller 1
I'm trying to write a code for a TC74 temp sensor. I'm using what I can from other devices but since I'm new to spin, I need a little help. Where does the data that is read, get returned? I also don't understand how the address gets changed to read (lsb of 1).
CON
_clkmode = xtal1 + pll16x                                                      
_xinfreq = 5_000_000

SDA_pin = 12
SCL_pin = 13
Bitrate = 400_000
read    =       $00             


OBJ

  I2C : "I2C PASM driver v1.3"
  TV  : "TV_TEXT"

PUB Main | Idx 
  TV.start(20)
  waitcnt(clkfreq + cnt)     
  TV.out($00)                'clear screen   
  temperature 

PUB temperature
TV.out($00)                'clear screen    
  tv.str(string("Temperature info 1st in bin",$0D)) '2s compliment value
  I2C.start(SCL_pin,SDA_pin,bitrate) 
  I2C.command(I2C#TC74,read)   
  tv.bin(result, 8)
  I2C.stop  
  waitcnt(clkfreq*2+cnt)         '2 seconds before next read
  temperature

I added the TC74 to the object device list
Thanks,
Aaron

Comments

  • AGCBAGCB Posts: 327
    edited 2013-11-24 04:44
    In the I2C PASM driver and others , I don't understand what to put in the (ackbit)
  • Tracy AllenTracy Allen Posts: 6,664
    edited 2013-11-24 10:01
    Your temperature routine should not call itself at the end. That could be bad!

    You asked, "Where does the data that is read, get returned?". The data needs to be put into the variable "result", in your temperature method:

    result := I2C.Read(I2C#TC74,address)

    Then in your Main method, you would have this,
    result := temperature
    and the call returns the result assigned in the temperature method, and you would go on to show that on the TV. Every method has its own implied result variable. You can also give that variable an alias name, or you can use the return (...) command to explicitly put a value in the result (see the manual).

    In your program, I2C.Start and I2C.Stop belong in Main, not in the Temperature method. Those methods start and stop the pasm cog. They are not the start and stop command of the i2c protocol.

    There is a remaining issue though. I understand that you added the I2C#TC74 device code. I haven't used the TC74 myself, but it appears to be one of those devices that does not take an address. All it takes is the device ID set to read, and then the next transaction has to be a read of the temperature. It appears that the pasm driver insists on sending an address. It has a mechanism for sending either one or two bytes of address, but not zero bytes. I may well be missing something. Chris?

    As to the question of what to put in the ackbit. The pasm driver takes care of that for you and you don't have to deal with it in the Spin methods. During a read operation, the master is supposed to send out an ack after each byte that it receives, until the last one, which it naks to indicate that it has all that it needs. So in a read of many bytes, all but the last one are acked.
  • AGCBAGCB Posts: 327
    edited 2013-11-24 11:21
    Thanks Tracy
    Let me decipher this and try it and I'll report back.
    Aaron
  • AGCBAGCB Posts: 327
    edited 2013-11-25 05:05
    Forgive me for newby sounding questions and language. I am new to SPIN.

    I think I've made some progress. Getting something different than all zeros, (all ones). Tried a different object, the " jm_i2c" ,which I believe has a better method for the TC74 read. Hope JM sees this!

    I still don't know what to enter in the (ackbit). It has to have something put in it or it will not compile. I made it a constant to be able to try different numbers.

    This is the latest code. Your help is greatly appreciated! Aaron
    CON
    _clkmode = xtal1 + pll16x                                                      
    _xinfreq = 5_000_000
    
    sdapin = 12
    sclpin = 13
    ackbit  =   1    
    TC74    =       %1001_1010                  
    
    OBJ 
      I2C : "jm_i2c"
      TV  : "TV_TEXT"
      
    VAR     byte          temper
    
    PUB Main | Idx 
      TV.start(20)  
      I2C.init(12,13)  
      waitcnt(clkfreq + cnt)
      repeat   
        temperature     
        temper:=temperature     
        waitcnt(clkfreq + cnt)       
        tv.str(string($0d,"Temperature info 1st in bin",$0D)) '2s compliment value
        tv.str(string("Temper =   ")) '2s compliment value
        tv.bin(temper, 8)      
        waitcnt(clkfreq*2+cnt)         '2 seconds before next read
        TV.out($00)                'clear screen      
       
    PUB temperature     
        i2c.start         
        i2c.read(ackbit)
        result := i2c.read (tc74)
    
  • Tracy AllenTracy Allen Posts: 6,664
    edited 2013-11-25 08:44
    Looking at it again, the TC74 does have an command register and several ways to address the temperature readings. You can see it in the timing diagram, figure 3-1 in the data sheet:
    Screen shot 2013-11-25 at 8.22.36 AM.png

    You have the TC74-5 device ID 01_1010. Eight bits as those two i2c drivers expect it. That is the 7-bit device ID shifted left by one to make room for the read/write bit.

    The following simple one should work...
    PUB temperature
      result := i2c.ReadByte(TC74, 0)   ' read a byte from the temperature register
    
    or this as a sequence of low level routines. This is straight off the data sheet diagram.
    PUB temperature
      i2c.Start
      i2c.Write(TC74)   ' device ID
      i2c.Write(0)    ' command to select the temperature register
      i2c.Start   ' repeated start
      i2c.Write(TC74 | 1)   ' device ID again, lsb set to read
      result := i2c.Read(i2c#NAK)  ' 1 byte is the last byte
      i2c.Stop
    
    or this abbreviated routine, because the register selection stays pointing to the temperature. This is the 3rd option in the data sheet diagram.
    PUB temperature
      i2c.Start
      i2c.Write(TC74 | 1)   ' device ID, lsb set to read
      result := i2c.Read(i2c#NAK)  ' 1 byte is the last byte
      i2c.Stop
    
  • AGCBAGCB Posts: 327
    edited 2013-11-25 14:47
    There's another thread on "SMBus question today.

    The tc74 is a SMBus/I2C device. Could this be part of the problem? I still get no usable data , even with Tracy's codes, though they look good. I had to modify them slightly for use with the "jm_i2c" object. Maybe I'll try the "i2cobject" again.

    Aaron

    When I used this with a PIC chip, there was a register setting for the SMBus
  • D.PD.P Posts: 790
    edited 2013-11-25 15:33
    AGCB wrote: »
    There's another thread on "SMBus question today.

    The tc74 is a SMBus/I2C device. Could this be part of the problem? I still get no usable data , even with Tracy's codes, though they look good. I had to modify them slightly for use with the "jm_i2c" object. Maybe I'll try the "i2cobject" again.

    Aaron



    When I used this with a PIC chip, there was a register setting for the SMBus


    I have had great luck with the jm_i2c object for the most recalcitrant sensors (K33 CO2/Temp sensor for one), can you post the entire code you are attempting to use with this device. Snippets are hard to follow.
  • AGCBAGCB Posts: 327
    edited 2013-11-25 17:40
    D.P wrote: »
    can you post the entire code you are attempting to use with this device. Snippets are hard to follow.

    Here's the latest which gives output of all 1s. I just looked up info on SMBus and it says the max bitrate is 100kHz. Is the bitrate specified anywhere in the program?
    CON
    _clkmode = xtal1 + pll16x                                                      
    _xinfreq = 5_000_000
    
    sdapin = 12
    sclpin = 13
        
    TC74    =       %1001_1010                  
    
    OBJ 
      I2C : "jm_i2c"
      TV  : "TV_TEXT"
      
    VAR     byte          temper
    
    PUB Main | Idx 
      TV.start(20)  
      I2C.init(12,13)  
      waitcnt(clkfreq + cnt)
      repeat   
        temperature
        tv.bin(temperature,8)
        temper:=temperature     
        waitcnt(clkfreq + cnt)       
        tv.str(string($0d,"Temperature info 1st in bin",$0D)) '2s compliment value
        tv.str(string("Temper =   ")) '2s compliment value
        tv.bin(temper, 8)      
        waitcnt(clkfreq*2+cnt)         '2 seconds before next read
        TV.out($00)                'clear screen      
       
    PUB temperature  
      i2c.start
      i2c.write(tc74)
      i2c.write(0)  
      i2c.start
      i2c.read(i2c#nak)
      i2c.stop
      'result:=i2c.read(i2c#ack)
      result:=i2c.read(result)  
    
  • Tracy AllenTracy Allen Posts: 6,664
    edited 2013-11-25 18:10
    The version of jm_i2c I have (from OBEX) does not have an "init(..)" method by that name, rather, it has a method called setupx(sclpin, sdapin). Yours must have init(..), otherwise it would not compile, but that is a bit puzzling. I also have to ask, do you have the pullup resistors to Vdd installed?

    I take it you've been playing with the temperature routine, but what you posted just above can't work.
    [SIZE=1][FONT=courier new]PUB temperature  
      i2c.start
      i2c.write(tc74)
      i2c.write(0)  
      i2c.start
      [COLOR=#ff0000]result := [/COLOR]i2c.read(i2c#nak)  ' have to capture the result here
      i2c.stop
      [s]'result:=i2c.read(i2c#ack)[/s]   ' these lines can't work here
      [s]result:=i2c.read(result)[/s]
    [/FONT][/SIZE]
    

    I don't think it is an issue of SMB vs i2c. For most intents and purposes those are the same.

    Chris Gadd's pasm driver does have a bitrate option:
    start(clk_pin, data_pin, bitrate)
    So you could set that to 100_000. Spin versions are intrinsically slow and can't go that fast.
  • AGCBAGCB Posts: 327
    edited 2013-11-25 19:15
    I have 4.7K resistors on both. I'll keep trying and some different objects too although this one seemed to me to be easiest to use.

    This is one thing I don't like about higher level languages, you don't know what's going on behind the scene. With assembly you do it all and you know exactly what it does and there's no one else to blame. I was hoping spin would be fast and easy but it's introduced a bunch of new problems.

    Thanks
    Aaron
  • Tracy AllenTracy Allen Posts: 6,664
    edited 2013-11-25 23:14
    Don't be discouraged. Spin allows for layers of abstraction in methods and objects, but when you drill down, it is very close to the hardware operation of the Propeller. Just slower than pasm.

    I've heard somewhere that I2C written in spin runs at about 35kHz when clocking scl. The minimum for SMB (which has a bus timeout feature) is 1kHz, so the Prop is still way above that.

    I2C devices are picky about certain things, but when everything is lined up, they are very reliable. You may be left wondering why they gave you so much trouble the first time around. (Been there! :innocent:). Problems with i2c or SMB devices come up here on the forum frequently, and they are often resolved with a sheepish admission that the wires were reversed or not making good contact or something like that, or the wrong device ID has been used, say 7 bits/8 bit confusion, or there is a mixup of innumerable register pointers, etc. Manufacturers are given a lot of latitude in how to implement i2c, so there are indeed esoteric variations you might run across.

    The TC74 doesn't appear to be exotic though, and either of the objects you have IMHO should be up to the job once you find the trick.

    A tool like the Saleae logic analyzer can be a great help in diagnosing I2C protocol issues.

    Are you sure you have address #5 version of the TC74?
  • AGCBAGCB Posts: 327
    edited 2013-11-26 04:47

    Are you sure you have address #5 version of the TC74?

    I used the same device in a PIC assembly program, with that address and it worked fine. I've looked at that program several times to see if I could discover anything, but nothing.

    And yes, I am discouraged! But not giving up yet.

    Thanks
    Aaron
  • ChrisGaddChrisGadd Posts: 310
    edited 2013-11-26 09:55
    Sorry, didn't see this thread.

    My I2C drivers expect a 7-bit device address, the handler shifts the address and appends the read/write internally, so your device should be addressed at %100_1101 ($4D).
    If that's the case, then TV.bin(I2C.read($4D,00),8) should display the reading.

    Here's a poller routine to verify that it's awake and on that address.
    CON
      _clkmode = xtal1 + pll16x
      _xinfreq = 5_000_000
      SDA_pin = 12
      SCL_pin = 13
      BITRATE = 100_000
    
    OBJ
      I2C : "I2C PASM driver v1.3"
      FDS : "FullDuplexSerial"
    
    PUB Main | device_id
      FDS.start(31,30,0,115_200)
      waitcnt(clkfreq + cnt)
      FDS.tx($00)
      I2C.start(SCL_pin,SDA_pin,BITRATE)
      device_id := 0
      repeat until device_id == $80
        if (I2C.command(device_id,0))
          FDS.str(string("Device found at "))
          FDS.hex(device_id,2)
          FDS.tx($0D)
        device_id++
      I2C.stop
    
  • AGCBAGCB Posts: 327
    edited 2013-11-26 15:42
    YES!!!

    I got it! Used the "device finder" to make sure it was there and working and then with a little monkeying got it to display binary and decimal Celsius.

    Thanks Chris and everyone.

    Now how do I convert to Fahrenheit?
    And is there a hex code for the degree symbol in full duplex or TV? I tried the ascii code $DF but got something else.

    If anyone is interested in the not quite final code, say so.

    Aaron
  • ChrisGaddChrisGadd Posts: 310
    edited 2013-11-26 16:40
    Congratulations!

    Under the Propeller tool Help menu you can view the character chart and select the ° symbol directly, and can see that it's actually at hex $B0.

    For converting Celsius to Fahrenheit, the formula is F := C * 9/5 + 32. That'll give you the integer degrees, and c * 9 // 5 gets the remainder.
  • AGCBAGCB Posts: 327
    edited 2013-11-26 17:51
    Thanks.

    Next week I'll display it on a LCD before I move on to another project.

    Feels like post pardom depression now that the big push is over LOL

    Aaron
  • Tracy AllenTracy Allen Posts: 6,664
    edited 2013-11-27 08:01
    And Eureka! What were the final tricks that got it working?
  • AGCBAGCB Posts: 327
    edited 2013-12-01 14:24
    And Eureka! What were the final tricks that got it working?

    Sorry, I've been out of town for a few days.

    It was 2 things that both you and Chris said but it took time to sink in to my old head.
    The way of writing a 7 bit address goofed me up and the 'way too simple' read device and collect data all in one line command.

    Thanks
    Aaron
Sign In or Register to comment.