Remove prediv*2, set loadper=1 and allow 1 divider to extent frequency range

This commit is contained in:
F5OEO 2018-04-30 11:57:03 +00:00
parent e608ff8936
commit 9e757ea566
3 changed files with 429 additions and 416 deletions

View file

@ -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()
{ {
} }

View file

@ -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

View file

@ -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()