|
|
View previous topic :: View next topic |
Author |
Message |
p_chusak
Joined: 24 Nov 2004 Posts: 3 Location: thailand
|
How to make this code more fast? |
Posted: Wed Nov 24, 2004 1:13 am |
|
|
Hi i'am a new pic user;
I try to make servo control By Pic 18f4431
I have some problem
for this code
output_bit(PIN_B1,1);
compen_s=(kp_servo*new_error_pos/100)+ Kd_servo*diff_error_pos/100);
output_bit(PIN_B1,0);
all variable are 32bit signed
I use oscillloscope display output of PIN_B1
it show B1 high about 0.235ms or 235us i use 10Mz in H4 mode so
this process use 2350 Cycle (approximate) it use 35-40% cpu bandwidth
for one line code ( servo loop call every .5ms )
In datasheet of pic18f4431 i see hard ware multiply for fast mul
How i use it for this problem? or How to make this code line faster?
Thank. |
|
|
Ttelmah Guest
|
|
Posted: Wed Nov 24, 2004 3:56 am |
|
|
Division is the real 'killer' here. Do you need to use /100?. If you can change the scaling of your numbers, so you can use a _binary_ division (/128, or even better /256), then you can easily reduce the times by perhaps a factor of 3*. Division is the slowest arithmetic operation in general.
In general, servo algorithms in the PIC, use *256, as the 'factor', then you can declare a union somthing like:
Code: |
/* This union is used internally to allow access to the various parts of each
32bit 'address' as bytes, 16bit integers etc. */
union lblock {
unsigned int16 ui[2];
signed int16 i[2];
int8 b[4];
signed int32 word;
};
//Trims an incoming 32bit value to a 24bit value.
signed int32 trim24(union lblock val) {
if (val.b[3] & 0x80) {
//Here -ve
if ((val.b[3] != 0xFF) || !(val.b[1] & 0x80)) val.word=0xff800001l;
}
else {
if ((val.b[3]) || (val.b[1] & 0x80)) val.word=0x7FFFFFl;
}
return(val.word);
}
//performs a division by 256 (using shift), and trims result to 24 bits.
signed int32 div256(union lblock val) {
val.b[0]=val.b[1];
val.b[1]=val.b[2];
val.b[2]=val.b[3];
return(trim24(val.word));
}
|
The main arithmetic, is then done on the values at 256* their 'target' sizes, and div256, used to give the final scale.
On the code as written (without bothering to do this), you could probably get about a 25% speed increase, by recoding as:
compen_s=(kp_servo*new_error_pos)+ (Kd_servo*diff_error_pos)/100;
This gives just one division, rather than the two seperate ones being used...
The hardware multiplier should already be being used by the compiler. Even then though, it is only an '8*8' multiplier, and requires several calls to complete a 32*32 multiplication, and handle the signs correctly.
Best Wishes |
|
|
p_chusak
Joined: 24 Nov 2004 Posts: 3 Location: thailand
|
|
Posted: Wed Nov 24, 2004 7:53 pm |
|
|
Wow""ThanK:)......A lot>>.
now speed up >60% by shift>>8 and get 24bit signed""" |
|
|
Guest
|
|
Posted: Thu Nov 25, 2004 12:37 am |
|
|
p_chusak wrote: | Wow""ThanK:)......A lot>>.
now speed up >60% by shift>>8 and get 24bit signed""" |
18F452, 20 MHz, CCS 3.212, arithematics speed in usec
s_int32 * s_int32 45
float + float 36
float * float 28
float / float 227
floating point (24 bits) is faster than int32 !
I did not check how long does s_int32 / s_int32 takes,
anyway, divide always takes a long long time,
instead of using (int32)x / (int32)100,using (float)x * 0.01 might be faster ? |
|
|
Guest
|
|
Posted: Thu Nov 25, 2004 12:53 am |
|
|
noticed that 1/100 ~ 1/128 + 1/512 + 1/4096
so, instead of using y = x/(int32)100, try this
int32 x, y, a;
y = (a=x>>7);
y+= (a>>=2);
y+= (a>>=3);
should be less than 7 usec at 40 MHz, I guess |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|