View previous topic :: View next topic |
Author |
Message |
antosci
Joined: 29 Apr 2013 Posts: 13
|
I2C slave receives address instead of data |
Posted: Fri Apr 25, 2014 8:36 am |
|
|
hi all !
I'm trying to send/read data to/from slave board.
Master is a 18F47J53 based board, slave is a 16F1828 based board.
Slave address is 0xBA and i'm using pins that are shown in the datasheet as scl1 sda1 (slave) and scl2 sda2 (master)
The slave board has 8 led that show the byte received in binary.
What happen is the follow: instead of showing 00000001 (0x01) sent from master, it shows 10111010 (0xBA) which is the address of the slave...
I don't know how to fix this problem...
Master code:
Code: |
#include <scheda_principale_test.h>
#include <usb_cdc.h>
void main()
{
enable_interrupts(INT_RDA);
enable_interrupts(GLOBAL);
usb_cdc_init();
usb_init();
delay_ms(3000);
int16 lux;
int16 Temp;
output_float(PIN_D0);
output_float(PIN_D1);
int z=1;
while(1)
{
lux = read_lux();
Temp = onboard_temperature();
printf(usb_cdc_putc,"\r\nluminosita = %Lu",lux);
printf(usb_cdc_putc,"\r\ntemperatura = %Ld",Temp);
i2c_start(OUT);
i2c_write(OUT,0xba);
i2c_write(OUT,z);
i2c_stop(OUT);
delay_ms(50);
i2c_start(OUT);
i2c_write(OUT,0xbb);
z=i2c_read(OUT,0);
i2c_stop(OUT);
delay_ms(50);
printf(usb_cdc_putc,"\r\ni2c effettuata risposta %u", z);
delay_ms(2000);
z++;
}
} |
and slave code is:
Code: |
#include <scheda_led_test.h>
int8 value = 5;
int8 g = 0;
#INT_SSP
void i2c_isr()
{
output_high(LED7);
BYTE state;
state=i2c_isr_state();
if(state < 0x80) //Master is sending data
{
value = i2c_read();
}
if(state >= 0x80) //Master is requesting data
{
i2c_write(value);
}
delay_ms(10);
output_LOW(LED7);
}
void main()
{
enable_interrupts(GLOBAL);
enable_interrupts(INT_SSP);
while (1)
{
output_C(value);
delay_ms(50);
}
} |
settings of i2c in master are:
Code: | #use i2c(master, sda=PIN_D1, scl=PIN_D0, stream=OUT, FORCE_HW, FAST=200000)
#use i2c(master, sda=PIN_B5, scl=PIN_B4, stream=ON_BOARD, FORCE_HW) |
and in slave are:
Code: | #use i2c(Slave,sda=PIN_B4,scl=PIN_B6,address=0xba, FORCE_HW, FAST=200000) |
When master reads data from slave everything is ok but when master sends data to slave it receives 0xBA instead of 1 (z)
after when master read slave responds with 0xBA (obviously)...
What's the problem ?
Thanks everybody
Last edited by antosci on Fri Apr 25, 2014 11:00 am; edited 1 time in total |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19537
|
|
Posted: Fri Apr 25, 2014 9:40 am |
|
|
Comments/problems:
1) On state 0x80, the slave must _read_ and then write. This is required, and failure to do so can cause all sorts of problems on some PIC's.
2) The first byte received will always be the address. This is when isr_state ==0. You should not display the value till you get to state==1.
Best Wishes |
|
|
antosci
Joined: 29 Apr 2013 Posts: 13
|
|
Posted: Fri Apr 25, 2014 11:05 am |
|
|
do you mean i should write something like this ?
Code: | #INT_SSP
void i2c_isr()
{
output_high(LED7);
BYTE state;
state=i2c_isr_state();
if(state < 0x80) //Master is sending data
{
if(state == 0x00) {i2c_read();}
else{ value = i2c_read();}
}
if(state >= 0x80) //Master is requesting data
{
if (state == 0x80)
{
i2c_read();
}else
{
i2c_write(value);
}
}
delay_ms(10);
output_LOW(LED7);
} |
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19537
|
|
Posted: Fri Apr 25, 2014 11:11 am |
|
|
Not quite.
State 0x80, needs to read then write.
Look at the slave example. If you look at it carefully, you will see it does both on this one state. |
|
|
antosci
Joined: 29 Apr 2013 Posts: 13
|
|
Posted: Fri Apr 25, 2014 12:04 pm |
|
|
slave example is:
Code: | #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]);
}
}
|
i write something similar now:
Code: | #INT_SSP
void i2c_isr()
{
output_high(LED7);
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
value = incoming;
if(state == 2) //Second received byte is data
g = incoming;
}
if(state == 0x80) //Master is requesting data
{
i2c_write(value);
}
delay_ms(10);
output_LOW(LED7);
} |
now "value" is always 5 (as declaration) and LEDs are 0 0 0 0 0 1 0 1.
this mean nothing is received from master.
when master attempt to read, slave respond with 118 (0x76) O.o
i forgot to say i'm using 10K pull-up resistor. could it be a wrong value ?? |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19537
|
|
Posted: Fri Apr 25, 2014 1:23 pm |
|
|
You need two resistors. One on each line. 10K should be OK if the line is short, but 4K7 is more commonly a good starting point. |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9241 Location: Greensville,Ontario
|
|
Posted: Fri Apr 25, 2014 6:47 pm |
|
|
10K might be just a wee bit too high.....
4k7 should work fine...
3k3 has always worked for me....
jay |
|
|
antosci
Joined: 29 Apr 2013 Posts: 13
|
|
Posted: Tue Apr 29, 2014 11:07 am |
|
|
thanks a lot for help. i solved...
change 10K pull-up resistor in 3.9K
but it didn't work.
so i thought: maybe slave can receive first byte (which is the address)
and even not the second byte (which is the data) cause there's a delay on interrupts entering operation.
Deleting the
Code: | output_high(LED7);
[...]
delay_ms(10);
output_LOW(LED7); |
and declaring
Code: | BYTE incoming,state; |
out of interrupt (i know, this was unnecessary )
everything works fine.
thanks again |
|
|
|