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

I2C fast problems
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
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Fri Aug 10, 2007 10:02 pm     Reply with quote

The problem is that the software i2c routines can't go that fast. The
actual SCL clock frequency is much less than the specified speed.

For example, I did a test just now with the following #use statement,
with a 16F877 running at 20 MHz. This will generate software i2c code.
Code:
#use i2c(Master, sda=PIN_C4, scl=PIN_C3, FAST=450000)

I measured 6.4 us between clock edges on SCL. That's about 156 KHz.
We know the slave has no problem with that low of a clock speed.

If you look at the code below and count cycles, it looks like the shortest
path through the main loop is 31 cycles, which is 6.2 us at 20 MHz, and
about 161 KHz. This is the CCS library code for a software i2c write.
Code:

0013:  MOVLW  08
0014:  MOVWF  78

0015:  NOP               
0016:  NOP           
0017:  BCF    07.3
0018:  BCF    21.3
0019:  MOVF   21,W
001A:  BSF    03.5
001B:  MOVWF  07
001C:  NOP
001D:  BCF    03.5
001E:  RLF    23,F
001F:  BCF    07.4
0020:  BTFSS  03.0
0021:  GOTO   028
0022:  BSF    21.4
0023:  MOVF   21,W
0024:  BSF    03.5
0025:  MOVWF  07
0026:  GOTO   02C
0027:  BCF    03.5
0028:  BCF    21.4
0029:  MOVF   21,W
002A:  BSF    03.5
002B:  MOVWF  07
002C:  NOP
002D:  BCF    03.5
002E:  BSF    21.3
002F:  MOVF   21,W
0030:  BSF    03.5
0031:  MOVWF  07
0032:  BCF    03.5
0033:  BTFSC  07.3
0034:  GOTO   037
0035:  BSF    03.5
0036:  GOTO   032
0037:  DECFSZ 78,F
0038:  GOTO   015


I looked at the problem for about 20-30 minutes on Friday morning.
Most of that time was spent setting up the logic analyzer and boards.
I modified the Ex_slave isr to set Pin B0 high at the start, and low at
the end of the isr. I think I was running the master at 100 KHz.
(I don't remember for sure). I noticed that sometimes the slave isr
took up to 82 us to complete. That's not including the 10 us of overhead
in the CCS interrupt dispatcher. So it's really more like 92 us.
There are two places in the isr where a delay could occur. These are
in the i2c_read() and i2c_write() routines. Each one of those has a
tight loop where they poll the BF flag in SSPSTAT.

At that point it required more time that I could commit on Friday. I can
do more on Sunday. It's an interesting problem to find out why there
are limits to the CCS i2c slave code with respect to the SCL clock
speed. If someone else has already researched this problem and
wants to answer, that's fine with me. But if not, I can look at it more
later in the weekend.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Tue Aug 14, 2007 11:51 am     Reply with quote

I looked at this problem some more.

If you increase the Master PIC's SCL clock frequency beyond about
250 KHz, then byte transactions will finish before the end of the Slave isr.
In the Slave PIC, an SSPIF interrupt occurs at the end of each byte that
is transmitted or received. CCS puts a line of code near the end of the
Slave isr which clears the SSPIF flag. So if a byte finishes before
the end of the isr, it will set the SSPIF flag, but then the flag will be
cleared at the end of the isr. The PIC won't see that next interrupt.

One fix for this is to clear the SSPIF flag at the start of the Slave isr
instead of the end. This can be done by adding the NOCLEAR directive
and by calling clear_interrupt() at the start of the Slave isr. Example:
Code:

#INT_SSP  NOCLEAR    // Disable automatic clearing of SSPIF
void ssp_interrupt(void)
{
BYTE incoming, state;

clear_interrupt(INT_SSP);  // Clear SSPIF flag at start of isr

With these changes, I was able to boost the SCL frequency to 350 KHz.
I couldn't go beyond that, because there's another problem with the
i2c_write() section of the isr code that I haven't yet analyzed.

To look at this problem, I used the following logic analyzer.
It's low cost and it has a very useful i2c interpreter.
http://www.pctestinstruments.com/
I also used Pins B0, B1, and B2 as markers for the entire slave isr,
the i2c_read(), and the i2c_write() operations inside the isr, respectively.
I set a pin high at the beginning and low at the end of each operation.
Then the logic analyzer will show the duration of the operation.
Example:
Code:

if(state < 0x80)      // Master is sending data
  {
   output_high(PIN_B1); // *** Start of i2c_read marker
   incoming = i2c_read();
   output_low(PIN_B1);  // *** End of i2c_read marker


The original poster seems to have lost interest in this, so I'm not going
to do any more on it in the short term.
Tim Bobbins
Guest







on the contrary!
PostPosted: Tue Aug 14, 2007 12:28 pm     Reply with quote

No nooo! I have anything but lost interest in this topic. I am loosing sleep over it as a matter of fact. I've been very busy the past few days, so i havent had time to continue my work, plus I didnt feel I had anything else constructive to contribute just yet.

I do not have the needed equipment to diagnose so I am very appreciative of PCM Programmer to take his time to look into this problem!

That is a wonderful find! I will try it tonight.

Was it the I2C hardware, or software method you tried?
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Tue Aug 14, 2007 12:30 pm     Reply with quote

Using i2c hardware mode for the Master. (Slave must always use H/W).

Also be aware that to make the code reliable, you may have to back off
the SCL frequency from the highest value that works in initial testing.
I didn't do any reliability tests.
Tim Bobbins
Guest







my results
PostPosted: Thu Aug 16, 2007 1:29 am     Reply with quote

Here are my results with FORCE_HW enabled with the test code as found below. The test master code sends a character continuously to the slave. The slave returns the same character back to the master. The master code counts the number of times per second a successful reception is made:

FAST=100000
~1300 bytes per second

FAST=250000
~2900Bps

FAST=300000
~3300Bps

FAST=320000
~3400Bps

with FORCE_HW removed (software mode) the best I get is 2300Bps

Any idea why I cannot attain higher speeds past 320,000 and 350,000 for PCM programmer?




**slave code is the same as found in EX_SLAVE.C with the I2C line changed to:
#use i2c(SLAVE, SDA=PIN_C4, SCL=PIN_C3, address=0xa0, FORCE_HW, FAST=320000) **

**master code is as follows: **
Code:
#include <16F876A.h>

  #fuses HS                         // High speed external oscillator
  #fuses PUT                        // Using the power up timer
  #fuses NODEBUG                    // Do not use debug mode
  #fuses NOBROWNOUT                 // Do not use brownout detect
  #fuses NOLVP                      // Do not use low voltage programming
  #fuses NOCPD                      // Do not use code protect
  #fuses NOWRT                      // Do now use write protect

#use delay(clock=20M,oscillator)
#use rs232(STREAM=RS485_PORT,BRGH1OK,baud=115200, xmit=PIN_C6, rcv=PIN_C7, ERRORS)
#use i2c(Master, sda=PIN_C4, scl=PIN_C3,FAST=350000) //FORCE_HW,

//RTC variables
#define XTAL_FREQUENCY  20000000
#define TIMER1_FREQUENCY (XTAL_FREQUENCY / 4)      // 1 clock tick = 1 instr. cycle = crystal frequency / 4
int32 Ticker;
int8 Seconds=0;

//====================================


#int_TIMER1                               
void TIMER1_isr()                         
{
  Ticker -= 65536;                        // Decrement ticker by clocks per interrupt
  if ( Ticker < 65536 )                   // If second has expired
  {  Ticker += TIMER1_FREQUENCY;          //   Increment ticker by clocks per second
     seconds++;                           //   Increment number of seconds
  }
}

////////////////////////////////////////////////////////////////////////////////
//    Initialize RTC
////////////////////////////////////////////////////////////////////////////////
void Initialize_RTC(void)
{
  Ticker = TIMER1_FREQUENCY;                  // initialize clock counter to number of clocks per second
  setup_timer_1( T1_INTERNAL | T1_DIV_BY_1 ); // initialize 16-bit Timer1 to interrupt
                                              // exactly every 65536 clock cycles
                                              // (about 76 times per second)
  enable_interrupts( INT_TIMER1 );            // Start RTC
}

void main()
{
int8 data,prev_second=-1;
int32 sent=0,received=0;

printf("START\n\r");

Initialize_RTC();
enable_interrupts( GLOBAL );
 

//have second counter increment, and show the findings
while(1)
{
if (seconds != prev_second)
{
  prev_second = seconds;
  output_toggle(PIN_A1);
  printf("Time:%u  Sent:%Lu  Rcvd:%Lu\n\r",seconds,sent,received);
  sent=0;
  received=0;
}

// Write the letter 'B' to the slave board.
i2c_start();
i2c_write(0xA0);
i2c_write(0x00);
i2c_write('B');
i2c_stop();
sent++;

// Read from the slave board and display the data.
i2c_start();
i2c_write(0xA0);
i2c_write(0x00);
i2c_start();
i2c_write(0xA1);
data = i2c_read(0);
i2c_stop();
if (data=='B') received++; //increment counter
}

}
Tim Bobbins
Guest







any takers?
PostPosted: Sun Aug 19, 2007 10:10 pm     Reply with quote

Can anyone help to shine some light on why we cant achieve higher speeds above 300k?
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Sun Aug 19, 2007 10:43 pm     Reply with quote

Microchip doesn't say that it will work at 400 KHz. In fact, they hint
that it will not. Here's a note from the MSSP errata:
Quote:
Note 1: The I2C™ interface does not conform to the 400 kHz I2C
specification (which applies to rates greater than 100 kHz) in all details,
but may be used with care where higher rates are required by the
application.

http://ww1.microchip.com/downloads/en/DeviceDoc/80131e.pdf

I suggest that you contact a Microchip FAE and ask if they know how
fast you can run an i2c slave. If they say 400 KHz, then ask them for
sample code. It will likely be MPASM code, but you can still test it,
and if it works, maybe it can be translated to C.
Tim Bobbins
Guest







microchip response
PostPosted: Wed Aug 22, 2007 11:49 am     Reply with quote

This is the response I received back from Microchip:

Quote:
Per the Errata you should be able to achieve the 400kHz rate but it cautions you that the I2C module does not meet the 400kHz specifications of I2C.

Unfortunately all the sample code we have for I2C is in regards to Master mode communication.

Regards.


So, I will search on the internet to see if someone else has implemented some fast-spec assembly I2C code - or just deal with the 300k speed. Will also look into whether changing to a 18-series chip will make any difference. The speed is of critical importance
ckielstra



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

View user's profile Send private message

PostPosted: Wed Aug 22, 2007 12:32 pm     Reply with quote

Quote:
The speed is of critical importance
Íf speed is so critical, how about changing the bus? The SPI bus is much faster, up to 10megabit on a 40MHz processor. Less communication overhead too, so less stress on your processor. Disadvantage is that it uses 1 more communication line plus an additional chip select line for every connected device.
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