• Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

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!
 

MikeMl

Well-Known Member
Most Helpful Member

Ian Rogers

User Extraordinaire
Forum Supporter
Most Helpful Member
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
Most Helpful Member
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
   addwf pcl,f
   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
   addwf pcl,f
   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
   addwf yL,w
   movwf xL
   btfsc status,c
   incf xH,f
   movf yH,w
   addwf xH,f
   ;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
   addwf yL,f
   btfsc status,c
   incf yH,f
   movf vH,w
   addwf yH,f
   ;x=x+y>>index
   movf tL,w
   addwf xL,f
   btfsc status,c
   incf xH,f
   movf tH,w
   addwf xH,f
   ; Sum Angle from lookup table
   movf index,w
   call LU_AngleFrac
   movwf tL
   movf index,w
   call LU_AngleInt
   movwf tH
   btfss yH,7
   goto AddSum
   comf tH,f
   comf tL,f
   incf tL,f
   btfsc status,z
   incf tH,f
AddSum
   movf tL,w
   addwf angleL,f
   btfsc status,c
   incf angleH,f
   movf tH,w
   addwf angleH,f
   incf index,f
   movlw nTable
   subwf index,w
   btfss status,z
   goto MainLoop
   retlw 1
 
Last edited:
Status
Not open for further replies.

Latest threads

EE World Online Articles

Loading
Top