Remove prediv*2, set loadper=1 and allow 1 divider to extent frequency range
This commit is contained in:
parent
e608ff8936
commit
9e757ea566
3 changed files with 429 additions and 416 deletions
194
src/gpio.cpp
194
src/gpio.cpp
|
@ -15,9 +15,7 @@ This program is free software: you can redistribute it and/or modify
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
extern "C"
|
|
||||||
{
|
|
||||||
#include "mailbox.h"
|
#include "mailbox.h"
|
||||||
}
|
}
|
||||||
#include "gpio.h"
|
#include "gpio.h"
|
||||||
|
@ -31,10 +29,8 @@ gpio::gpio(uint32_t base, uint32_t len)
|
||||||
{
|
{
|
||||||
|
|
||||||
gpioreg = (uint32_t *)mapmem(base, len);
|
gpioreg = (uint32_t *)mapmem(base, len);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
uint32_t gpio::GetPeripheralBase()
|
uint32_t gpio::GetPeripheralBase()
|
||||||
{
|
{
|
||||||
RASPBERRY_PI_INFO_T info;
|
RASPBERRY_PI_INFO_T info;
|
||||||
|
@ -54,7 +50,6 @@ uint32_t gpio::GetPeripheralBase()
|
||||||
return BCM2708_PERI_BASE;
|
return BCM2708_PERI_BASE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//******************** DMA Registers ***************************************
|
//******************** DMA Registers ***************************************
|
||||||
|
|
||||||
dmagpio::dmagpio() : gpio(GetPeripheralBase() + DMA_BASE, DMA_LEN)
|
dmagpio::dmagpio() : gpio(GetPeripheralBase() + DMA_BASE, DMA_LEN)
|
||||||
|
@ -97,19 +92,28 @@ uint64_t clkgpio::GetPllFrequency(int PllNo)
|
||||||
uint64_t Freq = 0;
|
uint64_t Freq = 0;
|
||||||
switch (PllNo)
|
switch (PllNo)
|
||||||
{
|
{
|
||||||
case clk_osc:Freq=XOSC_FREQUENCY;break;
|
case clk_osc:
|
||||||
case clk_plla:Freq=XOSC_FREQUENCY*((uint64_t)gpioreg[PLLA_CTRL]&0x3ff) +XOSC_FREQUENCY*(uint64_t)gpioreg[PLLA_FRAC]/(1<<20);break;
|
Freq = XOSC_FREQUENCY;
|
||||||
|
break;
|
||||||
|
case clk_plla:
|
||||||
|
Freq = XOSC_FREQUENCY * ((uint64_t)gpioreg[PLLA_CTRL] & 0x3ff) + XOSC_FREQUENCY * (uint64_t)gpioreg[PLLA_FRAC] / (1 << 20);
|
||||||
|
break;
|
||||||
//case clk_pllb:Freq=XOSC_FREQUENCY*((uint64_t)gpioreg[PLLB_CTRL]&0x3ff) +XOSC_FREQUENCY*(uint64_t)gpioreg[PLLB_FRAC]/(1<<20);break;
|
//case clk_pllb:Freq=XOSC_FREQUENCY*((uint64_t)gpioreg[PLLB_CTRL]&0x3ff) +XOSC_FREQUENCY*(uint64_t)gpioreg[PLLB_FRAC]/(1<<20);break;
|
||||||
case clk_pllc:Freq=XOSC_FREQUENCY*((uint64_t)gpioreg[PLLC_CTRL]&0x3ff) +XOSC_FREQUENCY*(uint64_t)gpioreg[PLLC_FRAC]/(1<<20);break;
|
case clk_pllc:
|
||||||
case clk_plld:Freq=(XOSC_FREQUENCY*((uint64_t)gpioreg[PLLD_CTRL]&0x3ff) +(XOSC_FREQUENCY*(uint64_t)gpioreg[PLLD_FRAC])/(1<<20))/(gpioreg[PLLD_PER]>>1);break;
|
Freq = XOSC_FREQUENCY * ((uint64_t)gpioreg[PLLC_CTRL] & 0x3ff) + XOSC_FREQUENCY * (uint64_t)gpioreg[PLLC_FRAC] / (1 << 20);
|
||||||
case clk_hdmi:Freq=XOSC_FREQUENCY*((uint64_t)gpioreg[PLLH_CTRL]&0x3ff) +XOSC_FREQUENCY*(uint64_t)gpioreg[PLLH_FRAC]/(1<<20);break;
|
break;
|
||||||
|
case clk_plld:
|
||||||
|
Freq = (XOSC_FREQUENCY * ((uint64_t)gpioreg[PLLD_CTRL] & 0x3ff) + (XOSC_FREQUENCY * (uint64_t)gpioreg[PLLD_FRAC]) / (1 << 20)) / (gpioreg[PLLD_PER] >> 1);
|
||||||
|
break;
|
||||||
|
case clk_hdmi:
|
||||||
|
Freq = XOSC_FREQUENCY * ((uint64_t)gpioreg[PLLH_CTRL] & 0x3ff) + XOSC_FREQUENCY * (uint64_t)gpioreg[PLLH_FRAC] / (1 << 20);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
fprintf(stderr, "Freq = %lld\n", Freq);
|
fprintf(stderr, "Freq = %lld\n", Freq);
|
||||||
|
|
||||||
return Freq;
|
return Freq;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int clkgpio::SetClkDivFrac(uint32_t Div, uint32_t Frac)
|
int clkgpio::SetClkDivFrac(uint32_t Div, uint32_t Frac)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -119,19 +123,17 @@ int clkgpio::SetClkDivFrac(uint32_t Div,uint32_t Frac)
|
||||||
//gpioreg[GPCLK_CNTL]= 0x5A000000 | (Mash << 9) | pllnumber |(1<<4) ; //4 is START CLK
|
//gpioreg[GPCLK_CNTL]= 0x5A000000 | (Mash << 9) | pllnumber |(1<<4) ; //4 is START CLK
|
||||||
// usleep(10);
|
// usleep(10);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int clkgpio::SetMasterMultFrac(uint32_t Mult, uint32_t Frac)
|
int clkgpio::SetMasterMultFrac(uint32_t Mult, uint32_t Frac)
|
||||||
{
|
{
|
||||||
|
|
||||||
//fprintf(stderr,"Master Mult %d Frac %d\n",Mult,Frac);
|
//fprintf(stderr,"Master Mult %d Frac %d\n",Mult,Frac);
|
||||||
gpioreg[PLLA_CTRL] = (0x5a<<24) | (0x21<<12) | Mult;
|
gpioreg[PLLA_CTRL] = (0x5a << 24) | (0x21 << 12) | Mult; //PDIV=1
|
||||||
usleep(100);
|
usleep(100);
|
||||||
gpioreg[PLLA_FRAC] = 0x5A000000 | Frac;
|
gpioreg[PLLA_FRAC] = 0x5A000000 | Frac;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int clkgpio::SetFrequency(double Frequency)
|
int clkgpio::SetFrequency(double Frequency)
|
||||||
|
@ -145,24 +147,22 @@ int clkgpio::SetFrequency(double Frequency)
|
||||||
uint32_t FracMultiply = freqctl & 0xFFFFF;
|
uint32_t FracMultiply = freqctl & 0xFFFFF;
|
||||||
//gpioreg[PLLA_FRAC]= 0x5A000000 | FracMultiply ; // Only Frac is Sent
|
//gpioreg[PLLA_FRAC]= 0x5A000000 | FracMultiply ; // Only Frac is Sent
|
||||||
SetMasterMultFrac(IntMultiply, FracMultiply);
|
SetMasterMultFrac(IntMultiply, FracMultiply);
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
double Freqresult = (double)Pllfrequency / (double)(CentralFrequency + Frequency);
|
double Freqresult = (double)Pllfrequency / (double)(CentralFrequency + Frequency);
|
||||||
uint32_t FreqDivider = (uint32_t)Freqresult;
|
uint32_t FreqDivider = (uint32_t)Freqresult;
|
||||||
uint32_t FreqFractionnal = (uint32_t)(4096 * (Freqresult - (double)FreqDivider));
|
uint32_t FreqFractionnal = (uint32_t)(4096 * (Freqresult - (double)FreqDivider));
|
||||||
if((FreqDivider>4096)||(FreqDivider<2)) fprintf(stderr,"Frequency out of range\n");
|
if ((FreqDivider > 4096) || (FreqDivider < 2))
|
||||||
|
fprintf(stderr, "Frequency out of range\n");
|
||||||
printf("DIV/FRAC %u/%u \n", FreqDivider, FreqFractionnal);
|
printf("DIV/FRAC %u/%u \n", FreqDivider, FreqFractionnal);
|
||||||
|
|
||||||
SetClkDivFrac(FreqDivider, FreqFractionnal);
|
SetClkDivFrac(FreqDivider, FreqFractionnal);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
uint32_t clkgpio::GetMasterFrac(double Frequency)
|
uint32_t clkgpio::GetMasterFrac(double Frequency)
|
||||||
{
|
{
|
||||||
if (ModulateFromMasterPLL)
|
if (ModulateFromMasterPLL)
|
||||||
|
@ -176,7 +176,6 @@ uint32_t clkgpio::GetMasterFrac(double Frequency)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
return 0; //Not in Master CLk mode
|
return 0; //Not in Master CLk mode
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int clkgpio::ComputeBestLO(uint64_t Frequency, int Bandwidth)
|
int clkgpio::ComputeBestLO(uint64_t Frequency, int Bandwidth)
|
||||||
|
@ -188,43 +187,48 @@ int clkgpio::ComputeBestLO(uint64_t Frequency,int Bandwidth)
|
||||||
double xtal_freq_recip = 1.0 / 19.2e6; // todo PPM correction
|
double xtal_freq_recip = 1.0 / 19.2e6; // todo PPM correction
|
||||||
int best_divider = 0;
|
int best_divider = 0;
|
||||||
|
|
||||||
|
|
||||||
int solution_count = 0;
|
int solution_count = 0;
|
||||||
//printf("carrier:%3.2f ",carrier_freq/1e6);
|
//printf("carrier:%3.2f ",carrier_freq/1e6);
|
||||||
int divider, min_int_multiplier, max_int_multiplier, fom, int_multiplier, best_fom = 0;
|
int divider, min_int_multiplier, max_int_multiplier, fom, int_multiplier, best_fom = 0;
|
||||||
double frac_multiplier;
|
double frac_multiplier;
|
||||||
best_divider = 0;
|
best_divider = 0;
|
||||||
for( divider=1;divider<4096;divider++)
|
for (divider = 1; divider < 4096; divider++)//1 is allowed only for MASH=0
|
||||||
{
|
{
|
||||||
if( Frequency*divider < 600e6 ) continue; // widest accepted frequency range
|
if (Frequency * divider < 600e6)
|
||||||
if( Frequency*divider > 1500e6 ) break;
|
continue; // widest accepted frequency range
|
||||||
|
if (Frequency * divider > 1700e6) // By Experiment on Rpi3B
|
||||||
|
break;
|
||||||
|
|
||||||
max_int_multiplier = ((int)((double)(Frequency + Bandwidth) * divider * xtal_freq_recip));
|
max_int_multiplier = ((int)((double)(Frequency + Bandwidth) * divider * xtal_freq_recip));
|
||||||
min_int_multiplier = ((int)((double)(Frequency - Bandwidth) * divider * xtal_freq_recip));
|
min_int_multiplier = ((int)((double)(Frequency - Bandwidth) * divider * xtal_freq_recip));
|
||||||
if( min_int_multiplier!=max_int_multiplier ) continue; // don't cross integer boundary
|
if (min_int_multiplier != max_int_multiplier)
|
||||||
|
continue; // don't cross integer boundary
|
||||||
|
|
||||||
solution_count++; // if we make it here the solution is acceptable,
|
solution_count++; // if we make it here the solution is acceptable,
|
||||||
fom = 0; // but we want a good solution
|
fom = 0; // but we want a good solution
|
||||||
|
|
||||||
if( Frequency*divider > 900e6 ) fom++; // prefer freqs closer to 1000
|
if (Frequency * divider > 900e6)
|
||||||
if( Frequency*divider < 1100e6 ) fom++;
|
fom++; // prefer freqs closer to 1000
|
||||||
if( Frequency*divider > 800e6 ) fom++; // accepted frequency range
|
if (Frequency * divider < 1100e6)
|
||||||
if( Frequency*divider < 1200e6 ) fom++;
|
fom++;
|
||||||
|
if (Frequency * divider > 800e6)
|
||||||
|
fom++; // accepted frequency range
|
||||||
|
if (Frequency * divider < 1200e6)
|
||||||
|
fom++;
|
||||||
|
|
||||||
frac_multiplier = ((double)(Frequency)*divider * xtal_freq_recip);
|
frac_multiplier = ((double)(Frequency)*divider * xtal_freq_recip);
|
||||||
int_multiplier = (int)frac_multiplier;
|
int_multiplier = (int)frac_multiplier;
|
||||||
frac_multiplier = frac_multiplier - int_multiplier;
|
frac_multiplier = frac_multiplier - int_multiplier;
|
||||||
if((int_multiplier%2)==0) fom++;
|
if ((int_multiplier % 2) == 0)
|
||||||
if( (frac_multiplier>0.4) && (frac_multiplier<0.6) ) fom+=2; // prefer mulipliers away from integer boundaries
|
fom++;
|
||||||
|
if ((frac_multiplier > 0.4) && (frac_multiplier < 0.6))
|
||||||
|
fom += 2; // prefer mulipliers away from integer boundaries
|
||||||
|
|
||||||
//if( divider%2 == 1 ) fom+=2; // prefer odd dividers
|
//if( divider%2 == 1 ) fom+=2; // prefer odd dividers
|
||||||
// Even and odd dividers could have different harmonic content,
|
// Even and odd dividers could have different harmonic content,
|
||||||
// but the latest measurements have shown no significant difference.
|
// but the latest measurements have shown no significant difference.
|
||||||
|
|
||||||
|
printf("Try multiplier:%f divider:%d VCO: %4.1fMHz\n",Frequency*divider*xtal_freq_recip,divider,(double)Frequency*divider/1e6);
|
||||||
//printf(" multiplier:%f divider:%d VCO: %4.1fMHz\n",carrier_freq*divider*xtal_freq_recip,divider,(double)carrier_freq*divider/1e6);
|
|
||||||
if (fom > best_fom)
|
if (fom > best_fom)
|
||||||
{
|
{
|
||||||
best_fom = fom;
|
best_fom = fom;
|
||||||
|
@ -308,14 +312,14 @@ void clkgpio::SetPhase(bool inversed)
|
||||||
clkgpio::gpioreg[GPCLK_CNTL] = (0x5A << 24) | StateBefore | ((inversed ? 1 : 0) << 8) | 1 << 5;
|
clkgpio::gpioreg[GPCLK_CNTL] = (0x5A << 24) | StateBefore | ((inversed ? 1 : 0) << 8) | 1 << 5;
|
||||||
clkgpio::gpioreg[GPCLK_CNTL] = (0x5A << 24) | StateBefore | ((inversed ? 1 : 0) << 8) | 0 << 5;
|
clkgpio::gpioreg[GPCLK_CNTL] = (0x5A << 24) | StateBefore | ((inversed ? 1 : 0) << 8) | 0 << 5;
|
||||||
}
|
}
|
||||||
|
//Should inspect https://github.com/raspberrypi/linux/blob/ffd7bf4085b09447e5db96edd74e524f118ca3fe/drivers/clk/bcm/clk-bcm2835.c#L695
|
||||||
void clkgpio::SetAdvancedPllMode(bool Advanced)
|
void clkgpio::SetAdvancedPllMode(bool Advanced)
|
||||||
{
|
{
|
||||||
ModulateFromMasterPLL = Advanced;
|
ModulateFromMasterPLL = Advanced;
|
||||||
if (ModulateFromMasterPLL)
|
if (ModulateFromMasterPLL)
|
||||||
{
|
{
|
||||||
SetPllNumber(clk_plla, 0); // Use PPL_A , Do not USE MASH which generates spurious
|
SetPllNumber(clk_plla, 0); // Use PPL_A , Do not USE MASH which generates spurious
|
||||||
gpioreg[0x104/4]=0x5A00020A; // Enable Plla_PER
|
gpioreg[0x104 / 4] = 0x5A00022A; // Enable Plla_PER
|
||||||
usleep(100);
|
usleep(100);
|
||||||
|
|
||||||
uint32_t ana[4];
|
uint32_t ana[4];
|
||||||
|
@ -324,16 +328,16 @@ void clkgpio::SetAdvancedPllMode(bool Advanced)
|
||||||
ana[i] = gpioreg[(0x1010 / 4) + i];
|
ana[i] = gpioreg[(0x1010 / 4) + i];
|
||||||
}
|
}
|
||||||
|
|
||||||
//ana[1]&=~(1<<14); // No use prediv means Frequency
|
ana[1]&=~(1<<14); // No use prediv means Frequency
|
||||||
ana[1]|=(1<<14); // use prediv means Frequency*2
|
//ana[1] |= (1 << 14); // use prediv means Frequency*2
|
||||||
for (int i = 3; i >= 0; i--)
|
for (int i = 3; i >= 0; i--)
|
||||||
{
|
{
|
||||||
gpioreg[(0x1010 / 4) + i] = (0x5A << 24) | ana[i];
|
gpioreg[(0x1010 / 4) + i] = (0x5A << 24) | ana[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
usleep(100);
|
usleep(100);
|
||||||
gpioreg[PLLA_PER]=0x5A000002; // Div ?
|
gpioreg[PLLA_CORE] = 0x5A000001; // Div ?
|
||||||
|
gpioreg[PLLA_PER] = 0x5A000001; // Div ?
|
||||||
usleep(100);
|
usleep(100);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -396,7 +400,6 @@ void clkgpio::print_clock_tree(void)
|
||||||
printf("UART CTL=%08x DIV=%8x ", gpioreg[60], gpioreg[61]);
|
printf("UART CTL=%08x DIV=%8x ", gpioreg[60], gpioreg[61]);
|
||||||
printf("VEC CTL=%08x DIV=%8x\n", gpioreg[62], gpioreg[63]);
|
printf("VEC CTL=%08x DIV=%8x\n", gpioreg[62], gpioreg[63]);
|
||||||
|
|
||||||
|
|
||||||
printf("PULSE CTL=%08x DIV=%8x ", gpioreg[100], gpioreg[101]);
|
printf("PULSE CTL=%08x DIV=%8x ", gpioreg[100], gpioreg[101]);
|
||||||
printf("PLLT CTL=%08x DIV=????????\n", gpioreg[76]);
|
printf("PLLT CTL=%08x DIV=????????\n", gpioreg[76]);
|
||||||
|
|
||||||
|
@ -413,42 +416,48 @@ void clkgpio::print_clock_tree(void)
|
||||||
printf("EMMC CTL=%08x DIV=%8x\n", gpioreg[112], gpioreg[113]);
|
printf("EMMC CTL=%08x DIV=%8x\n", gpioreg[112], gpioreg[113]);
|
||||||
printf("EMMC CTL=%08x DIV=%8x\n", gpioreg[112], gpioreg[113]);
|
printf("EMMC CTL=%08x DIV=%8x\n", gpioreg[112], gpioreg[113]);
|
||||||
|
|
||||||
|
|
||||||
// Sometimes calculated frequencies are off by a factor of 2
|
// Sometimes calculated frequencies are off by a factor of 2
|
||||||
// ANA1 bit 14 may indicate that a /2 prescaler is active
|
// ANA1 bit 14 may indicate that a /2 prescaler is active
|
||||||
printf("PLLA PDIV=%d NDIV=%d FRAC=%d ",(gpioreg[PLLA_CTRL]>>16) ,gpioreg[PLLA_CTRL]&0x3ff, gpioreg[PLLA_FRAC] );
|
printf("PLLA PDIV=%d NDIV=%d FRAC=%d ", (gpioreg[PLLA_CTRL] >> 12)&0x7, gpioreg[PLLA_CTRL] & 0x3ff, gpioreg[PLLA_FRAC]);
|
||||||
printf(" %f MHz\n", 19.2 * ((float)(gpioreg[PLLA_CTRL] & 0x3ff) + ((float)gpioreg[PLLA_FRAC]) / ((float)(1 << 20))));
|
printf(" %f MHz\n", 19.2 * ((float)(gpioreg[PLLA_CTRL] & 0x3ff) + ((float)gpioreg[PLLA_FRAC]) / ((float)(1 << 20))));
|
||||||
printf("DSI0=%d CORE=%d PER=%d CCP2=%d\n\n", gpioreg[PLLA_DSI0], gpioreg[PLLA_CORE], gpioreg[PLLA_PER], gpioreg[PLLA_CCP2]);
|
printf("DSI0=%d CORE=%d PER=%d CCP2=%d\n\n", gpioreg[PLLA_DSI0], gpioreg[PLLA_CORE], gpioreg[PLLA_PER], gpioreg[PLLA_CCP2]);
|
||||||
|
|
||||||
|
printf("PLLB PDIV=%d NDIV=%d FRAC=%d ", (gpioreg[PLLB_CTRL] >> 12)&0x7, gpioreg[PLLB_CTRL] & 0x3ff, gpioreg[PLLB_FRAC]);
|
||||||
printf("PLLB PDIV=%d NDIV=%d FRAC=%d ",(gpioreg[PLLB_CTRL]>>16) ,gpioreg[PLLB_CTRL]&0x3ff, gpioreg[PLLB_FRAC] );
|
|
||||||
printf(" %f MHz\n", 19.2 * ((float)(gpioreg[PLLB_CTRL] & 0x3ff) + ((float)gpioreg[PLLB_FRAC]) / ((float)(1 << 20))));
|
printf(" %f MHz\n", 19.2 * ((float)(gpioreg[PLLB_CTRL] & 0x3ff) + ((float)gpioreg[PLLB_FRAC]) / ((float)(1 << 20))));
|
||||||
printf("ARM=%d SP0=%d SP1=%d SP2=%d\n\n", gpioreg[PLLB_ARM], gpioreg[PLLB_SP0], gpioreg[PLLB_SP1], gpioreg[PLLB_SP2]);
|
printf("ARM=%d SP0=%d SP1=%d SP2=%d\n\n", gpioreg[PLLB_ARM], gpioreg[PLLB_SP0], gpioreg[PLLB_SP1], gpioreg[PLLB_SP2]);
|
||||||
|
|
||||||
printf("PLLC PDIV=%d NDIV=%d FRAC=%d ",(gpioreg[PLLC_CTRL]>>16) ,gpioreg[PLLC_CTRL]&0x3ff, gpioreg[PLLC_FRAC] );
|
printf("PLLC PDIV=%d NDIV=%d FRAC=%d ", (gpioreg[PLLC_CTRL] >> 12)&0x7, gpioreg[PLLC_CTRL] & 0x3ff, gpioreg[PLLC_FRAC]);
|
||||||
printf(" %f MHz\n", 19.2 * ((float)(gpioreg[PLLC_CTRL] & 0x3ff) + ((float)gpioreg[PLLC_FRAC]) / ((float)(1 << 20))));
|
printf(" %f MHz\n", 19.2 * ((float)(gpioreg[PLLC_CTRL] & 0x3ff) + ((float)gpioreg[PLLC_FRAC]) / ((float)(1 << 20))));
|
||||||
printf("CORE2=%d CORE1=%d PER=%d CORE0=%d\n\n", gpioreg[PLLC_CORE2], gpioreg[PLLC_CORE1], gpioreg[PLLC_PER], gpioreg[PLLC_CORE0]);
|
printf("CORE2=%d CORE1=%d PER=%d CORE0=%d\n\n", gpioreg[PLLC_CORE2], gpioreg[PLLC_CORE1], gpioreg[PLLC_PER], gpioreg[PLLC_CORE0]);
|
||||||
|
|
||||||
printf("PLLD %x PDIV=%d NDIV=%d FRAC=%d ",gpioreg[PLLD_CTRL],(gpioreg[PLLD_CTRL]>>16) ,gpioreg[PLLD_CTRL]&0x3ff, gpioreg[PLLD_FRAC] );
|
printf("PLLD %x PDIV=%d NDIV=%d FRAC=%d ", gpioreg[PLLD_CTRL], (gpioreg[PLLD_CTRL] >> 12)&0x7, gpioreg[PLLD_CTRL] & 0x3ff, gpioreg[PLLD_FRAC]);
|
||||||
printf(" %f MHz\n", 19.2 * ((float)(gpioreg[PLLD_CTRL] & 0x3ff) + ((float)gpioreg[PLLD_FRAC]) / ((float)(1 << 20))));
|
printf(" %f MHz\n", 19.2 * ((float)(gpioreg[PLLD_CTRL] & 0x3ff) + ((float)gpioreg[PLLD_FRAC]) / ((float)(1 << 20))));
|
||||||
printf("DSI0=%d CORE=%d PER=%d DSI1=%d\n\n", gpioreg[PLLD_DSI0], gpioreg[PLLD_CORE], gpioreg[PLLD_PER], gpioreg[PLLD_DSI1]);
|
printf("DSI0=%d CORE=%d PER=%d DSI1=%d\n\n", gpioreg[PLLD_DSI0], gpioreg[PLLD_CORE], gpioreg[PLLD_PER], gpioreg[PLLD_DSI1]);
|
||||||
|
|
||||||
printf("PLLH PDIV=%d NDIV=%d FRAC=%d ",(gpioreg[PLLH_CTRL]>>16) ,gpioreg[PLLH_CTRL]&0x3ff, gpioreg[PLLH_FRAC] );
|
printf("PLLH PDIV=%d NDIV=%d FRAC=%d ", (gpioreg[PLLH_CTRL] >> 12)&0x7, gpioreg[PLLH_CTRL] & 0x3ff, gpioreg[PLLH_FRAC]);
|
||||||
printf(" %f MHz\n", 19.2 * ((float)(gpioreg[PLLH_CTRL] & 0x3ff) + ((float)gpioreg[PLLH_FRAC]) / ((float)(1 << 20))));
|
printf(" %f MHz\n", 19.2 * ((float)(gpioreg[PLLH_CTRL] & 0x3ff) + ((float)gpioreg[PLLH_FRAC]) / ((float)(1 << 20))));
|
||||||
printf("AUX=%d RCAL=%d PIX=%d STS=%d\n\n", gpioreg[PLLH_AUX], gpioreg[PLLH_RCAL], gpioreg[PLLH_PIX], gpioreg[PLLH_STS]);
|
printf("AUX=%d RCAL=%d PIX=%d STS=%d\n\n", gpioreg[PLLH_AUX], gpioreg[PLLH_RCAL], gpioreg[PLLH_PIX], gpioreg[PLLH_STS]);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void clkgpio::enableclk(int gpio)
|
void clkgpio::enableclk(int gpio)
|
||||||
{
|
{
|
||||||
switch (gpio)
|
switch (gpio)
|
||||||
{
|
{
|
||||||
case 4: gengpio.setmode(gpio,fsel_alt0);break;
|
case 4:
|
||||||
case 20:gengpio.setmode(gpio,fsel_alt5);break;
|
gengpio.setmode(gpio, fsel_alt0);
|
||||||
case 32:gengpio.setmode(gpio,fsel_alt0);break;
|
break;
|
||||||
case 34:gengpio.setmode(gpio,fsel_alt0);break;
|
case 20:
|
||||||
default: fprintf(stderr,"gpio %d has no clk - available(4,20,32,34)\n",gpio);break;
|
gengpio.setmode(gpio, fsel_alt5);
|
||||||
|
break;
|
||||||
|
case 32:
|
||||||
|
gengpio.setmode(gpio, fsel_alt0);
|
||||||
|
break;
|
||||||
|
case 34:
|
||||||
|
gengpio.setmode(gpio, fsel_alt0);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fprintf(stderr, "gpio %d has no clk - available(4,20,32,34)\n", gpio);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
usleep(100);
|
usleep(100);
|
||||||
}
|
}
|
||||||
|
@ -456,7 +465,6 @@ void clkgpio::enableclk(int gpio)
|
||||||
void clkgpio::disableclk(int gpio)
|
void clkgpio::disableclk(int gpio)
|
||||||
{
|
{
|
||||||
gengpio.setmode(gpio, fsel_input);
|
gengpio.setmode(gpio, fsel_input);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void clkgpio::Setppm(double ppm)
|
void clkgpio::Setppm(double ppm)
|
||||||
|
@ -478,7 +486,6 @@ void clkgpio::SetppmFromNTP()
|
||||||
if (status != TIME_OK)
|
if (status != TIME_OK)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Warning: NTP calibrate failed\n");
|
fprintf(stderr, "Warning: NTP calibrate failed\n");
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -498,7 +505,6 @@ generalgpio::generalgpio():gpio(GetPeripheralBase()+GENERAL_BASE,GENERAL_LEN)
|
||||||
|
|
||||||
generalgpio::~generalgpio()
|
generalgpio::~generalgpio()
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int generalgpio::setmode(uint32_t gpio, uint32_t mode)
|
int generalgpio::setmode(uint32_t gpio, uint32_t mode)
|
||||||
|
@ -513,7 +519,6 @@ int generalgpio::setmode(uint32_t gpio, uint32_t mode)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// ********************************** PWM GPIO **********************************
|
// ********************************** PWM GPIO **********************************
|
||||||
|
|
||||||
pwmgpio::pwmgpio() : gpio(GetPeripheralBase() + PWM_BASE, PWM_LEN)
|
pwmgpio::pwmgpio() : gpio(GetPeripheralBase() + PWM_BASE, PWM_LEN)
|
||||||
|
@ -535,22 +540,40 @@ void pwmgpio::enablepwm(int gpio,int PwmNumber)
|
||||||
{
|
{
|
||||||
switch (gpio)
|
switch (gpio)
|
||||||
{
|
{
|
||||||
case 12:gengpio.setmode(gpio,fsel_alt0);break;
|
case 12:
|
||||||
case 18:gengpio.setmode(gpio,fsel_alt5);break;
|
gengpio.setmode(gpio, fsel_alt0);
|
||||||
case 40:gengpio.setmode(gpio,fsel_alt0);break;
|
break;
|
||||||
|
case 18:
|
||||||
|
gengpio.setmode(gpio, fsel_alt5);
|
||||||
|
break;
|
||||||
|
case 40:
|
||||||
|
gengpio.setmode(gpio, fsel_alt0);
|
||||||
|
break;
|
||||||
|
|
||||||
default: fprintf(stderr,"gpio %d has no pwm - available(12,18,40)\n",gpio);break;
|
default:
|
||||||
|
fprintf(stderr, "gpio %d has no pwm - available(12,18,40)\n", gpio);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (PwmNumber == 1)
|
if (PwmNumber == 1)
|
||||||
{
|
{
|
||||||
switch (gpio)
|
switch (gpio)
|
||||||
{
|
{
|
||||||
case 13:gengpio.setmode(gpio,fsel_alt0);break;
|
case 13:
|
||||||
case 19:gengpio.setmode(gpio,fsel_alt5);break;
|
gengpio.setmode(gpio, fsel_alt0);
|
||||||
case 41:gengpio.setmode(gpio,fsel_alt0);break;
|
break;
|
||||||
case 45:gengpio.setmode(gpio,fsel_alt0);break;
|
case 19:
|
||||||
default: fprintf(stderr,"gpio %d has no pwm - available(13,19,41,45)\n",gpio);break;
|
gengpio.setmode(gpio, fsel_alt5);
|
||||||
|
break;
|
||||||
|
case 41:
|
||||||
|
gengpio.setmode(gpio, fsel_alt0);
|
||||||
|
break;
|
||||||
|
case 45:
|
||||||
|
gengpio.setmode(gpio, fsel_alt0);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fprintf(stderr, "gpio %d has no pwm - available(13,19,41,45)\n", gpio);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
usleep(100);
|
usleep(100);
|
||||||
|
@ -559,7 +582,6 @@ void pwmgpio::enablepwm(int gpio,int PwmNumber)
|
||||||
void pwmgpio::disablepwm(int gpio)
|
void pwmgpio::disablepwm(int gpio)
|
||||||
{
|
{
|
||||||
gengpio.setmode(gpio, fsel_input);
|
gengpio.setmode(gpio, fsel_input);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int pwmgpio::SetPllNumber(int PllNo, int MashType)
|
int pwmgpio::SetPllNumber(int PllNo, int MashType)
|
||||||
|
@ -581,7 +603,6 @@ int pwmgpio::SetPllNumber(int PllNo,int MashType)
|
||||||
uint64_t pwmgpio::GetPllFrequency(int PllNo)
|
uint64_t pwmgpio::GetPllFrequency(int PllNo)
|
||||||
{
|
{
|
||||||
return clk.GetPllFrequency(PllNo);
|
return clk.GetPllFrequency(PllNo);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int pwmgpio::SetFrequency(uint64_t Frequency)
|
int pwmgpio::SetFrequency(uint64_t Frequency)
|
||||||
|
@ -590,7 +611,8 @@ int pwmgpio::SetFrequency(uint64_t Frequency)
|
||||||
double Freqresult = (double)Pllfrequency / (double)(Frequency * Prediv);
|
double Freqresult = (double)Pllfrequency / (double)(Frequency * Prediv);
|
||||||
uint32_t FreqDivider = (uint32_t)Freqresult;
|
uint32_t FreqDivider = (uint32_t)Freqresult;
|
||||||
uint32_t FreqFractionnal = (uint32_t)(4096 * (Freqresult - (double)FreqDivider));
|
uint32_t FreqFractionnal = (uint32_t)(4096 * (Freqresult - (double)FreqDivider));
|
||||||
if((FreqDivider>4096)||(FreqDivider<2)) fprintf(stderr,"Frequency out of range\n");
|
if ((FreqDivider > 4096) || (FreqDivider < 2))
|
||||||
|
fprintf(stderr, "Frequency out of range\n");
|
||||||
fprintf(stderr, "PWM clk=%d / %d\n", FreqDivider, FreqFractionnal);
|
fprintf(stderr, "PWM clk=%d / %d\n", FreqDivider, FreqFractionnal);
|
||||||
clk.gpioreg[PWMCLK_DIV] = 0x5A000000 | ((FreqDivider) << 12) | FreqFractionnal;
|
clk.gpioreg[PWMCLK_DIV] = 0x5A000000 | ((FreqDivider) << 12) | FreqFractionnal;
|
||||||
|
|
||||||
|
@ -598,10 +620,8 @@ int pwmgpio::SetFrequency(uint64_t Frequency)
|
||||||
clk.gpioreg[PWMCLK_CNTL] = 0x5A000000 | (Mash << 9) | pllnumber | (1 << 4); //4 is STAR CLK
|
clk.gpioreg[PWMCLK_CNTL] = 0x5A000000 | (Mash << 9) | pllnumber | (1 << 4); //4 is STAR CLK
|
||||||
usleep(100);
|
usleep(100);
|
||||||
|
|
||||||
|
|
||||||
SetPrediv(Prediv); //SetMode should be called before
|
SetPrediv(Prediv); //SetMode should be called before
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void pwmgpio::SetMode(int Mode)
|
void pwmgpio::SetMode(int Mode)
|
||||||
|
@ -633,14 +653,19 @@ int pwmgpio::SetPrediv(int predivisor) //Mode should be only for SYNC or a Data
|
||||||
//gpioreg[PWM_CTL] = PWMCTL_USEF1| PWMCTL_MODE1| PWMCTL_PWEN1|PWMCTL_MSEN1;
|
//gpioreg[PWM_CTL] = PWMCTL_USEF1| PWMCTL_MODE1| PWMCTL_PWEN1|PWMCTL_MSEN1;
|
||||||
switch (ModePwm)
|
switch (ModePwm)
|
||||||
{
|
{
|
||||||
case pwm1pin:gpioreg[PWM_CTL] = PWMCTL_USEF1| PWMCTL_MODE1| PWMCTL_PWEN1|PWMCTL_MSEN1;break; // All serial go to 1 pin
|
case pwm1pin:
|
||||||
case pwm2pin:gpioreg[PWM_CTL] = PWMCTL_USEF2|PWMCTL_PWEN2|PWMCTL_MODE2|PWMCTL_USEF1| PWMCTL_MODE1| PWMCTL_PWEN1;break;// Alternate bit to pin 1 and 2
|
gpioreg[PWM_CTL] = PWMCTL_USEF1 | PWMCTL_MODE1 | PWMCTL_PWEN1 | PWMCTL_MSEN1;
|
||||||
case pwm1pinrepeat:gpioreg[PWM_CTL] = PWMCTL_USEF1| PWMCTL_MODE1| PWMCTL_PWEN1|PWMCTL_RPTL1;break; // All serial go to 1 pin, repeat if empty : RF mode with PWM
|
break; // All serial go to 1 pin
|
||||||
|
case pwm2pin:
|
||||||
|
gpioreg[PWM_CTL] = PWMCTL_USEF2 | PWMCTL_PWEN2 | PWMCTL_MODE2 | PWMCTL_USEF1 | PWMCTL_MODE1 | PWMCTL_PWEN1;
|
||||||
|
break; // Alternate bit to pin 1 and 2
|
||||||
|
case pwm1pinrepeat:
|
||||||
|
gpioreg[PWM_CTL] = PWMCTL_USEF1 | PWMCTL_MODE1 | PWMCTL_PWEN1 | PWMCTL_RPTL1;
|
||||||
|
break; // All serial go to 1 pin, repeat if empty : RF mode with PWM
|
||||||
}
|
}
|
||||||
usleep(100);
|
usleep(100);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ********************************** PCM GPIO (I2S) **********************************
|
// ********************************** PCM GPIO (I2S) **********************************
|
||||||
|
@ -652,7 +677,6 @@ pcmgpio::pcmgpio():gpio(GetPeripheralBase()+PCM_BASE,PCM_LEN)
|
||||||
|
|
||||||
pcmgpio::~pcmgpio()
|
pcmgpio::~pcmgpio()
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int pcmgpio::SetPllNumber(int PllNo, int MashType)
|
int pcmgpio::SetPllNumber(int PllNo, int MashType)
|
||||||
|
@ -673,7 +697,6 @@ int pcmgpio::SetPllNumber(int PllNo,int MashType)
|
||||||
uint64_t pcmgpio::GetPllFrequency(int PllNo)
|
uint64_t pcmgpio::GetPllFrequency(int PllNo)
|
||||||
{
|
{
|
||||||
return clk.GetPllFrequency(PllNo);
|
return clk.GetPllFrequency(PllNo);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int pcmgpio::ComputePrediv(uint64_t Frequency)
|
int pcmgpio::ComputePrediv(uint64_t Frequency)
|
||||||
|
@ -698,11 +721,11 @@ int pcmgpio::SetFrequency(uint64_t Frequency)
|
||||||
uint32_t FreqDivider = (uint32_t)Freqresult;
|
uint32_t FreqDivider = (uint32_t)Freqresult;
|
||||||
uint32_t FreqFractionnal = (uint32_t)(4096 * (Freqresult - (double)FreqDivider));
|
uint32_t FreqFractionnal = (uint32_t)(4096 * (Freqresult - (double)FreqDivider));
|
||||||
fprintf(stderr, "PCM clk=%d / %d\n", FreqDivider, FreqFractionnal);
|
fprintf(stderr, "PCM clk=%d / %d\n", FreqDivider, FreqFractionnal);
|
||||||
if((FreqDivider>4096)||(FreqDivider<2)) fprintf(stderr,"PCM Frequency out of range\n");
|
if ((FreqDivider > 4096) || (FreqDivider < 2))
|
||||||
|
fprintf(stderr, "PCM Frequency out of range\n");
|
||||||
clk.gpioreg[PCMCLK_DIV] = 0x5A000000 | ((FreqDivider) << 12) | FreqFractionnal;
|
clk.gpioreg[PCMCLK_DIV] = 0x5A000000 | ((FreqDivider) << 12) | FreqFractionnal;
|
||||||
SetPrediv(Prediv);
|
SetPrediv(Prediv);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int pcmgpio::SetPrediv(int predivisor) //Carefull we use a 10 fixe divisor for now : frequency is thus f/10 as a samplerate
|
int pcmgpio::SetPrediv(int predivisor) //Carefull we use a 10 fixe divisor for now : frequency is thus f/10 as a samplerate
|
||||||
|
@ -728,21 +751,14 @@ int pcmgpio::SetPrediv(int predivisor) //Carefull we use a 10 fixe divisor for n
|
||||||
gpioreg[PCM_CS_A] |= 1 << 2; //START TX PCM
|
gpioreg[PCM_CS_A] |= 1 << 2; //START TX PCM
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// ********************************** PADGPIO (Amplitude) **********************************
|
// ********************************** PADGPIO (Amplitude) **********************************
|
||||||
|
|
||||||
padgpio::padgpio() : gpio(GetPeripheralBase() + PADS_GPIO, PADS_GPIO_LEN)
|
padgpio::padgpio() : gpio(GetPeripheralBase() + PADS_GPIO, PADS_GPIO_LEN)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
padgpio::~padgpio()
|
padgpio::~padgpio()
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -44,9 +44,10 @@ phasedmasync::phasedmasync(uint64_t TuneFrequency,uint32_t SampleRate,int Number
|
||||||
fprintf(stderr,"PWM Mult %d Frac %d Div %d\n",IntMultiply,FracMultiply,clkgpio::PllFixDivider);
|
fprintf(stderr,"PWM Mult %d Frac %d Div %d\n",IntMultiply,FracMultiply,clkgpio::PllFixDivider);
|
||||||
|
|
||||||
|
|
||||||
pwmgpio::clk.gpioreg[PWMCLK_DIV] = 0x5A000000 | ((clkgpio::PllFixDivider)<<12); // PWM clock input divider
|
pwmgpio::clk.gpioreg[PWMCLK_DIV] = 0x5A000000 | ((clkgpio::PllFixDivider)<<12) |pwmgpio::pllnumber; // PWM clock input divider
|
||||||
usleep(100);
|
usleep(100);
|
||||||
pwmgpio::clk.gpioreg[PWMCLK_CNTL]= 0x5A000000 | (pwmgpio::Mash << 9) | pwmgpio::pllnumber|(1 << 4) ; //4 is START CLK
|
|
||||||
|
pwmgpio::clk.gpioreg[PWMCLK_CNTL]= 0x5A000000 | (pwmgpio::Mash << 9) | ((clkgpio::PllFixDivider)<<12)| pwmgpio::pllnumber|(1 << 4) ; //4 is START CLK
|
||||||
usleep(100);
|
usleep(100);
|
||||||
pwmgpio::SetPrediv(32); //SetMode should be called before
|
pwmgpio::SetPrediv(32); //SetMode should be called before
|
||||||
|
|
||||||
|
|
|
@ -49,10 +49,6 @@ serialdmasync::serialdmasync(uint32_t SampleRate,int Channel,uint32_t FifoSize,b
|
||||||
SetDmaAlgo();
|
SetDmaAlgo();
|
||||||
|
|
||||||
|
|
||||||
// Note : Spurious are at +/-(19.2MHZ/2^20)*Div*N : (N=1,2,3...) So we need to have a big div to spurious away BUT
|
|
||||||
// Spurious are ALSO at +/-(19.2MHZ/2^20)*(2^20-Div)*N
|
|
||||||
// Max spurious avoid is to be in the center ! Theory shoud be that spurious are set away at 19.2/2= 9.6Mhz ! But need to get account of div of PLLClock
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
serialdmasync::~serialdmasync()
|
serialdmasync::~serialdmasync()
|
||||||
|
|
Loading…
Reference in a new issue