help using I2C functions generated by MCC

This forum handles questions and discussions concerning Microchip’s MPLAB® Code Configurator (MC2).

help using I2C functions generated by MCC

Postby cyberduke » Fri Jan 19, 2018 11:17 am

Hi guys, I have acquired a pic24fv32ka302 and a mpu 6050 gyroscope and accelerator unit. See below all relevant documents/links for these units.

https://www.invensense.com/wp-content/u ... sheet1.pdf
https://www.invensense.com/wp-content/u ... r-Map1.pdf
https://www.microchip.com/wwwproducts/en/PIC24F32KA302

Now I recently graduated from arduinos where I have used I2C on this exact gyro unit. So I know the theory. I have been struggling to implement this on MPlab using my pic. I am stuck for a while now and would really appreciate some input. I have succesfully setup the UART so that I can read results using a serial monitor on my pc.

1. I setup the I2C using the microchip code configurator.(mcc) This generated a I2c.c and I2c.h file.
2. In the I2C.h file there is some examples. And I implemented one as follows, yeah I know I literally copied and pasted and edited just what was absolutely necessary, Ill make it nice once it works)

Code: Select all
 
#define MCHP24AA512_RETRY_MAX 100 // define the retry count
#define MCHP24AA512_ADDRESS 0x68 // slave device address
 
 
uint8_t MCHP24AA512_Read(
                                            uint16_t address,
                                            uint8_t *pData,
                                            uint16_t nCount)
            {
                I2C1_MESSAGE_STATUS status;
                uint8_t writeBuffer[3];
                uint16_t timeOut;
                uint16_t counter;
                uint8_t *pD, ret;
 
                pD = pData;
 
                for (counter = 0; counter < nCount; counter++)
                {
 
                    // build the write buffer first
                    // starting address of the EEPROM memory
                    writeBuffer[0] = (address >> 8); // high address
                    writeBuffer[1] = (uint8_t)(address); // low low address
 
                    // Now it is possible that the slave device will be slow.
                    // As a work around on these slaves, the application can
                    // retry sending the transaction
                    timeOut = 0;
                    while(status != I2C1_MESSAGE_FAIL)
                    {
                        // write one byte to EEPROM (2 is the count of bytes to write)
                        I2C1_MasterWrite( writeBuffer,
                                                2,
                                                MCHP24AA512_ADDRESS,
                                                &status);
 
                        // wait for the message to be sent or status has changed.
                        while(status == I2C1_MESSAGE_PENDING);
 
                        if (status == I2C1_MESSAGE_COMPLETE)
                            break;
 
                        // if status is I2C_MESSAGE_ADDRESS_NO_ACK,
                        // or I2C_DATA_NO_ACK,
                        // The device may be busy and needs more time for the last
                        // write so we can retry writing the data, this is why we
                        // use a while loop here
 
                        // check for max retry and skip this byte
                        if (timeOut == MCHP24AA512_RETRY_MAX)
                            break;
                        else
                            timeOut++;
                    }
 
                    if (status == I2C1_MESSAGE_COMPLETE)
                    {
 
                        // this portion will read the byte from the memory location.
                        timeOut = 0;
                        while(status != I2C1_MESSAGE_FAIL)
                        {
                            // write one byte to EEPROM (2 is the count of bytes to write)
                            I2C1_MasterRead( pD,
                                                    1,
                                                    MCHP24AA512_ADDRESS,
                                                    &status);
 
                            // wait for the message to be sent or status has changed.
                            while(status == I2C1_MESSAGE_PENDING);
 
                            if (status == I2C1_MESSAGE_COMPLETE)
                                break;
 
                            // if status is I2C_MESSAGE_ADDRESS_NO_ACK,
                            // or I2C_DATA_NO_ACK,
                            // The device may be busy and needs more time for the last
                            // write so we can retry writing the data, this is why we
                            // use a while loop here
 
                            // check for max retry and skip this byte
                            if (timeOut == MCHP24AA512_RETRY_MAX)
                                break;
                            else
                                timeOut++;
                        }
                    }
 
                    // exit if the last transaction failed
                    if (status == I2C1_MESSAGE_FAIL)
                    {
                        ret = 0;
                        break;
                    }
 
                    pD++;
                    address++;
 
                }
                return (ret);
 
            }
 

Then I call the function from my main using
Code: Select all
 
  uint16_t GyroData1 = 0;
 
    GyroData1 = MCHP24AA512_Read(63,0x68,1);
        UartSentint(GyroData1);
 


So Using this http://ww1.microchip.com/downloads/en/D ... 00195f.pdf I have been trying to just manually also play around with the registers and it seems that a start condition never gets initiated.

now I know that the returned result will be rubbish since I am only reading 1 byte from a 16bit unsigned int(in the register of the gyro) but I am getting no result yet. Once I can read something, getting it right should be easy.

I am stuck for a while now so I would appreciate any help.
cyberduke
 
Posts: 4
Joined: Thu Jan 18, 2018 6:02 pm
PIC experience: EE Student

Re: help using I2C functions generated by MCC

Postby ric » Sat Jan 20, 2018 6:59 am

I've never used the MCC functions, but don't you need to call an "init" function first to enable the I2C peripheral?
Is the MCC code polling, or using interrupts?
The code you've posted is plainly expecting things to happen in the background, so must be assuming it is interrupt driven.
Latest test project, an LED matrix display made from one reel of addressable LEDs. here
User avatar
ric
Verified identity
 
Posts: 412
Joined: Sat May 24, 2014 2:35 pm
Location: Melbourne, Australia
PIC experience: Professional 5+ years with MCHP products

Re: help using I2C functions generated by MCC

Postby cyberduke » Sun Jan 21, 2018 2:41 pm

Apologies. I Assumed a lot more prior knowledge of MCC. I do call the initializing function. But lets take it back to basics.

So I plugged an arduino back in and looked at the I2C comms over a scope. So at this point I can probably draw an I2C conversation happening.

But when I plug the pic back in the Data line never gets pulled low to start a conversation. (Start condition). Doesn't matter what I do. I have tried soo many approaches etc.
if you look here http://ww1.microchip.com/downloads/en/D ... 00195f.pdf then it says the P status bit (page 21) needs to be in idle then you can call a start condition. But the P status bit also never goes to idle.(HIGH) This convinces me that I am setting this up wrong.

I really would appreciate it if anyone just could maybe give me a pointer maybe of what register I am forgetting or something so I can actually start the conversation.

The initializing function generated by the MCC is as follows(I even went through the datasheet and re-dit it and it was exactly the same as how I would have set it up manually. ):
Code: Select all
    i2c1_object.pTrHead = i2c1_tr_queue;//I assume the next few lines is jusst class-type code
    i2c1_object.pTrTail = i2c1_tr_queue;//and has not much to do with the actual setup of the i2c
    i2c1_object.trStatus.s.empty = true;
    i2c1_object.trStatus.s.full = false;

    i2c1_object.i2cErrors = 0;
   
    // initialize the hardware
    // Baud Rate Generator Value: I2CBRG 19;   
    I2C1BRG = 0x0013;
    // ACKEN disabled; STREN disabled; GCEN disabled; SMEN disabled; DISSLW enabled; I2CSIDL disabled; ACKDT Sends ACK; SCLREL Holds; RSEN disabled; IPMIEN disabled; A10M 7 Bit; PEN disabled; RCEN disabled; SEN disabled; I2CEN enabled;
    I2C1CON = 0x8000;
    // P disabled; S disabled; I2COV disabled; IWCOL disabled;
    I2C1STAT = 0x0000;

    /* MI2C1 - I2C1 Master Events */
    // clear the master interrupt flag
    IFS1bits.MI2C1IF = 0;
    // enable the master interrupt
    IEC1bits.MI2C1IE = 1;
cyberduke
 
Posts: 4
Joined: Thu Jan 18, 2018 6:02 pm
PIC experience: EE Student

Re: help using I2C functions generated by MCC

Postby Roche » Sun Jan 21, 2018 3:24 pm

You could try setting the I2CEN bit prior to setting the baud rate...
Roche
 
Posts: 28
Joined: Fri Jul 11, 2014 12:35 pm
PIC experience: Professional 5+ years with MCHP products

Re: help using I2C functions generated by MCC

Postby cyberduke » Sun Jan 21, 2018 4:15 pm

I got slightly happy when i saw that because it makes perfect sense. But sadly makes no difference.
cyberduke
 
Posts: 4
Joined: Thu Jan 18, 2018 6:02 pm
PIC experience: EE Student

Re: help using I2C functions generated by MCC

Postby ric » Mon Jan 22, 2018 12:58 am

cyberduke wrote:...
if you look here http://ww1.microchip.com/downloads/en/D ... 00195f.pdf then it says the P status bit (page 21) needs to be in idle then you can call a start condition. But the P status bit also never goes to idle.(HIGH) This convinces me that I am setting this up wrong.

That's an interesting comment Microchip make.
In my experience, P will not go high until AFTER there has been one full cycle on the bus.
i.e. it has to have seen a STOP condition sent, which is not true straight after the peripheral has been initialised, so it's a bad idea to wait for it before you do your first operation.

My next guess would have been a problem with analog pin settings, however on your chip, only the second I2C peripheral shares analog pins.
Make sure no other shared functions on SDA1 and SCL1 are interfering. If the peripheral sees either pin low when you set SEN, you should get a bus collision error.
Latest test project, an LED matrix display made from one reel of addressable LEDs. here
User avatar
ric
Verified identity
 
Posts: 412
Joined: Sat May 24, 2014 2:35 pm
Location: Melbourne, Australia
PIC experience: Professional 5+ years with MCHP products

Re: help using I2C functions generated by MCC

Postby cyberduke » Mon Jan 22, 2018 12:45 pm

That was an issue! yay! so I rechecked the configuration(made sure I turn all analog off etc) and played around a bit. I nearly fell off my chair after the scope moved after about a week of constant struggle. !!

But it is not working yet. See attached the screenshot of the scope (Clock ontop, data at the bottom). I apologize for the photo,I don't have a flash drive handy.

Now the slave address (ox68) is visible but it seems that an ack doesn't come though(The low pull of the data line) .

I am also attaching all my brand new code I got that seems the most promising. (I know this is not the interrupt based MCC code but it actually is starting to seem promising thats why I am leaning this way)

d88e8c54-aa0a-47bc-8e97-10fe94068eed.jpg
d88e8c54-aa0a-47bc-8e97-10fe94068eed.jpg (117.58 KiB) Viewed 726 times


Code: Select all
#define DS1621ADDR 0x68   //slave address
#define ACCESS_CONFIG 0x3F //to be honest I arent exactly sure what all these addresses means, so I set them all equal to the register I want to read
#define START_CONVERT 0x3F
#define READ_TEMP 0x3F

#define I2C_WADDR(x) (x & 0xFE) //clear R/W bit of I2C addr
#define I2C_RADDR(x) (x | 0x01) //set R/W bit of I2C addr

void startI2C1(void) {
   //uint8_t u8_wdtState;
 
   //sz_lastTimeoutError = "I2C1 Start";
  // u8_wdtState = _SWDTEN;  //save WDT state
  //_SWDTEN = 1; //enable WDT
   I2C1CONbits.SEN = 1;   // initiate start
   // wait until start finished
   while (I2C1CONbits.SEN);
   //_SWDTEN = u8_wdtState;  //restore WDT
  // sz_lastTimeoutError = NULL;
 }

 void putI2C1(uint8_t u8_val) {
  // uint8_t u8_wdtState;
 
  // sz_lastTimeoutError = "I2C1 Put";
  // u8_wdtState = _SWDTEN;  //save WDT state
  // _SWDTEN = 1;       //enable WDT
   I2C1TRN = u8_val;    // write byte
   while (I2C1STATbits.TRSTAT);   // wait for 8bits+ ack bit to finish
 // _SWDTEN = u8_wdtState;  //restore WDT
  // sz_lastTimeoutError = NULL;
   if (I2C1STATbits.ACKSTAT != I2C_ACK) {
   //////error
       //NAK returned
   };
     
     //reportError("I2CPUT1, NAK returned.");
   }
 
  void stopI2C1(void) {
  // uint8_t u8_wdtState;
 
  // sz_lastTimeoutError = "I2C1 Stop";
 //  u8_wdtState = _SWDTEN;  //save WDT state
 //  _SWDTEN = 1;  //enable WDT
   I2C1CONbits.PEN=1;     // initiate stop, PEN=1
   //wait until stop finished
   while (I2C1CONbits.PEN);
 //  _SWDTEN = u8_wdtState;  //restore WDT
  // sz_lastTimeoutError = NULL;
 }
 
  uint8_t getI2C1(uint8_t u8_ack2Send) {
   uint8_t u8_wdtState;
   uint8_t u8_inByte;
//UartSentint(21);
  // sz_lastTimeoutError = "I2C1 Get";
 //  u8_wdtState = _SWDTEN;              //save WDT state
 //  _SWDTEN = 1;                        //enable WDT                                 
   while (I2C1CON & 0x1F);           //wait for idle condition
  // UartSentint(22);
   I2C1CONbits.RCEN = 1;             //enable receive
  // UartSentint(23);
   while (!I2C1STATbits.RBF);        //wait for receive byte..........................gets stuck here!!!!!!!!!!
   //CLRWDT();
 //  UartSentint(24);
   u8_inByte = I2C1RCV;              //read byte;
   //wait for idle condition before attempting ACK
  // UartSentint(25);
   while (I2C1CON & 0x1F);           //lower 5 bits must be 0
   I2C1CONbits.ACKDT = u8_ack2Send;  //ACK bit to send back on receive
   I2C1CONbits.ACKEN = 1;            //enable ACKbit transmittion
   while (I2C1CONbits.ACKEN);        //wait for completion
   //_SWDTEN = u8_wdtState;              //restore WDT
   //sz_lastTimeoutError = NULL;
   return(u8_inByte);                  //return the value
 }

 //00000000000000000000000000000
   void read2I2C1 (uint8_t u8_addr,uint8_t* pu8_d1, uint8_t* pu8_d2) {
 //      UartSentint(10);
   startI2C1();
  // UartSentint(11);
   putI2C1(I2C_RADDR(u8_addr));
  // UartSentint(12);
   *pu8_d1 = getI2C1(I2C_ACK);
 //  UartSentint(13);
   *pu8_d2 = getI2C1(I2C_NACK);
  // UartSentint(14);
   stopI2C1();
 //  UartSentint(15);
 }
 
 void write2I2C1(uint8_t u8_addr,uint8_t u8_d1, uint8_t u8_d2) {
   startI2C1();
   putI2C1(I2C_WADDR(u8_addr));
   putI2C1(u8_d1);
   putI2C1(u8_d2);
   stopI2C1();
 }
 
  void write1I2C1(uint8_t u8_addr,uint8_t u8_d1) {
   startI2C1();
   putI2C1(I2C_WADDR(u8_addr));
   putI2C1(u8_d1);
   stopI2C1();
 }
 
int16_t readTempDS161() {
  uint8_t u8_lo, u8_hi;
  int16_t i16_temp;
 // UartSentint(1);
  write1I2C1(DS1621ADDR, READ_TEMP);
 // UartSentint(2);
   read2I2C1 (DS1621ADDR, &u8_hi, &u8_lo);
 //  UartSentint(3);
  i16_temp = u8_hi;
   return ((i16_temp<<8)|u8_lo);
 }

void I2C1_Initialize(void)
{
    // initialize the hardware
    // Baud Rate Generator Value: I2CBRG 19;   
      I2C1CON = 0x8000;
     
    I2C1BRG = 0x0013;
    // ACKEN disabled; STREN disabled; GCEN disabled; SMEN disabled; DISSLW enabled; I2CSIDL disabled; ACKDT Sends ACK; SCLREL Holds; RSEN disabled; IPMIEN disabled; A10M 7 Bit; PEN disabled; RCEN disabled; SEN disabled; I2CEN enabled;
 
    // P disabled; S disabled; I2COV disabled; IWCOL disabled;
    I2C1STAT = 0x0000;
}



and then A call to the code
Code: Select all
I2C1_Initialize();
write2I2C1(DS1621ADDR, ACCESS_CONFIG, 0x00);
 write1I2C1(DS1621ADDR, START_CONVERT);
 
    while(1)
    {
     
       int16_t in  = readTempDS161();
}
cyberduke
 
Posts: 4
Joined: Thu Jan 18, 2018 6:02 pm
PIC experience: EE Student

Re: help using I2C functions generated by MCC

Postby ric » Wed Jan 24, 2018 1:05 am

0x68 is the 7 bit address. The PIC peripheral uses the full 8 bit address, so you need to shift it left one bit.
Try 0xD0 instead.
Latest test project, an LED matrix display made from one reel of addressable LEDs. here
User avatar
ric
Verified identity
 
Posts: 412
Joined: Sat May 24, 2014 2:35 pm
Location: Melbourne, Australia
PIC experience: Professional 5+ years with MCHP products

Re: help using I2C functions generated by MCC

Postby Roche » Fri May 25, 2018 6:35 pm

Thanks for the pearl of wisdom about the P bit Ric, It saved me a load of time today.

Regards,

Roche
Roche
 
Posts: 28
Joined: Fri Jul 11, 2014 12:35 pm
PIC experience: Professional 5+ years with MCHP products


Return to MPLAB® Code Configurator

Who is online

Users browsing this forum: No registered users and 1 guest