|
|
View previous topic :: View next topic |
Author |
Message |
cbarberis
Joined: 01 Oct 2003 Posts: 172 Location: Punta Gorda, Florida USA
|
Can't seem to make I2C Master - Slave work |
Posted: Mon Apr 06, 2009 7:35 pm |
|
|
Hello,
I am posting the code below because I seem to be lost as to why my Master and Slave configuration does not seem to be working
For this particular test I am using two PIC16F88's and using the internal USART to do the I2C communications. What I need to do is the following:
For the master; all I need to do is to send to the slave a single byte command whenever the master gets a single byte char from the rs232 serial port, that is all the master does.
For the Slave all I need to do is to read its I2C port address from a 10 pos bcd switch on port a0-a3, that becomes it's address which is conveyed to the master. I use a 3 byte buffer where the first location is the slave address and the second location is the data or command I receive from the master. After that, all I do is just sit on a loop waiting for a I2C interrupt (which does not seem to work, in other words I never go into the interrupt, first clue) when I come out of the interrupt I set a flag, and on the main loop if this flag is set I then decode the data the master sent to me and turn on or off one of three leds....That is it!
Sounds very simple and I am sure it is, but I cannot seem to get the slave to do anything, although the master seems to be sending the correct data. I have looked at various samples here and I still can't seem to see what I am missing. If anyone can look at this and give me a clue it would be of great help.
Thank you
Master code:
Code: |
unsigned char Command,result,Address;
int8 RCVFlag = 0;
#define EPPHVREAD (Address << 1) | 0x1
#define EPPHVWRITE (Address << 1) | 0x0
void Init()
{
setup_adc_ports(NO_ANALOGS|VSS_VDD);
setup_adc(ADC_OFF);
port_b_pullups(TRUE);
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);
setup_oscillator(OSC_8MHZ|OSC_TIMER1);
enable_interrupts(INT_RDA);
enable_interrupts(GLOBAL);
}
#int_RDA
void RDA_isr()
{
Command = getc();
RCVFlag = 1;
restart_wdt();
}
int8 Read_Device(int8 register_address)
{
unsigned char data;
restart_wdt();
i2c_start();
i2c_write(EPPHVWRITE);
i2c_write(register_address);
i2c_write(EPPHVREAD);
data = i2c_read(0);
i2c_stop();
return(data);
}
void Write_Register(int8 register_address, int8 register_data)
{
i2c_start();
i2c_write(EPPHVWRITE);
i2c_write(register_address);
i2c_write(register_data);
i2c_stop();
}
void main()
{
Init();
Address = 0x9;
result = Read_Device(0);
delay_ms(50);
while(1)
{
if(RCVFlag)
{
i2c_write (1,Command);
RCVFlag = 0;
}
restart_wdt();
}
} |
Slave Code:
Code: |
#include "C:\PICOMP\FILES\Sage\PIPPIN\EPPSMOD.h"
#ZERO_RAM
int8 I2CFlag = 0;
unsigned int8 state,address,data,portvalue, buffer[3];
#define PORTADDRESS buffer[0]
#define COMMAND buffer[1]
void Init()
{
#use i2c(Slave,Fast,sda=PIN_B1,scl=PIN_B4,address=0x09,force_hw,restart_wdt)
port_b_pullups(TRUE);
setup_adc_ports(NO_ANALOGS|VSS_VDD);
setup_adc(ADC_OFF);
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
setup_wdt(WDT_576MS|WDT_DIV_16);
setup_timer_1(T1_DISABLED);
setup_timer_2(T2_DISABLED,0,1);
setup_comparator(NC_NC_NC_NC);
setup_vref(FALSE);
setup_oscillator(OSC_8MHZ|OSC_TIMER1);
output_high(VICTRL);
delay_ms(1000);
output_high(HVCTRL);
delay_ms(1000);
output_high(ECNTRL);
delay_ms(1000);
output_low(VICTRL); //comes up in CV mode
output_low(HVCTRL); //comes up with electrodes innactive
output_low(ECNTRL); //comes up with DRAIN electrode active
enable_interrupts(INT_SSP); //enable I2C interrupts
enable_interrupts(GLOBAL);
}
#INT_SSP
void sspinterupt ()
{
state = i2c_isr_state();
if(state < 0x80) //Master is sending data
{
if(state == 0)
{
}
if(state == 1) //First received byte is address
{
data = i2c_read();
address = data;
}
if(state == 2) //Second received byte is data
{
data = i2c_read();
buffer[address] = data;
}
}
if(state == 0x80) //Master is requesting data
{
i2c_write (buffer[address]);
}
I2CFlag = 1;
}
void main()
{
Init();
PORTADDRESS = portA & 0x0F;
//PortAddress = 9;
// i2c_SlaveAddr(PORTADDRESS);
while(1)
{
if(I2CFlag)
{ output_high(HVCTRL); DELAY_MS(100); output_low(HVCTRL);
switch (COMMAND)
{ case 'V':
output_low(VICTRL); // turn off CI LED
I2CFlag = 0;
break;
case 'I':
output_high(VICTRL); //turn on CI LED
I2CFlag = 0;
break;
case 'X':
output_low(HVCTRL); //turn off HVCTRL LED
I2CFlag = 0;
break;
case 'O':
output_high(HVCTRL); //turn on HVCTRL LED
I2CFlag = 0;
break;
case 'D':
output_low(ECNTRL); //turn off DRAIN LED
I2CFlag = 0;
break;
case 'S':
output_high(ECNTRL); //turn on DRAIN LED
I2CFlag = 0;
break;
default:
output_low(VICTRL); //comes up to init mode
output_low(HVCTRL);
output_low(ECNTRL);
I2CFlag = 0;
break;
}
}
restart_wdt();
}
} |
|
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon Apr 06, 2009 7:57 pm |
|
|
Quote: |
Address = 0x9;
#define EPPHVREAD (Address << 1) | 0x1
#define EPPHVWRITE (Address << 1) | 0x0
|
You can't use 0x09 for the Slave address. It's reserved. See this post:
http://www.ccsinfo.com/forum/viewtopic.php?t=33966&start=3
Quote: | #use i2c(Slave,Fast,sda=PIN_B1,scl=PIN_B4,address=0x09,force_hw,restart_wdt) |
The Slave address specified in the #use i2c() statement must be in
pre-shifted byte format. This is different from the Philips 7-bit unshifted
format. If you were allowed to use 0x09 (in Philips format) for the
slave address, you would specifiy it as 0x12 in the #use i2c() statement.
But you can't use that address. |
|
|
cbarberis
Joined: 01 Oct 2003 Posts: 172 Location: Punta Gorda, Florida USA
|
|
Posted: Mon Apr 06, 2009 8:24 pm |
|
|
Thank You pcm programmer, I totally forgot that there were reserved addresses, I tried adding 10 (decimal) to my slave address field, I think that would get me out of the conflicting addresses? but I still seem to have the same problem; the slave will not recognise any commands. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon Apr 06, 2009 9:01 pm |
|
|
Quote: | I tried adding 10 (decimal) to my slave address field |
Post your revised code. |
|
|
bsturm
Joined: 23 Feb 2009 Posts: 29
|
|
Posted: Mon Apr 06, 2009 9:19 pm |
|
|
I think you have to use even numbers for the address, as the LSB is reserved for the read/write bit. |
|
|
cbarberis
Joined: 01 Oct 2003 Posts: 172 Location: Punta Gorda, Florida USA
|
|
Posted: Tue Apr 07, 2009 6:42 am |
|
|
I tried changing the slave address by doing the following:
ON the Slave:
#use i2c(Slave,Fast,sda=PIN_B1,scl=PIN_B4,address=0x13,force_hw,restart_wdt)
PORTADDRESS = portA & 0x0F;
PORTADDRESS += 10;
On the master:
Address = 0x13;
I believe this takes me away from the conflicting addresses? |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue Apr 07, 2009 8:44 am |
|
|
No. Don't use odd i2c slave addresses.
My advice is to get rid of the "Address" variable. Also get rid of the
shifting and OR'in in your code. Create the addresses (slave read
and write) with constants.
In the Slave:
Quote: | #use i2c(Slave,Fast,sda=PIN_B1,scl=PIN_B4,address=0x14,force_hw,restart_wdt) |
In the Master:
Quote: | #define EPPHVWRITE 0x14
#define EPPHVREAD 0x15 |
If you do it this way, everything will be very clean, at least with regard
to the addresses. |
|
|
cbarberis
Joined: 01 Oct 2003 Posts: 172 Location: Punta Gorda, Florida USA
|
|
Posted: Tue Apr 07, 2009 3:52 pm |
|
|
Once again; Thank you pcm programmer
I tried using the fixed constants as you outlined in your previous post but I seem to be getting the same results. Why is this so difficult? I never had any issues with any other serial protocol working a slave master combination. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue Apr 07, 2009 3:57 pm |
|
|
Quote: | if(state < 0x80) //Master is sending data
{
if(state == 0)
{
}
if(state == 1) //First received byte is address
{
data = i2c_read(); address = data;
}
if(state == 2) //Second received byte is data
{
data = i2c_read();
buffer[address] = data;
}
} |
Your code is different from the CCS example file Ex_Slave.c in an
essential way. They always do the i2c_read() operation if the state
is less than or equal to 0x80. Furthermore, you have modified the
test, to make it be only "less than 0x80".
My suggestion: Put everything back the way it was in the CCS example.
Don't change anything until you get the basic example working. Then
make only very carefully considered changes. |
|
|
bsturm
Joined: 23 Feb 2009 Posts: 29
|
|
Posted: Tue Apr 07, 2009 4:58 pm |
|
|
Does any info from this thread help? http://www.ccsinfo.com/forum/viewtopic.php?t=38091&highlight=i2c+16f886
I had to add some short delays in strategic places. I also started with Ex_Slave.c and a short master program that I found on this board. The master was not much longer than the examples in the help file. Like PCM Programmer said, start with a simple program that has been known to work, then build on it. |
|
|
|
|
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
|