I2C

Help
Anobium
2014-03-28
2014-03-28
1 2 > >> (Page 1 of 2)
  • Anobium

    Anobium - 2013-10-04

    I have asked Hugh for a code review.

    Inclusion? We need people to test and validate this is working correctly then it could be included. I will complete more tests today with a clean install of GCB - I do not expect any issues. Ozzy is testing - he has a really nice protocol analyser - hopefully we will have more test results in a few days.

     
  • Anobium

    Anobium - 2013-10-05

    PS

    I can now get back to the project I started which was to implement a Picaxe based DS1307 with LCD device metering device with my uber cool Great Cow Solution!!

     
  • Anobium

    Anobium - 2013-10-13

    No idea why you get the error, but, I have posted all new code (with the error resolved?). I corrected the code in that area a few days ago.

    See ftp://tmail.mooo.com:8021/gcb/contributions/I2C/Test Release/Version_0_85.zip

     
    Last edit: Anobium 2013-10-13
  • Anobium

    Anobium - 2013-10-14

    :-)

     
  • Anobium

    Anobium - 2013-10-14

    :-)

     
  • joe rocci

    joe rocci - 2014-03-23

    Hi Guys!
    I'm trying to get my I2C device going, but running into some confusing results. I installed Anobium's I2C.h file and ran the discovery program in the Help file. My I2C device, which should discover at address h55 is actually discovering at address hAA. The device is a SI570 from Silicon Labs. My PIC is a 16F877A running @ 20mhz.

    Suggestions?

     
  • Anobium

    Anobium - 2014-03-23

    I am glad to hear that someone is using the code.

    The address found has included the 8th bit, which is the READ/WRITE address.

    Lets walk this through.

    0xAA = b'10101010' ' this has all 8 bits. If we shift the bit to the right, this would remove bit 0 giving b'1010101' which equates the 0x55. So, IC2 is locating your device correctly.

    Remember, when you address an IC2 device is has a seven bit left shifted address with a binary 1 or 0 to make up the full 8 bit transmission on the i2c bus.

    The code is working as expected.

     
    • joe rocci

      joe rocci - 2014-03-23

      Thanks

      Does this mean I need to shift-
      left whatever I read as data? Seems weird. I'd expect the R/W bit to have been stripped off by the handler.

       
      • Anobium

        Anobium - 2014-03-23

        See the code below.

        A shift means... 0x55 * 2 = 0xAA for write operations and 0xAB for read operations.

        And, there is not hardware handler for this device - yet.

        We can work together to write one. We have the basic I2C commands, see the help file, and we can build the handler from the basic I2C commands.

        A basic read / write is shown below. But, if you need multiple byte reads, or multi byte write is down to the device and your use case(s). If is very simple to write a generic handler in GCB - its fun.

         
  • Anobium

    Anobium - 2014-03-23

    From a quick scan of the S1570 datasheet.

    I would simply do the following in your code.

         I2CSTART
         I2CSEND( your_slaveaddress ) 'i.e 0xAA
         I2CSEND( the_byte_Address_you_are_going_to_set )
         I2CSEND( data_to_be_set )
         I2CStop
    

    If you need to read.

         I2CSTART
         I2CSEND( your_slaveaddress )   'ie 0xAA
         I2CSEND( the_byte_Address_you_are_going_to_read )
         I2CSTOP
         I2CSEND ( your_read slaveaddress )   'ie 0xAB
         I2CRECEIVE your_returnedbyte  , NACK
         I2CStop
    
     
    • joe rocci

      joe rocci - 2014-03-23

      I think you're missing the point...the slave address of the SI570 is actually 55, not AA, but it's replying to AA.

       
  • Anobium

    Anobium - 2014-03-23

    The slave address is 0x55 shifted by one bit to the right then ORed 0 or 1 for read/write operations. I know this as this is the standard for I2C. I studied this for a long time last year. See http://www.totalphase.com/support/articles/200349176-7-bit-8-bit-and-10-bit-I2C-Slave-Addressing

    But I think address you need to use is 0xAA or 0xAB for a device address of 0x55.

    I always stand to be corrected.

     
    • joe rocci

      joe rocci - 2014-03-23

      As a user, all I want to care about is sending the actual address and getting the actual data. If I have to make special considerations in my code for the peculiarities of I2C, then I might as well write my own handler, which is what I'm probably going to do.

      I've been using GCB for several years. In general, l find the compiler core to be quite good, but the libraries never cease to surprise me.

      Joe

       
  • Anobium

    Anobium - 2014-03-23

    I working to improve the libraries and the documentation at the moment.

    You should be able to create your own handler based on the many we have recently published. I am currently working with vendors to increase the I2C library.

    Let us know how you get on.

     
  • joe rocci

    joe rocci - 2014-03-27

    I'm still struggling trying to get a simple read operation to work properly. Here's some sample code per sequence suggested by Anobium:

    'I2C device address is 55H
    I2CSTART
    I2CSEND(0xaa) 'Express address left-shifted with a "0" in bit 0 to tell device
    this is a write
    hserprint I2Csendstate: hserprintcrlf 'I get an ACK here ("0")
    I2CSEND(7) ' I want to read decimal register 7
    hserprint I2Csendstate: hserprintcrlf ''I get an ACK here too
    I2CSTOP
    I2CSEND (0xab) 'Express address left-shifted with a "1" in bit 0 to tell device
    this is a read
    hserprint I2Csendstate: hserprintcrlf 'I don't get an ACK here
    I2CRECEIVE InValue , NACK
    hserprint I2Csendstate: hserprintcrlf 'I don't get an ACK here
    hserprint InValue hserprintcrlf 'I don't proper read data here
    I2CStop

    I can get the device to ACK on the ICSend operations, but nothing comes back on the I2CReceive operation. Also, I still find it tedious and arcane that I have to left-shift my base address and stuff bit-zero to make anything work. Why aren't the functions structured to do this low-level stuff for you?

    Joe

     
  • Anobium

    Anobium - 2014-03-27

    Let me try and find an example of a SI570.h file from another platform.

    If you can find one, please post here.

     
  • joe rocci

    joe rocci - 2014-03-27

    Thanks

    Most are written in assembler, but there is a "C" handler in the Arduino libraries somewhere.

     
  • Anobium

    Anobium - 2014-03-27

    OK. Please be patient. This has taken a few hours to understand. I do not have this device and this may take one or two posting.

    I am going to use http://mbed.org/users/soldeerridder/code/SI570/file/dae1bf95c49e/SI570.h as the reference model (see line 52 of the listing.... 0xAA. Lets discuss device addressing later) and the product datasheet.

    I would typically have a device in the lab here and I would use my protocol analyser verify - do not have a device here.... so here goes.

    You may need to recall the device settings upon power up, this looks like.

    I2CSTART
    I2CSEND( 0xAA )
    I2CSEND( 0x87 )
    I2CSEND( 0x01 )
    I2CSTOP
    

    You create a subroutine of these commands because you will need to recall the device setting after each frequency change. I think this is the case - it is repeatedly stated in the datasheet.

    Then, to read the registers you need to complete a sequential read of six bytes. I would use and array to do this. As follows:

    dim registerarray as array * 6
    
    I2CSTART
    I2CSEND( 0xAA )
    I2CSEND( 0x07 )
    I2CSTOP
    I2CSEND ( 0xAB )
    for in_bytes = 1 to 5
        I2CRECEIVE registerarray[in_bytes], ACK
    next
    I2CRECEIVE registerarray[in_bytes], NACK
    I2CStop
    

    You should find, hopefully, the register is in the array.

    To read the HS_DIV you will need to read array as follows. This code is NOT GCBasic ready. You need to convert, but, lets see if you can read the registers first.

    // HS_DIV conversion
    hsdiv = ((buf[0] & 0xE0) >> 5) + 4; // get reg 7 bits 5, 6, 7
    // hsdiv's value could be verified here to ensure that it is one
    // of the valid HS_DIV values from the datasheet.
    // n1 conversion
    n1 = (( buf[0] & 0x1F ) << 2 ) + // get reg 7 bits 0 to 4
                 (( buf[1] & 0xC0 ) >> 6 );  // add with reg 8 bits 7 and 8
    if (n1 == 0) {
        n1 = 1;
    } else if (n1 & 1 != 0) {
        // add one to an odd number
        n1 = n1 + 1;
    }
    
    frac_bits = (( buf[2] & 0xF ) * POW_2_24 );
    frac_bits = frac_bits + (buf[3] * POW_2_16);
    frac_bits = frac_bits + (buf[4] * 256);
    frac_bits = frac_bits + buf[5];
    
    rfreq = frac_bits;
    rfreq = rfreq / POW_2_28;
    rfreq = rfreq + ( (( buf[1] & 0x3F ) << 4 ) + (( buf[2] & 0xF0 ) >> 4 ) );
    

    Good luck

     
  • joe rocci

    joe rocci - 2014-03-27

    Thanks for doing the research
    I ran the GCBasic part of the code above and got numerous errors. Here's the code and the result:

    dim registerarray as array * 6

    I2CSTART
    I2CSEND( 0xAA )
    I2CSEND( 0x87 )
    I2CSEND( 0x01 )
    I2CSTOP

    I2CSTART
    I2CSEND( 0xAA )
    I2CSEND( 0x07 )
    I2CSTOP
    I2CSEND ( 0xAB )
    for in_bytes = 1 to 5
    I2CRECEIVE registerarray[in_bytes], ACK
    next
    I2CRECEIVE registerarray[in_bytes], NACK
    I2CStop

    Great Cow BASIC (0.9 22/9/2013)
    Compiling C:\Documents and Settings\SI570\I2C Experiments\Internal I2C test.~pbs ...
    Errors have been found:
    Internal I2C test.~pbs (52): Error: Invalid variable type: ARRAY * 6
    Internal I2C test.~pbs (60): Error: Invalid variable type: IN_BYTES
    Internal I2C test.~pbs (60): Warning: Type cast should be written before the
    value it applies to
    Internal I2C test.~pbs (61): Error: Array/Function REGISTERARRAY[IN_BYTES]
    has not been declared
    Internal I2C test.~pbs (63): Error: Invalid variable type: IN_BYTES
    Internal I2C test.~pbs (63): Warning: Type cast should be written before the
    value it applies to
    The message has been logged to the file Errors.txt.

     
  • Anobium

    Anobium - 2014-03-28

    Moved to HELP Forum.

    My error. I was on the train. I have created an outline for you. This is all from the datasheet but you should be able to get the hsdiv value returned if you use the code shown below.

    A few points.
    1. After we have the basic device working, by that I mean you get hsdiv returned we need to move to a zip for this code. It is will be large header file. :-)
    2. The device uses decimal values for the Mhz and the code frequencies are very big numbers and these numbers must be floating point number especially 2^28, So we need to sure there is enough memory to do the calculations needed in some of the later methods. What chip are you using?
    3. And, as we only have integer maths available we will need to multiple values by 100 (equates to three decimal places). I mention this as the porting of the code needs to account for decimal frequencies.... a problem that we come across often.

    Anyway, please try this. Does this return a value for hsdiv?

    Anobium

     ' YOU NEED TO ADD CHIP, IC2 and SERIAL stuff here.   
     'start of code version 0.01
    
      dim buf_SI570 (6)
    
      SI570_Reset
      SI570_Get_Registers
    
      HSerPrint SI570_Get_hsdiv
      HserPrintCRLF
    
      ' This may work if you have the later libaries.
      HSerPrint ByteToBin ( SI570_Get_hsdiv )
      HserPrintCRLF
    
      END
    
      ' start of the new SI570.h for Great Cow Basic
      ' We can cut this code out into a file called SI570.h once the code works
    
      ' these must be floating point number especially 2^28 so that
      ' there is enough memory to use them in the calculation
      #define POW_2_16              65536.0
      #define POW_2_24           16777216.0
      #define POW_2_28          268435456.0
      #define FOUT_START_UP            56.320     //MHz
      #define PPM                    3500         // +/- max ppm from centre frequency
      #define FDCO_MAX                5670.0         //MHz
      #define FDCO_MIN                4850.0         //MHz
    
      Sub SI570_Reset
          I2CSTART
          I2CSEND( 0xAA )
          I2CSEND( 0x87 )
          I2CSEND( 0x01 )
          I2CSTOP
      End sub
    
      Sub SI570_Get_Registers
          I2CSTART
          I2CSEND( 0xAA )
          I2CSEND( 0x07 )
          I2CSTOP
          I2CSEND ( 0xAB )
          for SI570_in_bytes = 1 to 5
              I2CRECEIVE  buf_SI570(SI570_in_bytes), ACK
          next
          I2CRECEIVE buf_SI570(in_bytes), NACK
          I2CStop
    
      '    HS_DIV conversion
           hsdiv = ((buf_SI570(0) & 0xE0) / 16 ) + 4   ' get reg 7 bits 5, 6, 7
      '    hsdiv's value could be verified here to ensure that it is one
      '    of the valid HS_DIV values from the datasheet.
      '    n1 conversion
      '    n1 = (( buf[0] & 0x1F ) << 2 ) + // get reg 7 bits 0 to 4
      '                 (( buf[1] & 0xC0 ) >> 6 );  // add with reg 8 bits 7 and 8
      '    if (n1 == 0) {
      '        n1 = 1;
      '    } else if (n1 & 1 != 0) {
      '        // add one to an odd number
      '        n1 = n1 + 1;
      '    }
      '
      '    frac_bits = (( buf[2] & 0xF ) * POW_2_24 );
      '    frac_bits = frac_bits + (buf[3] * POW_2_16);
      '    frac_bits = frac_bits + (buf[4] * 256);
      '    frac_bits = frac_bits + buf[5];
      '
      '    rfreq = frac_bits;
      '    rfreq = rfreq / POW_2_28;
      '    rfreq = rfreq + ( (( buf[1] & 0x3F ) << 4 ) + (( buf[2] & 0xF0 ) >> 4 ) );
    
      End Sub
    
      Function SI570_get_frequency
               SI570_Get_Registers
               SI570_get_frequency = (rfreq*fxtal_device)/(hsdiv*n1)
      End Function
    
      sub SI570_get_rfreq
    
      End Sub
    
      sub SI570_get_n1
    
      End Sub
    
      function SI570_Get_hsdiv
          SI570_Get_Registers
          SI570_Get_hsdiv = hsdiv
      End  Function
    
      sub SI570_set_frequency(in  frequency as word )
    
      End Sub
    
      sub SI570_set_frequency_small_change(in  frequency as word) {
    
      End Sub
    
      sub SI570_set_frequency_large_change(in  frequency as word)
    
      End Sub
    
      sub SI570_SetBits(original as bit, reset_mask as bit , new_val as bit)
    
      end sub
    
     
  • Anobium

    Anobium - 2014-03-28

    Moved to Help Forum

    ...update... brilliant... move posting to new forum... messed up the Thread... a call to Sourceforge Support in progress. Sorry.

     
    Last edit: Anobium 2014-03-28
  • Anobium

    Anobium - 2014-03-28

    An update.

    I used the incorrect buffer and this now had register N1 coded.

    Version 0.02. If you updated can you post back an update so we are working on the latest version?

    And, can you review https://sourceforge.net/p/gcbasic/discussion/579126/thread/1a3accc6/#f57e ? These questions will need resolving.

     
    Last edit: Anobium 2014-03-28
  • joe rocci

    joe rocci - 2014-03-28

    Anobium
    I really appreciate all youre trying to offer, but all I
    I need is to the get single-byte I2C reads and writes working and I can take it from there. I understand how the SI570 works quite thoroughly and in fact Ive already coded and tested the math to calculate the frequency bytes. The data sheet is very poorly written and the calculations really dont require high precision floating point math. I did it with just long integer math using a very different algorithm from the data sheet recommendations and that part is short, compact, and simple.

    So, if we can get the byte reads and writes going, I'll have the whole thing going very quickly and I'll gladly share with the community.

    Joe

     
  • Anobium

    Anobium - 2014-03-28

    Try the file I just posted. If this code reads hsdiv and displays a valid value then I know the method of access 6 six bytes in sequence is correct.

     
  • Anobium

    Anobium - 2014-03-28

    I just spotted another error. Change:

    for SI570_in_bytes = 1 to 5 to for SI570_in_bytes = 1 to 6

    I have reviewed a number of sites. You may have to read all 6 bytes in sequence.

     
1 2 > >> (Page 1 of 2)

Log in to post a comment.

Get latest updates about Open Source Projects, Conferences and News.

Sign up for the SourceForge newsletter:

JavaScript is required for this form.





No, thanks