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

I2C between 2 16F690 chips

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



Joined: 22 Jun 2011
Posts: 7
Location: Tandragee, Northern Ireland

View user's profile Send private message AIM Address

I2C between 2 16F690 chips
PostPosted: Thu Feb 08, 2018 6:33 am     Reply with quote

Hello All,

CCS PCM C Compiler, Version 5.025, xxxxx

I am very confused and in desperate need of enlightenment!!! I have been going round in circles for a few days trying to get 2 16F690's to talk to each other via I2C.

I have 2 programs, One is the Master and the other is the Slave.
The 2 devices are connected together, using pins B6 (SCL) & B4 (SDA). Both these pins are pulled to 5V with 2k2 resistors and both chips run off a common 5V supply.

This is a first pass test before I get into communicating between a PIC and an I2C based device. I will need to move on to addressing registers on the device and getting multiple bytes of data back, but I can't move on until I get the basics under control!

Here is my MASTER code
Code:

/* ******************************************** */
/*         I2C Master System.c               */
/* ******************************************** */

#include <16F690.h>

#use delay(internal = 8MHz)
#use rs232(UART1, Stream = Out, Baud = 19200,Bits=8,Parity=N)
#use i2c(MASTER,stream = Master, SCL=PIN_B6,SDA=PIN_B4)

/* Declare Constants, Variables etc   */
const int8 SLAVE_WRITE_ADDR =  24 ;

int8 data = 0;

/* Define Functions */

int8 OneReadI2C(int8 addr);
/* ******************************************** */
/*   Program below this line                  */
/* ******************************************** */
void main()
{
    fprintf(Out,"System Booted\r\n");
   while(1)
     {        
     data = OneReadI2C(SLAVE_WRITE_ADDR);   
     fprintf(Out,"Data from Read = %u \n\r", data);
     delay_ms(1000);
   }
}

/* ******************************************** */
/*   Writes Address + 1 to Slave and          */
/*  Reads 1 value from Slave               */
/* ******************************************** */
int8 OneReadI2C( int8 write_address )
{
   i2c_start(Master);
   delay_us(50);
   i2c_write(Master , write_address + 1);
   delay_us(50);
   data = i2c_read( Master,0);
   delay_us(50);
   i2c_stop(Master);
   return data;
}   


Here is my SLAVE code
Code:

/* ******************************************** */
/*   I2C Slave System.c                     */
/* ******************************************** */
#include <16F690.h>

#use delay(internal = 8MHz)
#use rs232(UART1, Stream = Out, Baud = 19200,Bits=8,Parity=N)
#use i2c(SLAVE,stream = MySlave, SCL=PIN_B6,SDA=PIN_B4,Address=24 )

/* Declare Constants, Variables etc   */

#define LED PIN_C7

const int16 SlaveAddr = 24;


boolean Int_Flag;

unsigned int8 IntPointer = 0;
unsigned int8 Pointer = 0;

int8 incoming = 0;

int8 state = 0;

int8 address;
int8 data;


/* Define Functions */

int8 I2C_Interrupt( int state);


/* ******************************************** */
/*         Program below this line            */
/* ******************************************** */

#INT_SSP
void ssp_interrupt()
{
   Output_high(LED);
   state = i2c_isr_state(MySlave);
   Disable_interrupts(INT_SSP);   
   Int_Flag = 1;
   Output_Low(LED);
}      

void main()
{
   Int_Flag = 0;
   Pointer = 0;
   IntPointer = 0;
   delay_ms(100);
   fprintf(Out,"\r\nSystem Booted, Slave address = %Ld\r\n",SlaveAddr);
   enable_interrupts(GLOBAL);
   enable_interrupts(INT_SSP);
   fprintf(Out,"Interrupts Enabled \r\n");
   while(1)
   {
      if(Int_Flag == 1 )
      {   
         I2C_Interrupt(state);
         Int_Flag = 0;
         enable_interrupts(int_ssp);
      }         
   }   
}
   
int8 I2C_Interrupt( int state)
{
   fprintf(Out,"In INT\t");
   if(state == 0)
   {
      address = i2c_read( MySlave );
      fprintf(Out,"state = 0,  Pointer = %u\t 'state' = %X\r\n",Pointer,state);
return 0;
   }   
/* ******************************************** */
/*    This section Receives DATA from the Master */
/* ******************************************** */
   if(state < 0x80)                 // Master is sending data
     {
      incoming = i2c_read(MySlave); 
      fprintf(Out,"state < 0x80,  Pointer = %u\t 'data' = %X\r\n",Pointer,state);
     }
/* ******************************************** */    
/* This section reads Address and then Data    */
/* ******************************************** */
   if(state == 1)                    //First received byte is address
      {
      address = incoming;
      incoming = 0;
       fprintf(Out,"state = 1,  Pointer = %u\t 'data' = %X\r\n",Pointer,state);
     }
     else
     {         
       if((state >= 2) && ( state != 0x80))  //Received byte is data
         {
           incoming = 0;
           fprintf(Out,"2 <= state != 0x80 Pointer = %u\t 'state' = %X\r\n",Pointer,state);
         } 
     }        
/* ******************************************** */
/*    This section Sends DATA to the Master       */
/* ******************************************** */
   if(state >= 0x80)   // Master is requesting data from slave
     {
      Pointer ++;
      if(Pointer > 20)
      {
         Pointer = 0;
      }   
      i2c_write(Pointer);
      fprintf(Out,"state >= 0x80 Pointer = %u\t 'state' = %X\r\n",Pointer,state);    
     }                    
     Int_Flag = true;
     enable_interrupts(INT_SSP);
     return incoming;
}


This code runs and displays matching values on my PC screen, running 2 copies of Hyperterminal.

My problem is:
1 As I understand things, everytime my SLAVE detects an Interrupt, my Interrupt Handler: int8 I2C_Interrupt( int state) will run, which it does!
However, again according to my understanding, it should run the Interrupt Handler when it receives a transmission from I2CStart(Master) in my MASTER code. But it doesn't appear to do so. I never get to see a line containing "state = 0". The only message I ever see is that printed when "state = >= 0x08.

Can anyone P L E A S E tell me what I am doing wrong or thinking wrong!!!


Many thanks for your time

John
temtronic



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

View user's profile Send private message

PostPosted: Thu Feb 08, 2018 6:46 am     Reply with quote

first thing to do ..
get PCM Ps 'I2C scanner' program from the code library and put into your master. If your Slave is 'seen' then you know it's not a basic hardware problem and the Slave is OK.

have you access to an oscilloscope ? When 'Playing with PICs', it's a very important tool. Even a used, 2 chnl, CRT scope for $50 is money very well spent.

I haven't looked further into your codes..one step at a time process.

there maybe I2C M/S code in the CCS examples ??

Jay
john822179



Joined: 22 Jun 2011
Posts: 7
Location: Tandragee, Northern Ireland

View user's profile Send private message AIM Address

PostPosted: Thu Feb 08, 2018 7:20 am     Reply with quote

Hello Jay,

Many thanks for your response.

I have already build a SNIFFER, using the I2CScanner code and that finds my SLAVE with no problems.
I have a 'scope and an 8 bit logic analyser to hand, but getting things to trigger is a bit of a problem! However, I can see traffic on both I2C lines.

I'll check the examples again, but I haven't seen anything that is immediately shouting at me!

John
Ttelmah



Joined: 11 Mar 2010
Posts: 19520

View user's profile Send private message

PostPosted: Thu Feb 08, 2018 7:31 am     Reply with quote

Then, look at the I2C slave example.

There are several problems in what you post:

Your slave goes into the interrupt, sets a flag and exits with the ISR_state.
The handler for this, then gets called, and immediately delays while seven characters are printed. At 19200bps, some 3.5mSec. The master expects the slave to be ready for the next operation in just 50uSec....
Similar things happen at each stage.
Then you try to pass the read address to the read operation. Wrong. The slave hardware is already programmed with the read address. The read operation, expects just a single bit to specify whether it is to ACK or not. Sending the wrong ack will hang the hardware.
Then at the end of the routine you set the int flag back to TRUE (1), so the routine will be called again even if there is no interrupt, and the state will be wrong....

Use the example.

If you want to see where it is, then just add code so it sets a variable with a value at each point, and print this in the main. Ideally use a buffered serial, so the data can just be written to the buffer, and printed in the one second delay. Currently it hasn't a hope.
john822179



Joined: 22 Jun 2011
Posts: 7
Location: Tandragee, Northern Ireland

View user's profile Send private message AIM Address

PostPosted: Thu Feb 08, 2018 7:57 am     Reply with quote

Hi Jay,

Thanks for opening the eyes!!!

I'll go away and have another go at it and get back to you.
I'll be out of the office until Tuesday, so hopefully I'll post some good news then!!

Many thanks again

John
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

Re: I2C between 2 16F690 chips
PostPosted: Thu Feb 08, 2018 8:01 am     Reply with quote

john822179 wrote:

However, again according to my understanding, it should run the Interrupt
Handler when it receives a transmission from I2CStart(Master) in my
MASTER code. But it doesn't appear to do so. I never get to see a line
containing "state = 0". The only message I ever see is that printed
when "state = >= 0x08.


Compile your slave program and look at the .LST file. Note that it moves
0x09 into the SSPCON register. This is the SSP mode.
Code:
03D4:  MOVLW  09
03D5:  BCF    STATUS.RP0
03D6:  MOVWF  SSPCON

The 16F690 data sheet says (for mode 9):
Quote:

REGISTER 13-2: SSPCON: SYNC SERIAL PORT CONTROL REGISTER

SSPM<3:0>: Synchronous Serial Port Mode Select bits:

1001 = Load SSPMSK register at SSPADD SFR address. (ie, mode 9)

When this mode is selected, any reads or writes to the SSPADD SFR
address actually accesses the SSPMSK register.

Since the SSPMSK register defaults to all 1's and CCS doesn't change it,
this means the incoming slave address is compared to the SSPADD
register. I.e., the SSPMSK feature is not used. It's not in play.

Now look farther down in the mode list in the data sheet:
Quote:
1110 = I2C Slave mode, 7-bit address with Start and Stop bit interrupts enabled

This mode (0x0E) would give you an interrupt on the start bit.

CCS doesn't use that mode. That's why you don't get an interrupt on
the start bit.
RF_Developer



Joined: 07 Feb 2011
Posts: 839

View user's profile Send private message

PostPosted: Thu Feb 08, 2018 8:04 am     Reply with quote

The basic learning approach is flawed. Most people coding for external I2C slaves never needs to code a slave at all. I've never done it for example. However, i f you really want to try then it's really much simpler to start off with a known working slave instead of trying to debug both master and slave together.

On PICs IC slaves are more difficult to get right, so its far easier to start off with a known working master, and the way to get that working is with a known working slave, i.e. someone else's I2C device, such as an EEPROM memory, which has a good mix of read and write operations, unlike a DAC which only needs writes, or an ADC which is mostly read but also needs a sensible input signal to convert.
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