|
|
View previous topic :: View next topic |
Author |
Message |
bogzao
Joined: 07 Mar 2007 Posts: 4 Location: Portugal, Aveiro
|
I2C MSSP PIC18/DS1339 Read() HELP?? |
Posted: Wed Mar 07, 2007 12:13 pm |
|
|
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
|
|
Posted: Wed Mar 07, 2007 12:48 pm |
|
|
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
|
:\ |
Posted: Thu Mar 08, 2007 6:59 am |
|
|
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
|
|
Posted: Thu Mar 08, 2007 10:51 am |
|
|
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
|
:o |
Posted: Fri Mar 09, 2007 6:44 am |
|
|
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
|
|
Posted: Fri Mar 09, 2007 8:28 am |
|
|
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
|
|
Posted: Wed Mar 21, 2007 12:01 pm |
|
|
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
|
|
Posted: Wed Mar 21, 2007 1:37 pm |
|
|
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. |
|
|
|
|
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
|