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

i2c problem on read

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
christian.koji



Joined: 12 May 2010
Posts: 16

View user's profile Send private message

i2c problem on read
PostPosted: Wed May 12, 2010 9:06 am     Reply with quote

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
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Wed May 12, 2010 11:43 am     Reply with quote

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:
Code:
i2c_isr_state()


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().
christian.koji



Joined: 12 May 2010
Posts: 16

View user's profile Send private message

PostPosted: Fri May 14, 2010 5:27 am     Reply with quote

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 =]
christian.koji



Joined: 12 May 2010
Posts: 16

View user's profile Send private message

PostPosted: Fri May 14, 2010 7:25 am     Reply with quote

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??
Ttelmah



Joined: 11 Mar 2010
Posts: 19328

View user's profile Send private message

PostPosted: Fri May 14, 2010 8:14 am     Reply with quote

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
christian.koji



Joined: 12 May 2010
Posts: 16

View user's profile Send private message

PostPosted: Wed May 19, 2010 5:47 am     Reply with quote

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
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Wed May 19, 2010 12:29 pm     Reply with quote

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.
christian.koji



Joined: 12 May 2010
Posts: 16

View user's profile Send private message

PostPosted: Fri May 21, 2010 11:03 am     Reply with quote

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
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
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