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 support@ccsinfo.com

Need I2C examples
Goto page Previous  1, 2, 3  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
valemike
Guest







working i2c example...
PostPosted: Thu Jun 10, 2004 9:31 am     Reply with quote

I too was not satisfied with CCS's Slave examples. So I made my own, based on the assembly examples in Microchip's APP Note AN734 (AN735?)

When looking at the code below, you'll find that I sprinkled way too many "delay_ms()" statements. This was just to let the other PIC catch up, but i'm sure not all of the delay_ms() statements are necessary, and probably the values in them are too excessive.

The master code is straightforward, and I use CCS's libraries...

Code:

#include <18F452.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock=4000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, ERRORS)
#use i2c(master, sda=PIN_C4, scl=PIN_C3, FORCE_HW)
//#use i2c(master,sda=PIN_C4, scl=PIN_C3)

#define SLAVE_ADDRESS 0x02
void main(void)
{
    unsigned char rx_byte;
   
    while (1)
    {
        printf ("Start i2c Master logger.\r\n");
        i2c_start();
        delay_ms(50);
        i2c_write(SLAVE_ADDRESS);  /* Device Address */
        delay_ms(50);
        i2c_write(0x05);
        delay_ms(50);
//    i2c_write(12);
        delay_ms(100);
        i2c_start();   // restart condition
        i2c_write(SLAVE_ADDRESS + 1);
        rx_byte = i2c_read(0);
        printf ("rx_byte = 0x%2.2X\r\n", rx_byte);
        i2c_stop();
   
        printf ("Ending i2c Master Logger.\r\n");
    }
}




Here is the slave code. Cut and paste it, and compile. If you're using a different processor, then you need to change the #byte statements to match the particular PIC you're using.

Code:

#define PIC18F452


#include <18F452.h>
#fuses HS,NOWDT,NOPROTECT
#use delay(clock=4000000)

unsigned char read_i2c(void);
void i2c_interrupt_handler(void);
void i2c_initialize(void);
void i2c_error(void);
void write_i2c(unsigned char transmit_byte);

#INT_SSP
void ssp_interupt ()
{
    i2c_interrupt_handler();
}


/* These #byte's are for PIC18F452 ONLY!! */
/* Change it per chip */
#byte PIC_SSPBUF=0xFC9
#byte PIC_SSPADD=0xFC8
#byte PIC_SSPSTAT=0xFC7
#byte PIC_SSPCON1=0xFC6
#byte PIC_SSPCON2=0xFC5

#byte PIC_SSPBUF=0x13
#byte PIC_SSPADD=0x93
#byte PIC_SSPSTAT=0x94
#byte PIC_SSPCON1=0x14

/* Bit defines */
#define PIC_SSPSTAT_BIT_SMP     0x80
#define PIC_SSPSTAT_BIT_CKE     0x40
#define PIC_SSPSTAT_BIT_DA      0x20
#define PIC_SSPSTAT_BIT_P       0x10
#define PIC_SSPSTAT_BIT_S       0x08
#define PIC_SSPSTAT_BIT_RW      0x04
#define PIC_SSPSTAT_BIT_UA      0x02
#define PIC_SSPSTAT_BIT_BF      0x01

#define PIC_SSPCON1_BIT_WCOL    0x80
#define PIC_SSPCON1_BIT_SSPOV   0x40
#define PIC_SSPCON1_BIT_SSPEN   0x20
#define PIC_SSPCON1_BIT_CKP     0x10
#define PIC_SSPCON1_BIT_SSPM3   0x08
#define PIC_SSPCON1_BIT_SSPM2   0x04
#define PIC_SSPCON1_BIT_SSPM1   0x02
#define PIC_SSPCON1_BIT_SSPM0   0x01

#define PIC_SSPCON2_BIT_GCEN    0x80
#define PIC_SSPCON2_BIT_ACKSTAT 0x40
#define PIC_SSPCON2_BIT_ACKDT   0x20
#define PIC_SSPCON2_BIT_ACKEN   0x10
#define PIC_SSPCON2_BIT_RCEN    0x08
#define PIC_SSPCON2_BIT_PEN     0x04
#define PIC_SSPCON2_BIT_RSEN    0x02
#define PIC_SSPCON2_BIT_SEN     0x01


#define RX_BUF_LEN  32
#define NODE_ADDR   0x02    /* I2C address of the slave node */

unsigned char slave_buffer[RX_BUF_LEN];
int buffer_index;
int comms_error;
int debug_state;


void i2c_initialize(void)
{
   /* Set up SSP module for 7-bit */
   PIC_SSPCON1 = 0x36;   /* 0011 0101 */
   PIC_SSPADD = NODE_ADDR;  /* Set the slave's address */
   PIC_SSPSTAT = 0x00;     /* Clear the SSPSTAT register. */
   enable_interrupts(INT_SSP);  /* Enable MSSP interrupts. */
}   
   
void i2c_interrupt_handler(void)
{

    unsigned char i2c_mask = 0x2D;  /* 0010 1101 */
    unsigned char temp_sspstat;
    unsigned char this_byte;
    unsigned char tx_byte;
    int x;
   
    /* Mask out the unnecessary bits */
    temp_sspstat = PIC_SSPSTAT & i2c_mask;
   
    switch (temp_sspstat)
    {
        /* Write operation, last byte was an address, buffer is full */
        case 0x09:   /* 0000 1001 */
            /* Clear the receive buffer */
            for (x=0; x<RX_BUF_LEN; x++)
            {
               slave_buffer[x] = 0x00;
            }
            buffer_index = 0;  /* Clear the buffer index */
            this_byte = read_i2c();   /* Do a dummy read of PIC_SSPBUF */
           
            debug_state = 1;
            break;
       
        /* Write operation, last byte was data, buffer is full */
        case 0x29:   /* 0010 1001 */
            /* Point to the buffer */
            this_byte = read_i2c();  /* Get the byte from the SSP */
            slave_buffer[buffer_index] = this_byte; /* Put it into the buffer */
            buffer_index++; /* Increment the buffer pointer */
            /* Get the current buffer index */
            /* Subtract the buffer length */
            /* Has the index exceeded the buffer length? */
            if (buffer_index >= RX_BUF_LEN)
            {
               buffer_index = 0; /* Yes, clear the buffer index. */
            }
            debug_state = 2;
            break;
       
        /* Read operation; last byte was an address, buffer is empty */
        case 0x0C:   /* 0000 1100 */
            buffer_index = 0; /* Clear the buffer index */
            /* Point to the buffer */
            tx_byte = slave_buffer[buffer_index]; /* Get byte from the buffer */
            write_i2c(tx_byte); /* Write the byte to PIC_SSPBUF */
            buffer_index++; /* increment the buffer index */
            debug_state = 3;
            break;
       
        /* Read operation; last byte was data, buffer is empty */
        case 0x2C:   /* 0010 1100 */
            /* Get the current buffer index */
            /* Subtract the buffer length */
            /* Has the index exceeded the buffer length? */
            if (buffer_index >= RX_BUF_LEN)
            {
                buffer_index = 0; /* Yes, clear the buffer index */
            }   
            /* Point to the buffer */
            /* Get the byte */
            tx_byte = slave_buffer[buffer_index];
            write_i2c(tx_byte);  /* Write to PIC_SSPBUF */
            buffer_index++; /* increment the buffer index */
            debug_state = 4;
            break;
           
        /* A NACK was received when transmitting data back from the master. */
        /* Slave logic is reset in this case. R_W=0, D_A=1, and BF=0. */
        /* If we don't stop in this state, then something is wrong!! */
        case 0x28:   /* 0010 1000 */
            debug_state = 5;
            break;
       
        /* Something went wrong!! */
        default:
            i2c_error();
            break;
    }
}

void i2c_error(void)
{
    comms_error = 1;
    printf ("I2C ERROR!\r\n");
}

void write_i2c(unsigned char transmit_byte)
{
    unsigned char temp;
    unsigned char write_collision = 1;
   
    while (PIC_SSPSTAT & PIC_SSPSTAT_BIT_BF) /* Is BF bit set in PIC_SSPSTAT? */
    {
        /* If yes, then keep waiting */
    }
   
    while (write_collision)
    {
        /* If not, then do the i2c_write. */   
        PIC_SSPCON1 &= ~PIC_SSPCON1_BIT_WCOL;  /* Clear the WCOL flag */
        PIC_SSPBUF = transmit_byte;
   
        /* Was there a write collision? */
        if (PIC_SSPCON1 & PIC_SSPCON1_BIT_WCOL)
        {
            /* Yes there was a write collision. */
            write_collision = 1;
        }
        else
        {
            /* NO, there was no write collision. */
            /* The transmission was successful */
            write_collision = 0;
        }
    }
    PIC_SSPCON1 |= PIC_SSPCON1_BIT_CKP;  /* Release the clock. */
}

/* This function returns the byte in SSPBUF */
unsigned char read_i2c(void)
{
    return PIC_SSPBUF;
}

void main(void)
{
    debug_state = 0;
    i2c_initialize();
    enable_interrupts(GLOBAL);
//    printf ("Starting I2C Slave Logger.\r\n");
   
    while (1)
    {
        if (debug_state)
        {
//            printf ("Debug State = %d\r\n", debug_state);
            debug_state = 0;
        }
    }
}
falleaf



Joined: 23 May 2004
Posts: 48

View user's profile Send private message

PostPosted: Thu Jun 10, 2004 11:33 am     Reply with quote

Oh,thanks indeed. It's that what I need.

Thanks muchie. If I have some question on this code, may I ask you for more information?

Thanks.
dyeatman



Joined: 06 Sep 2003
Posts: 1914
Location: Norman, OK

View user's profile Send private message

PostPosted: Thu Jun 10, 2004 11:37 am     Reply with quote

With all the noise he is making about this I would suspect he is trying to get us to do a school project or something similar for him.

With the fact of his requestes do not make sense and how insistant he is to get specifically the I2C drivers. In that the posts in the board are apparently not good enough for him, I would suspect he wants us to hand him a working solution to his problem with us doing all the work for him.

I may be wrong but I bet not!
falleaf



Joined: 23 May 2004
Posts: 48

View user's profile Send private message

PostPosted: Thu Jun 10, 2004 11:10 pm     Reply with quote

hallo,

Yeah, this is a school project. However, don't bet on this, because you will lose. Smile. My project is on motion control.

I'm trying with my project on C. And if you pay a visit to electrotech, you will see I helped students there. That is, I would like to ask, and will help if I can.

I need to have to comparation between the C code >> view as ASM with the ASM writen myself. However, it's difficult to compare the code if I cannot write as I need. Don't know anything about C for PIC.

My undertaking is not writing the communication, but understanding C.

By the way, I2C communication in ASM published everywhere. If you need it to include to C, I think no problems.

That is my question about.
Dont feel so bad to meeh.

And my question will not as how to write the code, but it should be. As writing on ASM, I need to do this this this... so how should we do it on C... blah blah..

I asked about PWM, but no ans !!

As generating C code to change PWM. We only use set_pwm_duty function. But in ASM, as I change PWM duty, I have to wait until the timer overflow. So will the C code do this? The problem is that, if the pin is HIGH, and we change the duty, it still get HIGH at the next period, and we get wrong at the first period as changing duty. What is the way C code do?

I would like to know about such problems on C, to understand and make a C program better. And You will see that, C is not always good as ASM. Some init function, I have to use ASM for example. Now, I did some simple function and understand how to fix C code and ASM. With simple function, and repeated unexpectedly, I change to use ASM.

Sorry, my English is not good, so I have a long explanation. But that is what I'm doing.
falleaf



Joined: 23 May 2004
Posts: 48

View user's profile Send private message

PostPosted: Fri Jun 11, 2004 1:07 am     Reply with quote

Example codes also here:

Source: http://www.walking-productions.com/school/adtech/

Master
Code:

/* Standard Include for 16F877 Chip */
#include <16F877.h>
#fuses XT,NOWDT,NOPROTECT,NOLVP,PUT

/* Delay for 4 mhz crystal */
#use delay (clock=4000000)

/* Setup RS232 */
#use rs232(baud=9600, xmit=PIN_D4,rcv=PIN_D5, INVERT)

/* Setup I2C */
#use I2C(MASTER, sda=PIN_C4, scl=PIN_C3, SLOW)

main()
{
   int8 i2c_command = 66;

   while (true)
   {
      delay_ms(1000);
      printf("Outputting: %c", i2c_command);
     
      /* Master */
      i2c_start();      // Start condition
      i2c_write(0xa0);   // Device address
      i2c_write(i2c_command);   // Write Command
      i2c_stop();      // Stop condition

   }
}


Slave

Code:
/* Standard Include for 16F877 Chip */
#include <16F877.h>
#fuses XT,NOWDT,NOPROTECT,NOLVP,PUT

/* Delay for 4 mhz crystal */
#use delay (clock=4000000)

/* Setup RS232 */
#use rs232(baud=9600, xmit=PIN_D4,rcv=PIN_D5, INVERT)

/* Setup I2C */
#use i2c(SLAVE, SDA=PIN_C4, SCL=PIN_C3, address=0xa0, SLOW, FORCE_HW)

#INT_SSP
void ssp_interupt ()
{
   byte incoming;
   incoming = i2c_read();
   printf("\n\rRead byte 1: %x\n\r", incoming);
   incoming = i2c_read();
   printf("Read byte 2: %x\n\r\n\r", incoming);
}


main()
{
      delay_ms(1000);
      printf("Running");

      enable_interrupts(GLOBAL);
      enable_interrupts(INT_SSP);
      while (true)
   {

   }
}
valemike
Guest







PostPosted: Fri Jun 11, 2004 8:17 am     Reply with quote

falleaf wrote:
Example codes also here:

Source: http://www.walking-productions.com/school/adtech/
[snip]

Master
}[/code]


Not quite. It looks like the slave can only handle incoming bytes, but it doesn't handle when the master is requesting data. At one time, I too thought it was easy to just do like the example.

However, the "state machine" in the APP note AN735/AN734 is in fact the proper way to handle the i2c interrupts on the slave side. It's not really a state machine though as far as the source code is concerned, since I don't have to worry about previous states. I guess the PIC's SSP does it for us. You just have to worry about the current contents of SSPSTAT with each interrupt.

-Mike
falleaf



Joined: 23 May 2004
Posts: 48

View user's profile Send private message

PostPosted: Sun Jun 13, 2004 5:43 am     Reply with quote

Yes, I used AN735 ASM code, and it worked very good. So the problem is that I don't know exactly how the C code work!!!. I'm trying to understand it.

Thanks muchie.
ben500
Guest







Acknowledgment bit
PostPosted: Mon Jun 14, 2004 1:09 pm     Reply with quote

Hi,

I'm trying to make communicate a PIC16F819 (master) with a PIC16F876 (slave) by I2C. I've tried now a lot of different example codes, but it is always the same error which occured: the slave does not send any acknowledgement! According to the datasheets (16f87x, table 9-2), I think I am in the fifth case where the BF bit is cleared and the SSPOV bit is set. My problem is that I don't know how to avoid it. Perhaps someone could help me, it is near to break my nerves... Smile

Thanks you,

~Ben
Guest








PostPosted: Thu Jun 17, 2004 3:28 am     Reply with quote

Code:
#byte PIC_SSPBUF=0xFC9
#byte PIC_SSPADD=0xFC8
#byte PIC_SSPSTAT=0xFC7
#byte PIC_SSPCON1=0xFC6
#byte PIC_SSPCON2=0xFC5

#byte PIC_SSPBUF=0x13
#byte PIC_SSPADD=0x93
#byte PIC_SSPSTAT=0x94
#byte PIC_SSPCON1=0x14


You redefine here, and the 4 below lines is use for 16Fxxx PIC only, does it mean in C that the program can choose one of these address? Or you write as an example for who want to use 16F PICs?

What is the different between hardware I2C and software?

As using #uses I2C from CCS C, what will it generate?
falleaf



Joined: 23 May 2004
Posts: 48

View user's profile Send private message

PostPosted: Thu Jun 17, 2004 3:31 am     Reply with quote

Sorry, it's meeh, I forgot to login Smile
valemike1
Guest







oops
PostPosted: Fri Jun 18, 2004 11:17 am     Reply with quote

Code:

#byte PIC_SSPBUF=0xFC9
#byte PIC_SSPADD=0xFC8
#byte PIC_SSPSTAT=0xFC7
#byte PIC_SSPCON1=0xFC6
#byte PIC_SSPCON2=0xFC5

#byte PIC_SSPBUF=0x13
#byte PIC_SSPADD=0x93
#byte PIC_SSPSTAT=0x94
#byte PIC_SSPCON1=0x14


When I cut and pasted the code, I dont know why but I took out the #if 0...#endif statements.

Delete one of the groups, since you don't want to redefine twice. The second set 0x13,0x93,0x94,0x14 is for the PIC16F876, 873, etc. The numbers with the 0xFc9, etc. is for the PIC18F252/452/etc.

-Mike

p.s. Software i2c is bitbanged and you just toggle these pins high and low like any general purpose i/o pin. Hardware i2c actually uses the built-in MSSP/SSP module. If you must use i2c, then go use a PIC with the hardware i2c mssp/ssp module. That way you won't burn processor time bitbanging.
falleaf



Joined: 23 May 2004
Posts: 48

View user's profile Send private message

PostPosted: Sat Jun 19, 2004 3:15 am     Reply with quote

Yes, I'm using 16F876A and 16F877A. I'm using 16F876A as a slave and 877 as the master.

Everything seems oki.

I found that CCS C is really like normal C, and the function is clear. But I still cannot read the ASM code generated from CCS C.

With your code, I save it as a file i2c_slave_mike.c and include to my program, then use it.

Code:
#byte PIC_SSPBUF=0x13
#byte PIC_SSPADD=0x93
#byte PIC_SSPSTAT=0x94
#byte PIC_SSPCON1=0x14
#byte PIC_SSPCON2=0x91


And I see that there is some #define *BIT* you didn't use in the code. Will it takes the memories a compiling the code? Because as defining, we can only define it as a number. And will the C takes some memories to save those number?

By the way, what is the difference between using your code on 16f876 and #uses I2C of CCS C?

Because I see that we can force it to hardware mode?

I would like to understand more about function i2c_start();

As it generate start condition, will it reset the buffer_index? Because if I would like to use 8 first bytes to save data from master, and 8 low bytes to save transmit bytes. I will have to set buffer length as 8 or 16 bytes?

If this is writen identically as AN734, I can use 16 bytes. Because the master will do as below: (I don't write in CCS C code, because I'm not sure of it).

function TX_RX ()
{
start condition
send the address of slave in write mode

for i from 1 to 8
write (data[i]);

start condition
send the address of slave in read mode
for i from 9 to 16
data[i] = read_i2c;
}

In slave chip, I have 16 bytes buffer. In write condition of master, the slave will receive 8 byte and save to buffer[1..8]. After that, the read condition, the index still at 9. Then the slave will send buffer[9..16].

May we do this with your code?

Then each sampling time I only have to call function TX_RX. I can send and receive all what I need.

I see that you put buffer_index as a global variable, so that it can do this. In ASM, I can easily know exactly register address, so I don't care muchie as writing in ASM, but C for PIC confuse meeh Smile

And pls explain me about #uses I2C in CCS C? which is smaller code between yours and force hardware CCS C? I'm using 16F876a.

Thanks muchie.
falleaf



Joined: 23 May 2004
Posts: 48

View user's profile Send private message

PostPosted: Sun Jun 20, 2004 11:57 am     Reply with quote

Mike,

I've tested with your code, the tx from master to slave is oki, but as rx, it wrong.

In your code, I've tested:

master:

....
i2c_write(0x05);
i2c_write(0x06);
i2c_write(0x07);

i2c_start(); //restart
i2c_write(add +1); // normally in asm I used to set this bit0
byte1 = i2c_read();
byte2 = i2c_read();
...

but rx way is not good, and I receive wrong result.

Pls explain me about this.
valemike
Guest







PostPosted: Mon Jun 21, 2004 3:28 pm     Reply with quote

For receiving, you will need to determine what you want to put in the outgoing bytes. The global array I provided is just an example taken from the application note. However, it is pretty much useless by itself.

So, you said that you tried it and it works fine for master sending bytes to the slave, and you confirmed that the slave received the bytes? But when the master tries to read from the slave, then you get errors?

I'll try to answer your questions later this evening when I go home.
-Mike
Guest








Re: Acknowledgment bit
PostPosted: Mon Jun 21, 2004 3:33 pm     Reply with quote

ben500 wrote:
Hi,

I'm trying to make communicate a PIC16F819 (master) with a PIC16F876 (slave) by I2C. I've tried now a lot of different example codes, but it is always the same error which occured: the slave does not send any acknowledgement! According to the datasheets (16f87x, table 9-2), I think I am in the fifth case where the BF bit is cleared and the SSPOV bit is set. My problem is that I don't know how to avoid it. Perhaps someone could help me, it is near to break my nerves... Smile

Thanks you,

~Ben


When using the CCS-supplied libraries for the MASTER, my AN735-based Slave gets NACK states (case 5?) all the time, but it doesn't seem to hurt anything.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page Previous  1, 2, 3  Next
Page 2 of 3

 
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