(Solved) Pic18f452 to Pic18f4520 - can't get I2C to work - Page 1
Forum section: electronics / general

author: Puffie40
author_rank: Regular Contributor
timestamp: March 26, 2016, 08:39:59 pm
content: I'm trying to convert a I2C program written for the 452 to work on the 4520. So far, I've have not been able to get a serial LCD display to do anything, despite being able to print stuff before with the 452.The only thing I see microchip mentions about I2C in its conversion document is the MSSP module have to be completely idle before it receives I2C data. Since I'm just sending data at the moment, I dont think that applies, so I am left scratching my head.Any thoughts on what I need to do? It's a 4MHz oscillator and a 100khz bus speed.I'll share the code a little later as I'm on mobile.

author: Wilksey
author_rank: Super Contributor
timestamp: March 26, 2016, 10:25:03 pm
content: Possibly pin multiplexing, I am not sure what pins the I2C are on, but turn stuff like the ADC off (ANSELx)

author: Puffie40
author_rank: Regular Contributor
timestamp: March 27, 2016, 05:47:13 am
content: Code:// PIC18F4520 Configuration Bit Settings// 'C' source line config statements#include <xc.h>// #pragma config statements should precede project file includes.// Use project enums instead of #define for ON and OFF.// CONFIG1H#pragma config OSC = XT // Oscillator Selection bits (XT oscillator)#pragma config FCMEN = OFF // Fail-Safe Clock Monitor Enable bit (Fail-Safe Clock Monitor disabled)#pragma config IESO = OFF // Internal/External Oscillator Switchover bit (Oscillator Switchover mode disabled)// CONFIG2L#pragma config PWRT = OFF // Power-up Timer Enable bit (PWRT disabled)#pragma config BOREN = SBORDIS // Brown-out Reset Enable bits (Brown-out Reset enabled in hardware only (SBOREN is disabled))#pragma config BORV = 3 // Brown Out Reset Voltage bits (Minimum setting)// CONFIG2H#pragma config WDT = OFF // Watchdog Timer Enable bit (WDT disabled (control is placed on the SWDTEN bit))#pragma config WDTPS = 32768 // Watchdog Timer Postscale Select bits (1:32768)// CONFIG3H#pragma config CCP2MX = PORTBE // CCP2 MUX bit (CCP2 input/output is multiplexed with RB3)#pragma config PBADEN = OFF // PORTB A/D Enable bit (PORTB<4:0> pins are configured as digital I/O on Reset)#pragma config LPT1OSC = ON // Low-Power Timer1 Oscillator Enable bit (Timer1 configured for low-power operation)#pragma config MCLRE = ON // MCLR Pin Enable bit (MCLR pin enabled; RE3 input pin disabled)// CONFIG4L#pragma config STVREN = ON // Stack Full/Underflow Reset Enable bit (Stack full/underflow will cause Reset)#pragma config LVP = ON // Single-Supply ICSP Enable bit (Single-Supply ICSP enabled)#pragma config XINST = OFF // Extended Instruction Set Enable bit (Instruction set extension and Indexed Addressing mode disabled (Legacy mode))// CONFIG5L#pragma config CP0 = OFF // Code Protection bit (Block 0 (000800-001FFFh) not code-protected)#pragma config CP1 = OFF // Code Protection bit (Block 1 (002000-003FFFh) not code-protected)#pragma config CP2 = OFF // Code Protection bit (Block 2 (004000-005FFFh) not code-protected)#pragma config CP3 = OFF // Code Protection bit (Block 3 (006000-007FFFh) not code-protected)// CONFIG5H#pragma config CPB = OFF // Boot Block Code Protection bit (Boot block (000000-0007FFh) not code-protected)#pragma config CPD = OFF // Data EEPROM Code Protection bit (Data EEPROM not code-protected)// CONFIG6L#pragma config WRT0 = OFF // Write Protection bit (Block 0 (000800-001FFFh) not write-protected)#pragma config WRT1 = OFF // Write Protection bit (Block 1 (002000-003FFFh) not write-protected)#pragma config WRT2 = OFF // Write Protection bit (Block 2 (004000-005FFFh) not write-protected)#pragma config WRT3 = OFF // Write Protection bit (Block 3 (006000-007FFFh) not write-protected)// CONFIG6H#pragma config WRTC = OFF // Configuration Register Write Protection bit (Configuration registers (300000-3000FFh) not write-protected)#pragma config WRTB = OFF // Boot Block Write Protection bit (Boot block (000000-0007FFh) not write-protected)#pragma config WRTD = OFF // Data EEPROM Write Protection bit (Data EEPROM not write-protected)// CONFIG7L#pragma config EBTR0 = OFF // Table Read Protection bit (Block 0 (000800-001FFFh) not protected from table reads executed in other blocks)#pragma config EBTR1 = OFF // Table Read Protection bit (Block 1 (002000-003FFFh) not protected from table reads executed in other blocks)#pragma config EBTR2 = OFF // Table Read Protection bit (Block 2 (004000-005FFFh) not protected from table reads executed in other blocks)#pragma config EBTR3 = OFF // Table Read Protection bit (Block 3 (006000-007FFFh) not protected from table reads executed in other blocks)// CONFIG7H#pragma config EBTRB = OFF // Boot Block Table Read Protection bit (Boot block (000000-0007FFh) not protected from table reads executed in other blocks)#define _XTAL_FREQ 4000000// Defines crystal speed - 4MHZ#include <pic18f4520.h> // Header file for PIC18F4520//I2C Constants - EEPROM#define I2CEEPROM_WRITE 0x50//I2C Function declarationsvoid I2C_eepromwrite(char, char, char);unsigned char I2C_eepromread(char, char);void setup_I2C(void);void startbit_I2C(void);void stopbit_I2C(void);void restartbit_I2C(void);void writeeeprom_I2C(void);void readeeprom_I2C(void);unsigned char receive_I2C(void);void writememhigh_I2C(char);void writememlow_I2C(char);void writedata_I2C(char);char mydata= {"Hello World"};char text2 = {"this is a test"};char text3 = {"really lonnnnnnnnng text"};char text4 = {"Project Sunflower"};void main(void) {//main variablesunsigned char dataread = 0;unsigned char memhigh = 0x00;unsigned char memlow = 0xFF;unsigned char data = 0x88;//SetupTRISD = 0x00; //Set LEDs as outputsLATD = 0x00; //LED status = 0setup_I2C(); //initalize I2C on PIC18__delay_ms(100); //wait for I2C to set up//initalize LCDstartbit_I2C(); //I2C start bitLATD = 0x01; //LED status = 0writeeeprom_I2C();__delay_ms(2); //address displayLATD = 0x02; //LED status = 0writedata_I2C(0xFE);__delay_ms(2);LATD = 0x03;writedata_I2C(0x41); //Turn on displayLATD = 0x04;__delay_ms(2);LATD = 0x05;writedata_I2C(0xFE);LATD = 0x06;__delay_ms(2);LATD = 0x07;stopbit_I2C(); //I2C Stop bitLATD = 0x08; //LED status = 0__delay_ms(10); //wait for EEPROM to finish writingwhile(1);}void setup_I2C(void){TRISC = 0x00; //Set I2C ports as outputs.LATC = 0x00; //force PortC LowSSPSTAT &= 0x3F; //power on stateSSPCON1 = 0x00; //power on stateSSPCON2 = 0x00; //power on state//enable the serial port and configure SDA and SCL as serial port pinsSSPCON1 = 0x28; //select I2C ModeSSPADD = 0x08; //Sets BRG freq to 100kHz=(fosc/(4 *(SSPADD+1))SSPSTATbits.SMP = 1; //slew rate is disabled for 100kHz and 1MHz modesSSPCON2bits.ACKSTAT = 1; //Sets ACK Status to 1 making wait for an ACK.}void startbit_I2C(void){//I2C STARTSSPCON2bits.SEN = 1; //Generates the Start bitwhile (SSPCON2bits.SEN); //Waits for acknowlege__delay_ms(10);}void stopbit_I2C(void){PIR1bits.SSPIF = 0;SSPCON2bits.PEN = 1; //Generates the stop Bitwhile ((SSPCON2 & 0x1F)||(SSPSTATbits.R_W));__delay_ms(10);}void restartbit_I2C(void){SSPCON2bits.RSEN = 1; //Generates the restarted start bitwhile (SSPCON2bits.RSEN); //Waits for acknowlege}void writeeeprom_I2C(void){SSPBUF = I2CEEPROM_WRITE; //EEPROM Device address with R/W bitwhile (SSPSTATbits.BF); //Waits till write cycle is overwhile ((SSPCON2 & 0x1F)||(SSPSTATbits.R_W)); //Ensures bus is idlewhile (SSPCON2bits.ACKSTAT); //Waits for acknowlegeSSPCON2bits.ACKSTAT = 1;__delay_ms(10);}void readeeprom_I2C(void){SSPBUF = I2CEEPROM_READ; //Sends Device address with read command.while (SSPSTATbits.BF); //wait for end of write cycle.while ((SSPCON2 & 0x1F) || (SSPSTATbits.R_W));while (SSPCON2bits.ACKSTAT); //Waits for acknowlege}unsigned char receive_I2C(void){SSPCON2bits.RCEN = 1; //Enables receive modewhile (!SSPSTATbits.BF); //wait for the write operationreturn SSPBUF; //return SSPBUF to main function}void writememhigh_I2C(unsigned char memhigh){SSPBUF = memhigh; //EEPROM Low Memory Bytewhile (SSPSTATbits.BF); //Wait for write cycle completionwhile ((SSPCON2 & 0x1F) || (SSPSTATbits.R_W));while (SSPCON2bits.ACKSTAT); //Waits for acknowlege}void writememlow_I2C(unsigned char memlow){SSPBUF = memlow; //EEPROM Low Memory Bytewhile (SSPSTATbits.BF); //Wait for write cycle completionwhile ((SSPCON2 & 0x1F) || (SSPSTATbits.R_W));while (SSPCON2bits.ACKSTAT); //Waits for acknowlege}void writedata_I2C(unsigned char data){SSPBUF = data; //Sends low byte of EEPROM memory locationwhile (SSPSTATbits.BF); //wait till write cycle is completewhile ((SSPCON2 & 0x1F)||(SSPSTATbits.R_W));while (SSPCON2bits.ACKSTAT); //Waits for acknowlege__delay_ms(10);}C3 is the clock and C4 is the data. The code originally used a EEPROM, hence the references in the function names.There is an 4520 errata (http://ww1.microchip.com/downloads/en/DeviceDoc/80209h.pdf) that had a bunch of notes about I2C Transmission, but none that proved useful in getting the screen to show anything.

author: ade
author_rank: Unknown
timestamp: March 27, 2016, 09:36:33 am
content: Hmm, first thing to do I guess is to verify the correct I2C address (I2CEEPROM_WRITE define). 0x50 is address 0x28 in write mode. Is that the right address?It looks like you are sending a command to turn on the LCD but then that's it. Actually you then send half a command (0xFE) followed by nothing else. Was this intended? The LCD should turn on but nothing will show up on the screen.If the address is correct then maybe start by stepping through void writeeeprom_I2C() via the debugger. Does it get through the acknowledgement without error or does it get stuck in one of the while loops?I've found debugging I2C is much easier if you have an oscilloscope to see what's being sent & received. Do you have appropriate pull-up resistors on the clock & data lines?

author: dannyf
author_rank: Super Contributor
timestamp: March 27, 2016, 01:58:26 pm
content: you have some diagnostic lights to help you and they should tell you where your code execution is stuck. Go from there.In debugging, don't assume anything: the hardest bugs tend to be the ones you are most confident of. So if I were you, I would start from the set-up portion of the code - compare it to the datasheet and ....

author: Puffie40
author_rank: Regular Contributor
timestamp: March 27, 2016, 09:09:05 pm
content: QuoteThe default address of the display is 0x50, from the datasheet. The display sends no data, so a receive mode is not needed.Yes, it was intended. The first command is 0xFE and 0X41, which is supposed to initialize the display. after that, I just need to send the ASCII number of the character to get it to display. in the code right now, it just sends a capital A to the display.here is the datasheet for the display if you're curious:http://www.newhavendisplay.com/specs/NHD-0420D3Z-FL-GBW-V3.pdfThe display also has pullup resistors right on it, so there is no problem there.Quote from: dannyf on March 27, 2016, 01:58:26 pmThat's the frustrating part - the lights flash through the sequence just fine, so the code is not sticking anywhere. I'm fairly certain it is a configuration issue, as if I put a 452 into the board and change out the configuration bits in the code to work with the 452, the code works.

author: dannyf
author_rank: Super Contributor
timestamp: March 27, 2016, 11:25:11 pm
content: QuoteIt is generally a bad strategy to "assume", at least without verification, that something is working. If anything, start from the very basic, question what you are most confident of, and go down from there.For example, does the set-up work? can you blink an led? ....What I can say with 100% confidence (because I have tried it myself,) is that configuration is NOT your problem: I have a working set of your code running with your configuration set-up, as is, on a 4520 and a 452.QuoteUnless you have compiled the code under some vastly different compiler, that code you posted will hang just as quickly on the 452 as it does on the 4520.

author: ade
author_rank: Unknown
timestamp: March 28, 2016, 02:42:05 am
content: QuoteHmm, that is not in the code posted above. The code sends 0xFE 0x41 0xFE, which will not produce a capital A.QuoteShouldn't this be 0x09? (4 MHz / (4 * (9 + 1)) = 100 kHz.

author: Puffie40
author_rank: Regular Contributor
timestamp: March 28, 2016, 06:52:13 pm
content: QuoteOhhh, you are right! Capital A should be 0x41.QuoteYes, but I was going by a note in the errata mentioned above that another formula should be used instead for I2C Master:(SSPADD = INT((FCY/FSCL) - (FCY/1.111 MHz)) - 1) where FCY=1MHz and FSCL=100khz. I get 8.1, which I rounded to 8.QuoteI'm using MPLABX 2.05 with the XC8 compiler, and it compiles with no complaints. did you have to modify the code any to get it to work?A Couple of things I have done last night:-Tested port C on the LEDs to confirm the 4520 was actually putting out voltage on C3 and C4-put some stop loops into the code to see if WCOL was being set after an operation. Code cycles fine.-checked and rechecked the values of SSPCON1, SSPCON2 and SSPSTAT.

author: ade
author_rank: Unknown
timestamp: March 28, 2016, 08:34:24 pm
content: Puffie that particular errata is for very old chips (manufactured prior to 2009) so unless you have old stock it may not apply to you. You should be able to check your chip's revision ID from MPLAB.As mentioned before, it's hard -- for me anyway -- to debug tricky I2C problems without an oscilloscope or logic analyzer (or a bus pirate). It's helpful to see what (if anything) is actually being output by the master, if an ACK is being returned by the slave, etc.; as well as the levels, timing, and quality of the I2C signal. I chased an I2C problem for hours until hooking it up to a scope immediately showed poor signaling which was traced back to incorrect pull-up resistors being installed by the manufacturer.If you have a PICKit 2 or 3 it can be used as a simple logic analyzer. Or you can even make a simple one out of a spare PIC.

author: nomadd
author_rank: Contributor
timestamp: March 29, 2016, 12:45:29 pm
content: Quote from: Puffie40 on March 28, 2016, 06:52:13 pmHaving spent most of the weekend wrestling with I2C on PIC18's, I feel your pain.Seriously, as others have suggested, get yourself a cheap LA. Without one, I would have been totally screwed in my troubleshooting.Mine cost less than £10, and works fine with the excellent Saleae software. The I2C decode is excellent and clearly marks data, clock, start, restart and stop events on the trace. Data direction for Read and Write is also clearly marked; you can also view the actual data in a variety of formats. It helped me debug both the sending and receiving of I2C traffic, and without it I would have been lost. If Saleae's hardware was reasonable cost, I'd even have no problem handing over cash to them for their efforts..but that's a different topic already done to death.

author: Ice-Tea
author_rank: Super Contributor
timestamp: March 29, 2016, 01:41:27 pm
content: From a HW point of view: I²C requires pullups. You might assume the PIC has them(or can be configured to have them) but suggest you verify this if you haven't implemented them physically yourself.

author: nomadd
author_rank: Contributor
timestamp: March 29, 2016, 04:13:19 pm
content: Quote from: Ice-Tea on March 29, 2016, 01:41:27 pmWhich brings one more thought to mind..OP: Did you hard-wire the address for your target correctly? Pulling all the address pins to ground will give your device an address of 0. Just make sure that's the address you target in your code.

author: Howardlong
author_rank: Super Contributor
timestamp: March 29, 2016, 05:29:02 pm
content: I breadboarded your setup on a pic18f2620 (similar chip but with more memory, 28pin rather than 40, most importantly the same MSSP peripheral).You don't need to #include the PIC header file in XC8, the xc.h will do that for you. I got a ton of redefine errors with it included.Also you have incorrectly specified the EEPROM write and haven't mentioned the EEPROM read in your code.Code:#define _XTAL_FREQ 4000000// Defines crystal speed - 4MHZ//#include <pic18f4520.h> // Header file for PIC18F4520//I2C Constants - EEPROM#define I2CEEPROM_WRITE 0xA0#define I2CEEPROM_READ 0xA1When I ran your code with the above changes, you're setting RC3 and RC4 to outputs. You need to set them to inputs.Section 17.4.2 of the datasheet:QuoteI commented out the two lines below and put in the TRISC=0x18;Code:void setup_I2C(void){// TRISC = 0x00; //Set I2C ports as outputs.TRISC = 0x18; //RC3/SCL=input, RC4/SDA=input.// LATC = 0x00; //force PortC LowSSPSTAT &= 0x3F; //power on stateSSPCON1 = 0x00; //power on stateSSPCON2 = 0x00; //power on stateI used an MSO, I'd fixed it within five minutes of wiring it up ;-) so in short get yourself an LA and/or a scope. The scope is good for checking your oscillator's running, the second thing to check after you check your power on an MCU before you even try to do a blinky ;-).The complete modified code (with LATB instead of LATD due to my chip not having LATD)Code:// PIC18F4520 Configuration Bit Settings// 'C' source line config statements#include <xc.h>// #pragma config statements should precede project file includes.// Use project enums instead of #define for ON and OFF.// CONFIG1H#pragma config OSC = XT // Oscillator Selection bits (XT oscillator)#pragma config FCMEN = OFF // Fail-Safe Clock Monitor Enable bit (Fail-Safe Clock Monitor disabled)#pragma config IESO = OFF // Internal/External Oscillator Switchover bit (Oscillator Switchover mode disabled)// CONFIG2L#pragma config PWRT = OFF // Power-up Timer Enable bit (PWRT disabled)#pragma config BOREN = SBORDIS // Brown-out Reset Enable bits (Brown-out Reset enabled in hardware only (SBOREN is disabled))#pragma config BORV = 3 // Brown Out Reset Voltage bits (Minimum setting)// CONFIG2H#pragma config WDT = OFF // Watchdog Timer Enable bit (WDT disabled (control is placed on the SWDTEN bit))#pragma config WDTPS = 32768 // Watchdog Timer Postscale Select bits (1:32768)// CONFIG3H#pragma config CCP2MX = PORTBE // CCP2 MUX bit (CCP2 input/output is multiplexed with RB3)#pragma config PBADEN = OFF // PORTB A/D Enable bit (PORTB<4:0> pins are configured as digital I/O on Reset)#pragma config LPT1OSC = ON // Low-Power Timer1 Oscillator Enable bit (Timer1 configured for low-power operation)#pragma config MCLRE = ON // MCLR Pin Enable bit (MCLR pin enabled; RE3 input pin disabled)// CONFIG4L#pragma config STVREN = ON // Stack Full/Underflow Reset Enable bit (Stack full/underflow will cause Reset)#pragma config LVP = ON // Single-Supply ICSP Enable bit (Single-Supply ICSP enabled)#pragma config XINST = OFF // Extended Instruction Set Enable bit (Instruction set extension and Indexed Addressing mode disabled (Legacy mode))// CONFIG5L#pragma config CP0 = OFF // Code Protection bit (Block 0 (000800-001FFFh) not code-protected)#pragma config CP1 = OFF // Code Protection bit (Block 1 (002000-003FFFh) not code-protected)#pragma config CP2 = OFF // Code Protection bit (Block 2 (004000-005FFFh) not code-protected)#pragma config CP3 = OFF // Code Protection bit (Block 3 (006000-007FFFh) not code-protected)// CONFIG5H#pragma config CPB = OFF // Boot Block Code Protection bit (Boot block (000000-0007FFh) not code-protected)#pragma config CPD = OFF // Data EEPROM Code Protection bit (Data EEPROM not code-protected)// CONFIG6L#pragma config WRT0 = OFF // Write Protection bit (Block 0 (000800-001FFFh) not write-protected)#pragma config WRT1 = OFF // Write Protection bit (Block 1 (002000-003FFFh) not write-protected)#pragma config WRT2 = OFF // Write Protection bit (Block 2 (004000-005FFFh) not write-protected)#pragma config WRT3 = OFF // Write Protection bit (Block 3 (006000-007FFFh) not write-protected)// CONFIG6H#pragma config WRTC = OFF // Configuration Register Write Protection bit (Configuration registers (300000-3000FFh) not write-protected)#pragma config WRTB = OFF // Boot Block Write Protection bit (Boot block (000000-0007FFh) not write-protected)#pragma config WRTD = OFF // Data EEPROM Write Protection bit (Data EEPROM not write-protected)// CONFIG7L#pragma config EBTR0 = OFF // Table Read Protection bit (Block 0 (000800-001FFFh) not protected from table reads executed in other blocks)#pragma config EBTR1 = OFF // Table Read Protection bit (Block 1 (002000-003FFFh) not protected from table reads executed in other blocks)#pragma config EBTR2 = OFF // Table Read Protection bit (Block 2 (004000-005FFFh) not protected from table reads executed in other blocks)#pragma config EBTR3 = OFF // Table Read Protection bit (Block 3 (006000-007FFFh) not protected from table reads executed in other blocks)// CONFIG7H#pragma config EBTRB = OFF // Boot Block Table Read Protection bit (Boot block (000000-0007FFh) not protected from table reads executed in other blocks)#define _XTAL_FREQ 4000000// Defines crystal speed - 4MHZ//#include <pic18f4520.h> // Header file for PIC18F4520//I2C Constants - EEPROM#define I2CEEPROM_WRITE 0xA0#define I2CEEPROM_READ 0xA1//I2C Function declarationsvoid I2C_eepromwrite(char, char, char);unsigned char I2C_eepromread(char, char);void setup_I2C(void);void startbit_I2C(void);void stopbit_I2C(void);void restartbit_I2C(void);void writeeeprom_I2C(void);void readeeprom_I2C(void);unsigned char receive_I2C(void);void writememhigh_I2C(char);void writememlow_I2C(char);void writedata_I2C(char);char mydata= {"Hello World"};char text2 = {"this is a test"};char text3 = {"really lonnnnng text"};char text4 = {"Project Sunflower"};void main(void) {//main variablesunsigned char dataread = 0;unsigned char memhigh = 0x00;unsigned char memlow = 0xFF;unsigned char data = 0x88;//SetupTRISB = 0x00; //Set LEDs as outputsLATB = 0x00; //LED status = 0setup_I2C(); //initalize I2C on PIC18__delay_ms(100); //wait for I2C to set up//initalize LCDstartbit_I2C(); //I2C start bitLATB = 0x01; //LED status = 0writeeeprom_I2C();__delay_ms(2); //address displayLATB = 0x02; //LED status = 0writedata_I2C(0xFE);__delay_ms(2);LATB = 0x03;writedata_I2C(0x41); //Turn on displayLATB = 0x04;__delay_ms(2);LATB = 0x05;writedata_I2C(0xFE);LATB = 0x06;__delay_ms(2);LATB = 0x07;stopbit_I2C(); //I2C Stop bitLATB = 0x08; //LED status = 0__delay_ms(10); //wait for EEPROM to finish writingwhile(1);}void setup_I2C(void){// TRISC = 0x00; //Set I2C ports as outputs.TRISC = 0x18; //RC3/SCL=input, RC4/SDA=input.// LATC = 0x00; //force PortC LowSSPSTAT &= 0x3F; //power on stateSSPCON1 = 0x00; //power on stateSSPCON2 = 0x00; //power on state//enable the serial port and configure SDA and SCL as serial port pinsSSPCON1 = 0x28; //select I2C ModeSSPADD = 0x08; //Sets BRG freq to 100kHz=(fosc/(4 *(SSPADD+1))SSPSTATbits.SMP = 1; //slew rate is disabled for 100kHz and 1MHz modesSSPCON2bits.ACKSTAT = 1; //Sets ACK Status to 1 making wait for an ACK.}void startbit_I2C(void){//I2C STARTSSPCON2bits.SEN = 1; //Generates the Start bitwhile (SSPCON2bits.SEN); //Waits for acknowlege__delay_ms(10);}void stopbit_I2C(void){PIR1bits.SSPIF = 0;SSPCON2bits.PEN = 1; //Generates the stop Bitwhile ((SSPCON2 & 0x1F)||(SSPSTATbits.R_W));__delay_ms(10);}void restartbit_I2C(void){SSPCON2bits.RSEN = 1; //Generates the restarted start bitwhile (SSPCON2bits.RSEN); //Waits for acknowlege}void writeeeprom_I2C(void){SSPBUF = I2CEEPROM_WRITE; //EEPROM Device address with R/W bitwhile (SSPSTATbits.BF); //Waits till write cycle is overwhile ((SSPCON2 & 0x1F)||(SSPSTATbits.R_W)); //Ensures bus is idlewhile (SSPCON2bits.ACKSTAT); //Waits for acknowlegeSSPCON2bits.ACKSTAT = 1;__delay_ms(10);}void readeeprom_I2C(void){SSPBUF = I2CEEPROM_READ; //Sends Device address with read command.while (SSPSTATbits.BF); //wait for end of write cycle.while ((SSPCON2 & 0x1F) || (SSPSTATbits.R_W));while (SSPCON2bits.ACKSTAT); //Waits for acknowlege}unsigned char receive_I2C(void){SSPCON2bits.RCEN = 1; //Enables receive modewhile (!SSPSTATbits.BF); //wait for the write operationreturn SSPBUF; //return SSPBUF to main function}void writememhigh_I2C(unsigned char memhigh){SSPBUF = memhigh; //EEPROM Low Memory Bytewhile (SSPSTATbits.BF); //Wait for write cycle completionwhile ((SSPCON2 & 0x1F) || (SSPSTATbits.R_W));while (SSPCON2bits.ACKSTAT); //Waits for acknowlege}void writememlow_I2C(unsigned char memlow){SSPBUF = memlow; //EEPROM Low Memory Bytewhile (SSPSTATbits.BF); //Wait for write cycle completionwhile ((SSPCON2 & 0x1F) || (SSPSTATbits.R_W));while (SSPCON2bits.ACKSTAT); //Waits for acknowlege}void writedata_I2C(unsigned char data){SSPBUF = data; //Sends low byte of EEPROM memory locationwhile (SSPSTATbits.BF); //wait till write cycle is completewhile ((SSPCON2 & 0x1F)||(SSPSTATbits.R_W));while (SSPCON2bits.ACKSTAT); //Waits for acknowlege__delay_ms(10);}

author: Wilksey
author_rank: Super Contributor
timestamp: March 29, 2016, 09:42:55 pm
content: Top job Howard!You won't get a more complete response than that, and not many people (on other forums) would go to the trouble of breadboarding it for you either!

author: Puffie40
author_rank: Regular Contributor
timestamp: March 30, 2016, 06:33:11 am
content: Thank you very much, Howard, for the breadboarding! I adjusted those two bits and the LCD display started working!I just went on ebay and got myself a USB Logic analyzer, so that should help me immensely in the future.

author: Howardlong
author_rank: Super Contributor
timestamp: March 30, 2016, 09:46:30 am
content: Well I'm glad it worked.I've been doing PICs for a very long time, indeed my lineage goes back to the General Instrument days in the 70s. Inevitably over the years I have accumulated a modest but reasonable stock of bits and pieces for PICs of all shapes an sizes, from PIC10 to PIC32MZ EF. They all have their own quirks, and although there is some similarity or peripherals and functionality between devices, there are plenty of differences too. I've lost count of the number of PIC projects I've worked on, but it's well into triple figures, and there's no way my memory is good enough to remember all the differences.Because of those differences, unless you happened to have fairly recent experience, it's unlikely that without the benefit of a data sheet you'd come up with a solution off the top of your head, however I did remember that for some peripherals on some devices like MSSP you need to set up TRIS correctly, but I couldn't remember exactly how.To breadboard something simple like this up takes me about ten minutes: in fact, it took far longer to write the reply than it did to breadboard it up and figure out a fix, but that's just experience and having the right tools.Back in the early/mid '80s when I first used I2C as a student, my sum total of test equipment amounted to a crappy 1k ohm/volt analogue multimeter, an LED+resistor and a home brew logic probe (a retriggerable monostable ~100ms pulse stretcher). With a healthy dose of imagination, you can do an awful lot with those simple tools, but debugging I2C in any depth, not so much. Back then, we didn't have the luxury of on-chip in circuit debugging on an MCU either, that was still about fifteen years away, but you could spend an arm an a leg on an external hardware in-circuit emulator.Nowadays in real terms, you can pick up a reasonable 2nd hand CRO for the same as I paid for my multimeter!While it's possible to debug your problem with very rudimentary tools and a reasonable amount of creativity, in view of the almost obscene cheapness of some tools available nowadays where the retail cost is frequently less the the BOM cost, you'd be nuts to want to beat yourself up. As a caveat to that I would say that doing it the hard way you will inevitably learn a lot more, mostly by gaining a far deeper and granular understanding, as well as dramatically improving your troubleshooting and analytical skills.Again, thank you for your kind comments, but it wasn't much effort: I like to take these opportunities to keep my own skills polished.

author: dannyf
author_rank: Super Contributor
timestamp: March 30, 2016, 10:56:05 am
content: Quotethis goes to what I said earlier: there is no way this exact piece of code could have run on a 452.