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

Who wants I2C master/slave code
Goto page 1, 2  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
Mark



Joined: 07 Sep 2003
Posts: 2838
Location: Atlanta, GA

View user's profile Send private message Send e-mail

Who wants I2C master/slave code
PostPosted: Tue Feb 15, 2005 9:53 pm     Reply with quote

Alright, I am tired of seeing so many people struggle with this topic. Some body (I ain't saying who) decided it would be a good communication bus for our modules to communicate with (I disagree). After about 7 years of fiddling with the stuff I think maybe I can give you folks some code that should work pretty well for you. Now we use this to pass messages back and forth in a multi-master system. Our protocol actually follows (well sort of) the Access.bus specification with some slight modifications. We added a checksum and a message acknowledgement.

So to the point:

What I want to know from those of you who would like some code is how you intend to use it. What are you trying to do between microcontrollers. I'll post some code that will best fit those cases. Now don't post talking to eeproms, realtime clocks and stuff like that. You can already find that code. I want those cases where people are trying to talk PIC to PIC
dyeatman



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

View user's profile Send private message

PostPosted: Tue Feb 15, 2005 10:14 pm     Reply with quote

Mark,
I recently built a PIC based interface controller to tie a home automation controller to an RCS HVAC zone controller. I am planning to expand the capabilities to tie in additional systems by adding two more PICs on the same board. My prototype uses I2C for the tie-together. I for one would like to see what you have... Likely much better than what I have so far.

Dave
future



Joined: 14 May 2004
Posts: 330

View user's profile Send private message

PostPosted: Wed Feb 16, 2005 3:11 am     Reply with quote

I am doing an engine controller, soon it will be expanded to control other things as well... new pic to do it and they must talk.

Second pic will receive data and process it.
Guest








PostPosted: Wed Feb 16, 2005 3:29 am     Reply with quote

I want to connect a master and several slaves, where the master should issue commands received from a PC to specific i2c slaves. The slaves in turn should be able to interrupt to the master, and transfer data back to the master, who transfers it to the PC. Shocked
Guest








PostPosted: Wed Feb 16, 2005 3:30 am     Reply with quote

I want to connect a master and several slaves, where the master should issue commands received from a PC to specific i2c slaves. The slaves in turn should be able to interrupt to the master, and transfer data back to the master, who transfers it to the PC. Shocked
treitmey



Joined: 23 Jan 2004
Posts: 1094
Location: Appleton,WI USA

View user's profile Send private message Visit poster's website

I2C message passing uses
PostPosted: Wed Feb 16, 2005 9:53 am     Reply with quote

I have hardware that was handed to me that uses two 16F877A's for the two hardware UARTS. These two pics then send simple messages to each other.
MikeW



Joined: 15 Sep 2003
Posts: 184
Location: Warrington UK

View user's profile Send private message

PostPosted: Wed Feb 16, 2005 12:39 pm     Reply with quote

I need PIC code to enable the PIC to be a master, or a slave device.

It would sit on the bus, with other devices (Philips micro), and do the collision detection, and arbitration etc.

I cannot get the source code for the philips micro, so it is going to difficult.

any help would be appreciated.

real e-mail is mikestefoy at hotmail dot com
e



Joined: 02 Feb 2005
Posts: 9
Location: New York City

View user's profile Send private message Visit poster's website

PostPosted: Wed Mar 02, 2005 3:06 pm     Reply with quote

yay! i've been struggling with i2c for weeks now, trying to synthesize all the different approaches and caveats found on this forum. my application is an interactive art installation involving a tree made of lots of dot matrix displays whose pixels disintegrate depending on proximity of viewers. i have something built from scratch working fairly consistently in slow mode but not fast mode. and am i the only one who finds it hard to believe CCS has built-in functions that don't really work? i mean, what's the point of built-in functions in a compiler package?

my i2c setup is fairly typical, i.e. 1 master with about 20-40 slaves, each of which drives clusters of LED displays. fast updating and zero errors are important. typical data packet involves address, command, and 1 or 2 bytes of data. occasionally will burst out 8 bytes of data per slave to re-write all pixels, meaning potentially 400 bytes fast enough that update appears simultaneous. not necessary for slaves to send anything back, although a status check would probably be a good idea. maximum bus length 15 feet. (capacitance might be an issue?)

(originally i had the display data just cascade serially from 1 uP but that ruled out simultaneous disintegration, so i've been rebuilding it using slave uPs and i2c. also tried simple rs232 between pics but felt like i2c was built for this so why not use it?)
Mark



Joined: 07 Sep 2003
Posts: 2838
Location: Atlanta, GA

View user's profile Send private message Send e-mail

PostPosted: Wed Mar 02, 2005 3:30 pm     Reply with quote

I haven't forgotten about this yet. Out of my department of 4 engineers and my boss, 3 people got laid off and one of them was my boss! Kind of busy right now, but I will post an example program that can be used as a multi-master or master/slave.
Guest








PostPosted: Wed Mar 02, 2005 10:12 pm     Reply with quote

i'm curious to see what you think of PH Anderson's routines. He does things very differently than i2c code posted on this forum.

paraphrased code:

Code:
// Program 24_256_1.C (CCS Info PCM Compiler - PIC16F84)
// copyright, Peter H. Anderson, Scotland Co, NC, Mar, '99

#case

#include <16f84.h>
#include <string.h>
#include <defs_f84.h>   // See Notes

// common i2c routines
byte i2c_in_byte(void);
void i2c_out_byte(byte o_byte);
void i2c_nack(void);
void i2c_ack(void);
void i2c_start(void);
void i2c_stop(void);
void i2c_high_sda(void);
void i2c_low_sda(void);
void i2c_high_scl(void);
void i2c_low_scl(void);

// other routines
void delay_ms(long t);
void delay_10us(int t);
int num_to_char(int val);

#define SDA_PIN rb2      // RB.2
#define SCL_PIN rb1      // RB.1

#define SDA_DIR trisb2
#define SCL_DIR trisb1

void main(void) {
   long mem_adr;
   byte dat, n;
   // demo write and read
   while(1) {
      mem_adr=0x0700;
      for(n=0; n<16; n++) {
         dat = 0xff - n;
         random_write(0x00, mem_adr, dat);
         ++mem_adr;
      }
      mem_adr=0x0700;
      for(n=0; n<16; n++) {
         dat = random_read(0x00, mem_adr);
         // display or use dat here
         ++mem_adr;
      }
      delay_ms(500);
   }
}

// demo write & read routines

void random_write(byte dev_adr, long mem_adr, byte dat)
{
   i2c_start();
   i2c_out_byte(0xa0 | (dev_adr << 1));
   i2c_nack();
   i2c_out_byte((mem_adr >> 8) & 0xff);   // high byte of memory address
   i2c_nack();
   i2c_out_byte(mem_adr & 0xff);      // low byte of mem address
   i2c_nack();
   i2c_out_byte(dat);               // and finally the data
   i2c_nack();
   i2c_stop();
   delay_ms(25);                   // allow for EEPROM programming
}

byte random_read(byte dev_adr, long mem_adr)
{
   byte y;
   i2c_start();
   i2c_out_byte(0xa0 | (dev_adr << 1));
   i2c_nack();
   i2c_out_byte((mem_adr >> 8) & 0xff);
   i2c_nack();
   i2c_out_byte(mem_adr & 0xff);
   i2c_nack();
   i2c_start();                     // no intermediate stop
   i2c_out_byte(0xa1 | (dev_adr << 1));   // read operation
   i2c_nack();
   y = i2c_in_byte();               // get data
   i2c_stop();
   return(y);
}

//////////// Common I2C Routines ///////////////

byte i2c_in_byte(void) {
   byte i_byte, n;
   i2c_high_sda();
   for (n=0; n<8; n++) {
      i2c_high_scl();

      if (SDA_PIN) {
         i_byte = (i_byte << 1) | 0x01; // msbit first
      } else {
         i_byte = i_byte << 1;
      }
      i2c_low_scl();
   }
   return(i_byte);
}

void i2c_out_byte(byte o_byte) {
   byte n;
   for(n=0; n<8; n++) {
      if(o_byte&0x80) {
         i2c_high_sda();
      } else {
         i2c_low_sda();
      }
      i2c_high_scl();
      i2c_low_scl();
      o_byte = o_byte << 1;
   }
   i2c_high_sda();
}

void i2c_nack(void) {
   i2c_high_sda();         // data at one
   i2c_high_scl();         // clock pulse
   i2c_low_scl();
}

void i2c_ack(void) {
   i2c_low_sda();         // bring data low and clock
   i2c_high_scl();
   i2c_low_scl();
   i2c_high_sda();
}


void i2c_start(void) {
   i2c_low_scl();
   i2c_high_sda();
   i2c_high_scl();         // bring SDA low while SCL is high
   i2c_low_sda();
   i2c_low_scl();
}

void i2c_stop(void) {
   i2c_low_scl();
   i2c_low_sda();
   i2c_high_scl();
   i2c_high_sda();         // bring SDA high while SCL is high
   // idle is SDA high and SCL high
}

void i2c_high_sda(void) {
   SDA_DIR = 1;            // bring SDA to high impedance
   delay_10us(5);
}

void i2c_low_sda(void) {
   SDA_PIN = 0;
   SDA_DIR = 0;            // output a hard logic zero
   delay_10us(5);
}

void i2c_high_scl(void) {
   SCL_DIR = 1;            // high impedance
   delay_10us(5);
}

void i2c_low_scl(void) {
   SCL_PIN = 0;
   SCL_DIR = 0;
   delay_10us(5);
}


// delay routines

void delay_10us(int t) {
   #asm
      BCF STATUS, RP0
      DELAY_10US_1:
         CLRWDT
         NOP
         NOP
         NOP
         NOP
         NOP
         NOP
         DECFSZ t, F
         GOTO DELAY_10US_1
   #endasm
}

void delay_ms(long t) {
   do {
     delay_10us(100);
   } while(--t);
}
Mark



Joined: 07 Sep 2003
Posts: 2838
Location: Atlanta, GA

View user's profile Send private message Send e-mail

PostPosted: Thu Mar 03, 2005 6:53 am     Reply with quote

His routines do not use the built in routines provided with the CCS compiler which gives him more control. Also, these routines are just basic master routines to access a slave. That is NOT what I am planning on posting. While the routines will do that, the routines that I am going to post are both the slave and master portions that will allow each pic to talk with the other. I didn't look at Peter's that closely but I would rather use his than the CCS functions because I can see what is going on.
valemike
Guest







PostPosted: Thu Mar 03, 2005 9:54 am     Reply with quote

Using CCS's library routines...

i2c_start();
ack = i2c_write(slave_address);
ack = i2c_write(data1);
ack = i2c_write(data2);
...

What happens if the slave has not yet digested the write of data1, and the master tries a write of data2?

From what i've seen in my debugging, there will be an ack of '1' on the failed write.

And clock stretching (CKP bit) by the slave only applies to when the master does an i2c_read(). This makes sense that the slave has to inhibit the bus while it's getting its outgoing data ready.

How then is the slave supposed to "inhibit" the master from bombarding it with i2c_write()s at a fast rate? The only way i have gotten around this is to put the mssp interrupt as priority (#priority) in the slave source code. Maybe if i can slow down the clock (with the newer 3.214+ compiler versions), then i won't see this problem.

I've also done some unorthodox clock stretching even when the master issues an i2c_write() (not a read). All the above methods combined has been failproof for me, but i know one day, there will be a problem in the fiield and i'm going to eat crow.
valemike
Guest







PostPosted: Thu Mar 03, 2005 9:55 am     Reply with quote

Using CCS's library routines...

i2c_start();
ack = i2c_write(slave_address);
ack = i2c_write(data1);
ack = i2c_write(data2);
...

What happens if the slave has not yet digested the write of data1, and the master tries a write of data2?

From what i've seen in my debugging, there will be an ack of '1' on the failed write.

And clock stretching (CKP bit) by the slave only applies to when the master does an i2c_read(). This makes sense that the slave has to inhibit the bus while it's getting its outgoing data ready.

How then is the slave supposed to "inhibit" the master from bombarding it with i2c_write()s at a fast rate? The only way i have gotten around this is to put the mssp interrupt as priority (#priority) in the slave source code. Maybe if i can slow down the clock (with the newer 3.214+ compiler versions), then i won't see this problem.

I've also done some unorthodox clock stretching even when the master issues an i2c_write() (not a read). All the above methods combined has been failproof for me, but i know one day, there will be a problem in the fiield and i'm going to eat crow.
Mark



Joined: 07 Sep 2003
Posts: 2838
Location: Atlanta, GA

View user's profile Send private message Send e-mail

PostPosted: Thu Mar 03, 2005 10:00 am     Reply with quote

If the master does not get the ACK (a 0) then it should handle what needs to be done. Most of the examples that you are going to find are pretty basic. They hope for a perfect world. Sometimes they are kludged with delays. Take a look at how many people write to an eeprom. They just stick a huge delay in there for the write to complete. The proper way is to check for an ACK on the next write.
valemike
Guest







PostPosted: Thu Mar 03, 2005 10:34 am     Reply with quote

Mark wrote:
If the master does not get the ACK (a 0) then it should handle what needs to be done. Most of the examples that you are going to find are pretty basic. They hope for a perfect world. Sometimes they are kludged with delays. Take a look at how many people write to an eeprom. They just stick a huge delay in there for the write to complete. The proper way is to check for an ACK on the next write.


After skimming thru Microchip's App note AN735 just now, it says that a NACK indicates a hw/sw error, or simply an overrun. Even if it's an overrun, then what should the error handler do? Is it possible to simply re-try the write? From what i get out of the app note, it says to issue a restart, or stop/start.

I think my overruns are a result of the slave's interrupt latency handling of multiple frequent interrupts from other sources. It may just well be that a slave PIC needs to be given ample time to digest things. If there was a NACK, then everything has to be aborted, and the whole start/write_address/write_etc sequence has to be re-started anyways.

So such delays liberally sprinkled all over the place, which we both feel are kludges, are probably absolutely necessary. It seems the goal is NACK avoidance rather than NACK error handling. I can't see any other way to avoid a NACK than to inject delays.
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 1, 2  Next
Page 1 of 2

 
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