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

Trouble with I2C comm 18f452 (M) to 18f2550 (Sl)
Goto page 1, 2  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
meepa123



Joined: 27 Feb 2007
Posts: 17

View user's profile Send private message

Trouble with I2C comm 18f452 (M) to 18f2550 (Sl)
PostPosted: Tue Feb 27, 2007 12:01 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Tue Feb 27, 2007 2:31 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Wed Feb 28, 2007 12:16 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Wed Feb 28, 2007 12:36 pm     Reply with quote

Quote:
ex_slave at 18f2550@20mhz slave

The A3 silicon for the 18F2550 has several erratas for i2c slave mode.
The B4 silicon still has one errata for an i2c slave.

You can download the errata sheets from this page:
http://www.microchip.com/stellent/idcplgidcplg?IdcService=SS_GET_PAGE&nodeId=1335&dDocName=en010280

My suggestion is to try using a different PIC for the slave.
meepa123



Joined: 27 Feb 2007
Posts: 17

View user's profile Send private message

PostPosted: Wed Feb 28, 2007 4:09 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Wed Feb 28, 2007 4:25 pm     Reply with quote

Quote:
So how can I set up i2c, without using #use i2c?

Look for posts that have sample code for writing your own i2c routines.
Here are some:
http://www.ccsinfo.com/forum/viewtopic.php?t=28531
http://www.ccsinfo.com/forum/viewtopic.php?t=26349

I think there are many more. Search for the i2c register names.
meepa123



Joined: 27 Feb 2007
Posts: 17

View user's profile Send private message

PostPosted: Thu Mar 01, 2007 11:15 am     Reply with quote

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

View user's profile Send private message

PostPosted: Thu Mar 01, 2007 12:35 pm     Reply with quote

You didn't find anything in those links ?

There's a post by me that takes register level i2c code and converts
it to CCS functions. You can do the reverse.

Then if you use the forum's search page, and search for i2c_isr_state()
you'll find a page with this information on it:

Commented .LST file for the i2c_isr_state() function:
http://www.ccsinfo.com/forum/viewtopic.php?t=28531&start=10

C source code for i2c_isr_state():
http://www.ccsinfo.com/forum/viewtopic.php?t=26477&start=3

Here's a link to an old post where I had converted Julian Winpenny's
register level hardware i2c routines to CCS:
http://web.archive.org/web/20030926033103/http://www.ccsinfo.com/wwwboard/messages/725.html


Search the archives for more information:
http://www.ccsinfo.com/forum/search.php
meepa123



Joined: 27 Feb 2007
Posts: 17

View user's profile Send private message

PostPosted: Thu Mar 01, 2007 2:03 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Thu Mar 01, 2007 2:43 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Mon Mar 12, 2007 11:09 am     Reply with quote

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

View user's profile Send private message

PostPosted: Mon Mar 12, 2007 11:37 am     Reply with quote

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

View user's profile Send private message

PostPosted: Mon Mar 12, 2007 11:51 am     Reply with quote

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

View user's profile Send private message

PostPosted: Mon Mar 12, 2007 11:55 am     Reply with quote

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

View user's profile Send private message

PostPosted: Mon Mar 12, 2007 12:06 pm     Reply with quote

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.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page 1, 2  Next
Page 1 of 2

 
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