Searching \ for '[PIC] I2C on PIC16F877 with ASM' in subject line. ()
Make payments with PayPal - it's fast, free and secure! Help us get a faster server
FAQ page: www.piclist.com/techref/i2cs.htm?key=i2c
Search entire site for: 'I2C on PIC16F877 with ASM'.

Exact match. Not showing close matches.
PICList Thread
'[PIC] I2C on PIC16F877 with ASM'
2005\06\27@080834 by liam .

picon face
List,

I've finally got back around to a project which has been hanging
around for a while using I2C. The aspect of the project I am having
trouble with happens to be the heart of it, the I2C (would it be
anything else???). Initially I figured I would try and get the PIC to
control a single MAX7300 I2C GPIO. After going through many
application notes, mpasm manuals and countless web pages describing
very similar setups I felt comfortable it wouldnt be overly difficult.

I've got a 16F877 on a board with 20Mhz Crystal, and an old ICD (and
old version of MPLAB to match).

It could be my assumptions in testing which are letting me down but I
dont think im that lucky. I've tried various example codes off the net
and written my own and have settled on this jigsaw as probably the
best however it still doesnt work.

When I run the code through I am expecting to see activity on the cro
on either the SDA or SCL however see none, only a constant high caused
by the pull up resisters.

When I debug the code in MPLAB it seems to endlessly loop in the
routine which checks the status of the bus (This one is directly
copied from the application note) I2CWait.

Can anyone with experiance in I2C see where I am going wrong??


Any help appriciated.




       LIST p=16F877
       include "P16F877.INC"

       #define R_W_MASK 0x04
       #define SSPIF_MASK 0x08
DELAYC EQU 32

       org 0
       goto start


;==================================================
;=Configure the MSSP as an I2C Port on a PIC16F877                       =
;==================================================
ConfigureI2C        
       bsf SSPCON, SSPEN        ;Enable I2C
       bsf SSPCON, SSPM3        ;Setup I2C
       bcf SSPCON, SSPM2
       bcf SSPCON, SSPM1
       bcf SSPCON, SSPM0
       
       bsf STATUS, RP0     ;Register Page 1
       
       movlw .0
       movwf SSPCON2
       
       bcf SSPSTAT, SMP
       bcf SSPSTAT, CKE        ;Set I2C Levels
       
       ;Set I2C Speed
       movlw        b'00001100'        ;100k at 4Mhz Clock  THIS NEEDS CHANGING
       movwf        SSPADD
       
       bcf STATUS, RP0                ;Return to Page 0
;================================================



;================================================
;=Send a Character via I2C                                            
                 =
;================================================
I2CSend
       movwf        SSPBUF                ;Load data to send
       call I2CWait                ;Wait for completion
       return
;================================================





;================================================
;=Send an I2C ACK                                                    
                    =
;================================================
I2CAck
       bsf STATUS, RP0                        ;Page 1
       bcf SSPCON2, ACKDT                ;Setup for Ack
       bsf SSPCON2, ACKEN                ;Send Ack
       bcf STATUS, RP0                        ;Page 0
       call I2CWait                        ;Wait for completion
       return
;================================================


;================================================
;=Send an I2C NAK                                                    
                    =
;================================================
I2CNak
       bsf STATUS, RP0                        ;Page 1
       bcf SSPCON2, ACKDT                ;Setup for NAK
       bsf SSPCON2, ACKEN                ;Send NAK
       bcf STATUS, RP0                        ;Page 0
       call I2CWait                        ;Wait for completion
       return
;================================================


;================================================
;=Generate an I2C Start                                              
                   =
;================================================
I2CStart
       bsf STATUS, RP0                        ;Page 1
       bsf SSPCON2, SEN                ;Initiate Start Condition
       bcf STATUS, RP0                        ;Page 0
       call I2CWait                        ;Wait for completion
       return
;================================================


;================================================
;=Generate an I2C Restart                                            
                 =
;================================================
I2CRestart
       bsf STATUS, RP0                ;Page 1
       bsf        SSPCON2, RSEN        ;Initiate Restar Condition
       bcf STATUS, RP0                ;Page 0
       call I2CWait                ;Wait for completition
       return
;================================================


;================================================
;=Generate an I2C Stop                                                
                  =
;================================================
I2CStop
       bsf STATUS, RP0                ;Page 1
       bsf SSPCON2, PEN        ;Generate Stop
       bcf STATUS, RP0                ;Page 0
       call I2CWait                ;Wait for completion
       return
;================================================


;================================================
;=Waits for I2C Process to complete                                  
          =
;================================================
I2CWait
       banksel SSPSTAT        ; select SFR bank
       btfsc SSPSTAT,R_W        ; transmit in progress?
       goto $-1                ; module busy so wait
       banksel SSPCON2        ; select SFR bank
       movf SSPCON2,w                ; get copy of SSPCON2
       andlw 0x1F                ; mask out non-status
       btfss STATUS,Z                ; test for zero state
       goto $-3                ; bus is busy test again
       return ; return
;================================================

start
       call ConfigureI2C
       call I2CStart
       movlw .255
       call I2CSend
       call I2CStop
       goto start
       end

2005\06\27@082240 by Jinx

face picon face
Liam, do you have TRISC <3:4> set as i/p and what value pull-ups ?

2005\06\27@085832 by liam .

picon face
On 6/27/05, Jinx <spam_OUTjoecolquittTakeThisOuTspamclear.net.nz> wrote:
> Liam, do you have TRISC <3:4> set as i/p and what value pull-ups ?
>


Hm.... What happend to my input/output configurations??? [I'll fix
that tomorrow]

The pull ups are 2k4


liaaam

2005\06\27@192312 by Hector Martin

flavicon
face
liam . wrote:
> ;================================================
> ;=Waits for I2C Process to complete                                  
>            =
> ;================================================
> I2CWait
>        banksel SSPSTAT        ; select SFR bank
>        btfsc SSPSTAT,R_W        ; transmit in progress?
>        goto $-1                ; module busy so wait
>        banksel SSPCON2        ; select SFR bank
>        movf SSPCON2,w                ; get copy of SSPCON2
>        andlw 0x1F                ; mask out non-status
>        btfss STATUS,Z                ; test for zero state
>        goto $-3                ; bus is busy test again
>        return ; return
> ;================================================

Usually I just test SSPIF (and clear it if set), it makes things simpler.

Also, I think your BRG value might be too low, although I haven't made
much sense from the specs. For my current project (10Mhz) the value
specified in the datasheet (0x3F) works fine, but those values don't
really make much sense to me. You might want to specify SSPADD higher,
since usually slower I2C will not hurt. Also, I used a 16F877A (not
the same, they have a slightly different MSSP, but that only affected
me on SLAVE mode which I used in an adjacent 16F876, because the non-A
versions do not feature receive clock stretching).

Check your TRIS bits, the pins must be set as inputs. Your Nak routine
is wrong too, you want to bsf ACKDT

If you're interested, the relevant bits of my code are:

;=====================================================
#define I2CBRG 0x3F
#define INPADDR b'0100000'      ; PCF8574 address
;=====================================================
START
       bcf     STATUS,IRP
       bcf     STATUS,RP1      ; setup bank 1 stuff
       bsf     STATUS,RP0

; TRIS Setup
       movlw   b'101111'
       movwf   TRISA
       movlw   b'00000000'
       movwf   TRISB
       movlw   b'11011000' ; <- note setting as inputs
       movwf   TRISC
       movlw   b'00000000'
       movwf   TRISD
       movlw   b'111'
       movwf   TRISE
;=====================================================
; I2C Setup
       movlw   (1<<SMP)|(0<<CKE)          ; normal rate, no SMBUS
       movwf   SSPSTAT

       movlw   I2CBRG          ; setup I2C Baud Rate Generator
       movwf   SSPADD

       bcf     STATUS,RP0      ; back to bank 0

       movlw   (1<<SSPEN) | b'1000'       ; SSP ON, I2C Master mode
       movwf   SSPCON

       clrf    SSPCON2
;=====================================================

And this example for reading 8 input bits from a PCF8574 chip:

;=====================================================
WAITSET MACRO   REG,BIT         ; wait for bit set
       btfss   REG,BIT
       goto    $-1
       ENDM

;=====================================================

       bcf     PIR1,SSPIF      ; clear any previous interrupt
       bsf     STATUS,RP0
       bsf     SSPCON2,SEN     ; send I2C START
       bcf     STATUS,RP0
       WAITSET PIR1,SSPIF
       bcf     PIR1,SSPIF

       movlw   (INPADDR<<1)|1  ; send address, read mode
       movwf   SSPBUF
       WAITSET PIR1,SSPIF
       bcf     PIR1,SSPIF

       bsf     STATUS,RP0
       btfsc   SSPCON2,ACKSTAT ; ACK received?
       goto    IN_NAK          ; Nope. Problem.

       bsf     SSPCON2,RCEN    ; OK, receive data
       bcf     STATUS,RP0
       WAITSET PIR1,SSPIF
       bcf     PIR1,SSPIF
       movf    SSPBUF,W        ; get data
       movwf   INPUT_VALUE

       bsf     STATUS,RP0
       bsf     SSPCON2,ACKDT   ; NAK (we do not want any more data)
       bsf     SSPCON2,ACKEN   ; send it
       bcf     STATUS,RP0
       WAITSET PIR1,SSPIF
       bcf     PIR1,SSPIF

       goto    IN_DONE         ; all done, STOP

IN_NAK  bcf     STATUS,RP0
       ; put your error set-up here, but jump
       ; to / fall down to IN_DONE for I2C stop

IN_DONE bsf     STATUS,RP0
       bsf     SSPCON2,PEN     ; send I2C STOP
       bcf     STATUS,RP0
       WAITSET PIR1,SSPIF
       bcf     PIR1,SSPIF

       ; all done now

;=====================================================

(writing is the same, but with the LSB of the address set to 0 and
writing afterwards and checking for NAK, same as when sending the address)

Regards,
--
Hector Martin (.....hectorKILLspamspam@spam@marcansoft.com)
Public Key: http://www.marcansoft.com/hector.asc

2005\06\28@034735 by Alan B. Pearce

face picon face
>I've got a 16F877 on a board with 20Mhz Crystal, and
>an old ICD (and old version of MPLAB to match).

Is there a reason to not use the code from AN735? I used that code on a
16F876, and it just plugged right in and ran. I can supply a module that
uses Olins development environment.

2005\06\28@044813 by liam .

picon face
>
> Is there a reason to not use the code from AN735? I used that code on a
> 16F876, and it just plugged right in and ran. I can supply a module that
> uses Olins development environment.
>


This is where I really confused my self as one of the times I tried
different code I used that code. At least for readability though I
made the jigsaw pussle I posted from my understanding of that code as
well as other code found on the net which reportedly works. But it
appears I did miss the obvious of setting the pins as inputs, so i'll
check this out in an hour or so and let everyone know..



liaam

2005\06\28@072629 by liam .

picon face
>
> Usually I just test SSPIF (and clear it if set), it makes things simpler.

I've changed my wait routine to this and strangely enough I get the
same problem it seems to just hang and loop forever in this sub
routine.

{Quote hidden}

Done...


I've tried varrying the SSPADD value but got no where. At one point i
thought I had it working but it was a loose lead causing the cro to
jump around the place.

One thing thats different tonight verse last night and I'm not sure
why is as soon as I start the program bit 4 (SDA) is pulled low and
stays that way.

Just checking, is my test setup at the moment right?

PIC 16F877 with 20Mhz crystal with caps.
47K pull up on MCLR
2K4 pull up on SDA, and SCL (RC4, RC3)
60Mhz CRO attached to both SDA and SCL in refference to ground.


Liam

2005\06\28@211134 by liam .

picon face
I tried the following code provided by Hector and still have the same
problem. The program forever loops in the I2C wait. Considering that
this code works for Hector (correct me if Im wrong) as well as the
other code direct from application notes and websites and my own ideas
all haveing the same problems I am shifting my focus to hardware.

What size pull ups do other people use ??  At the moment I am testing
using a CRO and have no slave I2C components on the bus, i was under
the impression I should still see activity such as I2C start.


liaaam



{Quote hidden}

> -

2005\06\29@200724 by Hector Martin

flavicon
face
liam . wrote:
> I tried the following code provided by Hector and still have the same
> problem. The program forever loops in the I2C wait. Considering that
> this code works for Hector (correct me if Im wrong) as well as the
> other code direct from application notes and websites and my own ideas
> all haveing the same problems I am shifting my focus to hardware.
>
> What size pull ups do other people use ??  At the moment I am testing
> using a CRO and have no slave I2C components on the bus, i was under
> the impression I should still see activity such as I2C start.

I'm using 10K successfully right now.

I can't see where I2C hardware problems could cause hangups. If a
device does not respond, you get a NACK for the address byte. A
possible hangup could be a forced CLK line low, since that would stop
the current transfer (clock stretching). SDA going low means the START
bit is properly sent (SDA high-to-low transition while CLK high means
START).

I haven't tried the ICD, but I wouldn't trust it much when working
with hardware comms. Can you check using some simple debugging
(bringing some outputs high on certain code points or similar)? Does
it hang on the check after setting SEN high, or does it hang after
placing the slave address in SSPBUF?

As an aside note, I just saw a bug in my code: I clear SSPCON2 while
in bank 0 (which clears TMR2 instead). It is probably not the cause of
the problem, but worth noting.

--
Hector Martin (.....hectorKILLspamspam.....marcansoft.com)
Public Key: http://www.marcansoft.com/hector.asc

2005\06\29@215053 by Jinx

face picon face
> I'm using 10K successfully right now.
>
> I can't see where I2C hardware problems could cause hangups

If the pull-up is too high for the buss capacitance, the signal transition
times will fall outside I2C spec. Your 10k implies a buss C of 75pF
according to Section 16.1

303kB

http://www.semiconductors.philips.com/acrobat/literature/9398/39340011.pdf

More... (looser matching)
- Last day of these posts
- In 2005 , 2006 only
- Today
- New search...