4

I am new to embedded programming and am trying to get my first I2C project working. I am using the PIC32MX795F512L. I am pretty much following the microchip datasheet for I2C on PIC32. The problem I'm having is the S bit is never cleared from the I2C1STAT register. It is actually unclear to me whether I have to do this or if it is done automatically at the conclusion of the Start event, but right now I'm trying to manually clear it. However, nothing that I do seems to have an effect. If more information is needed to make it easier to understand what is happening let me know. I am using a PICKIT3 so I can get debugging information as well. I know that the Master interrupt occurs, the S bit gets set, I exit the interrupt code and hang on the while statement checking the I2C1STATbits.S.

Edit: I'm editing this post to have my new code instead of the old code. I am now using a 20MHZ peripheral clock. Just one of the many things I tried today that did not work. Delay is just a 256ms delay. Super long I know, but it was quick.

main()
{
//Setup I2C1CON

I2C1CONbits.SIDL = 0;   //Continue to run while in Idle
I2C1CONbits.SCLREL = 1; //Release the clock (Unsure of this)
I2C1CONbits.A10M = 0;   //Using a 7 bit slave address
I2C1CONbits.DISSLW = 1; //Slew rate control disabled because running at 100 KHZ

I2C1ADD = 0x1E;         //Slave address without read or write bit
I2C1BRG = 0x060;        //Set the BRG clock rate - Based on Page 24-19

I2C1CONbits.ON = 1;     //Turn on the I2C module

delay();

I2C1CONbits.SEN = 1;    //Initiate a start event

while(I2C1CONbits.SEN == 1);    //Wait until Start event is done

I2C1TRN = 0x3C;                 //Load the address into the Transmit register

while(I2C1STATbits.TRSTAT == 1);
while(I2C1STATbits.ACKSTAT == 0);    //Wait for a ACK from the device

I2C1TRN = 0x00;

while(I2C1STATbits.TRSTAT == 1);
while(I2C1STATbits.ACKSTAT == 0);

I2C1TRN = 0x70;

while(I2C1STATbits.TRSTAT == 1);
while(I2C1STATbits.ACKSTAT == 0);


while(1);

}

Thanks for any help.

user36927
  • 41
  • 1
  • 3
  • Have you read over ww1.microchip.com/downloads/en/DeviceDoc/61116E.pdf, which is Microchip's generic I2C description and handling? – Ross Jul 31 '14 at 21:02
  • Yes, that is the document that I am following. From working on it today I have learned that the S bit in the I2C1STAT register should be cleared by hardware. On page 24-9 of that PDF it says that the Start bit is updated when a Start, Reset or Stop is detected. What's happening now is this. I set the SEN bit. My interrupt occurs with the S bit in I2C1STAT set. I ensure SEN is set to 0 before moving on. I put my I2C device address into I2C1TRN. However on the next interrupt S bit is set and RBF is set in I2C1STAT. Buffer contains the device address. No ACK in I2CSTAT. – user36927 Aug 01 '14 at 00:35
  • Hey Guys, I wanted to update this post. I completely deleted it all and started over. This time I'm doing it by polling instead of trying to use the interrupts. The original problem is gone and it seems to be working fairly well. Thank you Ross for taking a look at this post. I'm going to continue trying to implement through polling. Once I get that working I'm going to go back and try using interrupts again. Does anyone have any pointers for me for using the I2C master interrupt? Any ideas why using the interrupt would create problems for me? – user36927 Aug 01 '14 at 01:58
  • Sigh... I spoke to soon. I just realized I made a typo on when I put the I2C's device into I2C1TRN. It was the wrong address which is why everything was going smoothly. When I changed it to the correct address it stopped working. Just like before the I2CSTAT.S stays 1 after I2C1CON.SEN is cleared automatically. I2C1STAT.RBF is 1 as well. No ACK sent by the device. Could somebody explain the purpose of I2C1ADD to me? My devices address is 0x1E. That makes 0x3C and 0x3D my write/read addresses. So I do I2C1ADD = 0x1E. And to start a write I2C1TRN = 0x3C. Whats the purpose of I2C1ADD. – user36927 Aug 01 '14 at 02:06
  • Just out of curiosity, are you using MPLABX? If so, can you show how you are setting your `DEVCFG` bits with the `#pragma config` statements? – embedded_guy Aug 04 '14 at 18:02

2 Answers2

1

I'm also just beggining on PIC32MZ family, setting up the I2C to talk to various memory chips. I used your code and modified it so that it would work properly. Since I am using PIC32MZ family, I believe the I2C registers should probably be the same.

I2C configuration:

I2C1CONbits.SIDL = 0;       // Stop in Idle Mode bit                        -> Continue module operation when the device enters Idle mode
I2C1CONbits.A10M = 0;       // 10-bit Slave Address Flag bit                -> I2CxADD register is a 7-bit slave address
I2C1CONbits.DISSLW = 1;     // Slew Rate Control Disable bit                -> Slew rate control disabled for Standard Speed mode (100 kHz)
I2C1CONbits.ACKDT = 0;      // Acknowledge Data bit                         -> ~ACK is sent
I2C1BRG = 0x0F3;            // Baud Rate Generator set to provide 100KHz for SCL with 50 MHz xtal. 

I followed the transmission steps provided in the I2C Datasheet so it would be easy to follow the steps coupled with the pdf and my comments on the code.

I2C Data Transmission:

// 1. Turn on the I2C module by setting the ON bit (I2CxCON<15>) to ‘1’.
I2C1CONbits.ON = 1;         // I2C Enable bit                               -> Enables the I2C module and configures the SDAx and SCLx pins as serial port pins

//------------- WRITE begins here ------------
// 2. Assert a Start condition on SDAx and SCLx.
I2C1CONbits.PEN = 0;        // Stop Condition Enable Bit                    -> Stop Condition Idle 
I2C1CONbits.SEN = 1;        // Start Condition Enable bit                   -> Initiate Start condition on SDAx and SCLx pins; cleared by module
while(I2C1CONbits.SEN == 1);            // SEN is to be cleared when I2C Start procedure has been completed 

// 3. Load the Data on the bus
I2C1TRN = 0b10100000 ;          // Write the slave address to the transmit register for I2C WRITE 
while(I2C1STATbits.TRSTAT == 1);        // MASTER Transmit still in progress
while(I2C1STATbits.ACKSTAT == 1);       // Master should receive the ACK from Slave, which will clear the I2C1STAT<ACKSTAT> bit. 

I2C1TRN = 0xCE;                 // Register Address 
while(I2C1STATbits.TRSTAT == 1);
while(I2C1STATbits.ACKSTAT == 1);

I2C1TRN = 0xCF;                 // Register Value 
while(I2C1STATbits.TRSTAT == 1);
while(I2C1STATbits.ACKSTAT == 1);
I2C1CONbits.PEN = 1;        // Stop Condition Enable Bit                    -> Initiate Stop condition on SDAx and SCLx pins; cleared by module

//-------------- WRITE ends here -------------

This code works well as I used a couple of LEDs to toggle indicating a successful write procedure.

Babak D
  • 41
  • 1
  • 8
-1

The while(!(I2C1STATbits.ACKSTAT == 0)); is the right way i guess.I2C1ADD is used to set the slave address of the current PIC mc if you are using your I2C as slave.If any master requests start with that slave address the PIC will respond to that as slave.

Read this pdf where initially they have specified that in PIC the I2C is configured as both master and slave and the master request is checked by the same PIC with with the slave address in the I2C1ADD value. http://ww1.microchip.com/downloads/en/DeviceDoc/61116F.pdf

prashanth
  • 1
  • 1