|
|
View previous topic :: View next topic |
Author |
Message |
meepa123
Joined: 27 Feb 2007 Posts: 17
|
Trouble with I2C comm 18f452 (M) to 18f2550 (Sl) |
Posted: Tue Feb 27, 2007 12:01 pm |
|
|
Hello
I am having trouble with I2C communication between a 18f452@20mhz in master mode and a 18f2550@48mhz (20mhz xtal) in slave mode.
Code: |
#include <18f452.h>
#fuses HS,NOWDT
#use delay(clock=20000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)
#build (reset=0x04,interrupt=0x08)
#use i2c(master, sda=PIN_C4,scl=PIN_C3,force_hw,slow)
void main()
{
output_float(PIN_C4);
output_float(PIN_C3);
setup_timer_0 (RTCC_INTERNAL|RTCC_DIV_4);
enable_interrupts(GLOBAL);
enable_interrupts(INT_TIMER0);
lcd_init();
printf(LCD_PUTC,"INICIO!!");
delay_ms(1000);
lcd_putc('\f');
while(1)
{
printf(LCD_PUTC,"Start");
delay_ms(1000);
lcd_putc('\f');
i2c_start();
output_bit(PIN_B7,i2c_write(0xa0));
output_bit(PIN_B7,i2c_write(0x00));
i2c_write(0x80);
printf(LCD_PUTC,"Datos");
lcd_putc('\f');
i2c_stop();
printf(LCD_PUTC,"Dato enviado");
delay_ms(1000);
lcd_putc('\f');
i2c_start();
i2c_write(0xa0);
i2c_write(0x00);
i2c_start();
i2c_write(0xa1);
tmp=i2c_read();
printf(LCD_PUTC,"%u",tmp);
i2c_stop();
}
|
We write "0x80" at adress 0x00 of the only slave device, and after that, we point at 0x00 adress, we restart i2c, and we read at this adress. So tmp value should be 0x80.
The output_bit command (so as the printfs) is used with debug purposes, in order to know, with a led, whether ACK is succesful from slave or not.
The whole main() routine executes well. But "tmp" is always filled with 0xFF. The OK value would be, that it had 0x80. The annoying fact is, that if I unplug the slave device (the 18f2550) from it's socket, the result is THE SAME. Any connection problem shall be discarded, as i've checked and re-checked the I2C connection. We know the device is running because it also has two PWM outputs that can be succesfully checked. (which i've omitted on the code following)
Slave code:
Code: |
#include <18f2550.h>
#fuses HSPLL,PLL5,CPUDIV1,NOWDT,LVP,NOPROTECT,PUT,NOBROWNOUT,NOPBADEN
#use delay(clock=48000000)
#use I2C(slave,sda=PIN_B0,scl=PIN_B1,address=0xa0,force_hw,slow)
#priority SSP
void main()
{
set_tris_a(0x00);
setup_adc_ports(NO_ANALOGS);
set_tris_b(0xF0);
output_c(0x00);
output_float(PIN_B0);
output_float(PIN_B1);
imagen_ENC1=input(ENCODER1);
imagen_ENC2=input(ENCODER2);
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_8);
enable_interrupts(INT_TIMER0);
setup_timer_1(T1_INTERNAL|T1_DIV_BY_8);
enable_interrupts(INT_TIMER1);
setup_timer_2(T2_DIV_BY_16,0xff,1); //Timer del PWM
enable_interrupts(INT_RB); //INT ENCODERS
enable_interrupts(INT_SSP); //INT I2C
setup_ccp1(CCP_PWM);//PWM1
setup_ccp2(CCP_PWM);//PWM2
enable_interrupts(GLOBAL);
while(1)
{
while(!i2c_poll());
output_toggle(PIN_A0);
delay_ms(500);
}
}
//Other routines and INTs are omitted prior to better understanding
#INT_SSP
void isr4()
{
state = i2c_isr_state();
output_a(0xFF);
if(state>=0x80) // Solicitud de envio
{
i2c_write(I2C_BUFFER[i2c_addr+(state-0x80)]); //Envio dato desde direccion, esta
} //se incrementa por cada solicitud antes del STOP.
if (state>=2) // Recibe datos II
{
I2C_BUFFER[i2c_addr+state-2]=i2c_read(); //Segundo y consecutivos datos, la direccion
//se incrementa por cada envio antes del STOP.
if(i2c_addr==9) I2C_READ_RDY=1; //Si se escribe el comando, se sube flag de datos recibidos.
}
if(state==1) //Recibe PRIMER dato
{
i2c_addr=i2c_read(); //Primer dato direccion
}
}
|
Don't know if the I2C Interrupt handling routine is ok or not. But the fact is that i've put OUTPUT_A(0xFF) as soon as the ISR is reached. No port_a response, it's always at 0x00 (as declared at startup). That means that, despite being active the SSP interrupt, there's no entering at it.
The i2c_poll command in main() sub has been set to once again and desperately check out if any i2c data is received.
I should repeat again, that physical conditions have been double-checked with the continuity tester. Pull-ups are single 2k2 resistors, and i2c wire length is 12-15cm. Both chips have common ground, and are powered with the same +5V regulator. Chip trouble may not be very probable, as i've had the same result with four different 18f2550s.
I hope you can help me, i'm getting very annoyed with this problem, for the third day consecutively.
Looking forward for any response, thanks beforehand! |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue Feb 27, 2007 2:31 pm |
|
|
It's clear that you're new to the compiler. My advice is to first
study the CCS example for an i2c slave. Learn how to write
programs in CCS. Here is the location of the CCS slave example:
c:\Program Files\Picc\Examples\Ex_Slave.c
The following post contains sample code for an i2c master which
can talk to the CCS Ex_Slave.c code. You should program this
code into your Master PIC and program the Ex_Slave code into
your Slave PIC.
http://www.ccsinfo.com/forum/viewtopic.php?t=28097&start=9
Also make sure you have pull-up resistors on the SDA and SCL lines.
You can use 4.7K resistors for this. |
|
|
meepa123
Joined: 27 Feb 2007 Posts: 17
|
|
Posted: Wed Feb 28, 2007 12:16 pm |
|
|
Ok, just to tell you that i keep receiving "0xFF", having loaded both programs (your code at 18f452@20mhz master, and ex_slave at 18f2550@20mhz slave).
I'd bet no ack is done by the slave. Anyone can help?
Thx!! |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
|
meepa123
Joined: 27 Feb 2007 Posts: 17
|
|
Posted: Wed Feb 28, 2007 4:09 pm |
|
|
Ok, thanks a lot.
One of the A3 erratas seems the most conflictive to me, as it mentions that there have been noticed some i2c troubles about it. The one concerning the TRISB and the LATB registers. It says, that prior to setting up I2C, <B1> have to be set as outputs, put low both, and then cfg them as inputs.
But the main problem is, that the only way i know to setup I2C is #use i2c statement. And we all know that #use statements must be put before any command.
So how can I set up i2c, without using #use i2c? Shall I learn microscopically 18f2550's i2c workarounds, and then set-clear register bits as if it'd be an ASM code snippet?
thanks beforehand. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
|
meepa123
Joined: 27 Feb 2007 Posts: 17
|
|
Posted: Thu Mar 01, 2007 11:15 am |
|
|
I didn't find anything at those links. Nevertheless... if i don't use "#use i2c", i can't use useful commands like i2c_isr_state, for example. That may be rather annoying.
Hasn't anyone tried i2c on 18f2550? I keep on and keep on, but the slave does never enter at the interrupt. I'm very lost, really.
Thanks! |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
|
meepa123
Joined: 27 Feb 2007 Posts: 17
|
|
Posted: Thu Mar 01, 2007 2:03 pm |
|
|
Hello once again. I made an i2c_slave driver, but still doesn't work the whole thing.
Code: |
#if defined(__PCM__)
#include <16F877.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock=20000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)
#elif defined(__PCH__)
#include <18F2550.h>
#fuses HSPLL,PLL5,CPUDIV1,NOWDT,NOPROTECT,NOLVP
#use delay(clock=48000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)
#endif
#include <i2c_18f2550.c>
BYTE address, buffer[0x10];
#INT_SSP
void ssp_interupt ()
{
BYTE incoming, state;
output_a(0xFF);
output_c(0xFF);
state = my_i2c_isr_state();
if(state < 0x80) //Master is sending data
{
incoming = i2c_read();
if(state == 1) //First received byte is address
address = incoming;
if(state == 2) //Second received byte is data
buffer[address] = incoming;
}
if(state == 0x80) //Master is requesting data
{
i2c_write(buffer[address]);
}
}
void main ()
{
setup_adc_ports(NO_ANALOGS);
output_a(0x00);
set_tris_c(0x00);
init_i2c();
enable_interrupts(GLOBAL);
enable_interrupts(INT_SSP);
while (TRUE) {}
}
|
And i2c_18f2550 is the routine container:
Code: |
#byte TRISB = 0xF93
#define SDA PIN_B0
#define SCL PIN_B1
#byte MCU_SSPBUF = 0xFC9
#byte MCU_SSPADD = 0xFC8
#byte MCU_SSPSTAT = 0xFC7
#byte MCU_SSPCON1 = 0xFC6
#byte MCU_SSPCON2 = 0xFC5
#bit DA_BIT = MCU_SSPSTAT.5
#bit RW_BIT = MCU_SSPBUF.0
#define ADRESS 0xA0;
void init_i2c()
{
setup_adc_ports(NO_ANALOGS);
bit_clear(TRISB,0);
bit_clear(TRISB,1);
output_low(SDA);
output_low(SCL);
bit_set(TRISB,0);
bit_set(TRISB,1);
MCU_SSPADD=ADRESS;
MCU_SSPCON1=0x36;
}
int8 i2c_read()
{
return MCU_SSPBUF;
}
int1 i2c_write(int8 data)
{
MCU_SSPBUF=data;
}
//int8 my_i2c_isr_state(void)
//0= Adress, to write in slave
//1= Data, to write in slave
//0x80=Adress,to send from slave
//0x81=Data, to send from slave
int8 my_i2c_isr_state(void)
{
int8 i2c_state=0;
int8 retval;
if(!DA_BIT) // If address byte was received
{
i2c_state = 0; // Suppose it is a write adress
if(RW_BIT) // If it is a Read address
bit_set(i2c_state, 7); // Then set bit 7 of state.
}
else // If data was received
{
i2c_state++; //Suppose it is data to be read, increment each data.
if(RW_BIT) //If it is data sent
bit_set(i2c_state,7);
}
return(i2c_state);
}
|
Should that work? Anything wrong? I am very desperated.
Thanks a lot for you attention.
PD: Before criticising the code, which probably has many bugs, let me tell you that it simply doesn't enter at the interrupt. Because otherwise porta and portc would both 5V, and i measure 0-1V values. To initialize the I2C hardware with init_i2c() , i've followed the microchip errata doc's advice. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Mar 01, 2007 2:43 pm |
|
|
Not only do you have to make the i2c routines, you also have to add
code to do work-arounds for the bugs in the erratas, depending upon
what version of the 18F2550 silicon you have.
I don't want to do this. If it was me, I would buy a different PIC
that doesn't have erratas on the MSSP in i2c mode. |
|
|
meepa123
Joined: 27 Feb 2007 Posts: 17
|
|
Posted: Mon Mar 12, 2007 11:09 am |
|
|
Hello
I have fresh news. The problem is more focused now. I've tried a different master pic (18f4680) but it still doesn't work. After checking everything out with a digital oscilloscope, i came to this:
The I2C bus works, but it goes constantly low after the slave's read adress is written.
When i2c_write(0xa1) is done, both clock and data go low. And don't expect them to change. If I unplug the slave (18f2550), the signals are ok (despite no ack, obviously). So the problem must be at 18f2550. At the isr maybe?
Slave code is ex_slave modified:
Code: |
#if defined(__PCM__)
#include <16F877.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock=20000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)
#elif defined(__PCH__)
#include <18F2550.h>
#fuses HSPLL,PLL5,CPUDIV1,NOWDT,NOPROTECT,NOLVP
#use delay(clock=48000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)
#endif
#use i2c(SLAVE, SDA=PIN_B0, SCL=PIN_B1, address=0xa0)
BYTE address, buffer[0x10];
#INT_SSP
void ssp_interupt ()
{
][ FORUM DISPLAYS CORRUPT DATA, SEE IMAGE
}
void main ()
{
setup_adc_ports(NO_ANALOGS);
output_a(0x00);
set_tris_c(0x00);
*0xFC6=0x00;
set_tris_b(0xF0);
output_low(PIN_B0);
output_low(PIN_B1);
set_tris_b(0xF3);
*0xFC6=0x36;
enable_interrupts(GLOBAL);
enable_interrupts(INT_SSP);
while (TRUE) {}
}
|
When running, A0 and A1 get high, so there must have been i2c activity. A2 pin never goes high. So i2c_isr_state never gets >= 0x80. Do you have any ideas? Hardware problem?
I have just tried with a brand new 18f2550 slave, and the problem is the same. Any idea?
Thanks beforehand! |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon Mar 12, 2007 11:37 am |
|
|
Try a different PIC type for the slave. The master is no problem.
The 18F2550 has erratas for i2c slave mode. Get a different PIC.
Also, the reason code doesn't display properly is because HTML is
enabled. This means the angle brackets < > are interpreted as
HTML symbols. It destroys your posted code. There is a tickbox
just below the posting window to disable HTML. Use it.
I have sent a PM to the forum admin requesting them to globally
disable HTML by default, but they just ignore me. I give up on
PM'ing them about it anymore. So you have to do it when you post. |
|
|
meepa123
Joined: 27 Feb 2007 Posts: 17
|
|
Posted: Mon Mar 12, 2007 11:51 am |
|
|
I can't give up with this PIC, as so much work would have been in vain. Nevertheless, your words are taken into account, and I'll think about it.
The slave's adress is 0xa0 , and the "conflictive" code is, when master points to adress 0xa1, i mean, the slave's read adress.
There the bus gets hung. I hope somebody can help. I read somebody around the forum, who said that the pic should be "timeouted" to reset the start bit... or something like that. How can I timeout the 18f2550's hold? Because looks like the slave is holding the clock down. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon Mar 12, 2007 11:55 am |
|
|
Temporarily try a different PIC for the slave, just to see if the problem
is in your code. |
|
|
meepa123
Joined: 27 Feb 2007 Posts: 17
|
|
Posted: Mon Mar 12, 2007 12:06 pm |
|
|
18f2550 pinout-compatible devices, which suit the requirement of having hardware I2C on <B0>, have the same errata-set.
I can't afford getting into pic16 devices, as they don't suit my project's requirements. |
|
|
|
|
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
|