;compiler: avrasm .include "m32def.inc" ;************************************************************************************************************************************** ; Programek s rutinkami pro kresleni usecek a bodu na LCD podle zadanych koncovych bodu. ; Zaroven jsem vytvoril rutiny pro vykresleni jednoducheho 3D objektu. Puvodne to mela byt ; rotujici krychle, ale nejak se mi nepovedlo vhodne poskladat sin/cos, takze je to spis ; rotujici nesmysl, ale jako demonstrace kresleni usecek to snad to postaci. ; ; LCD: 128x64pix, radic KS0108 ; XTAL: max. 16MHz (klidne i interni oscilator, ale pojede to pomalu) ; ; Author Stanislav Maslan, s.maslan@seznam.cz ;************************************************************************************************************************************** .dseg ImageBuffer: .byte 1024 PointsBuffer: .byte 16 Xrot: .byte 3 Yrot: .byte 3 .cseg .org 0x0000 rjmp Init ;portc: LCD D0-D7 ;portd piny: .equ DRW=7 ;LCD R/W .equ DCS1=6 ;LCD chip select 1 .equ DCS2=5 ;LCD chip select 2 .equ DRS=4 ;LCD RS .equ DE=3 ;LCD E (hodiny) .equ DRST=2 ;LCD reset ;************************************************************************************************************************************** ; inicializace ;************************************************************************************************************************************** Init: ldi R16,0b00000000 out ddra,R16 ldi R16,0b00000000 out ddrb,R16 ldi R16,0b00000000 out ddrc,R16 ldi R16,0b11111100 out ddrd,R16 ldi R16,low(ramend) ldi R17,high(ramend) out sph,R17 out spl,R16 ;nastavit stack cbi portd,DE ;E na log.0 sbi portd,DCS1 sbi portd,DCS2 ;inicializace LCD cbi portd,DRST nop nop sbi portd,DRST ;resetovat sbi portd,DRW ;cteni cbi portd,DRS ;instrukce WaitLCDinit: nop nop sbi portd,DE nop nop in R16,pinc ;naloudit data byte cbi portd,DE andi R16,0b10010000 ;cekat dokud nezmizi priznaky reset a busy brne WaitLCDinit cbi portd,DRW ldi R16,0b11111111 out ddrc,R16 ;inicializace, CS1 i CS2 v log.1, takze pro obe poloviny LCD ldi R16,0b00111111 ;zapnout LCD rcall LCDtxInstr ldi R16,0b01000000 rcall LCDtxInstr ldi R16,0b10111000 rcall LCDtxInstr ldi R16,0b11000000 ;nastavit pocatecni lajnu LCD na 0 rcall LCDtxInstr ;pocatecni pootoceni ldi R18,0 ;zlomkova cast ldi R16,low(0) ldi R17,high(0) ;pocatecni uhel sts Xrot+0,R16 sts Xrot+1,R17 sts Xrot+2,R18 sts Yrot+0,R16 sts Yrot+1,R17 sts Yrot+2,R18 ;tady se kresli vlastni obraz Loop1: ldi R28,low(ImageBuffer) ldi R29,high(ImageBuffer) ldi R24,low(1024) ldi R25,high(1024) ldi R16,0b00000000 LCDclrImgBuff: st Y+,R16 sbiw R24,1 brne LCDclrImgBuff ;mazat buffer rcall DrawBox ;kreslit kostku rcall LCDtxBuffer ;odeslat obraz ldi R16,2 rcall DelayLongVar ;nejaky to zpozdenicko rcall RotBox ;provest rotaci kostky rjmp Loop1 ;a repete ;************************************************************************************************************************************** ; rutiny pro kresleni ukazkoveho 3D objektu ;************************************************************************************************************************************** ;------------------------------------------------------------------------------------------ ; vykreslit 3D objekt ;------------------------------------------------------------------------------------------ DrawBox: ;nejdriv spocitat adresy bodu ldi R26,low(PointsBuffer) ldi R27,high(PointsBuffer) ldi R30,low(BoxPointsT*2) ldi R31,high(BoxPointsT*2) ldi R24,8 ;8 bodu ;x DrawBoxGenPtsL: push R24 lpm R16,Z+ lpm R17,Z+ movw R2,R30 lds R18,Xrot+0 lds R19,Xrot+1 add R16,R18 adc R17,R19 rcall sin16u8s asr R16 ; rcall FitToLCD subi R16,(-64) st X+,R16 ;y movw R30,R2 lpm R16,Z+ lpm R17,Z+ movw R2,R30 lds R18,Yrot+0 lds R19,Yrot+1 add R16,R18 adc R17,R19 rcall sin16u8s asr R16 asr R16 ; rcall FitToLCD subi R16,(-32) st X+,R16 ; movw R30,R2 pop R24 dec R24 brne DrawBoxGenPtsL ;ted ty bodiky vykreslit ; ldi R26,low(PointsBuffer) ; ldi R27,high(PointsBuffer) ; ldi R24,8 ;DrawBoxPix: push R24 ; ld R11,X+ ; ld R13,X+ ; rcall DrawPix4Ln ; pop R24 ; dec R24 ; brne DrawBoxPix ;ted kreslit spojnice ldi R30,low(BoxLinesT*2) ldi R31,high(BoxLinesT*2) clr R0 ldi R24,12 DrawBoxLine: push R24 ;bod A lpm R16,Z+ lsl R16 ldi R26,low(PointsBuffer) ldi R27,high(PointsBuffer) add R26,R16 adc R17,R0 ld R18,X+ ld R19,X+ ;bod B lpm R16,Z+ lsl R16 ldi R26,low(PointsBuffer) ldi R27,high(PointsBuffer) add R26,R16 adc R17,R0 ld R16,X+ ld R17,X+ ; push R30 push R31 rcall DrawLine pop R31 pop R30 ; pop R24 dec R24 brne DrawBoxLine ret ;------------------------------------------------------------------------------------------ ; korekce sin -127..+127 na velikost LCD ;------------------------------------------------------------------------------------------ FitToLCD: ldi R17,7 muls R16,R17 lsr R1 ror R0 lsr R1 ror R0 lsr R1 ror R0 lsr R1 ror R0 lsr R1 ror R0 mov R16,R0 ret ;------------------------------------------------------------------------------------------ ; parametry rotace ;------------------------------------------------------------------------------------------ RotBox: lds R23,Xrot+2 lds R24,Xrot+0 lds R25,Xrot+1 subi R23,low(-305) sbci R24,high(-305) sbci R25,byte3(-305) sts Xrot+2,R23 sts Xrot+0,R24 sts Xrot+1,R25 ; lds R23,Yrot+2 ;zlomkova cast lds R24,Yrot+0 lds R25,Yrot+1 subi R23,low(-187) sbci R24,high(-187) sbci R25,byte3(-187) sts Yrot+2,R23 ;zlomkova cast sts Yrot+0,R24 sts Yrot+1,R25 ret ;uhly bodu BoxPointsT: .dw 45,45 .dw 135,135 .dw 225,135 .dw 315,45 .dw 45,315 .dw 135,225 .dw 225,225 .dw 315,315 ;cisla bodu pro spojnice BoxLinesT: .db 0,1 .db 1,2 .db 2,3 .db 3,0 .db 4,5 .db 5,6 .db 6,7 .db 7,4 .db 0,4 .db 1,5 .db 2,6 .db 3,7 ;************************************************************************************************************************************** ; rutiny spojene se zakladni grafikou ;************************************************************************************************************************************** ;------------------------------------------------------------------------------------------ ; kreslit lajnu z bodu A do bodu B ; A: R16=x, R17=y ; B: R18=x, R19=y ; ; vyuziva rutinu deleni 16/16bit div16u pro urceni smernice, jinak to ; vyuziva klasickou matiku s pevnou radovou carkou, takze to beha celkem ; svizne ;------------------------------------------------------------------------------------------ DrawLine: movw R6,R16 movw R8,R18 ;zapamtovat body A,B ;kdyz je Ax vetsi nez Bx, tak prohodit body A,B cp R6,R8 brcs DrawLineABnch ;prohodit A,B movw R8,R16 movw R6,R18 DrawLineABnch: ;kreslit pocatecni a koncovy bod mov R11,R6 mov R13,R7 rcall DrawPix4Ln ;kreslit bod ;vybrat kvadrant (I. nebo IV.) cp R9,R7 brcc DrawLineQ1 ;kvadrant IV. mov R20,R8 sub R20,R6 ;delka v x mov R21,R7 sub R21,R9 ;delka v y cp R20,R21 ;ktera osa je delsi? brcs DrawLineQ4y ;x je delsi clr R16 mov R17,R21 ;y*0x100 mov R18,R20 clr R19 ;x rcall div16u ;R16:R17 <- (y*0x100)/x mov R11,R6 ;pocatecni x clr R12 mov R13,R7 ;pocatecni y cpi R20,0 breq DrawLineFinito ;kreslit primku DrawLineQ4xL: inc R11 ;x+=1 sub R12,R16 sbc R13,R17 ;y+=smernice rcall DrawPix4Ln ;kreslit bod dec R20 brne DrawLineQ4xL ;dalsi bod rjmp DrawLineFinito ;y je delsi DrawLineQ4y: clr R16 mov R17,R20 ;x*0x100 mov R18,R21 clr R19 ;y rcall div16u ;R16:R17 <- (x*0x100)/y clr R12 mov R11,R6 ;pocatecni x mov R13,R7 ;pocatecni y cpi R21,0 breq DrawLineFinito ;kreslit primku DrawLineQ4yL: dec R13 ;y+=1 add R12,R16 adc R11,R17 ;x+=smernice rcall DrawPix4Ln ;kreslit bod dec R21 brne DrawLineQ4yL ;dalsi bod rjmp DrawLineFinito ;kvadrant I. DrawLineQ1: mov R20,R8 sub R20,R6 ;delka v x mov R21,R9 sub R21,R7 ;delka v y cp R20,R21 ;ktera osa je delsi? brcs DrawLineQ1y ;x je delsi clr R16 mov R17,R21 ;y*0x100 mov R18,R20 clr R19 ;x rcall div16u ;R16:R17 <- (y*0x100)/x mov R11,R6 ;pocatecni x clr R12 mov R13,R7 ;pocatecni y cpi R20,0 breq DrawLineFinito ;kreslit primku DrawLineQ1xL: inc R11 ;x+=1 add R12,R16 adc R13,R17 ;y+=smernice rcall DrawPix4Ln ;kreslit bod dec R20 brne DrawLineQ1xL ;dalsi bod rjmp DrawLineFinito ;y je delsi DrawLineQ1y: clr R16 mov R17,R20 ;x*0x100 mov R18,R21 clr R19 ;y rcall div16u ;R16:R17 <- (x*0x100)/y clr R12 mov R11,R6 ;pocatecni x mov R13,R7 ;pocatecni y cpi R21,0 breq DrawLineFinito ;kreslit primku DrawLineQ1yL: inc R13 ;y+=1 add R12,R16 adc R11,R17 ;x+=smernice rcall DrawPix4Ln ;kreslit bod dec R21 brne DrawLineQ1yL ;dalsi bod ; DrawLineFinito: ret ;------------------------------------------------------------------------------------------ ; vykresli bod na pozici x=R11, y=R13 ;------------------------------------------------------------------------------------------ DrawPix4Ln: clr R0 ldi R28,low(ImageBuffer) ldi R29,high(ImageBuffer) ;obrazovy buffer add R28,R11 adc R29,R0 ;pricist x pozici bodu clr R18 mov R19,R13 lsr R19 ror R18 lsr R19 ror R18 lsr R19 ;page (svisla osmice pixelu na LCD) ror R18 swap R18 lsr R18 ;ID masky ldi R30,low(DrawPixMskT*2) ldi R31,high(DrawPixMskT*2) add R30,R18 adc R31,R0 ;vybrat masku podle ID lpm R18,Z ;nacist masku lsr R19 ror R0 add R28,R0 adc R29,R19 ;byte bufferu nastaven ld R19,Y ;nacist puvodni byte or R19,R18 ;pridat novy bod st Y,R19 ;zpatky do bufferu ret DrawPixMskT: .db 0b00000001,0b00000010,0b00000100,0b00001000 .db 0b00010000,0b00100000,0b01000000,0b10000000 ;************************************************************************************************************************************** ; rutiny pro ovladani LCD ;************************************************************************************************************************************** ;------------------------------------------------------------------------------------------ ; odeslat obrazovy buffer LCD ;------------------------------------------------------------------------------------------ LCDtxBuffer: sbi portd,DCS1 sbi portd,DCS2 ;obe pulky LCD ldi R16,0b01000000 rcall LCDtxInstr ;sloupec=0 ; ldi R28,low(ImageBuffer) ldi R29,high(ImageBuffer) ;obrazpvy buffer ldi R21,0b10111000 ;page 0 ; ldi R24,8 ;8 pages LCDtxBuffL3: sbi portd,DCS1 sbi portd,DCS2 ;obe pulky LCD ldi R16,0b01000000 rcall LCDtxInstr ;sloupec=0 mov R16,R21 rcall LCDtxInstr ;nastav page sbi portd,DRS ;data sbi portd,DCS1 cbi portd,DCS2 ;jen leva cast LCD ldi R20,64 ;64 sloupcu LCDtxBuffL1: ld R16,Y+ out portc,R16 ;byte na port rcall DelayLCD sbi portd,DE ;E log.1 rcall DelayLCD cbi portd,DE ;E log.0 rcall DelayLCD dec R20 brne LCDtxBuffL1 ;dalsi byte cbi portd,DCS1 sbi portd,DCS2 ;jen prava pulka LCD ldi R20,64 ;64 B LCDtxBuffL2: ld R16,Y+ out portc,R16 ;byte na port rcall DelayLCD sbi portd,DE ;E high rcall DelayLCD cbi portd,DE ;E low rcall DelayLCD dec R20 brne LCDtxBuffL2 ;dalsi B inc R21 ;ukazatel na dalsi page dec R24 brne LCDtxBuffL3 ;dalsi page ret ;zpozdenicko pro casovani sbernice KS0108 DelayLCD: push R16 ldi R16,16 DelayLCD1: dec R16 brne DelayLCD1 pop R16 ret ;------------------------------------------------------------------------------------------ ; poslat instrukci radici LCD ;------------------------------------------------------------------------------------------ LCDtxInstr: cbi portd,DRS ;instrukce out portc,R16 ;data na port nop nop sbi portd,DE ;E high nop nop cbi portd,DE ;E low nop nop ldi R16,0b00000000 out ddrc,R16 ;portc jako vstup sbi portd,DRW ;cteni z LCD LCDtxInstrBSY: nop nop sbi portd,DE ;E high nop nop in R16,pinc ;nacist byte cbi portd,DE ;E low bst R16,7 ;busy priznak brts LCDtxInstrBSY ;cekat na busy=false cbi portd,DRW ;zpet na zapis do LCD ldi R16,0b11111111 out ddrc,R16 ;port zpet jako vystup ret ;************************************************************************************************************************************** ; MATIKA ;************************************************************************************************************************************** ;------------------------------------------------------------------------------------------ ; sin16u8s - sinus from 16-bit unsigned input (0..65535 in deg) to 8-bit signed output ; vypocet funkce sinus z uhlu ve stupnich s 8-bit znamenkovym vystupem ; vstup muze byt v rozsahu 0-65535 deg, zaporny neni podporovan ; ; sin(0)=0, sin(90)=127, sin(180)=0, sin(270)=-127 ; ; R16 <- sin(R16:R17) ; ; Author: Stanislav Maslan, s.maslan@seznam.cz ;------------------------------------------------------------------------------------------ sin16u8s: ldi R18,high(360) cpi R16,low(360) cpc R17,R18 brcs sin16u8sIL ;mimo rozsah 0-359 deg - upravit ldi R18,low(360) ldi R19,high(360) rcall div16u movw R16,R14 ;uprava provedena ;R16:R17 upraveno na rozsah 0-359 deg sin16u8sIL: ldi R30,low(SinCosT*2) ldi R31,high(SinCosT*2) ldi R18,high(180) cpi R16,low(180) cpc R17,R18 brcc sin16u8sH2 ;0-179 deg cpi R16,90 brcc sin16u8sQ2 ;0-89 deg add R30,R16 adc R31,R17 lpm R16,Z ;R16=sin(R16:R17) rjmp sin16u8sFin ;90-189 deg sin16u8sQ2: subi R16,low(90) sbci R17,high(90) ;na 0-89 ldi R18,90 sub R18,R16 add R30,R18 adc R31,R17 lpm R16,Z ;R16=sin(R16:R17) rjmp sin16u8sFin ;180-359 deg sin16u8sH2: subi R16,low(180) sbci R17,high(180) cpi R16,90 brcc sin16u8sQ4 ;180-269 deg add R30,R16 adc R31,R17 lpm R16,Z neg R16 ;R16=sin(R16:R17) rjmp sin16u8sFin ;270-359 sin16u8sQ4: subi R16,low(90) sbci R17,high(90) ldi R18,90 sub R18,R16 add R30,R18 adc R31,R17 lpm R16,Z neg R16 ;R16=sin(R16:R17) sin16u8sFin: ret ;8 bit znamikove konstanty pro sinus 0-90 deg SinCosT: .db 0,2,4,7,9,11,13,15 ;sin 0 deg .db 18,20,22,24,26,29,31,33 .db 35,37,39,41,43,46,48,50 .db 52,54,56,58,60,62,64,65 .db 67,69,71,73,75,76,78,80 .db 82,83,85,87,88,90,91,93 .db 94,96,97,99,100,101,103,104 .db 105,107,108,109,110,111,112,113 .db 114,115,116,117,118,119,119,120 .db 121,121,122,123,123,124,124,125 .db 125,125,126,126,126,127,127,127 .db 127,127,127 ;sin 90 deg ;------------------------------------------------------------------------------------------ ; div16u - 16/16 bit unsigned division, max. speed optimized ; deleni dvou neznaminkovych 16-bit cisel, maximalni optimalizace na rychlost ; ; Author: Pavel Borovsky, Czech Republic, Europe 3.6.2000 ; email: profesor@ti.cz ; ; dDd16r0u:dDd16r1u <- dDd16r0u:dDd16r1u div dDs16r0u:dDs16r1u ; dRe16r0u:dRe16r1u <- dDd16r0u:dDd16r1u mod dDs16r0u:dDs16r1u ; ; words: 142 + ret (puvodni od ATMELu: 196 + ret) ; cycles: 126/134/142 + ret [min/avg/max] (puvodni od ATMELu: 148/172/196 + ret) ;------------------------------------------------------------------------------------------ .def dRe16r0u=R14 .def dRe16r1u=R15 .def dDd16r0u=R16 .def dDd16r1u=R17 .def dDs16r0u=R18 .def dDs16r1u=R19 ; div16u: clr dRe16r0u sub dRe16r1u,dRe16r1u rol dDd16r0u rol dDd16r1u rol dRe16r0u sub dRe16r0u,dDs16r0u sbc dRe16r1u,dDs16r1u brcc d16u_1 add dRe16r0u,dDs16r0u adc dRe16r1u,dDs16r1u d16u_1: rol dDd16r0u rol dDd16r1u rol dRe16r0u sub dRe16r0u,dDs16r0u sbc dRe16r1u,dDs16r1u brcc d16u_2 add dRe16r0u,dDs16r0u adc dRe16r1u,dDs16r1u d16u_2: rol dDd16r0u rol dDd16r1u rol dRe16r0u sub dRe16r0u,dDs16r0u sbc dRe16r1u,dDs16r1u brcc d16u_3 add dRe16r0u,dDs16r0u adc dRe16r1u,dDs16r1u d16u_3: rol dDd16r0u rol dDd16r1u rol dRe16r0u sub dRe16r0u,dDs16r0u sbc dRe16r1u,dDs16r1u brcc d16u_4 add dRe16r0u,dDs16r0u adc dRe16r1u,dDs16r1u d16u_4: rol dDd16r0u rol dDd16r1u rol dRe16r0u sub dRe16r0u,dDs16r0u sbc dRe16r1u,dDs16r1u brcc d16u_5 add dRe16r0u,dDs16r0u adc dRe16r1u,dDs16r1u d16u_5: rol dDd16r0u rol dDd16r1u rol dRe16r0u sub dRe16r0u,dDs16r0u sbc dRe16r1u,dDs16r1u brcc d16u_6 add dRe16r0u,dDs16r0u adc dRe16r1u,dDs16r1u d16u_6: rol dDd16r0u rol dDd16r1u rol dRe16r0u sub dRe16r0u,dDs16r0u sbc dRe16r1u,dDs16r1u brcc d16u_7 add dRe16r0u,dDs16r0u adc dRe16r1u,dDs16r1u d16u_7: rol dDd16r0u rol dDd16r1u rol dRe16r0u sub dRe16r0u,dDs16r0u sbc dRe16r1u,dDs16r1u brcc d16u_8 add dRe16r0u,dDs16r0u adc dRe16r1u,dDs16r1u d16u_8: rol dDd16r0u rol dDd16r1u rol dRe16r0u rol dRe16r1u sub dRe16r0u,dDs16r0u sbc dRe16r1u,dDs16r1u brcc d16u_9 add dRe16r0u,dDs16r0u adc dRe16r1u,dDs16r1u d16u_9: rol dDd16r0u rol dDd16r1u rol dRe16r0u rol dRe16r1u sub dRe16r0u,dDs16r0u sbc dRe16r1u,dDs16r1u brcc d16u_10 add dRe16r0u,dDs16r0u adc dRe16r1u,dDs16r1u d16u_10: rol dDd16r0u rol dDd16r1u rol dRe16r0u rol dRe16r1u sub dRe16r0u,dDs16r0u sbc dRe16r1u,dDs16r1u brcc d16u_11 add dRe16r0u,dDs16r0u adc dRe16r1u,dDs16r1u d16u_11: rol dDd16r0u rol dDd16r1u rol dRe16r0u rol dRe16r1u sub dRe16r0u,dDs16r0u sbc dRe16r1u,dDs16r1u brcc d16u_12 add dRe16r0u,dDs16r0u adc dRe16r1u,dDs16r1u d16u_12: rol dDd16r0u rol dDd16r1u rol dRe16r0u rol dRe16r1u sub dRe16r0u,dDs16r0u sbc dRe16r1u,dDs16r1u brcc d16u_13 add dRe16r0u,dDs16r0u adc dRe16r1u,dDs16r1u d16u_13: rol dDd16r0u rol dDd16r1u rol dRe16r0u rol dRe16r1u sub dRe16r0u,dDs16r0u sbc dRe16r1u,dDs16r1u brcc d16u_14 add dRe16r0u,dDs16r0u adc dRe16r1u,dDs16r1u d16u_14: rol dDd16r0u rol dDd16r1u rol dRe16r0u rol dRe16r1u sub dRe16r0u,dDs16r0u sbc dRe16r1u,dDs16r1u brcc d16u_15 add dRe16r0u,dDs16r0u adc dRe16r1u,dDs16r1u d16u_15: rol dDd16r0u rol dDd16r1u rol dRe16r0u rol dRe16r1u sub dRe16r0u,dDs16r0u sbc dRe16r1u,dDs16r1u brcc d16u_16 add dRe16r0u,dDs16r0u adc dRe16r1u,dDs16r1u d16u_16: rol dDd16r0u rol dDd16r1u com dDd16r0u com dDd16r1u ret ;************************************************************************************************************************************** ; some garbage ;************************************************************************************************************************************** ;------------------------------------------------------------------------------------------ ; R16 * nejaky zpozdeni ;------------------------------------------------------------------------------------------ DelayLongVar: clr R0 DelayLongVar2: clr R1 DelayLongVar1: dec R1 brne DelayLongVar1 dec R0 brne DelayLongVar2 dec R16 brne DelayLongVar ret