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 MSSP PIC18/DS1339 Read() HELP??

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



Joined: 07 Mar 2007
Posts: 4
Location: Portugal, Aveiro

View user's profile Send private message

I2C MSSP PIC18/DS1339 Read() HELP??
PostPosted: Wed Mar 07, 2007 12:13 pm     Reply with quote

I´m trying to make (MSSP) I2C driver to communicate a pic18f6722 with a RTC DS1339. The original code is in C and it´s running well.. I get good readings from the RTC.
Do to memory problems, I´m trying to convert C read function to ASM to reduce the code and free some program memory. But I found this task dificult. I only tried to make a start condition replacing the "i2c_start()" with a "BSF SSPCON2,SEN" as shown above, and I dont get any readings and no Start. The program get this result:

..
START I2C
START I2C
START I2C
START I2C
START I2C
Error I2C
..

Anyone knows how to help me..
I forgot to mention I´m a beginner in assembler programming and sorry for my english.
Best Regards,

Bio

Part of the Code:
----------------

#use delay(clock=20000000)
#use i2c(Master, SLOW, sda=PIN_C4, scl=PIN_C3)
...

#define READ 1
#define WRITE 0

#byte SSPCON2 = 0xFC5

#define SEN 0

...

void READ_I2C(unsigned int8 ADR_SLAVE,unsigned int8 ADR_REG,char PTR_DATA[],unsigned int8 LENGTH)
{
unsigned int8 i;
unsigned int Slave_ack=1;
unsigned int time_count=0;
while ((Slave_ack==1)&&(time_count<5))
{
time_count++;
do {

#asm
CLRF SSPCON2
BSF SSPCON2,SEN // SEEMS A ERROR!!
#endasm
fprintf(CON,"\r\nSTART I2C");

//i2c_start(); ****
Slave_ack=i2c_write(ADR_SLAVE | WRITE);
if (Slave_ack){
i2c_stop();
break;
}
fprintf(CON,"\r\nError I2C 1"); // ERROR Debug

if (ADR_SLAVE==0xB8)
delay_ms(5);
Slave_ack=i2c_write(ADR_REG);
if (Slave_ack){
i2c_stop();
break;
}
fprintf(CON,"\r\nError I2C 2"); // ERROR Debug

if (ADR_SLAVE==0xB8)
delay_ms(5);
i2c_start();
Slave_ack=i2c_write(ADR_SLAVE | READ);
if (Slave_ack){
i2c_stop();
break;
}
fprintf(CON,"\r\nError I2C 3"); // ERROR Debug

for (i=ADR_REG;i<(ADR_REG+LENGTH-1);i++)
PTR_DATA=i2c_read(1);
PTR_DATA=i2c_read(0);
i2c_stop();

} while (time_count<5);
}
if (time_count==5)
{
#ifdef DEBUG_I2C
if (Consola_Enable())
fprintf(CON,"\r\nError I2C");
#endif
}
}


**** The result of the compiler (CCS PCH C Compiler, Version 3.224) just of I2C_READ():
.................... i2c_start();
698A: BSF F94.4
698C: MOVLW 02
698E: MOVWF 00
6990: DECFSZ 00,F
6992: BRA 6990
6994: BSF F94.3
6996: MOVLW 03
6998: MOVWF 00
699A: DECFSZ 00,F
699C: BRA 699A
699E: BCF F8B.4
69A0: BCF F94.4
69A2: MOVLW 02
69A4: MOVWF 00
69A6: DECFSZ 00,F
69A8: BRA 69A6
69AA: BCF F8B.3
69AC: BCF F94.3
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Wed Mar 07, 2007 12:48 pm     Reply with quote

Quote:

I´m trying to make (MSSP) I2C driver to communicate a pic18f6722 with
a RTC DS1339. I´m trying to convert C read function to ASM to reduce
the code and free some program memory.

The 18F6722 has 64K words of program memory space. You're
proposing to write your own hardware MSSP i2c routines, in order to
save a few instruction words ?

Here's a little test program that will generate ASM code for the
the CCS hardware i2c routines.
Code:

#include <18F6722.h>
#fuses XT, NOWDT, PUT, BROWNOUT, NOLVP 
#use delay(clock=4000000)
#use i2c(Master, sda=PIN_C4, scl=PIN_C3, FORCE_HW)

//========================
void main()
{
int8 c;

i2c_start();
i2c_write(0x55);
c = i2c_read(0);
i2c_stop();

while(1);
}


Here is the generated code for the CCS i2c_write() routine:
Code:

00004:  BCF    FC6.7   // Set SSP1CON1.WCOL = 0
00006:  BCF    F9E.3   // Set PIR1.SSP1IF = 0
00008:  MOVFF  07,FC9  // Set SSP1BUF = byte to send
0000C:  MOVLW  02
0000E:  BTFSC  FC6.7   // Is WCOL = 1 ?
00010:  BRA    001C    // If so, exit and return 2

00012:  BTFSS  F9E.3   // Wait in loop until SSP1IF = 1
00014:  BRA    0012   

00016:  MOVLW  00
00018:  BTFSC  FC5.6   // Return state of ACKSTAT
0001A:  MOVLW  01
0001C:  MOVWF  01
0001E:  GOTO   006E (RETURN)

What parts would you cut out ? Maybe the WCOL part, and the
returning of the ACKSTAT state ? This would save about 6 words.
You have 65536 words in the 18F6722. You would increase the free
program memory by .01 %. Is this worth doing ?
bogzao



Joined: 07 Mar 2007
Posts: 4
Location: Portugal, Aveiro

View user's profile Send private message

:\
PostPosted: Thu Mar 08, 2007 6:59 am     Reply with quote

Code:
#include <18F6722.h>
#fuses XT, NOWDT, PUT, BROWNOUT, NOLVP
#use delay(clock=4000000)
#use i2c(Master, sda=PIN_C4, scl=PIN_C3, FORCE_HW)

//========================
void main()
{
int8 c;

i2c_start();
i2c_write(0x55);
c = i2c_read(0);
i2c_stop();

while(1);
}


My generated result code from your function is:

Code:
.................... i2c_start();
*
5458:  BSF    F94.4
545A:  MOVLW  02
545C:  MOVWF  00
545E:  DECFSZ 00,F
5460:  BRA    545E
5462:  BSF    F94.3
5464:  MOVLW  03
5466:  MOVWF  00
5468:  DECFSZ 00,F
546A:  BRA    5468
546C:  BCF    F8B.4
546E:  BCF    F94.4
5470:  MOVLW  02
5472:  MOVWF  00
5474:  DECFSZ 00,F
5476:  BRA    5474
5478:  BCF    F8B.3
547A:  BCF    F94.3
.................... i2c_write(0x55);
547C:  MOVLW  55
547E:  MOVLB  E
5480:  MOVWF  xE0
5482:  MOVLB  0
5484:  RCALL  5158
.................... c = i2c_read(0);
5486:  CLRF   00
5488:  RCALL  53EE
548A:  MOVFF  01,BA4
.................... i2c_stop();
548E:  BCF    F94.4
5490:  NOP
5492:  BSF    F94.3
5494:  BTFSS  F82.3
5496:  BRA    5494
5498:  MOVLW  02
549A:  MOVWF  00
549C:  DECFSZ 00,F
549E:  BRA    549C
54A0:  NOP
54A2:  NOP
54A4:  NOP
54A6:  BSF    F94.4
54A8:  MOVLW  02
54AA:  MOVWF  00
54AC:  DECFSZ 00,F
54AE:  BRA    54AC
....................
.................... while(1);
54B0:  BRA    54B0
.................... }
54B2:  GOTO   69BC (RETURN)


I look to my result code and it´s difficult for me to understand the "machine" logic! Your I2C_Write() result is quite different from mine.. :o and compared with mine is simple to understand.. what´s the reason for this difference?

What I want is to reduce the code by substituting this instructions generated, that I don´t understand, by for example:

Code:
...
#asm
Start:
   bsf     SSPCON2,SEN      
TestSEN:
   btfsc   SSPCON2,SEN      
   goto    TestSEN
Send_Bit:
      bsf      PIE1,SSPIE
      btfss    PIR1,SSPIF
      goto     Send_Bit
      bcf      PIR1,SSPIF

SendWriteaddress:
   movlw   adr_slave   
   movwf   adr_slave
   movwf   SSPBUF                 
   call    Buffer_Bit

WriteACKtest:
    btfss   SSPCON2,ACKSTAT     
      goto    SendaddressWriteREG
   bsf     SSPCON2,PEN           
.
.
.
#endasm


But I don´t know if this possible and worth it.. The program seems not accepting this.. Can you give me your opinion and help.
Best Regards,

Joao Bio
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Thu Mar 08, 2007 10:51 am     Reply with quote

Your code is doing bit-banging. The way to get reduced code size is
to use the hardware MSSP, which is available on pins C4 and C3.
You have to tell the compiler to use the hardware i2c library functions
by using the FORCE_HW parameter in the #use i2c() statement.

Did you do this ?

If you did, and it's still generating software i2c ASM code, then
post your compiler version.
bogzao



Joined: 07 Mar 2007
Posts: 4
Location: Portugal, Aveiro

View user's profile Send private message

:o
PostPosted: Fri Mar 09, 2007 6:44 am     Reply with quote

I didnt know that.. I did that and the result from the compiler is..
(CCS PCH C Compiler, Version 3.224)

Code:
#include <18F6722.h>
#device   adc=10
#fuses  EC_IO, NOBROWNOUT, WDT16384, NOPUT, NOSTVREN, NODEBUG, PROTECT, PUT, LVP
#use    delay(clock=20000000)
#use    rs232(baud=9600, parity=N, xmit=PIN_C6, rcv=PIN_C7, bits=8, errors, stream=USART_A)
#use    rs232(baud=9600, parity=N, xmit=PIN_G1, rcv=PIN_G2, bits=8, errors, stream=USART_B)
#use    rs232(baud=19200, parity=N, xmit=PIN_C0, rcv=PIN_B1, bits=8, stream=USART_C)
#use    i2c(Master, SLOW, sda=PIN_C4, scl=PIN_C3, FORCE_HW)


Code:
...
i2c_start();

675C:  BCF    F9E.3       // SSPIF = 0
675E:  BCF    FC6.7     // WCOL = 0, Write Collision
6760:  BSF    FC5.0     // SEN = 1, Start Condition Enable
6762:  BTFSC  F9E.3     // is SSPIF = 1 ??
6764:  BRA    675C     // yes, jump
6766:  BTFSC  FC6.7     // is WCOL = 1 ??
6768:  BRA    675C     // yes, jump
676A:  BTFSC  FC5.0     // is SEN = 1 ??
676C:  BRA    676A     // yes, jump

Slave_ack=i2c_write(ADR_SLAVE | WRITE);

676E:  MOVFF  B9B,BA4
6772:  MOVFF  B9B,EE0
6776:  MOVLB  0
6778:  CALL   50AA
677C:  MOVFF  01,BA2
....................          if (Slave_ack){
6780:  MOVLB  B
6782:  MOVF   xA2,F
6784:  BZ    678E

i2c_stop();

6786:  BSF    FC5.2       // PEN = 1, Stop Condition Enable
6788:  BTFSC  FC5.2       // is PEN = 1 ??
678A:  BRA    6788       // yes, jump
....................             break;
678C:  BRA    69B4
...

Seems ok and just by switching to FORCE_HW I reduced some memory..
But now I have another problem.. The program seems not initicialize.. It resets itself by watchdog.. Just by adding "FORCE_HW", if I remove it it works fine.. what may be the problem? :O
Best regards,

Joao Bio
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Fri Mar 09, 2007 8:28 am     Reply with quote

Quote:

#fuses EC_IO, NOBROWNOUT, WDT16384, NOPUT, NOSTVREN,
NODEBUG, PROTECT, PUT, LVP

Are you really using a Low Voltage Programmer ? It's very rare and
the programmers are home-built. Most likely, you have a normal
High Voltage programmer. In that case, you should change the fuse
to NOLVP. The reason is, if you leave it at LVP and the pin goes to a
high level, the PIC will go into programming mode and lock up.
bogzao



Joined: 07 Mar 2007
Posts: 4
Location: Portugal, Aveiro

View user's profile Send private message

PostPosted: Wed Mar 21, 2007 12:01 pm     Reply with quote

Yes, you´re right it´s a High voltage programmer. I´ve changed to NOLVP.
The program works!
I´m trying to change C to Asm, but I found some problems in some code parts.
When I change:
- Slave_ack=i2c_write(ADR_SLAVE | WRITE);
- Slave_ack=i2c_write(ADR_REG);

the result is:
Code:
...
W<D0>
ACK WR = 0
ACK WR2 = 1   //The slave do not respond with a ack
... (x6 times)
Error I2C - Write
...


The Function:
Code:
void WRITE_I2C(unsigned int8 ADR_SLAVE,unsigned int8 ADR_REG,char PTR_DATA[],unsigned int8 LENGTH)
{
   unsigned int8 i;
   unsigned int Slave_ack=1;
   unsigned int time_count=0;
   while ((Slave_ack==1)&&(time_count<6))
   {
      time_count++;
      while (Slave_ack==1)
      {
         #ifdef DEBUG_I2C
         if (Consola_Enable())
            fprintf(CON,"\r\nW<X>",ADR_SLAVE,ADR_REG,ADR_REG+LENGTH-1);
         #endif
         if (ADR_SLAVE==0xB8)
            delay_ms(10);
       //i2c_start();
       //***************************************
         //                           START
         #asm
         Startescrita:
               bcf     PIR1,SSPIF              // SSPIF = 0
               bcf     SSPCON1,WCOL              // WCOL = 0, Write Collision
               bsf     SSPCON2,SEN              // SEN = 1, Start Condition Enable
               btfsc   PIR1,SSPIF              // is SSPIF = 1 ??
               goto    Startescrita            // yes, jump
               btfsc   SSPCON1,WCOL              // is WCOL = 1 ??
               goto    Startescrita            // yes, jump
         TestaSEN:
               btfsc   SSPCON2,SEN             
               goto    TestaSEN
         #endasm
      
       //***************************************
         //          SEND SLAVE ADDRESS
       i=(ADR_SLAVE | WRITE);
       #asm
            movlw   i
            movwf   SSPBUF
         Buffer_Bit:                     
           btfsc   SSPSTAT,BF           
         goto    Buffer_Bit           
         btfss   SSPCON2,ACKSTAT
         decf    Slave_ack,f
         #endasm
      
       //Slave_ack=i2c_write(ADR_SLAVE | WRITE);
       fprintf(CON,"\n\rACK WR = %d",Slave_ack);
         if (akstat){
            #asm
                  bsf     SSPCON2,PEN           
            TestaPEN:
                  btfsc   SSPCON2,PEN           
                  goto    TestaPEN
            #endasm
         //i2c_stop();
            break;
         }
         #asm
         incf  Slave_ack,f
         #endasm
         if (ADR_SLAVE==0xB8)
            delay_ms(10);
         
       //***************************************
         //          SEND ADDRESS REG
         #asm
                movlw   ADR_REG
                movwf   SSPBUF
         Buffer_Bit2:                        // Test buffer
               btfsc   SSPSTAT,BF             
                  goto    Buffer_Bit2          */
                btfss   SSPCON2,ACKSTAT
                decf    Slave_ack,f
         #endasm
         //Slave_ack=i2c_write(ADR_REG);
         fprintf(CON,"\n\rACK WR2 = %d",Slave_ack);

         if (Slave_ack){
            i2c_stop();
            break;
         }

       //***************************************
         //                 WRITE
         for (i=ADR_REG;i<(ADR_REG+LENGTH);i++)
         {
            if (ADR_SLAVE==0xB8)
               delay_ms(10);
            Slave_ack=i2c_write(PTR_DATA[i]);
            if (Slave_ack){
               i2c_stop();
               break;
            }
         }
         i2c_stop();
      }
   }
   if (time_count==6)
   {
      if (ADR_SLAVE==0xB8)
         flag_picgps_resetado=FALSE;
      #ifdef DEBUG_I2C
         if (Consola_Enable())
            fprintf(CON,"\r\nError I2C - Write");
      #endif
   }
   delay_ms(15);
}


I tried to understand what the compiler gives in asm.. but I dont understand.. :\
Can anyone help me to convert this and see if I´m doing things right.
Best regards,

João Bio

Note: Code in C works.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Wed Mar 21, 2007 1:37 pm     Reply with quote

Quote:
I tried to understand what the compiler gives in asm.. but I dont understand

Read this post. It has commented ASM code for the CCS hardware
i2c write routine:
http://www.ccsinfo.com/forum/viewtopic.php?t=29926&start=3

Quote:

Can anyone help me to convert this and see if I´m doing things right.

I don't have any interest in re-writing CCS library routines in ASM
to save a couple bytes. You are the one who is interested in it.
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