View previous topic :: View next topic |
Author |
Message |
Zulander
Joined: 04 Dec 2006 Posts: 14
|
I2c MASTER/SLAVE Again ! |
Posted: Wed Mar 14, 2007 4:56 pm |
|
|
Hi, guys
I am having a problem with I2c master and slave communication. I’ve searched the whole forum for master slave example I’ve tried all of them, my master can’t see to read the data form the SLAVE, I know that the slave is sending data because I am pulsing an LED (pulselight();)
My SCL/SDA are connected to each other with a pull-up resistors (4.7K each)
So is my code wrong or my HW ?
thank you
Code: |
-----------------Salve.h--------------
#include <16F690.h>
#device adc=8
#FUSES NOWDT //No Watch Dog Timer
#FUSES RC //Resistor/Capacitor Osc with CLKOUT
#FUSES NOPROTECT //Code not protected from reading
#FUSES BROWNOUT //Reset when brownout detected
#FUSES NOMCLR //Master Clear pin enabled
#FUSES NOCPD //No EE protection
#FUSES NOPUT //No Power Up Timer
#FUSES IESO //Internal External Switch Over mode enabled
#FUSES FCMEN //Fail-safe clock monitor enabled
#use delay(clock=4000000)
#use i2c(Slave,sda=PIN_B4,scl=PIN_B6,address=0xa0,FORCE_HW, SLOW)
|
Code: |
-----------------Salve.c--------------
#include "slave.h"
#INT_SSP
void ssp_interupt ()
{
BYTE incoming, state;
state = i2c_isr_state();
if(state < 0x80) //Master is sending data
{
incoming = i2c_read();
if(state == 1) //First received byte is address
address = incoming;
if(state == 2) //Second received byte is data
buffer[address] = incoming;
}
if(state == 0x80) //Master is requesting data
{
stepup();
i2c_write(buffer[address]);
pulselight();
}
}
void main(){
setup_adc_ports(NO_ANALOGS | VSS_VDD);
setup_adc(PIN_A0);
setup_timer_0(RTCC_INTERNAL | RTCC_DIV_1);
setup_timer_1(T1_DISABLED);
setup_timer_2(T2_DISABLED, 0, 1);
setup_comparator(NC_NC_NC_NC);
// This device COMP currently not supported by the PICWizard
enable_interrupts(INT_SSP);
enable_interrupts(GLOBAL);
setup_oscillator(False);
while(1){}
}
|
Code: |
------------Controller.h----------------
#include <16F690.h>
#device adc=8
#FUSES NOWDT //No Watch Dog Timer
#FUSES BROWNOUT //Reset when brownout detected
#FUSES MCLR //Master Clear pin enabled
#FUSES NOCPD //No EE protection
#FUSES NOPUT //No Power Up Timer
#FUSES IESO //Internal External Switch Over mode enabled
#FUSES FCMEN//Fail-safe clock monitor enabled
#use delay(clock=4000000)
#use rs232(baud=9600,parity=N,xmit=PIN_B7,rcv=PIN_B5,bits=8)
#use i2c(MASTER,sda=PIN_B4,scl=PIN_B6,FORCE_HW, SLOW)
// ***************** COMMUNICATION VARIABLE *****************
|
Code: |
---------------------------------- MASTER.C -------------------------------
#include "Controller.h"
void main()
{
int8 data;
// Write the letter 'B' to the slave board.
i2c_start();
i2c_write(0xA0);
i2c_write(0x00);
i2c_write('B');
i2c_stop();
// Read from the slave board and display the data.
i2c_start();
i2c_write(0xA0);
i2c_write(0x00);
i2c_start();
i2c_write(0xA1);
data = i2c_read(0);
i2c_stop();
printf("read %c \n\r", data);
while(1);
}
|
|
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Mar 14, 2007 4:59 pm |
|
|
What's your compiler version ? |
|
|
Zulander
Joined: 04 Dec 2006 Posts: 14
|
|
Posted: Wed Mar 14, 2007 5:56 pm |
|
|
PCM programmer wrote: | What's your compiler version ? |
The compiler version is 4.023 |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Mar 14, 2007 6:51 pm |
|
|
Quote: | -----------------Slave.h--------------
#include <16F690.h>
#device adc=8
#FUSES NOWDT //No Watch Dog Timer
#FUSES RC //Resistor/Capacitor Osc with CLKOUT |
Before we go any further, is there a reason why you're using an
external R-C oscillator, instead of the internal oscillator ?
The external oscillator requires a resistor and a capacitor, and it's
not a very accurate.
Quote: | ------------Controller.h----------------
#include <16F690.h>
#device adc=8
#FUSES NOWDT //No Watch Dog Timer
#FUSES BROWNOUT //Reset when brownout detected |
For the Master PIC, you have not specified an oscillator fuse. |
|
|
Zulander
Joined: 04 Dec 2006 Posts: 14
|
|
Posted: Wed Mar 14, 2007 8:51 pm |
|
|
PCM programmer wrote: | is there a reason why you're using an
external R-C oscillator |
Yes, i have used it for testing and i have removed it and i am no longer using it !
PCM programmer wrote: | For the Master PIC, you have not specified an oscillator fuse. |
Yes, I have forgot end the oscillator fuse and i have fixed the problem with the fallowing segment: Code: | #FUSE INTRC //Internal RC Osc |
|
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Mar 14, 2007 9:54 pm |
|
|
I looked at the .LST file for vs. 4.023 and the compiler is using the
correct register addresses, so I don't see a problem there.
There are two things in your code that are wrong.
Quote: | void main(){
setup_adc_ports(NO_ANALOGS | VSS_VDD);
setup_adc(PIN_A0);
setup_timer_0(RTCC_INTERNAL | RTCC_DIV_1);
setup_timer_1(T1_DISABLED);
setup_timer_2(T2_DISABLED, 0, 1);
setup_comparator(NC_NC_NC_NC);
// This device COMP currently not supported by the PICWizard
enable_interrupts(INT_SSP);
enable_interrupts(GLOBAL);
setup_oscillator(False);
while(1){}
} |
1. The parameter for setup_adc() should be ADC_OFF, not a pin number.
2. The setup_oscillator() statement writes 0x00 to the OSCCON register.
This tells the internal oscillator to run at 31 KHz. That's not what you
want. Delete that line.
The compiler will automatically put in code to setup the OSCCON
register to program the internal oscillator to the same frequency
that you specify in your #use delay() statement. This works if
the #use delay() statement is placed after the #fuses statement
that specifies INTRC or INTRC_IO. (Which you are correctly doing).
You don't need a setup_oscillator() statement. Delete it. |
|
|
Zulander
Joined: 04 Dec 2006 Posts: 14
|
|
Posted: Thu Mar 15, 2007 6:10 am |
|
|
OK, let me try what you suggested and ill get back to you |
|
|
Zulander
Joined: 04 Dec 2006 Posts: 14
|
|
Posted: Fri Mar 16, 2007 12:45 pm |
|
|
So, I got my communication to work but, the data is not synchronizing.
I am sending 0x0C using i2c_write(0x0C);
And I am reading D7
am i using the wrong switch ?
it's really wired, I've used a power supply to power up the chip and i am reading DD now !
thank |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri Mar 16, 2007 1:13 pm |
|
|
Post your current master and slave test code. (Fully compilable, with
the actual #fuses statements, etc.) |
|
|
Zulander
Joined: 04 Dec 2006 Posts: 14
|
|
Posted: Fri Mar 16, 2007 1:22 pm |
|
|
Code: |
//slave.h
#include <16F690.h>
#device adc=8
#FUSES NOWDT //No Watch Dog Timer
#FUSES NOPROTECT //Code not protected from reading
#FUSES BROWNOUT //Reset when brownout detected
#FUSES NOMCLR //Master Clear pin enabled
#FUSES NOCPD //No EE protection
#FUSES NOPUT //No Power Up Timer
#FUSES IESO //Internal External Switch Over mode enabled
#FUSES FCMEN //Fail-safe clock monitor enabled
#FUSES INTRC
#use delay(clock=4000000)
#use i2c(Slave,sda=PIN_B4,scl=PIN_B6,address=0xa0)
|
Code: |
//Slave.c
#include "slave.h"
BYTE address, buffer[0x10];
void pulsepin(void){
output_high(PIN_C0);
delay_us(100);
output_low(PIN_C0);
}
#INT_SSP
void ssp_interupt ()
{
BYTE incoming, state;
state = i2c_isr_state();
if(state < 0x80) //Master is sending data
{
incoming = i2c_read();
if(state == 1) //First received byte is address
address = incoming;
if(state == 2) //Second received byte is data
buffer[address] = incoming;
}
if(state == 0x80) //Master is requesting data
{
i2c_write(buffer[address]);
pulsepin();
}
}
void main(){
setup_adc_ports(NO_ANALOGS | VSS_VDD);
setup_adc(ADC_OFF);
setup_timer_0(RTCC_INTERNAL | RTCC_DIV_1);
setup_timer_1(T1_DISABLED);
setup_timer_2(T2_DISABLED, 0, 1);
setup_comparator(NC_NC_NC_NC);
// This device COMP currently not supported by the PICWizard
enable_interrupts(INT_SSP);
enable_interrupts(GLOBAL);
while(1){}
}
|
Code: |
//Master.h
#include <16F690.h>
#device adc=8
#FUSES NOWDT //No Watch Dog Timer
#FUSES BROWNOUT //Reset when brownout detected
#FUSES MCLR //Master Clear pin enabled
#FUSES NOCPD //No EE protection
#FUSES NOPUT //No Power Up Timer
#FUSES IESO //Internal External Switch Over mode enabled
#FUSES FCMEN//Fail-safe clock monitor enabled
#FUSES INTRC
#use delay(clock=4000000)
#use rs232(baud=9600,parity=N,xmit=PIN_B7,rcv=PIN_B5,bits=8)
#use i2c(Master,sda=PIN_B4,scl=PIN_B6,fast)
// ***************** COMMUNICATION VARIABLE *****************
|
Code: |
//master.c
#include "master.h"
static int Sensor3_Add=0xa0;
void read_temp(int add)
{
int data,lsb,lsba;
//char xRETURN[4];
i2c_start();
i2c_write(0xA0);
i2c_write(0x00);
i2c_write('B');
i2c_stop();
delay_ms(1000);
i2c_start();
i2c_write(0xA0);
i2c_write(0x00);
i2c_start();
i2c_write(0xA1);
data = i2c_read(0);
i2c_stop();
printf("read %x \n\r", data);
}
void main(void){
int x;
while (1){
//delay_ms(1000);
read_temp(Sensor3_Add);
}
}
|
|
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri Mar 16, 2007 2:07 pm |
|
|
I don't have any 16F690's at the moment. I tested your software
with two PicDem2-Plus boards, with a 16F877 running at 4 MHz on
each board. I used vs. 4.023, and I made as few changes as
possible to your posted code to make it compile for a 16F877.
I have a 4.7K pull-up to +5v on SDA and on SCL.
It worked. It displays this:
Quote: |
read 42
read 42
read 42
read 42
read 42
read 42
read 42
|
Things to try:
1. Don't run the master in "fast" mode. Remove the FAST parameter
from the #use i2c() statement.
2. Check your pull-up resistor size. Use 2.2K to 4.7K.
If you can't make it work, I ordered a 16F690 a few days ago.
It should come in early next week and I can test it as the slave chip then. |
|
|
Zulander
Joined: 04 Dec 2006 Posts: 14
|
|
Posted: Fri Mar 16, 2007 2:32 pm |
|
|
Hi,
I don't understand why you are reading 42 ?
isn't 42 a *, we should get 66 for B
p.s: i went from 4.7 to 1k resistor and i have updated the compiler version to 4.029
Thanks PCM for helping me !!! |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri Mar 16, 2007 2:41 pm |
|
|
Quote: | printf("read %x \n\r", data); |
The printf statement uses "%x" as the format specifier. This means
the output is displayed in Hex, and 'B' = 0x42 in hex.
Quote: | i went from 4.7 to 1k resistor |
In my post I said to use anything from 2.2K to 4.7K.
How did that get turned into "change it to 1k" ?
1K might work with PICs, because they have a strong pull-down
capability on the pin drivers. But for normal i2c chips, 1K violates
the specification. For a 5v i2c bus, 1.6K is about the lowest value
allowed.
http://www.maxim-ic.com/appnotes.cfm?appnote_number=476 |
|
|
Zulander
Joined: 04 Dec 2006 Posts: 14
|
|
Posted: Fri Mar 16, 2007 8:10 pm |
|
|
Quote: | The printf statement uses "%x" as the format specifier. |
Ahh yes, my fault i should have double checked for the printf which was HEX and not DEC,
Quote: | How did that get turned into "change it to 1k" ? |
After hours of testing, I was tired; I thought that changing the pull-up value of the resistor world help, and it got me nowhere. But Monday will go with 4.7k. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri Mar 16, 2007 8:30 pm |
|
|
On Tuesday I should have a 16F690 and can test it with the Ex_Slave.c program. |
|
|
|