Last active
July 22, 2020 13:53
-
-
Save carlosdelfino/3f6c00800f48126fe223f66c6ca51d18 to your computer and use it in GitHub Desktop.
Estudos de otimização trigonometria em C e ASM em especial Cortex-M e AVR
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
;CORDIC Degrees to SIN COS (As Used On Youtube http://www.youtube.com/watch?v=Ze4UnE8R4FM) | |
;20x2 OLED display | |
;Craig Webster (IXIBA) | |
;Melboune Australia | |
;Updated 18/2/2014 | |
;Found this usefull? | |
;Bitcoin: 1LqDCrj8QAUjACnjRNEw8vq3T9p2R5k5RW | |
;Use TAB space = 7 | |
.nolist | |
.include "m88def.inc" | |
.list | |
;LCD pins ;LCD pins D0-D3 & R/W Join to gnd | |
.equ LCD_RS =PC0 ;LCD RS 0=control, 1=data | |
.equ LCD_EN =PC1 ;LCD Enable on falling edge | |
.equ LCD_D4 =PC2 ;LCD data bit D4 ;Bits D0-D3 not used (Tied low) | |
.equ LCD_D5 =PC3 ;LCD data bit D5 | |
.equ LCD_D6 =PC4 ;LCD data bit D6 | |
.equ LCD_D7 =PC5 ;LCD data bit D7 | |
;Tack Switch | |
.equ SW_Up =PD0 | |
.equ SW_Down =PD1 | |
;.def =r0 | |
;.def =r1 | |
;.def =r2 | |
;.def =r3 | |
;.def =r4 | |
;.def =r5 | |
;.def =r6 | |
;.def =r7 | |
;.def =r8 | |
;.def =r9 | |
;.def =r10 | |
;.def =r11 | |
;.def =r12 | |
;.def =r13 | |
;.def =r14 | |
;.def =r15 | |
.def temp =r16 | |
.def temp1 =r17 | |
.def flags =r18 | |
.def Loop_Count =r19 | |
;.def =r20 | |
.def Conversion_State =r21 ;Used to direct conversion of 0<>90 to 0<>360 | |
.def Angle_L =r22 ;Angle 0000 000n nnnn nnnn . dddd dddd dddd dddd | |
.def Angle_H =r23 | |
.def Angle_DPH =r24 | |
.def Angle_DPL =r25 | |
;r27,r26 Xh:Xl | |
;r29,r28 Yh:Yl | |
;r31,r30 Zh:Zl | |
;General Flags | |
.equ Negative =0 | |
.equ Wait =1 | |
;.equ =2 | |
;.equ =3 | |
;.equ =4 | |
;.equ =5 | |
;.equ =6 | |
;.equ =7 | |
;LCD screen positions | |
.equ LCD_SinPos =0x8c | |
.equ LCD_CosPos =0xcc | |
.equ LCD_AnglePOS =0xc0 | |
;With no delay at 1mhz delay between writes is 48us | |
.equ LCD_120uS =40 ;Value for 120uS delay for LCD, 1Mhz=40, 2Mhz=80, 4Mhz=160 | |
.equ LCD_600uS =50 ;Value for 600uS delay for LCD, 1Mhz=200 newhaven OLED ,SUS seems to work ok at <20us | |
.equ Del_15ms =15 ;Value for 15ms delay, 1Mhz=15, 2Mhz=30, 4Mhz=60, 8Mhz=120, 16Mhz=240 | |
.equ Cordic1K =0x136E9DB5 ;Will result in a N3.Q29 number (2 guard bits) | |
; 0.6072529350088812561694 << 29 , Size of cordic expansion | |
.equ Cordic_Iterations =21 ;How many iteration in Cordic loop, Max=30, Recomended not less then 16 | |
;(No point having more iteration than number of bits in Cordic1K) | |
; ; | |
;SIN(28.125) = 0.47331966718484338944103927991974 | |
; 29 = 0f256f46 = 0.47331966 0 | |
; 21 = 0f256f08 = 0.473319 545 | |
; 20 = 0f256d45 = 0.47331 8705 | |
; 19 = 0f2570cb = 0.4733 20385 | |
; 18 = 0f2577d7 = 0.4733 23745 | |
; 17 = 0f2585ef = 0.4733 30466 | |
; 16 = 0f2569bf = 0.4733 17025 | |
; 15 = 0f25315f = 0.473 290143 | |
.equ Fraction_Count_Demo =0x2000 ;The fraction step for demo 0x20 = .125 | |
; | |
;****************************************** | |
;* * | |
;* Start/Init * | |
;* * | |
;****************************************** | |
; | |
.CSEG | |
.org 0000 | |
rjmp Reset | |
.org INT0addr ; External Interrupt Request 0 | |
reti | |
.org INT1addr ; External Interrupt Request 1 | |
reti | |
.org PCI0addr ; Pin Change Interrupt Request | |
reti | |
.org PCI1addr ; Pin Change Interrupt Request 0 | |
reti | |
.org PCI2addr ; Pin Change Interrupt Request 1 | |
reti | |
.org WDTaddr ; Watchdog Time-out Interrupt | |
reti | |
.org OC2Aaddr ; Timer/Counter2 Compare Match A | |
reti | |
.org OC2Baddr ; Timer/Counter2 Compare Match A | |
reti | |
.org OVF2addr ; Timer/Counter2 Overflow | |
reti | |
.org ICP1addr ; Timer/Counter1 Capture Event | |
reti | |
.org OC1Aaddr ; Timer/Counter1 Compare Match A | |
reti | |
.org OC1Baddr ; Timer/Counter1 Compare Match B | |
reti | |
.org OVF1addr ; Timer/Counter1 Overflow | |
reti | |
.org OC0Aaddr ; TimerCounter0 Compare Match A | |
reti | |
.org OC0Baddr ; TimerCounter0 Compare Match B | |
reti | |
.org OVF0addr ; Timer/Couner0 Overflow | |
reti | |
.org SPIaddr ; SPI Serial Transfer Complete | |
reti | |
.org URXCaddr ; USART Rx Complete | |
reti | |
.org UDREaddr ; USART, Data Register Empty | |
reti | |
.org UTXCaddr ; USART Tx Complete | |
reti | |
.org ADCCaddr ; ADC Conversion Complete | |
reti | |
.org ERDYaddr ; EEPROM Ready | |
reti | |
.org ACIaddr ; Analog Comparator | |
reti | |
.org TWIaddr ; Two-wire Serial Interface | |
reti | |
.org SPMRaddr ; Store Program Memory Read | |
reti | |
Reset: ldi temp,high(RAMEND) ;Set stack pointer | |
out SPH,temp | |
ldi temp,low(RAMEND) | |
out SPL,temp | |
;Watchdog | |
cli ;Disabe Watdog to prevent endless reset cycle (Code from data sheet) | |
wdr | |
in temp,MCUSR | |
cbr temp,1<<WDRF | |
out MCUSR,temp | |
lds temp,WDTCSR | |
sbr temp,(1<<WDCE | 1<<WDE) | |
sts WDTCSR,temp | |
ldi temp,0<<WDE | |
sts WDTCSR,temp | |
;CPU Clock | |
ldi temp,1<<CLKPCE ;Set clock prescaler | |
sts CLKPR,temp | |
ldi temp,( 0<<CLKPCE | 0<<CLKPS3 | 0<<CLKPS2 | 1<<CLKPS1 | 1<<CLKPS0) | |
sts CLKPR,temp ;8Mhz/8=1Mhz | |
; ldi temp,( 0<<CLKPCE | 0<<CLKPS3 | 0<<CLKPS2 | 1<<CLKPS1 | 0<<CLKPS0) | |
; sts CLKPR,temp ;8Mhz/4=2Mhz | |
; ldi temp,( 0<<CLKPCE | 0<<CLKPS3 | 0<<CLKPS2 | 0<<CLKPS1 | 1<<CLKPS0) | |
; sts CLKPR,temp ;8Mhz/2=4Mhz | |
; | |
;C Port | |
ldi temp,(1<<LCD_RS | 1<<LCD_EN | 1<<LCD_D4 | 1<<LCD_D5 | 1<<LCD_D6 | 1<<LCD_D7) | |
out ddrc,temp ;Set LCD interface pins to output | |
ldi temp, (1<<LCD_RS | 0<<LCD_EN) | |
out portc,temp ;Set initial pin val E to inactive, RS data | |
; | |
;D Port | |
ldi temp,(0<<SW_Down | 0<<SW_Up) | |
out ddrd,temp | |
ldi temp,(1<<SW_Down | 1<<SW_Up) | |
out portd,temp ;Pullups on | |
;Setup LCD | |
rcall LCD_Initialize_4bit | |
; | |
;Defaults | |
clr flags | |
cli | |
; | |
;***************************************** | |
; | |
; Main program | |
; | |
;***************************************** | |
; | |
Main: | |
ldi temp,0x80 ;Home Cursor, 1st line | |
rcall LCD_cnt | |
ldi temp,LOW(Line1) | |
rcall Send_String | |
ldi temp,0xc0 ;2nd line | |
rcall LCD_CNT | |
ldi temp,LOW(Line2) | |
rcall Send_String | |
ldi Angle_H,0 ;N16 | |
ldi Angle_L,0 | |
ldi Angle_DPH,0 ;Q16 | |
ldi Angle_DPL,0 | |
ldi Xl,low(Fraction_Count_Demo) ;Fraction added per loop | |
ldi Xh,high(Fraction_Count_Demo) | |
ldi temp,0 ;A zero for maths | |
Key_Loop: | |
sbis pind,SW_Down | |
rjmp Count_Down | |
sbis pind,Sw_Up | |
rjmp Count_Up | |
sbr flags,1<<Wait ;To give the effect of an Auto-repeat after button continuosly held | |
rjmp Key_loop | |
Count_Up: | |
add Angle_DPL,Xl | |
adc Angle_DPH,Xh | |
adc Angle_L,temp | |
adc Angle_H,temp | |
ldi temp1,high(360) ;Gone past 359.999, just reset the whole part to 0 | |
cpi Angle_L,low(360) | |
cpc Angle_H,temp1 | |
brlo DO_Conversion | |
ldi Angle_H,0 | |
ldi Angle_L,0 | |
rjmp DO_Conversion | |
Count_Down: | |
sub Angle_DPL,Xl | |
sbc Angle_DPH,Xh | |
sbc Angle_L,temp | |
sbc Angle_H,temp | |
brcc DO_Conversion | |
ldi Angle_H,high(360) ;Gone negative so reset to 360.00 - Fraction_Count_Demo | |
ldi Angle_L,low(360) | |
ldi Angle_DPH,0 | |
ldi Angle_DPL,0 | |
sub Angle_DPL,Xl | |
sbc Angle_DPH,Xh | |
sbc Angle_L,temp | |
sbc Angle_H,temp | |
rjmp DO_Conversion | |
DO_Conversion: | |
sts Cordic_Angle,Angle_H | |
sts Cordic_Angle+1,Angle_L | |
sts Cordic_Angle+2,Angle_DPH | |
sts Cordic_Angle+3,Angle_DPL | |
rcall CORDIC_Sin_Cos_Deg | |
rcall Display_Result | |
sbrs flags,Wait ;Auto-repeat Delay | |
rjmp Key_Loop | |
ldi Loop_Count,60 | |
W_Lp: | |
rcall Delay15ms | |
dec loop_Count | |
brne W_Lp | |
cbr flags,1<<Wait | |
rjmp Key_Loop | |
; | |
;***************************************** | |
; | |
; CORDIC | |
; | |
;***************************************** | |
; | |
CORDIC_Sin_Cos_Deg: ;Calculate Sin Cos in Degrees using Cordic (Ver 2/8/2012) | |
;By Craig Webster (IXIBA) | |
;Cordic1K = 0x136E9DB5 | |
;Cordic_Iterations = 16 > 30 | |
;In: Angle N16.Q16 (32bit) (DSEG) | |
;Out: Sin N3.Q29S (32bit) & Cos N3.Q29S (32bit) (DSEG) | |
push r0 ;L TY | |
push r1 ; TY | |
push r2 ; TY | |
push r3 ;H TY | |
push r4 ;L Y | |
push r5 ; Y | |
push r6 ; Y | |
push r7 ;H Y | |
push r8 ;L Z | |
push r9 ; Z | |
push r10 ; Z | |
push r11 ;H Z | |
push r12 ;L X | |
push r13 ; X | |
push r14 ; X | |
push r15 ;H X | |
push r22 ;L TX | |
push r23 ; TX | |
push r24 ; TX | |
push r25 ;H TX | |
push Zl | |
push Zh | |
push Loop_Count | |
push temp | |
push Conversion_State | |
;Wrapper, Convert 0<>359 to 0<>89.9 | |
; ;Z=Angle<<8 (N16.Q16 > N8.Q24), To have same radix as TAN Table | |
lds r8,(Cordic_Angle) ;Z, Needs to be shifted Left 8 bits to allighn radix | |
lds r11,(Cordic_Angle+1) ;so load into Z one bite over and use Lower byte r8 | |
lds r10,(Cordic_Angle+2) ;witch will be zeroed later for high byte (Use r8:r11 | |
lds r9,(Cordic_Angle+3) ;in quadrant determiner) | |
;No needed if sure to be in range | |
; ldi Zh,high(360) ;Sanity check, exit if >=360 deg | |
; ldi Zl,low(360) | |
; cp r11,Zl | |
; cpc r8,Zh | |
; brlo CSCD_InRange | |
; sec ;Return Carry=1, Error | |
; rjmp CSCD_X | |
;Conversion state=1 0=>,<90 deg ,Sin=Sin(n) ,Cos=Cos(n) | |
;Conversion state=2 90=>,<180 deg ,Sin=Cos(n) ,Cos=Inv(Sin(n)) | |
;Conversion state=3 180=>,<270 deg,Sin=Inv(Sin(n)) ,Cos=Inv(Cos(n)) | |
;Conversion state=4 270=>,<360 deg,Sin=Inv(Cos(n)) ,Cos=Sin(n) | |
CSCD_InRange: | |
ldi Zl,90 | |
ldi Zh,0 | |
ldi Conversion_State,0 | |
CSCD_State_Lp: | |
inc Conversion_State | |
sub r11,Zl | |
sbc r8,Zh | |
brcc CSCD_State_Lp | |
add r11,Zl | |
adc r8,Zh | |
CSCD_Do_Conv: | |
;Game the system slightly, the first time through X=Y=Cordic1K, Preloading TX=TY=Cordic1K and | |
;juping in on +Z branch before Z adjust will skip some code & X,Y initilization | |
ldi r22,low(Cordic1K) ;TX=Cordic1K | |
ldi r23,byte2(Cordic1K) | |
ldi r24,byte3(Cordic1K) | |
ldi r25,byte4(Cordic1K) | |
movw r1:r0,r23:r22 ;TY=TX | |
movw r3:r2,r25:r24 | |
ldi Zh,high(ArcTan_Tab<<1) ;Arctan table | |
ldi Zl,low(ArcTan_Tab<<1) | |
ldi Loop_Count,0 | |
rjmp CSCD_Z_First ;Skip >>0 | |
CSCD_Shift: ;Y & X >>Loop_Count | |
mov temp,Loop_Count | |
CSCD_Shift_Lp: | |
cpi temp,8 ;If >>8 or more then do whole byte shift | |
brsh CSCD_Shift_Byte | |
CSCD_Shift_Bit: ;Bit shift, must be less than 8 so run down to 0 | |
asr r7 ;Y>>1 | |
ror r6 | |
ror r5 | |
ror r4 | |
asr r15 ;X>>1 | |
ror r14 | |
ror r13 | |
ror r12 | |
dec temp | |
brne CSCD_Shift_Bit | |
rjmp CSCD_Z_Sighn | |
CSCD_Shift_Byte: ;Shift whole byte to avoid 8 shifts | |
mov r4,r5 ;Y>>8 | |
mov r5,r6 | |
mov r6,r7 | |
clr r7 | |
sbrc r6,7 ;Extend sighn | |
com r7 | |
mov r12,r13 ;X>>8 | |
mov r13,r14 | |
mov r14,r15 | |
clr r15 | |
sbrc r14,7 ;Extend sighn | |
com r15 | |
subi temp,8 | |
brne CSCD_Shift_Lp | |
CSCD_Z_Sighn: | |
sbrs r11,7 ;Branch on Z sighn bit | |
rjmp CSCD_Z_Pos | |
;Z is Negative | |
add r22,r4 ;TX += Y | |
adc r23,r5 | |
adc r24,r6 | |
adc r25,r7 | |
sub r0,r12 ;TY -= X | |
sbc r1,r13 | |
sbc r2,r14 | |
sbc r3,r15 | |
lpm r4,Z+ ;Y=(Arctab+), Use Y as temp storage | |
lpm r5,Z+ | |
lpm r6,Z+ | |
lpm r7,Z+ | |
add r8,r4 ;Z += Y | |
adc r9,r5 | |
adc r10,r6 | |
adc r11,r7 | |
rjmp CSCD_Finalize | |
CSCD_Z_Pos: | |
;Z is Positive | |
sub r22,r4 ;TX -= Y | |
sbc r23,r5 | |
sbc r24,r6 | |
sbc r25,r7 | |
add r0,r12 ;TY += X | |
adc r1,r13 | |
adc r2,r14 | |
adc r3,r15 | |
CSCD_Z_First: | |
lpm r4,Z+ ;Y=(Arctab+), Use Y as temp storage | |
lpm r5,Z+ | |
lpm r6,Z+ | |
lpm r7,Z+ | |
sub r8,r4 ;Z -= Y | |
sbc r9,r5 | |
sbc r10,r6 | |
sbc r11,r7 | |
CSCD_Finalize: | |
movw r5:r4,r1:r0 ;Y = TY | |
movw r7:r6,r3:r2 | |
movw r13:r12,r23:r22 ;X = TX | |
movw r15:r14,r25:r24 | |
inc Loop_Count | |
cpi Loop_Count,Cordic_Iterations | |
brsh CSCD_End_State | |
rjmp CSCD_Shift | |
;Done so use Conversion_State to adjust to correct quadrant | |
CSCD_End_State: | |
cpi Conversion_State,1 ;Sin=Sin(n), Cos=Cos(n) | |
brne CSCD_End_State_Setup_Inveres | |
rjmp CSCD_Done | |
CSCD_End_State_Setup_Inveres: | |
ldi temp,0xff | |
com r12 ;X will be the inv Cos(n) | |
com r13 | |
com r14 | |
com r15 | |
sub r12,temp ;2's comp using sub -1 (FFFFFF) | |
sbc r13,temp | |
sbc r14,temp | |
sbc r15,temp | |
com r4 ;Y will be the inv Sin(n) | |
com r5 | |
com r6 | |
com r7 | |
sub r4,temp | |
sbc r5,temp | |
sbc r6,temp | |
sbc r7,temp | |
CSCD_End_State2: | |
cpi Conversion_State,2 ;Sin=Cos(n), Cos=Inv(Sin(n)) | |
brne CSCD_End_State3 | |
mov r0,r22 ;Sin=Cos(n) | |
mov r1,r23 | |
mov r2,r24 | |
mov r3,r25 | |
mov r22,r4 ;Cos=Inv(Sin(n)) | |
mov r23,r5 | |
mov r24,r6 | |
mov r25,r7 | |
rjmp CSCD_Done | |
CSCD_End_State3: | |
cpi Conversion_State,3 ;Sin=Inv(Sin(n)), Cos=Inv(Cos(n)) | |
brne CSCD_End_State4 | |
mov r0,r4 ;Sin=Inv(Sin(n)) | |
mov r1,r5 | |
mov r2,r6 | |
mov r3,r7 | |
mov r22,r12 ;Cos=Inv(Cos(n)) | |
mov r23,r13 | |
mov r24,r14 | |
mov r25,r15 | |
rjmp CSCD_Done | |
CSCD_End_State4: ;Sin=Inv(Cos(n)), Cos=Sin(n) | |
mov r22,r0 ;Cos=Sin(n) | |
mov r23,r1 | |
mov r24,r2 | |
mov r25,r3 | |
mov r0,r12 ;Sin=Inv(Cos(n)) | |
mov r1,r13 | |
mov r2,r14 | |
mov r3,r15 | |
CSCD_Done: | |
;Last 2 bit rubbish | |
sts Cordic_Sin,r3 ;Sin 32bit N3.Q29S | |
sts Cordic_Sin+1,r2 | |
sts Cordic_Sin+2,r1 | |
sts Cordic_Sin+3,r0 | |
sts Cordic_Cos,r25 ;Cos 32bit N3.Q29S | |
sts Cordic_Cos+1,r24 | |
sts Cordic_Cos+2,r23 | |
sts Cordic_Cos+3,r22 | |
clc ;Retun Carry=0, no error | |
CSCD_X:pop Conversion_State | |
pop temp | |
pop Loop_Count | |
pop Zh | |
pop Zl | |
pop r25 | |
pop r24 | |
pop r23 | |
pop r22 | |
pop r15 | |
pop r14 | |
pop r13 | |
pop r12 | |
pop r11 | |
pop r10 | |
pop r9 | |
pop r8 | |
pop r7 | |
pop r6 | |
pop r5 | |
pop r4 | |
pop r3 | |
pop r2 | |
pop r1 | |
pop r0 | |
ret | |
; | |
;***************************************** | |
; | |
;Display Stuff | |
; | |
;***************************************** | |
; | |
Display_Result: ;Display Thata,Sin ,Cos | |
;In: Angle,Cordic_Sin (DSEG),Cordic_Cos (DSEG) | |
;Out: LCD | |
push Xh | |
push Xl | |
push Yh | |
push Yl | |
push Zh | |
push Zl | |
push temp | |
ldi temp,LCD_AnglePOS ;Display Angle | |
rcall LCD_cnt | |
movw Yh:Yl,Angle_H:Angle_L | |
rcall Hex_Dec_999LZ | |
ldi temp,'.' | |
rcall LCD_Dat | |
clr Yh | |
clr Yl | |
sbrs Angle_DPH,7 ;MSB worth 500 | |
rjmp DR_AB2 | |
ldi Yh,high(500) | |
ldi Yl,low(500) | |
DR_AB2: | |
ldi Xh,high(250) | |
ldi Xl,low(250) | |
sbrs angle_DPH,6 ;Worth 250 | |
rjmp DR_AB3 | |
add Yl,Xl | |
adc Yh,Xh | |
DR_AB3: | |
ldi Xh,high(125) | |
ldi Xl,low(125) | |
sbrs angle_DPH,5 ;Worth 125 | |
rjmp DR_ABX | |
add Yl,Xl | |
adc Yh,Xh | |
DR_ABX: | |
rcall Hex_Dec_999 | |
ldi temp,LCD_CosPos ;Display COS | |
rcall LCD_cnt | |
lds Xh,Cordic_Cos | |
lds Xl,Cordic_Cos+1 | |
lds Zh,Cordic_Cos+2 | |
lds Zl,Cordic_Cos+3 | |
asr Xh ;Aligh fractinal part to byte N3.Q29 > N8.Q24 (preserve sighn) | |
ror Xl | |
ror Zh | |
ror Zl ;N4 | |
asr Xh | |
ror Xl | |
ror Zh | |
ror Zl ;N5 | |
asr Xh | |
ror Xl | |
ror Zh | |
ror Zl ;N6 | |
asr Xh | |
ror Xl | |
ror Zh | |
ror Zl ;N7 | |
asr Xh | |
ror Xl | |
ror Zh | |
ror Zl ;N8 | |
cbr flags,1<<Negative ;Convert negative numers to positive, flag to indicate action | |
sbrs Xh,7 | |
rjmp DR_CosPos | |
com Zl | |
com Zh | |
com Xl | |
com Xh | |
subi Zl,0xff ;2's comp using sub -1 (FFFF) | |
sbci Zh,0xff | |
sbci Xl,0xff | |
sbci Xh,0xff | |
sbr flags,1<<Negative ;Set flag to indicate its a negative num | |
DR_CosPos: | |
sts Bin_Frac,Xl | |
sts Bin_Frac+1,Zh | |
sts Bin_Frac+2,Zl | |
rcall BinFrac_To_BCD | |
ldi temp,' ' | |
sbrc flags,Negative | |
ldi temp,'-' | |
rcall LCD_dat | |
ori Xh,0x30 | |
mov temp,Xh | |
rcall LCD_dat | |
ldi temp,'.' | |
rcall LCD_dat | |
lds Xh,Bin_Frac_BCD | |
ldi temp,0xf0 | |
and temp,Xh | |
swap temp | |
ori temp,0x30 | |
rcall LCD_dat | |
ldi temp,0x0f | |
and temp,Xh | |
ori temp,0x30 | |
rcall LCD_dat | |
lds Xh,Bin_Frac_BCD+1 | |
ldi temp,0xf0 | |
and temp,Xh | |
swap temp | |
ori temp,0x30 | |
rcall LCD_dat | |
ldi temp,0x0f | |
and temp,Xh | |
ori temp,0x30 | |
rcall LCD_dat | |
lds Xh,Bin_Frac_BCD+2 | |
ldi temp,0xf0 | |
and temp,Xh | |
swap temp | |
ori temp,0x30 | |
rcall LCD_dat | |
ldi temp,LCD_SinPos ;Display Sin | |
rcall LCD_cnt | |
lds Xh,Cordic_Sin | |
lds Xl,Cordic_Sin+1 | |
lds Zh,Cordic_Sin+2 | |
lds Zl,Cordic_Sin+3 | |
asr Xh ;Aligh fractional part to byte N3.Q29 > N8.Q24 (preserve sighn) | |
ror Xl | |
ror Zh | |
ror Zl ;N4 | |
asr Xh | |
ror Xl | |
ror Zh | |
ror Zl ;N5 | |
asr Xh | |
ror Xl | |
ror Zh | |
ror Zl ;N6 | |
asr Xh | |
ror Xl | |
ror Zh | |
ror Zl ;N7 | |
asr Xh | |
ror Xl | |
ror Zh | |
ror Zl ;N8 | |
cbr flags,1<<Negative ;Convert negative numers to positive, flag to indicate action | |
sbrs Xh,7 | |
rjmp DR_SinPos | |
com Zl | |
com Zh | |
com Xl | |
com Xh | |
subi Zl,0xff ;2's comp using sub -1 (FFFF) | |
sbci Zh,0xff | |
sbci Xl,0xff | |
sbci Xh,0xff | |
sbr flags,1<<Negative ;Flag to indicate its a negative number | |
DR_SinPos: | |
sts Bin_Frac,Xl | |
sts Bin_Frac+1,Zh | |
sts Bin_Frac+2,Zl | |
rcall BinFrac_To_BCD | |
ldi temp,' ' | |
sbrc flags,Negative | |
ldi temp,'-' | |
rcall LCD_dat | |
ori Xh,0x30 | |
mov temp,Xh | |
rcall LCD_dat | |
ldi temp,'.' | |
rcall LCD_dat | |
lds Xh,Bin_Frac_BCD | |
ldi temp,0xf0 | |
and temp,Xh | |
swap temp | |
ori temp,0x30 | |
rcall LCD_dat | |
ldi temp,0x0f | |
and temp,Xh | |
ori temp,0x30 | |
rcall LCD_dat | |
lds Xh,Bin_Frac_BCD+1 | |
ldi temp,0xf0 | |
and temp,Xh | |
swap temp | |
ori temp,0x30 | |
rcall LCD_dat | |
ldi temp,0x0f | |
and temp,Xh | |
ori temp,0x30 | |
rcall LCD_dat | |
lds Xh,Bin_Frac_BCD+2 | |
ldi temp,0xf0 | |
and temp,Xh | |
swap temp | |
ori temp,0x30 | |
rcall LCD_dat | |
DR_X: pop temp | |
pop Zl | |
pop Zh | |
pop Yl | |
pop Yh | |
pop Xl | |
pop Xh | |
ret | |
; | |
; | |
BinFrac_To_BCD: ;Convert Binary Fraction (Q24) to BCD *10 method (16 Digit) (Ver 29/10/2012) | |
;Removed trailing zero suppresion in this version, hope nuffin broken | |
;Reduce to 6 digits, no need to waist time doing all 16 | |
;Convert to accept 24bit in (was 16 originaly) | |
;In: Bin_Frac (Q24) | |
;Out: Bin_Frac_BCD (upto 16 digits) | |
push r0 | |
push r1 | |
push r2 | |
push r3 | |
push r4 | |
push r5 | |
push Xl | |
push Xh | |
push Yl | |
push Yh | |
push Zl | |
push Zh | |
push Loop_Count | |
push temp | |
ldi Xh,high(Bin_Frac_BCD) | |
ldi Xl,low(Bin_Frac_BCD) | |
ldi temp,0 | |
sts Bin_Frac_BCD,temp | |
sts Bin_Frac_BCD+1,temp | |
sts Bin_Frac_BCD+2,temp | |
sts Bin_Frac_BCD+3,temp | |
sts Bin_Frac_BCD+4,temp | |
sts Bin_Frac_BCD+5,temp | |
sts Bin_Frac_BCD+6,temp | |
sts Bin_Frac_BCD+7,temp | |
lds Zl,Bin_Frac | |
lds Yh,Bin_Frac+1 | |
lds Yl,Bin_Frac+2 | |
ldi Zh,10 ;For Mult 10 | |
ldi temp,0 ;Build 2 BCD digits | |
ldi Loop_Count,6 ;6 BCD digits | |
BTB_LP: | |
clr r4 ;Multiply Zl:Yh:Yl * 10(Zh) = r5:r4:r3:r2 (Mul8x24_32U) | |
clr r5 | |
mul Zh,Yl | |
movw r3:r2,r1:r0 | |
mul Zh,Yh | |
add r3,r0 | |
adc r4,r1 | |
adc r5,r5 ;r5=0 | |
mul Zh,Zl | |
add r4,r0 | |
adc r5,r1 | |
movw Yh:Yl,r3:r2 ;Keep lower 24 bits for next cycle | |
mov Zl,r4 | |
swap temp | |
or temp,r5 ;r5 should only be 0<>9 | |
sbrs Loop_Count,0 ;Store BCD evey 2nd cycle | |
rjmp BTB_CY1 | |
st X+,temp | |
mov temp,Yh ;If zero then finish early | |
or temp,Yl | |
or temp,Zl | |
breq BTB_X | |
ldi temp,0 | |
BTB_CY1: | |
dec Loop_Count | |
brne BTB_LP | |
BTB_X: pop temp | |
pop Loop_Count | |
pop Zh | |
pop Zl | |
pop Yh | |
pop Yl | |
pop Xh | |
pop Xl | |
pop r5 | |
pop r4 | |
pop r3 | |
pop r2 | |
pop r1 | |
pop r0 | |
ret | |
; | |
; | |
Hex_Dec_999: ;Display 0<>999 | |
;In: Yh:Yl | |
;Out: LCD | |
push temp | |
push Loop_Count | |
ldi temp,high(1000) ;Check if within 0<>999 | |
cpi Yl,low(1000) | |
cpc Yh,temp | |
brlo HDa999_100 | |
ldi temp,'E' | |
rcall LCD_dat | |
ldi temp,'E' | |
rcall LCD_dat | |
ldi temp,'E' | |
rcall LCD_dat | |
rjmp HDa999S_X | |
HDa999_100: | |
clr Loop_Count | |
HDa999S_100L: | |
subi Yl,low(100) ;How many 100's | |
sbci Yh,high(100) | |
inc Loop_Count | |
brcc HDa999S_100L | |
dec Loop_Count | |
subi Yl,low(-100) | |
sbci Yh,high(-100) | |
ldi temp,0x30 | |
or temp,Loop_Count | |
rcall LCD_dat | |
clr Loop_Count | |
HDa999S_10L: | |
subi Yl,low(10) ;How many 10's | |
sbci Yh,high(10) | |
inc Loop_Count | |
brcc HDa999S_10L | |
dec Loop_Count | |
subi Yl,low(-10) | |
sbci Yh,high(-10) | |
ldi temp,0x30 | |
or temp,Loop_Count | |
rcall LCD_dat | |
ldi temp,0x30 | |
or temp,Yl | |
rcall LCD_dat | |
HDa999S_X: | |
pop Loop_Count | |
pop temp | |
ret | |
; | |
; | |
Hex_Dec_999LZ: ;Display 0<>999 supress leading Zeros(Uses T bit!!!) | |
;In: Yh:Yl | |
;Out: LCD | |
push temp | |
push Loop_Count | |
set ;Use Tbit ripple zero blank | |
HD999S_Pos: | |
ldi temp,high(1000) ;Check if within 0<>999 | |
cpi Yl,low(1000) | |
cpc Yh,temp | |
brlo HD999_100 | |
ldi temp,'E' | |
rcall LCD_dat | |
ldi temp,'E' | |
rcall LCD_dat | |
ldi temp,'E' | |
rcall LCD_dat | |
rjmp HD999S_X | |
HD999_100: | |
clr Loop_Count | |
HD999S_100L: | |
subi Yl,low(100) ;How many 100's | |
sbci Yh,high(100) | |
inc Loop_Count | |
brcc HD999S_100L | |
dec Loop_Count | |
subi Yl,low(-100) | |
sbci Yh,high(-100) | |
tst Loop_Count | |
brne HD999_Show100 | |
ldi temp,' ' | |
rcall LCD_dat | |
rjmp HD999_10 | |
HD999_Show100: | |
ldi temp,0x30 | |
or temp,Loop_Count | |
rcall LCD_dat | |
clt ;Stop blank ripple | |
HD999_10: | |
clr Loop_Count | |
HD999S_10L: | |
subi Yl,low(10) ;How many 10's | |
sbci Yh,high(10) | |
inc Loop_Count | |
brcc HD999S_10L | |
dec Loop_Count | |
subi Yl,low(-10) | |
sbci Yh,high(-10) | |
brtc HD999_Show10 | |
tst Loop_Count | |
brne HD999_Show10 | |
ldi temp,' ' | |
rcall LCD_dat | |
rjmp HD999S_Units | |
HD999_Show10: | |
ldi temp,0x30 | |
or temp,Loop_Count | |
rcall LCD_dat | |
HD999S_Units: | |
ldi temp,0x30 | |
or temp,Yl | |
rcall LCD_dat | |
HD999S_X: | |
pop Loop_Count | |
pop temp | |
ret | |
; | |
; | |
Send_String: | |
push Zl | |
push Zh | |
ldi Zh,high(LCD_Tables) ;All have same high byte addres | |
ldi ZL,low(LCD_Tables) | |
add Zl,temp | |
ldi temp,0 | |
adc Zh,temp | |
lsl Zl | |
rol Zh | |
SS_Lp: lpm temp,z+ ;Loop until null (0x00) | |
tst temp | |
breq SS_End | |
rcall LCD_dat | |
rjmp SS_Lp | |
SS_End: | |
pop Zh | |
pop Zl | |
ret | |
; | |
;***************************************** | |
; | |
; LCD interface | |
; | |
;***************************************** | |
; | |
LCD_Initialize_4bit: ;Initialize LCD to 4 bit mode (OLED) | |
rcall Delay15ms | |
rcall Delay15ms | |
;Function Set | |
ldi temp,(0<<LCD_RS | 0<<LCD_EN | 0<<LCD_D7 | 0<<LCD_D6 | 1<<LCD_D5 | 1<<LCD_D4) ;8bit mode | |
out portc, temp | |
sbi portc, LCD_EN ;In worst case, in 4 bit mode expecting second nibble of data | |
nop | |
nop | |
nop | |
nop | |
nop | |
cbi portc, LCD_EN | |
rcall Delay15ms | |
sbi portc, LCD_EN ;In worst case, in 4 bit mode, 1st nibble of camand that will tell it to switch to 8bit mode | |
nop | |
nop | |
nop | |
nop | |
nop | |
cbi portc, LCD_EN | |
rcall Delay15ms | |
sbi portc, LCD_EN | |
nop | |
nop | |
nop | |
nop | |
nop | |
cbi portc, LCD_EN ;In worst case, will be in 8 bit mode now | |
ldi temp,0xff | |
LI_L1: dec temp | |
brne LI_L1 | |
;Function Set | |
ldi temp,(0<<LCD_RS | 0<<LCD_EN | 0<<LCD_D7 | 0<<LCD_D6 | 1<<LCD_D5 | 0<<LCD_D4) ;4 Bit mode | |
out portc, temp | |
sbi portc, LCD_EN | |
nop | |
nop | |
nop | |
nop | |
nop | |
cbi portc, LCD_EN | |
rcall Delay15ms | |
sbi portc, LCD_EN ;Now in 4bit mode | |
nop | |
nop | |
nop | |
nop | |
nop | |
cbi portc, LCD_EN | |
ldi temp,0xff | |
LI_L2: dec temp | |
brne LI_L2 | |
ldi temp,(0<<LCD_RS | 0<<LCD_EN | 1<<LCD_D7 | 0<<LCD_D6 | 0<<LCD_D5 | 0<<LCD_D4) | |
out portc, temp | |
sbi portc, LCD_EN | |
nop | |
nop | |
nop | |
nop | |
nop | |
cbi portc, LCD_EN | |
ldi temp,0x08 ;Display Off | |
rcall LCD_cnt | |
ldi temp,0x01 ;Display Clear | |
rcall LCD_cnt | |
rcall Delay15ms | |
ldi temp,0x06 ;Entry Mode Set | |
rcall LCD_cnt | |
ldi temp,0x02 ;Home Command | |
rcall LCD_cnt | |
ldi temp,0x10 ;Cursor/Shift | |
rcall LCD_cnt | |
ldi temp,0x0c ;Display On | |
rcall LCD_cnt | |
ret | |
; | |
; | |
LCD_cnt: | |
push temp1 | |
ldi temp1,0<<LCD_RS ;RS=0 control | |
rjmp LCD_S | |
LCD_dat: | |
push temp1 | |
ldi temp1,1<<LCD_RS ;RS=1 Data | |
LCD_S: push temp | |
cbr temp,0x0f ;Upper nibble | |
lsr temp | |
lsr temp | |
or temp1,temp | |
out portc,temp1 | |
sbi portc,LCD_EN ;Pulse Enable | |
nop | |
nop | |
nop | |
nop | |
nop | |
cbi portc,LCD_EN | |
pop temp ;Lower nibble | |
cbr temp,0xf0 | |
lsl temp | |
lsl temp | |
cbr temp1,0xfc ;Preserve control bits | |
or temp1,temp | |
out portc,temp1 | |
sbi portc,LCD_EN ;Pulse Enable | |
nop | |
nop | |
nop | |
nop | |
nop | |
cbi portc,LCD_EN | |
ldi temp1,LCD_600uS | |
LCD_L2:dec temp1 | |
brne LCD_L2 | |
pop temp1 | |
ret | |
; | |
; | |
Delay15ms: | |
push temp | |
push temp1 | |
ldi temp1,Del_15ms | |
Del_L1:clr temp | |
Del_L2:dec temp | |
nop | |
brne Del_L2 | |
dec temp1 | |
brne Del_L1 | |
pop temp1 | |
pop temp | |
ret | |
end: | |
.org (end & 0xff00) + 0x100 | |
tables: | |
;Atan(1)=45 > 45 * 0x01000000 = 0x2D000000 | |
ArcTan_Tab: .dd 0x2D000000,0x1A90A731,0x0E094740,0x07200112 ;30 | |
.dd 0x03938AA6,0x01CA3794,0x00E52A1A,0x007296D7 | |
.dd 0x00394BA5,0x001CA5D9,0x000E52ED,0x00072976 | |
.dd 0x000394BB,0x0001CA5D,0x0000E52E,0x00007297 | |
.dd 0x0000394B,0x00001CA5,0x00000E52,0x00000729 | |
.dd 0x00000394,0x000001CA,0x000000E5,0x00000072 | |
.dd 0x00000039,0x0000001C,0x0000000E,0x00000007 | |
.dd 0x00000003,0x00000001 | |
endARC: | |
.org (endARC & 0xff00) + 0x100 | |
LCD_Tables: | |
Line1: .db " SIN:--.-----",0,0 | |
Line2: .db "---.---",0xdf,"COS:--.-----",0,0 | |
.DSEG | |
;Cordic Transfer: | |
Cordic_Angle: ;Angle in 32bit N16.Q16 (0.0 > 359.0) | |
.byte 4 | |
Cordic_Sin: ;Sin out, 32bit N3.Q29 ,-1.0 <> 1.0 = F00000 <> 100000, =n * 0x100000 | |
.byte 4 | |
Cordic_Cos: | |
.byte 4 ;Cos out, 32bit N3.Q29, -1.0 <> 1.0 = F00000 <> 100000, =n * 0x100000 | |
;Binary fraction to BCD | |
Bin_Frac: ;Q24, Fraction to be converted to Decimal | |
.byte 3 | |
Bin_Frac_BCD: ;Upto 16 BCD digits | |
.byte 8 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment