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 support@ccsinfo.com

I2C issue with PIC18F2550

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
Maze



Joined: 12 Sep 2012
Posts: 4

View user's profile Send private message

I2C issue with PIC18F2550
PostPosted: Wed Sep 12, 2012 5:08 am     Reply with quote

Hi everyone.

I don't know if there is any other topic about my problem, anyway I'm going to explain.

I'm using 18F2550 trying to program a Master and a Slave that must communicate with I2C module. The function of the master is to read the adc value from slave but it gets stuck and doesn't read anything, giving as result just "128". I'm sending 49 with V, using a voltage source of 5V and pull-up resistors of 2.2k for the SDA and SCL.

I just can't find the errors so I'm going to post here the codes, praying for someone to help me Embarassed

Master:
Code:

#include <prova master.h>
#device adc=10

#FUSES NOWDT                   
#FUSES WDT128                   
#FUSES CPUDIV4                 
#FUSES INTRC_IO                 
#FUSES NOBROWNOUT             
#FUSES NOMCLR                   
#FUSES NOLVP                     
#FUSES NOXINST                 

#use delay(int=8000000)

#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8,stream=PORT1)
#use i2c(Master,Fast,sda=PIN_B0,scl=PIN_B1)

#define SLAVE1_WRT_ADDR   0x14
#define SLAVE1_READ_ADDR  0x15

int data;
void main()
{
   setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);      //32.7 ms overflow

   setup_timer_3(T3_DISABLED | T3_DIV_BY_1);

   enable_interrupts(INT_RTCC);
   enable_interrupts(INT_EXT);
   enable_interrupts(INT_SSP);
   enable_interrupts(GLOBAL);
   setup_oscillator(OSC_8MHZ|OSC_INTRC|OSC_31250|OSC_PLL_OFF);

   while(TRUE)
   {
      i2c_start();
      i2c_write(SLAVE1_READ_ADDR);
      data = i2c_read(0);
      i2c_stop();
      delay_ms(500);
      printf("%u \n\r", data);
     
   }

}


Slave:
Code:

#include <prova slave.h>
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8)
#include <18F2550.h>
#device adc=10

#FUSES NOWDT                    //No Watch Dog Timer
#FUSES WDT128                   //Watch Dog Timer uses 1:128 Postscale
#FUSES CPUDIV4                  //System Clock by 4
#FUSES INTRC_IO                 //Internal RC Osc, no CLKOUT
#FUSES NOBROWNOUT               //No brownout reset
#FUSES NOMCLR                   //Master Clear pin used for I/O
#FUSES NOLVP                    //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOXINST                  //Extended set extension and Indexed Addressing mode disabled (Legacy mode)

#use delay(int=8000000)

#use i2c(Slave,sda=PIN_B0,scl=PIN_B1,address=0x14)

int V;
float temp;
#define ris 20.48f

#int_SSP
void  SSP_isr(void)
{
int8 incoming, state;

state = i2c_isr_state();
   
if(state <= 0x80)     // Master is sending data
  {
   incoming = i2c_read(); 
  }

if(state == 0x80)   // Master is requesting data from slave
  {
   i2c_write(V);
  }

}



void main()
{
   setup_adc(ADC_CLOCK_INTERNAL);
   setup_adc_ports(AN0);
   setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);      //32.7 ms overflow

   setup_timer_3(T3_DISABLED | T3_DIV_BY_1);

   enable_interrupts(INT_SSP);
   enable_interrupts(GLOBAL);
   setup_oscillator(OSC_8MHZ|OSC_INTRC|OSC_31250|OSC_PLL_OFF);
   set_adc_channel(0);

   while(TRUE)
   {
      temp=read_adc();
      V=(int8)(temp/ris);
      printf("%u \n\r", V);
   }

}
temtronic



Joined: 01 Jul 2010
Posts: 9174
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Wed Sep 12, 2012 5:25 am     Reply with quote

hmm...
without trying it and quickly scanning your code..

1) you need ( must ) add 'errors' to the use rs232(...) options. This will keep the hardware UART from 'locking' up, 'stalling', 'freezing'...

2) never enable an interrupt unless you have an ISR for it! Sooner or later, it'll get triggered and the PIC will 'freeze'.

3) it's good programming to specify the I2C speed in both programs, to tell the compiler (and YOU) what speed is desired. Might not matter here but it's another 'going to get you ' item.

4) #define ris 20.48f ...hmm, don't really need the 'f' on the end, might cause a problem?

hth
jay
Ttelmah



Joined: 11 Mar 2010
Posts: 19368

View user's profile Send private message

PostPosted: Wed Sep 12, 2012 8:19 am     Reply with quote

I'd say temtronic's #2, is what is killing the code. You never want INT_SSP on a master device (unless you are implementing a circular transmit buffer), and this interrupt will trigger after every SSP transaction, resetting, or hanging the chip....
The same applies to the other interrupts.

I disagree with him about putting a speed in the slave. This can actually result in invalid numbers being put into the registers on some chips. Only the master want/needs a speed value.

I suspect if you disable the interrupts in the master things will suddenly improve a lot (and ERRORS should _always_ be used with the hardware UART).

Best Wishes
Maze



Joined: 12 Sep 2012
Posts: 4

View user's profile Send private message

PostPosted: Thu Sep 13, 2012 1:56 am     Reply with quote

Thanks for your answers

I think I found the errors, or so it seems. I added all the features you said in your posts but the things that made this work was changing the conditions in the slave with the address 0x80, instead of:

Code:
#int_SSP
void  SSP_isr(void)
{
int8 incoming, state;

state = i2c_isr_state();
   
if(state <= 0x80)     // Master is sending data
  {
   incoming = i2c_read(); 
  }

if(state == 0x80)   // Master is requesting data from slave
  {
   i2c_write(V);
  }

}


I used:

Code:
#int_SSP
void  SSP_isr(void)
{
int8 incoming, state;

state = i2c_isr_state();
   
if(state < 0x80)     // Master is sending data
  {
   incoming = i2c_read(); 
  }

if(state == 0x80)   // Master is requesting data from slave
  {
   i2c_write(V);
  }

}


without the = in the first "if" it works how it should, even if the "built in function" of CCS said that conditions
Ttelmah



Joined: 11 Mar 2010
Posts: 19368

View user's profile Send private message

PostPosted: Thu Sep 13, 2012 3:07 am     Reply with quote

On a lot of chips, the I2C fails, _unless_ you perform the read as well as the write on state 80. Some others allow this to be skipped. Yours is the first one I've heard of, that is requiring it to be skipped!....

Your code is 'unusual', in going straight to the read routine. In general the standard I2C transaction is:

Start
send device write address
send slave register number

Then either:
send bytes to write to registers

Or:
send restart
send device read address
read bytes from slave

Then
stop

So there is normally at least one write before the read, to send the register number required. Suggests that failing to do this, may be changing the behaviour of the slave!.

Best Wishes
Maze



Joined: 12 Sep 2012
Posts: 4

View user's profile Send private message

PostPosted: Thu Sep 13, 2012 4:22 am     Reply with quote

There's another problem, I have modified the code adding timer0 because I had to put in output a waveform and when the master decides the waveform to send in output after some seconds the I2C stop working (even the SDA and SCL pins stay always low). Here is the code:

master:
Code:
#include <i2c_master.h>
#include <18F2550.h>
#device adc=10

#FUSES NOWDT                      //Watch Dog Timer
#FUSES WDT64                    //Watch Dog Timer uses 1:64 Postscale
#FUSES CPUDIV4                  //System Clock by 4
#FUSES INTRC_IO                 //Internal RC Osc, no CLKOUT
#FUSES NOBROWNOUT               //No brownout reset
#FUSES NOMCLR                   //Master Clear pin used for I/O
#FUSES NOLVP                    //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOXINST                  //Extended set extension and Indexed Addressing mode disabled (Legacy mode)

#use delay(int=8000000)

#use i2c(Master,Fast,sda=PIN_B0,scl=PIN_B1)
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8,stream=PORT1,errors)
#define SLAVE1_WRT_ADDR   0x14
#define SLAVE1_READ_ADDR  0x15

int i, y, var, data, a, b, c;

#int_RTCC
void  RTCC_isr(void)
{
output_toggle(PIN_B7);
set_timer0(45609);
}


void main()
{
   setup_adc_ports(AN0);
   setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);      //32.7 ms overflow

   setup_timer_3(T3_DISABLED | T3_DIV_BY_1);

   enable_interrupts(INT_RTCC);
   enable_interrupts(GLOBAL);
   setup_oscillator(OSC_8MHZ|OSC_INTRC|OSC_31250|OSC_PLL_OFF);
   set_timer0(45536);
   delay_ms(10);

   while(TRUE)
   {
      i2c_start();
      i2c_write(SLAVE1_WRT_ADDR);
      i2c_write(1);
      i2c_start();
      i2c_write(SLAVE1_READ_ADDR);
      data = i2c_read(0);
      i2c_stop();        //prova:
      printf("%u \n\r", data);
      i2c_start();
      i2c_write(SLAVE1_WRT_ADDR);
      i2c_write(2);
      i2c_write(2);
      i2c_stop();
      delay_ms(100);
      i2c_start();
      i2c_write(SLAVE1_WRT_ADDR);
      i2c_write(2);
      i2c_write(3);
      i2c_stop();
      delay_ms(100);
      i2c_start();
      i2c_write(SLAVE1_WRT_ADDR);
      i2c_write(2);
      i2c_write(1);
      i2c_stop();
      delay_ms(100);
}
}


Slave:
Code:
#include <i2c.h>
#define ris 204
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8,stream=PORT1,errors)

#include <18F2550.h>
#device adc=10

#FUSES NOWDT                    //No Watch Dog Timer
#FUSES WDT128                   //Watch Dog Timer uses 1:128 Postscale
#FUSES CPUDIV4                  //System Clock by 4
#FUSES INTRC_IO                 //Internal RC Osc, no CLKOUT
#FUSES NOBROWNOUT               //No brownout reset
#FUSES NOMCLR                   //Master Clear pin used for I/O
#FUSES NOLVP                    //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOXINST                  //Extended set extension and Indexed Addressing mode disabled (Legacy mode)

#use delay(int=8000000)

#use i2c(SLAVE, SDA=PIN_B0, SCL=PIN_B1, address=0x14, FORCE_HW)

int16 x, y, x1=64420, y1=48198, x2=62661, y2=51596, x3=59494, y3=58054;  //+62
int number, V, function, ok=0;
float temp;

#int_RTCC
void  RTCC_isr(void)
{
if(ok==0){
   output_low(PIN_A1);
   set_timer0(x);
   ok=1;
}
else if(ok==1){
   output_high(PIN_A1);
   set_timer0(y);
   ok=2;
}
   else{
      output_low(PIN_A1);
      set_timer0(x);
      ok=0;
   }
}

#int_EXT2
void  EXT2_isr(void)
{
disable_interrupts(INT_RTCC);
if(function==2){
if(number==2){
   x=x2;
   y=y2;
}
else if(number==3){
   x=x3;
   y=y3;
}
else{
   x=x1;
   y=y1;
}
}
output_low(PIN_A1);
set_timer0(x);
ok=1;
enable_interrupts(INT_RTCC);
}


#int_SSP
void  SSP_isr(void)
{
BYTE state, incoming;

state=i2c_isr_state();

if(state < 0x80)                     //Master is sending data
   {
      incoming = i2c_read();
      if(state == 1)                     //First received byte is address
         function = incoming;
      if(state == 2)                     //Second received byte is data
         number = incoming;
   }
   if(state >= 0x80)                     //Master is requesting data
   {
      if(function==1)
         i2c_write(V); //V=tensione batteria
   }

}



void main()
{
   setup_adc(ADC_CLOCK_INTERNAL);
   setup_adc_ports(AN0);
   setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);      //32.7 ms overflow

   setup_timer_3(T3_DISABLED | T3_DIV_BY_1);

   disable_interrupts(INT_RTCC);
   enable_interrupts(INT_EXT2);
   enable_interrupts(INT_SSP);
   enable_interrupts(GLOBAL);
   setup_oscillator(OSC_8MHZ|OSC_INTRC|OSC_31250|OSC_PLL_OFF);
   x=x1;
   y=y1;
   set_adc_channel(0);
   output_low(PIN_A1);
   set_timer0(x-62);
   
   while(TRUE)
   {
     temp=read_adc();
     V=(int8)(temp/ris);
     delay_ms(100);
     printf("%u \n\r", V);
   }

}



If I comment the code inside INT_RTCC the i2c keep working. Is it possible that the interrupt of the timer force the i2c to stop?
jeremiah



Joined: 20 Jul 2010
Posts: 1328

View user's profile Send private message

PostPosted: Thu Sep 13, 2012 6:52 am     Reply with quote

2 comments:
1. You are not handling i2c isr state 0x80 fully, which you should be. Read the manual description for i2c_isr_state() for requirements.

2. You are not always writing when state is >= 0x80, which you should be. Even if you write another value instead of the one for the if, you need to write something.

The hardware expects certain things to happen. Not doing them can cause it to lock up.
Maze



Joined: 12 Sep 2012
Posts: 4

View user's profile Send private message

PostPosted: Thu Sep 13, 2012 8:36 am     Reply with quote

I modified the code with this things but keep not working

Code:
#int_SSP
void  SSP_isr(void)
{
BYTE state, incoming;

state=i2c_isr_state();

if(state <= 0x80)                     //Master is sending data
   {
      incoming = i2c_read();
      if(state == 1)                     //First received byte is address
         function = incoming;
      if(state == 2)                     //Second received byte is data
         number = incoming;
   }
   if(state >= 0x80)                     //Master is requesting data
   {
      if(function==1)
        i2c_write(V); //V=tensione batteria
      else i2c_write(1);
   }

}
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
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