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

Strange thing with i2c

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



Joined: 07 Mar 2008
Posts: 28

View user's profile Send private message

Strange thing with i2c
PostPosted: Wed Apr 30, 2008 4:14 am     Reply with quote

I have encountered this strange thing with the i2c_isr_state() This is my source:
Code:

#include <18F2520.h>
#device adc=8

#FUSES NOWDT                    //No Watch Dog Timer
#FUSES WDT128                   //Watch Dog Timer uses 1:128 Postscale
#FUSES H4                       //High speed with 4xPLL enabled
#FUSES NOPROTECT                //Code not protected from reading
#FUSES NOBROWNOUT               //No brownout reset
#FUSES BORV20                   //Brownout reset at 2.0V
#FUSES PUT                      //Power Up Timer
#FUSES NOCPD                    //No EE protection
#FUSES STVREN                   //Stack full/underflow will cause reset
#FUSES NODEBUG                  //No Debug mode for ICD
#FUSES NOLVP                    //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOWRT                    //Program memory not write protected
#FUSES NOWRTD                   //Data EEPROM not write protected
#FUSES IESO                     //Internal External Switch Over mode enabled
#FUSES FCMEN                    //Fail-safe clock monitor enabled
#FUSES NOPBADEN                 //PORTB pins are configured as digital I/O on RESET
#FUSES NOWRTC                   //configuration not registers write protected
#FUSES NOWRTB                   //Boot block not write protected
#FUSES NOEBTR                   //Memory not protected from table reads
#FUSES NOEBTRB                  //Boot block not protected from table reads
#FUSES NOCPB                    //No Boot Block code protection
#FUSES LPT1OSC                  //Timer1 configured for low-power operation
#FUSES MCLR                     //Master Clear pin enabled
#FUSES NOXINST                  //Extended set extension and Indexed Addressing mode disabled (Legacy mode)

#use delay(clock=40000000)
#define I2C_SCL   PIN_C3
#define I2C_SDA   PIN_C4
#use i2c(Slave,sda=PIN_C4,scl=PIN_C3,force_hw,address=0x10)

void Init()
{
   setup_adc_ports(NO_ANALOGS|VSS_VDD);
   setup_adc(ADC_OFF|ADC_TAD_MUL_0);
   setup_wdt(WDT_OFF);
   setup_timer_0(RTCC_INTERNAL);
   setup_timer_1(T1_DISABLED);
   setup_timer_2(T2_DIV_BY_16,124,1);
   setup_timer_3(T3_DISABLED|T3_DIV_BY_1);
   setup_ccp1(CCP_PWM);
   setup_ccp2(CCP_PWM);
   set_pwm1_duty(0);
   set_pwm2_duty(0);
   setup_comparator(NC_NC_NC_NC);
   setup_vref(FALSE);
   //enable_interrupts(INT_EXT);
   //enable_interrupts(INT_EXT1);
   enable_interrupts(INT_SSP);
   enable_interrupts(GLOBAL);
}

#define HR1 PIN_A0
#define HL1 PIN_A1
#define LR1 PIN_A2
#define LL1 PIN_A3

#define HR2 PIN_B2
#define HL2 PIN_B3
#define LR2 PIN_B4
#define LL2 PIN_B5

#define BCKWRD 0
#define STOP   1
#define FRWRD  2
#define LEFT   3
#define RIGHT  4

struct Motor
{
   int16 line;
   int16 turn;
   int16 error;     
   int16 pwm;
   int status;
   unsigned int32 pos;
};

void Init_Motors(void);
void Motor_Control(int direct, int16 speed, int m);

int value_X = 140, value_Y = 140;
struct Motor M1;
struct Motor M2;

#int_EXT
void  EXT1_isr(void)
{
   M1.pos++;
}

#int_EXT1
void  EXT2_isr(void)
{
   M2.pos++;
}

#int_SSP
void  SSP_isr(void)
{
   int incoming, state;
   state = i2c_isr_state();
   if(state < 0x80)                     
   {
      incoming = i2c_read();
      if(state == 0)                     
         value_X = incoming;
      if(state == 1)                     
         value_Y = incoming;   
   }
}

void Init_Motors(void)
{
   output_bit(HR1, 0);
   output_bit(HL1, 0);
   output_bit(LL1, 1);
   output_bit(LR1, 1);
   M1.line = 0;
   M1.turn = 0;
   M1.error = 0;
   M1.pwm = 0;
   M1.status = STOP;
   M1.pos = 0;
   output_bit(HR2, 0);
   output_bit(HL2, 0);
   output_bit(LL2, 1);
   output_bit(LR2, 1);
   M2.line = 0;
   M2.turn = 0;
   M2.error = 0;
   M2.pwm = 0;
   M2.status = STOP;
   M2.pos = 0;
}

void Motor_Control(int direct, int16 speed, int m)
{
   switch(m)
   {
      case 1:
         M1.line = speed;
         M1.pwm = M1.line + M1.turn + M1.error;
         set_pwm1_duty(M1.pwm);
         switch(direct)
         {
            case BCKWRD:
               output_bit(HR1, 0);
               output_bit(LL1, 0);
               output_bit(HL1, 1);
               output_bit(LR1, 1);
               M1.status = BCKWRD;
               break;
            case FRWRD:
               output_bit(HL1, 0);
               output_bit(LR1, 0);
               output_bit(HR1, 1);
               output_bit(LL1, 1);
               M1.status = FRWRD;
               break;
            case STOP:   
               output_bit(HR1, 0);
               output_bit(HL1, 0);
               output_bit(LL1, 1);
               output_bit(LR1, 1);
               M1.status = STOP;
               break;
         }
           break; 
      case 2:
         M2.line = speed;
         M2.pwm = M2.line + M2.turn + M2.error;
         set_pwm2_duty(M2.pwm);
         switch(direct)
         {
            case BCKWRD:
               output_bit(HR2, 0);
               output_bit(LL2, 0);
               output_bit(HL2, 1);
               output_bit(LR2, 1);
               M2.status = BCKWRD;
               break;
            case FRWRD:
               output_bit(HL2, 0);
               output_bit(LR2, 0);
               output_bit(HR2, 1);
               output_bit(LL2, 1);
               M2.status = FRWRD;
               break;
            case STOP:   
               output_bit(HR2, 0);
               output_bit(HL2, 0);
               output_bit(LL2, 1);
               output_bit(LR2, 1);
               M2.status = STOP;
               break;
         }   
         break;
   }
}
               
         
void main()
{
   int i = 0;
   Init();
   Init_Motors();
   Motor_Control(FRWRD, 128, 1);
}


When it is compiled and loaded everything works fine, but it is theoreticaly wrong. When i2c_isr_state() is 0 this means that the address is received and matched. But if I write
Code:

#int_SSP
void  SSP_isr(void)
{
   int incoming, state;
   state = i2c_isr_state();
   if(state < 0x80)                     
   {
      incoming = i2c_read();
      if(state == 1)                     
         value_X = incoming;
      if(state == 2)                     
         value_Y = incoming;   
   }
}
this is how it is supposed to be, I get the value for value_Y in value_X and the value in value_Y is always 16 which is 0x10, which is the addres of the slave. I havent faced this problem before... I use PIC182520 for the first time, but I don't think this makes any difference. Any ideas what is the reason for this strange problem ?
Matro
Guest







PostPosted: Wed Apr 30, 2008 4:21 am     Reply with quote

Could you try with the following line
Code:

#opt 0

added at the beginning of your code?

And could you post a part of .lst corresponding to #INT_SSP function?

Matro
sv_shady



Joined: 07 Mar 2008
Posts: 28

View user's profile Send private message

PostPosted: Wed Apr 30, 2008 5:37 am     Reply with quote

Here is the .lst file with #opt 0:
Code:

#int_SSP
.................... void  SSP_isr(void) 
.................... {
....................    int incoming, state;
....................    state = i2c_isr_state();
00E2:  BTFSC  FC7.5
00E4:  GOTO   00EE
00E8:  CLRF   34
00EA:  BTFSC  FC9.0
00EC:  BSF    34.7
00EE:  MOVF   34,W
00F0:  INCF   34,F
00F2:  MOVWF  3D
....................    if(state < 0x80)
00F4:  MOVF   3D,W
00F6:  SUBLW  7F
00F8:  BTFSS  FD8.0
00FA:  GOTO   011E
....................    {
....................       incoming = i2c_read();
00FE:  BTFSS  FC7.0
0100:  GOTO   00FE
0104:  MOVFF  FC9,3C
....................       if(state == 0)
0108:  MOVF   3D,F
010A:  BTFSS  FD8.2
010C:  GOTO   0114
....................          value_X = incoming;
0110:  MOVFF  3C,18
....................       if(state == 1)                     
0114:  DECFSZ 3D,W
0116:  GOTO   011E
....................          value_Y = incoming;   
011A:  MOVFF  3C,19
....................    }
.................... }
}


And this is without the #opt 0 statement:
Code:
#int_SSP
.................... void  SSP_isr(void) 
.................... {
....................    int incoming, state;
....................    state = i2c_isr_state();
00E2:  BTFSC  FC7.5
00E4:  BRA    00EC
00E6:  CLRF   34
00E8:  BTFSC  FC9.0
00EA:  BSF    34.7
00EC:  MOVF   34,W
00EE:  INCF   34,F
00F0:  MOVWF  3D
....................    if(state < 0x80)
00F2:  MOVF   3D,W
00F4:  SUBLW  7F
00F6:  BNC   0110
....................    {
....................       incoming = i2c_read();
00F8:  BTFSS  FC7.0
00FA:  BRA    00F8
00FC:  MOVFF  FC9,3C
....................       if(state == 0)
0100:  MOVF   3D,F
0102:  BNZ   0108
....................          value_X = incoming;
0104:  MOVFF  3C,18
....................       if(state == 1)                     
0108:  DECFSZ 3D,W
010A:  BRA    0110
....................          value_Y = incoming;   
010C:  MOVFF  3C,19
....................    }
.................... }

There is now effect on matter wether there is #opt 0 or there isn't.
Ttelmah
Guest







PostPosted: Wed Apr 30, 2008 7:48 am     Reply with quote

What are you actually sending?.

Best Wishes
sv_shady



Joined: 07 Mar 2008
Posts: 28

View user's profile Send private message

PostPosted: Wed Apr 30, 2008 10:45 am     Reply with quote

Here is the source of the sender:
Code:

#include <16F877A.h>
#device adc=8

#FUSES NOWDT                    //No Watch Dog Timer
#FUSES HS                       //High speed Osc (> 4mhz)
#FUSES PUT                      //Power Up Timer
#FUSES NOPROTECT                //Code not protected from reading
#FUSES NODEBUG                  //No Debug mode for ICD
#FUSES NOBROWNOUT               //No brownout reset
#FUSES NOLVP                    //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOCPD                    //No EE protection
#FUSES NOWRT                    //Program memory not write protected

#use delay(clock=10000000)

#use i2c(Master,sda=PIN_C4,scl=PIN_C3,force_hw)
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8)

void INIT(void)
{
   set_tris_c(0x80);
   setup_adc(ADC_CLOCK_INTERNAL);
   setup_adc_ports(NO_ANALOGS);
   setup_psp(PSP_DISABLED);
   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);
}

#define START_BYTE 0x41

int c;
int value_X, value_Y;
void main()
{
   INIT();
   for(;;)
   {
      if(kbhit())
      {
         c = getc();
         if(c == START_BYTE)
         {
              value_X = getc();
            value_Y = getc();
            i2c_start();
            i2c_write(0x10);
            i2c_write(value_X);
            i2c_write(value_Y);
            i2c_stop();
         }
      }
   }
}

Firstly I've used PIC18F4431 and there were no problems, than I've changed to PIC18F2520 and this complication appeared.
Ttelmah
Guest







PostPosted: Wed Apr 30, 2008 2:26 pm     Reply with quote

Try with the receive routine like this:
Code:

#int_SSP
void  SSP_isr(void)
{
   int incoming, state;
   state = i2c_isr_state();
   if(state < 0x80)                     
   {
      if(state == 1)                     
         value_X = I2C_READ();
      else if(state == 2)                     
         value_Y = I2C_READ(0);
      else incoming=I2C_READ(); 
   }
}


Best Wishes
sv_shady



Joined: 07 Mar 2008
Posts: 28

View user's profile Send private message

PostPosted: Fri May 23, 2008 4:17 pm     Reply with quote

Excuse me for the delay, but I had some problems...this routine
Code:
#int_SSP
void  SSP_isr(void)
{
   int incoming, state;
   state = i2c_isr_state();
   if(state < 0x80)                     
   {
      if(state == 1)                     
         value_X = I2C_READ();
      else if(state == 2)                     
         value_Y = I2C_READ(0);
      else incoming=I2C_READ();
   }
}
does not work :( Any other ideas ? I have used I2C successfully with 3 PIC16F887A...this is very frustrating :(
sv_shady



Joined: 07 Mar 2008
Posts: 28

View user's profile Send private message

PostPosted: Sat May 24, 2008 1:34 am     Reply with quote

I decided to test the problem more extensively. I have changed the slave address to 0xA0 and put all the received bytes into an array and this is the result:
Code:
(137,130,160,137,129,160,137,130,160,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)

The first thing that I noticed is that the first byte is not the slave address, but the first data byte... Next the last received byte is not the last data byte, but the slave address... The problem is not in the sender either, here it is its source:
Code:

#include <16F88.h>
#device adc=8

#FUSES NOWDT                    //No Watch Dog Timer
#FUSES HS                       //High speed Osc (> 4mhz)
#FUSES PUT                      //Power Up Timer
#FUSES MCLR                     //Master Clear pin enabled
#FUSES BROWNOUT                 //Reset when brownout detected
#FUSES NOLVP                    //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOCPD                    //No EE protection
#FUSES NOWRT                    //Program memory not write protected
#FUSES NODEBUG                  //No Debug mode for ICD
#FUSES NOPROTECT                //Code not protected from reading
#FUSES FCMEN                    //Fail-safe clock monitor enabled
#FUSES NOIESO                   //Internal External Switch Over mode disabled

#use delay(clock=20000000)

#use rs232(baud=9600,parity=N,xmit=PIN_B5,rcv=PIN_B2,bits=8)
#use i2c(Master,sda=PIN_B1,scl=PIN_B4, Fast, force_sw)

#define I2C_SDA   PIN_B1
#define I2C_SCL   PIN_B4
 

#define START_BYTE 0x41
#define LED PIN_B0

int c;
int value_X, value_Y;

void main()
{

   setup_adc_ports(NO_ANALOGS|VSS_VDD);
   setup_adc(ADC_OFF);
   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);
   output_bit(LED, 0);
   for(;;)
   {
      if(kbhit())
      {
         c = getc();
         if(c == START_BYTE)
         {
              value_X = getc();
            value_Y = getc();
            output_bit(LED, 1);
            i2c_start();
            i2c_write(0xA0);
            i2c_write(value_X);
            i2c_write(value_Y);
            i2c_stop();
            output_bit(LED, 0);
         }
      }
   }
}


This might be some kind of bug, but I am not sure, most of the times the bug is in the writer of the source :P
sv_shady



Joined: 07 Mar 2008
Posts: 28

View user's profile Send private message

PostPosted: Sat May 24, 2008 1:37 am     Reply with quote

I decided to test the problem more extensively. I have changed the slave address to 0xA0 and put all the received bytes into an array and this is the result:
Code:
(137,130,160,137,129,160,137,130,160,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)

The first thing that I noticed is that the first byte is not the slave address, but the first data byte... Next the last received byte is not the last data byte, but the slave address... The problem is not in the sender either, here it is its source:
Code:

#include <16F88.h>
#device adc=8

#FUSES NOWDT                    //No Watch Dog Timer
#FUSES HS                       //High speed Osc (> 4mhz)
#FUSES PUT                      //Power Up Timer
#FUSES MCLR                     //Master Clear pin enabled
#FUSES BROWNOUT                 //Reset when brownout detected
#FUSES NOLVP                    //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOCPD                    //No EE protection
#FUSES NOWRT                    //Program memory not write protected
#FUSES NODEBUG                  //No Debug mode for ICD
#FUSES NOPROTECT                //Code not protected from reading
#FUSES FCMEN                    //Fail-safe clock monitor enabled
#FUSES NOIESO                   //Internal External Switch Over mode disabled

#use delay(clock=20000000)

#use rs232(baud=9600,parity=N,xmit=PIN_B5,rcv=PIN_B2,bits=8)
#use i2c(Master,sda=PIN_B1,scl=PIN_B4, Fast, force_sw)

#define I2C_SDA   PIN_B1
#define I2C_SCL   PIN_B4
 

#define START_BYTE 0x41
#define LED PIN_B0

int c;
int value_X, value_Y;

void main()
{

   setup_adc_ports(NO_ANALOGS|VSS_VDD);
   setup_adc(ADC_OFF);
   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);
   output_bit(LED, 0);
   for(;;)
   {
      if(kbhit())
      {
         c = getc();
         if(c == START_BYTE)
         {
              value_X = getc();
            value_Y = getc();
            output_bit(LED, 1);
            i2c_start();
            i2c_write(0xA0);
            i2c_write(value_X);
            i2c_write(value_Y);
            i2c_stop();
            output_bit(LED, 0);
         }
      }
   }
}


Another strange thing is that the controller does not perform any other task but the #INT_SSP routine.
This might be some kind of bug, but I am not sure, most of the times the bug is in the writer of the source :P
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Sat May 24, 2008 12:02 pm     Reply with quote

Quote:
#use i2c(Master,sda=PIN_B1,scl=PIN_B4, Fast, force_sw)

Don't run the master in Fast mode. Microchip doesn't guarantee that
the SSP hardware will work in fast mode.
sv_shady



Joined: 07 Mar 2008
Posts: 28

View user's profile Send private message

PostPosted: Sun May 25, 2008 7:57 am     Reply with quote

Just in case someone else encounters the same problem, or is just curios what's the soluten I have slightly changed the interrupt routine:
Code:
#int_SSP
void  SSP_isr(void)
{
   
   int incoming, state;
   output_bit(LED, 1);
   incoming = i2c_read();
   state = i2c_isr_state();
   if(state < 0x80)
   {
      if(state == 1)
         value_X = incoming;
      if(state == 2)                     
      {           
         value_Y = incoming;
         cmds = 1;
      }
   }
   output_bit(LED, 0);
}

First I read the incoming byte then get the i2c_isr_state() value. I don't know why it shoud be like this but everything now works perfectly even in Fast mode Smile I wonder if there is some explanation or it is just some kind of a bug ?
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