Pic to Pic I2C

General discussion on mikroC.
Post Reply
Author
Message
CVMichael
Posts: 239
Joined: 30 Apr 2009 02:36
Location: Canada, Toronto

Pic to Pic I2C

#1 Post by CVMichael » 17 Jun 2009 13:28

I want to connect a PIC16F88 with a PIC18F4550 with I2C connection, but I cannot find any examples using MikroC with PIC to PIC connection, and I have no idea how to even start.

I want the PIC16F88 to be master, and the PIC18F4550 to be slave.

Also, how would be physical connection (what pin to what pin) between them ?

Thanks

Nick101
Posts: 339
Joined: 06 Aug 2006 15:32
Location: Texas
Contact:

Re: Pic to Pic I2C

#2 Post by Nick101 » 17 Jun 2009 13:45

CVMichael wrote: how would be physical connection (what pin to what pin) between them ?

Thanks
Like other I2C connection, CLK <--> CLK, SCL <--> SCL, and SDA <-->SDA. You should not have a problem with Master because you can use MikroC routines but you have to work on the Slave side.
Regards
Nick
[url]http://www.pic_examples.byethost3.com/[/url]

CVMichael
Posts: 239
Joined: 30 Apr 2009 02:36
Location: Canada, Toronto

#3 Post by CVMichael » 17 Jun 2009 17:47

Hi Nick101,

I only found code that communicates with a device like temperature sensor.

Do you have an example where master sends some data, and slave receives the message, then sends back something else ? (i.e. pic to pic code)

barbarossa
Posts: 37
Joined: 25 Jan 2007 14:18
Location: Sweden, Tågarp

#4 Post by barbarossa » 17 Jun 2009 22:00

A data sheet from any I2C peripheral device, such as MCP3221, should answer your questions.

Nick101
Posts: 339
Joined: 06 Aug 2006 15:32
Location: Texas
Contact:

#5 Post by Nick101 » 18 Jun 2009 13:12

Hi,
Someone posted example code long time ago. Here is the link
http://www.mikroe.com/forum/viewtopic.p ... =i2c+slave
Nick
[url]http://www.pic_examples.byethost3.com/[/url]

CVMichael
Posts: 239
Joined: 30 Apr 2009 02:36
Location: Canada, Toronto

#6 Post by CVMichael » 18 Jun 2009 13:34

Excellent Nick101, I can't wait to try it

Thank You

CVMichael
Posts: 239
Joined: 30 Apr 2009 02:36
Location: Canada, Toronto

#7 Post by CVMichael » 22 Jun 2009 06:16

Hi Nick101,

I finally got the time to try the code in the link. I connected the 2 microcontrollers (PIC18F4550 and PIC16F88).

The problem is that it hangs when it's calling the send function.

I connected SCL to SCL and SDA to SDA, what is the CLK pin you were talking about earlier ?

Anyways, from other sources on the net, I found that only SCL and SDA has to be connected, for example:
http://www.botdream.com/blog/2008/02/01 ... ication-2/
Image

Do the 1K resistors have to be there ? you did not say anything about resistors on the SCL / SDA in the previous post.

Here is my code, I am doing a lot of things in the code, it is actually almost 700 lines of code, but I copied and pasted what I think it is more important. (I am also using interrupts)

Code: Select all

// PIC18F4550

void Config(void) {
	T0CON = 0b10000000;		// Set TMR0 in 8bit mode, assign prescaler to TMR0
	TMR0L = 131;          	// Timer0 initial value
	TMR0H = 255;
	INTCON = 0b11100000;  	// Enable TMRO interrupt, and PEIE: Peripheral Interrupt Enable bit

	PIE1.RCIE = 1;			// enable receive interrupt

	PORTA  = 0b00000000;
	LATA   = 0b00000000;
	CMCON  = 0b00000111;	// Turn off Comparator
	ADCON0 = 0b00000001;	// A/D Converter module is enabled
	ADCON1 = 0b00001110;	// AN0 Analog, everything else digital
	TRISA  = 0b11111111;	// PORTA is input
	//         76543210

	PORTB  = 0;
	LATB   = 0b00000000;
	TRISB  = 0b00000000;	// Configure PORTB as output
	//         76543210

	UCON  = 0; // Dissable USB
	PORTC = 0;
	LATC  = 0;
	TRISC = 0b00000000;		// Configure PORTC as output
	//        76543210

	PORTD = 0;
	LATD  = 0;
	TRISD = 0b00000000;   // Configure PORTD as output

	motorz1_enable   = 0;   // Enable
	motorz2_enable   = 0;   // Enable
	motorz_clock     = 0;   // Clock
	motorz_direction = 0;   // Direction

	motorx_enable    = 0;   // Enable
	motorx_clock     = 0;   // Clock
	motorx_direction = 0;   // Direction

	motory_enable    = 0;   // Enable
	motory_clock     = 0;   // Clock
	motory_direction = 0;   // Direction

	//Usart_Init(9600);
	Usart_Init(57600);

    Pwm1_Init(5000);
    Pwm2_Init(5000);
}

const Slave_Addy = 0x69;

void I2C_SendByte(unsigned short send_data){
	I2C_Init(100000);
	I2C_Start();
	I2C_Wr(Slave_Addy);
	I2C_Wr(send_data);
	I2C_Stop();
}

unsigned short I2C_ReadByte(){
	unsigned short read_data;

	I2C_Init(100000);
	I2C_Start();
	I2C_Wr(Slave_Addy + 1);
	read_data = I2C_Rd(0);
	delay_ms(100);
	I2C_Stop();

	return read_data;
}

void main(){
	long read_count = 0;
	long prev_curr_move_pos = 0;

    Config();

    Pwm1_Start();
    Pwm2_Start();

    x_power = 110;
	y_power = 110;
	z_power = 110;
    Pwm2_Change_Duty(x_power);
    Pwm1_Change_Duty(y_power);

    do {
        read_count++;
		if(cnt >= refresh_interval) {  // 20,000 equal to 1 second
		    cnt -= refresh_interval;

			LED1 = !LED1;
			I2C_SendByte(75);
			LED1 = !LED1;

            SendReport(read_count);
	        read_count = 0;
		} else if (buff_len > 0) {
			ProcessCommand();
		} else if (command_type_done != 0) {
            SendReport(read_count);
	        read_count = 0;
	        cnt = 0;

            CommandComplete();
            prev_curr_move_pos = curr_move_pos;
		}
    } while(1);
}
As you can see with this code:

LED1 = !LED1;
I2C_SendByte(75);
LED1 = !LED1;

The LED is OFF when the program starts, the first line it turns the LED ON, then it's supposed to send the data "75", and turn the LED OFF, therefore showing me how long it takes to send the data.

But the LED never turns OFF, and everything hangs, i.e. even the interrupts stop...

Can you help me please ?

Thank You

Nick101
Posts: 339
Joined: 06 Aug 2006 15:32
Location: Texas
Contact:

#8 Post by Nick101 » 22 Jun 2009 14:15

Hi, Michael
CVMichael wrote: what is the CLK pin you were talking about earlier ?
I'm sorry about CLK pin, there is no CLK pin for I2C. I was mix up with the SPI. Both SDA and SCL must have pull-up resistors around 4.7K (1K is fine).
Your problem may be on the slave side. First, you might check if I2C_Wr was succeed, I2C_Wr return 0 if no error so this is what I come up with.

Code: Select all

void I2C_SendByte(unsigned short send_data){ 
   I2C_Init(100000);    // one time initialize need
   I2C_Start(); 
   if (I2C_Wr(Slave_Addy) != 0) LED1 = 1; 
   if (I2C_Wr(send_data) != 0) LED2 = 1; 
   I2C_Stop(); 
} 
Assume you have 2 extra LEDs connected to available pins. If you see any of those LED light, the problem is because it's not succeed writen to the slave.
Regards,
Nick
[url]http://www.pic_examples.byethost3.com/[/url]

Mince-n-Tatties
Posts: 2780
Joined: 25 Dec 2008 15:22
Location: Scotland

#9 Post by Mince-n-Tatties » 25 Jun 2009 11:04

Hi,

i may have missed something by not looking through all the code but...

Code: Select all

LED1 = !LED1;
I2C_SendByte(75);
LED1 = !LED1;
you are using timer0 as an interrupt source, does the I2C function disable interrupts? if not then you stand the chance of a timer0 int breaking the I2C comm's (unless you disable int's before entry or very carefully time when an I2C communications burst can take place). Similarly if the I2C function where to disable interrupts without your knowledge what effect would that have on your code flow. (i truly cant remember if I2C serial comms library tools disable interrupts on-the-fly and i am on a public PC with no compiler installed to check).

From the schematic... why do you have a pull-up on the PicRx line

CVMichael
Posts: 239
Joined: 30 Apr 2009 02:36
Location: Canada, Toronto

#10 Post by CVMichael » 18 Jul 2009 04:42

Mince-n-Tatties wrote:...you are using timer0 as an interrupt source, does the I2C function disable interrupts?
The mikroC documentation does not say anything about interrupts in the I2C Library

Nick101,

I finally had time to continue working on this project. I did the test you asked me, and it stops at this line:

Code: Select all

if (I2C_Wr(Slave_Addy) != 0) LED1 = 1;
The thing is that it does not return from that function, therefore LED1 does not even turn ON... it just waits inside the I2C_Wr function, and never returns. Interrupts keep going though... (I was wrong before about the interrupts stopping also)

If I comment the I2C_Wr lines, then there are no error, everything is as normal.

Do you have any idea what could be wrong ?

Nick101
Posts: 339
Joined: 06 Aug 2006 15:32
Location: Texas
Contact:

#11 Post by Nick101 » 18 Jul 2009 15:24

Hi,
I2C module needs initialize time, put some delay to be sure the slave module compleat initial before you send anything to slave. If it's not help, the problem might be the slave code.
Regards,
Nick
[url]http://www.pic_examples.byethost3.com/[/url]

CVMichael
Posts: 239
Joined: 30 Apr 2009 02:36
Location: Canada, Toronto

#12 Post by CVMichael » 20 Jul 2009 00:00

I put a delay after init, but still nothing:

Code: Select all

void I2C_SendByte(unsigned short send_data){
	I2C_Init(100000);
	delay_ms(50);
	LED3 = 1;
	I2C_Start();
	LED3 = 0;
	delay_ms(50);

	LED4 = 1;
	I2C_Wr(Slave_Addy);
	LED4 = 0;
	
	I2C_Wr(send_data);
	I2C_Stop();
}
LED4 stays ON, so it means I2C_Wr never returns...

I check the slave code also, it looks right:

Code: Select all

unsigned int cnt = 0;

#define LED1  PORTA.F6
#define LASER PORTA.F7

const Addy = 0x69;          // set I2C device address
const Delay_Time = 250;     // port check delay

unsigned short j;           // just dummy for buffer read
unsigned short rxbuffer;
unsigned short tx_data;

void interrupt(){
	if (PIR1.SSPIF == 1){                     // I2C Interrupt
		if (SSPSTAT.R_W == 1){            // transmit data to master, Read request from master
			SSPBUF = tx_data;         // Get data to send
			SSPCON.CKP = 1;           // Release SCL line
			j = SSPBUF;               // That's it
		} else if (SSPSTAT.BF == 0){      // all done,
			j = SSPBUF;               // Nothing in buffer so exit
		} else if (SSPSTAT.D_A == 1){     //recieve data from master, Data [not address]
			rxbuffer = SSPBUF;        // get data
			LED1 = !LED1;
			j = SSPBUF;               // read buffer to clear flag [address]
		} else {
			j = SSPBUF;               // read buffer to clear flag [address]
			PIR1.SSPIF = 0;           // reset SSP interrupt flag
		}
	} else {
		TMR0 = 131;
		INTCON.TMR0IE = 1;
		INTCON.TMR0IF = 0;
		//INTCON = 0b00100000;  // Set T0IE, clear T0IF
		//         76543210

		cnt++;
		if (cnt > 1000) {
			LASER = !LASER;
			cnt = 0;
		}
	}
}

void Config(){
	OSCCON  = 0b01110000;   // Internal 8MHz

	//ADCON1 = 0;      // All ports set to digital
	PORTA  = 0;
	TRISA  = 0b00111111;
	//         76543210

	TMR0       = 131;          // Timer0 initial value
	OPTION_REG = 0b10000001;   // Assign prescaler to TMR0
	//             76543210

	PORTB = 0;
	TRISB = 0b00000000;   // Configure PORTB as output

	SSPADD = Addy;        // Get address (7bit). Lsb is read/write flag
	SSPCON = 0b00110110;  // Set to I2C slave with 7-bit address
	//         76543210

	PIE1.SSPIE = 1;        // enable SSP interrupts
	INTCON = 0b11100000;   // Enable TMRO interrupt AND enable INTCON.GIE
}

void main(){
	unsigned int ad0 = 0, ad1 = 0, ad2 = 0, ad3 = 0;

	Config();

	LED1 = 0;
	LASER = 0;

	do {
		ad0 = Adc_Read(0);
                //ad1 = Adc_Read(1);
                //ad2 = Adc_Read(2);
                //ad3 = Adc_Read(3);

                tx_data = ad0 / 4;
                Delay_ms(Delay_Time);
        } while(1);
}
I don't know what else to do / check... I am almost giving up. I think I'll have a better change if I make my own protocol comunication between the PICs...

Nick101
Posts: 339
Joined: 06 Aug 2006 15:32
Location: Texas
Contact:

#13 Post by Nick101 » 20 Jul 2009 01:32

I did not see the config SCL and SDA as input. Add this in Config() :

Code: Select all

TRISC |= 0b00011000;     // SCL and SDA pins are input
Also interrupt flags (SSPIF) need to be clear.
Nick
[url]http://www.pic_examples.byethost3.com/[/url]

bobx
Posts: 115
Joined: 14 Mar 2010 08:35

Re: Pic to Pic I2C

#14 Post by bobx » 12 Jun 2010 19:43

Hi,Nick101.Why you suggest this instruction for I2C config;( TRISC |= 0b00011000; // SCL and SDA pins are input )? Why we do not simply write;( TRISC = 0b00011000; )
instead of above instruction?Would you please tell me that?
Thanks,

Post Reply

Return to “mikroC General”