ASM – I2C

i2c-master.asm:

;#ASM###########################################################################################MCH#
; i2c-master.asm
; ``````````````
;
; I2C KOMUNIKACE TYPU MASTER
;
; 2.6.2018
;---------------------------------------------------------------------------------------------------
;      ___|_   | |_____| |     |   _|________
; SDA:    | \__|X|_____|X| ... |__/ |
;      ___|___ | |  _  | |     | ___|________
; SCL:    |   \|_|_/ \_|_| ... |/   |
;          start  akcept   ...  stop uvolneno
;---------------------------------------------------------------------------------------------------
  INCLUDE<P16F73.INC>        ; definice konstant procesoru

  GLOBAL  r_I2C_STATUS, r_I2C_ADR_ZARIZENI
  GLOBAL  r_I2C_ADR_DAT_H, r_I2C_ADR_DAT_L, r_I2C_FSR_1.REG, r_I2C_POCET_BYTE
  GLOBAL  _I2C_EEPROM_ZAPIS, _I2C_EEPROM_CTENI

MEM_I2C_0  UDATA_SHR        ; v bance 0

r_I2C_TMP      RES 1        ; pomocny registr
r_I2C_STATUS      RES 1        ; HLAVICKA - behem prenosu, NULOVY - po zdarnem ukonceni
r_I2C_ADR_ZARIZENI  RES 1        ; 3 bitova <2~0> adresa ciloveho zarizeni napr. EEPROM
r_I2C_ADR_DAT_H      RES 1        ; horni cast adresy dat napr. EEPROM
r_I2C_ADR_DAT_L      RES 1        ; spodni cast adresy dat napr. EEPROM
r_I2C_FSR_1.REG      RES 1        ; ukazatel na pocatecni datovy registr
r_I2C_POCET_BYTE    RES 1        ; pocet byte k prenosu ! PREPISUJE SE !

#DEFINE      I2C_PORT    PORTC      ; port pro SDA a SCL

#DEFINE      b_I2C_TRIS_SCL  I2C_PORT,3  ; TRIS - namapovany pin pro SCL (synchro)
#DEFINE      b_I2C_PORT_SCL  I2C_PORT,3  ; PORT - namapovany pin pro SCL (synchro)

#DEFINE      b_I2C_TRIS_SDA  I2C_PORT,4  ; TRIS - namapovany pin pro SDA (data)
#DEFINE      b_I2C_PORT_SDA  I2C_PORT,4  ; PORT - namapovany pin pro SDA (data)
    
I2C  CODE

;###################################################################################################
; CTENI DAT Z I2C EEPROM PAMETI
;
;  a) odeslani start bitu k zahajeni spojeni
;  b) odeslani byte hlavicky s adresou EEPROM zarizeni dle (r_I2C_ADR_ZARIZENI) a atributem zapisu
;  c) odeslani byte horni casti adresy dat v EEPROM (r_I2C_ADR_DAT_H)
;  d) odeslani byte dolni casti adresy dat v EEPROM (r_I2C_ADR_DAT_L)
;  e) odeslani start bitu k zahajeni spojeni
;  f) odeslani byte hlavicky s adresou EEPROM zarizeni dle (r_I2C_ADR_ZARIZENI) a atributem cteni
;  g) prijem dat z EEPROM do registru s sdresou v (r_I2C_FSR_1.REG) o poctu (r_I2C_POCET_BYTE)
;  h) odeslani stop bitu k ukonceni spojeni 
;
;  Uspesny zapis je indikovan vynulovanym registrem (r_I2C_STATUS), pri neuspesnem obsahuje hlavicku
;  Registr poctu byte ke cteni (r_I2C_POCET_BYTE) se prepisuje !
;---------------------------------------------------------------------------------------------------
_I2C_EEPROM_CTENI:

  CALL  _I2C_HLAVICKA        ; sestaveni hlavicky

  ; _________________________________________________________
  ; ODESLANI 1 BYTE HLAVICKY: ADRESA ZARIZENI + ATRIBUT ZAPIS

  CALL  _I2C_START_BIT        ; zahajeni spojeni, obsazeni sbernice

  BCF  STATUS,RP0        ; BANKA 0
  MOVLW  r_I2C_STATUS        ; --. 
  MOVWF  FSR          ; <-'  (r_I2C_STATUS) ulozena hlavicka
  CALL  _I2C_SDA_TX        ; <-'  odeslani hlavicky

  DECFSZ  r_I2C_TMP,f        ; ?? PROBEHLO ODESLANI BYTE OK ??
  GOTO  _I2C_STOP_BIT        ; 'NE'  ukonceni spojeni, uvolneni sbernice

  ; ________________________________
  ; ODESLANI 1 BYTE HORNI ADRESY DAT

  MOVLW  r_I2C_ADR_DAT_H        ; --. 
  MOVWF  FSR          ; <-'  (r_I2C_ADR_DAT_H)
  CALL  _I2C_SDA_TX        ; <-'

  DECFSZ  r_I2C_TMP,f        ; ?? PROBEHLO ODESLANI BYTE OK ??
  GOTO  _I2C_STOP_BIT        ; 'NE'  ukonceni spojeni, uvolneni sbernice

  ; ________________________________
  ; ODESLANI 1 BYTE DOLNI ADRESY DAT

  INCF  FSR          ; (r_I2C_ADR_DAT_L) 
  CALL  _I2C_SDA_TX        ; <-'

  DECFSZ  r_I2C_TMP,f        ; ?? PROBEHLO ODESLANI BYTE OK ??
  GOTO  _I2C_STOP_BIT        ; 'NE'  ukonceni spojeni, uvolneni sbernice

  ; _________________________________________________________
  ; ODESLANI 1 BYTE HLAVICKY: ADRESA ZARIZENI + ATRIBUT CTENI

  CALL  _I2C_START_BIT        ; zahajeni spojeni, obsazeni sbernice

  MOVLW  r_I2C_STATUS        ; --. 
  MOVWF  FSR          ; <-'  (r_I2C_STATUS) ulozena hlavicka
  BSF  INDF,0          ; nastavi pro cteni, bit:0
  CALL  _I2C_SDA_TX        ; <-'  

  DECFSZ  r_I2C_TMP,f        ; ?? PROBEHLO ODESLANI BYTE OK ??
  GOTO  _I2C_STOP_BIT        ; 'NE'  ukonceni spojeni, uvolneni sbernice

  ; __________
  ; PRIJEM DAT

  MOVF  r_I2C_FSR_1.REG,w      ; ukazatel na prvni datovy registr
  MOVWF  FSR          ; <-'

_I2C_EEPROM_CTENI_SMYCKA:

  CALL  _I2C_SDA_RX        ; nacteni 1 byte dat z EEPROM do registru dle FSR

  INCF  FSR,f          ; ukazatel na nasledujici datovy registr

  DECFSZ  r_I2C_POCET_BYTE      ; ?? PRENESEN PLNY POCET REGISTRU ??
  GOTO  _I2C_EEPROM_CTENI_SMYCKA    ; 'NE'

  CALL  _I2C_STOP_BIT        ; ukonceni spojeni, uvolneni sbernice

  ; ___________
  ; STATUS - OK

   CLRF  r_I2C_STATUS        ; vynulovani statusu

  RETURN

;###################################################################################################
; ZAPIS DAT DO I2C EEPROM PAMETI
;
;  Data do EEPROM jdou prvne do jeho zasobniku a az ukoncenim spojeni STOP BITEM se trvale zapisi,
; po tuto dobu zapisu cca 4ms EEPROM nekomunikuje.
;
;  a) odeslani start bitu k zahajeni spojeni
;  b) odeslani byte hlavicky s adresou EEPROM zarizeni dle (r_I2C_ADR_ZARIZENI) a atributem zapisu
;  c) odeslani byte horni casti adresy dat v EEPROM (r_I2C_ADR_DAT_H)
;  d) odeslani byte dolni casti adresy dat v EEPROM (r_I2C_ADR_DAT_L)
;  e) odeslani dat z registru s sdresou v (r_I2C_FSR_1.REG) a naslednych v poctu (r_I2C_POCET_BYTE)
;  f) odeslani stop bitu k ukonceni spojeni a zahajeni cca 4ms interniho zapisu v EEPROM
;
;  Uspesny zapis je indikovan vynulovanym registrem (r_I2C_STATUS), pri neuspesnem obsahuje hlavicku
;  Registr poctu byte k zapisu (r_I2C_POCET_BYTE) se prepisuje !
;---------------------------------------------------------------------------------------------------
_I2C_EEPROM_ZAPIS:

  CALL  _I2C_HLAVICKA        ; sestaveni hlavicky

  ; _________________________________________________________
  ; ODESLANI 1 BYTE HLAVICKY: ADRESA ZARIZENI + ATRIBUT ZAPIS

  CALL  _I2C_START_BIT        ; zahajeni spojeni, obsazeni sbernice

  MOVLW  r_I2C_STATUS        ; --. 
  MOVWF  FSR          ; <-'  (r_I2C_STATUS) ulozena hlavicka
  CALL  _I2C_SDA_TX        ; <-'  

  DECFSZ  r_I2C_TMP,f        ; ?? PROBEHLO ODESLANI BYTE OK ??
  GOTO  _I2C_STOP_BIT        ; 'NE'  ukonceni spojeni, uvolneni sbernice

  ; ________________________________
  ; ODESLANI 1 BYTE HORNI ADRESY DAT

  MOVLW  r_I2C_ADR_DAT_H        ; --. 
  MOVWF  FSR          ; <-'  (r_I2C_ADR_DAT_H)
  CALL  _I2C_SDA_TX        ; <-'

  DECFSZ  r_I2C_TMP,f        ; ?? PROBEHLO ODESLANI BYTE OK ??
  GOTO  _I2C_STOP_BIT        ; 'NE'  ukonceni spojeni, uvolneni sbernice

  ; ________________________________
  ; ODESLANI 1 BYTE DOLNI ADRESY DAT

  INCF  FSR          ; (r_I2C_ADR_DAT_L) 
  CALL  _I2C_SDA_TX        ; <-'

  DECFSZ  r_I2C_TMP,f        ; ?? PROBEHLO ODESLANI BYTE OK ??
  GOTO  _I2C_STOP_BIT        ; 'NE'  ukonceni spojeni, uvolneni sbernice

  ; ____________
  ; ODESLANI DAT

  MOVF  r_I2C_FSR_1.REG,w      ; ukazatel na prvni datovy registr
  MOVWF  FSR          ; <-'

_I2C_EEPROM_ZAPIS_SMYCKA:

  CALL  _I2C_SDA_TX        ; zapis 1 byte dat z registru dle FSR do EEPROM

  DECFSZ  r_I2C_TMP,f        ; ?? PROBEHLO ODESLANI BYTE OK ??
  GOTO  _I2C_STOP_BIT        ; 'NE'  ukonceni spojeni, uvolneni sbernice

  INCF  FSR,f          ; ukazatel na nasledujici datovy registr

  DECFSZ  r_I2C_POCET_BYTE      ; ?? PRENESEN PLNY POCET REGISTRU ??
  GOTO  _I2C_EEPROM_ZAPIS_SMYCKA    ; 'NE'

  CALL  _I2C_STOP_BIT        ; ukonceni spojeni, uvolneni sbernice

  ; ___________
  ; STATUS - OK

   CLRF  r_I2C_STATUS        ; vynulovani statusu

  RETURN

;###################################################################################################
; PRIJEM 1 BYTE DAT Z I2C DO (INDF)
;---------------------------------------------------------------------------------------------------
_I2C_SDA_RX:           

  ; _________________________________________________________
  ; PRIJMUTI 8 BITU ZE SERIOVE LINKY SDA DO DATOVEHO REGISTRU

  CLRF  INDF

  MOVLW  0x08
  MOVWF  r_I2C_TMP

_I2C_SDA_RX_SMYCKA:        

  CALL  _I2C_PAUZA
  CALL    _I2C_SCL_UP        ; SCL: -> 1, AKCEPTACE
  CALL  _I2C_PAUZA
    
  BCF  STATUS,C        ; C: prednastaveni 0
  BTFSC  b_I2C_PORT_SDA        ; ?? JE PRIJMUTY BIT Z SDA V 1 ??     
  BSF  STATUS,C        ; 'ANO' C: 1
  RLF  INDF          ; bit:0 <- C  posuvny registr

  CALL    _I2C_SCL_DOWN        ; SCL: -> 0

  DECFSZ  r_I2C_TMP,f        ; ?? BYLO PRENESENO 8 BITU ??
  GOTO  _I2C_SDA_RX_SMYCKA      ; 'NE'

  ; _______________
  ; VYSLANI 9. BITU

  DECF  r_I2C_POCET_BYTE,w
  BSF  STATUS,RP0        ; BANKA 1
  BTFSS  STATUS,Z        ; ?? JDE O POSLEDNI BYTE ??
  BCF  b_I2C_TRIS_SDA        ; 'NE'  SDA: -> 0 

  BCF  STATUS,RP0        ; BANKA 0
  BCF  b_I2C_PORT_SDA        ; SDA: -> 0

  CALL  _I2C_PAUZA

  CALL    _I2C_SCL_UP        ; SCL: -> 1, AKCEPTACE
  CALL  _I2C_PAUZA

  CALL    _I2C_SCL_DOWN        ; SCL: -> 0

  BSF  STATUS,RP0        ; BANKA 1
  BSF  b_I2C_TRIS_SDA        ; SDA: -> 1, uvolneni datove linky
  BCF  STATUS,RP0        ; BANKA 0

  CALL  _I2C_PAUZA

  RETURN

;###################################################################################################
; ODESLANI 1 BYTE DAT Z (INDF) DO I2C 
;---------------------------------------------------------------------------------------------------
_I2C_SDA_TX:           

  ; __________________________________________________________________
  ; ODESLANI 8 BIT DATOVEHO REGISTRU DO SERIOVE LINKY SDA ROTACI VLEVO

  MOVLW  0x08
  MOVWF  r_I2C_TMP
      
_I2C_SDA_TX_SMYCKA:        
  
  BCF  STATUS,C        ; C: prednastaveni 0
  BTFSC  INDF,7          ; ?? JE 7 BIT DATOVEHO REGISTRU V 1 ??     
  BSF  STATUS,C        ; 'ANO' C: 1
  RLF     INDF,f          ; C <- bit:7~0 <- C  posuvny registr 
              ;      
  BSF  STATUS,RP0        ; BANKA 1

  BTFSS  STATUS,C        ; ?? 0 ??    
  BCF  b_I2C_TRIS_SDA        ; SDA: -> 0
  BTFSC  STATUS,C        ; ?? JE NACTENY BIT Z SDA V 1 ??      
  BSF  b_I2C_TRIS_SDA        ; 'ANO' SDA: -> 1
  BCF  STATUS,RP0        ; BANKA 0
  BCF  b_I2C_PORT_SDA        ; SDA: -> 0

  CALL  _I2C_PAUZA
  CALL    _I2C_SCL_UP        ; SCL: -> 1, AKCEPTACE
  CALL  _I2C_PAUZA
  CALL    _I2C_SCL_DOWN        ; SCL: -> 0

  DECFSZ  r_I2C_TMP,f        ; ?? BYLO PRENESENO 8 BITU ??
  GOTO  _I2C_SDA_TX_SMYCKA      ; 'NE'

  ; _______________________________
  ; PRIJMUTI A KONTROLA 9. BITU ACK
      
  BSF  STATUS,RP0        ; BANKA 1
  BSF  b_I2C_TRIS_SDA        ; SDA: -> 1, uvolneni datove linky  
  CALL  _I2C_PAUZA
  CALL    _I2C_SCL_UP        ; SCL: -> 1, AKCEPTACE
  CALL  _I2C_PAUZA

  BTFSS  b_I2C_PORT_SDA        ; ?? PROBEHLO ODESLANI BYTE OK ??  
  INCF  r_I2C_TMP,f        ; 'NE'  0x01 ->(r_I2C_TMP)

  CALL    _I2C_SCL_DOWN        ; SCL: -> 0

  CALL  _I2C_PAUZA

  RETURN

;###################################################################################################
; SESTAVENI HLAVICKY K NAVAZANI KOMUNIKACE
;---------------------------------------------------------------------------------------------------
_I2C_HLAVICKA:

  BCF  STATUS,RP0        ; BANKA 0
  RLF  r_I2C_ADR_ZARIZENI,w      ; nacteni adr zarizeni, posun o bit vlevo
  ANDLW  b'00001110'        ; maska na 3 bitovou adresu zarizeni
  IORLW  b'10100000'        ; pridani hlavicky pro zapis
  MOVWF  r_I2C_STATUS        ; <-'

  RETURN

;###################################################################################################
; ODESLANI START BITU PRO OBSAZENI SBERNICE A ZAHAJENI SPOJENI : PRI SCL V 1 PREJDE SDA Z 1 DO 0
;---------------------------------------------------------------------------------------------------
_I2C_START_BIT:

  BSF  STATUS,RP0        ; BANKA 1
  BSF  b_I2C_TRIS_SDA        ; SDA: -> 1
  CALL  _I2C_PAUZA

  BSF  b_I2C_TRIS_SCL        ; SCL: -> 1, AKCEPTACE
  CALL  _I2C_PAUZA

        BCF  b_I2C_TRIS_SDA        ; SDA: -> 0
  BCF  STATUS,RP0        ; BANKA 0
  BCF  b_I2C_PORT_SDA        ; SDA: -> 0
  CALL  _I2C_PAUZA

  BSF  STATUS,RP0        ; BANKA 1
  BCF  b_I2C_TRIS_SCL        ; SCL: -> 0
  BCF  STATUS,RP0        ; BANKA 0
  BCF  b_I2C_PORT_SCL        ; SCL: -> 0
  CALL  _I2C_PAUZA

  RETURN

;###################################################################################################
; ODESLANI STOP BITU PRO UKONCENI SPOJENI A UVOLNENI SBERNICE : PRI SCL V 1 PREJDE SDA Z 0 DO 1
;---------------------------------------------------------------------------------------------------
_I2C_STOP_BIT:

  BSF  STATUS,RP0        ; BANKA 1
  BCF  b_I2C_TRIS_SCL        ; SCL: -> 0
  BCF  STATUS,RP0        ; BANKA 0
  BCF  b_I2C_PORT_SCL        ; SCL: -> 0

  BSF  STATUS,RP0        ; BANKA 1
  BCF  b_I2C_TRIS_SDA        ; SDA: -> 0
  BCF  STATUS,RP0        ; BANKA 0
  BCF  b_I2C_PORT_SDA        ; SDA: -> 0
  CALL  _I2C_PAUZA

  BSF  STATUS,RP0        ; BANKA 1
  BSF  b_I2C_TRIS_SCL        ; SCL: -> 1, AKCEPTACE
  CALL  _I2C_PAUZA

  BSF  b_I2C_TRIS_SDA        ; SDA: -> 1, uvolneni datove linky
  CALL  _I2C_PAUZA

  BCF  STATUS,RP0        ; BANKA 0

  RETURN   

;###################################################################################################
; SCL: 0 -> 1  PRECHOD AKCEPTACNI
;---------------------------------------------------------------------------------------------------
_I2C_SCL_UP:

  BSF  STATUS,RP0        ; BANKA 1
  BSF  b_I2C_TRIS_SCL        ; SCL: 0 -> 1
  BCF  STATUS,RP0        ; BANKA 0

  RETURN

;###################################################################################################
; SCL: 1 -> 0  PRECHOD NAVRATOVY
;---------------------------------------------------------------------------------------------------
_I2C_SCL_DOWN:

  BSF  STATUS,RP0        ; BANKA 1
  BCF  b_I2C_TRIS_SCL        ; SCL: 1 -> 0
  BCF  STATUS,RP0        ; BANKA 0
  BCF  b_I2C_PORT_SCL        ; SCL: -> 0

  RETURN

;###################################################################################################
; PAUZA CELKEM 20 INSTRUKCNICH CYKLU, 20us PRI 4 MHz, 10us PRI 8 MHz, ...
;---------------------------------------------------------------------------------------------------
_I2C_PAUZA:       

  NOP
  NOP
  NOP
  NOP
  NOP
  NOP
  NOP
  NOP
  NOP
  NOP

  NOP
  NOP
  NOP
  NOP
  NOP
  NOP

  RETURN      

;###################################################################################################
  END