AnsweredAssumed Answered

Function to calc PSC and ARR for a desired frequency, fairly fast!

Question asked by 69.ninja on May 20, 2012
Latest reply on Sep 30, 2014 by ChrisO
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 = 11.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;
}

Outcomes