Author Topic: == I2C C Source Code ==  (Read 32427 times)

modtro2

  • Administrator
  • Hero Member
  • *****
  • Posts: 564
    • View Profile
== I2C C Source Code ==
« on: November 27, 2006, 08:13:57 PM »
The Modtronix LCD2S family of Serial LCD Displays can be configured to communicate via the I2C or SPI (mode 0) protocol. To use the I2C mode, both switches on the DIP switch must be set to the off (0) position. This will configure the module for I2C address 80. By setting switches to other combination, address 82 and 84 can also be selected (see documentation for details).

Each command sent to the module must be preceded by an I2C start condition, and finished with an I2C stop condition. An I2C bus has two lines, one for data (SDA) and one for the clock (SCL).

For example projects (written in C using free MPLAB C18 compiler) on using the LCD2S in I2C mode, see these topics:
- Example projects in C for PIC18F452
- Example projects in C for PIC18F2520

The following code shows how to write a "hello world" string to the LCD2S module. It is written in C, for the PIC18F452 PIC chip, and the Microchip MPLAB C18 C compiler. The I2C module on most PIC16 and PIC18 chips (with Master I2C module) is the same, and this code should work on most chips with minor modifications for different compilers.

Code: [Select]
#include <p18cxxx.h>

// Configuration bits for PIC18F452 chip with a 10MHz crystal. It sets the following configuration:
// Debug OFF, Oscillator in HS mode with PLL enabled (40Mhz clock), Watchdog timer off, Extended CPU mode off
#pragma config OSC = HSPLL  //HS with 4 x PLL enabled - clock is speed of crystal x 4
#pragma config WDT = OFF    //Watchdog timer can be enabled in software with SWDTEN bit
#pragma config LVP = OFF    //Low voltage programming disabled

//External functions, and function prototypes
unsigned char lcdPutRomString(unsigned char lcdAdr, const rom char* s);

//Defines
#define LCD2S_I2C_ADR 80    /* Default LCD I2C address when both switches on back of LCD2S board are set to 0 */

void delay (unsigned long dly)
{
  unsigned long i;
  for (i = 0; i < dly; i++);
}

void main (void)
{
    unsigned char i;

    /////////////////////////////////////////////////
    //Configure SSP Peripheral for I2C Master mode
    //Set port B6 as an output
    TRISBbits.TRISB6 = 0;

    //RC3 (I2C clock) and RC4 (I2C data) a configured as inputs at this stage
    TRISC |= 0b00011000;

    //Delay at while before writing to LCD display
    delay(200000ul);

    //0xxx xxxx = Slew rate off, for high speed mode (400 kHz)
    //x0xx xxxx = Disable SMBus specific inputs
    SSPSTAT &= 0x3F;        // power on state, and clear bits 6 and 7

    //xx0x xxxx = SSPEN, Disable SSP
    //xxxx 1000 = I2C Master mode, clock = FOSC / (4 * (SSPADD+1))
    SSPCON1 = 0x08;

    SSPCON2 = 0x00;         // power on state
    SSPCON1bits.SSPEN = 1;  //Enable SSP module, and configure port pins as serial port pins
    SSPADD = 24;            //Set Baud rate to 400,000. SSPADD = ( ((40,000,000/400,000) / 4) - 1 ) = 24


    /////////////////////////////////////////////////
    //Send "Hello World" string. Sring is contained in ROM memory
    if (lcdPutRomString(LCD2S_I2C_ADR, "\fhello\nworld") == 1) {
        //An error will be returned if there is no LCD display on I2C bus for example
        //...... Handle Error!!!!!
    }

    while (1)
    {  /* ....... Main Program ...... */   }
}

/** Waits until the I2C bus is IDLE, and available to be used. */
#define i2cWaitForIdle()    while ((SSPCON2 & 0x1F) | (SSPSTATbits.R_W))

/** Generate bus start condition, and waits until it is finished */
#define i2cPutStartAndWait()  {SSPCON2bits.SEN=1; while ( SSPCON2bits.SEN );}

/** Generate bus stop condition, and waits until it is finished */
#define i2cPutStopAndWait()  {SSPCON2bits.PEN=1; while(SSPCON2bits.PEN);}

/** Tests if an ACK was received from the slave. Returns true if it was, else false. */
#define i2cWasAckReceived() (!SSPCON2bits.ACKSTAT)

/**
 * This routine writes a single byte to the I2C bus,
 * and waits until the bus is idle before returning.
 *
 * @param data_out  Single data byte for I2C bus
 *
 * @return      Status byte for WCOL detection.  Returns 0 if OK, else 1 if error
 */
unsigned char i2cPutByteAndWait(unsigned char data_out) {
    SSPBUF = data_out;          // write single byte to SSPBUF
    if ( SSPCON1bits.WCOL ) {       // test if write collision occurred
        return ( 1 );           // if WCOL bit is set return negative #
    }

    while( SSPSTATbits.BF );        // wait until write cycle is complete

    i2cWaitForIdle();           // wait until bus goes idle

    return ( 0 );               // if WCOL bit is not set return non-negative #
}

unsigned char lcdPutRomString(unsigned char lcdAdr, const rom char* s) {
    unsigned char i = 0;
    char c;
    rom char* p;

    i2cWaitForIdle();

    i2cPutStartAndWait();       //Write I2C Start Condition, and wait for it to complete

    //Write module address
    i2cPutByteAndWait(lcdAdr);

    //Only continue if slave sent ACK. If no slave present, no ACK is sent. If no slave with address sent is present, no ACK is sent.
    if(i2cWasAckReceived()==0) {
        i2cPutStopAndWait();    //Reset I2C bus
        return 1;               //Error
    }

    //Write "Write Parsed String" command
    i2cPutByteAndWait(0x80);

    p = s;
    while((c = *p++)) {
        //Write next character to LCD display
        i2cPutByteAndWait(c);
    }

    i2cPutStopAndWait();    //Write I2C Stop condition, and wait for it to complete
   
    return 0;   //OK
}
« Last Edit: July 02, 2009, 12:14:34 AM by modtro2 »

naifatt

  • Newbie
  • *
  • Posts: 4
    • View Profile
Re: == I2C C Source Code ==
« Reply #1 on: June 22, 2008, 07:47:23 PM »
Thanks to SK Pang's program, I have  been able to get the keypad and OUT1 and OUT2 to work too.
My program uses Microchip's C18 compiler. Hope this is helpful to some of you.

unsigned char lcd_keypad(void)
{
    unsigned char c;
    IdleI2C();
    StartI2C();
    IdleI2C();
    WriteI2C(LCD2S_ADDR);
    IdleI2C();
    WriteI2C(0xd1);
    IdleI2C();
    RestartI2C();
    IdleI2C();
    WriteI2C(LCD2S_ADDR+1);
    IdleI2C();
    c=ReadI2C();
    IdleI2C();
    NotAckI2C();
    IdleI2C();   
    StopI2C();
    return(c);
}

// wait for a key to be pressed
// keypressed is in a 16 byte buffer.
unsigned char lcd_wait_key(void)
{
   unsigned char c;
   while((c=lcd_keypad())==0);
   return(c);
}

// LED connected to OUT2
void lcd_led2_on(void)
{
    lcd2s_cmd(0x39);
}   

void lcd_led2_off(void)
{
    lcd2s_cmd(0x31);
}

void lcd2s_cmd_value(unsigned char command, unsigned char value)
{

    IdleI2C();
    StartI2C();
    IdleI2C();
    WriteI2C(LCD2S_ADDR);
    IdleI2C();
    WriteI2C(command);
    IdleI2C();
    WriteI2C(value);
    IdleI2C();   
    StopI2C();
}

sdea

  • Newbie
  • *
  • Posts: 1
    • View Profile
Re: == I2C C Source Code ==
« Reply #2 on: May 29, 2009, 04:29:29 PM »
I have been trying to connect my SBC44B with a pic18F452 with 10Mhz XTAL to a LCD2S-204 using the I2C interface. This is my first I2C and I am a little unsure. I have connected the micro match cable(Modtronix) between the SBC and the LCD2S and set the S1 switch to off,off default address 80. When I power up the LCD displays the " This is a 4x20 ......." startup message.When I run the program there is  pause of several seconds before a single char is displayed for each loop the char is a '=' above a '-'. I expected to get "hello" I have been using the MPLAB C18 compiler. I have been through this forum and numerous others looking for clues with regards to I2C. If anyone could shed some light on this it would be great. Once I have it working I will post the interface on this forum as I am sure that others may find it useful

modtro2

  • Administrator
  • Hero Member
  • *****
  • Posts: 564
    • View Profile
Re: == I2C C Source Code ==
« Reply #3 on: June 14, 2009, 11:19:18 PM »
Hi. See example I posted at top of this page.
http://forum.modtronix.com/index.php?topic=402.msg1281#msg1281

Aletstero

  • Jr. Member
  • **
  • Posts: 9
    • View Profile
I2C C Source Code
« Reply #4 on: December 29, 2009, 08:23:06 AM »
It's not the 'source code' it is just injector of some functions into d2gs..
DC/WE is asm injector into d2server.dll, and Warden is cpp project.

gbgb

  • Newbie
  • *
  • Posts: 4
    • View Profile
Re: == I2C C Source Code ==
« Reply #5 on: August 06, 2012, 12:07:19 AM »
I am trying to use the code posted at  the beginning of this thread and it does not work.
Although I use a different PIC - a 16F8772 family I see no major difference so this code should basically work
I see some problems which need clarification.
1. What is the purpose of setting port B6 as an output? Can not find any relation between this port and the I2C functions of the PIC.
2. Ports C3 and C4 are set as inputs (for the time being) but never set later as outputs which I think is required for I2C operation.

Could you please clarify?

gbgb

  • Newbie
  • *
  • Posts: 4
    • View Profile
Re: == I2C C Source Code ==
« Reply #6 on: August 06, 2012, 04:47:35 AM »
Problem solved.
dip switch was set to SPI instead of I2C.

1. Still do not understand that purpose of port B6, commented it and it still works.
2. Found in the PIC documentation that pins must be set as inputs