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

whats so wrong with my i2c communication code

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



Joined: 16 Jul 2009
Posts: 4

View user's profile Send private message

whats so wrong with my i2c communication code
PostPosted: Thu Jul 23, 2009 4:18 am     Reply with quote

Code:
#include <16F876.h>
#device ADC=8
#fuses XT,NOWDT,NOPROTECT,NOLVP, PUT , BROWNOUT
#use delay(clock=4000000)        //4 Mhz osilatör hızı

#use i2c(Master, sda=PIN_C4, scl=PIN_C3, FORCE_HW,RESTART_WDT)

#byte portb = TRUE        //portb tanımlaması 
#byte portc = TRUE
#byte porta = TRUE

#define SLAVE1_WRT_ADDR   0x1A
#define SLAVE1_READ_ADDR  0x1B



                 
void main()
{
   
   int key;

   set_tris_b (0xF8);// B portunun giris cıkıs pinlerinin ayarlanması
   set_tris_c(0x3D);// C portunun giris cıkıs pinlerinin ayarlanması
   set_tris_a(0x17);
   
   delay_ms(10);


   WHILE (true)
   {

      key = 0x16


         i2c_start();
         i2c_write(SLAVE1_WRT_ADDR);
         i2c_write(key);
         i2c_stop();
         delay_ms(5);

         delay_ms(2);

      }



and for slave



Code:

#include <18F452.h>

#device ADC=8 

#fuses XT,NOWDT,PUT,BROWNOUT,NOLVP, NOPROTECT
#use delay(clock=4000000)       
#use i2c(SLAVE, SDA=PIN_C4, SCL=PIN_C3, address=0x1A, FORCE_HW,RESTART_WDT)
#INT_SSP
void ssp_interrupt()
{
   int8  state, adc_result, ad;

   disable_interrupts(INT_SSP);
   
   state = i2c_isr_state();
   if(state < 0x80)     // Master is sending data
   {
      while(!i2c_poll());
      key = i2c_read();
   }
   if(state == 0x80)   // Master is requesting data from slave
   {

      i2c_write(adc_result);
   }   
   clear_interrupt(INT_SSP);
   delay_ms(100);
   enable_interrupts(INT_SSP);
}



it works fine with proteus but when with real hardware it send 0x01 - 0x0A but after then it stucks
ckielstra



Joined: 18 Mar 2004
Posts: 3680
Location: The Netherlands

View user's profile Send private message

PostPosted: Thu Jul 23, 2009 4:40 am     Reply with quote

NEVER enable the global interrupt flag inside an interrupt handler!!!
If you do this and another interrupt is waiting to be handled the hardware will immediately execute the interrupt dispatcher again. You will get nested interrupts, a feature not supported by the hardware and software.
When an interrupt becomes active the hardware will disable the global interrupt and on exiting the interrupt handler the hardware will enable the flag again. There is no need for you to do this in the interrupt handler. Disabling the interrupt (again) is only extra overhead, and enabling it will create havoc as explained.

Code:
clear_interrupt(INT_SSP);
On exiting the interrupt handler the CCS compiler adds code for clearing the interrupt. This line can be left out.

Code:
#byte portb = TRUE        //portb tanımlaması
#byte portc = TRUE
#byte porta = TRUE
The #byte command expects a memory address, not TRUE or FALSE. Use of this command is only recommended if you want to directly manipulate port registers. Much easier is use the CCS commands for input/output output_low(), output_high(), etc.

Code:
   set_tris_b (0xF8);// B portunun giris cıkıs pinlerinin ayarlanması
   set_tris_c(0x3D);// C portunun giris cıkıs pinlerinin ayarlanması
   set_tris_a(0x17);
The CCS compiler will automatically set the TRIS registers for you when you use the inbuilt I/O functions. If you want to manipulate the TRIS registers yourself you have to specify '#use fast_io'.

adc_result is not initialised, so random data may be expected.

Other errors might be present.
gurhalil



Joined: 16 Jul 2009
Posts: 4

View user's profile Send private message

PostPosted: Thu Jul 23, 2009 5:12 am     Reply with quote

Quote:
NEVER enable the global interrupt flag inside an interrupt handler!!!
If you do this and another interrupt is waiting to be handled the hardware will immediately execute the interrupt dispatcher again. You will get nested interrupts, a feature not supported by the hardware and software.
When an interrupt becomes active the hardware will disable the global interrupt and on exiting the interrupt handler the hardware will enable the flag again. There is no need for you to do this in the interrupt handler. Disabling the interrupt (again) is only extra overhead, and enabling it will create havoc as explained.

Thanks for that I have tried without disabling the interrupt too.

The real problem is it transmits some values. The master will send the key values ranging 0x01 to 0x19, but it transmits 0x01 to 0x0A but does not transmit other values. I thinks it sticks at one of the i2c_read() functions. The master is wating to send data and freezes there.
ckielstra



Joined: 18 Mar 2004
Posts: 3680
Location: The Netherlands

View user's profile Send private message

PostPosted: Thu Jul 23, 2009 5:36 am     Reply with quote

In the code as posted the master will only transmit 0x16 and the slave will transmit random values. This tells me the code as posted is not the same code you are testing with. I'm not going to waste time looking into this as the problem might be in some part you didn't post.
gurhalil



Joined: 16 Jul 2009
Posts: 4

View user's profile Send private message

PostPosted: Thu Jul 23, 2009 5:48 am     Reply with quote

Well, the rest of the code is irrelevant. Just the idea is that master must transmit the key value that ranges between specific values. It works fine with the Proteus simulator and again works fine with values up to 0x0A. But when the key value is greater than that, the master is freezing and I think it freezes at the i2c_write() waiting for a respond. Is it because of the ack?
ckielstra



Joined: 18 Mar 2004
Posts: 3680
Location: The Netherlands

View user's profile Send private message

PostPosted: Thu Jul 23, 2009 3:19 pm     Reply with quote

You think the rest of the code is irrelevant. I don't. Even in this short program I discovered one major error.

Another problem in your code is the delay_ms(100) inside the slave interrupt routine. _Always_ keep interrupt routines as quick as possible or you will miss incoming data.

The code working in Proteus proves little. See the above mentioned problems not detected in the simulator.

If you want my help you have to play by my rules and post a short but complete program demonstrating your problem.
bkamen



Joined: 07 Jan 2004
Posts: 1611
Location: Central Illinois, USA

View user's profile Send private message

PostPosted: Thu Jul 23, 2009 4:05 pm     Reply with quote

Also,

Inside an interrupt, you don't need to disable, clear and enable the interrupt. CCS's compiler takes care of all this stuff for you.

Also, keep in mind you don't NEED to poll the I2C register. This isn't a software I2C... As I understand it, an interrupt is generated when the byte is received. You just need to go fetch it. (someone else can correct me if I'm wrong)

Only enable/disable/clear OUTSIDE your ISR routine.

Don't use delay_ms(! -- as mentioned)

-Ben

p.s. don't forget the ; after key=0x16 in your code.
p.p.s. Read the datasheet for the part carefully. This will help guide your coding.
_________________
Dazed and confused? I don't think so. Just "plain lost" will do. :D
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