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 Master & Slave with 2 PIC's SOLVED
Goto page 1, 2, 3, 4, 5, 6  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
gjs_rsdi



Joined: 06 Feb 2006
Posts: 468
Location: Bali

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

I2C Master & Slave with 2 PIC's SOLVED
PostPosted: Sun Jun 23, 2019 7:26 pm     Reply with quote

Hi

I finally have connected two boards to make a master and slave communication with PIC16F1847
1. The master connected to PC terminal
2. Master & Slave boards connected with 6" cables for I2C
3. 2K2 resistors on SDA and SCL
4. Both boards powered from same 5VDC source

I am sending from the PC to the master:
Quote:
55 AA CC CB or
55 AA DD DC or
55 AA EE ED

and suppose to get the same back twice, ones report from the master and ones report from the slave I2C to master and to PC.

The communication of master with PC is OK but the data supposed to be from the slave is the default value in the main, for example:
Quote:
55 AA CC CB
55 AA 00 FF

My conclusion is the I2C don't work.
Code:
/////////////////////////////////////////////////////////////////
//Master I2C test program
//TM1847.c
/////////////////////////////////////////////////////////////////
#include <16F1847.h>

#FUSES HS,NOIESO,PLL,WDT,MCLR,PUT
#FUSES NOPROTECT,NOCPD,WRT,STVREN
#FUSES BROWNOUT,BORV25,NODEBUG,NOLVP
#use delay(clock=32MHz,crystal=8MHz,restart_wdt)
#use rs232(baud=9600,parity=N,xmit=PIN_B5,rcv=PIN_B2,bits=8,restart_wdt,errors)//alternative
#use i2c(Master,Slow,I2C1,restart_wdt)//I2C1 module, automatically hardware
//////////////////////////////////////////////////////////////
#define flashled PIN_A3
int flashcnt=0;
int scomtxwords=0;
int scomtxw2=0;
int scomtxwchs=0;
short rxnewmsgF=0;
int rxwords=0;
int rxdata0=0;
int rxdata1=0;
int rxdata2=0;
int rxdata3=0;
int rxwchs=0;
short I2CstartF=0;
int slave01addr=0x80;
int slave01dataout=0x00;
int slave01datain=0x00;
/////////////////////////////////////////////////////////////
#INT_TIMER1
void  TIMER1_isr(void)
{
   flashcnt++;
   set_timer1(25536);//timer1 overflow 40ms
}
//FUNCTIONS////////////////////////////////////////////////////////
void FUNCTIONS(void)
{
//LED FLASH////////////////////////////////////////////////////////
   if(flashcnt>=25)
   {
      flashcnt=0;
      output_toggle(flashled);
   }   
//RX NEW MESSAGE///////////////////////////////////////////////////
   if(rxnewmsgF==1)
   {
      scomtxw2=rxdata2;
      slave01dataout=rxdata2;//updates data received to send to slave
      enable_interrupts(INT_TBE);//sends back to PC the rx data received
      delay_ms(2000);//delay before sending data to slave
      I2CstartF=1;
   }
//I2C & PC communication///////////////////////////////////////////
   if(I2CstartF==1)
   {
      i2c_start();//Start condition
      i2c_write(slave01addr);//R/W bit low for a write
      i2c_write(slave01dataout);//Data to the slave
      i2c_start();//Restart the bus
      i2c_write((slave01addr)+1);//R/W bit high for a read
      slave01datain = i2c_read();//Read the data from the slave
      i2c_stop();
      scomtxw2=slave01datain;//sends slave data to PC
      enable_interrupts(INT_TBE);   
   }
}
//rs232 TX/////////////////////////////////////////////////////////
#int_TBE
void TBE_isr(void)
{
   switch(scomtxwords)
   {
      case 0:
      {
         putc(85);
         scomtxwchs=85;   
         scomtxwords++;      
      }
      break;
      case 1:
      {
         putc(170);
         scomtxwchs=255;
         scomtxwords++;         
      }
      break;
      case 2:
      {
         putc(scomtxw2);
         scomtxwchs=scomtxwchs+scomtxw2;
         scomtxwords++;         
      }
      break;
      case 3:
      {
         putc(scomtxwchs);
         scomtxwords=0;   
         disable_interrupts(INT_TBE);            
      }
      break;
   }   
}
//rs232 RX/////////////////////////////////////////////////////////
#INT_RDA
void  RDA_isr(void)
{
   switch(rxwords)
   {
      case 0:
      {
         rxdata0=getc();
         if (rxdata0==85)
         {
            rxwchs=85;
            rxwords=1;
         }
         else
         {
            rxwords=0;
         }   
      }
      break;
      case 1:
      {
         rxdata1=getc();
         if (rxdata1==170)
         {
            rxwchs=255;
            rxwords++;
         }
         else
         {
            rxwords=0;
         }         
      }
      break;
      case 2:
      {
         rxdata2=getc();
         rxwchs=rxwchs+rxdata2;
         rxwords++;         
      }
      break;
      case 3:
      {
         rxdata3=getc();
         if (rxwchs==rxdata3)
         {
            rxnewmsgF=1;
         }
         rxwords=0;   
      }
      break;
   }
}

#ZERO_RAM

void main()
{
   setup_adc_ports(NO_ANALOGS);
   setup_wdt(WDT_256MS);//~256 ms reset
   setup_timer_1(T1_INTERNAL|T1_DIV_BY_8);//65 ms overflow
   enable_interrupts(INT_TIMER1);
   enable_interrupts(INT_TBE);
   enable_interrupts(INT_RDA);
   enable_interrupts(GLOBAL);

   while(TRUE)
   {
      FUNCTIONS();
      restart_wdt();
   }

}

Code:
////////////////////////////////////////////////////////////////
//Slave I2C test program
//TS1847.c
/////////////////////////////////////////////////////////////////
#include <16F1847.h>

#FUSES HS,NOIESO,PLL,WDT,MCLR,PUT
#FUSES NOPROTECT,NOCPD,WRT,STVREN
#FUSES BROWNOUT,BORV25,NODEBUG,NOLVP
#use delay(clock=32MHz,crystal=8MHz,restart_wdt)
#use i2c(Slave,I2C1,restart_wdt)//I2C1 module, automatically hardware
//////////////////////////////////////////////////////////////
#define flashled PIN_A3
int flashcnt=0;
int slave01addr=0x80;
int slave01dataout=0xAA;
int slave01datain=0x00;
/////////////////////////////////////////////////////////////
#INT_TIMER1
void  TIMER1_isr(void)
{
   flashcnt++;
      set_timer1(25536);//timer1 overflow 40ms
}
//////////////////////////////////////////////////////////////////
#INT_SSP
void  SSP_isr(void)
{
   slave01addr = i2c_isr_state();     
   if(slave01addr==0x80)//Master is sending data
   {
      slave01datain = i2c_read();
       slave01dataout=slave01datain;
   }
   if(slave01addr==0x81)//Master is requesting data from slave
   {
      i2c_write(slave01dataout);
   }
}
///////////////////////////////////////////////////////////////////
void FUNCTIONS(void)
{
 
   if(flashcnt>=25)
   {
      flashcnt=0;
      output_toggle(flashled);
   }     
}
///////////////////////////////////////////////////////////////////
#ZERO_RAM

void main()
{
   setup_adc(NO_ANALOGS);
   setup_wdt(WDT_256MS);
   setup_timer_1(T1_INTERNAL|T1_DIV_BY_8);//65 ms overflow
   enable_interrupts(INT_TIMER1);
   enable_interrupts(INT_SSP);
   enable_interrupts(GLOBAL);

   while(TRUE)
   {
      FUNCTIONS();
      restart_wdt();
   }

}


First time I am trying to make an I2C using CCS, what I am doing wrong?
Sad
(made in the far past I2C in assembler and worked)

Best wishes
Joe


Last edited by gjs_rsdi on Mon Feb 03, 2020 5:56 pm; edited 3 times in total
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Sun Jun 23, 2019 7:54 pm     Reply with quote

Quote:
if(I2CstartF==1)
{
i2c_start();//Start condition
i2c_write(slave01addr);//R/W bit low for a write
i2c_write(slave01dataout);//Data to the slave
i2c_start();//Restart the bus
i2c_write((slave01addr)+1);//R/W bit high for a read
slave01datain = i2c_read();//Read the data from the slave
i2c_stop();
scomtxw2=slave01datain;//sends slave data to PC
enable_interrupts(INT_TBE);
}

You are missing the NACK on the last i2c_read().
It should be:
Code:
slave01datain = i2c_read(0);
gjs_rsdi



Joined: 06 Feb 2006
Posts: 468
Location: Bali

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

PostPosted: Sun Jun 23, 2019 11:37 pm     Reply with quote

Thank you PCM Programmer

I change:
Code:
slave01datain = i2c_read(0);

Sill the same.
I checked again the boards and connections to be sure that they are OK, no problems there.
I must have some additional mistake Sad

Best wishes
Joe
gjs_rsdi



Joined: 06 Feb 2006
Posts: 468
Location: Bali

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

PostPosted: Sun Jun 23, 2019 11:44 pm     Reply with quote

Sorry, forget to mention:

CCS PCM C Compiler, Version 5.062, 31220

Best wishes
Joe
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Mon Jun 24, 2019 12:20 am     Reply with quote

I think your program is excessively complicated.

Here is a way to start simple:
http://www.ccsinfo.com/forum/viewtopic.php?t=55342&start=15
Ttelmah



Joined: 11 Mar 2010
Posts: 19195

View user's profile Send private message

PostPosted: Mon Jun 24, 2019 12:29 am     Reply with quote

Your slave handling is wrong.

You are misunderstanding what has to happen, and when.

State = 0x00 - this is the address byte being received for a _write_
0x01 - this is the data byte then written (state increments for each
following byte.
State = 0x80 - this is the address byte being received for a _read_.
In this state the address byte must be read, and then immediately the
reply written.
On many chips the 'standard' is to follow the address byte, with a second
'register address' byte. This is what is done in the CCS examples, so
on these the first actual data byte is state==2. However for what you
show state==1 can be used.

Now you are not handling the write state numbers. State 0x0, and 0x1
will not result in your slave doing an I2C read. Result there will be a
peripheral overflow....

Now also understand that the first byte that arrives is always the address.
Not the data.

For your system, you need:
Code:

//////////////////////////////////////////////////////////////////
#INT_SSP
void  SSP_isr(void)
{
   int8 incoming;
   slave01addr = i2c_isr_state(); 
   if (slave01address==0x0)
      incoming=i2c_read(); //dummy read of the device address
   if (slave01address==0x1) {
      //This is where the data _arrives_
      slave01datain = i2c_read();
      slave01dataout=slave01datain;
   }
   if(slave01addr==0x80)//Master is requesting data from slave
   {
      dummy=i2c_read(2); //here we need to read the address byte
      //without releasing the clock line, ready to load the data
      i2c_write(slave01dataout);
      //Now load the data

     //Now on some chips, the clock does not correctly release.
#BIT CKP=getenv("BIT:CKP")
     CKP=TRUE; //This ensures it does release.
   }
}


I've also added the patch for CKP. This is not needed on most chips
but it's safer to include it.
gjs_rsdi



Joined: 06 Feb 2006
Posts: 468
Location: Bali

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

PostPosted: Mon Jun 24, 2019 3:19 am     Reply with quote

Thank you for the answers Smile

I read the link PCM Programmer wrote and the post of Ttelmah.
I will learn the subject, implement accordingly and test.
Will be back with the results.

Best wishes
Joe
gjs_rsdi



Joined: 06 Feb 2006
Posts: 468
Location: Bali

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

PostPosted: Wed Jun 26, 2019 3:39 am     Reply with quote

Hi

I am back after tried a few things but with no success to make a communication between I2C master and slave Sad

Whatever I am doing I am getting in the terminal:
Quote:
55,AA,CC,CB
55,AA,CC,CB
55,AA,00,FF

The 55,AA,00,FF supposed to be the slave answer.

My last slave is the ex_slave.c
Code:
#INT_SSP
void  SSP_isr(void)
{
   unsigned int8 incoming, state;
   state = i2c_isr_state();

   if(state <= 0x80)                      //Master is sending data
   {
      if(state == 0x80)
         incoming = i2c_read(2);          //Passing 2 as parameter, causes the function to read the SSPBUF without releasing the clock
      else
         incoming = i2c_read();

      if(state == 1)                      //First received byte is address
         address = incoming;
      else if(state >= 2 && state != 0x80)   //Received byte is data
         buffer[address++] = incoming;
   }

   if(state >= 0x80)                      //Master is requesting data
   {
      i2c_write(buffer[address++]);
   }
}

My last main:
Code:
   if(I2CstartF==1)
   {
//Master write to Slave////////////////////////////////////////////
      i2c_start();
      i2c_write(0xA0);//slave address
      i2c_write(i2cWaddr);//slave location address
      i2c_write(i2cWdata);//CC; DD; FF
      i2c_stop();
      delay_cycles(60);
//Master read from Slave///////////////////////////////////////////
      i2c_start();
      i2c_write(0xA0);//device address
      i2c_write(i2cWaddr);//write location address
      i2c_start();
      i2c_write(0xA1);//write command to slave
      i2cRdata=i2c_read(0);
      i2c_stop();
      scomtxw2=i2cRdata;
         I2CstartF=0;
        enable_interrupts(INT_TBE);//rpt to PC data from slave
   }

I made int i2cRdata=0xFF; in the master.
If the slave not sending data, the i2cRdata should be 0xFF, but I have 0x00 so I think the slave sends 0x00
I made the slave to send 0xAA instead of buffer[address++] but still have 0x00.

For sure I am making mistakes.
Please help

Best wishes
Joe
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Thu Jun 27, 2019 1:36 am     Reply with quote

Here is a bug. You don't specify the slave address in your #use i2c()
statement:
Quote:
//Slave I2C test program
//TS1847.c
/////////////////////////////////////////////////////////////////
#include <16F1847.h>

#FUSES HS,NOIESO,PLL,WDT,MCLR,PUT
#FUSES NOPROTECT,NOCPD,WRT,STVREN
#FUSES BROWNOUT,BORV25,NODEBUG,NOLVP
#use delay(clock=32MHz,crystal=8MHz,restart_wdt)
#use i2c(Slave,I2C1,restart_wdt) // I2C1 module, automatically hardware
//////////////////////////////////////////////////////////////


Example of how to specify the slave address:
Code:
#use i2c(Slave, I2C1, address=0x80, restart_wdt)
gjs_rsdi



Joined: 06 Feb 2006
Posts: 468
Location: Bali

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

PostPosted: Mon Jul 01, 2019 7:55 pm     Reply with quote

Thank you PCM Programmer

I corrected the slave bug (added slave address) still not working.
I have already many versions tested without success.
I found a program I wrote in 2006 for PIC18F252 to read & write for EEPROM 24C512.

I will buy a 24C512 and will start from there, I don't remember if the program was working.

Best wishes
Joe
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Mon Jul 01, 2019 9:19 pm     Reply with quote

Another useful test is to run the slave at 32 MHz, and
run the master at 4 MHz. This gives the slave plenty
of time to respond. If there is a problem with the slave
responding in time, and this test makes it work, then
you know what to do. ie., insert larger delay(s) in the
master code, if both are running at 32 MHz.
gjs_rsdi



Joined: 06 Feb 2006
Posts: 468
Location: Bali

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

PostPosted: Tue Jul 02, 2019 2:06 am     Reply with quote

Thank you again PCM Programmer.

I will do as you advised, just right now my brain stuck Sad
So I will start first to talk with the 24C512.

Best wishes
Joe
temtronic



Joined: 01 Jul 2010
Posts: 9081
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Tue Jul 02, 2019 4:59 am     Reply with quote

I suggest you stop using the WDT until you get your program running 100%.

All too often I see code here with WDT enabled and wonder why. Unless properly coded a WDT can easily lead you 'down the wrong path'... thinking 'this' is wrong when in reality it's 'that'.
WDT should only be installed AFTER 'main()' is truly working properly.

Jay
gjs_rsdi



Joined: 06 Feb 2006
Posts: 468
Location: Bali

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

PostPosted: Tue Jul 02, 2019 4:22 pm     Reply with quote

Thanks Jay, will disable it.

Best wishes
Joe
gjs_rsdi



Joined: 06 Feb 2006
Posts: 468
Location: Bali

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

PostPosted: Wed Jul 10, 2019 12:52 am     Reply with quote

Finally I have a working master with 24C512 Smile
Thanks everyone with the help Smile
Understanding how I2C works (or any other subject) is the key.
I added back the wdt (eliminated it per Jay advice) because in some stage the PIC stuck so I wanted to learn why.

The working program:
Code:
/////////////////////////////////////////////////////////////////
//PIC16F1847 Master I2C with 24C512 eeprom test program
//TM1847.c
/////////////////////////////////////////////////////////////////
#include <16F1847.h>

#FUSES INTRC_IO,NOIESO,PLL,WDT,MCLR,PUT
#FUSES NOPROTECT,NOCPD,WRT,STVREN
#FUSES BROWNOUT,BORV25,NODEBUG,NOLVP
#use delay(clock=32MHz,INTERNAL=8MHz)
#use rs232(baud=9600,parity=N,xmit=PIN_B5,rcv=PIN_B2,bits=8,restart_wdt,errors)//V1
#use i2c(Master,Slow,I2C1)//I2C1 module, automatically hardware

#define flashled PIN_A2
short powerupF=1;
int flashcnt=0;
short I2CstartF=0;
int C512rpt=0;
int i2cStartTimer=0;
int scomtxwords=0;//V1
int scomtxw2=0;//V1
int scomtxwchs=0;//V1

#INT_TIMER1
void  TIMER1_isr(void)
{
   flashcnt++;
   set_timer1(25536);//timer1 overflow 40ms
}

#int_TBE//V1
void TBE_isr(void)
{
   switch(scomtxwords)
   {
      case 0:
      {
         putc(85);
         scomtxwchs=85;   
         scomtxwords++;     
      }
      break;
      case 1:
      {
         putc(170);
         scomtxwchs=255;
         scomtxwords++;         
      }
      break;
      case 2:
      {
         putc(scomtxw2);
         scomtxwchs=scomtxwchs+scomtxw2;
         scomtxwords++;         
      }
      break;
      case 3:
      {
         putc(scomtxwchs);
         scomtxwords=0;   
         disable_interrupts(INT_TBE);           
      }
      break;
   }   
}

void COUNTERS(void)
{
   if(flashcnt>=25)
   {
      flashcnt=0;
      if(powerupF==1)
      {
         powerupF=0;
         enable_interrupts(INT_TBE);//should send 0x00
      }
        output_toggle(flashled);//LED flash every sec
         i2cStartTimer++;
         if(i2cStartTimer==4)
         {
            I2CstartF=1;//start i2c every 4 sec
            i2cStartTimer=0;
         }
   }


void I2C (void)
{
   if(I2CstartF==1)
      {
   //write 0xAA to the 24C512
      I2CstartF=0;
      i2c_start();
        i2c_write(0xA0);//24C512 address with write
         i2c_write(0x00);//24C512 write address high
         i2c_write(0x00);//24C512 write address low
        i2c_write(0xAA);//data byte
        i2c_stop();
   //read back 0xAA from the 24C512
      delay_ms(60); //ensure the 24C512 has had time to complete the write
      i2c_start();
      i2c_write(0xA0);//24C512 address with write
      i2c_write(0x00);//24C512 read address high
      i2c_write(0x00);//24C512 read address low
      i2c_start();
      i2c_write(0xA1);//24C512 address with read~
      C512rpt = i2c_read(0);//24C512 rpt to master
      i2c_stop();
       scomtxw2 = C512rpt;
       enable_interrupts(INT_TBE);//rpt to PC data from 24C512       
      }
}

#ZERO_RAM

void main()
{
   setup_adc_ports(NO_ANALOGS);
      setup_wdt(WDT_128MS);   
      setup_timer_1(T1_INTERNAL|T1_DIV_BY_8);//65 ms overflow
      enable_interrupts(INT_TIMER1);
      disable_interrupts(INT_TBE);//V1
      enable_interrupts(GLOBAL);

      while(TRUE)
      {
         COUNTERS();   
      I2C();
      restart_wdt();
      }
}

The program works also without sending address, then you get the data from location 0x01 that is 0xFF for empty chip

Code:
      i2c_start();
      i2c_write(0xA1);//24C512 address with read~
      C512rpt = i2c_read(0);//24C512 rpt to master
      i2c_stop();


Thank you again PCM Programmer, Ttelmah and Jay Smile

Will start now with the slave PIC

Best wishes
Joe
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page 1, 2, 3, 4, 5, 6  Next
Page 1 of 6

 
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