Efficient Fixed-Point Trigonometry For PIC16F


Closed Thread
Results 1 to 13 of 13

Hybrid View

  1. #1
    Join Date
    Feb 2006
    Location
    Gilroy, CA
    Posts
    1,530

    Default Efficient Fixed-Point Trigonometry For PIC16F

    Microchip has an application note AN1061 http://ww1.microchip.com/downloads/e...tes/01061A.pdf which talks about using the ATAN function, among other things. I can't wait to use it for a project I am working on ........ I just need to know how. .....

    I am a newbie when it comes to adding includes. I tried a few different ways to add the assembly code for the atan, and I could not get it to compile. I tried using the math16.asm file as an include in a new main program, I also tried cutting and pasting the assembly into a main.pbp program with asm and endasm lines on the front and back. Can someone steer me in the right direction? This cordic function would be perfect for me.

    I get the following error when trying to compile with MPASM using MicroCode Studio Plus: Error[149] Directive only allowed when generating an object file.
    I get this for multiple line listings of the assembly code, but this does not seem to make sense for the lines it references. Like

    movlw 0x00 ; Y_H & Y_L is loaded with 0x0000

    Thanks for your help.

    Walter
    Attached Files Attached Files
    Last edited by ScaleRobotics; - 15th November 2007 at 16:47.

  2. #2
    Join Date
    Jul 2003
    Location
    Colorado Springs
    Posts
    4,959


    Did you find this post helpful? Yes | No

    Default

    Hi Walter,

    The MATH16.ASM file looks interesting.
    It's written as Relocatable Object Code, so isn't directly compatible with PBP.

    But with a bit of work you could modify it.

    Statements like UDATA, CODE , GLOBAL , and END get removed, or commented.

    Names with RES are variables, so they need to be defined in Basic.
    Something like ...
    Code:
    X    VAR WORD
    @X_H = _X + 1 
    @X_L = _X
    And some of the labels need to be renamed.
    DIV and MUL already exist is PBP.
    DT

  3. #3
    Join Date
    Feb 2006
    Location
    Gilroy, CA
    Posts
    1,530


    Did you find this post helpful? Yes | No

    Default

    Thanks for the pointers. I was able to get ATAN working! Wooohooo! I must have done something to the sincos function though. I get the same result, no matter what variable I enter into x. It is supposed to cos the value of x and give the result in y, and sin the value of x, and give the result in z. I'm a little brain dead right now, so I will have to check it further in the morning.

    Code:
    ;****************************************************************************
    ;*	Microchip Technology Inc. 2006					*
    ;*	Filename: Main.asm									*
    ;*																*
    ;****************************************************************************
    
    DEFINE __16F877A 1				; list directive to define processor
    DEFINE OSC 20                          ' Define Oscillator Speed
    DEFINE LOADER_USED 1
    
    ' Shutdown comparators
    ADCON1 = 7                        ; Turn of all A/D
    CMCON  = 7
    ' Set the port directions
    ' 0=output 1=input
    TRISA=%00000011                         ' Set PORTA  0-1-3 used for AD
    TRISB=%11011100                         ' Set PortB
    TRISC=%10000000  
    TRISD=%00000000                       ' Set PortC USART RX as an input
    porta.2 = 0 
    porta.3 = 0
    
    X_H         VAR     byte
    ITERATION  VAR      byte
    X_L         VAR     byte
    Y_H         VAR     byte
    Y_L         VAR     byte
    Z_H         VAR     byte
    Z_L         VAR     byte
    X_TMP_H     VAR     byte
    X_TMP_L     VAR     byte
    Y_TMP_H     VAR     byte
    Y_TMP_L     VAR     byte
    ITERAT_TMP  VAR     byte
    Di          VAR     byte
    COSCH       VAR     byte
    COSCL       VAR     byte
    Counter1    VAR     byte
    SHIFT       VAR     byte
    x           var     word
    y           var     word
    z           var     word
    i           var     word
    
    ;---------[change these to match your hardware]------------------------------
    DEFINE LCD_DREG PORTD             ; Set LCD Data port                B C   D
    DEFINE LCD_DBIT 0                 ; Set starting Data bit (0 or 4)   4 0
    DEFINE LCD_RSREG PORTA            ; Set LCD Register Select port     A A
    DEFINE LCD_RSBIT 3                ; Set LCD Register Select bit      3 2
    DEFINE LCD_EREG PORTA             ; Set LCD Enable port              A A
    DEFINE LCD_EBIT 1                 ; Set LCD Enable bit               1 5
    DEFINE LCD_BITS 4                 ; Set LCD bus size (4 or 8 bits)   4 4
    DEFINE LCD_LINES 2                ; Set number of lines on LCD       2 2
    '----------------------------------------------------------------------------
    clear
    lcdout $FE,1
    portb.0 = 0
    pause 500
    lcdout $FE,1,"Test"
    portb.0 = 1
    
    Start:
    x = 250
    y = 0
    
    X_L = x.byte0
    X_H = x.byte1
    
    Y_L = y.byte0             'load values of y into Y_L ,just for atan, but does not hurt to leave 
    Y_H = y.byte1             'dito
    
    call sincos
    y.byte0 = Y_L             ' edit out if looking at atan
    y.byte1 = Y_H              'same here
    
    'Call atan
    
    
    z.byte0 = Z_L
    z.byte1 = Z_H
    'z=(z*100)/284                                       'corrects our output to an angle in degrees for atan
    'lcdout $FE,1,#z    
    
    
    
    portb.0 = 0
    lcdout $FE,1,#y
    lcdout $FE,$C0,#z 
    end '***********************************
    
    atan:
        asm
            call ATAN
        endasm
    return
    
    sincos:
        asm
            call SINCOS
        endasm
    return
    
    asm
    ;__________________________________________________________________________
    FSR_ptr	macro	addr
    	banksel	addr
    	bcf		STATUS,IRP
    	btfsc		STATUS,RP1
    	bsf		STATUS,IRP
    	movlw		LOW addr
    	movwf		FSR
    			endm
    
    	#define 	Dir	_Di,0
    	#define 	RV		_Di,1
    	#define	_C		STATUS,0
    	#define	_Z		STATUS,2
    
    Z_stepH_tbl
    	addwf	PCL,f
    	dt	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
    Z_stepL_tbl
    	addwf	PCL,f
    	dt	0x80,0x4C,0x28,0x14,0x0A,0x05,0x03,0x01
    Z_NstepH_tbl
    	addwf	PCL,f
    	dt	0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
    Z_NstepL_tbl
    	addwf	PCL,f
    	dt	0x80,0xB4,0xD8,0xEC,0xF6,0xFB,0xFD,0xFF
    
    ATAN
    	banksel	   _Z_H				; Z_H & Z_L is loaded with 0x0000
    	movlw		0x00				; Y & X is the input
    	movwf		_Z_H				; X(i+1)	=	Xi - Yi*_Di*2^-i
    	movlw		0x00				; Y(I+1)	=	Yi + Xi*_Di*2^-i
    	movwf		_Z_L				; Z(i+1)	=	Zi - _Di*ATAN(2^-i)
    	banksel	   _Di					; _Di		=	1 if Yi < 0 ELSE _Di	=	0
    	bsf		      RV					; Set Vectoring Mode
    	goto		CORDIC_Alg		
    
    SINCOS
    	banksel	   _Y_L				; Z_H & Z_L is the input
    	movlw		0x00				; Y_H & Y_L is loaded with 0x0000	
    	movwf		_Y_L				; X_H & X_L is loaded with 6070 (1/An constant)
    	movlw		0x00			
    	movwf		_Y_H			
    	movlw		LOW .6070	
    	movwf		_X_L				; X(i+1)	=	Xi - Yi*_Di*2^-i
    	movlw		HIGH .6070		; Y(I+1)	=	Yi + Xi*_Di*2^-i
    	movwf		_X_H				; Z(i+1)	=	Zi - _Di*ATAN(2^-i)
    	banksel	   _Di					; _Di		=	0 if Zi < 0 ELSE _Di	=	1
    	bcf		      RV					; Set Rotational Mode
    
    CORDIC_Alg
    	banksel	_ITERATION
    	clrf	_ITERATION
    Rotation_loop						
    BUFF_X_Y							; Buffers both X & Y into temporary registers 
    	banksel 	_Y_L
    	movf		_Y_L, W			; Move Y --> T_TEMP
    	movwf		_Y_TMP_L
    	movf		_Y_H, W
    	movwf		_Y_TMP_H
    	movf		_X_L, W			; Move Y --> T_TEMP
    	movwf		_X_TMP_L
    	movf		_X_H, W
    	movwf		_X_TMP_H
    
    	banksel	   _Di					; Vectoring or Rotational Mode?
    	bcf		      Dir
    	btfsc		RV
    	goto		Rot
    Vec
    	btfss		_Z_H, 7			; Determine the state of _Di (1 OR -1)
    	bsf		  Dir				; _Di=1 when Z_H is pos
    	goto		Cordic
    Rot
    	btfsc		_Y_H, 7			; Determine the state of _Di (1 OR -1)
    	bsf		  Dir				; _Di=1 when Y_H is neg
    
    Cordic
    	movfw		_ITERATION
    	movwf		_SHIFT				; Load number of shifts
    	bsf		      _SHIFT,7			; Shift right (Division)
    	FSR_ptr	   _Y_TMP_L			; Load FSR
    	call		Shifter			; Execute shift
    
    	btfsc		Dir
    	call		COM_YTEMP		; Get the 2's complement of teh TEMP register 
    SUM_X								; Calculate X(i+1)
    	movf		_Y_TMP_H, W		
    	addwf		_X_H, F
    	movf		_Y_TMP_L, W
    	addwf		_X_L, F
    	btfsc		_C
    	incf		_X_H, F
    	
    	movfw		_ITERATION
    	movwf		_SHIFT				; Load number of shifts
    	bsf		  _SHIFT,7			; Shift right (Division)
    	FSR_ptr	   _X_TMP_L			; Load FSR
    	call		Shifter			; Execute shift
    
    	btfss		Dir
    	call		COM_XTEMP		; Get the 2's complement of teh TEMP register
    SUM_Y								; Calulate Y(i+1)
    	movf		_X_TMP_H, W		
    	addwf		_Y_H, F
    	movf		_X_TMP_L, W
    	addwf		_Y_L, F
    	btfsc		_C
    	incf		_Y_H, F
    
    	btfss		Dir
    	goto		ADD_Z
    
    	movlw		HIGH Z_NstepH_tbl	
    	movwf		PCLATH
     	movfw		_ITERATION		; Fetch appropriate value from table
    	call		Z_NstepH_tbl	
    	addwf		_Z_H, F
    	movlw		HIGH Z_NstepL_tbl
    	movwf		PCLATH
     	movfw		_ITERATION
    	call		Z_NstepL_tbl	
    	addwf		_Z_L, F
    	btfsc		_C
    	incf		_Z_H, F
    	goto		Rot_Loop_out
    
    ADD_Z
    	movlw		HIGH Z_stepL_tbl
    	movwf		PCLATH
     	movfw		_ITERATION
    	call		Z_stepH_tbl
    	addwf		_Z_H, F
    	movlw		HIGH Z_stepH_tbl
    	movwf		PCLATH
     	movfw		_ITERATION
    	call		Z_stepL_tbl
    	addwf		_Z_L, F
    	btfsc		_C
    	incf		_Z_H, F
    
    Rot_Loop_out
    	incf		_ITERATION,f
    	btfsc		_ITERATION,3
    	return
    	goto		Rotation_loop
    
    COM_YTEMP
    	comf		_Y_TMP_L, F		; Complememt Y_TMP
    	comf		_Y_TMP_H, F
    	movlw		01H
    	addwf		_Y_TMP_L, F
    	btfsc		_C
    	incf		_Y_TMP_H, F
    	return 
    COM_XTEMP
    	comf		_X_TMP_L, F		; Complememt X_TMP
    	comf		_X_TMP_H, F
    	movlw		01H
    	addwf		_X_TMP_L, F
    	btfsc		_C
    	incf		_X_TMP_H, F
    	return
    
    Shifter							; Function for shifting 16bit signed REG i times 
    	banksel	   _SHIFT				;  left/right MUL/DIV
    	movfw		_SHIFT				; INPUTS: FSR & IRP are pointing to LOW REG
    	andlw		0x0F				; SHIFT = d000 XXXX where XXXX = # of shifts 
    	btfsc		_Z					; 	and d = dir of shift
    	return						; check for zero interations
    	movwf		_Counter1
    	btfss		_SHIFT,0x7
    	goto		CORDIC_MUL
    	
    CORDIC_DIV
    	rrf		INDF, F			; Divide INDF/2 INDF --> low byte
    	bcf		INDF, 7
    	decf 		FSR, F
    	rrf		INDF, F	 
    	incf 		FSR, F
    	btfsc		_C
    	bsf		INDF, 7			; Carry from the upper byte to the lower byte
    	decf 		FSR, F
    	bcf		INDF, 7			; Check to see if TEMP should be a positive number
    	btfsc		INDF, 6
    	bsf		INDF, 7			; Was a negative number, force it negative again 
    	incf 		FSR, F
    	decfsz	_Counter1, F
    	goto		CORDIC_DIV
    	return
    	
    CORDIC_MUL
    	bcf		_C
    	rlf		INDF, F
    	decf 		FSR, F
    	rlf		INDF, F
    	bcf		INDF, 7
    	btfsc		_C
    	bsf		INDF, 7
    	incf 		FSR, F
    	decfsz	_Counter1, F
    	goto		CORDIC_MUL
    	return
    ;______________________________________________________________________________
    endasm
    Last edited by ScaleRobotics; - 16th November 2007 at 10:40.

  4. #4
    Join Date
    Sep 2004
    Location
    montreal, canada
    Posts
    6,898


    Did you find this post helpful? Yes | No

    Default

    Carefull when using Banksel and PBP, i would suggest you to replace all BANKSEL for CHK?RP

    CHK?RP is to PBP what BANKSEL is to ASM.

    Using BANKSEL will make weird things and lost compiler because he don't know where he was before etc etc... i understand why... i just can't explain it correctly.

    Darrel could you shed some lights and explain it in english
    Steve

    It's not a bug, it's a random feature.
    There's no problem, only learning opportunities.

  5. #5
    Join Date
    Feb 2006
    Location
    Gilroy, CA
    Posts
    1,530


    Did you find this post helpful? Yes | No

    Default

    Thanks a lot mister_e,

    I added your suggestion, which will probably help in the long run. However, I still get the same result for Cos(x) = 71 no matter what I give as x. When edited out of some of the lines that had "global" in them, as suggested in an earlier post, was I supposed to replace "global" with something else? Here are some of the lines I deleted from various places in the program:

    GLOBAL X_L, X_H, Y_L, Y_H, Z_L, Z_H, SHIFT
    GLOBAL ATAN
    GLOBAL SINCOS
    GLOBAL Shifter

    I don't really understand what these lines did in the original assembly code.
    I also wonder if I defined any of the variables wrong. RV, Dir, _C, and _Z are defined inside the assembly code, and the other variables are named in the pbp code. Strange that the ATAN functions great, just the SINCOS having difficulties.

  6. #6
    Join Date
    Jul 2003
    Location
    Colorado Springs
    Posts
    4,959


    Did you find this post helpful? Yes | No

    Default

    The Input to SINCOS is the Z variable. (Not X)

    I've got it working here, but it seems like it's not right.
    Input range is from -256 to +255.

    I've plotted the results. Does it look right to you?

    <img src="http://www.picbasic.co.uk/forum/attachment.php?attachmentid=2133&stc=1&d=119533895 6">
    <br>
    Attached Images Attached Images  
    DT

Members who have read this thread : 2

You do not have permission to view the list of names.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts