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 CCS Technical Support

HELP WITH I2C PIC16F690

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



Joined: 05 Feb 2005
Posts: 10

View user's profile Send private message Send e-mail MSN Messenger

HELP WITH I2C PIC16F690
PostPosted: Mon Aug 21, 2006 8:17 am     Reply with quote

HELLO,

I was looking for information in all topics about I2C and I still can't solve my problem.....

I'm trying to comunicate 2 PIC16F690 with I2C, 1 Master and 1 Slave, but i don't know what is the problem with my code......the 'ACK' bit sometimes is received and sometimes isn't.

START
1st byte - adress
2nd byte - data
3rd byte - data
STOP

Sometimes the master reveceives 3 'ACK', 1 per bit.....and doesn't receive the 'NACK'......othewise there are no any 'ACK'.

The 'ssp_handler' routine in the SLAVE is like Microchip's one.

Thanks

Henry


Last edited by henry on Tue Aug 22, 2006 2:37 am; edited 2 times in total
Ttelmah
Guest







PostPosted: Mon Aug 21, 2006 9:07 am     Reply with quote

Without looking too deeply, there are two big problems 'leaping out', which are connected.
You are using the 'INT_SSP' defintion, which inherently implies that the _compiler_ will have allready 'added' the interrupt register saves, before this code is called. You then save the registers inside your routine, which is both unnecessary (given that the compiler has already done this), and takes _time_. Now you send bytes immediately following one another. Given the time delays in the interrupt handling (worse in C, because of the number of registers involved), and especially given your code effectively 'saving' the registers twice, the slave just does not have time to actually handle it's 'end' of the transaction...
You need to make a decision, whether you are going to use the existing assembler SSP handler, and the assembler register saving (which should only be used together, and without _any_ C in the routines), in which case, your interrupt handler, needs to be defined as 'int_global', or use the C approach, in which case a lot of the routine can be thrown away, since the compiler has already done the necessary register saving. However the 'ssp_handler' routine you are using, needs a _lot_ of extra registers saved (it is using array accesses, and a switch statement in particular), so going to assembler, would involve a lot of work.
Look at the CCS example I2C slave routine, which shows how to handle this, and slow down the master transactions a little, and you may then have a chance.

Best Wishes
henry



Joined: 05 Feb 2005
Posts: 10

View user's profile Send private message Send e-mail MSN Messenger

PostPosted: Tue Aug 22, 2006 1:43 am     Reply with quote

Hello everybody,

Now, i changed my code and i can send and receive correctly the 3 bytes i want...

START
delay....
1st byte - Address
delay...
2nd byte - data
delay...
3rd byte - data
delay...
STOP

The problem is that i'm not receiving the NACK at the end of the last byte.

How the MASTER sends a NACK???

Thanks

Henry

Code:


/////////////////////////////////////////////////////////////////////////////////
MASTER
/////////////////////////////////////////////////////////////////////////////////


#if defined(__PCM__)
#include <16F690.h>
#device ADC=10
#fuses HS, NOPROTECT, NOBROWNOUT, NOMCLR, NOCPD, NOWDT, PUT, NOIESO, NOFCMEN
#use delay(clock=20000000)
#use rs232(baud=19200, xmit=PIN_B7, rcv=PIN_B5, BITS = 8 )
#use i2c(MASTER, sda=PIN_B4, scl=PIN_B6, SLOW=100000 )


////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////FUNCIONES//////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

#include "inicializacion.c"         //Config. inicial de todos los registros
#include "puerto_serie.c"           //On serial port, off serial port....

////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////MAIN/////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////


void  main()
{


   delay_cycles( 1 );

   output_a(0b00000000);                  //Latch del puerto a 00
   output_b(0b00000000);                  //Latch del puerto a 00
   output_c(0b00000000);                  //Latch del puerto a 00

   delay_cycles( 1 );

   set_tris_a(0b11111111);                //All I/O ports as inputs
   set_tris_b(0b11111111);
   set_tris_c(0b11111111);

   delay_cycles( 1 );


   puerto_serie_off();     //Serial port off


   inicializacion();       //Inicializacion general de registros


   delay_ms( 1000 );


   do
   {

      i2c_start();            //start bit
      delay_cycles( 50 );
      i2c_write(0xa0);        //Send slave address
      delay_cycles( 50 );
      i2c_write(1);           //Send first data
      delay_cycles( 50 );
      i2c_write(40);          //Send second data
      delay_cycles( 50 );
      i2c_stop();             //Stop bit

      delay_ms( 1000 );       //delay

      i2c_start();            //start bit
      delay_cycles( 50 );
      i2c_write(0xa0);        //Send slave address
      delay_cycles( 50 );
      i2c_write(2);           //Send first data
      delay_cycles( 50 );
      i2c_write(80);          //Send second data
      delay_cycles( 50 );
      i2c_stop();             //Stop bit

      delay_ms( 1000 );       //delay

      i2c_start();            //start bit
      delay_cycles( 50 );
      i2c_write(0xa0);        //Send slave address
      delay_cycles( 50 );
      i2c_write(3);           //Send first data
      delay_cycles( 50 );
      i2c_write(120);          //Send second data
      delay_cycles( 50 );
      i2c_stop();             //Stop bit

      delay_ms( 1000 );       //delay

   }while( TRUE );


}




/////////////////////////////////////////////////////////////////////////////////
SLAVE
/////////////////////////////////////////////////////////////////////////////////


#if defined(__PCM__)
#include <16F690.h>
#device ADC=10
#fuses HS, NOPROTECT, NOBROWNOUT, NOMCLR, NOCPD, NOWDT, PUT, NOIESO, NOFCMEN
#use delay(clock=20000000)
#use rs232(baud=19200, xmit=PIN_B7, rcv=PIN_B5, BITS = 8 )
#use i2c( SLAVE, SDA=PIN_B4, SCL=PIN_B6, address=0xa0, SLOW=100000 )


////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////FUNCIONES//////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

#include "ssp_handler.c"
#include "inicializacion.c"         //Config. inicial de todos los registros
#include "puerto_serie.c"           //On serial port, off serial port....

////////////////////////////////////////////////////////////////////////////////
////////////////////////////////INTERRUPCIONES//////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

#INT_SSP NOCLEAR

void ssp_interupt ()
{

////////////////////////////////////////////////////////////////////////////////

   ssp_handler();

////////////////////////////////////////////////////////////////////////////////

   bit_clear( SSPSTAT_R, 0);  //Clear flag buffer full
   bit_clear( SSPCON_R, 6);   //Clear flag Overflow
   bit_clear( SSPSTAT_R,7 );  //Must be clear

}

////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////MAIN/////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////


void  main()
{


   delay_cycles( 1 );

   output_a(0b00000000);                  //Latch del puerto a 00
   output_b(0b10000000);                  //PIN TX puerto serie a alto
   output_c(0b00000000);                  //Latches del puerto a 00

   delay_cycles( 1 );

   set_tris_a(0b00001111);
   set_tris_b(0b01111111);
   set_tris_c(0b11111111);

   delay_cycles( 1 );



   inicializacion();             //Inicializacion general de registros

   delay_ms( 100 );

   puerto_serie_tx();

   printf("start");

   bit_clear( SSPSTAT_R,7 );     //Must be clear

   buffer_full = 0;

   bit_clear( PIR1_R, 3 );    //Clean interrupt flag

   bit_clear( SSPCON_R,5 );   //reset ssp module
   delay_cycles( 5 );
   bit_set( SSPCON_R,5 );     //reset ssp module
   delay_cycles( 5 );

   enable_interrupts(INT_SSP);
   enable_interrupts(GLOBAL);

   do
   {

      bit_clear( SSPSTAT_R,7 );     //Must be clear

      if(buffer_full == 1)
      {
         buffer_full = 0;
         printf("%u,%u\n\r",buffer_i2c[ 0 ], buffer_i2c[ 1 ]);
      }

   }while( TRUE );


}

/////////////////////////////////////////////////////////////////////////////////
SLAVE FUNCTIONS
/////////////////////////////////////////////////////////////////////////////////

//SSP_Handler
//---------------------------------------------------------------------
// The I2C code below checks for 5 states:
//---------------------------------------------------------------------
// State 1: I2C write operation, last byte was an address byte.
//
// SSPSTAT bits: S = 1, D_A = 0, R_W = 0, BF = 1
//
// State 2: I2C write operation, last byte was a data byte.
//
// SSPSTAT bits: S = 1, D_A = 1, R_W = 0, BF = 1
//
// State 3: I2C read operation, last byte was an address byte.
//
// SSPSTAT bits: S = 1, D_A = 0, R_W = 1, BF = 0
//
// State 4: I2C read operation, last byte was a data byte.
//
// SSPSTAT bits: S = 1, D_A = 1, R_W = 1, BF = 0
//
// State 5: Slave I2C logic reset by NACK from master.
//
// SSPSTAT bits: S = 1, D_A = 1, R_W = 0, BF = 0
//
// For convenience, WriteI2C and ReadI2C functions have been used.
//----------------------------------------------------------------------                                                                        ////


//////////////////////////////VARIABLES GLOBALES////////////////////////////////

   int   buffer_i2c[0x02];        //Data buffer
   int   address_i2c;             //address i2c
   int   buffer_full;

////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////ssp_handler.c/////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

void ssp_handler()

{

   int SSPSTAT_TEMP  = 0;           //Auxiliar register for SSPSTAT
   int incoming      = 0;


   SSPSTAT_TEMP   = SSPSTAT_R & 0b00101101;  //Masking bits unuseful on SSPSTAT



   switch ( SSPSTAT_TEMP )
   {

                                    //State 1
      case 0x09:                    //Write operation,last byte was address,
      {                             //buffer is full
         buffer_i2c[ 0 ] = 0;       //clean  data buffer
         buffer_i2c[ 1 ] = 0;

         address_i2c = 0;           //Clean address i2c

         incoming = i2c_read();     //Read byte received

         bit_clear( PIR1_R, 3 );    //Clean Interrupt flag


      }
         break;
////////////////////////////////////////////////////////////////////////////////
                                 //State 2
      case 0x29:                 //Write operation, last byte was data,
      {                          //buffer is full

         buffer_i2c[ address_i2c ] = i2c_read();//Received byte to buffer

         bit_clear( PIR1_R, 3 );                //Clean interrupt flag

         address_i2c++;                         //++ buffer address

         if( address_i2c >= 2)
         {
            address_i2c = 0;                    //Clean address i2c
            buffer_full = 1;
         }


      }
         break;
////////////////////////////////////////////////////////////////////////////////
                                 //State 3
      case 0x0C:                 //Read operation, las byte was address,
      {                          //buffer empty

         address_i2c = 0;                       //Clean address i2c
         i2c_write(buffer_i2c[address_i2c]);    //Write byte in SSPBUF

         bit_clear( PIR1_R, 3 );                //Clean interrupt flag

         address_i2c++;                         //++ buffer address


      }
         break;
////////////////////////////////////////////////////////////////////////////////
                                 //State 4
      case 0x2C:                 //Read operation, last byte was data,
      {                          //buffer empty

         if( address_i2c >= 2)
         {
            address_i2c = 0;                    //Clean address i2c
         }
         i2c_write(buffer_i2c[address_i2c]);    //Write byte in SSPBUF

         bit_clear( PIR1_R, 3 );                //Clean interrupt flag

         address_i2c++;                         //++ buffer address


      }
         break;
////////////////////////////////////////////////////////////////////////////////
                                 //Estado 5
      case 0x28:                 //NACK receive when transmiting data
      {

         bit_clear( PIR1_R, 3 );                //Clean interrupt flag
         printf("todo ok\n\r");

      }
         break;
////////////////////////////////////////////////////////////////////////////////

      default:                   //ERROR
      {

         bit_clear( PIR1_R, 3 );    //Clean interrupt flag
         bit_clear( SSPCON_R,5 );   //reset ssp module
         delay_cycles( 5 );
         bit_set( SSPCON_R,5 );     //reset ssp module
         printf("todo ko\n\r");

      }
         break;

   }



}

rnielsen



Joined: 23 Sep 2003
Posts: 852
Location: Utah

View user's profile Send private message

PostPosted: Tue Aug 22, 2006 12:54 pm     Reply with quote

If the Master is writing to the slave then it's the slave that sends the ACK/NOACK back to let the master know if the information was received okay. The only time the master sends the ACK/NOACK to the slave is if the master is Reading from the slave. This tells the slave if the master is still going to want more data or if it's done reading from the slave. The NOACK is sent on the Last read that is sent from the master by sending the command:

variable = i2c_read(0);

The zero(0) sends the NOACK to the slave at the end of the read sequence.

Ronald
Guest








PostPosted: Wed Aug 23, 2006 12:14 am     Reply with quote

Thanks,

Now i have a tested I2C for 2 PIC16f690 (MASTER - SLAVE) at 100kbps. anyone who needs the code just ask Smile.....
henry



Joined: 05 Feb 2005
Posts: 10

View user's profile Send private message Send e-mail MSN Messenger

PostPosted: Wed Aug 23, 2006 12:16 am     Reply with quote

Thanks,

Now i have a tested I2C for 2 PIC16f690 (MASTER - SLAVE) at 100kbps. anyone who needs the code just ask Smile.....
Guest








PostPosted: Wed Jun 13, 2007 10:08 am     Reply with quote

henry wrote:
Thanks,

Now i have a tested I2C for 2 PIC16f690 (MASTER - SLAVE) at 100kbps. anyone who needs the code just ask Smile.....



Yes, Thank-you, would you send me the code? I too am using the 690s.

Please send to

ebarnes@islandhideaway.net

Thanks in advance.
Ed.
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