Code:
; This program emulates an I2C bus expander PCF8574 on address 0x40.
; Fuses:
; RSTDISBL programmed (0) - External Reset disabled
; BODEN unprogrammed (1) - Brown out detector disabled
; PLLCK unprogrammed (1) - PLL disabled
; CKOPT unprogrammed (1) - internal capacitors for an Xtal oscillator disabled
; SUT=10 - long start-op time 65ms
; CKSEL=0100 - Internal RC Oscillator 8MHz
.include "tn26def.inc"
; port A - parallel data
; port B
.equ SDA =0
.equ PAR_STROBE =1 ;control
.equ SCL =2
.equ PAR_ERROR =3 ;status
.equ PAR_INIT =4 ;control
.equ PAR_BUSY =5 ;status
.equ PAR_ACK =6 ;status
.def Flags =r16
; meaning of individual bits
.equ START_DETECTED =7 ;set by the USI Start handler when the start
;condition detected
.def Temp1 =r17 ;local temporary variable
.def DeviceAddress =r18
.org 0x0000
rjmp reset ;Reset handler
reti ;IRQ0 handler
reti ;Pin change handler
reti ;Timer1 compare match 1A
reti ;Timer1 compare match 1B
reti ;Timer1 overflow handler
reti ;Timer0 overflow handler
rjmp usi_strt ;USI Start handler
reti ;USI Overflow handler
reti ;EEPROM Ready handler
reti ;Analog Comparator handler
reti ;ADC Conversion Handler
reset: ldi Temp1,RAMEND
out SP,Temp1
ldi Temp1,0x00
out PORTA,Temp1
out DDRA,Temp1
out PORTB,Temp1
out DDRB,Temp1
; USI settings:
; Start Condition Interrupt Enable
; Counter Overflow Interrupt Enable
; Two-wire mode
; Shift Register Clock Source - External, positive edge
; 4-bit Counter Clock Source - External, both edges
ldi Temp1,(1<<USISIE)+(0<<USIOIE)+(1<<USIWM1)+(0<<USIWM0)+(1<<USICS1)+(0<<USICS0)+(0<<USICLK)
out USICR,Temp1
sei
main_loop: cbi DDRB,SDA
cbr Flags,(1<<START_DETECTED)
ldi Temp1,(1<<USIPF)
out USISR,Temp1
; wait for the start condition
main_1: sbrs Flags,START_DETECTED
rjmp main_1
; start condition detected
start_cond: cbr Flags,(1<<START_DETECTED)
ldi Temp1,(1<<USIOIF)+0x0F ;1 SCL edge
out USISR,Temp1
; skip the first falling SCL edge after the start condition
main_2: ; sbic USISR,USIPF ;stop condition detected?
; rjmp main_loop
sbrc Flags,START_DETECTED ;start condition detected?
rjmp start_cond
sbis USISR,USIOIF
rjmp main_2
ldi Temp1,(1<<USIOIF)+0x00 ;10 SCL edges
out USISR,Temp1
; wait until the master sends the Device Address
main_3: ; sbic USISR,USIPF ;stop condition detected?
; rjmp main_loop
sbrc Flags,START_DETECTED ;start condition detected?
rjmp start_cond
sbis USISR,USIOIF
rjmp main_3
in DeviceAddress,USIDR
mov Temp1,DeviceAddress
andi Temp1,0xFE ;ignore the R/W bit
cpi Temp1,0x40 ;PCF8574 device address
brne main_loop
; valid Device Address received from the master,
; read or write?
sbrc DeviceAddress,0 ;R/W bit
rjmp read
; prepare the ATtiny26 to send the ACK bit to the master
write_loop: ldi Temp1,(1<<USIOIF)+0x0E ;2 SCL edges
out USISR,Temp1
cbi PORTB,SDA
sbi DDRB,SDA
; wait until the master reads the ACK bit
write_1: sbis USISR,USIOIF
rjmp write_1
cbi DDRB,SDA
; the master sends data to the ATtiny26
ldi Temp1,(1<<USIOIF)+0x00 ;16 SCL edges
out USISR,Temp1
ldi Temp1,0 ;ACK=0
out USIDR,Temp1 ;bit 0 will be send as ACK
; wait until the master sends the Data Byte
write_2: ; sbic USISR,USIPF ;stop condition detected?
; rjmp main_loop
sbrc Flags,START_DETECTED ;start condition detected?
rjmp start_cond
sbis USISR,USIOIF
rjmp write_2
in Temp1,USIDR
com Temp1
out DDRA,Temp1
rjmp write_loop
; prepare the ATtiny26 to receive the ACK bit from the master
read: ldi Temp1,(1<<USIOIF)+0x0E ;2 SCL edges
out USISR,Temp1
cbi PORTB,SDA
sbi DDRB,SDA
; wait until the master reads the ACK bit
read_1: sbis USISR,USIOIF
rjmp read_1
;
; the master reads data from the ATtiny26
read_loop: in Temp1,PINA
out USIDR,Temp1
ldi Temp1,(1<<USIOIF)+0x00 ;16 SCL edges
out USISR,Temp1
sbi PORTB,SDA
sbi DDRB,SDA
; wait until the master reads the Data Byte
read_2: sbis USISR,USIOIF
rjmp read_2
cbi DDRB,SDA
; prepare the ATtiny26 to receive the ACK bit from the master
ldi Temp1,(1<<USIOIF)+0x0E ;2 SCL edges
out USISR,Temp1
; wait until the master sends the ACK bit
read_3: ; sbic USISR,USIPF ;stop condition detected?
; rjmp main_loop
sbrc Flags,START_DETECTED ;start condition detected?
rjmp start_cond
sbis USISR,USIOIF
rjmp read_3
in Temp1,USIDR
sbrs Temp1,0 ;test the ACK bit
rjmp read_loop
; no acknowledge, wait for a stop or start condition
read_4: ; sbic USISR,USIPF ;stop condition detected?
; rjmp main_loop
sbrc Flags,START_DETECTED ;start condition detected?
rjmp start_cond
rjmp read_4
; USI Start handler - called when the start condition detected
usi_strt: push Temp1
in Temp1,SREG
push Temp1
ldi Temp1,(1<<USISIF)
out USISR,Temp1
sbr Flags,(1<<START_DETECTED)
pop Temp1
out SREG,Temp1
pop Temp1
reti
Grüße
Lesezeichen