ccs __ view topic - need i2c examples
DESCRIPTION
I2C examplesTRANSCRIPT
FAQ Forum Help Official CCS Support Search
Profile You have no new messages Log out [jayanthd ]
Please go to www.mcuspace.com/mcuforum for posts concerning
PIC®MCU
CCS does not monitor this forum on a regular basis.
Please do not post bug Reports on this forum. Send them [email protected]
Need I2C examplesGoto page Previous 1, 2, 3 Next
CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic
Author Message
valemikeGuest
working i2c example...
Posted: Thu Jun 10, 2004 9:31 am
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 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 2004Posts: 48
Posted: Thu Jun 10, 2004 11:33 am
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 2003Posts: 1378Location: Norman, OK
Posted: Thu Jun 10, 2004 11:37 am
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 2004Posts: 48
Posted: Thu Jun 10, 2004 11:10 pm
hallo,
Yeah, this is a school project. However, don't bet on this, because you will lose. . 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 2004Posts: 48
Posted: Fri Jun 11, 2004 1:07 am
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)
{
}
}
valemikeGuest
Posted: Fri Jun 11, 2004 8:17 am
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 2004Posts: 48
Posted: Sun Jun 13, 2004 5:43 am
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.
ben500Guest
Acknowledgment bit
Posted: Mon Jun 14, 2004 1:09 pm
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...
Thanks you,
~Ben
Guest Posted: Thu Jun 17, 2004 3:28 am
Code:
#byte PIC_SSPBUF=0xFC9
#byte PIC_SSPADD=0xFC8
#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 2004Posts: 48
Posted: Thu Jun 17, 2004 3:31 am
Sorry, it's meeh, I forgot to login
valemike1Guest
oops
Posted: Fri Jun 18, 2004 11:17 am
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 2004Posts: 48
Posted: Sat Jun 19, 2004 3:15 am
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.
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
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 Posted: Sun Jun 20, 2004 11:57 am
Joined: 23 May 2004Posts: 48
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.
valemikeGuest
Posted: Mon Jun 21, 2004 3:28 pm
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
Posted: Mon Jun 21, 2004 3:33 pm
ben500 wrote:
Hi,
I'm trying to make communicate a PIC16F819 (master) with a PIC16F876 (slave) by I2C. I'vetried now a lot of different example codes, but it is always the same error which occured: theslave does not send any acknowledgement! According to the datasheets (16f87x, table 9-2), Ithink I am in the fifth case where the BF bit is cleared and the SSPOV bit is set. My problem isthat I don't know how to avoid it. Perhaps someone could help me, it is near to break my
nerves...
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: All Posts Oldest First Go
CCS Forum Index -> General CCS C DiscussionAll times are GMT - 6 Hours
Goto page Previous 1, 2, 3 Next
Page 2 of 3
Watch this topic for replies
Jump to: General CCS C Discussion Go
You can post new topics in this forumYou can reply to topics in this forum
You can edit your posts in this forumYou can delete your posts in this forum
You can vote in polls in this forum
Powered by phpBB © 2001, 2005 phpBB Group