# Cartesian to Polar coordinate on a PIC micro in Assembly

Status
Not open for further replies.

#### Beau Schwabe

##### Active Member
Just wondering if anyone has a slick Cartesian to Polar algorithm they would be willing to share that will work on a small microprocessor (PIC10F202) that does not have any built-in math functions? The X and Y values from the sensor are 12-Bit resolution, and I am just looking for the angle in the polar conversion and NOT the radius. It is easy enough to determine which 90-Deg quadrant the angle is in based on the sign of the X & Y values, and taking that a step further you can compare the X & Y values to determine which 45-Deg slice it is in within the 90-Deg quadrant... i.e. X=Y it's right on the 45... if X>Y or X<Y you can determine which half of the 90-Deg quadrant you are in... beyond that it gets a little more complex. I would like to minimize the lookup table to something as small as possible with at least 1 Deg resolution ....

Thanks!

#### Pommie

##### Well-Known Member
Check out Roman Blacks site.

I modified this slightly to make a circle 256 degrees. Very useful.

Mike.

#### Ian Rogers

##### User Extraordinaire
Forum Supporter
I would forget any calculations on that device... 24 bytes of ram and only 512 bytes of rom..
You would be far better off with the big brother Pic12f1840....

Forget the little six pin devices.. ( I take it's the small footprint you need )

You could get this in a 15 byte lookup table with 0.1 precision, but if X and Y are both 12bit that's a third of your memory gone...

#### Beau Schwabe

##### Active Member
"I would forget any calculations on that device... 24 bytes of ram and only 512 bytes of rom...( I take it's the small footprint you need )" ... Yes, I know, but you would be surprised when you program in nothing but Assembly .... I did some work last night and made some decent progress .... I have bit banged the I2C, Serial communication (autobaud), 32-bit math multiply/divide, and still have just enough room for a lookup table that represents 1/8th of a circle to have at least 1/2 a degree accuracy. If I have to I can back off of that for just 1 Deg accuracy. Between the micro and the sensor I am using, the total footprint fits in an 8-pin DIP, so a micro that is physically larger would not work. The price point for the PIC10F202 is good for me in quantities of 100.

#### Ian Rogers

##### User Extraordinaire
Forum Supporter
Fair due's...

The pic12 8pin range is quite vast and some are very cheap, but seeing as you are almost there on the 202 ( there is always the 3xx range..

I have some routines, but a bit too large for what you need.. My arctan routine has a 30 x int sized lookup..

#### BobW

##### Active Member
I agree with MikeMI. The CORDIC algorithm is ideal for this. I did quick spreadsheet to figure out how much input resolution you actually need in order to get an output to the nearest degree. I found that you can truncate your X and Y values to 7 bits (from the original 12), making the math a lot simpler. The lookup tables that CORDIC uses are very small. I believe the tables are only 6 elements long, and that you'd need four of them. Easily implemented in your chip in assembly language.

#### atferrari

##### Well-Known Member
Learning, always learning.

I should give a try to CORDIC.

Wow!

#### BobW

##### Active Member
I may have a solution for this. I was playing with the CORDIC algorithm on the weekend, and got it working… sort of. There are a couple of glitches that I'm trying to track down. For the most part, it's accurate to a small fraction of a degree, but there are certain combinations of X and Y that give the wrong results. No doubt, it's some silly programming blunder that I've made.

#### Beau Schwabe

##### Active Member
Hey Bob, I'd be interested in seeing that Coordic routine. I have used a COORDIC routine in the past on a Propeller Chip, but I couldn't easily get my head around it to convert it to a PIC. Right now I have an implementation that is accurate to 1/2 a degree and I only need to store 1/8th of the complete circle in a lookup table. .... So far I have used 390 BYTES out of 512, and 127 of the 390 is the lookup table.... 263 BYTES for I2C, Serial(Autobaud up to 38.4k), Command Decision Tree from the serial input and Lookup table conversion, and I was able to reduce my math to using only 24-bit division. The multiplication is a simple left shift routine.

#### BobW

##### Active Member
In the end, my program bug was that I was checking the carry bit when I should have been looking at the zero bit in a couple of places. It's always some dumb thing like that.
The lookup tables are very short, but there's quite a bit of code. This will work with any input 0..90°, it doesn't have to be limited to angles <= 45°. I looked at doing that, but there was no advantage in either the lookup table size or program size.
Total code including lookup tables is 149 instructions.
The result is accurate to within +/- 0.048 degrees.

Code:
;CORDIC ATAN2 function
;Coded by Robert Weaver, 2018-02-12
;On entry, the 12 bit (0..8191) values of x and y should be in xL,xH,yL,yH
;The upper 4 bits of xH and yH must be zero.
;Input values are assumed to be positive. Hence the angle is in the first quadrant.
;On completion, the angle (in degrees) is in AngleH and AngleL
;The integer part is in AngleH, and the fractional part is in AngleL
;If no error, then on return wreg contains 1, otherwise it contains 0.
;Due to the 16 bit math operations, the maximum error in the result is +/- 0.048 degrees.

cblock  0x20
xH,xL,yH,yL,angleH,angleL ; Input and output variables
index,count,tL,tH,vL,vH ; counters and temporary storage
endc

;Arctan lookup tables (degrees)
;Each entry is the arctan of a negative power of 2
;starting with 2^-1 and ending with 2^-14
LU_AngleFrac ;This table is the fractional part
retlw .144
retlw .9
retlw .32
retlw .147
retlw .202
retlw .229
retlw .114
retlw .57
retlw .28
retlw .14
retlw .7
retlw .4
retlw .2
retlw .1
LU_AngleInt ;This table is the integer part
retlw .26
retlw .14
retlw .7
retlw .3
retlw .1
retlw .0
retlw .0
retlw .0
retlw .0
retlw .0
retlw .0
retlw .0
retlw .0
retlw .0
nTable   equ LU_AngleInt - LU_AngleFrac ; calc size of lookup table

;Main entry point for Atan2 function
Atan2
clrf angleH
clrf angleL
;Check for all zero input combinations
movf xL,w
iorwf xH,w
iorwf yL,w
iorwf yH,w
btfsc status,z
retlw 0 ; Both inputs are zero which is indeterminate, return error
;check if y=0
movf yH,w
iorwf yL,w
btfsc status,z
retlw 1 ; angle is zero, so return
;check for x=0
movlw 90
movwf angleH
movf xH,w
iorwf xL,w
btfsc status,z
retlw 1 ;angle is 90, so return
movlw 45
movwf angleH
; Scale up x and y to improve resolution
ScaleXY
bcf status,c ;shift xH and yH left
rlf xL,f
rlf xH,f
bcf status,c
rlf yL,f
rlf yH,f
movf xH,w
iorwf yH,w
andlw 0xF0
btfsc status,z
goto ScaleXY
;xH and yH are now normalized
;calc x and y initial values
;save old x, as it will be overwritten
movf xH,w
movwf vH
movf xL,w
movwf vL
;calc x=x+y
movwf xL
btfsc status,c
incf xH,f
movf yH,w
;calc y=y-x
movf vL,w
subwf yL,f
btfss status,c
decf yH,f
movf vH,w
subwf yH,f
clrf index ;Loop counter and lookup table index
MainLoop
;shift x and y values
movf index,w
movwf count
;calc x y shift
movf yH,w
movwf tH
movf yL,w
movwf tL
movf xH,w
movwf vH
movf xL,w
movwf vL
btfss yH,7 ;check for negative y
goto ShiftLoop
comf tH,f
comf tL,f
incf tL,f
btfsc status,z
incf tH,f
ShiftLoop
bcf status,c
rrf vH,f
rrf vL,f
bcf status,c
rrf tH,f
rrf tL,f
bcf status,c
decfsz count,f
goto ShiftLoop
;calc new xH and yH
btfsc yH,7
goto NewXYcalc
;y=y+/-yH>>index
comf vH,f
comf vL,f
incf vL,f
btfsc status,z
incf vH,f
NewXYcalc
movf vL,w
btfsc status,c
incf yH,f
movf vH,w
;x=x+y>>index
movf tL,w
btfsc status,c
incf xH,f
movf tH,w
; Sum Angle from lookup table
movf index,w
call LU_AngleFrac
movwf tL
movf index,w
call LU_AngleInt
movwf tH
btfss yH,7
comf tH,f
comf tL,f
incf tL,f
btfsc status,z
incf tH,f
movf tL,w
btfsc status,c
incf angleH,f
movf tH,w
incf index,f
movlw nTable
subwf index,w
btfss status,z
goto MainLoop
retlw 1

Last edited:
Status
Not open for further replies.