![](templates/subSilver/images/CCSLogo.jpg) |
![CCS C Software and Maintenance Offers](templates/subSilver/images/forumAd6.jpg) |
View previous topic :: View next topic |
Author |
Message |
christian.koji
Joined: 12 May 2010 Posts: 16
|
i2c problem on read |
Posted: Wed May 12, 2010 9:06 am |
|
|
Hey guys, I'm with a little problem in my implementation. I'm a new pic programmer and I'm trying to program a i2c communication between 2 pics, however i don't know how to receive multiples data on slave. My problems is: I'm sending some data from the master. Like this:
Code: |
i2c_start();
i2c_write(device_addr);
i2c_write(data);
i2c_stop();
|
and then I'm receiving on the slave in an interrupt
Code: |
#INT_SSP NOCLEAR
void ssp_interupt ()
{
BYTE data1,data2;
data1 = i2c_read();
SSPOV = 0;
BF = 0;
SSPBUF = 0;
CKP = 1;
printf(lcd_escreve, "\fReceived %x", data1);
while(!i2c_poll());
//delay_ms(3000);
data2 = i2c_read();
delay_ms(1500);
printf(lcd_escreve, "\fReceived %x ", data2);
delay_ms(1500);
printf(lcd_escreve, "\fWaiting");
clear_interrupt(int_SSP);
}
|
well, i'm not receiving like i thought, both data1 and data2 have the same information.
does anyone know what's the problem??
thanks |
|
![](templates/subSilver/images/spacer.gif) |
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed May 12, 2010 11:43 am |
|
|
If you want to get specific bytes such as the Slave Address byte,
you need to be able to identify them in the interrupt routine.
CCS has a routine which helps you to do this:
Look at the CCS example file, Ex_Slave.c. It emulates a small eeprom.
It shows how to use the i2c_isr_state routine.
Quote: | c:\program files\picc\examples\ex_slave.c |
Normally, we don't have any interest in looking at the Slave Address byte
in the interrupt routine. The fact that the Slave is getting the interrupt
means that it was addressed successfully by the Master. There's no need
to look at the slave address byte. But, if you wanted to, then you would
check to see if i2c_isr_state() returned a 0. Then the Slave Address can
be read with i2c_read().
See the CCS manual for more information on i2c_isr_state(). |
|
![](templates/subSilver/images/spacer.gif) |
christian.koji
Joined: 12 May 2010 Posts: 16
|
|
Posted: Fri May 14, 2010 5:27 am |
|
|
Well, i guess i was thinking wrong. I thought when the address match the hw generates an interrupt and then i could read both the address and the data. But reading what you wrote and the example i guess theres is an interrupt to the address and another one for the data... am i right?
So i just have to do state = i2c_isr_state();
and when:
• state = 1 and state <= 0x80 --> i2c_read() return the Address
• state = 2 and state <= 0x80 --> i2c_read() return the Data
if i'm wrong correct me please =] |
|
![](templates/subSilver/images/spacer.gif) |
christian.koji
Joined: 12 May 2010 Posts: 16
|
|
Posted: Fri May 14, 2010 7:25 am |
|
|
Ok, i tried to do exactly like the example and i'm still with the same problem =/
My code on slave.c
Code: |
BYTE address, data, buffer;
#INT_SSP NOCLEAR
void ssp_interupt ()
{
BYTE state, incoming;
state = i2c_isr_state();
if(state < 0x80) //master is sending data
{
incoming = i2c_read();
if(state == 0)
{
printf(lcd_escreve,"\fCalling-me");
}
if(state == 1) //first received byte is address
{
address = incoming;
printf(lcd_escreve,"\fAddress: %x", address);
printf(lcd_escreve,"\nData: No Data");
delay_ms(2000);
}
if(state == 2) //second received byte is data
{
data = incoming;
printf(lcd_escreve,"\fAddress: %x", address);
printf(lcd_escreve,"\nData: %x", data);
}
}
if(state == 0x80) //master is requesting data
{
i2c_write (buffer); //send requested data
}
}
void main()
{
lcd_ini();
delay_ms(500);
set_tris_c(0xFF);
set_tris_d(0x00);
printf(lcd_escreve,"\f Inicio...");
enable_interrupts(INT_SSP); //enable I2C interrupts
enable_interrupts(GLOBAL);
while(TRUE)
{
delay_ms(100);
if (SSPOV || BF)
{
output_low(pin_d0);
delay_ms(2000);
SSPOV = 0;
BF = 0;
}
else output_high(pin_d0);
}
}
|
my code on master.c
Code: |
void envia_i2c(BYTE end_disp, BYTE dado)
{
i2c_start(); //begin transmission
i2c_write(end_disp); //select address of device to communicate with
i2c_write(dado); //send actual data
i2c_stop(); //terminate communication
delay_ms(10); //debouncing delay
}
void main()
{
lcd_ini();
delay_ms(500);
set_tris_b(0xF0);
set_tris_c(0b10100111);
set_tris_d(0x00);
output_b(0xFE);
printf(lcd_escreve,"\f");
printf(lcd_escreve,"Begin...");
while(TRUE)
{
if(!input(PIN_B4)){
printf(lcd_escreve,"\f");
printf(lcd_escreve,"Send 1");
envia_i2c(end_2, 1);
printf(lcd_escreve,"\f");
printf(lcd_escreve,"1 Sent");
}
if(!input(PIN_B7)){
printf(lcd_escreve,"\f");
printf(lcd_escreve,"Send 2");
envia_i2c(end_2, 2);
printf(lcd_escreve,"\f");
printf(lcd_escreve,"2 Sent");
}
}
}
|
PIN_B4 and PIN_B7 are pins of a keypad. So, when i push button 1 it sends 1 and when i push button 2 it sends 2...
Whats is happening?
when i first press button 1 in Master Device, it sends the address(0xB0) and the data(0x01). In the slave, i'm supposed to receive both address and Data, But at first i'm receiving only the address. So the variables "address" and "data" receives 0xB0.
so the lcd prints:
Address: b0
Data: b0
When i press the button 1 again, it sends address(0xB0) and data(0x01) again... But, In slave device when i print in the LCD it prints
Address: 01
Data: No b0
I dont know what is happening nor even how to fix it
maybe i've to set or clear a bit of some register.. but i really dont know... if some one could help i'd be very greatfull =P
I'm using 7bits address, 7bits is default or i have to set it? if i have to set, where do i set it?? |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19366
|
|
Posted: Fri May 14, 2010 8:14 am |
|
|
The big problem here is time.
Even one character of your print statements, takes longer than the time between successive interrupts....
To see what is happening, just write the successive bytes to a buffer, and set a value in the interrupt to say what the isr_state was showing. Then have you 'main' output the messages, and the bytes from the buffer.
Get out of the ISR _quickly_. It is always better to do this, but it is particularly important on I2C.
Best Wishes |
|
![](templates/subSilver/images/spacer.gif) |
christian.koji
Joined: 12 May 2010 Posts: 16
|
|
Posted: Wed May 19, 2010 5:47 am |
|
|
Hey thanks, the time really was my problem now its working for receive 2 bytes, but not for 3 bytes =/
i put my code below if you could help me...
slave.c
Code: |
#INT_SSP NOCLEAR
void ssp_interupt ()
{
BYTE state, incoming;
state = i2c_isr_state();
if(state < 0x80) //master is sending data
{
incoming = i2c_read();
if(state == 0)
{
address = incoming;
}
if(state == 1) //first received byte is address
{
buffer[i++] = incoming;
//data2 = incoming;
//legenda[i++] = 2;
}
if(state == 2) //second received byte is data
{
//data1 = incoming;
buffer[i++] = incoming;
//legenda[i++] = 3;
}
}
if(state == 0x80) //master is requesting data
{
i2c_write (0x25); //send requested data
}
}
void main()
{
lcd_ini();
delay_ms(500);
set_tris_c(0xFF);
set_tris_d(0x00);
set_tris_b(0xF0); ;
output_b(0xFE);
printf(lcd_escreve,"\f Inicio...");
enable_interrupts(INT_SSP); //enable I2C interrupts
enable_interrupts(GLOBAL);
i = 0;
while(TRUE)
{
//address = 0;
//data = 0;
delay_ms(300);
if(i>=4) i=0;
data1 = buffer[0];
data2 = buffer[1];
data3 = buffer[2];
data4 = buffer[3];
printf(lcd_escreve,"\f%x %x %x %x %x", data1, data2, data3, data4, address);
}
}
|
i also tried to put an if to state==3, 'cause i saw that every time i'm receiving the bytes sent, the first is received in state=1 and the second in state=2, but didnt work too
something strange happend when i sent 3 bytes from master. In slave i'm printing the buffer in the main, if i send 0x01, 0x02 and 0x03 to slave it will print 01 02 02 01, if i send 0x04, 0x05 and 0x06 it will print 04 05 05 04 o.O |
|
![](templates/subSilver/images/spacer.gif) |
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed May 19, 2010 12:29 pm |
|
|
Quote: |
#INT_SSP NOCLEAR
void ssp_interupt ()
{
|
Here you have 'NOCLEAR', but you never clear the interrupt by yourself
in code. I don't see why you do this.
CCS normally clears the peripheral interrupt bit in (hidden) code just
at the end of the interrupt routine, before it returns from the routine.
If you put in 'NOCLEAR' it won't do that. The SSP interrupt will just keep
occurring over and over again. |
|
![](templates/subSilver/images/spacer.gif) |
christian.koji
Joined: 12 May 2010 Posts: 16
|
|
Posted: Fri May 21, 2010 11:03 am |
|
|
Ok, thats was my problem... =P
I took out the NOCLEAR and add a state=3 and then I'm receiving the 3 datas my interrupt is like this:
Code: |
#INT_SSP
void ssp_interupt ()
{
j=1;
BYTE state, incoming;
state = i2c_isr_state();
if(state < 0x80) //master is sending data
{
incoming = i2c_read();
if(state == 0)
{
address = incoming;
}
if(state == 1) //first received byte is address
{
mem_add = incoming;
}
if(state == 2) //second received byte is data
{
buffer[i++] = incoming;
}
if(state == 3) //third received byte is data
{
buffer[i++] = incoming;
}
}
if(state == 0x80) //master is requesting data
{
i2c_write(info[mem_add]);
}
}
|
thanks all |
|
![](templates/subSilver/images/spacer.gif) |
|
|
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
|