;*************************************************** ; Test TWI via USI-Interface ; MCU: ATMEL ATtiny4313 ; Clock: 4 MHz ; TWI/I2C-PortB PB7=SCL; PB5=SDA ; LCD: 4x20 SainSmart2004; HD44780 compatible ; P7 P6 P5 P4 P3 P2 P1 P0 ; D7 D6 D5 D4 LED ENA R|W RS ; Device slave address: $38 (PCF8574A) ;ATtiny2313 memory use summary [bytes]: ;Segment Begin End Code Data Used Size Use% ;[.cseg] 0x000000 0x000318 722 70 792 2048 38.7% ;[.dseg] 0x000060 0x000060 0 0 0 128 0.0% ;[.eseg] 0x000000 0x000000 0 0 0 128 0.0% ;Assembly complete, 0 errors. 0 warnings ; ; Rev.: 23022026 ;*************************************************** ; ;Assembler direktives: ; .nolist .include "tn4313def.inc" .list ; ; ; SRAM Definitions: ; .dseg ; Datasegment (SRAM) Start on .org 0x0060 ; address 0x0060 ; ; ; Constants: .equ daten = portb .equ delay0 = 1000 .equ delay1 = 65535 ; ; ; Register synonyma: .def inttemp = r12 ; backup register for Interrupt-Routines .def intreg = r14 ; backup register for SREG on ISRs .def temp = r16 ; universal register for arithmetcs .def temp1 = r17 .def temp2 = r18 .def temp3 = r19 ; .cseg ; Codesegment .org 0x0000 ; Start address rjmp reset ; Interrupt vektors jump into addresses (default) ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - .org 0x0001 ; ext IRQ0 edge rjmp INT00 .org 0x0002 ; ext IRQ1 edge rjmp INT10 .org 0x0003 ; Timer 1 capt rjmp ICP10 .org 0x0004 ; Timer 1 comp match A rjmp OC100 .org 0x0005 ; Timer 1 overflow rjmp OVF10 .org 0x0006 ; Timer 0 overflow rjmp OVF00 .org 0x0007 ; UART Receive Complete rjmp URXC0 .org 0x0008 ; UART Data Register Empty rjmp UDRE0 .org 0x0009 ; UART Transmit Complete rjmp UTXC0 .org 0x000A ; Analog Comparator Interrupt rjmp ACI00 .org 0x000B ; Pin Change Interrupt Request B rjmp PCIBA .org 0x000C ; Timer 1 comp match B rjmp OC1BA .org 0x000D ; Timer 0 comp match A rjmp OC0AA .org 0x000E ; Timer 0 comp match B rjmp OC0BA .org 0x000F ; USI Start Condition rjmp USIST .org 0x0010 ; USI Overflow rjmp USIOV .org 0x0011 ; Eprom read ready rjmp ERDYA .org 0x0012 ; Watchdog Timer Overflow rjmp WDTAD .org 0x0013 ; Pin Change Interrupt Request A rjmp PCIAA .org 0x0014 ; Pin Change Interrupt Request D rjmp PCIDA ; ;Interrupt Service Routines - Interrupt Handler ;- - - - - - - - - - - - - - - - - - - - - - - - - INT00: ; ISR not in use reti INT10: ; ISR not in use reti ICP10: ; ISR not in use reti OC100: ; ISR not in use reti OVF10: ; ISR not in use reti OVF00: ; ISR not in use reti URXC0: ; ISR not in use reti UDRE0: ; ISR not in use reti UTXC0: ; ISR not in use reti ACI00: ; ISR not in use reti PCIBA: ; ISR not in use reti OC1BA: ; ISR not in use reti OC0AA: ; ISR not in use reti OC0BA: ; ISR not in use reti USIST: ; ISR not in use reti USIOV: ; ISR not in use reti ERDYA: ; ISR not in use reti WDTAD: ; ISR not in use reti PCIAA: ; ISR not in use reti PCIDA: ; ISR not in use reti ; reset: cli ; disable all interrupts ldi temp, low(ramend) ; Stackpointer set up out spl, temp ldi temp, high(ramend) ; only,when using ATtiny4313 out sph, temp rcall regclr ; register reset rcall portinit ; init I/O-Ports rcall twimain ; TWI/I2C-Setup rcall lcdinit ; LCD-initialization sei ; enable all interrupts again rjmp main ; jump to main program ; regclr: ; set all registers to zero clr inttemp clr intreg ldi temp, 0x00 ldi temp1, 0x00 ldi temp2, 0x00 ldi temp3, 0x00 ret ; portinit: ; Init I/O-Ports ldi temp, 0xFF ; PortB output TWI out ddrb, temp out portb, temp out ddrd, temp ldi temp, 0xFF out portd, temp ret ; main: ; Main program rcall text_1 rcall text_2 rcall text_3 rcall text_4 push temp ldi temp, 0b00000001 rcall cmd2lcd pop temp rjmp endless ; endless: ; Endless loop rcall text_5 rjmp endless ; text_1: ; call table "Text1" ldi temp, 0x80 ; locate lcd... rcall cmd2lcd ; ...row 1, column 1 rcall wait2 ldi ZL, LOW(text1*2) ; load strings' address ldi ZH, HIGH(text1*2) ; into Z-pointer rcall print ; call function print rcall wait2 ret ; text_2: ; call table "Text2" ldi temp, 0xC0 ; locate lcd... rcall cmd2lcd ; ...row 2, column 1 rcall wait2 ldi ZL, LOW(text2*2) ; load strings' address ldi ZH, HIGH(text2*2) ; into Z-pointer rcall print ; call function print rcall wait2 ret ; text_3: ; call table "Text3" ldi temp, 0x94 ; locate lcd... rcall cmd2lcd ; ...row 3, column 1 rcall wait2 ldi ZL, LOW(text3*2) ; load strings' address ldi ZH, HIGH(text3*2) ; into Z-pointer rcall print ; call function print rcall wait2 ret ; text_4: ; call table "Text4" ldi temp, 0xD4 ; locate lcd... rcall cmd2lcd ; ...row 4, column 1 rcall wait2 ldi ZL, LOW(text4*2) ; load strings' address ldi ZH, HIGH(text4*2) ; into Z-pointer rcall print ; call function print rcall wait2 ret ; text_5: ; call table "Text5" ldi temp, 0x80 ; locate lcd... rcall cmd2lcd ; ...row 4, column 1 rcall wait2 ldi ZL, LOW(text5*2) ; load strings' address ldi ZH, HIGH(text5*2) ; into Z-pointer rcall print ; call function print rcall wait1 ret ; print: lpm ; read table's first byte towards R0 mov temp, r0 ; testing "0" on R0 cpi temp, 0x00 ; you may use command "tst" instead of breq print_end ; if "0", then jump to "print_end" mov temp1, temp ; copy for output register in use rcall char2lcd ; call lcd output routine adiw ZL:ZH, 1 ; increment Z-pointer rjmp print ; jump to start to take next byte ; ; from table print_end: ; ending for table routine rcall wait3 ret ; text1: ; constants of tables, zero terminated .db "$80-ATMEL ATtiny4313 ",0 ; text2: .db "$C0- SainSmart2004 ",0 ; text3: .db "$94- TWI/I2C ",0 ; text4: .db "$D4- via USI ",0 ; text5: .db "Eingabe:_____ ",0 ;- - - - Delay routines - - - - - - - ; wait1: rcall wait3 nop rcall wait3 ret ; wait2: ; delay loop 2: push yl ; save registers to stack... push yh push temp push temp1 push temp2 in temp2, SREG ; ...status register, too push temp2 ldi yl, low(delay0) ; load constant into 16 bit register ldi yh, high(delay0) ; using previous declared "delay0" rjmp repeatx ; jump to shared subroutine ; wait3: ; delay loop 3: push yl ; save registers to stack... push yh push temp push temp1 push temp2 in temp2, SREG ;...status register, too push temp2 ldi yl, low(delay1) ; load constant into 16 bit register ldi yh, high(delay1) ; using previous declared "delay1" rjmp repeatx ; jump to shared counter subroutine ; repeatx: ; 16 Bit subtracting routine: sbiw yl:yh, 1 ; decrements register pair brne repeatx ; counts to zero pop temp2 ; reestablish all on stack saved registers out SREG, temp2 pop temp2 pop temp1 pop temp pop yh pop yl ret ; ; TWI/I2C Routines via USI Interface (ATtiny2313/4313) ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - twimain: cli rcall twiinit rcall twistart ldi temp, 0x70 ; address contains A0,A1,A2=GND + R/W-Bit (W=0; R=1) rcall twiout brts end ; if NACK (T-flag in SREG previous set to H), ret ; then jump to end ; end: rjmp endless ; twiinit: sbi portb, 7 ; SCL high sbi portb, 5 ; SDA high sbi ddrb, 7 ; PortB7 (SCL) configured as output sbi ddrb, 5 ; PortB5 (SDA) configured as output ldi temp, 0xFF out USIDR, temp ; fill up data register with ones completely ldi temp, 0x20 ; (1<no TWI clock out USICR,temp ret ; twidown: clr temp out USICR, temp ; set off USI-function, PortB5, PortB7 use as normal ret ; twistop: cbi portb, 5 ; SDA->L cbi USIDR, 7 ; data register MSB->L nop nop nop nop nop sbi portb, 7 ; SCL->H ; twistop1: sbis pinb, 7 ; wait for SCL=H rjmp twistop1 sbi portb, 5 sbi USIDR, 7 ; SDA->H ret ; twistart: sbi portb, 5 ; SDA->H sbi USIDR, 7 ; data register MSB->H nop nop nop sbi portb, 7 ; SCL->H ; twistart1: sbis pinb, 7 ; wait for SCL=H rjmp twistart1 ; cbi USIDR, 7 ; data register MSB->L nop nop nop cbi portb, 7 ; SCL->L nop nop nop nop nop ret ; twiout: ; send slave's address together with R/W-Bit on temp push temp push temp1 out USIDR, temp ; addresse/data in data register ldi temp, 0xF8 ; reset USI-status register IR-Flags, counter on 8 out USISR,temp ; (1<H (USI clock toggle mode) ; twiout2: sbis pinb, 7 ; wait for SCL=H rjmp twiout2 nop nop nop nop sbi USICR, USITC ; SCL H->L (USI clock toggle mode) nop nop nop nop sbi USICR, USICLK ; shifting data register +1 and counter +1 nop dec temp1 ; counter for remaining bits left cpi temp1, 0x00 brne twiout1 ; loop, until reached zero ldi temp, 0xFF ; reset all flags in USI-status register out USISR, temp cbi ddrb, 5 ; SDA -> configured as input sbi USICR, USITC ; SCL L->H (USI clock toggle mode; read ACK/NACK) nop nop nop nop nop set ; set T-flag in SREG sbis pinb, 5 ; SDA already H (NACK)? clt ; no-> clear T-flag in SREG sbi USICR, USITC ; SCL H->L (USI clock toggle mode) sbi ddrb, 5 ; SDA reconfigured to output nop nop nop pop temp1 pop temp ret ; lcdinit: ;LCD-Port: D0-D3=n.c.; D4-D7=data; ; ; ; P7 | P6 | P5 | P4 | P3 | P2 | P1 | P0 ; ; D7 | D6 | D5 | D4 | LED| ENA| R|W| RS ; ;======================================= ; ;Port adapter's pinout on backside of lcd board: ; ;Vss|Vdd|V0 |RS|R/W|ENA|D0|D1|D2|D3|D4|D5|D6|D7|A|K ; 0 +5V adj P0 P1 P2 nc nc nc nc P4 P5 P6 P7 nc nc ;===================================================== rcall wait1 ; wait for LCD power on self reset rcall twistart ldi temp, 0x70 ; slave start adresse + RW-Bit rcall twiout ; PCF8574->0x40; PCF8574A->0x70 rcall lcd_eight_bit ; LCD-Init: eight bit rcall lcd_eight_four ; LCD-Init: eight to four bit change rcall lcd_four_two_r ; LCD-Init: four bit, 2 rows rcall lcd_on_off ; LCD-Init: display buffer off rcall lcd_clear ; LCD-Init: clear display rcall lcd_entrymode ; LCD-Init: Entry Mode Set ret ; lcd_eight_bit: ; compulsary first LCD software init ldi temp, 0b00001000 ; LED-backlight on rcall twiout ldi temp, 0b00110000 ; 0x30 rcall twiout ; output via TWI subroutine rcall enable ; call enable impuls subroutine rcall wait1 ; wait for lcd processing ldi temp, 0b00110000 ; 0x30 rcall twiout rcall enable rcall wait1 ldi temp, 0b00110000 ; 0x30 rcall twiout rcall enable rcall wait1 ret ; lcd_eight_four: ; eight to four bit change push temp ldi temp, 0b00001000 ; LED-backlight on rcall twiout ldi temp, 0b00100000 ; first, four bit mode, only rcall twiout rcall enable rcall wait2 ; still lcd remains on 8 bit frame pop temp ; when accepting command lines ret ; lcd_four_two_r: ; four bit modus; two rows push temp ldi temp, 0b00101000 rcall cmd2lcd ; from now on lcd accepts rcall wait2 ; commands in a four bit frame, only pop temp ; do with call cmd2lcd subroutine ret ; lcd_on_off: ; On Off Control, swith display on/off: push temp ldi temp, 0b00001000 ; switch off display rcall cmd2lcd ; no cursor, no blinking rcall wait1 pop temp ret ; lcd_clear: ; clear entire display buffer: push temp ldi temp, 0b00000001 rcall cmd2lcd rcall wait1 pop temp ret ; lcd_entrymode: ; Entry/Shift Mode Set: push temp ldi temp, 0b00000110 ; cursor move direction from left to right rcall cmd2lcd ; no display shifting rcall wait2 ldi temp, 0b00010000 ; no display shifting, cursor move rcall cmd2lcd ; from left to right rcall wait2 ldi temp, 0b00001100 ; display on again rcall cmd2lcd ; no cursor, blinking off rcall wait2 ldi temp, 0b00000001 ; clearing display once more rcall cmd2lcd rcall wait2 pop temp ret ; char2lcd: ; charakter output on LCD via TWI: push temp ; saves "temps" on stack push temp1 mov temp1, temp ; content's copy for further actions below; andi temp, 0b11110000 ; blanking out D0-D3 data nibble ori temp, 0b00000001 ; RS=H masking rcall twiout ; output D4-D7 on B4-B7 rcall enable ; output first enable impuls swap temp1 ; swapping nibbles, uses copy of temp to temp1 andi temp1, 0b11110000 ; blanking out LSB port nibble ori temp1, 0b00001001 ; RS=H; LED-backlight on mov temp, temp1 ; copy temp1 to output register in use temp rcall twiout ; output D0-D3 on Port B4-B7 rcall enable ; output second enable impuls rcall wait2 ; wait for LCD processing pop temp1 ; reestablishing temps ... pop temp ; ...previous saved on stack ret ; cmd2lcd: ; transmitting instructions towards LCD via TWI push temp ; saves "temps" on stack push temp1 mov temp1, temp ; content's copy for further actions below andi temp, 0b11110000 ; RS=L; blanking out D0-D3 data nibble rcall twiout ; output D4-D7 on B4-B7 rcall enable ; output first enable impuls swap temp1 ; swapping nibbles, uses copy of temp to temp1 andi temp1, 0b11110000 ; blanking out LSB port nibble mov temp, temp1 ; copy temp1 to output register in use temp rcall twiout ; output D0-D3 on Port B4-B7 rcall enable ; output second enable impuls rcall wait2 ; wait for LCD processing pop temp1 ; reestablishing temps ... pop temp ; ...previous saved on stack ret ; enable: nop ori temp, 0b00000100 ; H-masking enable bit rcall twiout ; output via subroutine "twiout" nop nop nop nop nop nop nop nop andi temp, 0b11111011 ; L-masking enable bit rcall twiout ; output via subroutine "twiout" nop ret ; ;- fin -