2012-05-20 11:02 AM
The input to this function is a 'Desired Frequency' and the function, fairly quickly locates (out of the 4 billion possibilities! (ARR(16bit)*PSC(16bit)) the correct values for a given TIMER'S PRESCALER(PSC) and PERIOD(ARR) such that you get the TIMER as close as possible to your 'Desired Frequency.'
I just thought someone could use this, I have integrated this into my PHP web interface, but since it is practically C code, you guys could use it with little modification. Enjoy... Example outputs: 'Prescaler set at 0x2BFF uC Response: PSC=P00002BFF Period set at 0x0153 uC Response: ARR=A00000153 Desired Frequency = 11 Found Frequency = 000071500465, Prescaler = 2BFF, Period = 0153'' ''Prescaler set at 0x0005 uC Response: PSC=P00000005 Period set at 0x0054 uC Response: ARR=A00000054 Desired Frequency = 100000 Found Frequency = 100000, Prescaler = 0005, Period = 0054''function
SetTimeBase(
$fdes
)
{
$fclk
= 168000000;
$period
= 65535;
$fd
=0;
$ff
=0;
$z
=0;
for
(
$p
=1;
$p
<=65536;
$p
++)
{
$f
= ((
$fclk
/2)/
$p
);
$x1
=3;
$x2
=65535;
for
(
$t
=0;
$t
<16;
$t
++)
{
$x3
=
floor
((
$x2
-
$x1
)/2);
$x4
=
$x3
+
floor
((
$x2
-
$x3
)/2);
$x5
=
$x3
-
floor
((
$x3
-
$x1
)/2);
if
((
$x4
+1)%3 == 0)
{
$x4
+= 1;
}
else
if
((
$x4
-1)%3 == 0)
{
$x4
-= 1;
}
if
((
$x5
+1)%3 == 0)
{
$x5
+= 1;
}
else
if
((
$x5
-1)%3 == 0)
{
$x5
-= 1;
}
if
((
$x4
> 0) && (
$x5
> 0))
{
if
(
abs
((
$f
/
$x4
/2)-
$fdes
) <
abs
((
$f
/
$x5
/2)-
$fdes
))
{
$x1
=
$x3
;
}
else
{
$x2
=
$x3
;
}
}
else
{
break
;
}
}
if
((
$x4
> 0) && (
$x5
> 0))
{
if
(
abs
((
$f
/
$x4
/2)-
$fdes
) <
abs
((
$f
/
$x5
/2)-
$fdes
))
{
$x
=
$x4
;
}
else
{
$x
=
$x5
;
}
$ftmp
= (
$f
/
$x
/2);
$fdif
=
abs
(
$fdes
-(
$f
/
$x
/2));
if
(
$z
== 0)
{
$fd
=
$fdif
;
$ff
=
$ftmp
;
$xx
=
$x
;
$pp
=
$p
;
}
if
(
$fdif
<
$fd
)
{
$fd
=
$fdif
;
$ff
=
$ftmp
;
$xx
=
$x
;
$pp
=
$p
;
}
$z
++;
}
}
if
(
$pp
<= 0xFFFF &&
$xx
<= 0xFFFF &&
$pp
> 0 &&
$xx
> 0)
{
$pp
=
strtoupper
(
str_pad
(
dechex
(
$pp
),4,
''0''
,STR_PAD_LEFT));
$output
.=
''Prescaler set at 0x$pp<br>uC Response: PSC=''
;
$output
.= shell_exec(
''./test.sh psc=0x''
.
$pp
.
'' 9''
).
''<br />''
;
usleep(100);
$xx
=
strtoupper
(
str_pad
(
dechex
(
$xx
),4,
''0''
,STR_PAD_LEFT));
$output
.=
''Period set at 0x$xx<br>uC Response: ARR=''
;
$output
.= shell_exec(
''./test.sh arr=0x''
.
$xx
.
'' 9''
).
''<br />''
;
}
else
{
$pp
=
strtoupper
(
str_pad
(
dechex
(
$pp
),4,
''0''
,STR_PAD_LEFT));
$xx
=
strtoupper
(
str_pad
(
dechex
(
$xx
),4,
''0''
,STR_PAD_LEFT));
$output
.=
''Frequency is out of bounds!<br>Error codes: PSC=0x$pp,ARR=0x$xx<br />''
;
}
$output
.=
''Desired Frequency = $fdes<br />Found Frequency = $ff, Prescaler = $pp, Period = $xx<br />''
;
$objResponse
=
new
xajaxResponse();
$objResponse
->assign(
''SomeElementId''
,
''innerHTML''
,
$output
);
return
$objResponse
;
}
#timer #timer #timer-calculate-psc-arr-stm32f4
2012-05-20 05:10 PM
2013-02-11 07:29 AM
2013-02-11 10:35 AM
It is an exercise in factoring. You figure out the divisor for your input vs output clock, and generate two integer factors that multiplied together get you close to the desired divisor. I'd wade into the code, but I'm not that invested. When working with floats, fabs() might be closer to the documented behaviour of the PHP abs() function.
Do you need to do this on the fly? Do you have specific a frequency or range of frequencies you wish to compute? Are you aware that the integer nature of the prescaler and period can preclude the generation of specific or accurate frequencies from the source clock2013-02-11 09:22 PM
Hi Clive
Yes I need it on the fly and the frequency range is from 5 Hz to 3 K Hz. Expecting some solution from you. Thanks in advance Sajeed2013-02-12 07:15 AM
Expecting some solution from you.
That might have lost something in translation, but this isn't my project. You'll need to code or find a factoring routine. @48MHz 3KHz = 48000000 / (1 * 16000) 5Hz = 48000000 / (200 * 48000)2013-02-13 01:49 AM
Hi Clive
Thanks for the reply , this is helpful. Sajeed2014-09-30 02:27 PM
For those looking for a solution, I have started to make progress in a factoring routine (Very Simple) here:
/d6123d2c
All the best Chris