Copyright K.Unsworth and Unicorn Publications International 1990-2013 All Rights Reserved. Terms and Conditions.

;Maths functions

;for Home use only. NOT FOR COMMERCIAL USE

;clock switch works .

;3. The "__reset" label is the first label in the code section and must be    *

;   declared global. The Stack Pointer (W15) and the Stack Pointer Limit      *

;   register must be initialized to values that are past the run-time heap    *

;   space, so as to avoid corrupting user data. Initializing these registers  *

;   at the "__reset" label ensures that user data is not corrupted            *

;   accidentally. The __SP_init and __SPLIM_init literals are defined by the  *

;   linker. The linker automatically addresses above the run-time heap to     *

;   these symbols. Users can change the __SP_init and __SPLIM_init literals to*

;   suit their application.                                                   *

;                                                                             *

;4. A ".section <section_name>, <attributes>" directive declares a new section*

;   named "<section_name>" with an attribute list that specifies if the       *

;   section is located in Program Space(code), Uninitialized(bss) or          *

;   Initialized Data Space(data). Refer to the document "dsPIC 30F Assembler, *

;   Linker and Utilities User's Guide" for further details.                   *

;                                                                             *

;5. Initialize W registers: Using uninitialized W registers as Effective      *

;   Addresses(pointers) will cause an "Uninitialized W Register Trap" !       *

;                                                                             *

;6. The label "__T1Interrupt" is defined in the device linker script. The     *

;   label defines the starting location in program space of the Timer1        *

;   interrupt service routine (ISR).                                          *

;   Similarly, the linker script defines labels for all ISRs. Notice, that    *

;   the ISR label names are preceded by two underscore characters.            *

;   When users needs to write ISR code, they must use these labels after      *

;   providing them global scope. The linker will then place the ISR address in*

;   the respective interrupt vector table location in program space.          *

;   Context Save/Restore in ISRs can be performed using the double-word PUSH  *

;   instruction,PUSH.D. User can also make use of MOV.D, PUSH and PUSH.S      *

;   instructions. Refer dsPIC 30F 16-bit MCU Family Refernce Manual(DS70046)  *

;   for further details.                                                      *


       .equ __33fj256mc710, 1

       .include ""

;*****************Configuration bits:**************************

      config __FWDT, FWDTEN_OFF              ;Turn off Watchdog Timer


;   internal rc oscilator on  and watch dog off


;  clock switching on , multiple configs, i/o pins on, primary osc disabled


;  fast rc osc no pll ( yet), two speed osc off

;  set pll , tuning , clk div in main code then swap clocks

;from internet


;  fast rc osc


; Clock Switching is enabled and Fail Safe Clock Monitor is disabled

; OSC2 Pin Function: OSC2 is Clock Output ( might need to change)

; Primary Oscillator Mode: Disabled

;Starts at 7.37 MHz with no PLL

;changes to 79.2MHz in code

;runs at 83.989 Mhz with chip i have.

;no time crytical apps so not important

;********Global Declarations: ***********************************************

       .global _wreg_init       ;Provide global scope to _wreg_init routine

                                ;In order to call this routine from a C file,

                                ;place "wreg_init" in an "extern" declaration

                                ;in the C file.

       .global __reset          ;The label for the first line of code.

;***************Constants stored in Program space**************************

       .section .const,psv

;       .palign 2                ;Align next word stored in Program space to an

                                ;address that is a multiple of 2

;  <0x0> =chr$(0)  put 0 at end of string to mark end


  .ascii "UPI Func",<0x0>


 .ascii "tion Gen ",<0x0>


 .ascii  "123456789",<0x0>

;***************** variables in Near data memory (Lower 8Kb of RAM)*************

         .section .nbss, bss, near

; var1:     .space 2               ;Example of allocating 1 word of space for

                                  ;variable "var1".

intcounter:  .space 2    ;standard counter

   buffer:         .space 20               ;for ascii code    

 flags:   .space 2

.equ numberfound,0     ;used to diferentiate between zero and space on lcd

; .equ pb1f FLAGS,1

; .equ pb2f FLAGS,2

; .equ pb3f FLAGS,3

; .equ pb4f FLAGS,4

;********************constants for code************************

 .equ fcy,40000000     ;40 mips

 .equ  baudrate,9600     ;uart baud rate

 .equ  brval,((fcy/baudrate)/16)-1  ;value for setting uart

;*************Start of program**************

.text                               ;Start of Code section


       MOV  #__SP_init, W15       ;Initalize the Stack Pointer

       MOV  #__SPLIM_init, W0      ;Initialize the Stack Pointer Limit Register

       MOV  W0, SPLIM

       NOP                       ;Add NOP to follow SPLIM initialization      

; reset all w register  this MUST be done

       CLR  W0

       MOV  W0, W14

       REPEAT  #12

       MOV  W0, [++W14]

       CLR  W14

;**************setup oscilator pll (my code)****************

;Set clock to 80Mhz = 40 MIPs

;IMPORTANT set PLL ratios before change of clock to PLL

 bclr CLKDIV,#6

 bclr CLKDIV,#7  ;PLL post =0 divide = 2

 mov  #43,w0   ;7.37/4*43=79.2275Mhz

 mov  w0,PLLFBD  ;PLL feed back divisor = 40 (38+2)

;from book

 MOV  #1,w0   ;frc with PLL, new nosc code


  MOV  #OSCCONH,W1  ;unlock code

 MOV  #0x78,W2

 MOV  #0x9A,W3

 MOV.B W2,[W1]   ;WRITE 0x78

 MOV.B W3,[W1]   ;WRITE 0x9A

 MOV.B W0,[W1]   ;now set type of clock


  MOV  #0x01,W0


 MOV  #0x46,W2

 MOV  #0x57,W3

 MOV.B W2,[W1]   ;WRITE 0x46

 MOV.B W3,[W1]   ;WRITE Ox9A




;turn off bra for simulator. turn back on for real thing



      bra     numbertoascii


;square root from internet.

;input NNNN.NNNN     w0.w1

;result NN.NN  w0


;input .NNNNNNNN

;result .NNNN w0



;result NNNN w0


        push    w2

       push    w3

       push    w4

       push    w5


       mov.w   #0x8000,w3

       clr     w2


       ior     w3,w2,w2

       mul.uu  w2,w2,w4

       sub     w1,w4,w4

       subb    w0,w5,w5

       bra     C,sqroot2

       xor     w3,w2,w2


       lsr     w3,w3

       bra     NZ,sqroot1

       mov     w2,w0

       pop     w5

       pop     w4

       pop     w3

       pop     w2



;arctan  +- 0.75 deg

;for z<1

;input w0.NNNN as fraction ie opp/adj <1

;output w0 degrees  NN.NN

;arctan(z)=z-(z^3/4.6) ( approx in radians *57.26 for degrees )

;to do arctan >1 do adj/opp and subtract it from 90 for answer.

;test for this before calling


       push.d  w2

       push.d  w4

       mov     w0,w2           ;save z

       mul.uu  w2,w2,w4        ;w4:w5=z^2 w5=MSW

       mul.uu  w2,w5,w4        ;times by z again w5=MWS  z^3 in w5

       mov     #46,w4

       repeat  #17

       div.u   w5,w4           ;divide by 46. answer in w0

        mov     #10,w1

       mul.uu  w0,w1,w4        ;make it div by 4.6. w5=MSW w5 will be 0. max value of w4 14240

       sub     w2,w4,w0        ;w0=z-(z^3/4.6)

       mov     #58671,w1       ;57.296*1024 deg in a radian

       mul.uu  w0,w1,w4        ;w4:w5 = arctan(z)*1024 w5=MSW

       bclr    SR,#C           ;clear carry

       rrc     w5,w5           ;rotate down 2 bits

       bclr    SR,#C           ;clear carry

       rrc     w5,w5           ;now NN.NN

       mov     w5,w0           ;return degrees

       pop.d   w4

       pop.d   w2





;for z<1

;input w0 .NNNN

;output w0 NN.NN in degrees


       push.d  w2

       push.d  w4

       push.d  w6  

       push.d  w8      

       mov     w0,w2

       mul.uu  w0,w0,w4        ;w5 holds MSW

       mov     w5,w6           ;save z^2

       mul.uu  w0,w6,w4        ;w5 holds MSW

       mov     w5,w7           ;z^3

       mov     #13901,w1       ;a1

       mul.uu  w0,w1,w4        ;a1*z  w5=MSW

       mov     w5,w8           ;w8=a1*z

       mov     #4867,w1        ;a2

       mul.uu  w1,w6,w4        ;a2*z^2 w5=MSW

       mov     w5,w9           ;w9=a2*z^2

       mov     #1227,w1        ;a3

       mul.uu  w1,w7,w4        ;a3*z^3  w5=MSW

        bclr    SR,#C           ;clear carry

       rrc     w5,w5           ;/2

       bclr    SR,#C           ;clear carry

       rrc     w8,w8           ;/2  

       bclr    SR,#C           ;clear carry

       rrc     w9,w9           ;/2     

       mov     #51470,w0       ;a0

       sub     w0,w8,w0        ;w0=w0-w8 w0=a0-a1*z

       add     w0,w9,w0        ;w0=w0+w9 w0=a0-a1*z+a2*z^2

       sub     w0,w5,w0        ;w0=w0-w5 w0=a0-a1*z+a2*z^2-a3*z^3

       mov     w0,w9           ;save in w9

       mov     #65535,w0       ;move 1 into w0 ( nearly 1 )

       sub     w0,w2,w0        ;w1=w1-w2  1-z

       clr     w1              ;clear w0

       rcall   squareroot      ;answer in w0 .NNNN

       mul.uu  w0,w9,w4        ;sqrt(1-z)*(a0....) w5=MSW . B.NNN here w9 half size due to rrc above

       mov     w5,w0           ;get MSW

       mov     #51472,w1       ;pi/2 *32768 ( 15 bit B.NNN

       sub     w1,w0,w0        ;w0=w1-w0  pi/2-sqrt(1....     B.NNN-B.NNN=B.NNN

       mov     #29335,w1       ;57.296*512 deg in a radian

       mul.uu  w0,w1,w4        ;w4:w5 = arctan(z)*256 w5=MSW

       mov     w5,w0           ;return degrees        

       pop.d   w8

       pop.d   w6

       pop.d   w4

       pop.d   w2




;arccos(z)=pi/2-arcsin(z) in radians

;for z<1

;input w0 .NNNN

;output w0 NN.NN in degrees


       push    w1

       rcall   arcsin

       mov     #90*256,w1      ;90 degrees in NN.NN format

       sub     w1,w0,w0        ;90 degrees-arcsin(z) in NN.NN format

       pop     w1




;fraction as ascii  w0

;in w0=.NNNN output  buffer-> .AAAAAAAAAAAAAAAA  LSB first


       push    w1

       push.d  w4

       push.d  w6

       mov     #buffer,w6

       mov     #10,w4

       mul.uu  w0,w4,w0        ;w1 holds value

       mov     #48,w5          ;0 ascii

       ior.b   w1,w5,[w6++]    ;shift out ascii to w6 ( buffer )    

       mul.uu  w0,w4,w0        ;drops the old value in w1 and takes the next tenth of w0

       ior.b   w1,w5,[w6++]    ;n=0-9 plus 48

       mul.uu  w0,w4,w0

       ior.b   w1,w5,[w6++]

       mul.uu  w0,w4,w0

       ior.b   w1,w5,[w6++]

       mul.uu  w0,w4,w0

       ior.b   w1,w5,[w6++]

       mul.uu  w0,w4,w0

       ior.b   w1,w5,[w6++]

       mul.uu  w0,w4,w0

       ior.b   w1,w5,[w6++]

       mul.uu  w0,w4,w0

       ior.b   w1,w5,[w6++]

       mul.uu  w0,w4,w0

       ior.b   w1,w5,[w6++]

       mul.uu  w0,w4,w0

       ior.b   w1,w5,[w6++]

       mul.uu  w0,w4,w0

       ior.b   w1,w5,[w6++]

       mul.uu  w0,w4,w0

       ior.b   w1,w5,[w6++]

       mul.uu  w0,w4,w0

       ior.b   w1,w5,[w6++]

       mul.uu  w0,w4,w0

       ior.b   w1,w5,[w6++]

       mul.uu  w0,w4,w0

       ior.b   w1,w5,[w6++]

       mul.uu  w0,w4,w0

       ior.b   w1,w5,[w6++]

       pop.d   w6

       pop.d   w4

       pop     w1




Maths Functions for pic24/dspic30/33


In assembly

Download source here