CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

problem with I2C master on 16f88

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
epv



Joined: 23 Feb 2008
Posts: 8

View user's profile Send private message

problem with I2C master on 16f88
PostPosted: Sat Feb 23, 2008 4:43 am     Reply with quote

I've just started playing with i2c, and I'm having a hard time with making this chip speak i2c.

I'm using the sw implementation, since 16f88 can only do i2c slave in hardware.

If I use the PCM compiler's builtin "#use i2c..." (PCM compiler version 4.049;8/6/2007, this is the latest version on linux) it hangs forever without transferring any data. I've been experimenting with it trying to make it talk to an i2c LCD module, but the same thing happens trying to access the i2c 24lc16 eeprom on an Olimex PG4 board, too.

Code:

#include <16F88.h>
#fuses INTRC_IO, NOWDT, NOMCLR, NOPROTECT, BROWNOUT, PUT, NOLVP
#use delay(clock = 8000000)

#use i2c(master, sda=PIN_A0, scl=PIN_A1)
void main()
{
     i2c_start();
     i2c_write(0x50);   // 0x50 is the LCD module's address
     // i2c_start();  // should this be here or not? doesn't work either way
     i2c_write(0x41);   // print "A"
     i2c_stop();
     while(1);
}


No output..

If I don't use the #use i2c or the builtin i2c_*() functions and instead manually bit-bang out the i2c conversation it works, on the same chip, same pins, same LCD module, etc...

Code:
#include <16F88.h>
#fuses INTRC_IO, NOWDT, NOMCLR, NOPROTECT, BROWNOUT, PUT, NOLVP
#use delay(clock = 8000000)

#include <stdlib.h>

#define SDA PIN_A0
#define SCL PIN_A1
#define LCDADDR 0x50

void i2cstop(void)
{
        output_low(SDA);
        output_low(SCL);
        output_high(SDA);
}

void i2cinit(void)
{
        int n;
        output_high(SDA);
        output_low(SCL);
        for (n=0; n<3; n++)
                i2cstop();
}

void i2cstart(void)
{
        output_high(SCL);
        output_high(SDA);
        output_low(SDA);
        output_low(SCL);
        output_high(SDA);
}

void i2cgetack(void)
{
        output_high(SDA);
        output_high(SCL);
        while (input(SDA) != 0) ;
        output_low(SCL);
        output_low(SDA); // should already be, but set it to output
}

void i2cgiveack(void)
{
        output_low(SDA);
        output_high(SCL);
        output_low(SCL);
        output_high(SDA);
}

void i2cputbyte(int obyte)
{
        int n;
        for (n=0; n<8; n++) {
                if (obyte & 0x80)
                        output_high(SDA);
                else
                        output_low(SDA);
                output_high(SCL);
                output_low(SCL);
                obyte = obyte << 1;
        }
        output_high(SDA);
}

void i2csendaddr(int adr, int rw)
{
        i2cstart();
        if((adr & 0x8000) != 0) {
                i2cputbyte(0xF0 | rw | ((adr > 8) & 0x06));
                i2cgetack();
                i2cputbyte(adr & 0xFF);
        } else {
                i2cputbyte(adr | rw);
        }
        i2cgetack();
}

void i2cwrite(int adr, int num, char *buf) {
        i2csendaddr(adr, 0);
        while(num-- > 0) {
                i2cputbyte(*buf++);
                i2cgetack();
        }
        i2cstop();
}

void lcdcommand(int cmd, int num, int arg1, int arg2) {
        char buf[6];
        buf[0] = LCDCOMMAND;
        buf[1] = cmd;
        buf[2] = arg1;
        buf[3] = arg2;
        i2cwrite(LCDADDR, num + 1, buf);
}

void lcdwrite (int dat) {
   char buf [2];

   buf [0] = (char) dat;
   i2cwrite(LCDADDR, 1, buf);
}


void main() {
        i2cinit();
        delay_ms(100);
        printf(lcdwrite, "Hello, world.  \n                ");
        while(1);
}


(those functions were mostly cribbed from user RussCA on lcdforums.com, to give due credit)

The above code successfully writes a "Hello, world." to the display, so I am pretty sure there's not a hardware problem.


Additionally, I get the same thing going on in a simulator (gpsim) trying to write to an emulated i2c eeprom... the i2c builtins just hang, seem to be polling SDA forever.

I am more than happy to be told I am clueless and doing it wrong - but before I drive myself nuts trying to figure it out, could it be that there's a problem with the linux version of the compiler, or a problem that was fixed since version 4.049?

thanks for any help or advice,
eric
epv



Joined: 23 Feb 2008
Posts: 8

View user's profile Send private message

fixed...
PostPosted: Sat Feb 23, 2008 8:53 pm     Reply with quote

Well, my problem was a confluence of a number of factors. One was that the Olimex PG4 board has a pullup on SDA, but lacks one for SCL. Why? I dunno. When I added a pullup for SCL, I was able to read/write the 24LC16 with the *_ext_eeprom() routines, which of course just use the builtin i2c functions.
The other problem was that I was apparently talking to the i2c LCD incorrectly, and it was ignoring me until I got it's format figured out.

Anyway, I feel less frustrated now.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group