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

Serial port and I2C problems

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



Joined: 23 May 2007
Posts: 22

View user's profile Send private message

Serial port and I2C problems
PostPosted: Sun Aug 10, 2008 3:30 am     Reply with quote

I wrote a function GetI2C(), receiving data via I2C from another microcontroller,
by int_rda the MCU accept instruction from PC,then called this function, and then use int_tbe sent sent to the PC, function Key features as follows:
void GetI2C()
{
read_i2c data;
delay_ms(2);
bputc data;
}


this will bring error,the PC can't receive any char.


if the function doesn't read the I2C data, call the bputc to send data.

void GetI2C()
{
bputc data;
}

that is ok,I do not know whether the I2C read and serial port interrupt has conflict?How to amend it?

thanks.
Ttelmah
Guest







PostPosted: Sun Aug 10, 2008 4:20 am     Reply with quote

Are you using the I2C interrupt?.
If so, then the problem is almost certainly, that you are spending _too long_ in the handler for this. Look at the example I2C handler, and search here. The key with all interrupt handlers is 'get out fast', unless you understand the full implications of staying in the handler, and have written the code to deal with this.
If you haven't got 'errors' in your RS232 declaration, add it. Without this, the RS232 will not recover if it's internal buffering overflows. This may well get it working again, but will still leave you losing data, if you don't improe teh I2C handler.
There is nothing inherent preventing I2C, and serial being used together, _provided the code is properly written_.

Best Wishes
stefsun



Joined: 23 May 2007
Posts: 22

View user's profile Send private message

PostPosted: Sun Aug 10, 2008 4:56 am     Reply with quote

thanks for your replies;
In the code,I use as follings

#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, Parity=N, Bits=8, ERRORS)
#use i2c(Master, sda=PIN_C4, scl=PIN_C3,FORCE_HW)

I add 'errors' in RS232 declaration
but after MPLAB IDE compiling,It's Prompt is
"Warning 202 "F:\Microchip\20080805\20080805.C" Line 5(5,8): Variable never used: rs232_errors"

the I2C master code is

Code:

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

void Get873Data()
{
   i2c_start();
   i2c_write(0xa1);
   
   for(i=0;i<13;i++)
     PIC873[i] = i2c_read();
   PIC873[13] = i2c_read(0);
   
   i2c_stop();
   
   delay_ms(2);
   
   bputc(0x03);
   for(i=0;i<14;i++)
     bputc(PIC873[i]);
   bputc(0x95);
}


the slave code is

Code:

#use i2c(SLAVE, SDA=PIN_C4, SCL=PIN_C3, address=0xa0)


#INT_SSP
void ssp_interupt ()
{
   BYTE  state,dummy;

   state = i2c_isr_state();
   if(state >= 0x80)                     //Master is requesting data
   {
      i2c_write(buffer[state - 0x80]);
   }
   else
   {
      dummy=i2c_read();    //this line is to avoid locking the bus in case of a write
   }
}



Who can give some such references in this regard


Last edited by stefsun on Sun Aug 10, 2008 7:38 pm; edited 1 time in total
Ttelmah
Guest







PostPosted: Sun Aug 10, 2008 6:12 am     Reply with quote

RS232_errors, is just a warning.
When you add the 'errors' keyword, CCS adds code to automatically clear serial overrun errors. It also adds a variable 'rs232_errors', into which it puts any error bits that get set, so _you_ can check them if required. You don't need to do this unless you want to, but the 'unused' keyword, generates a warning.
Why has your 'master' code, got a 'slave' declaration.....
The master doesn't want an I2C_ISR handler....
In I2C, the _master_ generates the timings, and controls the transactions. The point about the ISR, is that the interrupt occurs when a transaction completes. In the slave this means that the master has sent something, or wants something, but in the master, the data has already _been_ sent, before the ISR occurs. Have an I2C handler in the master (except for a very carefully designed one used for sequential data transfers), is asking for trouble....

Best Wishes
Salenko



Joined: 08 Sep 2008
Posts: 84

View user's profile Send private message

PostPosted: Mon Aug 17, 2009 12:11 pm     Reply with quote

Ttelmah wrote:
Are you using the I2C interrupt?.
If so, then the problem is almost certainly, that you are spending _too long_ in the handler for this. Look at the example I2C handler, and search here. The key with all interrupt handlers is 'get out fast', unless you understand the full implications of staying in the handler, and have written the code to deal with this.
If you haven't got 'errors' in your RS232 declaration, add it. Without this, the RS232 will not recover if it's internal buffering overflows. This may well get it working again, but will still leave you losing data, if you don't improe teh I2C handler.
There is nothing inherent preventing I2C, and serial being used together, _provided the code is properly written_.

Best Wishes


Hi Mr Ttelmah and everyone,

I have almost the same problem. I'm using I²C bus between three PICs, it is working well. When I decided to send data (character typed on the keyboard) to one of the PIC's (a slave) from my PC, the PIC did not receive any character and the I²C bus is still working.


here is the routine I used to receive the character from the PC
Code:
#int_RDA
void RDA_isr ( ) 

{
ca=getchar();
printf("\n\r%c",ca);

switch (ca)
  {
  case 'e':  e=1; break;
  case 'd':  d=1; break;
  case 'h':  h=1; break;
  case 'a':  a=1; break;
  case 'l':  l=1; break;         
  case 'f':  f=1; break;
  case 'r':  r=1; break;             
 }
 
}




to communicate through I²C, I used the code of moacir_mendes http://www.ccsinfo.com/forum/viewtopic.php?t=36695 (from CCS forum Library)whose #INT_SSP() routine (Slave PIC) is as follows :

Code:

#INT_SSP NOCLEAR
void ssp_interupt ()
{
clear_interrupt(int_SSP);
                           
   state = i2c_isr_state();

   
  if(state < 0x80)           //master is sending data
    {                     
       if(state == 0)
       {     }
     
       if(state == 1)          //first received byte is address
         {                           
        address = i2c_read();     
         }
     
       if(state == 2)          //second received byte is data
        {           
        buffer[address] = i2c_read();
        }     
       
     }
   
  if(state == 0x80)   
    {             
      i2c_write (buffer[address]);  //send requested data
    }
   
}



you pointed out that spending _too long_ in the I²C handler cause loss of data coming from RS232, is this the case of my code ? If yes, can I "get_out_faster" ? Wink



here is my I²C and RS232 declarations

Code:

#include <16F877.h>

#FUSES NOWDT                    //No Watch Dog Timer
#FUSES HS                       //High Speed Clock (>4mHz)
#FUSES NOPUT                    //No 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

#use delay(clock = 20000000)
#use rs232 (baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,ERRORS,bits=8)

#use i2c(SLAVE,FAST,sda=PIN_C4,scl=PIN_C3,address=0xB0, force_hw)




compiler version : PCW 4.057
PIC used : 16F877



thanks in advance.
Ttelmah
Guest







PostPosted: Mon Aug 17, 2009 3:14 pm     Reply with quote

Seriously, your problem is not with the I2C.
If the RS232 was working, it'd create a potential problem by spending too long in the RS232 handler (since the hardware buffer is only two characters long, sending three characters in the interrupt, will cause timing problems), but I'd suggest you get your RS232 working first.
The fact that the I2C keeps working, suggests that at least the serial input line, is idling correctly 'high' at the PIC, but your behaviour is of something wrong in the hardware for the RS232, or the code enabling the interrupt for this.

Best Wishes
Salenko



Joined: 08 Sep 2008
Posts: 84

View user's profile Send private message

PostPosted: Wed Aug 19, 2009 5:17 pm     Reply with quote

Ttelmah wrote:
Seriously, your problem is not with the I2C.
If the RS232 was working, it'd create a potential problem by spending too long in the RS232 handler (since the hardware buffer is only two characters long, sending three characters in the interrupt, will cause timing problems), but I'd suggest you get your RS232 working first.
The fact that the I2C keeps working, suggests that at least the serial input line, is idling correctly 'high' at the PIC, but your behaviour is of something wrong in the hardware for the RS232, or the code enabling the interrupt for this.

Best Wishes


Thank you for your answer Mr Ttelmah,

I spent about one day trying to get my code working with I²C and RDA_int() routines together, finally I found that the RDA routine works (perfectly) only when I omit the I²C declaration (#use i2c()) and #INT_SSP routine. Otherwise only I²C works.


Here is a basic version of my code :

Declarations and interruptions routine
Code:

#include <16F877.h>

#FUSES NOWDT,HS,NOPUT,NOPROTECT,NODEBUG,NOBROWNOUT,,NOLVP,NOCPD                   

#use delay(clock = 20000000)

#use rs232 (baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,ERRORS,bits=8)

#use i2c(SLAVE,FAST,sda=PIN_C4,scl=PIN_C3,address=0xB0, force_hw)

#BIT SSPOV = 0x14.6        /*Indicates overflow - BIT 6 - SSPCON: SYNC SERIAL PORT CONTROL REGISTER (ADDRESS 14h)*/
#BIT BF = 0x94.0           /*Buffer Full - BIT 0 - SSPSTAT: SYNC SERIAL PORT STATUS REGISTER ADDRESS: 94h)*/


//========Variables=======

int1 e,d,h,a,l,f,r;    //bit
char ca;
BYTE state, address, buffer[10] ;

//============== INTERRUPTIONS ROUTINES============


#INT_SSP NOCLEAR
void ssp_interupt ()
{
clear_interrupt(int_SSP);                           
state = i2c_isr_state();
   
   if(state < 0x80)       //master is sending data
    {                     
       if(state == 0)
       {               
       }
     
       if(state == 1)              //first received byte is address
         {                         
        address = i2c_read();   
         }
     
       if(state == 2)              //second received byte is data
        {           
        buffer[address] = i2c_read();
        }           
     }
   
  if(state == 0x80)   //master is requesting data
    {                 
      i2c_write (buffer[address]);  //send requested data
    }
   
}



#int_RDA
void RDA_isr ( ) 
{

ca=getchar();
printf("\n\r%c",ca);

}



The main:
Code:

void main()
{
 
   //setup_spi(FALSE);
   enable_interrupts(INT_RDA);
   enable_interrupts(INT_SSP);
   enable_interrupts(GLOBAL);
   

while(true)
 {
      delay_ms(100);
     
      if (SSPOV || BF)
        {
         //output_high(pin_c2); 
         SSPOV = 0;
         BF = 0;         
        }

   if (buffer[1]==1)
      { 
      printf("\n\r 1");   
      buffer[1]=0;
      }
     
   if (buffer[1]==2)
      { 
      printf("\n\r 0");   
      buffer[1]=0; 
      }     

  }

}

Did I miss something ?
Ttelmah
Guest







PostPosted: Thu Aug 20, 2009 2:24 am     Reply with quote

Several problems leap out.
First your use of 'noclear', and clearing the interrupt as the first line in the code. The problem here is that for some events, you cannot clear the interrupt, till the hardware event has been serviced. In fact the act of reading the data, will clear the interrupt for you, for received data, but trying to clear the interrupt 'ahead of handling the actual event, is always a problem. In your code, you don't read the initial byte (state=0), so the interrupt will continuously retrigger.....
Then, you are not checking for, or handling possible error conditions in the interrupt code. WERR, and WCOL.
Then your code potentially gets into problems, if more than one byte is read or written. Though you don't obviously expect to do this, there should be handling of the possibilities.....
Also, you perform no check that 'address' is <10, potentially destroying the contents of other variables....
The I2C declaration for a 'slave', cannot have a clock speed associated with it.

Best Wishes
Salenko



Joined: 08 Sep 2008
Posts: 84

View user's profile Send private message

PostPosted: Thu Aug 20, 2009 3:42 pm     Reply with quote

thank you again Mr Ttelmah,

it seems that I have some work to do.


Quote:
The I2C declaration for a 'slave', cannot have a clock speed associated with it.


should I remove "FAST" then ?


thanks.
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