librpitx with PWM added

v2beta
F5OEO 2018-03-13 11:22:42 +00:00
rodzic 3a571e0e54
commit 40f2f7e3dd
11 zmienionych plików z 625 dodań i 96 usunięć

Wyświetl plik

@ -1,5 +1,5 @@
#all: ../rpitx ../pissb ../pisstv ../pifsq ../pifm ../piam ../pidcf77 ../piopera
all: v2rpitx ../rpitx ../pissb ../pisstv ../pifsq ../pifm ../piam ../pidcf77 ../piopera
all: librpitx v2rpitx ../rpitx ../pissb ../pisstv ../pifsq ../pifm ../piam ../pidcf77 ../piopera
#CFLAGS = -Wall -g -O2 -D DIGITHIN
CFLAGS = -Wall -g -O2 -Wno-unused-variable
@ -15,10 +15,15 @@ LDFLAGS = -lm -lrt -lpthread -lliquid
CCP = g++
CC = gcc
v2rpitx: librpitx.h gpio.h gpio.cpp dma.h dma.cpp mailbox.c raspberry_pi_revision.c v2rpitx.cpp fmdmasync.h fmdmasync.cpp ngfmdmasync.h ngfmdmasync.cpp dsp.h dsp.cpp iqdmasync.h iqdmasync.cpp
librpitx: librpitx.h gpio.h gpio.cpp dma.h dma.cpp mailbox.c raspberry_pi_revision.c fmdmasync.h fmdmasync.cpp ngfmdmasync.h ngfmdmasync.cpp dsp.h dsp.cpp iqdmasync.h iqdmasync.cpp serialdmasync.h serialdmasync.cpp phasedmasync.h phasedmasync.cpp
$(CC) $(CFLAGS) -c -o mailbox.o mailbox.c
$(CC) $(CFLAGS) -c -o raspberry_pi_revision.o raspberry_pi_revision.c
$(CCP) $(CFLAGS) -o v2rpitx dsp.cpp iqdmasync.cpp ngfmdmasync.cpp fmdmasync.cpp dma.cpp gpio.cpp mailbox.o raspberry_pi_revision.o v2rpitx.cpp $(LDFLAGS)
$(CCP) $(CFLAGS) -c dsp.cpp iqdmasync.cpp ngfmdmasync.cpp fmdmasync.cpp dma.cpp gpio.cpp mailbox.o raspberry_pi_revision.o v2rpitx.cpp serialdmasync.cpp phasedmasync.cpp
$(AR) rc librpitx.a dsp.o iqdmasync.o ngfmdmasync.o fmdmasync.o dma.o gpio.o mailbox.o raspberry_pi_revision.o serialdmasync.o phasedmasync.o
v2rpitx: librpitx.h librpitx.a
$(CCP) $(CFLAGS) -o v2rpitx v2rpitx.cpp librpitx.a $(LDFLAGS)
@ -30,8 +35,8 @@ LDFLAGS_Pissb = -lm -lrt -lpthread -lsndfile
CFLAGS_Pisstv = -Wall -g -O2 -Wno-unused-variable
LDFLAGS_Pisstv = -lm -lrt -lpthread
../pisstv : ../sstv/pisstv.c
$(CC) $(CFLAGS_Pisstv) -o ../pisstv ../sstv/pisstv.c $(LDFLAGS_Pisstv)
../pisstv : ../sstv/v2pisstv.cpp
$(CCP) $(CFLAGS_Pisstv) -o ../pisstv ../sstv/v2pisstv.cpp ../src/librpitx.a $(LDFLAGS_Pisstv)
CFLAGS_Pifsq = -Wall -g -O2 -Wno-unused-variable
LDFLAGS_Pifsq = -lm -lrt -lpthread

Wyświetl plik

@ -14,17 +14,6 @@ gpio::gpio(uint32_t base, uint32_t len)
}
int gpio::setmode(uint32_t gpio, uint32_t mode)
{
int reg, shift;
reg = gpio/10;
shift = (gpio%10) * 3;
gpioreg[reg] = (gpioreg[reg] & ~(7<<shift)) | (mode<<shift);
return 0;
}
uint32_t gpio::GetPeripheralBase()
{
@ -55,11 +44,14 @@ dmagpio::dmagpio():gpio(GetPeripheralBase()+DMA_BASE,DMA_LEN)
// ***************** CLK Registers *****************************************
clkgpio::clkgpio():gpio(GetPeripheralBase()+CLK_BASE,CLK_LEN)
{
}
clkgpio::~clkgpio()
{
gpioreg[GPCLK_CNTL]= 0x5A000000 | (Mash << 9) | pllnumber|(0 << 4) ; //4 is START CLK
usleep(100);
}
int clkgpio::SetPllNumber(int PllNo,int MashType)
@ -74,7 +66,7 @@ int clkgpio::SetPllNumber(int PllNo,int MashType)
Mash=MashType;
else
Mash=0;
gpioreg[GPCLK_CNTL]= 0x5A000000 | (Mash << 9) | pllnumber|(1 << 4) ; //4 is START CLK
gpioreg[GPCLK_CNTL]= 0x5A000000 | (Mash << 9) | pllnumber/*|(1 << 5)*/ ; //5 is Reset CLK
usleep(100);
Pllfrequency=GetPllFrequency(pllnumber);
return 0;
@ -102,7 +94,8 @@ int clkgpio::SetClkDivFrac(uint32_t Div,uint32_t Frac)
{
gpioreg[GPCLK_DIV] = 0x5A000000 | ((Div)<<12) | Frac;
usleep(10);
usleep(100);
fprintf(stderr,"Clk Number %d div %d frac %d\n",pllnumber,Div,Frac);
//gpioreg[GPCLK_CNTL]= 0x5A000000 | (Mash << 9) | pllnumber |(1<<4) ; //4 is START CLK
// usleep(10);
return 0;
@ -112,8 +105,9 @@ int clkgpio::SetClkDivFrac(uint32_t Div,uint32_t Frac)
int clkgpio::SetMasterMultFrac(uint32_t Mult,uint32_t Frac)
{
fprintf(stderr,"Master Mult %d Frac %d\n",Mult,Frac);
gpioreg[PLLA_CTRL] = (0x5a<<24) | (0x21<<12) | Mult;
usleep(100);
gpioreg[PLLA_FRAC]= 0x5A000000 | Frac ;
return 0;
@ -129,7 +123,9 @@ int clkgpio::SetFrequency(int Frequency)
int IntMultiply= freqctl>>20; // Need to be calculated to have a center frequency
freqctl&=0xFFFFF; // Fractionnal is 20bits
uint32_t FracMultiply=freqctl&0xFFFFF;
//gpioreg[PLLA_FRAC]= 0x5A000000 | FracMultiply ; // Only Frac is Sent
SetMasterMultFrac(IntMultiply,FracMultiply);
}
else
{
@ -137,7 +133,7 @@ int clkgpio::SetFrequency(int Frequency)
uint32_t FreqDivider=(uint32_t)Freqresult;
uint32_t FreqFractionnal=(uint32_t) (4096*(Freqresult-(double)FreqDivider));
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);
}
@ -162,28 +158,97 @@ uint32_t clkgpio::GetMasterFrac(int Frequency)
}
int clkgpio::ComputeBestLO(uint64_t Frequency)
int clkgpio::ComputeBestLO(uint64_t Frequency,int Bandwidth)
{
for(int i=1;i<4096;i++)
{
}
return 0;
// Algorithm adapted from https://github.com/SaucySoliton/PiFmRds/blob/master/src/pi_fm_rds.c
// Choose an integer divider for GPCLK0
//
// There may be improvements possible to this algorithm.
double xtal_freq_recip=1.0/19.2e6; // todo PPM correction
int best_divider=0;
int solution_count=0;
//printf("carrier:%3.2f ",carrier_freq/1e6);
int divider,min_int_multiplier,max_int_multiplier, fom, int_multiplier, best_fom=0;
double frac_multiplier;
best_divider=0;
for( divider=1;divider<4096;divider++)
{
if( Frequency*divider < 600e6 ) continue; // widest accepted frequency range
if( Frequency*divider > 1500e6 ) break;
max_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
solution_count++; // if we make it here the solution is acceptable,
fom=0; // but we want a good solution
if( Frequency*divider > 900e6 ) fom++; // prefer freqs closer to 1000
if( Frequency*divider < 1100e6 ) fom++;
if( Frequency*divider > 800e6 ) fom++; // accepted frequency range
if( Frequency*divider < 1200e6 ) fom++;
frac_multiplier=((double)(Frequency)*divider*xtal_freq_recip);
int_multiplier = (int) frac_multiplier;
frac_multiplier = frac_multiplier - int_multiplier;
if( (frac_multiplier>0.2) && (frac_multiplier<0.8) ) fom+=2; // prefer mulipliers away from integer boundaries
//if( divider%2 == 1 ) fom+=2; // prefer odd dividers
// Even and odd dividers could have different harmonic content,
// but the latest measurements have shown no significant difference.
//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 )
{
best_fom=fom;
best_divider=divider;
}
}
if(solution_count>0)
{
PllFixDivider=best_divider;
fprintf(stderr," multiplier:%f divider:%d VCO: %4.1fMHz\n",Frequency*best_divider*xtal_freq_recip,best_divider,(double)Frequency*best_divider/1e6);
return 0;
}
else
{
fprintf(stderr,"Central frequency not available !!!!!!\n");
return -1;
}
}
int clkgpio::SetCenterFrequency(uint64_t Frequency)
int clkgpio::SetCenterFrequency(uint64_t Frequency,int Bandwidth)
{
CentralFrequency=Frequency;
if(ModulateFromMasterPLL)
{
//Choose best PLLDiv and Div
ComputeBestLO(Frequency);
ComputeBestLO(Frequency,Bandwidth); //FixeDivider update
SetFrequency(0);
usleep(1000);
if((gpioreg[CM_LOCK]&CM_LOCK_FLOCKA)>0)
fprintf(stderr,"Master PLLA Locked\n");
else
fprintf(stderr,"Warning ! Master PLLA NOT Locked !!!!\n");
SetClkDivFrac(PllFixDivider,0); // NO MASH !!!!
SetFrequency(Frequency);
usleep(100);
usleep(100);
gpioreg[GPCLK_CNTL]= 0x5A000000 | (Mash << 9) | pllnumber|(1 << 4) ; //4 is START CLK
usleep(100);
gpioreg[GPCLK_CNTL]= 0x5A000000 | (Mash << 9) | pllnumber|(1 << 4) ; //4 is START CLK
usleep(100);
}
else
{
GetPllFrequency(pllnumber);// Be sure to get the master PLL frequency
gpioreg[GPCLK_CNTL]= 0x5A000000 | (Mash << 9) | pllnumber|(1 << 4) ; //4 is START CLK
}
return 0;
}
@ -305,6 +370,24 @@ void clkgpio::print_clock_tree(void)
}
void clkgpio::enableclk(int gpio)
{
switch(gpio)
{
case 4: gengpio.setmode(gpio,fsel_alt0);break;
case 20: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);
}
void clkgpio::disableclk(int gpio)
{
gengpio.setmode(gpio,fsel_input);
}
// ************************************** GENERAL GPIO *****************************************************
@ -314,23 +397,27 @@ generalgpio::generalgpio():gpio(GetPeripheralBase()+GENERAL_BASE,GENERAL_LEN)
generalgpio::~generalgpio()
{
disableclk();
}
void generalgpio::enableclk()
int generalgpio::setmode(uint32_t gpio, uint32_t mode)
{
gpioreg[GPFSEL0] = (gpioreg[GPFSEL0] & ~(7 << 12)) | (4 << 12);
int reg, shift;
reg = gpio/10;
shift = (gpio%10) * 3;
gpioreg[reg] = (gpioreg[reg] & ~(7<<shift)) | (mode<<shift);
return 0;
}
void generalgpio::disableclk()
{
gpioreg[GPFSEL0] = (gpioreg[GPFSEL0] & ~(7 << 12)) | (0 << 12);
}
// ********************************** PWM GPIO **********************************
pwmgpio::pwmgpio():gpio(GetPeripheralBase()+PWM_BASE,PWM_LEN)
{
gpioreg[PWM_CTL] = 0;
}
@ -341,6 +428,39 @@ pwmgpio::~pwmgpio()
gpioreg[PWM_DMAC] = 0;
}
void pwmgpio::enablepwm(int gpio,int PwmNumber)
{
if(PwmNumber==0)
{
switch(gpio)
{
case 12:gengpio.setmode(gpio,fsel_alt0);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;
}
}
if(PwmNumber==1)
{
switch(gpio)
{
case 13:gengpio.setmode(gpio,fsel_alt0);break;
case 19: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);
}
void pwmgpio::disablepwm(int gpio)
{
gengpio.setmode(gpio,fsel_input);
}
int pwmgpio::SetPllNumber(int PllNo,int MashType)
{
if(PllNo<8)
@ -378,11 +498,17 @@ int pwmgpio::SetFrequency(uint64_t Frequency)
usleep(100);
SetPrediv(Prediv);
SetPrediv(Prediv); //SetMode should be called before
return 0;
}
void pwmgpio::SetMode(int Mode)
{
if((Mode>=pwm1pin)&&(Mode<=pwm1pinrepeat))
ModePwm=Mode;
}
int pwmgpio::SetPrediv(int predivisor) //Mode should be only for SYNC or a Data serializer : Todo
{
Prediv=predivisor;
@ -402,8 +528,14 @@ int pwmgpio::SetPrediv(int predivisor) //Mode should be only for SYNC or a Data
usleep(100);
gpioreg[PWM_CTL] = PWMCTL_CLRF;
usleep(100);
//gpioreg[PWM_CTL] = PWMCTL_USEF1 | PWMCTL_PWEN1;
gpioreg[PWM_CTL] = PWMCTL_USEF1| PWMCTL_MODE1| PWMCTL_PWEN1|PWMCTL_MSEN1;
//gpioreg[PWM_CTL] = PWMCTL_USEF1| PWMCTL_MODE1| PWMCTL_PWEN1|PWMCTL_MSEN1;
switch(ModePwm)
{
case pwm1pin:gpioreg[PWM_CTL] = PWMCTL_USEF1| PWMCTL_MODE1| PWMCTL_PWEN1|PWMCTL_MSEN1;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);
return 0;
@ -443,9 +575,24 @@ uint64_t pcmgpio::GetPllFrequency(int PllNo)
}
int pcmgpio::ComputePrediv(uint64_t Frequency)
{
int prediv=5;
for(prediv=10;prediv<1000;prediv++)
{
double Freqresult=(double)Pllfrequency/(double)(Frequency*prediv);
if((Freqresult<4096.0)&&(Freqresult>2.0))
{
fprintf(stderr,"PCM prediv = %d\n",prediv);
break;
}
}
return prediv;
}
int pcmgpio::SetFrequency(uint64_t Frequency)
{
Prediv=10;
Prediv=ComputePrediv(Frequency);
double Freqresult=(double)Pllfrequency/(double)(Frequency*Prediv);
uint32_t FreqDivider=(uint32_t)Freqresult;
uint32_t FreqFractionnal=(uint32_t) (4096*(Freqresult-(double)FreqDivider));

Wyświetl plik

@ -2,13 +2,16 @@
#define DEF_GPIO
#include "stdint.h"
class gpio
{
public:
volatile uint32_t *gpioreg;
gpio(uint32_t base, uint32_t len);
int setmode(uint32_t gpio, uint32_t mode);
uint32_t GetPeripheralBase();
};
@ -52,6 +55,28 @@ class dmagpio:public gpio
};
//************************************ GENERAL GPIO ***************************************
#define GENERAL_BASE (0x00200000)
#define GENERAL_LEN 0xB4
#define GPFSEL0 (0x00/4)
#define GPFSEL1 (0x04/4)
#define GPFSEL2 (0x08/4)
#define GPPUD (0x94/4)
#define GPPUDCLK0 (0x9C/4)
enum {fsel_input,fsel_output,fsel_alt5,fsel_alt4,fsel_alt0,fsel_alt1,fsel_alt2,fsel_alt3};
class generalgpio:public gpio
{
public:
generalgpio();
int setmode(uint32_t gpio, uint32_t mode);
~generalgpio();
};
// Add for PLL frequency CTRL wihout divider
// https://github.com/raspberrypi/linux/blob/rpi-4.9.y/drivers/clk/bcm/clk-bcm2835.c
@ -67,6 +92,12 @@ class dmagpio:public gpio
#define EMMCCLK_CNTL (0x1C0/4)
#define EMMCCLK_DIV (0x1C4/4)
#define CM_LOCK (0x114/4)
# define CM_LOCK_FLOCKH (1<<12)
# define CM_LOCK_FLOCKD (1<<11)
# define CM_LOCK_FLOCKC (1<<10)
# define CM_LOCK_FLOCKB (1<<9)
# define CM_LOCK_FLOCKA (1<<8)
#define PLLA_CTRL (0x1100/4)
#define PLLA_FRAC (0x1200/4)
@ -115,10 +146,11 @@ class clkgpio:public gpio
int Mash;
uint64_t Pllfrequency;
bool ModulateFromMasterPLL=false;
uint64_t CentralFrequency=0;
int PllFixDivider=1; //Fix divider from the master clock in advanced mode
uint64_t CentralFrequency=0;
generalgpio gengpio;
public:
int PllFixDivider=8; //Fix divider from the master clock in advanced mode
clkgpio();
~clkgpio();
int SetPllNumber(int PllNo,int MashType);
@ -128,34 +160,17 @@ class clkgpio:public gpio
int SetClkDivFrac(uint32_t Div,uint32_t Frac);
void SetPhase(bool inversed);
void SetAdvancedPllMode(bool Advanced);
int SetCenterFrequency(uint64_t Frequency);
int ComputeBestLO(uint64_t Frequency);
int SetCenterFrequency(uint64_t Frequency,int Bandwidth);
int ComputeBestLO(uint64_t Frequency,int Bandwidth);
int SetMasterMultFrac(uint32_t Mult,uint32_t Frac);
uint32_t GetMasterFrac(int Frequency);
void enableclk(int gpio);
void disableclk(int gpio);
};
//************************************ GENERAL GPIO ***************************************
#define GENERAL_BASE (0x00200000)
#define GENERAL_LEN 0xB4
#define GPFSEL0 (0x00/4)
#define GPFSEL1 (0x04/4)
#define GPFSEL2 (0x08/4)
#define GPPUD (0x94/4)
#define GPPUDCLK0 (0x9C/4)
class generalgpio:public gpio
{
public:
generalgpio();
~generalgpio();
void enableclk();
void disableclk();
};
//************************************ PWM GPIO ***************************************
@ -187,6 +202,7 @@ class generalgpio:public gpio
#define PWMCTL_PWEN1 (1<<0)
#define PWMDMAC_ENAB (1<<31)
#define PWMDMAC_THRSHLD ((15<<8)|(15<<0))
enum pwmmode{pwm1pin,pwm2pin,pwm1pinrepeat};
class pwmgpio:public gpio
{
@ -196,6 +212,9 @@ class pwmgpio:public gpio
int Mash;
int Prediv; //Range of PWM
uint64_t Pllfrequency;
bool ModulateFromMasterPLL=false;
int ModePwm=pwm1pin;
generalgpio gengpio;
public:
pwmgpio();
~pwmgpio();
@ -203,6 +222,9 @@ class pwmgpio:public gpio
uint64_t GetPllFrequency(int PllNo);
int SetFrequency(uint64_t Frequency);
int SetPrediv(int predivisor);
void SetMode(int Mode);
void enablepwm(int gpio,int PwmNumber);
void disablepwm(int gpio);
};
//******************************* PCM GPIO (I2S) ***********************************
@ -229,6 +251,7 @@ class pcmgpio:public gpio
int pllnumber;
int Mash;
int Prediv; //Range of PCM
uint64_t Pllfrequency;
int SetPrediv(int predivisor);
@ -238,6 +261,7 @@ class pcmgpio:public gpio
int SetPllNumber(int PllNo,int MashType);
uint64_t GetPllFrequency(int PllNo);
int SetFrequency(uint64_t Frequency);
int ComputePrediv(uint64_t Frequency);
};

Wyświetl plik

@ -14,8 +14,9 @@ iqdmasync::iqdmasync(uint64_t TuneFrequency,uint32_t SampleRate,int Channel,uint
tunefreq=TuneFrequency;
clkgpio::SetAdvancedPllMode(true);
clkgpio::SetCenterFrequency(TuneFrequency); // Write Mult Int and Frac : FixMe carrier is already there
clkgpio::SetCenterFrequency(TuneFrequency,SampleRate); // Write Mult Int and Frac : FixMe carrier is already there
clkgpio::SetFrequency(0);
clkgpio::enableclk(4);
syncwithpwm=false;
if(syncwithpwm)
@ -45,6 +46,9 @@ iqdmasync::iqdmasync(uint64_t TuneFrequency,uint32_t SampleRate,int Channel,uint
iqdmasync::~iqdmasync()
{
padgpio pad;
pad.gpioreg[PADS_GPIO_0]=Originfsel;
clkgpio::disableclk(4);
}
void iqdmasync::SetPhase(bool inversed)

Wyświetl plik

@ -3,4 +3,7 @@
#include "fmdmasync.h"
#include "ngfmdmasync.h"
#include "iqdmasync.h"
#include "bpsk.h"
#include "serialdmasync.h"
#include "phasedmasync.h"
#include "dsp.h"

Wyświetl plik

@ -11,8 +11,9 @@ ngfmdmasync::ngfmdmasync(uint64_t TuneFrequency,uint32_t SampleRate,int Channel,
tunefreq=TuneFrequency;
clkgpio::SetAdvancedPllMode(true);
clkgpio::SetCenterFrequency(TuneFrequency); // Write Mult Int and Frac : FixMe carrier is already there
clkgpio::SetCenterFrequency(TuneFrequency,SampleRate); // Write Mult Int and Frac : FixMe carrier is already there
clkgpio::SetFrequency(0);
clkgpio::enableclk(4); // GPIO 4 CLK by default
syncwithpwm=false;
if(syncwithpwm)
@ -39,6 +40,7 @@ ngfmdmasync::ngfmdmasync(uint64_t TuneFrequency,uint32_t SampleRate,int Channel,
ngfmdmasync::~ngfmdmasync()
{
clkgpio::disableclk(4);
}
void ngfmdmasync::SetPhase(bool inversed)

Wyświetl plik

@ -0,0 +1,117 @@
#include "stdio.h"
#include "phasedmasync.h"
#include <unistd.h>
phasedmasync::phasedmasync(uint64_t TuneFrequency,uint32_t SampleRate,int NumberOfPhase,int Channel,uint32_t FifoSize):bufferdma(Channel,FifoSize,2,1) // Number of phase between 2 and 16
{
SetMode(pwm1pinrepeat);
pwmgpio::SetPllNumber(clk_plla,0);
tunefreq=TuneFrequency*NumberOfPhase;
if((NumberOfPhase==2)||(NumberOfPhase==4)||(NumberOfPhase==8)||(NumberOfPhase==16)||(NumberOfPhase==32))
NumbPhase=NumberOfPhase;
else
fprintf(stderr,"PWM critical error: %d is not a legal number of phase\n",NumberOfPhase);
clkgpio::SetAdvancedPllMode(true);
clkgpio::ComputeBestLO(tunefreq,0); // compute PWM divider according to MasterPLL clkgpio::PllFixDivider
double FloatMult=((double)(tunefreq)*clkgpio::PllFixDivider)/(double)(XOSC_FREQUENCY);
uint32_t freqctl = FloatMult*((double)(1<<20)) ;
int IntMultiply= freqctl>>20; // Need to be calculated to have a center frequency
freqctl&=0xFFFFF; // Fractionnal is 20bits
uint32_t FracMultiply=freqctl&0xFFFFF;
clkgpio::SetMasterMultFrac(IntMultiply,FracMultiply);
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
usleep(100);
pwmgpio::clk.gpioreg[PWMCLK_CNTL]= 0x5A000000 | (pwmgpio::Mash << 9) | pwmgpio::pllnumber|(1 << 4) ; //4 is START CLK
usleep(100);
pwmgpio::SetPrediv(32); //SetMode should be called before
enablepwm(12,0); // By default PWM on GPIO 12/pin 32
pcmgpio::SetPllNumber(clk_plld,1);// Clk for Samplerate by PCM
pcmgpio::SetFrequency(SampleRate);
SetDmaAlgo();
uint32_t ZeroPhase=0;
switch(NumbPhase)
{
case 2:ZeroPhase=0xAAAAAAAA;break;//1,0,1,0 1,0,1,0
case 4:ZeroPhase=0xCCCCCCCC;break;//1,1,0,0 //4
case 8:ZeroPhase=0xF0F0F0F0;break;//1,1,1,1,0,0,0,0 //8
case 16:ZeroPhase=0xFF00FF00;break;//1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0 //16
case 32:ZeroPhase=0xFFFF0000;break;//1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //32
default:fprintf(stderr,"Zero phase not initialized\n");break;
}
for(int i=0;i<NumbPhase;i++)
{
TabPhase[i]=ZeroPhase;
fprintf(stderr,"Phase[%d]=%x\n",i,TabPhase[i]);
ZeroPhase=(ZeroPhase<<1)|(ZeroPhase>>31);
}
}
phasedmasync::~phasedmasync()
{
disablepwm(12);
}
void phasedmasync::SetDmaAlgo()
{
dma_cb_t *cbp = cbarray;
for (uint32_t samplecnt = 0; samplecnt < buffersize; samplecnt++)
{
cbp->info = BCM2708_DMA_NO_WIDE_BURSTS | BCM2708_DMA_WAIT_RESP ;
cbp->src = mem_virt_to_phys(&usermem[samplecnt*registerbysample]);
cbp->dst = 0x7E000000 + (PWM_FIFO<<2) + PWM_BASE ;
cbp->length = 4;
cbp->stride = 0;
cbp->next = mem_virt_to_phys(cbp + 1);
//fprintf(stderr,"cbp : sample %x src %x dest %x next %x\n",samplecnt,cbp->src,cbp->dst,cbp->next);
cbp++;
cbp->info = BCM2708_DMA_NO_WIDE_BURSTS | BCM2708_DMA_WAIT_RESP |BCM2708_DMA_D_DREQ | BCM2708_DMA_PER_MAP(DREQ_PCM_TX);
cbp->src = mem_virt_to_phys(cbarray); // Data is not important as we use it only to feed the PWM
cbp->dst = 0x7E000000 + (PCM_FIFO_A<<2) + PCM_BASE ;
cbp->length = 4;
cbp->stride = 0;
cbp->next = mem_virt_to_phys(cbp + 1);
//fprintf(stderr,"cbp : sample %x src %x dest %x next %x\n",samplecnt,cbp->src,cbp->dst,cbp->next);
cbp++;
}
cbp--;
cbp->next = mem_virt_to_phys(cbarray); // We loop to the first CB
//fprintf(stderr,"Last cbp : src %x dest %x next %x\n",cbp->src,cbp->dst,cbp->next);
}
void phasedmasync::SetPhase(uint32_t Index,int Phase)
{
Index=Index%buffersize;
Phase=Phase%NumbPhase;
sampletab[Index]=TabPhase[Phase];
PushSample(Index);
}

22
src/phasedmasync.h 100644
Wyświetl plik

@ -0,0 +1,22 @@
#ifndef DEF_PHASEDMASYNC
#define DEF_PHASEDMASYNC
#include "stdint.h"
#include "dma.h"
#include "gpio.h"
class phasedmasync:public bufferdma,public clkgpio,public pwmgpio,public pcmgpio,public generalgpio
{
protected:
uint64_t tunefreq;
int NumbPhase=2;
uint32_t TabPhase[32];//32 is Max Phase
public:
phasedmasync(uint64_t TuneFrequency,uint32_t SampleRate,int NumberOfPhase,int Channel,uint32_t FifoSize);
~phasedmasync();
void SetDmaAlgo();
void SetPhase(uint32_t Index,int Phase);
};
#endif

Wyświetl plik

@ -0,0 +1,78 @@
#include "stdio.h"
#include "serialdmasync.h"
serialdmasync::serialdmasync(uint32_t SampleRate,int Channel,uint32_t FifoSize,bool dualoutput):bufferdma(Channel,FifoSize,1,1)
{
if(dualoutput) //Fixme if 2pin we want maybe 2*SRATE as it is distributed over 2 pin
{
pwmgpio::SetMode(pwm2pin);
SampleRate*=2;
}
else
{
pwmgpio::SetMode(pwm1pin);
}
if(SampleRate>250000)
{
pwmgpio::SetPllNumber(clk_plld,1);
pwmgpio::SetFrequency(SampleRate);
}
else
{
pwmgpio::SetPllNumber(clk_osc,1);
pwmgpio::SetFrequency(SampleRate);
}
enablepwm(12,0); // By default PWM on GPIO 12/pin 32
enablepwm(13,0); // By default PWM on GPIO 13/pin 33
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()
{
}
void serialdmasync::SetDmaAlgo()
{
dma_cb_t *cbp = cbarray;
for (uint32_t samplecnt = 0; samplecnt < buffersize; samplecnt++)
{
cbp->info = BCM2708_DMA_NO_WIDE_BURSTS | BCM2708_DMA_WAIT_RESP |BCM2708_DMA_D_DREQ | BCM2708_DMA_PER_MAP(DREQ_PWM);
cbp->src = mem_virt_to_phys(&usermem[samplecnt*registerbysample]);
cbp->dst = 0x7E000000 + (PWM_FIFO<<2) + PWM_BASE ;
cbp->length = 4;
cbp->stride = 0;
cbp->next = mem_virt_to_phys(cbp + 1);
//fprintf(stderr,"cbp : sample %x src %x dest %x next %x\n",samplecnt,cbp->src,cbp->dst,cbp->next);
cbp++;
}
cbp--;
cbp->next = mem_virt_to_phys(cbarray); // We loop to the first CB
//fprintf(stderr,"Last cbp : src %x dest %x next %x\n",cbp->src,cbp->dst,cbp->next);
}
void serialdmasync::SetSample(uint32_t Index,int Sample)
{
Index=Index%buffersize;
sampletab[Index]=Sample;
PushSample(Index);
}

Wyświetl plik

@ -0,0 +1,20 @@
#ifndef DEF_SERIALDMASYNC
#define DEF_SERIALDMASYNC
#include "stdint.h"
#include "dma.h"
#include "gpio.h"
class serialdmasync:public bufferdma,public clkgpio,public pwmgpio
{
protected:
uint64_t tunefreq;
bool syncwithpwm;
public:
serialdmasync(uint32_t SampleRate,int Channel,uint32_t FifoSize,bool dualoutput);
~serialdmasync();
void SetDmaAlgo();
void SetSample(uint32_t Index,int Sample);
};
#endif

Wyświetl plik

@ -2,36 +2,40 @@
#include "librpitx.h"
#include <unistd.h>
#include "stdio.h"
#include <cstring>
#include <signal.h>
void SimpleTest()
bool running=true;
void SimpleTest(uint64_t Freq)
{
generalgpio generalio;
generalio.enableclk();
clkgpio clk;
clk.SetPllNumber(clk_plld,1);
clk.print_clock_tree();
//clk.SetPllNumber(clk_plla,0);
clk.SetAdvancedPllMode(true);
clk.SetCenterFrequency(144100000);
for(int i=0;i<1000000;i+=1)
clk.SetCenterFrequency(Freq,100000);
clk.SetFrequency(000);
clk.enableclk(4);
sleep(60);
/*for(int i=0;i<100000;i+=1)
{
clk.SetFrequency(i);
//usleep(1);
}
usleep(1000);
}*/
clk.disableclk(4);
}
void SimpleTestDMA()
void SimpleTestDMA(uint64_t Freq)
{
generalgpio generalio;
generalio.enableclk();
int SR=200000;
int FifoSize=4096;
ngfmdmasync ngfmtest(1244200000,SR,14,FifoSize);
for(int i=0;i<SR;)
//ngfmdmasync ngfmtest(1244200000,SR,14,FifoSize);
ngfmdmasync ngfmtest(Freq,SR,14,FifoSize);
for(int i=0;running;)
{
//usleep(10);
usleep(FifoSize*1000000.0*3.0/(4.0*SR));
@ -42,7 +46,7 @@ void SimpleTestDMA()
//printf("GetIndex=%d\n",Index);
for(int j=0;j<Available;j++)
{
ngfmtest.SetFrequencySample(Index,((i%10000)>5000)?1000:0);
//ngfmtest.SetFrequencySample(Index,((i%10000)>5000)?1000:0);
ngfmtest.SetFrequencySample(Index+j,(i%SR));
i++;
@ -59,8 +63,7 @@ void SimpleTestDMA()
using std::complex;
void SimpleTestLiquid()
{
generalgpio generalio;
generalio.enableclk();
int SR=200000;
int FifoSize=4096;
@ -71,7 +74,7 @@ void SimpleTestLiquid()
nco_crcf_set_frequency(q, -0.2f);
//ngfmtest.print_clock_tree();
for(int i=0;i<SR;)
for(int i=0;(i<SR)&&running;)
{
//usleep(10);
usleep(FifoSize*1000000.0*3.0/(4.0*SR));
@ -106,22 +109,23 @@ void SimpleTestLiquid()
ngfmtest.stop();
}
void SimpleTestFileIQ()
void SimpleTestFileIQ(uint64_t Freq)
{
FILE *iqfile=NULL;
iqfile=fopen("ssb.iq","rb");
iqfile=fopen("../ssbtest.iq","rb");
if (iqfile==NULL) printf("input file issue\n");
generalgpio generalio;
generalio.enableclk();
bool stereo=true;
int SR=48000;
int FifoSize=512;
iqdmasync iqtest(1242300000,SR,14,FifoSize);
//iqdmasync iqtest(1245000000,SR,14,FifoSize);
//iqdmasync iqtest(50100000,SR,14,FifoSize);
iqdmasync iqtest(Freq,SR,14,FifoSize);
//iqdmasync iqtest(14100000,SR,14,FifoSize);
short IQBuffer[128*2];
printf("Sizeof = %d\n",sizeof(liquid_float_complex));
while(1)
while(running)
{
//usleep(FifoSize*1000000.0*1.0/(8.0*SR));
usleep(100);
@ -152,10 +156,113 @@ void SimpleTestFileIQ()
iqtest.stop();
}
void SimpleTestbpsk(uint64_t Freq)
{
clkgpio clk;
clk.print_clock_tree();
int SR=1000;
int FifoSize=1024;
int NumberofPhase=2;
phasedmasync biphase(Freq,SR,NumberofPhase,14,FifoSize);
int lastphase=0;
while(running)
{
//usleep(FifoSize*1000000.0*1.0/(8.0*SR));
usleep(10);
int Available=biphase.GetBufferAvailable();
if(Available>256)
{
int Index=biphase.GetUserMemIndex();
/*
for(int i=0;i<Available;i++)
{
int phase=(rand()%NumberofPhase);
biphase.SetPhase(Index+i,phase);
}*/
/*
for(int i=0;i<Available/2;i++)
{
int phase=2*(rand()%NumberofPhase/2);
biphase.SetPhase(Index+i*2,(phase+lastphase)/2);
biphase.SetPhase(Index+i*2+1,phase);
lastphase=phase;
}*/
for(int i=0;i<Available;i++)
{
lastphase=(lastphase+1)%NumberofPhase;
biphase.SetPhase(Index+i,lastphase);
}
}
}
biphase.stop();
}
void SimpleTestSerial()
{
bool stereo=true;
int SR=10000;
int FifoSize=1024;
bool dualoutput=true;
serialdmasync testserial(SR,14,FifoSize,dualoutput);
while(running)
{
usleep(10);
int Available=testserial.GetBufferAvailable();
if(Available>256)
{
int Index=testserial.GetUserMemIndex();
for(int i=0;i<Available;i++)
{
testserial.SetSample(Index+i,i);
}
}
}
testserial.stop();
}
static void
terminate(int num)
{
running=false;
fprintf(stderr,"Caught signal - Terminating\n");
}
int main(int argc, char* argv[])
{
SimpleTestFileIQ();
uint64_t Freq=144200000;
if(argc>1)
Freq=atol(argv[1]);
for (int i = 0; i < 64; i++) {
struct sigaction sa;
std::memset(&sa, 0, sizeof(sa));
sa.sa_handler = terminate;
sigaction(i, &sa, NULL);
}
//SimpleTest(Freq);
//SimpleTestbpsk(Freq);
//SimpleTestFileIQ(Freq);
SimpleTestDMA(Freq);
}