i2c.asm

来自「DSP中用MCBSP模拟I2C接口的程序.其中DSP的型号是C5416」· 汇编 代码 · 共 679 行 · 第 1/2 页

ASM
679
字号
	  ;***SET UP AR4 POINTS TO BYTE TO BE SENT***
      LD    #_ODPTR,B					;Load addr of out-data to B
      LD    _ODBYTECTR, -8,A			;Move current byte pointer
      STL	A,POINTER					;Store it to POINTER (1ST= BYTE 0)
      ADD   A,B							;Update current btye pointer
      STLM  B,AR4						;AR4 points to current byte
      ;***SET UP AR3 POINTS TO BIT TO BE SENT***
      STM	#MASK,AR3					;AR3 points to MASK
	  RPT	ODBITCTR					;Look up table (LUT)
	  LD	*AR3+,A						;Store mask to A  
	  AND	*AR4, A						;Check if the bit is high or low
	  ;***WRITE BIT***
	  CC	releaseSDA,ANEQ             ;Bit=1, SDA=high
	  CC    pullSDA,AEQ                 ;Bit=0, SDA=low
      ;***TEST IF COME TO LAST BIT***
      LD	ODBITCTR,A	                ;If BITCTR=0(LSB) ie. end of byte
      BC    tint_ws_next_byte,AEQ		;goto next byte
      SUB	#1,A,B						;Decrement A and store to B
      STL	B,ODBITCTR					;Store back to register
	  B	    tint_ws_next            	;Next bit
	  ;***TEST IF COME TO LAST BYTE***
tint_ws_next_byte:
	  LD	POINTER,B                   ;First byte is byte zero
	  ORM	#K_ACK_1,_I2CSTATUS			;Enable ACK flag
      ST	#7,ODBITCTR					;Start from MSB (initiate next byte)
      ADD	#1,B						;Increment POINTER
      STL   B,POINTER					;Store back
      ANDM	#0FFH,_ODBYTECTR			;Prepare num of btye to send
      LD    _ODBYTECTR,A                ;Load num of byte to A
      SUB   B,A							;A=(Num of byte) - (current byte POINTER)     
      BC	tint_ws_end_write,AEQ		;If=0,no more to send,enable stop condition
      LD	POINTER,8,A                 ;Shift 8 places forward
      LD	_ODBYTECTR,B				;
      OR	B,A							;Combine POINTER and num of btye to send                                                                 
      STL	A,_ODBYTECTR				;Update ODBYTECTR
	  B		tint_ws_next				;Goto next byte
      ;***NO MORE DATA***
tint_ws_end_write:                      ;Do not update POINTER for last byte
	  ORM	#K_STOP_1,_I2CSTATUS		;Enable STOP condition 
	  ST	#0,TEMP1_REG
      ;***PREPARE FOR NEXT BIT***
tint_ws_next:
	  ORM	#K_CLKH_1,_I2CSTATUS		;Next TINT,enable releaseSCL
  	  STM	#STOP_TIMER,TCR     		;stop timer
      STM	#K_SCL_LOW1,PRD    			;load SCL low period(interrupt at 5us)
      STM	#START_TIMER,TCR    		;start timer     
      B		tint_end_isr				;
      ;***BUSY LINES OR UNKNOWN CONDITION
tint_busy:                      		;Unknown condition or lines are busy
      ;***REPORT ERROR TYPE***
      ORM	#K_ERR_1,_I2CSTATUS			;Turn error flag on 
      ST	#K_ERR_UNKNOWN,ERRORCODE	;Give type of error
      B		tint_end_isr


;**************************************************************************
;**************************************************************************      


;*****MAKE CLK->HIGH SEQUENCES*****
tint_clk_go_high:
	  CALL  releaseSCL					;SCL=high
	  NOP                 				;Wait for a while. (Does SCL go high
	  NOP                               ;Wait for a while.   immediately?)
	  NOP                               ;Wait for a while.
      ;***SYNCHRONIZATION***
	  ;ST    SPSA,AR2                	;AR2 points to SPSA(redundant,safety)
	  ST	#PCR_SUB,*AR2+              ;Sub-bank address (SPSA)=PCR
  	  LD	#K_DR_STAT_1,A              ;Check if SCL go high?
      AND	*AR2-,A    
      BC	tint_clk_go_high_yes, ANEQ  ;if SCL=high, goto high_yes
	  ;***SLAVE HOLD SCL LOW***      
      STM	#STOP_TIMER,TCR     		;stop timer
      STM	#K_PRD_VAL,PRD    			;load PRD (interrupt at 1us)
      STM	#START_TIMER,TCR    		;start timer
      B		tint_end_isr        		;Do go_high procedure again

;***CLK GONE HIGH (SLAVE NO MORE HOLDING ONTO SCL)***
tint_clk_go_high_yes:
	  ANDM	#K_CLKH_0,_I2CSTATUS		;Remove SCL go_high flag            						

      ;*****ACKNOWLEDGE SEQUENCE***      
	  ;***CHECK IF IT IS IN THE ACK PHASE (write slave)***
	  LD	TEMP_REG,A					;Check if Slave release SDA line
	  BC	tint_ack_test,AEQ			;Extra ACT flag=0 : ACK in progress
      ;*****END OF ACKNOWLEDGE SEQUENCE***

      ;*****READ THE CURRENT SDA LEVEL (FOR READ SLAVE MODE)***
      ;***CHECK IF MASTER-RECEIVER MODE (read slave)***
	  LD	_I2CSTATUS,B				    ;
	  LD	B,A							;Duplicate  
	  AND   #K_ADDR_1,A 	   			;Check ADDR in i2c status
  	  BC	tint_clk_go_high_not_rs,ANEQ;If sending slave addr,goto not_rs
	  
	  MVDK	_I2CSTATUS,TEMP_REG			;Copy i2c status to temp register
	  ANDM	#01100000B, TEMP_REG	 	;Mask on 6 and 5 bit (Mode of operation)
	  CMPM	TEMP_REG,#K_READ_FROM_SLAVE	;Compare only 6 and 5 bit
	  BC	tint_clk_go_high_not_rs,NTC ;If not 10,goto not_rs
	  ;***CHECK IF IN ACK PHASE***
      AND   #K_ACK_1,B 		   			;Check ACK in i2c status
  	  BC	tint_rs_mode,BEQ			;If ACK=0, goto rs_mode
      ;***CHECK IF GOING TO STOP SEQUENCE***
  	  LD	_I2CSTATUS,A				;Check if come to the last byte
  	  AND	#K_STOP_1,A					;Need to set extra TEMP_REG flag=0
  	  BC	tint_clk_go_high_not_rs,AEQ ;Bcos to avoid the unknown transition of SDA
  	  ST	#0,TEMP1_REG				;To prolong SDA=0 in stop sequences									
  	  ;*****END OF READ THE CURRENT SDA LEVEL (FOR READ SLAVE MODE)***

tint_clk_go_high_not_rs:      
      ;***END OF READ SLAVE MODE***        	  
      ORM	#K_CLKL_1,_I2CSTATUS		;Enable SCL go_low flag
      STM	#STOP_TIMER,TCR     		;stop timer
      STM	#K_SCL_HIGH,PRD    			;load PRD (interrupt at 5us)
      STM	#START_TIMER,TCR    		;start timer
	  B		tint_end_isr    	        ;Interrupt at 5us


;**************************************************************************
;**************************************************************************      


;***MAKE CLK->LOW SEQUENCES***
tint_clk_go_low: 
	  CALL	pullSCL						;SCL=low               
	  ANDM	#K_CLKL_0,_I2CSTATUS		;Remove SCL go_low flag
	  STM	#STOP_TIMER,TCR     		;stop timer
      STM	#K_SCL_LOW2,PRD    			;load SCL low period(interrupt at 5us)
      STM	#START_TIMER,TCR    		;start timer     
      B		tint_end_isr	        	;Interrupt at 5us


;**************************************************************************
;**************************************************************************      

      
	  ;***DISABLE FURTHER TIMER INTERRUPT***		  
tint_disable_tint: 	  
	  ANDM	#0FFF7H,IMR					;Disable any further TINT
	  B     tint_end_end
	  
;******END OF ISR*****
tint_end_isr:
   	  ORM	#0008H,IMR         			;enable timer interrupt
 	  STM	#0FFFFH,IFR         		;clear any pending interrupts 	       
;***START OF OTHER TINT ISR
tint_end_end:
      ;***RESTORE CPU REGISTERS
      NOP
	  NOP
	  POPM	AR6
	  POPM	AR5
	  POPM	AR4
	  POPM	AR3
	  POPM	AR2
	  POPM	AR1
	  POPM	ST1
	  POPM	ST0
	  NOP
	  NOP
                                        ;END OF TIMER ISR
      RETE                              ;enable global INTM                    
      
;**************************************************************************
;**************************************************************************      


      
;***
;OTHER SUBROUTINES
;***        




;**************************************************************************
; SDA = HIGH ISR
;**************************************************************************
releaseSDA:  
	ST	#PCR_SUB,*AR2+                  ;Sub-bank address (SPSA0)=PCR0 
	ORM #K_DX_STAT_1, *AR2-			    ;Mask on DX_STAT BIT   
	NOP
	NOP
	RET
;**************************************************************************
; SDA = LOW ISR
;**************************************************************************
pullSDA: 
	ST	#PCR_SUB,*AR2+                  ;Sub-bank address (SPSA0)=PCR0 
    ANDM #K_DX_STAT_0,*AR2-             ;Mask off DX_STAT BIT
    NOP
    NOP
    RET            
;**************************************************************************
; SCL = HIGH ISR
;**************************************************************************
releaseSCL:  
	ST	#PCR_SUB,*AR2+                  ;Sub-bank address (SPSA0)=PCR0 
	ORM #K_FSRP_1,*AR2-			        ;Mask on FSR BIT   
    NOP
    NOP
	RET
;**************************************************************************
; SCL = LOW ISR
;**************************************************************************
pullSCL: 
	ST	#PCR_SUB,*AR2+                  ;Sub-bank address (SPSA0)=PCR0 
    ANDM #K_FSRP_0,*AR2-                ;Mask off FSR BIT
    NOP
    NOP
    RET                 
;**************************************************************************
;**************************************************************************

;**************************************************************************    
; SET MCBSP AS GPIO
;************************************************************************** 
_init_gpio:
	 NOP
	 PSHM  AR2
	 NOP
	 STM   #SPSA,AR2                    ;AR2 points to SPSA0

     ST    #SPCR2_SUB,*AR2+             ;Sub-bank address (SPSA0)=SPCR20
     ST    #0000000000000000b,*AR2-     ;
           ;~~~~~~~~~~~~~~~0 (XRST)     ;GPIO : transmitter is reset
      
     ST    #SPCR1_SUB,*AR2+             ;Sub-bank address (SPSA0)=SPCR20
     ST    #0000000000000000b,*AR2-     ;
           ;~~~~~~~~~~~~~~~0 (RRST)     ;GPIO : receiver set
    
     ST	  #PCR_SUB,*AR2+                ;Sub-bank address (SPSA0)=PCR0 
	 ST    #0011010100100101b,*AR2-     ;
           ;~~1~~~~~~~~~~~~~ (XIOEN)	;GPIO transmitter is enabled
           ;~~~1~~~~~~~~~~~~ (RIOEN)	;GPIO receiver is enabled
           ;~~~~0~~~~~~~~~~~ (FSXM)     ;FSX set as input 
           ;~~~~~1~~~~~~~~~~ (FSRM)     ;FSR set as output  
    	   ;~~~~~~~1~~~~~~~~ (CLKRM)	;CLKR set as output
    	   ;~~~~~~~~~~1~~~~~ (DX_STAT)  ;Release SDA line
    	   ;~~~~~~~~~~~~~1~~ (FSRP)	    ;Release SCL line
    	   ;~~~~~~~~~~~~~~~1 (CLKRP)    ;CLKR = 1
    
      NOP                               ;McBSP takes 2 clock cycle 
      NOP                               ;to start
      POPM	AR2
      NOP
      RET
;*************************************************************************
;*************************************************************************    


;*************************************************************************    
; INITIATE I2C
;*************************************************************************    
_init_i2c:      
	  NOP
	  PSHM	AR1
	  NOP
	  STM	#_I2CSTATUS,AR1
	  ST    #(K_RESET_I2C|K_CSDA_1|K_CSCL_1),*AR1+  ;I2CSTATUS
	  ST	#0,*AR1+   								;ODBYTECTR
	  ST	#7,*AR1+								;ODBITCTR
	  ST	#0,*AR1+   								;IDBYTECTR
	  ST	#7,*AR1+								;IDBITCTR
	  ST	#0,*AR1+   								;ERRORCODE  
	  ST	#K_SLAVEADDR,*AR1						;SLAVE_ADDR
      NOP
;************************************************************************    
; INIT TIMER  
;************************************************************************
      STM	#STOP_TIMER,TCR     ;stop timer
      STM	#K_PRD_VAL,PRD      ;load PRD
      STM	#START_TIMER,TCR    ;start timer
	  ORM	#0008H,*(IMR)       ;enable timer interrupt
   	  STM	#0FFFFH,IFR         ;clear any pending interrupts
      NOP
      POPM	AR1
      NOP
      RET
;***********************************************************************	
;***********************************************************************			

;***********************************************************************    
; INIT MASTER-TRANSMITTER PROCESS  
;***********************************************************************
_write_i2c:
	  NOP
	  PSHM	AR1
	  PSHM	AR2
	  NOP
	  STM	#_I2CSTATUS,AR1     ;Init i2cstatus register for write 
	  ST	#(K_START_1|K_WRITE_TO_SLAVE|K_ADDR_1|K_CSDA_1|K_CSCL_1),*AR1
      NOP
      STM	#_SLAVE_ADDR,AR1    ;1ST loc of ODPTR is slave address
      LD	*AR1,1,A            ;Shift slave address 1 place to the left
      ADD	#K_I2C_WRITE,A      ;Write mode of operation to LSB
      STM	#_ODPTR,AR2
      STL	A,*AR2              ;Store back to _ODPTR
      STM	#_ODBYTECTR,AR1
      ADDM	#1,*AR1             ;Add one more byte for slave address
      NOP
      POPM	AR2
      POPM	AR1
	  NOP      
	  RETE		
	  
;************************************************************************	
;************************************************************************			

;************************************************************************    
; INIT MASTER-RECEIVER PROCESS  
;************************************************************************
_read_i2c:
	  NOP      
	  PSHM	AR1
	  NOP
	  STM	#_I2CSTATUS,AR1     ;Init i2cstatus register for read 
	  ST	#(K_START_1|K_READ_FROM_SLAVE|K_ADDR_1|K_CSDA_1|K_CSCL_1),*AR1
      NOP
      STM	#_SLAVE_ADDR,AR1    ;1ST loc of ODPTR is slave address
      LD	*AR1,1,A            ;Shift slave address 1 place to the left
      ADD	#K_I2C_READ,A		;Write mode of operation to LSB
      STM	#_ODPTR,AR1         
      STL	A,*AR1              ;Store back to _ODPTR
      NOP
      STM	#_ODBYTECTR,AR1     ;Only 1 byte(slave addr) to be send
      ST	#2,*AR1				;Must store 1+1 num of bytes
                                
      NOP
      POPM	AR1
	  NOP
      RETE
	  
;************************************************************************    
;**************END*OF*FILE***********************************************    
;************************************************************************    

	.end
    
    

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?