• AVR Freaks

High Level I2C functions ?

Author
kelt
Starting Member
  • Total Posts : 34
  • Reward points : 0
  • Joined: 2012/11/29 05:28:29
  • Location: France
  • Status: offline
2017/03/11 07:29:34 (permalink)
0

High Level I2C functions ?

Hi everybody,
 
I am now in the communication part of my project.
 
I plan to use an I2C bus for communicating with an EEPROM and some peripherals.
I was thinking about using a high level function. In my previous project developped in PICBASIC Pro on a 18F we had such a fucntion, I2CWRITE. We had only to specify the slave address and the data to transmit and everything was done, automatically.
 
I am now using a 24F with XC16 and trying not to reinvent the wheel, but the 24FRM Library examples work at the bit level, while MCC generates (as usual !) tons of functions to decrypt !
 
Is there somewhere a High Level function equivalent to my old and very convenient I2CWRITE ?
 
Thank you for your help.
 
Kelt
 
 
 
 
#1

19 Replies Related Threads

    CinziaG
    die fucking humans
    • Total Posts : 3145
    • Reward points : 0
    • Joined: 2016/12/07 14:20:36
    • Location: Wien
    • Status: offline
    Re: High Level I2C functions ? 2017/03/11 07:36:48 (permalink)
    0
    Mmmm, it's not so difficult to write your own Smile
    I think you can find a lot of similar code in this forum or from the source code of old PLIBs. Or, as I always repeat, adopt a bit-banged I2C solution Smile

    in 2018 you signed for your annihilation. in 2019 it will come ;) I promise
    my most wonderful creations here
    https://www.youtube.com/c...dPFRvtwsbSTXp6Sk6azGOQ
    #2
    Mysil
    Super Member
    • Total Posts : 3783
    • Reward points : 0
    • Joined: 2012/07/01 04:19:50
    • Location: Norway
    • Status: online
    Re: High Level I2C functions ? 2017/03/11 08:54:15 (permalink)
    0
    Hi,
    It actually is a bit difficult to do it in a way that work every time and all the time.
    I have used something like half a year on very similar things for PIC16, PIC18, PIC32MX and PIC32MM.
    I think I may have something for PIC24 within a week.
     
    As for now, I think the code generated by MCC may still be the best starting point.
    Even the code generated by MCC have several weak points, but if your program have nothing better to do, than waiting for I2C hardware to transfer data, and then wait for the EEPROM to complete it's internal write operation, it may work.
    The function made by MCC for this purpose is I2Cx_MasterWrite,
    the first part of the function name may be I2C_, I2C1_, I2C2_ or I2C3_
    depending upon the hardware and what settings you have done in MCC menu.
                /*
                 *   Function I2Cx_MasterWrite will send Start signal, Address and contents of WriteData array.
                 *
                 *   WriteData[] must be a static or global array,
                 *            holding the application's data until transfer is completed.
                 *   Size argument is number of Bytes to transfer.
                 *   Address argument is I2C address of slave device in 7 bit format,
                 *            without the R/W bit, range 8 thru 119 .
                 *     WriteStat must be a static or global variable, It will be updated with status of the transfer.
                 *   it should be declared with enumeration type: I2C_MESSAGE_STATUS WriteStat;
                 */
                I2C1_MasterWrite( WriteData,  Size, RLY08_ADDRESS, &WriteStat);
                if ((WriteStatR == I2C_ERROR_FAIL) ||( WriteStatR == I2C_ERROR_QUEUE_FULL))
                { ...

    Then the example code in header files created by MCC have room for improvement. 
    Firstly, writing one word at a time to I2C EEPROM memory, is stupid when there is an array to be transferred.
    It will both take more time than needed, and also cause more wear on EEPROM cells.
    Then real hardware EEPROM memory have the restriction that writing must be done only within one page at a time.
    This make need for a little arithmetic and testing on EEPROM address before writing.
     
    Don't be too put off by those functions generated by MCC that you will not need.
    Like all general purpose library code, there is always more functions available than those you will need to use.
     
    Since MCC copy code into a program source directory, instead of loading pre-compiled objects from a library archive file, it is just much more visible. Since these functions are present in project source, linker may create warnings about functions that are not called, assuming it is something you have made with the intention of using, but missed because of mistyping or other.
    You may safely ignore warnings about functions not called, or make into comments, or remove functions you do not need.
    If you have ever made program for PC of any kind, there is 1000 times more functions not needed.
     
    Regards,
       Mysil
    #3
    kelt
    Starting Member
    • Total Posts : 34
    • Reward points : 0
    • Joined: 2012/11/29 05:28:29
    • Location: France
    • Status: offline
    Re: High Level I2C functions ? 2017/03/11 11:43:46 (permalink)
    0
    CinziaG, Mysil,
     
    Many thanks for your answers.
    A major element in this project is TIME.
     
    Development time first : I don't have time to explore everything in I2C. A lot of work is to be done involving electronics, mechanics and everything must be ready by june. So, even if it is intellectually interesting to rewrite and optimize a driver, I do prefer using something already available.
     
    Execution time : I have to write to an EEPROM and to read from it very few bytes (100 ?) and this is not time critical. But sometimes I have to read a sensor on my I2C bus and in the same time I must cope with a high priority interruption coming every 10µs ! A lot of fun and again time to spend to debug this.
     
    Mysil, MCC seams to be the best way. It is a little bit frightening and I cannot understand every detail but the structuration is good and probably the best amongst all sorts of things I have found on the web. It is a good basis to start.
     
    I keep you inforrmed about my progress.
     
    Best regards
    Kelt
     
     
    #4
    CinziaG
    die fucking humans
    • Total Posts : 3145
    • Reward points : 0
    • Joined: 2016/12/07 14:20:36
    • Location: Wien
    • Status: offline
    Re: High Level I2C functions ? 2017/03/11 11:47:42 (permalink)
    0
    Ok!
    Even if your I2C task gets interrupted every 10uS, it won't be an issue since I2C is a synchronous protocol (and you're the master)

    in 2018 you signed for your annihilation. in 2019 it will come ;) I promise
    my most wonderful creations here
    https://www.youtube.com/c...dPFRvtwsbSTXp6Sk6azGOQ
    #5
    BobAGI
    Super Member
    • Total Posts : 1734
    • Reward points : 0
    • Joined: 2011/03/09 00:04:35
    • Location: Texas and Sweden
    • Status: offline
    Re: High Level I2C functions ? 2017/03/12 00:01:46 (permalink)
    4 (1)
    I struggled 2 weeks with read/write off of a EEPROM using I2C a numbers of years ago. Could not get the I2C subsystem working on the PI24 chip so I reverted to a bit-bang approach instead and got that working fine in less than a day. Bit-bang also has the advantage that it works on all kinds of hardware...
     
    Maybe these posts and threads can be of help regarding bit-banging I2C:
    I2C in master mode failed
    How to reset an EEPROM that hangs the I2C bus
    Bitbang I2C tutorial  This is where I got the base of my code
     
     
    Here is an image showing how my EEPROM is connected to the PIC24 using only 2 pins and 2 resistors:
     

     
    My code can be seen in this clip from my sourcefiles:

    // ************************************************************************************
    //  Acknowledgement:
    //  Code copied/modified from web tutorial:
    //  http://www.robot-electronics.co.uk/acatalog/I2C_Tutorial.html
    //
    //
    //  Example I2C Master Code
    //  This example shows how to implement a software I2C master, including clock stretching.
    //  It is written in C for the PIC processor, but should be applicable to most processors
    //  with minor changes to the I/O pin definitions.
    //  Since the SCL and SDA lines are open drain type, we use the tristate control register
    //  to control the output, keeping the output register low.
    //  The port pins still need to be read though, so they're defined as SCL_IN and SDA_IN.
    //  This definition and the initialization is probably all you'll need to change for a
    //  different processor.
    //  
    // ***********************************************************************************

    #define SCL     TRISFbits.TRISF5 // I2C clock
    #define SDA     TRISFbits.TRISF4 // I2C data
    #define SCL_IN  PORTFbits.RF5    //
    #define SDA_IN  PORTFbits.RF4    //
    #define SCL_OUT LATFbits.LATF5    //
    #define SDA_OUT LATFbits.LATF4    //

    // ***********************************************************************************
    //  To initialize the ports set the output latch to 0 and the tristate registers
    //  to 1 which disables the outputs and allows them to be pulled high by the resistors.
    // ***********************************************************************************
    void i2c_initbus(void)
    {
        SDA = 1;
        SCL = 1;
        SCL_OUT = 0;
        SDA_OUT = 0;
    }

    // ************************************************************************************
    //  i2c_dly() is a small delay routine between SDA and SCL changes to give
    //  a clear sequence on the I2C bus.
    //  Also used to create the clock frequency (two calls plus a few more instructions
    // ************************************************************************************
    void i2c_dly(void)
    {
        Delay_us(1);
    }

    // **************************************************************************************
    //  The following 4 functions provide the primitive start, stop, read and write sequences.
    //  All I2C transactions can be built up from these.
    // **************************************************************************************


    // **************************************************************************************
    //  i2c_start() generates the start condition (SDA high->low transition with SCL high
    //  This begins a master data transfer
    // **************************************************************************************
    void i2c_start(void)
    {
        // i2c start bit sequence
        SDA = 1;    //tristate data bus
        i2c_dly();
        SCL = 1;    //tristate clock to set it to 1
        i2c_dly();
        SDA = 0;    //set data low, indicates start condition with clock high
        i2c_dly();
        SCL = 0;     //set clock low
        i2c_dly();
    }

    // **************************************************************************************
    //  i2c_stop() generates the stop condition (SDA low->high transition with SCL high
    //  This ends a master data transfer and resets the bus
    // **************************************************************************************
    void i2c_stop(void)
    {
      i2c_dly();
      SDA = 0;             // i2c stop bit sequence
      i2c_dly();
      SCL = 1;
      i2c_dly();
      SDA = 1;
      i2c_dly();
    }

    // **************************************************************************************
    //  i2c_tx() sends one byte of data
    //  Returns the final ACK state from the device
    //  Used in all transfers of data to the external device.
    // **************************************************************************************
    char i2c_tx(unsigned char d)
    {
        char x;
        static char b;

        SCL = 0;
        for(x=8; x; x--)
        {
            if(d&0x80)
                SDA = 1;
            else
                SDA = 0;
            i2c_dly();
            SCL = 1;
            d <<= 1;
            i2c_dly();
            SCL = 0;
        }
        SDA = 1;
        i2c_dly();
        SCL = 1;
        i2c_dly();
        b = SDA_IN;          // Read ACK bit
        SCL = 0;
        return b;
    }

    // **************************************************************************************
    //  i2c_rx() receives one byte of data from the device while clocking the SCL line
    //  Argument ack determines if the function shall acknowledge reception to the device or not.
    //  Used in all transfers of data from the external device.
    // **************************************************************************************
    unsigned char i2c_rx(char ack)
    {
    char x, d=0;
      SDA = 1;    //Tristate data line
      SCL = 0;            // Clock low
      for(x=0; x<8; x++)
      {
        i2c_dly();
        d <<= 1;
        do
        {
          SCL = 1;    //Clock high
        }while(SCL_IN==0);    // wait for any SCL clock stretching
        i2c_dly();
        if(SDA_IN) d |= 1;
        SCL = 0;    //Clock low
      }
      if(ack) SDA = 0;    // Set ACK response
      else SDA = 1;        // Set NAK response
      i2c_dly();    //At least this low time
      SCL = 1;            // Clock high
      i2c_dly();        // send (N)ACK bit
      SCL = 0;            // Clock low
      SDA = 1;            // Tristate data line
      return d;
    }

    // ************** Added functionality by Bo Berglund ********************

    // ***********************************************************************************
    //  i2c_reset() is used to gain control of the bus if an attached device (EEPROM) has
    //  locked up with the SDA bus in a low level, thus pereventing the master from sending
    //  any commands.
    //  Function: send clock pulses (max 9) until SDA releases, then send a stop condition.
    // ***********************************************************************************
    void i2c_reset(void)
    {
        char i;

        SDA = 1;  //Tristate data bus giving it a 1 level
        for(i=0; i<9; i++)
        {
            SCL = 1;  //Tristate clock line making it a 1
            Delay(5);
            SCL = 0;  //Force clock line low
            Delay(5);
            if(SDA_IN) break;     //Check SDA line if EEPROM has released it it goes high
        }
        i2c_stop();     //Send stop condition
    }


    // **************************************************************************************
    //  i2c_writeblock() writes a block of data to the device while clocking the SCL line
    //  Arguments:
    //  device  = I2C slave device address, 0xA0 for EEPROM 24AA04
    //            also includes the page address in the low nibble
    //  address = Data address where written block will start
    //  length  = Number of bytes to write to device
    //  dataout = pointer to block of data to transfer
    //
    //  Returns: value of device ACK, if 1 then an error occurred and the data are not
    //           completely written
    //
    //  NOTES: address + length must not traverse EEPROM page borders!
    //         The length parameter must be within the of the EEPROM write buffer size
    //         It is up to the caller to check this before using this function!!!!
    //
    // **************************************************************************************
    char i2c_writeblock(unsigned char device, UINT address, UINT length, void *dataout)
    {
        unsigned char *data = dataout;
        char ack;

        i2c_start();
        i2c_tx(device & 0xFE);    //Device ID + page addr + write bit=0
        i2c_tx(address & 0xFF);   //Address in block
        while (length--)
        {
            ack = i2c_tx(*data++);
            if(ack) break;
        }
        i2c_stop();

        return ack; //Good return == 0
    }


    // **************************************************************************************
    //  i2c_readblock() writes a block of data to the device while clocking the SCL line
    //  Arguments:
    //  device  = I2C slave device address, 0xA0 for EEPROM 24AA04
    //  address = Data address where written block will start
    //  length  = Number of bytes to write to device
    //  datain  = pointer to destination of data to transfer
    //
    //  NOTE:  address + length must not traverse EEPROM page borders!
    //         It is up to the caller to check this before using this function!!!!
    //
    // **************************************************************************************
    char i2c_readblock(unsigned char device, UINT address, UINT length, void *datain)
    {
        unsigned char *data = datain;
        i2c_initbus();
        i2c_start();                    //Start condition
        i2c_tx(device & 0xFE);          //Device ID + block addr 0 + write bit
        i2c_tx(address & 0xFF);         //Address in block
        i2c_start();                    //Send restart condition
        i2c_tx(device | 0x01);          //Device ID + block addr 0 + read bit

        while (length-- > 1)
        {
            *data++ = i2c_rx(1);
        }
        *data = i2c_rx(0);              //No ACK on read of last byte

        i2c_stop();                     //Stop data transfer

        return 0;
    }


    // **************************************************************************************
    //  i2c_writeready() checks if the write cycle is ready by repeatedly checking if the
    //  device sends an acknowledge when writing the control command
    //
    //  Arguments:
    //  device  = I2C slave device address, 0xA0 for EEPROM 24AA04
    //  timeout = Timeout in us before exiting with error
    //
    //  Sequence:
    //    - Send Start condition
    //    - Send Control byte with R/W bit = 0
    //    - if ACK = 1 go back in loop
    //
    //  Each loop takes approximately 120 us. A suitable value could be 80 for a 10 ms timeout
    //  Returns: ACK final state, could be 1 if timeout.
    // **************************************************************************************

    char i2c_writeready(unsigned char device, UINT timeout)
    {
        char ack;

        timeout /= 200; //Loop time below assumed to be 200 us
        do
        {
            i2c_start();
            ack = i2c_tx(device);
            if (timeout-- == 0) break;
            Delay_us(100);
        } while(ack);

        return ack;
    }


    --
    Bo B
    Sweden & Texas
     
    #6
    Les
    Super Member
    • Total Posts : 244
    • Reward points : 0
    • Joined: 2011/02/23 04:27:28
    • Location: UK
    • Status: offline
    Re: High Level I2C functions ? 2017/03/12 03:40:11 (permalink)
    3 (1)
    This forum is a waste of time ! spent 30 min preparing a post and got 'Denied Access " !
     
    In brief  Pic 24 I2c does work ,,,, 
     

    char EE_read(unsigned int location) {
    char ee_loc_byte_low = (location & 0x00FF);
    char ee_loc_byte_hi = location >> 8;
    char EEdata = 0;
    I2C_start_W(EE_addr);
    I2C_sendB(ee_loc_byte_hi);
    I2C_sendB(ee_loc_byte_low);
    I2C_restart(EE_addr);
    I2C1CONbits.RCEN = 1;
    while (!I2C1STATbits.RBF);
    EEdata = I2C1RCV;
    I2C_NAK();
    I2C_endtx();
    I2C1CONbits.RCEN = 0;
    return EEdata;
    }
     

    post edited by Les - 2017/03/12 03:41:41
    #7
    kelt
    Starting Member
    • Total Posts : 34
    • Reward points : 0
    • Joined: 2012/11/29 05:28:29
    • Location: France
    • Status: offline
    Re: High Level I2C functions ? 2017/03/13 02:37:15 (permalink)
    4 (1)
    Hi Les,
     
    Looks fine, but where are these functions defined ?
     
    Kelt
    #8
    CinziaG
    die fucking humans
    • Total Posts : 3145
    • Reward points : 0
    • Joined: 2016/12/07 14:20:36
    • Location: Wien
    • Status: offline
    Re: High Level I2C functions ? 2017/03/13 02:44:01 (permalink)
    0
    kelt
    Hi Les,
     
    Looks fine, but where are these functions defined ?
     




    Same my question Smile

    in 2018 you signed for your annihilation. in 2019 it will come ;) I promise
    my most wonderful creations here
    https://www.youtube.com/c...dPFRvtwsbSTXp6Sk6azGOQ
    #9
    BobAGI
    Super Member
    • Total Posts : 1734
    • Reward points : 0
    • Joined: 2011/03/09 00:04:35
    • Location: Texas and Sweden
    • Status: offline
    Re: High Level I2C functions ? 2017/03/13 07:48:41 (permalink)
    3 (1)
    In my bitbang suggestion above you have:

    char i2c_writeblock(unsigned char device, UINT address, UINT length, void *dataout)
    and
    char i2c_readblock(unsigned char device, UINT address, UINT length, void *datain)

    That is all what is needed to write and read the EEPROM chip...

    --
    Bo B
    Sweden & Texas
     
    #10
    Les
    Super Member
    • Total Posts : 244
    • Reward points : 0
    • Joined: 2011/02/23 04:27:28
    • Location: UK
    • Status: offline
    Re: High Level I2C functions ? 2017/03/13 08:49:00 (permalink)
    4 (1)
    As previous , i had it all typed in and hit submit , only to get "denied" so lengthy post was LOST !!! .I am trying again but may be missing bits.  I am no way a programmer , I am what is commonly called a 'maker' , my C is c**p I know , but it works.....
    This is for a PIC24FV32KA302 

    void I2C_Init()
    {
    TRISBbits.TRISB9=0; // I2C data PIN 18
    TRISBbits.TRISB8=0; // I2C CLOCK PIN 17
    LATBbits.LATB8=1;
    LATBbits.LATB9=1;
    TRISBbits.TRISB9=1; // I2C data PIN 18
    TRISBbits.TRISB8=1; // I2C CLOCK PIN 17
    I2C1MSK = 0; // set this controller's device address
    I2C1CONbits.A10M = 0; // I2C1ADD is a 7-bit slave address
    I2C1CONbits.DISSLW = 1; // Disable slew - 0 for 400 kHz up enable slew rate
    I2C1CONbits.SMEN = 0; // No signal conditioning
    I2C1CONbits.GCEN = 0; // general call for slave mode only
    I2C1BRG = (16000 / (2 *100)) - 1 ; //
    I2C1CONbits.I2CEN = 1;// enable I2C module
    __delay_ms(1);
    }
     
    void I2C_start_W(char device_addr)
    {
    I2C1CONbits.SEN = 1; // Set start bit
    while(I2C1CONbits.SEN){} // and wait
    I2C1TRN = (device_addr << 1) & 0xFE; // send (slave + write bit )
    while (I2C1STATbits.TBF){} // wait I2C buffer
    I2C_ACK_stat(); // test ACK
    }

    void I2C_start_R(char device_addr)
    {
    I2C1CONbits.SEN = 1; // Set start bit
    while(I2C1CONbits.SEN){} //
    I2C1TRN = ((device_addr << 1 ) & 0xFE) | 0x01; // send (slave + read bit )
    while (I2C1STATbits.TBF) {} //
    I2C_ACK_stat();
    }
     
    void I2C_sendB(char data)
    {
    I2C1TRN = data; // send byte
    while (I2C1STATbits.TBF){}
    I2C_ACK_stat();
    }
     
    void I2C_ACK_stat()
    {
    while (I2C1STATbits.TRSTAT){} // I2c frame finished at 9th clock
    if(I2C1STATbits.ACKSTAT)
    {
    I2C1CONbits.PEN = 1; // Set stop bit
    }
    __delay_us(20);
    }
     
    void I2C_ERR()
    {
    Nop();
    while(1){}
    // watchdog will time out !
    }
    void I2C_restart(char device_addr)
    {
    I2C1CONbits.RSEN = 1; // Set start bit
    while(I2C1CONbits.RSEN) {}
    I2C1TRN = ((device_addr << 1 ) & 0xFE) | 0x01;//Send (slave + write bit )
    while (I2C1STATbits.TBF) {} //
    I2C_ACK_stat();
    }

    void I2C_sendS(char sdata[], char count)
    {
    int x = 0;
    for ( x = 0; x < count; x++)
    {
    I2C1TRN = sdata[x]; // send the data
    while (I2C1STATbits.TBF){}
    I2C_ACK_stat();

    }
    }
    void I2C_endtx()
    {
    I2C1CONbits.PEN = 1; // Set stop bit
    while(I2C1CONbits.PEN){}
    __delay_us(30);
    }
    void I2C_ACK(){
    I2C1CONbits.ACKDT = 0; // Acknowledge data bit, 0 = ACK
    I2C1CONbits.ACKEN = 1; // Ack data enabled
    while(I2C1CONbits.ACKEN); // wait for ack data to send on bus
    }
    void I2C_NAK(){
    I2C1CONbits.ACKDT = 1; // Acknowledge data bit, 1 = NAK
    I2C1CONbits.ACKEN = 1; // Ack data enabled
    while(I2C1CONbits.ACKEN); // wait for ack data to send on bus
    }

    #11
    jtor
    New Member
    • Total Posts : 11
    • Reward points : 0
    • Joined: 2016/08/23 06:11:58
    • Location: 0
    • Status: offline
    Re: High Level I2C functions ? 2017/03/13 10:01:11 (permalink)
    3 (1)
    I am usually against giving freebies away for homework or college related classes because I always got screwed staying up all hours of the night trying every single little thing possible.  Honestly, if you read the user manual on these things, it tells you everything you need to do to implement I2C but without code.
     
    This is for a PIC24F - These may be a little lower level than what you want, but you can use these to write your own functions that interface with your specific I2C device.  Your register identifiers/names might be different just as with the different flavors of PIC24F's.  Also, not all I2C devices interface the same and you'll need to consult your EEPROM datasheet for an example.  Most EEPROMs are really easy and just have a high byte address and lower byte address whereas others may have pages and that gets a little more difficult since you need to align the memory and keep track of where you are in address space.
     
    You're welcome :)
     
     
    void i2cInit(void )
    {
        //SDA & SDC lines must be configured as inputs
        TRISBbits.TRISB8 = 1;
        TRISBbits.TRISB9 = 1;
        LATBbits.LATB8 = 1;
        LATBbits.LATB9 = 1;

        //Enable SSPEN - Master Synchronous Serial Port Enable Bit
        SSP1CON1bits.SSPEN = 1;
        
        SSP1CON1bits.SSPM = 0x08; //Configure I2C Bus 1 as I2C Master Mode
        
        SSP1STATbits.SMP = 1; //Slew Rate control. 1 = disabled (1Mhz).
        SSP1STATbits.CKE = 0; //1=Enable SMBuss Specific inputs.
        
        SSP1CON3bits.SDAHT = 1;
       
        SSP1ADD = 0x27;
        SSP1MSK = 0;
    }

    void i2cWait( void )
    {
        while( (SSP1CON2 & 0x1F ) || ( SSP1STAT & 0x04 ) );
    }

    void i2cStart( void )
    {
        i2cWait();
     SSP1CON2bits.SEN = 1;
    }

    void i2cRestart( void )
    {
        i2cWait();
     SSP1CON2bits.RSEN = 1;
    }

    void i2cStop( void )
    {
        i2cWait();
        SSP1CON2bits.PEN = 1;
    }

    void i2cWrite( uint8_t data )
    {
        i2cWait();
        SSP1BUF = data;
    }

    void i2cAddress( uint8_t address, uint8_t mode )
    {
        uint8_t lAddress;

        lAddress = address << 1;
        lAddress += mode;
        i2cWait();
        SSP1BUF = lAddress;
    }

    uint8_t i2cRead( uint8_t ack )
    {
        uint8_t i2cReadData;

        i2cWait();
        SSP1CON2bits.RCEN = 1; //_RCEN=1;
        i2cWait();
        i2cReadData = SSP1BUF;
        i2cWait();
        if ( ack ) SSP1CON2bits.ACKDT = 0; //_ACKDT=0;
        else SSP1CON2bits.ACKDT = 1; //_ACKDT=1;
        SSP1CON2bits.ACKEN = 1; //_ACKEN=1;

        return( i2cReadData );
    }

    #12
    kelt
    Starting Member
    • Total Posts : 34
    • Reward points : 0
    • Joined: 2012/11/29 05:28:29
    • Location: France
    • Status: offline
    Re: High Level I2C functions ? 2017/03/13 10:46:53 (permalink)
    3 (1)
    Hi everybody,
     
    It's a pleasure to see all these contributions !
    Now the difficulty is to make a choice. 
     
    Frankly speaking I don't like bit-banged solutions. I have paid for all these PIC registers ! mr green: mr green. I want to use them !
    More seriously, packaged and/or integrated solutions are supposed to be validated and therefore offer less opportunities to flaws for the user. I am not saying that other solutions cannnot work, of course. Just a matter of feeling and experience. (Sorry, no smiley with a long white beard...).
     
    MCC provides such a kind of thing but I cannot easily read this kind of C. Too subtil for me.
    So I have chosen to start with the library as proposed by Microchip.
    It is a little bit cryptic due to some useless macros which do not bring a real added value, but once replaced by more conventional code, it looks much better and comprehensive.
     
    It's beginning to work now.
    However SCL looks very strange (quite few transitions) with my logic analyser. 
    I need to go more deeply into the problem. I keep you informed. 
     
    Best regards
     
    Kelt.
     
    #13
    Gort2015
    Klaatu Barada Nikto
    • Total Posts : 4003
    • Reward points : 0
    • Joined: 2015/04/30 10:49:57
    • Location: 0
    • Status: offline
    Re: High Level I2C functions ? 2017/03/14 06:47:30 (permalink)
    0
    Download the ref.
    The code is very small.
     
    .include "xc.inc"
    .global _writeI2C
    .section i2c_code,code
    ;----------------------------------------------------
    .equ arg_Data,  w0

    _writeI2C:  ;void WriteI2C(ubyte Data)
        push    arg_Data
    busy:
        mov     #0x1f,w0
        and     I2C1CON,wreg
        bra     nz,busy
        pop     I2C1TRN
        ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    wait_transmit:
        btsc    I2C1STAT,#TRSTAT
        bra     wait_transmit
        return
    ;----------------------------------------------------
    .end
    That's all she wrote.
    #14
    kelt
    Starting Member
    • Total Posts : 34
    • Reward points : 0
    • Joined: 2012/11/29 05:28:29
    • Location: France
    • Status: offline
    Re: High Level I2C functions ? 2017/03/17 08:04:15 (permalink)
    3 (1)
    Well,
    I have to admit that official products also have their flaws and are not so reliable as they should.
    One could think that the Micrcohip Library functions would work without any problem on PIC 24F.
    At least in my case this is not the case.
     
    I have spent several days trying to correctly read my EEPROM (24AA08) with my PIC (24FJ64GA102). 
    I found the same problems as several members : Only FFh received from the EEPROM, no STOP condition at the end of readings and hardware reset necessary to unlock the situation.
    The Mastergets function is certainly the keypoint, but I have no more time to dig there and see exactly what happens.
     
    So, no way with the library. I surrender mad: mad.
    BobAGI has a very attractive solution. I am going to try it.
     
    Best regards
     
    Kelt
    #15
    BobAGI
    Super Member
    • Total Posts : 1734
    • Reward points : 0
    • Joined: 2011/03/09 00:04:35
    • Location: Texas and Sweden
    • Status: offline
    Re: High Level I2C functions ? 2017/03/17 08:46:55 (permalink)
    4 (1)
    I did not write it here before, but the reason I went with bit-bang I2C is that I spent over a week trying to get the peripheral Libraries to work. It really looked like the I2C subsystem had some silicon error inside my part (PIC24FJ256GB206).
    Then when I had gotten the link to the bit-bang page I showed above I had it working in about a day or so.
    Notice that I have used a Delay_us() function of my own, which is actually not very accurate for short delays.
     
    There exists a compiler built-in delay function that could probably be used instead:
    __delay_us(1);
    It requires that the include statements on top of the file contains this (for the C30 compiler):
    #include <libpic30.h>
     
    I have not checked this yet, only saw it a few days ago.
    But it does compile at least.
     

    --
    Bo B
    Sweden & Texas
     
    #16
    kelt
    Starting Member
    • Total Posts : 34
    • Reward points : 0
    • Joined: 2012/11/29 05:28:29
    • Location: France
    • Status: offline
    Re: High Level I2C functions ? 2017/03/18 06:36:46 (permalink)
    3 (1)
    It works !
    Many thanks to everybody and to BobAGI.
     
    It took a few minutes to install. As suggested I have replaced the delay function by the official one from the library.
    I had to define my working frequency at the top of the I2C module by :
     
    #define FCY 16000000UL
    in my case for 16 MHz.
     
    I am now going to setup my SPI channel. I hope it will be less difficult but, normally it is simpler.
     
    Kelt.
     
     
    #17
    BobAGI
    Super Member
    • Total Posts : 1734
    • Reward points : 0
    • Joined: 2011/03/09 00:04:35
    • Location: Texas and Sweden
    • Status: offline
    Re: High Level I2C functions ? 2017/03/18 06:47:58 (permalink)
    0
    LoL: LoLLoL: LoL

    --
    Bo B
    Sweden & Texas
     
    #18
    kelt
    Starting Member
    • Total Posts : 34
    • Reward points : 0
    • Joined: 2012/11/29 05:28:29
    • Location: France
    • Status: offline
    Re: High Level I2C functions ? 2017/03/19 09:10:18 (permalink)
    0
    I have done some frequency measurements under the following conditions :
     
    - FCY = 16 MHz
    - and the delay function made by __delay_us(1) or __delay32(12) (same thing)
     
    The obtained SCL frequency is 285 kHz. 
     
    I don't know if it fits with my application. I need to go further with my development to see.
     
    When replacing __delay_us(1) by Nop() one reach 500 kHz for SCL but I suspect some read/write errors.
    To be examined more precisely if a higher frequency is needed.
     
    Kelt
     
    #19
    BobAGI
    Super Member
    • Total Posts : 1734
    • Reward points : 0
    • Joined: 2011/03/09 00:04:35
    • Location: Texas and Sweden
    • Status: offline
    Re: High Level I2C functions ? 2017/03/19 12:27:59 (permalink)
    0
    Thanks for sharing measurements. I have not used the built-in delay macro earlier and now I don't have the hardware to test it on for a few days.

    --
    Bo B
    Sweden & Texas
     
    #20
    Jump to:
    © 2020 APG vNext Commercial Version 4.5