Frank01
Newbie
Here we go again with I2C and trying to get a 16F877A to send a data byte to a specific memory location on a 24LC16 EEPROM and read the data byte back to the 16F877A. The code generally follows the Microchip I2C Master Mode Tutorial. When the attached code is run using the Pickit3, the 16F877A shows 0xFF on PORTD at the end of the program. I am curious where the 0xFF came from. PORTD should show 0x34 at the conclusion. Hopefully, someday IÂ’ll actually be able to pull data from a real time clock. First, I have to be able to send and receive eight bits.
I rewrote this program several times and put routines in to look at various bytes/bits using leds on PORTD. The program appears to be sending & receiving the correct control, address, and data bytes. It just continues to put 0xFF on PORTD at the end of the program instead of the data byte sent to the EEPROM.
IÂ’m sure the error is trivial, but like many others, learning I2C on your own can be tedious. The last time I felt this frustrated was in college when I was attempting to program a PDP-8. The PDP-8 used individual toggle switches to set each bit, then you pressed a spring loaded toggle switch to transfer the byte, then entered the rest of the program. As you can imagine, entering a long program was brutal. If there were problems when the program ran, there were no diagnostics, the PDP-8 just sat there.
Thanks in advance for any ideas on how to tame the beast.
==================================================================
I rewrote this program several times and put routines in to look at various bytes/bits using leds on PORTD. The program appears to be sending & receiving the correct control, address, and data bytes. It just continues to put 0xFF on PORTD at the end of the program instead of the data byte sent to the EEPROM.
IÂ’m sure the error is trivial, but like many others, learning I2C on your own can be tedious. The last time I felt this frustrated was in college when I was attempting to program a PDP-8. The PDP-8 used individual toggle switches to set each bit, then you pressed a spring loaded toggle switch to transfer the byte, then entered the rest of the program. As you can imagine, entering a long program was brutal. If there were problems when the program ran, there were no diagnostics, the PDP-8 just sat there.
Thanks in advance for any ideas on how to tame the beast.
==================================================================
Code:
;============================================
; I2C connected to 24LC16B - only one address byte, no upper byte
; Write to location 0x12, data 0x34 and read it back.
; I2C MASTER mode is in use.
;
LC01CTRLIN equ 0xA0 ; I2C value for CONTROL BYTE when INputing data to the EEPROM - ; 1010 0000 - master to slave transfer
LC01CTRLOUT equ 0xA1 ; I2C value for CONTROL BYTE when requesting OUTput from EEPROM - ; 1010 0001 - slave to master transfer
LC01ADDR equ 0x12 ; Sample value for ADDRESS BYTE - 0001 0012 - 0x12
LC01DATA equ 0x34 ; Sample data to write to EEPROM - 0011 0100 - 0x34
;
;=====================================================
;
#include <p16F877.inc> ; Processor Include file
__CONFIG _CP_OFF & _DEBUG_OFF & _WRT_ENABLE_OFF & _CPD_OFF & _LVP_OFF & _BODEN_OFF & _PWRTE_ON & _WDT_OFF & _XT_OSC
;
ORG 0 ; Start of code
; *** Setup I/O ***
banksel TRISD ; go to bank1
clrf TRISD ; sets all PORTD pins to outputs - using portd instead of portb
;
banksel TRISC ; go to bank1
movlw 0x18 ; RC3, RC4 are inputs for PORTC - 0001 1000
movwf TRISC ; Remaining PORTC pins are output
;
; *** Setup Registers for I2C ***
;
; Configure MSSP module for Master Mode
banksel SSPCON ; go to bank0
movlw 0x28 ; Enables MSSP and uses PORTC pins for I2C mode(SSPEN set)& enables ; I2C Master Mode (SSPMx bits = 1000)
movwf SSPCON ; move 0x28 to the file SSPCON
;
; Input Levels and slew rate set to I2C
banksel SSPSTAT
movlw 0x80 ; Slew Rate control (SMP) 100kHz mode and input levels are I2C
movwf SSPSTAT ; move 0x80 to SSPSTAT
;
; Configure Baud Rate - (FOSC/(4*BAUD))-1 = (4000/(4*100))-1 = (4000/400)-1 = 10-1 = 9 - Calculates
; SSPADD for desired Baud rate and sets up SSPADD
banksel SSPADD
movlw 0x09
movwf SSPADD
;
;========================================================
;
; *** Begin I2C Data Transfer Sequences ***
I2CWrite
; Enable START and wait for it to complete
banksel SSPCON2 ; BANK 1
bsf SSPCON2,SEN ; Enable START
call WaitMSSP ; Wait for I2C to finish
;
; Transfer CONTROL BYTE, wait for it to complete
movlw LC01CTRLIN ; Load CONTROL BYTE (input to eeprom mode) - 1010 0000 - 0xA0
call Xfer_I2C_Byte ; Send Byte
call WaitMSSP ; Wait for I2C to finish
;
banksel SSPCON2
btfsc SSPCON2,ACKSTAT ; Check ACK Status bit
goto I2CFail ; failed, skip this instruction if ack or nack received
;
; Transfer ADDRESS BYTE, wait for it to complete
movlw LC01ADDR ; Load Address Byte - 0001 0010 - 0x12
call Xfer_I2C_Byte ; Send Byte
call WaitMSSP ; Wait for I2C to finish
;
banksel SSPCON2
btfsc SSPCON2,ACKSTAT ; Check ACK Status bit
goto I2CFail ; failed, skip this instruction if ack or nack received
;
; Transfer DATA BYTE, wait for it to complete
;
movlw LC01DATA ; Load Data Byte - 0011 0100 - 0x34
call Xfer_I2C_Byte ; Send Byte
call WaitMSSP ; Wait for I2C to finish
;
banksel SSPCON2
btfsc SSPCON2,ACKSTAT ; Check ACK Status bit
goto I2CFail ; failed, skip this instruction if ack or nack received
;
; Transfer the STOP condition, wait for it to complete
banksel SSPCON2
bsf SSPCON2,PEN ; Send STOP condition
call WaitMSSP ; Wait for I2C to finish. no need to check for ack or nack.
;
; The WRITE has now completed successfully.
;
;===================================================
;
; Begin the Read Sequence
I2CRead
;
; Enable RESTART and wait for it to complete
banksel SSPCON2
bsf SSPCON2,RSEN ; Enable RESTART
call WaitMSSP ; Wait for I2C to finish
;
; Transfer CONTROL BYTE, wait for it to complete
movlw LC01CTRLIN ; Load CONTROL BYTE (input to eeprom)- 0xA0 - 1010 0000
call Xfer_I2C_Byte ; Send Byte
call WaitMSSP ; Wait for I2C to finish
;
; Check to see if I2C EEPROM is ready
banksel SSPCON2
btfsc SSPCON2,ACKSTAT ; Check ACK Status bit
goto I2CRead ; ACK Poll waiting for EEPROM write to complete
;
; Transfer ADDRESS BYTE, wait for it to complete
movlw LC01ADDR ; Load ADDRESS BYTE
call Xfer_I2C_Byte ; Send Byte
call WaitMSSP ; Wait for I2C to finish
;
banksel SSPCON2
btfsc SSPCON2,ACKSTAT ; Check ACK Status bit
goto I2CFail ; failed, skip this instruction if ack or nack received
;
; Transfer REPEATED START condition and wait for it to complete
banksel SSPCON2
bsf SSPCON2,RSEN ; Generate RESTART Condition
call WaitMSSP ; Wait for I2C to finish
;
; Transfer CONTROL BYTE (slave to master), wait for it to complete
movlw LC01CTRLOUT ; Load CONTROL BYTE (output)
call Xfer_I2C_Byte ; Send Byte
call WaitMSSP ; Wait for I2C to finish
;
banksel SSPCON2
btfsc SSPCON2,ACKSTAT ; Check ACK Status bit
goto I2CFail ; failed, skip this instruction if ack or nack received
;
; Switch MSSP module to I2C Receive mode
bsf SSPCON2,RCEN ; Enable Receive Mode (I2C)
call WaitMSSP ; Wait for I2C to finish
; Get the DATA BYTE and wait for it to complete. Data is in SSPBUF when completed.
; The receive mode is disabled at end automatically by the MSSP module.
; Transfer NACK bit for Acknowledge Sequence
banksel SSPCON2
bsf SSPCON2,ACKDT ; setting the ackdt bit to nack
bsf SSPCON2,ACKEN ; enable ackstat check
; Once ACK or NACK is enabled, ACKDT is automatically cleared
;
;========================================================
;
; Transfer the STOP condition and wait for it to complete
banksel SSPCON2
bsf SSPCON2,PEN ; Send STOP condition
call WaitMSSP ; Wait for I2C to finish
;
;===================================================
;
; I2C Write and Read have both finished, move DATA from file SSPBUF to PORTD
banksel SSPBUF
movf SSPBUF,W ; Transfer data from SSPBUF into W
movwf PORTD ; Move the value in SSPBUF to PORTD
;
goto $ ; Loop forever
; Program has finished and completed successfully.
;
; *** SUBROUTINES & ERROR HANDLERS ***
;========================================================
;
; Transfer the value in the accumulator to SSPBUF. The SSPIF flag is checked to ensure the byte has been ; sent. On completion, the routine exits.
Xfer_I2C_Byte
banksel SSPBUF ; BANK 0
movwf SSPBUF ; Put value to transfer in SSPBUF
retlw 0
;
;========================================================
; I2C sequence failed - This will normally not happen, but if it does, a STOP is sent, the program loops, and the entire code must be tried again.
I2CFail
banksel SSPCON2
bsf SSPCON2,PEN ; Send STOP condition
call WaitMSSP ; Wait for I2C to finish
;
banksel PORTD ; BANK 0
clrf PORTD ; clear portd
movlw 0xfe
movwf PORTD
;
goto $ ; Loop forever
;
;=========================================================
; This routine waits for I2C to finish. It does this by polling the SSPIF flag in PIR1.
WaitMSSP
banksel PIR1 ; BANK 0
btfss PIR1,SSPIF ; Check if I2C is completed (SSPIF set)
goto $-1 ; SSP, keep testing SSPIF
bcf PIR1,SSPIF ; SSPIF was set, I2C ready, clear SSPIF
retlw 0
;
END ;End of Program
====================================================================
Last edited by a moderator: