## Thursday, May 8, 2014

### Finding Si570 divisors

Here is my function for determining an appropriate set of divisors (HSDiv and N1) given the desired output frequency that keeps the Si570 DCO within it's 4.85 GHz to 5.67 GHz operating range.

#define eSuccess 0
#define eFail 1
#define fDCOMinkHz 4850000 // Minimum DCO frequency in kHz
#define fDCOMaxkHz 5670000 // Maximum DCO frequency in kHz

int findDivisors(uint32_t fout, uint16_t &hsdiv, uint16_t &n1)
{
const uint16_t HS_DIV[] = {11, 9, 7, 6, 5, 4};
int32_t fout_kHz = fout / 1000;

// Floor of the division
uint16_t maxDivider = fDCOMaxkHz / fout_kHz;

// Ceiling of the division
n1 = 1 + ((fDCOMinkHz - 1) / fout_kHz / 11);

if (n1 < 1 || n1 > 128)
return eFail;

while (n1 <= 128)
{
if (0 == n1 % 2 || 1 == n1)
{
// Try each divisor from largest to smallest order
// to minimize power
for (int i = 0; i < 6 ; ++i)
{
hsdiv = HS_DIV[i];
if (hsdiv * n1 <= maxDivider)
return eSuccess;
}
}
n1++;
}
return eFail;
}

Plugging in my reset frequency of 56320000 we correctly calculate HSDiv of 11 and N1 of 8.  Spot checking other fOut values with the results from SiLabs tools so far checks out.  I will create a comprehensive test for this later, but pressing on...

So, considering the following test code:

uint32_t fOut = 56320000;  // My Si570 reset frequency
uint32_t fxtal = 114252366;
uint16_t HSDiv;
uint16_t N1;
uint64_t RFREQ;

if (findDivisors(fOut, HSDiv, N1) == eSuccess)
{
uint64_t tmp = (uint64_t) fOut * HSDiv * N1;
tmp = (tmp << 28) / (uint64_t) fxtal;
RFREQ = tmp + ((tmp & 1<<(28-1))<<1); // Round result
}

So, with the input parameters specified, the RFREQ value I calculate is 0x2B6109F04 as compared to the reset value of 0x2B6109F08 which is within 0.00000001490116119384765625 of the reset value.  This amounts to an output frequency of 56.31999998 instead of 56.32 which is within 0.02 Hz.  I don't think I will worry about it.

As always, comments welcome.  Straighten me out if I am not thinking clearly about this.