;---------------------------------------------------------------------
;18F slave as transmitter (only uses states 1,3 & 5) see I2C PIC slave f690 receiver
; File: an734_PIC18.asm CORRECTED so it WORKS
;in this simple example, I do not use the FSR but send a preloaded byte (info) in state 3
;there are LEDs turned on in the program to act as debug progress checks
list p=18f24K20
#include <p18f24K20.inc>
;---------------------------------------------------------------------
#define RX_BUF_LEN 2 ;one address byte and one data byte
#define info .199 ;this is the byte to be sent to the master
#define ADDRESS 0x34
#define SLAV_ADDR 0x20 ; I2C address of this node
cblock
FSRsave
PCLATHsave
Index
Temp
RXBuffer
info
TEMP_STAT ;in the AN this was a duplicate use of the temp file (temp)
endc
;---------------------------------------------------------------------
; Include Files
;---------------------------------------------------------------------
;config options at end of program
CONFIG fosc = intio67, fcmen = off, ieso = off ;1h
CONFIG pwrt = on, boren = OFF, borv = 18 ;2L
CONFIG wdtps = 1, wdten = off ;2h,
;default PBADEN = ON ;RB0-4 analog input on reset ;mclr enabled ;3h
CONFIG lvp = off, debug = off ;4L
;default code protection off ;5L, 5h
;default write protection off ;6L, 6h
;default table read protection off ;7L, 7h
memset macro Buf_addr,Value,RX_BUF_LEN
movlw RX_BUF_LEN ; This macro loads a range of data memory
movwf Temp ; with a specified value. The starting
movlw Buf_addr ; address and number of bytes are also
movwf FSR0L ; specified.
SetNext
movlw Value
movwf INDF0
incf FSR0L,F
decfsz Temp,F
goto SetNext
endm
load macro Address,Offset ; This macro loads the correct value
movlw Address ; into the FSR given an initial data
movwf FSR0L ; memory address and offset value.
movf Offset,W
addwf FSR0L,F
endm
org 0x0000
goto begin ;comment out if no interrupts
org 0x0008 ; (add enable/disable interrupts
goto isr_high ; to delays if there are interrupts)
; org 0x0018 ;
; goto isr_low ;
begin
movlw 0xD0 ;internal osc 4.0 MHz, b'11010000' pg 29
movwf osccon
bcf adcon0,ADON ;turn off AD
clrf ansel ;digital I/O on RA0-5 & RE0-2 of 43K pg 136
clrf anselh ;RB0-4 are NOT analog inputs pg 137
bcf cm1con0,c1on ;comparators off pg 284
bcf cm2con0,c2on ; pg 285
clrf trisa
clrf trisb
clrf portb
clrf porta
clrf Index
clrf Temp
clrf RXBuffer
movlw .199
movwf info
call Setup
Main
goto Main ;wait for interrupt
Setup
bsf TRISC,3
bsf TRISC,4
clrf FSR0L
clrf FSR0H
movlw SLAV_ADDR ;Load Address of Slave node
movwf SSPADD
movlw 0x36
movwf SSPCON1
clrf SSPSTAT
clrf SSPCON2
bsf SSPCON2,SEN ;Enable Clock Stretching for both transmit and slave
bcf PIR1,SSPIF ;Clear MSSP interrupt flag
bsf PIE1,SSPIE ;Enable MSSP interrupt enable bit
bsf intcon,peie
bsf intcon,gie
return
;---------------------------------------------------------------------
; Interrupt Code
;---------------------------------------------------------------------
ISR_HIGH
bsf portb,2 ;this is a debug progress check
movf FSR0L,W ;
movwf FSRsave ; Save FSR
btfss PIR1,SSPIF ; Is this a SSP interrupt?
goto $ ; No, just trap here. change if there are other typs of interrupts
bcf PIR1,SSPIF ;yes
call SSP_Handler ; Yes, service SSP interrupt.
movf FSRsave,W ;
movwf FSR0L ; Restore FSR
bsf SSPCON1,CKP ; Release clock( for transmit and receive)
retfie FAST ; Return from interrupt
;----------------------------------------------------------------
; State 1: I2C write operation, last byte was an address byte
; SSPSTAT bits: S = 1, D_A = 0, R_W = 0, BF = 1 b'0000 1001' 9h .9
;
; State 2: I2C write operation, last byte was a data byte b'0010 1001' 29h .41
; SSPSTAT bits: S = 1, D_A = 1, R_W = 0, BF = 1
;
; State 3: I2C read operation, last byte was an address byte b'0000 1100' Ch .12
; SSPSTAT bits: S = 1, D_A = 0, R_W = 1 (see Appendix C for more information)
;
; State 4: I2C read operation, last byte was a data byte b'0010 1100' 2Ch .44
; SSPSTAT bits: S = 1, D_A = 1, R_W = 1, BF = 0
;
; State 5: Slave I2C logic reset by NACK from master b'0010 1000 28h .40
; SSPSTAT bits: S = 1, D_A = 1, BF = 0, CKP = 1 (see Appendix C for more information)
; For convenience, WriteI2C and ReadI2C functions have been used.
;-----------------------------------------------------------------
SSP_Handler
movf SSPSTAT,W ; Get the value of SSPSTAT
andlw b'00101101' ; Mask out unimportant bits(7,6,4,1) in SSPSTAT.
movwf Temp_STAT ; for comparision checking.
State1 ; Write operation, last byte was an
movlw b'00001001' ;checking to see if it's an address,and if buffer is full.
xorwf Temp_STAT,W ;
btfss STATUS,Z ; Are we in State1? Yes if ^^^^, D/A=0, BF=1
goto State2 ; No, check for next state.....
memset RXBuffer,0,RX_BUF_LEN ; Clear the receive buffer.
clrf Index ; Clear the buffer index.
movf SSPBUF,W ; Do a dummy read of the SSPBUF.
bsf portb,0 ;this is a debug progress check
return
State2 ; Write operation, last byte was data,
movlw b'00101001' ; buffer is full.
xorwf Temp_STAT,W
btfss STATUS,Z ; Are we in State2?
goto State3 ; No, check for next state.....
load RXBuffer,Index ; Point to the buffer.
movf SSPBUF,W ; Dummy read to clear sspbuf so we can put number in FSR
movlw info ;this is the info we want stored in FSR
movwf INDF0 ; Put it in the buffer.
incf Index,F ; Increment the buffer pointer.
movf Index,W ; Get the current buffer index.
sublw RX_BUF_LEN ; Subtract the buffer length.
btfsc STATUS,Z ; Has the index exceeded the buffer length?
clrf Index
return
State3 ;read operation, last byte was address byte
movf Temp_STAT,W ;
andlw b'00101100' ; Mask BF bit in SSPSTAT
xorlw b'00001100' ;!!!!!!!!!!!!!
btfss STATUS,Z ; Are we in State3?
goto State4 ; No, check for next state.....
movf SSPBUF,W ; ??? THIS MUST BE A DUMMY READ TO CLEAR SSPBUF???
bcf sspstat,bf ;clear bf bit ????????????????????????
; clrf Index ; Clear the buffer index.
; load RXBuffer,Index ; Point to the buffer
; movf INDF0,W ; Get the byte from buffer.
movlw info ;writes 199 to w to be transmitted to master and displayed
call WriteI2C ; Write the byte to SSPBUF
; incf Index,F ; Increment the buffer index.
bsf sspcon1,ckp
clrf sspstat
bsf portb,1 ;this is a debug progress check
return
State4 ;read operation, last byte was a data byte
btfsc SSPCON1,CKP ;
goto State5
movlw b'00101100' ; buffer is empty.
xorwf Temp_STAT,W
btfss STATUS,Z ; Are we in State4?
goto State5 ; No, check for next state....
movf Index,W ; Get the current buffer index.
sublw RX_BUF_LEN ; Subtract the buffer length.
btfsc STATUS,Z ; Has the index exceeded the buffer length?
clrf Index ; Yes, clear the buffer index.
load RXBuffer,Index ; Point to the buffer
movf INDF0,W ; Get the byte
call WriteI2C ; Write to SSPBUF
incf Index,F ; Increment the buffer index.
return
State5 ; State 5: Slave I2C logic reset by NACK from master
; SSPSTAT bits: S = 1, D_A = 1, BF = 0, CKP = 1
;R/W remains set. Instead of testing
;this bit, the state machine tests the CKP bit,
;expecting it to be set.
movf Temp_STAT,W ;
andlw b'00101000' ; Mask RW bit in SSPSTAT
xorlw b'00101000'
btfss STATUS,Z ; Are we in State5?
goto I2CErr ; No, must be err
clrf index
clrf rxbuffer
clrf sspstat
bsf sspcon1,ckp
return ;to ISR
I2CErr ;we should not get here
nop ; Something went wrong! Set LED
bsf PORTB,7 ;turn on led 7 and loop forever. WDT will reset
goto $ ; device, if enabled.
;---------------------------------------------------------------------
; WriteI2C
;---------------------------------------------------------------------
WriteI2C
btfsc SSPSTAT,BF ; Is the buffer full?
goto WriteI2C ; Yes, keep waiting.
DoI2CWrite
bcf SSPCON1,WCOL ; Clear the WCOL flag.
movwf SSPBUF ; Write the byte in WREG
btfsc SSPCON1,WCOL ; Was there a write collision?
goto DoI2CWrite
return
end