📄 spdi2c.asm
字号:
mov bh, cl
mov cx, 00101h ; CH=send offset and CL=write 1 byte
jmp csI2C_Write
csWriteINDEXEDbyte ENDP
;**************************************************************************
;*
;* csWriteINDEXEDbyteStack
;*
;* This routine calls csWriteINDEXEDbyte (above) and saves/restores
;* registers. See above for details.
;*
;* Entry:
;* BL = chip address
;* CL = register address
;* AL = byte to write
;*
;* Exit:
;* CF=0 success BH = 0
;* CF=1 failure BH = ERROR
;* BH = 01h Invalid size ( CL = 0 )
;* BH = 02h I2C Comm Error
;* BH = 03h Buffer address wrap
;*
;* Destroys:
;* BH
;*
;**************************************************************************
csWriteINDEXEDbyteStack PROC NEAR PUBLIC
pushad
NOSTACK dx, csWriteINDEXEDbyte
; restore all while preserving BH
mov eax, DWORD PTR ss:[esp+16]
mov ah, bh
mov DWORD PTR ss:[esp+16], eax
popad
ret
csWriteINDEXEDbyteStack ENDP
;**************************************************************************
;*
;* csWriteI2CBlockStack
;*
;* See above csI2C_Write for details
;*
;* Entry:
;* CH = chip address
;* CL = register
;* DL = number of bytes to transfer
;* DS:SI = pointer to data to write to device
;*
;* Exit:
;* CF=0 success
;* CF=1 failure
;*
;* Destroys:
;* nothing only flags changed
;*
;**************************************************************************
csWriteI2CBlockStack PROC NEAR PUBLIC
pushad ; save all registers
push es
mov bh, cl ; Offset
mov bl, ch ; Address
mov ch, 001h ; Use offset flag
mov cl, dl ; # of bytes
mov di, si ; Buffer address
push ds
pop es
cmp dl, 4
ja csWIBS_Go
; 4 or less bytes, move data to EAX
mov eax, DWORD PTR es:[DI]
csWIBS_Go:
NOSTACK dx, csI2C_Write
; Restore Registers
; Update BH on the stack before restoring other registers
;mov eax, DWORD PTR ss:[esp+16]
;mov ah, bh
;mov DWORD PTR ss:[esp+16], eax
pop es
popad
ret
csWriteI2CBlockStack ENDP
;**************************************************************************
;*
;* csInitI2C
;*
;* (STACKLESS)
;*
;* 1) Call the Hook Procedure that sets up GPIO
;* 2) Initialize the I2C interface
;* a) SCL Out
;* b) SDA Out
;* c) SCL Low
;* d) SDA High
;* e) SCL High
;*
;* Entry:
;* SI = Return address
;*
;* Exit:
;* Destroys:
;* EAX, DX
;*
;**************************************************************************
csInitI2C PROC NEAR PUBLIC
; Set PCI Address register to point to 55x0 GPIO direction register
; and set DX to point to the PCI data register (CFCh)
;cli ; some platforms have problems with noise on interupt lines at power-on.
;Since this happens before an interupt code is initiazed this can cause teh system to crash.
mov dx, 0CF8h ; Point to PCI address register
mov eax, CX55x0_ID+090h ; 55XX GPIO direction register
out dx, eax
mov dl, 0FCh ; Point to PCI data register (CFCh)
;sti
; Initialize the I2C Interface
in ax, dx ; Drive SDA High
or ah, SDA
out dx, ax
in ax, dx ; Drive SCL High
or ah, SCL
out dx, ax
in al, dx ; Make SCL GPIO an output
or al, SCL
out dx, al
in al, dx ; Make SDA GPIO an output
or al, SDA
out dx, al
jmp si ; Return to calling address
csInitI2C ENDP
;**************************************************************************
;*
;* csInitI2CStack
;*
;* Initialize the I2C interface (calls stackless version)
;*
;* Entry:
;* Exit:
;* Destroys:
;* Nothing
;*
;**************************************************************************
csInitI2CStack PROC NEAR PUBLIC
push esi
push eax
push edx
NOSTACK si, csInitI2C ; Call stackless version
pop edx
pop eax
pop esi
ret
csInitI2CStack ENDP
;**************************************************************************
;*
;* csStartCondition
;*
;* (STACKLESS)
;*
;* This routine triggers the start condition on the I2C bus.
;*
;* Entry:
;* SI = Return Address
;*
;* Exit:
;*
;* Destroys:
;* AX, DX
;*
;**************************************************************************
csStartCondition PROC NEAR
in ax, dx ; Drive SDA and SCL High
or ah, SDA
or ah, SCL
out dx, ax
IOPAUSE
IOPAUSE
IOPAUSE
in al, dx ; Make SDA an output
or al, SDA
out dx, al
IOPAUSE
IOPAUSE
IOPAUSE
in ax, dx ; Drive SDA Low
and ah, NOT SDA
out dx, ax
IOPAUSE
IOPAUSE
IOPAUSE
IOPAUSE
IOPAUSE
IOPAUSE
in ax, dx ; Drive SCL Low
and ah, NOT SCL
out dx, ax
clc
jmp si
csStartCondition ENDP
;**************************************************************************
;*
;* csStopCondition
;*
;* (STACKLESS)
;*
;* This routine triggers the stop condition on the I2C bus.
;*
;* Entry:
;* SI = Return Address
;*
;* Exit:
;*
;* Destroys
;* AX, DX
;*
;**************************************************************************
csStopCondition PROC NEAR
in al, dx ; Make SDA an output
or al, SDA
out dx, al
in ax, dx ; Drive SCL Low
and ah, NOT SCL
out dx, ax
IOPAUSE
IOPAUSE
IOPAUSE
IOPAUSE
in ax, dx ; Drive SDA Low
and ah, NOT SDA
out dx, ax
IOPAUSE
IOPAUSE
IOPAUSE
IOPAUSE
in ax, dx ; Drive SCL High
or ah, SCL
out dx, ax
IOPAUSE
IOPAUSE
IOPAUSE
IOPAUSE
in ax, dx ; Drive SDA High
or ah, SDA
out dx, ax
IOPAUSE
IOPAUSE
IOPAUSE
IOPAUSE
clc
jmp si
csStopCondition ENDP
;**************************************************************************
;*
;* csWriteI2CData
;*
;* (STACKLESS)
;*
;* This routine writes the 8-bit value in BL to the I2C bus.
;*
;* Entry:
;* BL = data value
;* SI = return address
;*
;* Exit:
;* Carry flag set as follows
;* Set = acknowledge bit = 1
;* Clr = acknowledge bit = 0
;*
;* Destroys
;* AX, BL, CX, DX
;*
;**************************************************************************
csWriteI2CData PROC NEAR
in ax, dx ; Drive SCL Low
and ah, NOT SCL
out dx, ax
IOPAUSE
IOPAUSE
IOPAUSE
IOPAUSE
IOPAUSE
in al, dx ; Make SDA an output
or al, SDA
out dx, al
IOPAUSE
IOPAUSE
IOPAUSE
mov cx, 8 ; 8 bits to send
SetI2CDataBitLoop:
test bl, 80h ; Check data bit
jz SetI2CDataBitLow ; Branch if low
in ax, dx ; Drive SDA High
or ah, SDA
out dx, ax
IOPAUSE
IOPAUSE
IOPAUSE
IOPAUSE
IOPAUSE
jmp SetI2CDataBitClock
SetI2CDataBitLow:
in ax, dx ; Drive SDA Low
and ah, NOT SDA
out dx, ax
IOPAUSE
IOPAUSE
IOPAUSE
IOPAUSE
IOPAUSE
SetI2CDataBitClock:
in ax, dx ; Drive SCL High
or ah, SCL
out dx, ax
IOPAUSE
IOPAUSE
IOPAUSE
IOPAUSE
IOPAUSE
in ax, dx ; Drive SCL Low
and ah, NOT SCL
out dx, ax
IOPAUSE
IOPAUSE
IOPAUSE
IOPAUSE
IOPAUSE
shl bl, 1 ; Justify next bit
loop SetI2CDataBitLoop ; Next bit
in ax, dx ; Drive SDA High when done
or ah, SDA
out dx, ax
in al, dx ; Set SDA as input to check ACK
and al, NOT SDA
out dx, al
IOPAUSE
IOPAUSE
IOPAUSE
IOPAUSE
IOPAUSE
in ax, dx ; Clock in ACK
or ah, SCL ; Drive SCK high
out dx, ax
IOPAUSE
IOPAUSE
IOPAUSE
IOPAUSE
IOPAUSE
in ax, dx ; Read SDA (ACK)
shr ax, 8
mov cl, al ; Save the reading of ACK bit
in ax, dx ; Drive SCK Low
and ah, NOT SCL
out dx, ax
IOPAUSE
IOPAUSE
IOPAUSE
IOPAUSE
IOPAUSE
mov al, cl ; Retrieve save ACK value
test al, NOACK ; Make sure ACK was driven low
stc
jnz NoAckRcvd
clc
NoAckRcvd:
jmp si
csWriteI2CData ENDP
;**************************************************************************
;*
;* csReadI2CData
;*
;* (STACKLESS)
;*
;* This routine reads an 8-bit value from the I2C bus
;* This is a wrapper for the generic read
;*
;* Entry:
;* SI = return address
;*
;* Exit:
;* BL = data value
;* DI = 0 (ACK_FLAG clear)
;*
;* Destroys:
;* AX, BX, CX, DX, DI
;*
;**************************************************************************
csReadI2CData PROC NEAR
mov di, 0000h ; Say we don't want an acknowledge
jmp csRealReadI2CData
csReadI2CData ENDP
;**************************************************************************
;*
;* csReadAckI2CData
;*
;* (STACKLESS)
;*
;* This routine reads an 8-bit value from the I2C bus with acknowledge
;* This is a wrapper for the generic read
;*
;* Entry:
;* SI = return address
;*
;* Exit:
;* BL = data value
;* DI = ACK_FLAG
;*
;* Destroys:
;* AX, BX, CX, DX, DI
;*
;**************************************************************************
csReadAckI2CData PROC NEAR
mov di, ACK_FLAG ; Say we want an acknowledge
jmp csRealReadI2CData
csReadAckI2CData ENDP
;**************************************************************************
;*
;* csRealReadI2CData
;*
;* (STACKLESS)
;*
;* This routine reads an 8-bit value from the I2C bus
;*
;* Entry:
;* SI = return address
;* DI = acknowledge flag
;* 0000 = No acknowledge
;* ACK_FLAG = Acknowledge
;*
;* Exit:
;* BL = data value
;*
;* Destroys:
;* AX, BX, CX, DX
;*
;**************************************************************************
csRealReadI2CData PROC NEAR
in ax, dx ; Drive SCL Low
and ah, NOT SCL
out dx, ax
in al, dx ; Make SDA an input
and al, NOT SDA
out dx, al
mov cx, 8 ; 8 bits to read
mov bl, 0 ; Clear out BL
csGetI2CDataBitLoop:
shl bl, 1 ; Align Next Bit
IOPAUSE
IOPAUSE
IOPAUSE
IOPAUSE
IOPAUSE
in ax, dx ; Drive SCL High
or ah, SCL
out dx, ax
IOPAUSE
IOPAUSE
IOPAUSE
IOPAUSE
IOPAUSE
in ax, dx
shr ax, 8 ; Use AH
test al, SDA ; Data Low?
jz csGetI2CDataBitLow ; Yes, leave bit (0)
or bx, 01h ; No, OR in bit (1)
csGetI2CDataBitLow:
in ax, dx ; Drive SCL Low
and ah, NOT SCL
out dx, ax
loop csGetI2CDataBitLoop ; Next bit
IOPAUSE
IOPAUSE
IOPAUSE
IOPAUSE
IOPAUSE
test di, ACK_FLAG ; Do we need to ACK?
jz @f ; No, skip it
; Start ACK cycle
in al, dx ; Make SDA an output
or al, SDA
out dx, al
in ax, dx ; Drive SDA Low to start ACK
and ah, NOT SDA
out dx, ax
; Go ahead and toggle the clock
@@:
in ax, dx ; Drive SCL High
or ah, SCL
out dx, ax
IOPAUSE
IOPAUSE
IOPAUSE
IOPAUSE
IOPAUSE
in ax, dx ; Drive SCL Low
and ah, NOT SCL
out dx, ax
IOPAUSE
IOPAUSE
IOPAUSE
IOPAUSE
IOPAUSE
test di, ACK_FLAG ; Do we need to ACK?
jz @f ; No, skip it
; End ACK cycle
in ax, dx ; Drive SDA High to end ACK
or ah, SDA
out dx, ax
IOPAUSE
IOPAUSE
IOPAUSE
IOPAUSE
@@:
clc ; Clear Carry Flag
jmp si ; Return to calling address
csRealReadI2CData ENDP
_TEXT ENDS
END
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -