|
|
View previous topic :: View next topic |
Author |
Message |
john822179
Joined: 22 Jun 2011 Posts: 7 Location: Tandragee, Northern Ireland
|
I2C between 2 16F690 chips |
Posted: Thu Feb 08, 2018 6:33 am |
|
|
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: 9246 Location: Greensville,Ontario
|
|
Posted: Thu Feb 08, 2018 6:46 am |
|
|
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
|
|
Posted: Thu Feb 08, 2018 7:20 am |
|
|
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: 19552
|
|
Posted: Thu Feb 08, 2018 7:31 am |
|
|
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
|
|
Posted: Thu Feb 08, 2018 7:57 am |
|
|
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
|
Re: I2C between 2 16F690 chips |
Posted: Thu Feb 08, 2018 8:01 am |
|
|
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
|
|
Posted: Thu Feb 08, 2018 8:04 am |
|
|
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. |
|
|
|
|
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
|