![](templates/subSilver/images/CCSLogo.jpg) |
![CCS C Software and Maintenance Offers](templates/subSilver/images/forumAd6.jpg) |
View previous topic :: View next topic |
Author |
Message |
Mc
Joined: 07 May 2004 Posts: 11
|
I2C SW working... I2C HW don´t? |
Posted: Fri May 07, 2004 6:26 am |
|
|
Hi guys! I'm new to CCS C and I'm having some trouble getting the I2C HW working...
If I use #use i2c(Master,Fast,sda=PIN_C4,scl=PIN_C3) it works OK:
Program running
I2C init ok
Write: 00 02 04 06 08 0A 0C 0E
Read: 00 02 04 06 08 0A 0C 0E
but when I force HW I2C instead with #use i2c(Master,Fast,sda=PIN_C4,scl=PIN_C3,force_hw) it gets stuck:
Program running
I2C init ok
Here's my sample code, I use routines from 2465.C with some changes to fit my needs:
Code: | #include <16F876.h>
#use delay(clock=4000000)
#fuses NOWDT,XT,NOPUT,NOPROTECT,BROWNOUT,NOLVP,NOCPD,NOWRT,NODEBUG
#define EEPROM_SCL PIN_C3
#define EEPROM_SDA PIN_C4
#use rs232(baud=19200,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8,errors)
#use i2c(Master,Fast,sda=PIN_C4,scl=PIN_C3)
//#use i2c(Master,Fast,sda=PIN_C4,scl=PIN_C3,FORCE_HW)
#define hi(x) (*(&x+1))
void i2c_init (void)
{
output_float(EEPROM_SCL);
output_float(EEPROM_SDA);
}
int1 i2c_device_ready (int8 i2c_slave_address)
{
int1 ack;
i2c_start(); // Si se admite petición de escritura entonces
ack = i2c_write(i2c_slave_address); // el dispositivo está listo
i2c_stop();
return !ack;
}
void i2c_buffer_write_16 (int8 *i2c_buffer, int8 i2c_slave_address, int16 address0, int8 i2c_data_number)
{
int8 i;
while(!i2c_device_ready(i2c_slave_address));
i2c_start();
i2c_write(i2c_slave_address); // controlbyte (write)
i2c_write(hi(address0));
i2c_write(address0);
for(i=0;i<i2c_data_number;i++) i2c_write(i2c_buffer[i]);
i2c_stop();
}
void i2c_buffer_read_16 (int8 *i2c_buffer, int8 i2c_slave_address, int16 address0, int8 i2c_data_number)
{
int8 i;
while(!i2c_device_ready(i2c_slave_address));
i2c_start();
i2c_write(i2c_slave_address); // controlbyte (write)
i2c_write(hi(address0));
i2c_write(address0);
i2c_start();
i2c_write(i2c_slave_address+1); //controlbyte (read)
for(i=0;i<i2c_data_number-1;i++) i2c_buffer[i]=i2c_read(); //n-1 data->read+ack
i2c_buffer[i2c_data_number-1]=i2c_read(0); //last data->read+noack
i2c_stop();
}
#define I2CREGS 8
void main()
{
int8 i;
int8 i2c_buffer[I2CREGS];
for (i=0;i<I2CREGS;i++) i2c_buffer[i]=2*i; //0,2,4,6,8,10,12,14
setup_adc_ports(RA0_ANALOG);
setup_adc(ADC_CLOCK_DIV_32);
setup_spi(FALSE);
setup_counters(RTCC_INTERNAL,RTCC_DIV_256);
setup_timer_1(T1_DISABLED);
setup_timer_2(T2_DISABLED,0,1);
printf("Program running\n\r");
i2c_init();
printf("I2C init ok\n\r");
i2c_buffer_write_16(i2c_buffer,0xA0,0x00,I2CREGS);
printf("Write: ");
for(i=0;i<I2CREGS;i++) printf("%X ",i2c_buffer[i]);
printf("\n\r");
i2c_buffer_read_16(i2c_buffer,0xA0,0x00,I2CREGS);
printf("Read: ");
for(i=0;i<I2CREGS;i++) printf("%X ",i2c_buffer[i]);
printf("\n\r");
while(1);
}
|
I'm using an 16F876 @ 4MHz, CCS v3.187 and I'm testing the I2C with a 24LC64 EEPROM...
Any idea??
Thanx in advance ![Wink](images/smiles/icon_wink.gif) |
|
![](templates/subSilver/images/spacer.gif) |
Haplo
Joined: 06 Sep 2003 Posts: 659 Location: Sydney, Australia
|
|
Posted: Fri May 07, 2004 6:47 am |
|
|
Make sure RC3 and RC4 are configured as inputs. Have you tried taking the 'fast' keyword out to see if it works? How big are your pull-ups? |
|
![](templates/subSilver/images/spacer.gif) |
Mc
Joined: 07 May 2004 Posts: 11
|
|
Posted: Fri May 07, 2004 7:24 am |
|
|
Thanx for the quick answer!
Manually setting PORTC as inputs with set_tris_c(0xFF); doesn't solve the problem, maybe RS232 routines are overwiting this setting??
My pull-ups are 2k2 each. In 'Slow' mode it doesn´t work either.
Also I think that I don't have to output float the i2c pins while using i2c hw, I tried to comment
output_float(EEPROM_SCL);
output_float(EEPROM_SDA);
but still no luck...
I guess there's no HW related problem since I've been working with I2C HW ASM routines in the same board not so long ago with no issues whatsoever... |
|
![](templates/subSilver/images/spacer.gif) |
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri May 07, 2004 12:06 pm |
|
|
I would guess that you're probably using PCW.
If you don't use a peripheral module, PCW puts in code to
explicitly disable it. This isn't really necessary, because the
peripheral modules are disabled by default upon power-up.
The problem is caused by this line of code:
setup_spi(FALSE);
That line sets the SSPCON register to 0x00. So it affects
the entire SSP module, and not just "spi", as the function name
suggests. It writes a 0 to the SSPEN bit in that register.
According to the data sheet:
bit 5 SSPEN: Synchronous Serial Port Enable bit
0 = Disables serial port and configures these pins as I/O port pins
That's why it's not working. The solution is to delete that line. |
|
![](templates/subSilver/images/spacer.gif) |
kender_a Guest
|
Same problem. |
Posted: Fri May 07, 2004 2:22 pm |
|
|
Hello,
I have the same problem - I2C stops worling if is specify FORCE_HW. But I don't have a call to setup_spi() anywhere in my code. Here's my code:
Code: |
#include <18F442.h>
#device ICD=TRUE
#device adc=8
#use delay(clock=4000000)
#fuses NOWDT,WDT128,XT, NOPROTECT, NOOSCSEN, BROWNOUT, BORV20, NOPUT, STVREN, DEBUG, LVP, NOWRT, NOWRTD, NOWRTB, NOWRTC, NOCPD, NOCPB, NOEBTR, NOEBTRB
#use rs232(DEBUGGER)
#use i2c(Master,sda=PIN_C4,scl=PIN_C3,force_hw)
#include "i2ctest.h"
void main()
{
setup_adc_ports(NO_ANALOGS);
setup_adc(ADC_OFF);
setup_psp(PSP_DISABLED);
setup_wdt(WDT_OFF);
setup_timer_0(RTCC_INTERNAL);
setup_timer_1(T1_DISABLED);
setup_timer_2(T2_DISABLED,0,1);
setup_timer_3(T3_DISABLED|T3_DIV_BY_1);
while (1)
{
// single write to EEPROM
i2c_start();
i2c_write(0b10100000); // command byte
i2c_write(0x01); // address
i2c_write(0xAA); // data
i2c_stop();
// single read from EEPROM
i2c_start();
i2c_write(0b10100000); // command byte
i2c_write(0x01); // read address
i2c_start();
i2c_write(0b10100001); // command byte
printf("%4X\n\r", i2c_read(1)); // end of the read
i2c_stop();
// page write to EEPROM
// page read from EEPROM
// write to DAC
// read RTC
}
}
|
I'm running this with the debugger, and the execution halts at "setup_adc_ports(NO_ANALOGS);"
What am I doing wrong?
Nick |
|
![](templates/subSilver/images/spacer.gif) |
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri May 07, 2004 2:33 pm |
|
|
Quote: | I have the same problem - I2C stops working if I specify FORCE_HW |
Quote: | I'm running this with the debugger, and the execution halts
at "setup_adc_ports(NO_ANALOGS);" |
These are two separate complaints. I'll answer the one about
the i2c problem.
You have this line of code:
printf("%4X\n\r", i2c_read(1));
That's wrong. The last i2c read must do a "NAK".
It should be:
printf("%4X\n\r", i2c_read(0)); |
|
![](templates/subSilver/images/spacer.gif) |
kender_a Guest
|
NACK worked |
Posted: Fri May 07, 2004 2:52 pm |
|
|
Thanks, switching to i2c_read(0) worked, and formware doesn't halt at setup_adc_ports(NO_ANALOGS) too.
I have another question though. I have to pause for about 5ms between the read and the write. Otherwise I read 0xFF. Can this pause be avoided? Here's my code again:
Code: |
while (1)
{
// single write to EEPROM
i2c_start();
i2c_write(0b10100000); // command byte
i2c_write(0x01); // address
i2c_write(i); // data
i2c_stop();
delay_ms(5);
// single read from EEPROM
i2c_start();
i2c_write(0b10100000); // command byte
i2c_write(0x01); // read address
i2c_start();
i2c_write(0b10100001); // command byte
printf("%4X\n\r", i2c_read(0)); // end of the read, NACK
i2c_stop();
// page write to EEPROM
// page read from EEPROM
// write to DAC
// read RTC
++i;
if (i == 255) i = 1;
}
|
|
|
![](templates/subSilver/images/spacer.gif) |
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri May 07, 2004 3:21 pm |
|
|
Quote: | I have another question though. I have to pause for about 5ms
between the read and the write. Otherwise I read 0xFF. Can this pause
be avoided? |
The EEPROM data sheet will tell you that it takes about 5 ms for
the write operation to be completed. Look at page 4 of the
data sheet, at Parameter No. 17:
http://ww1.microchip.com/downloads/en/DeviceDoc/21203l.pdf
The two common ways to handle this are:
1. Put a delay_ms(5) statement at the end of the write operation.
ie., put it after the i2c_stop() statement at the end of the routine.
(Or use a slightly larger delay, such as 6 ms, to be extra safe).
2. Do "ack polling". This method is discussed in the 24LC256 data
sheet. CCS does this in their sample EEPROM drivers.
The drivers are in this directory:
c:\Program Files\Picc\Drivers
If you have the demo, you probably don't get these files. |
|
![](templates/subSilver/images/spacer.gif) |
dyeatman
Joined: 06 Sep 2003 Posts: 1924 Location: Norman, OK
|
I2C Delay Required |
Posted: Fri May 07, 2004 3:38 pm |
|
|
One way to eliminate the delay is to use FRAM which does not require a delay between the write and read.... |
|
![](templates/subSilver/images/spacer.gif) |
Mc
Joined: 07 May 2004 Posts: 11
|
|
Posted: Fri May 07, 2004 9:46 pm |
|
|
PCM programmer wrote: | The problem is caused by this line of code:
setup_spi(FALSE);
.
.
.
That's why it's not working. The solution is to delete that line. |
Yep, that was the problem!
Thanx a lot!! ![Wink](images/smiles/icon_wink.gif) |
|
![](templates/subSilver/images/spacer.gif) |
hayri Guest
|
|
Posted: Sat Mar 19, 2005 9:53 am |
|
|
very old topic to post. but i must!
thanks a lot PCM programmer it solved my problem. |
|
![](templates/subSilver/images/spacer.gif) |
|
|
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
|