Hi All, I am stuck with communicating between a pic16f684 and 24LC16B EEPROM. I am simply trying to write one byte to one Word Address of the EEPROM, and simply read it back. I then output it to a hyperterminal on my PC. I know my hyperterminal works fine, I have verified that.
Below is my code; I am using software rather than an MSSP module. I have previously been able to communicate with a different i2c device using the same code (a Kionix accelerometer). So I think my i2c routines are OK. I keep getting a result of 0x20 regardless of what I input into the EEPROM Word Address.
Any help is greatly appreciated!
Thx
Below is my code; I am using software rather than an MSSP module. I have previously been able to communicate with a different i2c device using the same code (a Kionix accelerometer). So I think my i2c routines are OK. I keep getting a result of 0x20 regardless of what I input into the EEPROM Word Address.
Any help is greatly appreciated!
Thx
Code:
;.......................................................................................................................
;.......................................................................................................................
;Define Global Deifnitions:
I2C_PORT equ PORTC
I2C_TRIS equ TRISC
#define SDA 2
#define SCL 3
;.......................................................................................................................
;.......................................................................................................................
START_PROGRAM
;Initialize Inputs/Outputs, and Registers on the PIC16F684.
;Initialize TRISA and TRISB registers.
bsf STATUS, RP0 ;Bank 1
movlw b'00001100'
movwf TRISC ;Assigns SDA and SCL Inputs.
movlw b'00000000'
movwf TRISA ;Assigns all TRISA as outputs.
movlw 0x03
movwf OSCCON ;Loads internal 31.25kHz clock
bcf STATUS, RP0 ;Bank 0
clrf CCP1CON
;......................................................................................................................
;.......................................................................................................................
Start_Loop
clrf TEST1
movlw 0x0A
movwf Write_Delay
Write_Delay_Loop
call Clock_Pulse_Delay
decfsz Write_Delay
goto Write_Delay_Loop
call Start_Command
movlw 0xA0
call Send_i2c_Byte
call ACK
movlw b'00001111'
call Send_i2c_Byte
call ACK
movlw 0x4D
call Send_i2c_Byte
call ACK
call Stop_Command
;;TEST TO WRITE TO JUST ONE REGISTER
goto Read_EEPROM
;Read from Bank 0, Word 0 (Control Byte: 10100001)
Read_EEPROM
movlw 0x0f
movwf Read_Delay
Read_Delay_Loop1
call Clock_Pulse_Delay
decfsz Read_Delay
goto Read_Delay_Loop1
call Start_Command
movlw b'10100000' ;A0
call Send_i2c_Byte
call ACK
movlw b'00001111' ;0x01
call Send_i2c_Byte
call ACK
; call Clock_Pulse_Delay
call Start_Command
movlw b'10100001'
call Send_i2c_Byte
call ACK
call Receive_i2c_Byte
movf Received_I2C_Byte, w
call Transmit_RS_232
call NACK
call Stop_Command
goto Send_Output
Send_Output
; movlw 0x55
; call Transmit_RS_232
; movf TEST1, w
; call Transmit_RS_232
;; movf TEST2, w
; call Transmit_RS_232
; movf TEST3, w
; call Transmit_RS_232
goto Start_Loop
;---------------------------------------------------------------------------------------
;Sub Routines for PIC
;---------------------------------------------------------------------------------------
;i2c Routines
;----------------------------------
Start_Command
call Set_SCL_High ;Release SCL
call Set_SDA_High ;Release SDA
call Clock_Pulse_Delay ;Delay
call Set_SDA_Low ;Set SDA Low
call Clock_Pulse_Delay ;Delay
return
;----------------------------------
SAD_W
movlw 0x1E
call Send_i2c_Byte ;(SAD+W)Slave Address plus write.
return
;----------------------------------
SAD_R
movlw 0x1F
call Send_i2c_Byte ;(SAD+R)Slave Address plus read.
return
;----------------------------------
ACK
call Set_SDA_High ;Release SCL
call Set_SCL_High ;Release SDA
call Clock_Pulse_Delay ;Delay
Clock_Stretch
btfss I2C_PORT, SCL
goto Clock_Stretch ;Wait for slave to release clock line (if "stretching")
call Clock_Pulse_Delay ;Delay
bcf STATUS, C ;Initally clears the carry bit
btfsc I2C_PORT, SDA ;Checks if slave is pulling SDA low (giving its ACK)
goto _Error ;Clear carry for NACK
bsf STATUS, C ;Set carry for ACK
btfss STATUS, C ;Check carry bit to ensure ACK
goto START_PROGRAM ;Start over if NACK
call Set_SCL_Low
return ;If ACK received, continue
;----------------------------------
SEND_ACK
call Clock_Pulse_Delay
call Set_SCL_Low
Get_ACK_SDA
btfss I2C_PORT, SDA ;Wait to see if the SDA line is released.
goto Get_ACK_SDA ;Loop
call Set_SDA_Low
; call Set_SDA_High ;Ensure SDA is released.
call Set_SCL_High ;Trigger SCL
call Clock_Pulse_Delay ;Delay
call Set_SCL_Low
; call Set_SCL_High ;Trigger Clock
call Set_SDA_High ;Release SDA
call Clock_Pulse_Delay ;Delay
; call Clock_Pulse_Delay ;Delay
; call Set_SDA_High ;Release SDA
; call Set_SCL_Low
return
NACK
call Set_SDA_High ;Release SCL
call Clock_Pulse_Delay ;Delay
call Set_SCL_High ;Set SCL Low
; call Set_SDA_High ;Release SDA
call Clock_Pulse_Delay ;Delay
call Set_SCL_Low
return
;----------------------------------
Stop_Command
call Set_SCL_High ;Release SCL
call Clock_Pulse_Delay ;Delay
call Set_SDA_High ;Release SDA
call Clock_Pulse_Delay ;Delay
call Clock_Pulse_Delay ;Delay
return
;----------------------------------
Send_i2c_Byte
movwf i2c_transmit_byte ;Moves whatever value is in the working register into i2c_transmit_byte
movlw 0x08
movwf i2c_bit_counter ;Sets 8 bits to be sent out
Send_i2c_Bit
call Set_SCL_Low ;Ensure SCL is low initially
call Clock_Pulse_Delay ;Delay
rlf i2c_transmit_byte, f ;MSB is now in carry (MSB is sent first)
btfsc STATUS, C
call Set_SDA_High
btfss STATUS, C
call Set_SDA_Low ;Sets either 0 or 1 to be sent out. (Checks carry bit)
call Clock_Pulse_Delay ;Delay
call Set_SCL_High ;Trigger Clock; set SCL high
call Clock_Pulse_Delay ;Delay
decfsz i2c_bit_counter, f ;Checks if 8 bits have been sent out
goto Send_i2c_Bit ;No
call Set_SCL_Low ;Yes; Set SCL Low
call Clock_Pulse_Delay ;Delay
return
;-------------------------------------
Receive_i2c_Byte
clrf Received_I2C_Byte ;Clears previous received byte
bsf Received_I2C_Byte, 0
; call Set_SDA_High
call Clock_Pulse_Delay
Get_i2c_Bit
call Set_SCL_Low
call Set_SDA_High ;Set SCL Low
call Clock_Pulse_Delay ;Delay
bcf STATUS, C ;Defaults to incoming bit = 0 (sets carry = 0)
call Set_SCL_High ;Release SCL
call Clock_Pulse_Delay
btfsc I2C_PORT, SDA ;Read port, skip if clear
bsf STATUS, C ;If incoming bit = 1, set carry flag to 1
rlf Received_I2C_Byte, f ;move carry into data (MSB first)
call Clock_Pulse_Delay
btfss STATUS, C
goto Get_i2c_Bit ;No
;Test to ensure hypertermianl works correctly.
; movlw 0x55
; movwf Received_I2C_Byte
; call Set_SCL_Low
call Clock_Pulse_Delay
call Clock_Pulse_Delay
call Clock_Pulse_Delay
return ;Yes, return
;Routines to Set SDA and SCL High/Low
Set_SCL_High
bsf STATUS, RP0 ;Bank 1
bsf I2C_TRIS, SCL ;Sets SCL as an input
clrf ANSEL
bcf STATUS, RP0 ;Bank 0
movlw 0x07
movwf CMCON0
return
Set_SCL_Low
bcf I2C_PORT, SCL ;Sets SCL port pin low
bsf STATUS, RP0 ;Bank 1
bcf I2C_TRIS, SCL ;Sets SCL as an output
clrf ANSEL
bcf STATUS, RP0 ;Bank 0
movlw 0x07
movwf CMCON0
return
Set_SDA_High
bsf STATUS, RP0 ;Bank 1
bsf I2C_TRIS, SDA ;Sets SDA as an input (high impedance)
clrf ANSEL
bcf STATUS, RP0 ;Bank 0
movlw 0x07
movwf CMCON0
return
Set_SDA_Low
bcf I2C_PORT, SDA ;Sets SDA port pin low
bsf STATUS, RP0 ;Bank 1
bcf I2C_TRIS, SDA ;Sets SDA as an output
clrf ANSEL
bcf STATUS, RP0 ;Bank 0
movlw 0x07
movwf CMCON0
return
;---------------------------------------------------------------------------------------
;---------------------------------------------------------------------------------------
;Delays
Clock_Pulse_Delay
movlw 0x03
movwf pw_counter
Clock_Pulse_Delay_Wait
nop
movlw 0x02
movwf pw_counter1
Clock_Pulse_Delay_Wait1
decfsz pw_counter1, f
goto Clock_Pulse_Delay_Wait1
decfsz pw_counter, f
goto Clock_Pulse_Delay_Wait
return
bit_delay
movlw 0x16
movwf delay_counter
bit_wait
nop
decfsz delay_counter, f
goto bit_wait
return
Osc_Stablize
movlw 0x0F
movwf osc_counter
Osc_Wait
nop
nop
nop
decfsz osc_counter, f
goto Osc_Wait
return
_Error
call Clock_Pulse_Delay
btfsc I2C_PORT, SDA
goto Next
return
Next
call Clock_Pulse_Delay
btfsc I2C_PORT, SDA
goto Next1
return
Next1
call Clock_Pulse_Delay
btfss I2C_PORT, SDA
return
;Error
movlw 0x45
call Transmit_RS_232
movlw 0x52
call Transmit_RS_232
movlw 0x52
call Transmit_RS_232
movlw 0x4F
call Transmit_RS_232
movlw 0x52
call Transmit_RS_232
goto START_PROGRAM
I2cInit
call Set_SCL_Low
call Set_SDA_Low
call Set_SCL_High
call Set_SDA_High
ClockLoop
btfsc PORTC,SDA
; goto BusFixed
bcf PORTC,SCL
bsf STATUS,RP0
bcf TRISC,SCL
goto $+1
bsf TRISC,SCL
bcf STATUS,RP0
goto ClockLoop
;---------------------------------------------------------------------------------------
;---------------------------------------------------------------------------------------
;Sub routines for PIC to Hyperterminal
;****SENDS INVERSE LOGIC TO PROLIFIC RS-232 TO USE CONVERTER
Transmit_RS_232
movwf transmit_byte_rs232 ;moves W to transmit_byte,
bsf STATUS, RP0
movlw 0x65
movwf OSCCON
movlw 0x00
movwf TRISC
movlw 0x00
movwf TRISA
bcf STATUS, RP0
; movwf transmit_byte_rs232 ;moves W to transmit_byte
call Osc_Stablize
; movlw 0x55
; movwf transmit_byte_rs232
bcf PORTC, 5
; movlw 0x55
; movwf Received_I2C_Byte
; movf Received_I2C_Byte, w
movlw 0x08
movwf bit_counter_rs232 ;sets 8 bits to send out
bsf PORTC, 5
call bit_delay
Send_Serial_Loop_RS232
rrf transmit_byte_rs232, f ;Send one bit
btfss STATUS, C
bsf PORTC, 5
btfsc STATUS, C
bcf PORTC, 5
call bit_delay
decfsz bit_counter_rs232, f ;Tests if all done
goto Send_Serial_Loop_RS232
bcf PORTC, 5
call bit_delay
call bit_delay
clrf transmit_byte_rs232
clrf bit_counter_rs232
bsf STATUS, RP0
movlw 0x03
movwf OSCCON
; movlw 0x00
; movwf TRISC
; movlw 0x00
; movwf TRISA
bcf STATUS, RP0
return
;--------------------------
Sleep_Routine
movlw 0x07
movwf WDTCON
sleep
movlw 0x00
movwf WDTCON
return
Control_Byte_Write_000
movlw 0xA0
call Send_i2c_Byte
return
Control_Byte_Write_010
movlw 0xA4
call Send_i2c_Byte
return
Control_Byte_Write_111
movlw 0xAE
call Send_i2c_Byte
return
Word_Address_0
movlw 0x00
call Send_i2c_Byte
return
Word_Address_55
movlw 0x55
call Send_i2c_Byte
return
Word_Address_ff
movlw 0xff
call Send_i2c_Byte
return