View previous topic :: View next topic |
Author |
Message |
rovtech
Joined: 24 Sep 2006 Posts: 262
|
Mixing Int8 and float in CCS C math |
Posted: Wed Mar 15, 2023 3:52 pm |
|
|
Doing math in CCS C
Y = mX + B
where Y and X are 8 bit integers (max 255), B is a constant 35, and m is a fraction 0.374
X and B get promoted in the expression to float for the evaluation, and the result is demoted by assignment to integer in Y. X remains int8 after the expression is evaluated.
Since mX + B can never exceed 255 then Y, X, and B can all be int8.
Am I correct? I don't want to have to test this on a PIC with a display.
Can I write the expression so B does not get promoted to float? |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9221 Location: Greensville,Ontario
|
|
Posted: Wed Mar 15, 2023 4:30 pm |
|
|
hmm, my first idea is to just code using 'scaled integers'.....
m becomes 374 instead of .374. Y,X and B have to be scaled as well....
this eliminates floats AND decreases the 'time of calculation by 10-15x.
,it'll also reduce code space a LOT as well.
others will reply that do this daily.
PICs don't play well with 'floats'.
Jay |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
Re: Mixing Int8 and float in CCS C math |
Posted: Wed Mar 15, 2023 5:15 pm |
|
|
rovtech wrote: |
I don't want to have to test this on a PIC with a display.
|
Since it's pure math, you can easily test it with MPLAB vs. 8.92 and the
built-in simulator.
Links to download MPLAB vs. 8.92 and the CCS plugin, if you don't have
them already:
http://www.ccsinfo.com/forum/viewtopic.php?t=59016&start=2
See this link for how to use the UART1 feature of MPLAB vs. 8.92 to display
printf statements in the Output window:
http://www.ccsinfo.com/forum/viewtopic.php?t=40045
You don't need hardware or a display. You can do it all in MPLAB vs. 8.92. |
|
|
rovtech
Joined: 24 Sep 2006 Posts: 262
|
|
Posted: Wed Mar 15, 2023 6:18 pm |
|
|
Thank you, I use MPLAB 8.92
I read the link but see a problem. My clock is 32kHz so this may not work.
I wasn't looking for another project but appreciate learning about it and will try it when I have time.
For now I like Y = (374 * X)/1000 +35 and can try it but that product can be as high as 95,370 (374 * 255) so can X still be Int8?
I thought there may be a way using casting to do this.
What about what I originally asked? Are my assumptions correct?
Since the PIC16F1509 is dedicated to running 4 PWM at 50 Hz it has lots of memory and time. It gets an I2C update about once a second. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Mar 15, 2023 8:20 pm |
|
|
0.374 x 255 = 95.37 and then add 35 to that and you get 130.7.
So yes, as long as m is always 0.374 and B is 35, you can use int8
variables for X, Y, and B.
Code: | #include <18F46K22.h>
#fuses NOWDT
#use delay(internal=4M)
#use rs232(UART1, baud=9600, ERRORS)
#define m 0.374
//=================================
void main (void)
{
int8 Y;
int8 X;
int8 B;
B = 35;
X = 255;
Y = (m * X) + B;
printf("Y=%u\r", Y);
while(TRUE);
}
|
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19496
|
|
Posted: Thu Mar 16, 2023 4:53 am |
|
|
and, in answer to:
"Can I write the expression so B does not get promoted to float?".
Yes:
Y = (int8)(m*X) + B;
Will evaluate m*x as float, then convert this to int8, and add the result to
B. So with the example of X=255, you get:
255*.374 = 95.37 -> gives 95 as an int.
95+35 = 130.
However it is also worth realising that the error between 0.374 and 0.375
is less than one in this. So you could use:
Code: |
int8 t;
t=X/4;
Y=t+t/2 + B;
|
Which for the example of 255, gives t=63, then Y = 63+31+35 = 129
Almost the same answer, for the cost of two integer divisions, and two
additions.
Smaller and faster than getting float involved at all.... |
|
|
rovtech
Joined: 24 Sep 2006 Posts: 262
|
|
Posted: Thu Mar 16, 2023 9:17 am |
|
|
Thank you all, these are exactly the ideas I was hoping for but easier than I anticipated.
The problem of slow clock I am using got me re-thinking where to do the math. Briefly, my submersible ROV has a slave PIC in the surface control console that reads switches, pots, and a Joystick. It passes the results to the Master PIC that sends, down 300ft of tether, to a Master PIC in the ROV which sends to various slaves including one that controls the servos. The climb/dive byte from the Joystick is X in the equation but also goes to my side thruster rotate control PIC that uses a motor and feedback pot so I cannot change X in the console. I could do the math in the ROV master PIC before it passes the data to the slave servo PIC. I don't want to mess with the Master PIC and slow it down. Just thinking aloud.
The math changes 0 to 5v from the Joystick to be 800 to 1800 uS pulses out of the PWM of the PIC at 50 Hz. Either variable is Int8 so it does not matter where the math is done except for speed and efficiency. It might be simpler to send an extra separate byte from the surface.
I will try PCM Programmers suggestion of using the UART1 feature of MPLAB in my Console slave PIC to confirm the math. It will be a very useful debug tool for me.
Updating from using delays to PWM is turning out to be unpleasant. However adding 2 more servos to rotate the camera and a sonar transducer dictate the change.
I also see that .375 = 3/8 so I can use
Y = ((3/8) * X) + B which Ttelmah used, but why that way?
Using X/4 in place of t in your equation gives Y=X/4 + (X/4)(1/2) + B
So 2X/8 + X/8 = 3/8 X why not use this?
However the m is the slope of a line and can easily be different for different ranges of servo travel. I must use float. I like Ttelmah's
Y = (int8)(m*X) + B;
I wonder if my 32kHz PIC can handle this. This would be the easiest solution.
Last edited by rovtech on Thu Mar 16, 2023 10:54 am; edited 1 time in total |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19496
|
|
Posted: Thu Mar 16, 2023 10:20 am |
|
|
Key is that if you do *3, this has to use the generic integer multiply.
Now /2, /4 & /8 in integer can all be optimised to a simple rotation.
So generating /4 and /2 each only use a couple of instructions. 3/8,
will use tens of instructions.
You could optimise it as X+=(X*2), then X/=8, which would be quite
efficient. |
|
|
rovtech
Joined: 24 Sep 2006 Posts: 262
|
|
Posted: Fri Mar 17, 2023 6:31 pm |
|
|
To get a PWM frequency of 50 Hz compatible with RC servos I had to use 31.25 kHz and a PR2 of 156. I measured the time for a loop of While (1) without the math, with the math, and with the math and cast as Ttelmah described. Slope m wound up at 0.14 so the exercise was well worth the effort.
Since 31.25 KHz froze my I2C communications I used 2 MHz and setup_timer_2(T2_DIV_BY_64,156,1) to retain the PRW 50 Hz and measured the times again.
31.25 kHz
No math = 3.6 mS
mX+B = 133 mS
Int8)(mX)+b = 110 mS
2 MHz
No math = 16 uS
mX+B = 1.7 mS
Int8)(mX)+b = 1.6 mS
My Rudder, Elevator, and Camera Tilt are working beautifully.
Thanks for the help.
Peter |
|
|
alan
Joined: 12 Nov 2012 Posts: 357 Location: South Africa
|
|
Posted: Sat Mar 18, 2023 2:31 am |
|
|
Just my 2c worth. Been using Horner method very sucessfully in floating point multiplication and division and works like a dream.
See TI app note
https://www.ti.com/lit/pdf/slaa329 |
|
|
|