PIC18F4520 with I2C Mode (PICDEM2 Plus Board)

Discussion in 'Embedded Systems and Microcontrollers' started by symphony888, May 5, 2014.

  1. symphony888

    Thread Starter New Member

    May 5, 2014
    13
    0
    I'm using PICDEM2 Plus Board as the microcontroller board with the P18F4520. There is also a 24LC256 EEPROM attached to it.

    The set up of it is 1 Master and 1 Slave both using the same board.
    The main question is, when I'm transmitting something from Master to Slave, does both the Master and Slave SSPBUF, shows as Write or Master as Write and Slave as Read?
     
  2. ErnieM

    AAC Fanatic!

    Apr 24, 2011
    7,386
    1,605
    Hi, welcome to the forums.

    SSPBUF is called the "Serial Receive/Transmit Buffer Register" wehich implies yoes you use it for both transmission and reception of data.

    In the config you are using the PIC is always the master. The slave bus address, slave memory address, and any data to be written go into SSPBUF. When reading back a byte you find it also in SSPBUF.

    Study the 24LC256 transmission carefully. When writing data the procedure is clear: Write slave addr, write data starting addr, then however many bytes you wish to send. However, wher reading data you send the first two elements (slave addr, data starting addr) to set the internal ROM data pointer, then restart to read by sending slave addr, then reading each byte of data.

    You ACK each byte you want until the last byte, which you NAK.
     
  3. symphony888

    Thread Starter New Member

    May 5, 2014
    13
    0
    Do I really need to use the 24LC256 EEPROM for the sending/receiving for the I2C Mode? Or is it possible to just wire the RC3 and RC4 which is know as CLK and Data I assume for I2C. And also the address of the EEPROM, do I need to set it manually or it has a pre-set address?
     
  4. ErnieM

    AAC Fanatic!

    Apr 24, 2011
    7,386
    1,605
    Now I am confused as to your intent. When you state you have a PIC18F4520 and a 24LC256 EEPROM it is natual to assume you want to use the PIC18F4520 to talk to the 24LC256 EEPROM.

    If you are asking can you do I2C without using the hardware module the answer is yes, it is very do-able to write code for the master (PIC controller) side. There are lots of examples on the web, but you may have to mentally translate from some other language to the one you are using.

    The 24LC256 does indeed have it's own range of preset slave addresses, well defined in the data sheet. Most of the address is preset, some has to be hard wired to the pins.
     
  5. symphony888

    Thread Starter New Member

    May 5, 2014
    13
    0
    Right now, I'm also finding out if I should do it so that it communicates with the EEPROM. Is there any example of it? I'm not sure where to do on the EEPROM side.

    I've done some coding and used an Oscilloscope to see if I can get the DATA/ADDRESS bit, START/STOP bits working. But sometimes it works, sometimes it don't. In my code, I have nothing related to the EEPROM as I'm not sure how to start at all, been trying to find an example but can't seem to find one. I'm using MPLAB IDE with C18 Compiler.
     
  6. ErnieM

    AAC Fanatic!

    Apr 24, 2011
    7,386
    1,605
    Figure 6.1 and 8.2 of the 24LC256 data sheet shows the bit by bit transaction sequence.

    If sometimes it works and sometimes it doesn't make sure every START is followed by a STOP.

    If all you are sending is the address then "works" is defined by seeing the ACK bit (a zero) in slot 9.
     
  7. symphony888

    Thread Starter New Member

    May 5, 2014
    13
    0
    I want to ask this question though. I still can't find an answer to it.

    My SSPBUF on my Master Device shows as 0xA0(R/W bit is '0') while on my Slave Device it shows as 0xA1(R/W bit is '1'). Is that suppose to be it or both needs to be '0'?
     
  8. symphony888

    Thread Starter New Member

    May 5, 2014
    13
    0
    Here is my Master Code:
    Code ( (Unknown Language)):
    1. #include <p18f4520.h>
    2. #include <delays.h>
    3. #include <i2c.h>
    4. unsigned char i2cPutByteAndWait(unsigned char);
    5.  
    6. char clearData = 0;
    7.  
    8. void main(void)
    9. {  
    10.     char address_w = 0xA8, result = 0, temp = 0;
    11.     SSPSTAT = 0x80;
    12.     SSPCON1 = 0x28;
    13.     SSPCON2 = 0x00;
    14.     SSPCON1bits.SSPEN = 1;
    15.    
    16.     TRISC = 0b00000000;
    17.     SSPBUF=temp;
    18.     CloseI2C();
    19.     OpenI2C(MASTER, SLEW_OFF);
    20.     SSPADD = 0x09;
    21.     IdleI2C();
    22.     StartI2C();
    23.     while(SSPCON2bits.SEN);
    24.     Delay10TCYx(5);
    25.    
    26.     WriteI2C((0xA8) & (0xFE));
    27.     while(SSPCON2bits.ACKSTAT);
    28.    
    29. /*do
    30. {
    31.     result = WriteI2C(address_w & 0xFE);
    32.     if(-1 == result)
    33.     {
    34.         temp = SSPBUF;
    35.         SSPCON1bits.WCOL = 0;
    36.     }
    37. }while(0 != result);   
    38.  
    39.  
    40. /*do
    41. {
    42.   result=WriteI2C (0x02);//sets the register on the RTC
    43.   if (-1 == result) //write collision handler
    44.   {
    45.     temp=SSPBUF;       //Clearing the junk in buffer
    46.     SSPCON1bits.WCOL=0;//Clearing the write collision flag
    47.   }
    48.  }*/
    49.  //while (0!=result);//we're repeating transmission until ACK is received
    50.  
    51. IdleI2C();
    52.     StopI2C();
    53.    
    54. while(SSPCON2bits.PEN);
    55.     Delay10TCYx(5);
    56.     CloseI2C();
    57.  
    58. }
    59. /*unsigned char i2cPutByteAndWait(unsigned char data_out) {
    60.     SSPBUF = data_out;          // write single byte to SSPBUF
    61.     if ( SSPCON1bits.WCOL ) {   // test if write collision occurred
    62.         SSPCON1bits.WCOL = 0;           // if WCOL bit is set return negative #
    63.     }
    64.     while(PIR1bits.SSPIF == 0);
    65.     PIR1bits.SSPIF = 0;
    66.     while( SSPSTATbits.BF );    // wait until write cycle is complete
    67.  
    68.    IdleI2C();           // wait until bus goes idle
    69.  
    70.    
    71. }
    And here is my Slave Code:
    Code ( (Unknown Language)):
    1. #include <p18f4520.h>
    2. #include <delays.h>
    3. #include <stdlib.h>
    4. #include <i2c.h>
    5.  
    6.  
    7. // Function prototypes for the high priority ISRs
    8. void ISR(void);
    9.  
    10. // Function prototype for the SSP ISR
    11. void SSPISR(void);
    12.  
    13. // This is the code for at the high priority vector
    14. #pragma code H_vector=0x08
    15. void H_vector(void) { _asm goto ISR _endasm }
    16. #pragma code
    17.  
    18. // The actual high priority ISR
    19. #pragma interrupt ISR
    20. void ISR(void)
    21. {
    22.     if (PIR1bits.SSPIF) // Check for SSP interrupt
    23.     {
    24.         SSPISR();
    25.         PIR1bits.SSPIF = 0;  // Clear the interrupt flag
    26.     }
    27.    
    28. }
    29.  
    30. // This is the actual SSP ISR
    31. void SSPISR(void)
    32. {
    33.     PORTBbits.RB1=1;
    34.    
    35. }
    36.  
    37. void main(void)
    38. {
    39.    
    40.     unsigned char sync_mode = SLAVE_7, slew = SLEW_OFF,slave_address = 0x08, clearBUF = 0;
    41.     TRISA = 0b11111111;
    42.     TRISB = 0b11000001;
    43.     TRISC = 0b00011110;         // configure SCL SDA as input
    44.     INTCONbits.GIEH = 0;
    45.     RCONbits.IPEN = 1;          // Enable interrupt priorities
    46.     IPR1bits.SSPIP = 1;         // Set SSP interrupt priority to high
    47.     PIR1bits.SSPIF = 0;  // Clear the interrupt flag
    48.     PIE1bits.SSPIE = 1;         // Enable SSP interrupt
    49.     INTCONbits.GIEH = 1;
    50.  
    51.     PORTBbits.RB1=1;
    52.     Delay10KTCYx(200);
    53.     PORTBbits.RB1=0;
    54.    
    55.     SSPADD = 0xA8;
    56.     SSPCON1 = 0b00100110;
    57.     SSPCON2 = 0b00000001;
    58.     SSPBUF = clearBUF;
    59.  
    60.     IdleI2C();
    61.     OpenI2C(SLAVE_7 , SLEW_OFF);
    62.     IdleI2C();
    63.     SSPCON1bits.CKP = 1;
    64.     while(1);
    65.    
    66.    
    67. }
    Now my SSPBUF keeps showing 0x00 and I got no idea why its like that. I'm very sure I'm overlooking something and I can't find out what is it about.
     
  9. ErnieM

    AAC Fanatic!

    Apr 24, 2011
    7,386
    1,605
    What condition is this? When do you see this mismatch?


    Slave code? Why in the world do you need slave code? What device is the master when the PIC is the slave?

    If you are attempting to make one PIC talk to another stop, you need to learn one side at a time.

    (I will check the master side code later.)
     
  10. symphony888

    Thread Starter New Member

    May 5, 2014
    13
    0
    I'm using a PICDEM2 Plus Board with the same chip which is the P18F4520. One set as Master and another as a Slave. With the RC3 and RC4 physically wired up to each other. SDA and SCL.
     
  11. ErnieM

    AAC Fanatic!

    Apr 24, 2011
    7,386
    1,605
    I think I now get what you are doing: you have TWO PIC18F4520 chips, and you wish to communicate from one to the other using I2C. The EEPROM is not part of the set-up.


    Is this correct?
     
  12. symphony888

    Thread Starter New Member

    May 5, 2014
    13
    0
    Yes sir. That is the current set up. As I have no idea about the EEPROM(even after reading the Datasheet, I'm still clueless about initializing it). So I'm just trying to do it via another way which is this.

    The EEPROM though, is attached to the board but I'm not using it at all. I'm scared that, the EEPROM might interfere with the communication of the 2 chips.
     
  13. ErnieM

    AAC Fanatic!

    Apr 24, 2011
    7,386
    1,605
    Unless you give the slave the same address as the EEPROM then it will sit there mute and ignore what you are doing. (So don't use 0xA0 thru 0xAF.)

    I have yet to check your code, but suggest you start by sending the very simple sequence START-ADDR-STOP, and use that to see if your slave code can ACK reliably. Once you have that working (and it works for either read or write) then you can start doing some real reading and writing.

    You have a scope, use it well. If you have a PICkit it works as an in circuit code debugger, meaning you can see what your code is really doing inside the hardware.
     
  14. symphony888

    Thread Starter New Member

    May 5, 2014
    13
    0
    I have PICKIT 3 that I'm using currently. Oh, the slave address initially I use was 0xA8 so I think maybe that might be one of the cause.

    So basically:
    IdleI2C();
    OpenI2C(MASTER, SLEW_OFF);
    StartI2C();
    IdleI2C();
    WriteI2C(Slave_address & 0XFE);
    IdleI2C();
    WriteI2C(data_out);
    IdleI2C();
    StopI2C();
    IdleI2C();
    CloseI2C();

    Is that what you're talking about?

    Also for Master Device, does the SSPBUF clears itself?

    edit1: I've just tried changing the address and nothing came up on the scope. No waveform or anything and also the Master Device bits.BF isn't Full and also there was no ACK from Slave. I must be overlooking something which I can't find out.
    edit2: Now the Interrupt Flag is set but the return of SSPBUF on Slave Device is = 0x99 and the SSPBUF on Master Device is 0x98. Is the R/W bit suppose to be like that or? It should be the same as the master.
    edit3: Interrupt Flag isn't always set. It is random. Sometimes it the IF will set, sometimes it will not. This happens even when I did not change anything.
     
    Last edited: May 6, 2014
  15. ErnieM

    AAC Fanatic!

    Apr 24, 2011
    7,386
    1,605
    symphony888: sorry I owe you a reply. Could you post you code as you have it now, and with any luck I can peek at it tonight.

    (Hopefully you already have it all working and onto the next big thing.)
     
  16. symphony888

    Thread Starter New Member

    May 5, 2014
    13
    0
    Slave.c

    Code ( (Unknown Language)):
    1. #include <p18f4520.h>
    2. #include <delays.h>
    3. #include <stdlib.h>
    4. #include <i2c.h>
    5.  
    6. #pragma config OSC = INTIO67
    7. // Function prototypes for the high priority ISRs
    8. void ISR(void);
    9.  
    10. // Function prototype for the SSP ISR
    11. void SSPISR(void);
    12.  
    13. // This is the code for at the high priority vector
    14. #pragma code H_vector=0x08
    15. void H_vector(void) { _asm goto ISR _endasm }
    16. #pragma code
    17.  
    18. // The actual high priority ISR
    19. #pragma interrupt ISR
    20. void ISR(void)
    21. {
    22.     if (PIR1bits.SSPIF) // Check for SSP interrupt
    23. {
    24. SSPISR();
    25.         PIR1bits.SSPIF = 0;  // Clear the interrupt flag
    26.     }
    27.    
    28. }
    29.  
    30. // This is the actual SSP ISR
    31. void SSPISR(void)
    32. {
    33.     PORTBbits.RB1=1;
    34.  
    35. }
    36.  
    37. void main(void)
    38. {
    39.  
    40. unsigned char sync_mode = SLAVE_7, slew = SLEW_OFF,slave_address = 0x08, clearBUF = 0;
    41. TRISA = 0b11111111;
    42. TRISB = 0b11000001;
    43. TRISC = 0b00011110;// configure SCL SDA as input
    44. PORTBbits.RB1 = 0;
    45. INTCONbits.GIEH = 0;
    46. RCONbits.IPEN = 1;          // Enable interrupt priorities
    47. IPR1bits.SSPIP = 1;         // Set SSP interrupt priority to high
    48. PIR1bits.SSPIF = 0;  // Clear the interrupt flag
    49. PIE1bits.SSPIE = 1;         // Enable SSP interrupt
    50. INTCONbits.GIEH = 1;
    51. SSPADD = 0x98;
    52. SSPCON1 = 0b00100110;
    53. SSPCON2 = 0b00000000;
    54. SSPBUF = clearBUF ;
    55.  
    56.  
    57. OpenI2C(SLAVE_7 , SLEW_OFF);
    58.  
    59. SSPCON1bits.CKP = 1;
    60. while(1);
    61. }
    62.  
    Master.c
    Code ( (Unknown Language)):
    1. #include <p18f4520.h>
    2. #include <delays.h>
    3. #include <i2c.h>
    4. unsigned char i2cPutByteAndWait(unsigned char);
    5.  
    6. char clearData = 0;
    7.  
    8. void main(void)
    9. {
    10. char address_w = 0x98, result = 0, temp = 0;
    11. SSPSTAT = 0xC0;
    12. SSPCON1 = 0x28;
    13. SSPCON2 = 0x00;
    14. SSPADD = 0x09;
    15. TRISC = 0b00000000;
    16. OpenI2C(MASTER, SLEW_OFF);
    17. StartI2C();
    18. IdleI2C();
    19. WriteI2C(address_w & 0xFE);
    20. IdleI2C();
    21. WriteI2C(0x01);
    22. IdleI2C();
    23.  
    24. SSPBUF = address_w;
    25. while(SSPSTATbits.BF);
    26. while((SSPCON2 & 0x1F) || (SSPSTAT & 0x04));
    27.  
    28. SSPCON2bits.PEN = 1;
    29. while(SSPCON2bits.PEN == 1);
    30. }
    31.  
     
  17. symphony888

    Thread Starter New Member

    May 5, 2014
    13
    0
    Anyone mind helping? I'm still stuck at this particular thing.
     
  18. ErnieM

    AAC Fanatic!

    Apr 24, 2011
    7,386
    1,605
    Besides a general comment not to put function calls inside an ISR nothing jumped out as wrong to me.

    Exactly what are you seeing, what is working, what is not working?
     
  19. symphony888

    Thread Starter New Member

    May 5, 2014
    13
    0
    I repatched the circuit. Only a PIC18F4520 and the needed stuffs for the I2C. No EEPROM and such, and still it didn't work.

    No start bit/stop bit is being produced at all.
     
  20. ErnieM

    AAC Fanatic!

    Apr 24, 2011
    7,386
    1,605
    OK, so the problem right now is in the master.

    Simplest thing first: do you have the I2C pull up resistors? 5K is typical. An unprogrammed (just bulk erase it) PIC should show these 2 pins as a high.

    Next, your code master does one write to the slave then stops. It's much easier to see a periodic repeating signal. I would make my test master as such:

    Code ( (Unknown Language)):
    1. #include <p18f4520.h>
    2. #include <delays.h>
    3. #include <i2c.h>
    4. unsigned char i2cPutByteAndWait(unsigned char);
    5. char clearData = 0;
    6. void main(void)
    7. {
    8.     char address_w = 0x98, result = 0, temp = 0;
    9.     SSPSTAT = 0xC0;
    10.     SSPCON1 = 0x28;
    11.     SSPCON2 = 0x00;
    12.     SSPADD = 0x09;
    13.     TRISC = 0b00000000;     // afaik the ports should be set as inputs
    14.                             // but OpenI2C does this for you.
    15.     while(1)    
    16.     {
    17.         OpenI2C(MASTER, SLEW_OFF);
    18.         StartI2C();
    19.         IdleI2C();
    20.         WriteI2C(address_w & 0xFE);
    21.         IdleI2C();
    22.         WriteI2C(0x01);
    23.         IdleI2C();
    24.  
    25.         SSPBUF = address_w;
    26.         while(SSPSTATbits.BF);
    27.         while((SSPCON2 & 0x1F) || (SSPSTAT & 0x04));
    28.  
    29.         SSPCON2bits.PEN = 1;        // StopI2C
    30.         // add a delay here to break up transmissions on your scope
    31.     }    
    32. //    while(SSPCON2bits.PEN == 1);
    33. }
    34.  
    Toggling an unused pin while transmitting gives your scope a synch to use. It's also a nice sanity test.

    (BTW, leaving the EEPROM would give you a 2nd slave to test the master's START/ADDR/STOP against. So it may have helped to have left it in.)
     
Loading...