Author Topic: (Solved) Pic18f452 to Pic18f4520 - can't get I2C to work  (Read 5044 times)

0 Members and 1 Guest are viewing this topic.

Offline Puffie40Topic starter

  • Regular Contributor
  • *
  • Posts: 54
  • Country: ca
  • Irregular Logic
(Solved) Pic18f452 to Pic18f4520 - can't get I2C to work
« on: March 26, 2016, 08:39:59 pm »
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.
« Last Edit: April 04, 2016, 05:39:22 pm by Puffie40 »
 

Offline Wilksey

  • Super Contributor
  • ***
  • Posts: 1329
Re: Pic18f452 to Pic18f4520 - can't get I2C to work
« Reply #1 on: March 26, 2016, 10:25:03 pm »
Possibly pin multiplexing, I am not sure what pins the I2C are on, but turn stuff like the ADC off (ANSELx)
 

Offline Puffie40Topic starter

  • Regular Contributor
  • *
  • Posts: 54
  • Country: ca
  • Irregular Logic
Re: Pic18f452 to Pic18f4520 - can't get I2C to work
« Reply #2 on: March 27, 2016, 05:47:13 am »
Code: [Select]
// 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 declarations
void 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[20]= {"Hello World"};
char text2[20] = {"this is a test"};
char text3[20] = {"really lonnnnnnnnng text"};
char text4[20] = {"Project Sunflower"};

void main(void) {

    //main variables
    unsigned char dataread = 0;
    unsigned char memhigh = 0x00;
    unsigned char memlow = 0xFF;
    unsigned char data = 0x88;

    //Setup
    TRISD = 0x00;               //Set LEDs as outputs
    LATD = 0x00;                //LED status = 0
    setup_I2C();                //initalize I2C on PIC18
    __delay_ms(100);            //wait for I2C to set up

    //initalize LCD
    startbit_I2C();             //I2C start bit
    LATD = 0x01;                //LED status = 0

    writeeeprom_I2C();
    __delay_ms(2);          //address display
    LATD = 0x02;                //LED status = 0

    writedata_I2C(0xFE);
    __delay_ms(2);
    LATD = 0x03;               
    writedata_I2C(0x41);        //Turn on display
    LATD = 0x04;               
    __delay_ms(2);
    LATD = 0x05;               

    writedata_I2C(0xFE);
    LATD = 0x06;               
    __delay_ms(2);
    LATD = 0x07;               

      stopbit_I2C();              //I2C Stop bit
      LATD = 0x08;                //LED status = 0
    __delay_ms(10);             //wait for EEPROM to finish writing
    while(1);
}





void setup_I2C(void){
    TRISC = 0x00;       //Set I2C ports as outputs.
    LATC = 0x00;        //force PortC Low

    SSPSTAT &= 0x3F;    //power on state
    SSPCON1 = 0x00;     //power on state
    SSPCON2 = 0x00;     //power on state

   
    //enable the serial port and configure SDA and SCL as serial port pins
    SSPCON1 = 0x28;             //select I2C Mode
    SSPADD = 0x08;              //Sets BRG freq to 100kHz=(fosc/(4 *(SSPADD+1))
    SSPSTATbits.SMP = 1;    //slew rate is disabled for 100kHz and 1MHz modes
    SSPCON2bits.ACKSTAT = 1;    //Sets ACK Status to 1 making wait for an ACK.
}

void startbit_I2C(void){
    //I2C START
    SSPCON2bits.SEN = 1;            //Generates the Start bit
    while (SSPCON2bits.SEN);        //Waits for acknowlege
    __delay_ms(10);
}

void stopbit_I2C(void){
    PIR1bits.SSPIF = 0;
    SSPCON2bits.PEN = 1;            //Generates the stop Bit
    while ((SSPCON2 & 0x1F)||(SSPSTATbits.R_W));
    __delay_ms(10);
}

void restartbit_I2C(void){
    SSPCON2bits.RSEN = 1;           //Generates the restarted start bit
    while (SSPCON2bits.RSEN);       //Waits for acknowlege
}

void writeeeprom_I2C(void){
    SSPBUF = I2CEEPROM_WRITE;       //EEPROM Device address with R/W bit
    while (SSPSTATbits.BF);         //Waits till write cycle is over
    while ((SSPCON2 & 0x1F)||(SSPSTATbits.R_W)); //Ensures bus is idle
    while (SSPCON2bits.ACKSTAT);    //Waits for acknowlege
    SSPCON2bits.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 mode
    while (!SSPSTATbits.BF);        //wait for the write operation
    return SSPBUF;                  //return SSPBUF to main function
}

void writememhigh_I2C(unsigned char memhigh){
    SSPBUF = memhigh;               //EEPROM Low Memory Byte
    while (SSPSTATbits.BF);         //Wait for write cycle completion
    while ((SSPCON2 & 0x1F) || (SSPSTATbits.R_W));
    while (SSPCON2bits.ACKSTAT);    //Waits for acknowlege
}

void writememlow_I2C(unsigned char memlow){
    SSPBUF = memlow;                //EEPROM Low Memory Byte
    while (SSPSTATbits.BF);         //Wait for write cycle completion
    while ((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 location
    while (SSPSTATbits.BF);         //wait till write cycle is complete
    while ((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.
« Last Edit: March 27, 2016, 05:55:03 am by Puffie40 »
 

Offline ade

  • Supporter
  • ****
  • Posts: 231
  • Country: ca
Re: Pic18f452 to Pic18f4520 - can't get I2C to work
« Reply #3 on: March 27, 2016, 09:36:33 am »
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?

 

Offline dannyf

  • Super Contributor
  • ***
  • Posts: 8221
  • Country: 00
Re: Pic18f452 to Pic18f4520 - can't get I2C to work
« Reply #4 on: March 27, 2016, 01:58:26 pm »
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 ....
================================
https://dannyelectronics.wordpress.com/
 

Offline Puffie40Topic starter

  • Regular Contributor
  • *
  • Posts: 54
  • Country: ca
  • Irregular Logic
Re: Pic18f452 to Pic18f4520 - can't get I2C to work
« Reply #5 on: March 27, 2016, 09:09:05 pm »
Quote
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.

The 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.pdf

The display also has pullup resistors right on it, so there is no problem there.

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 ....

That'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.
« Last Edit: March 27, 2016, 09:14:32 pm by Puffie40 »
 

Offline dannyf

  • Super Contributor
  • ***
  • Posts: 8221
  • Country: 00
Re: Pic18f452 to Pic18f4520 - can't get I2C to work
« Reply #6 on: March 27, 2016, 11:25:11 pm »
Quote
I'm fairly certain it is a configuration issue,

It 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.

Quote
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.

Unless 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.
================================
https://dannyelectronics.wordpress.com/
 

Offline ade

  • Supporter
  • ****
  • Posts: 231
  • Country: ca
Re: Pic18f452 to Pic18f4520 - can't get I2C to work
« Reply #7 on: March 28, 2016, 02:42:05 am »
Quote
in the code right now, it just sends a capital A to the display.
Hmm, that is not in the code posted above.  The code sends 0xFE 0x41 0xFE, which will not produce a capital A.

Quote
SSPADD = 0x08;              //Sets BRG freq to 100kHz=(fosc/(4 *(SSPADD+1))
Shouldn't this be 0x09?   (4 MHz / (4 * (9 + 1)) = 100 kHz.
 

Offline Puffie40Topic starter

  • Regular Contributor
  • *
  • Posts: 54
  • Country: ca
  • Irregular Logic
Re: Pic18f452 to Pic18f4520 - can't get I2C to work
« Reply #8 on: March 28, 2016, 06:52:13 pm »
Quote
Hmm, that is not in the code posted above.  The code sends 0xFE 0x41 0xFE, which will not produce a capital A.
:-[ Ohhh, you are right!  Capital A should be 0x41.

Quote
Quote
SSPADD = 0x08;              //Sets BRG freq to 100kHz=(fosc/(4 *(SSPADD+1))
Shouldn't this be 0x09?   (4 MHz / (4 * (9 + 1)) = 100 kHz.
Yes, 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.

Quote
Unless 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.

I'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. 
 

Offline ade

  • Supporter
  • ****
  • Posts: 231
  • Country: ca
Re: Pic18f452 to Pic18f4520 - can't get I2C to work
« Reply #9 on: March 28, 2016, 08:34:24 pm »
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.
 

Offline nomadd

  • Contributor
  • Posts: 25
  • Country: gb
Re: Pic18f452 to Pic18f4520 - can't get I2C to work
« Reply #10 on: March 29, 2016, 12:45:29 pm »

-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.

Having 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.



« Last Edit: March 29, 2016, 12:47:26 pm by nomadd »
 

Offline Ice-Tea

  • Super Contributor
  • ***
  • Posts: 3070
  • Country: be
    • Freelance Hardware Engineer
Re: Pic18f452 to Pic18f4520 - can't get I2C to work
« Reply #11 on: March 29, 2016, 01:41:27 pm »
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.

Offline nomadd

  • Contributor
  • Posts: 25
  • Country: gb
Re: Pic18f452 to Pic18f4520 - can't get I2C to work
« Reply #12 on: March 29, 2016, 04:13:19 pm »
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.

Which 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.
 

Offline Howardlong

  • Super Contributor
  • ***
  • Posts: 5319
  • Country: gb
Re: Pic18f452 to Pic18f4520 - can't get I2C to work
« Reply #13 on: March 29, 2016, 05:29:02 pm »
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: [Select]
#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

When 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:

Quote
Selection of any I2C mode, with the SSPEN bit set,
forces the SCL and SDA pins to be open-drain,
provided these pins are programmed to inputs by
setting the appropriate TRISC bits
. To ensure proper
operation of the module, pull-up resistors must be
provided externally to the SCL and SDA pins.

I commented out the two lines below and put in the TRISC=0x18;

Code: [Select]
void setup_I2C(void){
//    TRISC = 0x00;       //Set I2C ports as outputs.
    TRISC = 0x18;       //RC3/SCL=input, RC4/SDA=input.
//    LATC = 0x00;        //force PortC Low

    SSPSTAT &= 0x3F;    //power on state
    SSPCON1 = 0x00;     //power on state
    SSPCON2 = 0x00;     //power on state

I 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: [Select]

// 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 declarations
void 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[20]= {"Hello World"};
char text2[20] = {"this is a test"};
char text3[20] = {"really lonnnnng text"};
char text4[20] = {"Project Sunflower"};

void main(void) {

    //main variables
    unsigned char dataread = 0;
    unsigned char memhigh = 0x00;
    unsigned char memlow = 0xFF;
    unsigned char data = 0x88;

    //Setup
    TRISB = 0x00;               //Set LEDs as outputs
    LATB = 0x00;                //LED status = 0
    setup_I2C();                //initalize I2C on PIC18
    __delay_ms(100);            //wait for I2C to set up

    //initalize LCD
    startbit_I2C();             //I2C start bit
    LATB = 0x01;                //LED status = 0

    writeeeprom_I2C();
    __delay_ms(2);          //address display
    LATB = 0x02;                //LED status = 0

    writedata_I2C(0xFE);
    __delay_ms(2);
    LATB = 0x03;               
    writedata_I2C(0x41);        //Turn on display
    LATB = 0x04;               
    __delay_ms(2);
    LATB = 0x05;               

    writedata_I2C(0xFE);
    LATB = 0x06;               
    __delay_ms(2);
    LATB = 0x07;               

      stopbit_I2C();              //I2C Stop bit
      LATB = 0x08;                //LED status = 0
    __delay_ms(10);             //wait for EEPROM to finish writing
    while(1);
}





void setup_I2C(void){
//    TRISC = 0x00;       //Set I2C ports as outputs.
    TRISC = 0x18;       //RC3/SCL=input, RC4/SDA=input.
//    LATC = 0x00;        //force PortC Low

    SSPSTAT &= 0x3F;    //power on state
    SSPCON1 = 0x00;     //power on state
    SSPCON2 = 0x00;     //power on state

   
    //enable the serial port and configure SDA and SCL as serial port pins
    SSPCON1 = 0x28;             //select I2C Mode
    SSPADD = 0x08;              //Sets BRG freq to 100kHz=(fosc/(4 *(SSPADD+1))
    SSPSTATbits.SMP = 1;    //slew rate is disabled for 100kHz and 1MHz modes
    SSPCON2bits.ACKSTAT = 1;    //Sets ACK Status to 1 making wait for an ACK.
}

void startbit_I2C(void){
    //I2C START
    SSPCON2bits.SEN = 1;            //Generates the Start bit
    while (SSPCON2bits.SEN);        //Waits for acknowlege
    __delay_ms(10);
}

void stopbit_I2C(void){
    PIR1bits.SSPIF = 0;
    SSPCON2bits.PEN = 1;            //Generates the stop Bit
    while ((SSPCON2 & 0x1F)||(SSPSTATbits.R_W));
    __delay_ms(10);
}

void restartbit_I2C(void){
    SSPCON2bits.RSEN = 1;           //Generates the restarted start bit
    while (SSPCON2bits.RSEN);       //Waits for acknowlege
}

void writeeeprom_I2C(void){
    SSPBUF = I2CEEPROM_WRITE;       //EEPROM Device address with R/W bit
    while (SSPSTATbits.BF);         //Waits till write cycle is over
    while ((SSPCON2 & 0x1F)||(SSPSTATbits.R_W)); //Ensures bus is idle
    while (SSPCON2bits.ACKSTAT);    //Waits for acknowlege
    SSPCON2bits.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 mode
    while (!SSPSTATbits.BF);        //wait for the write operation
    return SSPBUF;                  //return SSPBUF to main function
}

void writememhigh_I2C(unsigned char memhigh){
    SSPBUF = memhigh;               //EEPROM Low Memory Byte
    while (SSPSTATbits.BF);         //Wait for write cycle completion
    while ((SSPCON2 & 0x1F) || (SSPSTATbits.R_W));
    while (SSPCON2bits.ACKSTAT);    //Waits for acknowlege
}

void writememlow_I2C(unsigned char memlow){
    SSPBUF = memlow;                //EEPROM Low Memory Byte
    while (SSPSTATbits.BF);         //Wait for write cycle completion
    while ((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 location
    while (SSPSTATbits.BF);         //wait till write cycle is complete
    while ((SSPCON2 & 0x1F)||(SSPSTATbits.R_W));
    while (SSPCON2bits.ACKSTAT);    //Waits for acknowlege
    __delay_ms(10);
}



« Last Edit: March 29, 2016, 05:39:32 pm by Howardlong »
 

Offline Wilksey

  • Super Contributor
  • ***
  • Posts: 1329
Re: Pic18f452 to Pic18f4520 - can't get I2C to work
« Reply #14 on: March 29, 2016, 09:42:55 pm »
 :-+ 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!
 

Offline Puffie40Topic starter

  • Regular Contributor
  • *
  • Posts: 54
  • Country: ca
  • Irregular Logic
Re: Pic18f452 to Pic18f4520 - can't get I2C to work
« Reply #15 on: March 30, 2016, 06:33:11 am »
 :-+ 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.
 

Offline Howardlong

  • Super Contributor
  • ***
  • Posts: 5319
  • Country: gb
Re: Pic18f452 to Pic18f4520 - can't get I2C to work
« Reply #16 on: March 30, 2016, 09:46:30 am »
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.
 

Offline dannyf

  • Super Contributor
  • ***
  • Posts: 8221
  • Country: 00
Re: Pic18f452 to Pic18f4520 - can't get I2C to work
« Reply #17 on: March 30, 2016, 10:56:05 am »
Quote
I adjusted those two bits and the LCD display started working!

this goes to what I said earlier: there is no way this exact piece of code could have run on a 452.
================================
https://dannyelectronics.wordpress.com/
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf