Hot!PIC Interface with MCP3425

Page: 123 > Showing page 1 of 3
Author
ajitnayak87
Super Member
  • Total Posts : 184
  • Reward points : 0
  • Joined: 2017/06/20 03:53:02
  • Location: 0
  • Status: offline
2018/04/09 21:24:45 (permalink)
0

PIC Interface with MCP3425

Dear all,
I am trying to establish code on temperature detection. I have used MCP3425 for interface.
Intially i have developed on PIC16F886 platform which comes up with I2c Library and Could able to read temperature data properly. Now i am transferring  code to PIC18F24K40 which wont comes up with I2C library.
PIC16F886 code for Read I2c data Here i can read data properly.
 
I have Temperature calibrator where i could able to give temprature Input. For PIC16F886 there is no issue i can provide temperature input 100,10,1,0.1 degree & it will vary accordingly. If same  input is given for PIC18F24k40
100 degree will work properly
10 degree applied  twice then find change in output value.
1 degree/.1 degree applied wont work at all.
Where as for PIC16F886 it work Properly.
 
 
 
 
post edited by ajitnayak87 - 2018/04/15 23:34:46
#1

44 Replies Related Threads

    JorgeF
    Super Member
    • Total Posts : 3281
    • Reward points : 0
    • Joined: 2011/07/09 11:56:58
    • Location: PT/EU @ Third rock from the Sun
    • Status: offline
    Re: PIC Interface with MCP3425 2018/04/10 01:57:48 (permalink)
    0
    Hi
     
    What library(ies) are you refering to?
     
     
     
    Best regards
    Jorge
     
    #2
    ajitnayak87
    Super Member
    • Total Posts : 184
    • Reward points : 0
    • Joined: 2017/06/20 03:53:02
    • Location: 0
    • Status: offline
    Re: PIC Interface with MCP3425 2018/04/10 02:22:01 (permalink)
    0
    This is problem i am facing,
    When i Config through MCC , MSSP part The controller start detecting input from Calibrator.But its not taking actual code background it running MCC generated I2c Slave library function in Interrupt.I have attached the code from MSSP i2c generated from MCC code configuration. MSSP i2c function bit complicated & difficult read value when trying to read data from slave. because of which i m not getting any response. I checked & confirm using logical analyzer 
     
    If i config directly without using MSSP, like we doing in PIC16F886 like i done in below code I2C start & stop Bits itself Not generating.
    any code for I2c configure that can be tested without MSSP c files.
     
     
    post edited by ajitnayak87 - 2018/04/15 23:35:36
    #3
    JorgeF
    Super Member
    • Total Posts : 3281
    • Reward points : 0
    • Joined: 2011/07/09 11:56:58
    • Location: PT/EU @ Third rock from the Sun
    • Status: offline
    Re: PIC Interface with MCP3425 2018/04/10 02:46:16 (permalink)
    0
    Hi
     
    This I2C1_ISR code seems to be for the PIC operating as a slave, but the datasheet for the MCP3425 states that it operates as slave only, so the PIC should operate as a I2C master.
     
    Best regards
    Jorge
     
    #4
    ajitnayak87
    Super Member
    • Total Posts : 184
    • Reward points : 0
    • Joined: 2017/06/20 03:53:02
    • Location: 0
    • Status: offline
    Re: PIC Interface with MCP3425 2018/04/10 04:12:12 (permalink)
    0
    i HAVE TRIED ALREADY. In MSSP , i config as slave mode only. But due to MCC generated i could not able to use it.
    IF i Make PIC as Master and use same code it wont Work. If i Use PiC as slave it start creating some waveform.
     
    Thats reason i am trying code without MCC. where i am trying to generated Start & stop pulse first. If its Generated its easy to write code further. But Without MCC i dont know why its not Generating start pulse itself.
     
    Is there any example code avialble for I2C without MSSP . so i can generate Start & stop waveform.
    post edited by ajitnayak87 - 2018/04/10 04:13:51
    #5
    JorgeF
    Super Member
    • Total Posts : 3281
    • Reward points : 0
    • Joined: 2011/07/09 11:56:58
    • Location: PT/EU @ Third rock from the Sun
    • Status: offline
    Re: PIC Interface with MCP3425 2018/04/10 04:21:55 (permalink)
    0
    Hi
     
    I don't have any sample code on I2C but in the Microchipp site, under "Design Support / Documentation" and "design support / training" you can find a number of resources that may be of help, like application notes and sample code.
     
     EDIT ADD:
    In the MCHP page for the PIC18F24K40 in the documentation section you can find AN2045 that deals with SPI and I2C interfacing. It refers an EEPROM as the slave device but the I2C protocol is the same, only the payload contents (commands/data) are different.
     
     
    Best regards
    Jorge
     
    post edited by JorgeF - 2018/04/10 04:26:33
    #6
    JorgeF
    Super Member
    • Total Posts : 3281
    • Reward points : 0
    • Joined: 2011/07/09 11:56:58
    • Location: PT/EU @ Third rock from the Sun
    • Status: offline
    Re: PIC Interface with MCP3425 2018/04/10 04:30:09 (permalink)
    0
    Hi
    ajitnayak87
    i HAVE TRIED ALREADY. In MSSP , i config as slave mode only. But due to MCC generated i could not able to use it.
    IF i Make PIC as Master and use same code it wont Work. If i Use PiC as slave it start creating some waveform.

    The code you posted seems to be a mix.
    Althought the structure of the ISR seems to be for a slave, the initialization sets the MSSP as a master (MODE = 0b1000).
    I don't know what happened but would chack again with soem new project just for checking that MCC is doing the write thing.
     
     
    Best reagrds
    Jorge
     
    #7
    ajitnayak87
    Super Member
    • Total Posts : 184
    • Reward points : 0
    • Joined: 2017/06/20 03:53:02
    • Location: 0
    • Status: offline
    Re: PIC Interface with MCP3425 2018/04/12 22:34:34 (permalink)
    0
    I have posted my code as below.
    The code written on pic18F24k40 without MCC. with below code I found SDA & SCL line wont goes high. I have gone through video shared by microchip on I2c for mplabX ide. according to video if device not config properly it wont generated SDA & SCL pulse.
     
    I have tested code with PIC16F886 where same syntax i used and it worked properly.
    If i use MSSP based MCC generated Master /Slave mode It start generating clock pulse. But i found difficulty in  changing or modification in code. Even i set device ID D0 it wont take it take default 0X68.
     
    Kindly let me know any suggestiion
    post edited by ajitnayak87 - 2018/04/15 23:36:04
    #8
    qɥb
    Monolothic Member
    • Total Posts : 3329
    • Reward points : 0
    • Joined: 2017/09/09 05:07:30
    • Location: Jupiter
    • Status: offline
    Re: PIC Interface with MCP3425 2018/04/12 22:47:05 (permalink)
    0
    ajitnayak87
    I have posted my code as below.
    The code written on pic18F24k40 without MCC.

    Then why is it including "mcc_generated_files/mcc.h" ?
     
    Where are your CONFIG settings?
     
    Is the PIC running at all? Have you tried flashing an LED at the same time?
     

    This forum is mis-configured so it only works correctly if you access it via https protocol.
    The Microchip website links to it using http protocol. Will they ever catch on?
    PicForum "it just works"
    #9
    ajitnayak87
    Super Member
    • Total Posts : 184
    • Reward points : 0
    • Joined: 2017/06/20 03:53:02
    • Location: 0
    • Status: offline
    Re: PIC Interface with MCP3425 2018/04/13 00:00:32 (permalink)
    0
    The basic config setting done through MCC. MSSP setting i am not config through MCC which widely used for I2c Intilization. yes PIC is running.
    Display_Single() function work well what ever data send in timer interrupt for 1ms it keep displaying. please let me know if u any other setting data to be posted.  
    When i config directly SDA &SCL line remain HIGH 
     
    post edited by ajitnayak87 - 2018/04/13 00:06:15

    Attached Image(s)

    #10
    ajitnayak87
    Super Member
    • Total Posts : 184
    • Reward points : 0
    • Joined: 2017/06/20 03:53:02
    • Location: 0
    • Status: offline
    Re: PIC Interface with MCP3425 2018/04/13 01:34:07 (permalink)
    0
    I need atleast for my code it should generate clock pulse and Data start & stop bit its easy to write further code. But i cant able to generate either clock pulse or start & stop Bit. SCL & SDA line can change based on setting in different mode.  
    #11
    qɥb
    Monolothic Member
    • Total Posts : 3329
    • Reward points : 0
    • Joined: 2017/09/09 05:07:30
    • Location: Jupiter
    • Status: offline
    Re: PIC Interface with MCP3425 2018/04/13 01:40:27 (permalink)
    0
    I think you're making this much harder than it needs to be.
    The PIC118F code you posted "bit bangs" the I2C interface by toggling LAT pins high and low.
    There's nothing stopping you doing exactly the same thing in the PIC16F886, but you have to use PORT pins as that chip doesn't have LAT registers.
    Just make sure you switch the pins to digital mode if you select pins that are analog capable.
     
    (Why are you using such an ancient chip as a PIC16F886 anyway? A PIC16F1xxxx chip could be pin compatible, and would have LAT registers.).
     
    Edit: oops, this was meant to be in response to a different thread. Please ignore.
    post edited by qɥb - 2018/04/13 03:01:45

    This forum is mis-configured so it only works correctly if you access it via https protocol.
    The Microchip website links to it using http protocol. Will they ever catch on?
    PicForum "it just works"
    #12
    ajitnayak87
    Super Member
    • Total Posts : 184
    • Reward points : 0
    • Joined: 2017/06/20 03:53:02
    • Location: 0
    • Status: offline
    Re: PIC Interface with MCP3425 2018/04/13 02:07:33 (permalink)
    0
    I could not able to get what trying to convey. 
    Just make sure you switch the pins to digital mode if you select pins that are analog capable.
     
    I have selected RC3 & RC4 pin as analog instead of digital .Disable as digital out.  Can you check and confirm MCC generated  properly or not
     
    TRISA = 0x18;
    TRISB = 0x00;
    TRISC = 0x3C;
     
    LATA = 0x00;
    LATB = 0x00;
    LATC = 0x00;
     
    ANSELC = 0x00;
    ANSELB = 0x00;
    ANSELA = 0x00;
     
     
     I need basic setting for I2c to generate Clock ,start & stop Bit. If i gone through example of I2c in google . major setting will be done
     
    SSP1STAT
    SSP1CON1
    SSPADD
     and straight away using i2c _start() & other function for programming. But i dont know how it work in  MCC genrated file . Please confirm me i2c setting so atleast i can generate clock,start,stop bit to proceed with coding
     
    #13
    ajitnayak87
    Super Member
    • Total Posts : 184
    • Reward points : 0
    • Joined: 2017/06/20 03:53:02
    • Location: 0
    • Status: offline
    Re: PIC Interface with MCP3425 2018/04/13 04:25:00 (permalink)
    0
     
    I could not able to make any difference . I have tried below line in my code There is no clock pulse generation.
     
     
     
    If  i am using MSSP based i2c master PIN config setting look like below
     

    void PIN_MANAGER_Initialize(void)
    {
        /**
        LATx registers
        */
        LATA = 0x00;
        LATB = 0x00;
        LATC = 0x00;

        /**
        TRISx registers
        */
        TRISA = 0x18;
        TRISB = 0x00;
        TRISC = 0x3C;

        /**
        ANSELx registers
        */
        ANSELC = 0x00;
        ANSELB = 0x00;
        ANSELA = 0x00;

        /**
        WPUx registers
        */
        WPUE = 0x00;
        WPUB = 0x00;
        WPUA = 0x00;
        WPUC = 0x00;

        /**
        ODx registers
        */
        ODCONA = 0x00;
        ODCONB = 0x00;
        ODCONC = 0x00;
        
        
        bool state = (unsigned char)GIE;
        GIE = 0;
        PPSLOCK = 0x55;
        PPSLOCK = 0xAA;
        PPSLOCKbits.PPSLOCKED = 0x00; // unlock PPS

        SSP1CLKPPSbits.SSP1CLKPPS = 0x13; //RC3->MSSP1:SCL1;
        SSP1DATPPSbits.SSP1DATPPS = 0x14; //RC4->MSSP1:SDA1;
        RC3PPS = 0x0D; //RC3->MSSP1:SCL1;
        RC4PPS = 0x0E; //RC4->MSSP1:SDA1;

        PPSLOCK = 0x55;
        PPSLOCK = 0xAA;
        PPSLOCKbits.PPSLOCKED = 0x01; // lock PPS

        GIE = state;
      
        
    }

     
    If  i am using  without mssp & use MCC generated file  pin manager look like this
     
    void PIN_MANAGER_Initialize(void)
    {
        /**
        LATx registers
        */
        LATA = 0x00;
        LATB = 0x00;
        LATC = 0x00;

        /**
        TRISx registers
        */
        TRISA = 0x18;
        TRISB = 0x00;
        TRISC = 0x3C;

        /**
        ANSELx registers
        */
        ANSELC = 0x00;
        ANSELB = 0x00;
        ANSELA = 0x00;

        /**
        WPUx registers
        */
        WPUE = 0x00;
        WPUB = 0x00;
        WPUA = 0x00;
        WPUC = 0x00;

        /**
        ODx registers
        */
        ODCONA = 0x00;
        ODCONB = 0x00;
        ODCONC = 0x00;

    }

    #14
    ajitnayak87
    Super Member
    • Total Posts : 184
    • Reward points : 0
    • Joined: 2017/06/20 03:53:02
    • Location: 0
    • Status: offline
    Re: PIC Interface with MCP3425 2018/04/13 04:27:03 (permalink)
    0
    qɥb
    I think you're making this much harder than it needs to be.
    The PIC118F code you posted "bit bangs" the I2C interface by toggling LAT pins high and low.
    There's nothing stopping you doing exactly the same thing in the PIC16F886, but you have to use PORT pins as that chip doesn't have LAT registers.
    Just make sure you switch the pins to digital mode if you select pins that are analog capable.
     
    (Why are you using such an ancient chip as a PIC16F886 anyway? A PIC16F1xxxx chip could be pin compatible, and would have LAT registers.).
     
    Edit: oops, this was meant to be in response to a different thread. Please ignore.




    Guide basic level i2c initialization w.r.t MPLAB xc8 platform. 
    #15
    JorgeF
    Super Member
    • Total Posts : 3281
    • Reward points : 0
    • Joined: 2011/07/09 11:56:58
    • Location: PT/EU @ Third rock from the Sun
    • Status: offline
    Re: PIC Interface with MCP3425 2018/04/13 07:49:59 (permalink)
    0
    Hi
     
    Looking at the code samples you posted, to use the MSSP periopheral you need to route the SCL and SDA signals via PPS to the intended pins for those signals.
     
    I created an empty project using MCC and the generated code seems OK.
    After the configurations you should be able to comunicate via I2C using the primitives defined in "i2c_driver.c" and declared in "i2c_driver.h".
     
    For a master mode you should be able to operate the MSSP using the following functions:

    /* I2C interfaces */
    bit i2c1_driver_open(void);
    INLINE char i2c1_driver_getRXData(void);
    INLINE char i2c1_driver_getAddr(void);
    INLINE void i2c1_driver_setAddr(char addr);
    INLINE void i2c1_driver_setMask(char mask);
    INLINE void i2c1_driver_TXData(char d);
    INLINE void i2c1_driver_resetBus(void);
    INLINE void i2c1_driver_start(void);
    INLINE void i2c1_driver_restart(void);
    INLINE void i2c1_driver_stop(void);
    INLINE bit i2c1_driver_isNACK(void);
    INLINE void i2c1_driver_startRX(void);
    INLINE void i2c1_driver_sendACK(void);
    INLINE void i2c1_driver_sendNACK(void);
    INLINE void i2c1_driver_clearBusCollision(void);

    Initialize master mode with "i2c1_driver_open()" and then use the remaining functions to operate the communications and check for status, respecting the protocol rules.
     
    This might help http://www.ti.com/lit/an/slva704/slva704.pdf
    See the sequence of operations for writing to a slave and reading from it (sections 3.1 and 3.2 @ page 7).
    Look at figures 8 and 9 and try to implement the sequence of operations using the functions above.
     
    HIH
     
    Best regards
    Jorge
     
    #16
    ajitnayak87
    Super Member
    • Total Posts : 184
    • Reward points : 0
    • Joined: 2017/06/20 03:53:02
    • Location: 0
    • Status: offline
    Re: PIC Interface with MCP3425 2018/04/13 08:49:02 (permalink)
    0
    can you share me the MCC generated file config for MSSP as master MCP3425 as slave ,with driver pack. since it mentioned it will work so i can tryout directly above. I tried above thing but it give errors
    I am using PIC18F24k40 with mplab4.01 Xc8
    kindly share zip file to ajit.track@gmail.com
     
    #17
    JorgeF
    Super Member
    • Total Posts : 3281
    • Reward points : 0
    • Joined: 2011/07/09 11:56:58
    • Location: PT/EU @ Third rock from the Sun
    • Status: offline
    Re: PIC Interface with MCP3425 2018/04/13 09:57:25 (permalink)
    0
    Hi
    ajitnayak87
    .....MCP3425 as slave....

    To set up the master you don't need to know the slave as it doesn't matter. Slave protocol only needs to be known when you write the code to comunicate with it.
     
    The code generated by "mcc" is in the attached zip file.
     
    You have to look at the I2C bus specification and in your code use the sequence of operations like the ones described in http://i2c.info/i2c-bus-specification
     
    HIH
     
    Best regards
    Jorge
     
    #18
    JorgeF
    Super Member
    • Total Posts : 3281
    • Reward points : 0
    • Joined: 2011/07/09 11:56:58
    • Location: PT/EU @ Third rock from the Sun
    • Status: offline
    Re: PIC Interface with MCP3425 2018/04/13 14:17:16 (permalink)
    0
    Hi
     
    By the way, the I2C clock is only generated during communication activity and only the necessary cycles, you won't be able to "see" it if there is no communication in progress.
    Also note that the clock may be freezed by the slave (clock stretching) if it needs extra time to react to the commands/data sent or requested by the master.
     
    HIH
     
    Best regards
    Jorge
     
    PS: Don't forget the pull-up resistors on the communication lines.
    #19
    ajitnayak87
    Super Member
    • Total Posts : 184
    • Reward points : 0
    • Joined: 2017/06/20 03:53:02
    • Location: 0
    • Status: offline
    Re: PIC Interface with MCP3425 2018/04/13 17:57:32 (permalink)
    0
    Thanks for zip file. Because  when i generated MCC  master MSSP below i2c driver its generating
    i try to directly or try to compile directly give update.
    let me which version of mplab using so i can download, which can create same driver files
     
     

    /**
      I2C1 Generated Driver File

      @Company
        Microchip Technology Inc.

      @File Name
        i2c1.c

      @Summary
        This is the generated header file for the I2C1 driver using PIC10 / PIC12 / PIC16 / PIC18 MCUs

      @Description
        This header file provides APIs for driver for I2C1.
        Generation Information :
            Product Revision  :  PIC10 / PIC12 / PIC16 / PIC18 MCUs  - 1.45
            Device            :  PIC18F24K40
            Driver Version    :  2.00
        The generated drivers are tested against the following:
            Compiler          :  XC8 1.35
            MPLAB               :  MPLAB X 3.40
    */

    /*
        (c) 2016 Microchip Technology Inc. and its subsidiaries. You may use this
        software and any derivatives exclusively with Microchip products.

        THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, WHETHER
        EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, INCLUDING ANY IMPLIED
        WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS FOR A
        PARTICULAR PURPOSE, OR ITS INTERACTION WITH MICROCHIP PRODUCTS, COMBINATION
        WITH ANY OTHER PRODUCTS, OR USE IN ANY APPLICATION.

        IN NO EVENT WILL MICROCHIP BE LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE,
        INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND
        WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS
        BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE
        FULLEST EXTENT ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN
        ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,
        THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.

        MICROCHIP PROVIDES THIS SOFTWARE CONDITIONALLY UPON YOUR ACCEPTANCE OF THESE
        TERMS.
    */

    /**
      Section: Included Files
    */

    #include "i2c1.h"

    /**
      I2C Driver Queue Status Type

      @Summary
        Defines the type used for the transaction queue status.

      @Description
        This defines type used to keep track of the queue status.
     */

    typedef union
    {
        struct
        {
                uint8_t full:1;
                uint8_t empty:1;
                uint8_t reserved:6;
        }s;
        uint8_t status;
    }I2C_TR_QUEUE_STATUS;

    /**
      I2C Driver Queue Entry Type

      @Summary
        Defines the object used for an entry in the i2c queue items.

      @Description
        This defines the object in the i2c queue. Each entry is a composed
        of a list of TRBs, the number of the TRBs and the status of the
        currently processed TRB.
     */
    typedef struct
    {
        uint8_t                             count;          // a count of trb's in the trb list
        I2C1_TRANSACTION_REQUEST_BLOCK *ptrb_list;     // pointer to the trb list
        I2C1_MESSAGE_STATUS            *pTrFlag;       // set with the error of the last trb sent.
                                                            // if all trb's are sent successfully,
                                                            // then this is I2C1_MESSAGE_COMPLETE
    } I2C_TR_QUEUE_ENTRY;

    /**
      I2C Master Driver Object Type

      @Summary
        Defines the object that manages the i2c master.

      @Description
        This defines the object that manages the sending and receiving of
        i2c master transactions.
      */

    typedef struct
    {
        /* Read/Write Queue */
        I2C_TR_QUEUE_ENTRY          *pTrTail;       // tail of the queue
        I2C_TR_QUEUE_ENTRY          *pTrHead;       // head of the queue
        I2C_TR_QUEUE_STATUS         trStatus;       // status of the last transaction
        uint8_t                         i2cDoneFlag;    // flag to indicate the current
                                                        // transaction is done
        uint8_t                         i2cErrors;      // keeps track of errors


    } I2C_OBJECT ;

    /**
      I2C Master Driver State Enumeration

      @Summary
        Defines the different states of the i2c master.

      @Description
        This defines the different states that the i2c master
        used to process transactions on the i2c bus.
    */

    typedef enum
    {
        S_MASTER_IDLE,
        S_MASTER_RESTART,
        S_MASTER_SEND_ADDR,
        S_MASTER_SEND_DATA,
        S_MASTER_SEND_STOP,
        S_MASTER_ACK_ADDR,
        S_MASTER_RCV_DATA,
        S_MASTER_RCV_STOP,
        S_MASTER_ACK_RCV_DATA,
        S_MASTER_NOACK_STOP,
        S_MASTER_SEND_ADDR_10BIT_LSB,
        S_MASTER_10BIT_RESTART,
        
    } I2C_MASTER_STATES;

    /**
     Section: Macro Definitions
    */

    /* defined for I2C1 */

    #ifndef I2C1_CONFIG_TR_QUEUE_LENGTH
            #define I2C1_CONFIG_TR_QUEUE_LENGTH 1
    #endif

    #define I2C1_TRANSMIT_REG                       SSP1BUF                 // Defines the transmit register used to send data.
    #define I2C1_RECEIVE_REG                        SSP1BUF                 // Defines the receive register used to receive data.

    // The following control bits are used in the I2C state machine to manage
    // the I2C module and determine next states.
    #define I2C1_WRITE_COLLISION_STATUS_BIT         SSP1CON1bits.WCOL     // Defines the write collision status bit.
    #define I2C1_MODE_SELECT_BITS                   SSP1CON1bits.SSPM     // I2C Master Mode control bit.
    #define I2C1_MASTER_ENABLE_CONTROL_BITS         SSP1CON1bits.SSPEN    // I2C port enable control bit.

    #define I2C1_START_CONDITION_ENABLE_BIT         SSP1CON2bits.SEN      // I2C START control bit.
    #define I2C1_REPEAT_START_CONDITION_ENABLE_BIT  SSP1CON2bits.RSEN     // I2C Repeated START control bit.
    #define I2C1_RECEIVE_ENABLE_BIT                 SSP1CON2bits.RCEN     // I2C Receive enable control bit.
    #define I2C1_STOP_CONDITION_ENABLE_BIT          SSP1CON2bits.PEN      // I2C STOP control bit.
    #define I2C1_ACKNOWLEDGE_ENABLE_BIT             SSP1CON2bits.ACKEN    // I2C ACK start control bit.
    #define I2C1_ACKNOWLEDGE_DATA_BIT               SSP1CON2bits.ACKDT    // I2C ACK data control bit.
    #define I2C1_ACKNOWLEDGE_STATUS_BIT             SSP1CON2bits.ACKSTAT  // I2C ACK status bit.

    #define I2C1_7bit    true
    /**
     Section: Local Functions
    */

    void I2C1_FunctionComplete(void);
    void I2C1_Stop(I2C1_MESSAGE_STATUS completion_code);

    /**
     Section: Local Variables
    */

    static I2C_TR_QUEUE_ENTRY                  i2c1_tr_queue[I2C1_CONFIG_TR_QUEUE_LENGTH];
    static I2C_OBJECT                          i2c1_object;
    static I2C_MASTER_STATES                   i2c1_state = S_MASTER_IDLE;
    static uint8_t                                 i2c1_trb_count = 0;

    static I2C1_TRANSACTION_REQUEST_BLOCK       *p_i2c1_trb_current = NULL;
    static I2C_TR_QUEUE_ENTRY                  *p_i2c1_current = NULL;


    /**
      Section: Driver Interface
    */


    void I2C1_Initialize(void)
    {
        i2c1_object.pTrHead = i2c1_tr_queue;
        i2c1_object.pTrTail = i2c1_tr_queue;
        i2c1_object.trStatus.s.empty = true;
        i2c1_object.trStatus.s.full = false;

        i2c1_object.i2cErrors = 0;

        // SMP High Speed; CKE enabled;
        SSP1STAT = 0x40;
        // SSPEN enabled; CKP Idle:Low, Active:High; SSPM FOSC/4_SSPxADD_I2C;
        SSP1CON1 = 0x28;
        // SBCDE disabled; BOEN disabled; SCIE disabled; PCIE disabled; DHEN disabled; SDAHT 100ns; AHEN disabled;
        SSP1CON3 = 0x00;
        // Baud Rate Generator Value: SSPADD 19;   
        SSP1ADD = 0x13;

       
        // clear the master interrupt flag
        PIR3bits.SSP1IF = 0;
        // enable the master interrupt
        PIE3bits.SSP1IE = 1;
        
    }

            
    uint8_t I2C1_ErrorCountGet(void)
    {
        uint8_t ret;

        ret = i2c1_object.i2cErrors;
        return ret;
    }

    void I2C1_ISR ( void )
    {
     
        static uint8_t  *pi2c_buf_ptr;
        static uint16_t i2c_address         = 0;
        static uint8_t  i2c_bytes_left      = 0;
        static uint8_t  i2c_10bit_address_restart = 0;

        PIR3bits.SSP1IF = 0;

        // Check first if there was a collision.
        // If we have a Write Collision, reset and go to idle state */
        if(I2C1_WRITE_COLLISION_STATUS_BIT)
        {
            // clear the Write colision
            I2C1_WRITE_COLLISION_STATUS_BIT = 0;
            i2c1_state = S_MASTER_IDLE;
            *(p_i2c1_current->pTrFlag) = I2C1_MESSAGE_FAIL;

            // reset the buffer pointer
            p_i2c1_current = NULL;

            return;
        }

        /* Handle the correct i2c state */
        switch(i2c1_state)
        {
            case S_MASTER_IDLE:    /* In reset state, waiting for data to send */

                if(i2c1_object.trStatus.s.empty != true)
                {
                    // grab the item pointed by the head
                    p_i2c1_current     = i2c1_object.pTrHead;
                    i2c1_trb_count     = i2c1_object.pTrHead->count;
                    p_i2c1_trb_current = i2c1_object.pTrHead->ptrb_list;

                    i2c1_object.pTrHead++;

                    // check if the end of the array is reached
                    if(i2c1_object.pTrHead == (i2c1_tr_queue + I2C1_CONFIG_TR_QUEUE_LENGTH))
                    {
                        // adjust to restart at the beginning of the array
                        i2c1_object.pTrHead = i2c1_tr_queue;
                    }

                    // since we moved one item to be processed, we know
                    // it is not full, so set the full status to false
                    i2c1_object.trStatus.s.full = false;

                    // check if the queue is empty
                    if(i2c1_object.pTrHead == i2c1_object.pTrTail)
                    {
                        // it is empty so set the empty status to true
                        i2c1_object.trStatus.s.empty = true;
                    }

                    // send the start condition
                    I2C1_START_CONDITION_ENABLE_BIT = 1;
                    
                    // start the i2c request
                    i2c1_state = S_MASTER_SEND_ADDR;
                }

                break;

            case S_MASTER_RESTART:

                /* check for pending i2c Request */

                // ... trigger a REPEATED START
                I2C1_REPEAT_START_CONDITION_ENABLE_BIT = 1;

                // start the i2c request
                i2c1_state = S_MASTER_SEND_ADDR;

                break;

            case S_MASTER_SEND_ADDR_10BIT_LSB:

                if(I2C1_ACKNOWLEDGE_STATUS_BIT)
                {
                    i2c1_object.i2cErrors++;
                    I2C1_Stop(I2C1_MESSAGE_ADDRESS_NO_ACK);
                }
                else
                {
                    // Remove bit 0 as R/W is never sent here
                    I2C1_TRANSMIT_REG = (i2c_address >> 1) & 0x00FF;

                    // determine the next state, check R/W
                    if(i2c_address & 0x01)
                    {
                        // if this is a read we must repeat start
                        // the bus to perform a read
                        i2c1_state = S_MASTER_10BIT_RESTART;
                    }
                    else
                    {
                        // this is a write continue writing data
                        i2c1_state = S_MASTER_SEND_DATA;
                    }
                }

                break;

            case S_MASTER_10BIT_RESTART:

                if(I2C1_ACKNOWLEDGE_STATUS_BIT)
                {
                    i2c1_object.i2cErrors++;
                    I2C1_Stop(I2C1_MESSAGE_ADDRESS_NO_ACK);
                }
                else
                {
                    // ACK Status is good
                    // restart the bus
                    I2C1_REPEAT_START_CONDITION_ENABLE_BIT = 1;

                    // fudge the address so S_MASTER_SEND_ADDR works correctly
                    // we only do this on a 10-bit address resend
                    i2c_address = 0x00F0 | ((i2c_address >> 8) & 0x0006);

                    // set the R/W flag
                    i2c_address |= 0x0001;

                    // set the address restart flag so we do not change the address
                    i2c_10bit_address_restart = 1;

                    // Resend the address as a read
                    i2c1_state = S_MASTER_SEND_ADDR;
                }

                break;

            case S_MASTER_SEND_ADDR:

                /* Start has been sent, send the address byte */

                /* Note:
                    On a 10-bit address resend (done only during a 10-bit
                    device read), the original i2c_address was modified in
                    S_MASTER_10BIT_RESTART state. So the check if this is
                    a 10-bit address will fail and a normal 7-bit address
                    is sent with the R/W bit set to read. The flag
                    i2c_10bit_address_restart prevents the  address to
                    be re-written.
                 */
                if(i2c_10bit_address_restart != 1)
                {
                    // extract the information for this message
                    i2c_address    = p_i2c1_trb_current->address;
                    pi2c_buf_ptr   = p_i2c1_trb_current->pbuffer;
                    i2c_bytes_left = p_i2c1_trb_current->length;
                }

                // check for 10-bit address
                if(!I2C1_7bit && (0x0 != i2c_address))
                {  
                    if (0 == i2c_10bit_address_restart)
                    {
                        // we have a 10 bit address
                        // send bits<9:8>
                        // mask bit 0 as this is always a write                    
                        I2C1_TRANSMIT_REG = 0xF0 | ((i2c_address >> 8) & 0x0006);
                        i2c1_state = S_MASTER_SEND_ADDR_10BIT_LSB;
                    }
                    else
                    {
                        // resending address bits<9:8> to trigger read
                        I2C1_TRANSMIT_REG = i2c_address;
                        i2c1_state = S_MASTER_ACK_ADDR;
                        // reset the flag so the next access is ok
                        i2c_10bit_address_restart = 0;
                    }
                }
                else
                {
                    // Transmit the address
                    I2C1_TRANSMIT_REG = i2c_address;
                    if(i2c_address & 0x01)
                    {
                        // Next state is to wait for address to be acked
                        i2c1_state = S_MASTER_ACK_ADDR;
                    }
                    else
                    {
                        // Next state is transmit
                        i2c1_state = S_MASTER_SEND_DATA;
                    }
                }
                break;

            case S_MASTER_SEND_DATA:

                // Make sure the previous byte was acknowledged
                if(I2C1_ACKNOWLEDGE_STATUS_BIT)
                {
                    // Transmission was not acknowledged
                    i2c1_object.i2cErrors++;

                    // Reset the Ack flag
                    I2C1_ACKNOWLEDGE_STATUS_BIT = 0;

                    // Send a stop flag and go back to idle
                    I2C1_Stop(I2C1_DATA_NO_ACK);

                }
                else
                {
                    // Did we send them all ?
                    if(i2c_bytes_left-- == 0U)
                    {
                        // yup sent them all!

                        // update the trb pointer
                        p_i2c1_trb_current++;

                        // are we done with this string of requests?
                        if(--i2c1_trb_count == 0)
                        {
                            I2C1_Stop(I2C1_MESSAGE_COMPLETE);
                        }
                        else
                        {
                            // no!, there are more TRB to be sent.
                            //I2C1_START_CONDITION_ENABLE_BIT = 1;

                            // In some cases, the slave may require
                            // a restart instead of a start. So use this one
                            // instead.
                            I2C1_REPEAT_START_CONDITION_ENABLE_BIT = 1;

                            // start the i2c request
                            i2c1_state = S_MASTER_SEND_ADDR;

                        }
                    }
                    else
                    {
                        // Grab the next data to transmit
                        I2C1_TRANSMIT_REG = *pi2c_buf_ptr++;
                    }
                }
                break;

            case S_MASTER_ACK_ADDR:

                /* Make sure the previous byte was acknowledged */
                if(I2C1_ACKNOWLEDGE_STATUS_BIT)
                {

                    // Transmission was not acknowledged
                    i2c1_object.i2cErrors++;

                    // Send a stop flag and go back to idle
                    I2C1_Stop(I2C1_MESSAGE_ADDRESS_NO_ACK);

                    // Reset the Ack flag
                    I2C1_ACKNOWLEDGE_STATUS_BIT = 0;
                }
                else
                {
                    I2C1_RECEIVE_ENABLE_BIT = 1;
                    i2c1_state = S_MASTER_ACK_RCV_DATA;
                }
                break;

            case S_MASTER_RCV_DATA:

                /* Acknowledge is completed.  Time for more data */

                // Next thing is to ack the data
                i2c1_state = S_MASTER_ACK_RCV_DATA;

                // Set up to receive a byte of data
                I2C1_RECEIVE_ENABLE_BIT = 1;

                break;

            case S_MASTER_ACK_RCV_DATA:

                // Grab the byte of data received and acknowledge it
                *pi2c_buf_ptr++ = I2C1_RECEIVE_REG;

                // Check if we received them all?
                if(--i2c_bytes_left)
                {

                    /* No, there's more to receive */

                    // No, bit 7 is clear.  Data is ok
                    // Set the flag to acknowledge the data
                    I2C1_ACKNOWLEDGE_DATA_BIT = 0;

                    // Wait for the acknowledge to complete, then get more
                    i2c1_state = S_MASTER_RCV_DATA;
                }
                else
                {

                    // Yes, it's the last byte.  Don't ack it
                    // Flag that we will nak the data
                    I2C1_ACKNOWLEDGE_DATA_BIT = 1;

                    I2C1_FunctionComplete();
                }

                // Initiate the acknowledge
                I2C1_ACKNOWLEDGE_ENABLE_BIT = 1;
                break;

            case S_MASTER_RCV_STOP:                
            case S_MASTER_SEND_STOP:

                // Send the stop flag
                I2C1_Stop(I2C1_MESSAGE_COMPLETE);
                break;

            default:

                // This case should not happen, if it does then
                // terminate the transfer
                i2c1_object.i2cErrors++;
                I2C1_Stop(I2C1_LOST_STATE);
                break;

        }
    }

    void I2C1_FunctionComplete(void)
    {

        // update the trb pointer
        p_i2c1_trb_current++;

        // are we done with this string of requests?
        if(--i2c1_trb_count == 0)
        {
            i2c1_state = S_MASTER_SEND_STOP;
        }
        else
        {
            i2c1_state = S_MASTER_RESTART;
        }

    }

    void I2C1_Stop(I2C1_MESSAGE_STATUS completion_code)
    {
        // then send a stop
        I2C1_STOP_CONDITION_ENABLE_BIT = 1;

        // make sure the flag pointer is not NULL
        if (p_i2c1_current->pTrFlag != NULL)
        {
            // update the flag with the completion code
            *(p_i2c1_current->pTrFlag) = completion_code;
        }

        // Done, back to idle
        i2c1_state = S_MASTER_IDLE;
        
    }

    void I2C1_MasterWrite(
                                    uint8_t *pdata,
                                    uint8_t length,
                                    uint16_t address,
                                    I2C1_MESSAGE_STATUS *pflag)
    {
        static I2C1_TRANSACTION_REQUEST_BLOCK   trBlock;

        // check if there is space in the queue
        if (i2c1_object.trStatus.s.full != true)
        {
            I2C1_MasterWriteTRBBuild(&trBlock, pdata, length, address);
            I2C1_MasterTRBInsert(1, &trBlock, pflag);
        }
        else
        {
            *pflag = I2C1_MESSAGE_FAIL;
        }

    }

    void I2C1_MasterRead(
                                    uint8_t *pdata,
                                    uint8_t length,
                                    uint16_t address,
                                    I2C1_MESSAGE_STATUS *pflag)
    {
        static I2C1_TRANSACTION_REQUEST_BLOCK   trBlock;


        // check if there is space in the queue
        if (i2c1_object.trStatus.s.full != true)
        {
            I2C1_MasterReadTRBBuild(&trBlock, pdata, length, address);
            I2C1_MasterTRBInsert(1, &trBlock, pflag);
        }
        else
        {
            *pflag = I2C1_MESSAGE_FAIL;
        }

    }

    void I2C1_MasterTRBInsert(
                                    uint8_t count,
                                    I2C1_TRANSACTION_REQUEST_BLOCK *ptrb_list,
                                    I2C1_MESSAGE_STATUS *pflag)
    {

        // check if there is space in the queue
        if (i2c1_object.trStatus.s.full != true)
        {
            *pflag = I2C1_MESSAGE_PENDING;

            i2c1_object.pTrTail->ptrb_list = ptrb_list;
            i2c1_object.pTrTail->count     = count;
            i2c1_object.pTrTail->pTrFlag   = pflag;
            i2c1_object.pTrTail++;

            // check if the end of the array is reached
            if (i2c1_object.pTrTail == (i2c1_tr_queue + I2C1_CONFIG_TR_QUEUE_LENGTH))
            {
                // adjust to restart at the beginning of the array
                i2c1_object.pTrTail = i2c1_tr_queue;
            }

            // since we added one item to be processed, we know
            // it is not empty, so set the empty status to false
            i2c1_object.trStatus.s.empty = false;

            // check if full
            if (i2c1_object.pTrHead == i2c1_object.pTrTail)
            {
                // it is full, set the full status to true
                i2c1_object.trStatus.s.full = true;
            }

        }
        else
        {
            *pflag = I2C1_MESSAGE_FAIL;
        }

        // for interrupt based
        if (*pflag == I2C1_MESSAGE_PENDING)
        {
            while(i2c1_state != S_MASTER_IDLE);
            {
                // force the task to run since we know that the queue has
                // something that needs to be sent
                PIR3bits.SSP1IF = true;
            }
        }   // block until request is complete

    }

    void I2C1_MasterReadTRBBuild(
                                    I2C1_TRANSACTION_REQUEST_BLOCK *ptrb,
                                    uint8_t *pdata,
                                    uint8_t length,
                                    uint16_t address)
    {
        ptrb->address  = address << 1;
        // make this a read
        ptrb->address |= 0x01;
        ptrb->length   = length;
        ptrb->pbuffer  = pdata;
    }

    void I2C1_MasterWriteTRBBuild(
                                    I2C1_TRANSACTION_REQUEST_BLOCK *ptrb,
                                    uint8_t *pdata,
                                    uint8_t length,
                                    uint16_t address)
    {
        ptrb->address = address << 1;
        ptrb->length  = length;
        ptrb->pbuffer = pdata;
    }

    bool I2C1_MasterQueueIsEmpty(void)
    {
        return(i2c1_object.trStatus.s.empty);
    }

    bool I2C1_MasterQueueIsFull(void)
    {
        return(i2c1_object.trStatus.s.full);
    }        
            
    void I2C1_BusCollisionISR( void )
    {
        // enter bus collision handling code here
    }        
            
            
    /**
     End of File
    */



    Attached Image(s)

    #20
    Page: 123 > Showing page 1 of 3
    Jump to:
    © 2018 APG vNext Commercial Version 4.5