|
![](static/image/common/ico_lz.png)
楼主 |
发表于 2007-8-30 14:03:40
|
显示全部楼层
库文件源代码:
基本上使用ASM写的,看不明白,晕~~~~~~~~~~~~
Copyright = Mcs Electronics
Www = Http : / / Www.mcselec.com
Email = Avr@mcselec.com
Comment = I2c Soft Slave Library
Libversion = 1.11.6.8
Date = 2 April 2002
Statement = No Source Code From The Library May Be Distributed In Any Form
Statement = Of Course This Does Not Applies For The Compiled Code When You Have A Bascom -avr License
Statement = It Is Not Allowed To Use The Asm In Any Other Development Tool Other Than Bascom !
Statement = Based On Atmel An 302. An302 Contained Some Bugs.
History = No Known Bugs.
[_i2c_slave]
;This modules contains all the I2C slave code
;Init is done in the BASIC program
;***************************************************************************
;*
;* FUNCTION
;* i2c_init
;*
;* DESCRIPTION
;* Initialization of interrupts and port used by the I2C interface
;* and waits for the first start condition.
;*
;* USAGE
;* Jump to this code directly after a reset.
;*
;* RETURN
;* none
;*
;***************************************************************************
_i2c_slave_init:
;**** PORT Initialization ****
* Cbi _i2c_slave_ddr , _i2c_slave_sda
; Initialize INT0 for open colector operation (SDA in/out)
* Cbi _i2c_slave_ddr , _i2c_slave_scl
; Initialize (T0) for open colector operation (SCL in/out)
* Cbi _i2c_slave_port , _i2c_slave_sda
* Cbi _i2c_slave_port , _i2c_slave_scl
;**** Interrupt Initialization ****
* Basic : Config Int0 = Falling
; Set INT0 to generate an interrupt on falling edge
; Enable INT0
* Basic : Enable Int0
; Set clock to count on falling edge of T0
* Basic : Config Timer0 = Counter , Edge = Falling
Sei ; enable interrupts
Ret
;Int0 interrupt
_i2c_slave_int0:
push r24 ; save reg
* In R24 , Sreg ; Get Sreg
push r24 ; save used register
push r25
push r16
push r17
; Get I2C Slave Address *
I2c_get_adr:
ldi R17,1 ; initialize address register
Wlo_ga0:
* Sbic _i2c_slave_pin , _i2c_slave_scl ; Wait For Scl Low
rjmp wlo_ga0
rjmp first_ga
Do_ga : ; Do
Wlo_ga:
* Sbic _i2c_slave_pin , _i2c_slave_scl ; Wait For Scl Low
rjmp wlo_ga
First_ga:
sec ; set carry
Whi_ga:
* Sbis _i2c_slave_pin , _i2c_slave_scl ; Wait For Scl High
rjmp whi_ga
* Sbis _i2c_slave_pin , _i2c_slave_sda ; If Sda Low
clc ; clear carry
rol R17 ; shift carry into address register
brcc do_ga ; while register not full
Wlo_ca:
* Sbic _i2c_slave_pin , _i2c_slave_scl ; Wait For Scl Low
rjmp wlo_ca
mov r24,R17 ; get copy of slave address
* Sts {_i2c_slave_address_received} , R24 ; Store For The User
* Lds R25 , {_i2c_slave_address} ; Load The Specified Slave Address
Andi r24,254 ; remove read/write bit
Cp r24,r25 ; compare with slave address
breq i2c_adr_ack ; does it match?
rjmp i2c_adr_miss ; no, goto address miss handle
;**** Acknowledge Address ****
I2c_adr_ack:
* Sbi _i2c_slave_ddr , _i2c_slave_sda ; Assert Acknowledge On Sda
Whi_aa:
* Sbis _i2c_slave_pin , _i2c_slave_scl ; Wait For Scl High
rjmp whi_aa
;**** Check Transfer Direction ****
lsr R17 ; if master write
brcc i2c_master_write ; goto master write handle
;* Transmit Data (master read) *
I2c_master_read:
* Sbi _i2c_slave_ddr , _i2c_slave_scl ; Start Wait State
@genus(100)
Call I2c_master_needs_data ; Call User Program To Get A Byte
sec ; shift MSB out and "floating empty flag" in
rol R16
* Cbi _i2c_slave_ddr , _i2c_slave_scl ; End Wait State
Wlo_mr:
* Sbic _i2c_slave_pin , _i2c_slave_scl ; Wait For Scl Low
rjmp wlo_mr
;**** Transmitt data ****
brcc fb_low_mr ; if current data bit high
* Cbi _i2c_slave_ddr , _i2c_slave_sda ; Release Sda
rjmp fb_mr ; goto read loop
Fb_low_mr:
* Sbi _i2c_slave_ddr , _i2c_slave_sda ; Force Sda
Fb_mr:
lsl R16 ; if data register not empty
Loop_mr:
Whi_mr:
* Sbis _i2c_slave_pin , _i2c_slave_scl ; Wait For Scl High
rjmp whi_mr
Wlo_mr2:
* Sbic _i2c_slave_pin , _i2c_slave_scl ; Wait For Scl Low
rjmp wlo_mr2
brcc b_low_mr ; if current data bit high
* Cbi _i2c_slave_ddr , _i2c_slave_sda ; Release Sda
lsl R16 ; if data register not empty
brne loop_mr ; loop
rjmp done_mr ; done
B_low_mr:
* Sbi _i2c_slave_ddr , _i2c_slave_sda ; Force Sda
lsl R16 ; if data register not empty
brne loop_mr ; loop
Done_mr:
Whi_mr2:
* Sbis _i2c_slave_pin , _i2c_slave_scl ; Wait For Scl High
rjmp whi_mr2
Wlo_mr3:
* Sbic _i2c_slave_pin , _i2c_slave_scl ; Wait For Scl Low
rjmp wlo_mr3
* Cbi _i2c_slave_ddr , _i2c_slave_sda ; Release Sda
;**** Read Acknowledge from Master ****
Whi_ra:
* Sbis _i2c_slave_pin , _i2c_slave_scl ; Wait For Scl High
rjmp whi_ra
sec ; read acknowledge
* Sbis _i2c_slave_pin , _i2c_slave_sda
clc
brcc i2c_master_read ; if ack transfer (next) data
Wlo_ra:
* Sbic _i2c_slave_pin , _i2c_slave_scl ; Wait For Scl Low
rjmp wlo_ra
rjmp i2c_wait_cond ; goto wait condition (rep. start or stop)
;*******************************
;* Receive Data (master write) *
;*******************************
I2c_master_write:
Wlo_mw0:
* Sbic _i2c_slave_pin , _i2c_slave_scl ; Wait For Scl Low
rjmp wlo_mw0
* Cbi _i2c_slave_ddr , _i2c_slave_sda ; Remove Acknowledge From Sda
Whi_mw:
* Sbis _i2c_slave_pin , _i2c_slave_scl ; Wait For Scl High
rjmp whi_mw
* In R24 , _i2c_slave_pin ; Sample Sda(first Bit) And Scl
* Andi R24 , _i2c_pinmask ; Mask Out Sda And Scl
Do_mw:
* In R25 , _i2c_slave_pin ; New Sample
* Andi R25 , _i2c_pinmask ; Mask Out Sda And Scl
cp r25,r24
breq do_mw ; while no change
* Sbrs R25 , _i2c_slave_scl ; If Scl Changed To Low
rjmp receive_data ; goto receive data
* Sbrs R25 , _i2c_slave_sda ; If Sda Changed To Low
rjmp i2c_get_adr ; goto repeated start
rjmp i2c_slave_stop ; goto transfer stop
Receive_data:
ldi R16,2 ; set R16 MSB to zero
* Sbrc R24 , _i2c_slave_sda ; If Sda Sample Is One
ldi R16,3 ; set R16 MSB to one
Do_rd:
Wlo_rd:
* Sbic _i2c_slave_pin , _i2c_slave_scl ; Wait For Scl Low
rjmp wlo_rd
sec ; set carry
Whi_rd:
* Sbis _i2c_slave_pin , _i2c_slave_scl ; Wait For Scl High
rjmp whi_rd
* Sbis _i2c_slave_pin , _i2c_slave_sda ; If Sda Low
clc ; clear carry
rol R16 ; shift carry into data register
brcc do_rd ; while register not full
;**** Acknowledge Data ****
I2c_dat_ack:
Wlo_da:
* Sbic _i2c_slave_pin , _i2c_slave_scl ; Wait For Scl Low
rjmp wlo_da
* Sbi _i2c_slave_ddr , _i2c_slave_sda ; Assert Acknowledge On Sda
Whi_da:
* Sbis _i2c_slave_pin , _i2c_slave_scl ; Wait For Scl High
rjmp whi_da
;**** Store Data (handle incoming data) ****
* Sbi _i2c_slave_ddr , _i2c_slave_scl ;(start Wait State)
@genus(100)
Call I2c_master_has_data ; Call User Program To Inform We Received A Byte
* Cbi _i2c_slave_ddr , _i2c_slave_scl ;(end Wait State)
rjmp i2c_master_write ; Start on next transfer
;timer0 interrupts
_i2c_slave_timer0:
;* This interrupt handles a "address miss". If the slave device is
;* not addressed by a master, it will not acknowledge the address.
;*
;* Instead of waiting for a new start condition in a "busy loop"
;* the slave set up the counter to count 8 falling edges on SCL and
;* returns from the current interrupt. This "skipping" of data
;* do not occupies any processor time. When 8 egdes are counted, a
;* timer overflow interrupt handling routine (this one) will check
;* the next condition that accure. If its a stop condition
;* the transfer ends, if its a repeated start condition a jump
;* to the i2c_wakeup interrupt will read the new address. If a new
;* transfer is initiated the "skipping" process is repeated.
;*
* Push R24 ; Save Reg
* In R24 , Sreg ; Get Sreg
push r24 ; save used register
push r25
push r16
push r17
I2c_adr_miss:
;**** Drop Acknowledge ****
Whi_dac:
* Sbis _i2c_slave_pin , _i2c_slave_scl ; Wait For Scl High
rjmp whi_dac
Wlo_dac:
* Sbic _i2c_slave_pin , _i2c_slave_scl ; Wait For Scl Low
rjmp wlo_dac
* Basic : Disable Timer0
* Basic : Enable Int0
;************************
;* Wait for a Condition *
;************************
I2c_wait_cond:
Whi_wc:
* Sbis _i2c_slave_pin , _i2c_slave_scl ; Wait For Scl High
rjmp whi_wc
* In R24 , _i2c_slave_pin ; Sample Sda(first Bit) And Scl
* Andi R24 , _i2c_pinmask ; Mask Out Sda And Scl
Do_wc:
* In R25 , _i2c_slave_pin ; New Sample
* Andi R25 , _i2c_pinmask ; Mask Out Sda And Scl
cp r25,r24
breq do_wc ; while no change
* Sbrs R25 , _i2c_slave_scl ; If Scl Changed To Low
rjmp i2c_skip_byte ; goto skip byte
* Sbrs R25 , _i2c_slave_sda ; If Sda Changed To Low
rjmp i2c_get_adr ; goto repeated start
;*************************
;* Handle Stop Condition *
;*************************
I2c_slave_stop:
; Set INT0 to generate an interrupt on low level,
* Basic : Config Int0 = Low Level
; then set INT0 to generate an interrupt on falling edge.
* Basic : Config Int0 = Falling
;This will clear the EXT_INT0 request flag.
I2c_exit:
pop r17 ; restore used registers
pop r16
pop r25
pop r24
* Out Sreg , R24
pop r24
Reti ; return from int
;****************
;* Skip byte(s) *
;****************
I2c_skip_byte:
ldi r24,-7
* Out Tcnt0 , R24
* Basic : Enable Timer0
; enable timer 0 overflow interrupt
* Basic : Disable Int0
rjmp i2c_exit ; return from int
[end] |
|