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

Bi-directional Communication problem with i2c

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



Joined: 02 Sep 2009
Posts: 4

View user's profile Send private message

Bi-directional Communication problem with i2c
PostPosted: Thu Sep 17, 2009 6:56 pm     Reply with quote

In my project i am trying to establish I2C communication between a master 16F877A and 2 slave 16F877A's. My testing code is to communicate between the master and slave A0. The Master send a value to the slave to save in the buffer array at address location. Then the master requests that same information.
My master code based on some examples i got on this site :
Code:
#include<16F877A.h>
//#include<def_16f886.h>
#fuses HS, noprotect, NOWDT
#use delay(clock = 4000000)
#use i2c(master, sda = pin_c4, scl = pin_c3)
#use rs232(baud=9600,xmit=PIN_C6,rcv=PIN_C7)

void main(void){
//   osccon = 0x41;
byte result2=0x00;
   while(1){
   //HERE I WANT TO SEND DATA TO SLAVE CONSISTING OF AN SLAVE_ADDRESS,
    //INTERNAL ADDRESS IN BUFFER AND THE DATA THAT NEED TO BE WRITTEN THERE
      i2c_start();            //begin transmission
         i2c_write(0xA0);      //Slave address A0
      i2c_write(0x01);      //Internal Adress 0x01
      i2c_write(0x41);        //send actual data                  
        i2c_stop();            //terminate communication
      
   //HERE I WANT TO READ THE DATA THAT I JUST SAVED ON THE CLIENT
      output_high(PIN_D7);    //Visual confirmation that the sending part is starting
      delay_ms(500);                 
         i2c_start ();           //begin communication
         i2c_write (0xA0);       //send slave address
      i2c_write (0x01);       //request slave to fetch buffer array element 0x01
         i2c_stop();             //stop write cycle to shift to read cycle
      i2c_start ();           //send repeated start command to begin read cycle
         i2c_write (0xA1);       //add 1 to the address to send a write bit
         delay_ms(100);
      result2 = i2c_read();   //read analogue information from the slave
         i2c_stop ();            //terminate communication
         output_low(PIN_D7);     //Visual confirmation that send part is done
         delay_ms(150);
      putc(result2);          //Print result on the hyperterminal
        result2=0x00;
        delay_ms(1000);
      
      }
}


And the Slave code:
Code:
#include<16F877A.h>
#fuses HS, noprotect, NOWDT
#use delay(clock = 4000000)
#use i2c(slave, sda = pin_c4, scl = pin_c3, address = 0xa0)

int8 address = 0;
int8 buffer[5] = {0x41, 0x42, 0x43, 0x44, 0x45};
int8 incoming = 0;
int8 first_byte = 0;
int8 second_byte = 0;

int8 state = 0;
#int_ssp
void ssp_interupt ()
{
   state = i2c_isr_state();
   if(state < 0x80)                     //Master is sending data
   { 
     incoming = i2c_read();
     if(state==1)
      {
         address = incoming;
         }
    if(state==2)
        {
         buffer[address]=incoming;
        }
   }
   if(state == 0x80)                     //Master is requesting data
   { 
     i2c_write(buffer[address]);
   }
    delay_ms(100);
   output_toggle(PIN_B1);   
}

void main(void){

   enable_interrupts(int_ssp);
   enable_interrupts(global);
   while(1){}
}


The problem is that i keep getting 0xFF values. No matter what i do the communication does not work. Please give me some pointers as to what may be wrong. I know that the hardware is allright and has be checked by peers. I thank you in advance.
Eben

PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Thu Sep 17, 2009 8:17 pm     Reply with quote

Quote:
i2c_start (); //send repeated start command to begin read cycle
i2c_write (0xA1); //add 1 to the address to send a write bit
delay_ms(100);
result2 = i2c_read(); //read analogue information from the slave
i2c_stop ();

I didn't look closely at your code, but I did see one thing. The last
i2c_read() operation must do a NACK. If you only do one read, then
it's the "last" one. This is in the i2c specification. You can tell it do a
NACK by using a 0 parameter, as shown below:
Code:
result2 = i2c_read(0);

This is in the manual.
ebenbekker



Joined: 02 Sep 2009
Posts: 4

View user's profile Send private message

PostPosted: Fri Sep 18, 2009 5:33 am     Reply with quote

I tried that ty but it did not resolve the latchup problem or the invalid received info. Thank you for your help! Much appreciated.
Eben
Wayne_



Joined: 10 Oct 2007
Posts: 681

View user's profile Send private message

PostPosted: Fri Sep 18, 2009 8:12 am     Reply with quote

Have you given each slave a different address ?
Ttelmah
Guest







PostPosted: Fri Sep 18, 2009 8:20 am     Reply with quote

Obvious first comment. Get rid of the delay in the ISR.
Your current handler, will still be in the ISR, from receiving the slave address, when the index address byte is sent.....

Second comment. Get rid of the I2C_stop, in front of the restart. A 'restart', involves sending a new 'start', without sending a 'stop'. On the PIC, it shouldn't matter (it should still work OK with a 'stop' present), but on many I2C peripherals, if you once send the 'stop', the internal state machine resets....

Best Wishes
ebenbekker



Joined: 02 Sep 2009
Posts: 4

View user's profile Send private message

PostPosted: Sat Sep 19, 2009 9:06 am     Reply with quote

I have added the NACK on the master's side, and not on the slave's side (see code below). The delays on the slave's side was not a problem, if (and this is a big if) there was sufficient delay on the master's side.

I also noticed that my programmer didn't always do what it should, meaning that at times I assumed correct code as incorrect due to a faulty programmer (this is very discouraging).

Thank you for the tips.

For those wonder what correct working code looks like for my implementation of a slave buffer reading looks like, I have attached the code (enjoy). The program merely writes 'A' to 'P' to the slave's buffer, and then reads the data from the buffer. On the CommPort is sends out "Ready123" followed by "ABCDEFGHIJKLMNOP" (if the buffer could be written and read properly).

MASTER'S CODE
Code:

#include <16F877A.h>
#device adc=8

#FUSES NOWDT                    //No Watch Dog Timer
#FUSES XT                       //Crystal osc <= 4mhz
#FUSES PUT                      //Power Up Timer
#FUSES NOPROTECT                //Code not protected from reading
#FUSES NODEBUG                  //No Debug mode for ICD
#FUSES NOBROWNOUT               //No brownout reset
#FUSES NOLVP                    //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOCPD                    //No EE protection
#FUSES WRT_50%                  //Lower half of Program Memory is Write Protected

#use delay (clock = 4M)
#use rs232 (baud = 9600, parity = N, xmit = PIN_C6, rcv = PIN_C7, bits = 8)
#use i2c (master, fast, sda = PIN_C4, scl = PIN_C3)

byte serial_buffer_size = 30;
byte serial_buffer [30];
byte serial_input_index = 0x00;
byte serial_output_index = 0x00;
byte serial_trasmission_ended = true;

#int_rda
void   rda_isr (void) {
   serial_buffer [serial_input_index] = getc ();
   serial_input_index = serial_input_index + 1;
}


byte serial_data_available () {
   byte temp_input_index;
   byte temp_output_index;
   
   temp_input_index = serial_input_index;
   temp_output_index = serial_output_index;
   
   if (temp_input_index < temp_output_index) {
      return serial_buffer_size - temp_output_index + temp_input_index;
   }
   else {
      return temp_input_index - temp_output_index;
   }
}


byte serial_read () {
   byte output;
   
   output = serial_buffer [serial_output_index];
   serial_output_index = (serial_output_index + 1) % serial_buffer_size;
   
   return output;
}


void serial_write (byte data) {
   serial_trasmission_ended = false;
   putc (data);
}


byte slave_read (byte slave_address, byte memory_address) {
   byte output;

   i2c_start ();
   i2c_write (slave_address);
   i2c_write (memory_address);
//   i2c_stop ();      // Be warned that this sends a I2C ISR reset condition.
   
   i2c_start ();   
   i2c_write (slave_address + 1);   
   output = i2c_read (0);   // Take note to add the NACK (No acknowledgement)
   i2c_stop ();
   
   return output;
}

void slave_write (byte slaveAddress, byte memoryAddress, byte value) {   
   i2c_start ();
   i2c_write (slaveAddress);
   i2c_write (memoryAddress);
   i2c_write (value);
   i2c_stop ();
}


void main()
{
   byte buffer [0x10];
   byte n = 0x00;
   
   setup_adc_ports(NO_ANALOGS);
   setup_adc(ADC_OFF);
   setup_psp(PSP_DISABLED);
   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);
   setup_vref(FALSE);
   
   enable_interrupts(int_rda);
   enable_interrupts(global);
   
   delay_ms(1000);
   
   printf ("ready123");
   
   for (n = 0; n < 16; n++) {
      slave_write (0xa0, n, 'A' + n);
      buffer [n] = slave_read (0xa0, n);
   }
   
   for (n = 0; n < 16; n++) {
      putc (buffer [n]);
   }
   
   delay_ms (1000);
   
   while (true) {
      ;
   }
}




SLAVE'S CODE
Code:

#include <16F877A.h>
#device adc=8

#FUSES NOWDT                    //No Watch Dog Timer
#FUSES XT                       //Crystal osc <= 4mhz
#FUSES PUT                      //Power Up Timer
#FUSES NOPROTECT                //Code not protected from reading
#FUSES NODEBUG                  //No Debug mode for ICD
#FUSES NOBROWNOUT               //No brownout reset
#FUSES NOLVP                    //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOCPD                    //No EE protection
#FUSES WRT_50%                  //Lower half of Program Memory is Write Protected

#use delay(clock=4M)
#use i2c(slave, fast, sda=PIN_C4, scl=PIN_C3, address=0xA0)

#define buffer_size 0x40
byte buffer [buffer_size];
byte address = 0x00;


#int_SSP
void  i2c_isr(void)
{   
   byte state;
   state = i2c_isr_state();
   
   // Send Buffer Data
   if(state >= 0x80) {
      i2c_write (buffer [address]);
   }
   
   // Reset/Data Received
   else { // (state >= 0x00)
      // Receive Address
      if (state == 0x01) {
         address = i2c_read ();
      }
      
      // Receive Buffer Data
      else if (state == 0x02) {
         buffer [address] = i2c_read ();
      }
      else {
         i2c_read ();
      }
   }
}


void main()
{
   setup_adc_ports(NO_ANALOGS);
   setup_adc(ADC_OFF);
   setup_psp(PSP_DISABLED);
   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);
   setup_vref(false);   
   
   enable_interrupts (int_ssp);
   enable_interrupts (global);
   
   while (true) {
      ;
   }
}

hmnrobots
Guest







I2C communication
PostPosted: Fri Oct 02, 2009 7:38 am     Reply with quote

All right with when a hardware I2C is available, but as I need to communicate with a non equipped device (12F629) I won't have the I2C interrupt and I can't see how to do it; any help ???
Ttelmah
Guest







PostPosted: Fri Oct 02, 2009 8:40 am     Reply with quote

Seriously, you won't.
Wiithout the hardware, a _master_, is easy, but a slave, is really hard. I won't say it "can't" be done, but it requires a huge amount, of really carefully done code, and is approaching impossibility...
It is a case where if you have several weeks of time, and are intending to produce the device in many thousands off, so the saving from not using a chip with slave hardware, is possibly worthwhile, but otherwise it is going to be cheaper, and easier, to use a PIC with the required hardware.
Look at possibly the 12F1822.

Best Wishes
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