kopia lustrzana https://github.com/F5OEO/rpitx
DMA working
rodzic
d0d2fd9aff
commit
a2dc4f509c
53
src/dma.cpp
53
src/dma.cpp
|
@ -43,7 +43,7 @@ dma::dma(int Channel,uint32_t CBSize,uint32_t UserMemSize) // Fixme! Need to che
|
|||
usermem= (unsigned int *)(virtbase+CBSize*sizeof(dma_cb_t)); // user memory is placed after
|
||||
//fprintf(stderr,"usermem %p\n", usermem);
|
||||
|
||||
dma_reg.gpioreg[DMA_CS+channel*0x40] = BCM2708_DMA_RESET;
|
||||
dma_reg.gpioreg[DMA_CS+channel*0x40] = BCM2708_DMA_RESET|DMA_CS_INT; // Remove int flag
|
||||
usleep(100);
|
||||
dma_reg.gpioreg[DMA_CONBLK_AD+channel*0x40]=mem_virt_to_phys((void*)cbarray ); // reset to beginning
|
||||
}
|
||||
|
@ -138,6 +138,12 @@ bool dma::isrunning()
|
|||
return ((dma_reg.gpioreg[DMA_CS+channel*0x40]&DMA_CS_ACTIVE)>0);
|
||||
}
|
||||
|
||||
bool dma::isunderflow()
|
||||
{
|
||||
//if((dma_reg.gpioreg[DMA_CS+channel*0x40]&DMA_CS_INT)>0) fprintf(stderr,"Status:%x\n",dma_reg.gpioreg[DMA_CS+channel*0x40]);
|
||||
return ((dma_reg.gpioreg[DMA_CS+channel*0x40]&DMA_CS_INT)>0);
|
||||
}
|
||||
|
||||
//**************************************** BUFFER DMA ********************************************************
|
||||
bufferdma::bufferdma(int Channel,uint32_t tbuffersize,uint32_t tcbbysample,uint32_t tregisterbysample):dma(Channel,tbuffersize*tcbbysample,tbuffersize*tregisterbysample)
|
||||
{
|
||||
|
@ -173,24 +179,29 @@ int bufferdma::GetBufferAvailable()
|
|||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr,"DMA Stopped\n");
|
||||
fprintf(stderr,"DMA WEIRD STATE\n");
|
||||
current_sample=0;
|
||||
}
|
||||
//fprintf(stderr,"CurrentCB=%d\n",current_sample);
|
||||
diffsample=current_sample-last_sample;
|
||||
if(diffsample<=0) diffsample+=buffersize;
|
||||
if(diffsample<0) diffsample+=buffersize;
|
||||
|
||||
fprintf(stderr,"cur %d last %d diff%d\n",current_sample,last_sample,diffsample);
|
||||
//fprintf(stderr,"cur %d last %d diff%d\n",current_sample,last_sample,diffsample);
|
||||
}
|
||||
else
|
||||
{
|
||||
last_sample=buffersize-1;
|
||||
//last_sample=buffersize-1;
|
||||
diffsample=buffersize;
|
||||
current_sample=0;
|
||||
fprintf(stderr,"Warning DMA stopped \n");
|
||||
fprintf(stderr,"cur %d last %d diff%d\n",current_sample,last_sample,diffsample);
|
||||
//fprintf(stderr,"Warning DMA stopped \n");
|
||||
//fprintf(stderr,"S:cur %d last %d diff%d\n",current_sample,last_sample,diffsample);
|
||||
}
|
||||
|
||||
if(isunderflow())
|
||||
{
|
||||
fprintf(stderr,"cur %d last %d \n",current_sample,last_sample);
|
||||
fprintf(stderr,"Underflow\n");
|
||||
}
|
||||
return diffsample;
|
||||
|
||||
}
|
||||
|
@ -203,7 +214,7 @@ int bufferdma::GetUserMemIndex()
|
|||
if(GetBufferAvailable()>0)
|
||||
{
|
||||
IndexAvailable=last_sample+1;
|
||||
if(IndexAvailable>=(int)buffersize-1) IndexAvailable=0;
|
||||
if(IndexAvailable>=(int)buffersize) IndexAvailable=0;
|
||||
}
|
||||
return IndexAvailable;
|
||||
}
|
||||
|
@ -214,16 +225,30 @@ int bufferdma::PushSample(int Index)
|
|||
|
||||
/*dma_cb_t *cbp;
|
||||
cbp=&cbarray[last_sample*cbbysample+cbbysample-1];
|
||||
cbp->next=mem_virt_to_phys(&cbarray[Index]);
|
||||
*/
|
||||
cbp->next=mem_virt_to_phys(&cbarray[Index]);*/
|
||||
|
||||
dma_cb_t *cbp;
|
||||
cbp=&cbarray[last_sample*cbbysample+cbbysample-1];
|
||||
//fprintf(stderr,"Info=%x\n",cbp->info);
|
||||
cbp->info=cbp->info&(~BCM2708_DMA_SET_INT);
|
||||
//fprintf(stderr,"Info2=%x\n",cbp->info);
|
||||
|
||||
|
||||
last_sample=Index;
|
||||
/*
|
||||
|
||||
cbp=&cbarray[Index*cbbysample+cbbysample-1];
|
||||
cbp->next=0;
|
||||
*/
|
||||
//fprintf(stderr,"Info=%x\n",cbp->info);
|
||||
cbp->info=cbp->info|(BCM2708_DMA_SET_INT);
|
||||
//fprintf(stderr,"Info2=%x\n",cbp->info);
|
||||
/*if(isunderflow())
|
||||
{
|
||||
fprintf(stderr,"cur %d last %d \n",current_sample,last_sample);
|
||||
fprintf(stderr,"Underflow\n");
|
||||
}*/
|
||||
if(isrunning()==false)
|
||||
{
|
||||
start();
|
||||
if(last_sample>buffersize/4) start(); // 1/4 Fill buffer before starting DMA
|
||||
|
||||
}
|
||||
return 0;
|
||||
|
||||
|
|
|
@ -89,6 +89,7 @@ class dma
|
|||
int stop();
|
||||
int getcbposition();
|
||||
bool isrunning();
|
||||
bool isunderflow();
|
||||
|
||||
};
|
||||
|
||||
|
|
45
src/gpio.cpp
45
src/gpio.cpp
|
@ -64,6 +64,7 @@ clkgpio::~clkgpio()
|
|||
|
||||
int clkgpio::SetPllNumber(int PllNo,int MashType)
|
||||
{
|
||||
//print_clock_tree();
|
||||
if(PllNo<8)
|
||||
pllnumber=PllNo;
|
||||
else
|
||||
|
@ -112,9 +113,9 @@ int clkgpio::SetMasterMultFrac(uint32_t Mult,uint32_t Frac)
|
|||
{
|
||||
|
||||
gpioreg[PLLA_CTRL] = (0x5a<<24) | (0x21<<12) | Mult;
|
||||
//usleep(10);
|
||||
gpioreg[PLLA_FRAC]= 0x5A000000 | Frac ; //4 is START CLK
|
||||
// usleep(10);
|
||||
usleep(10);
|
||||
gpioreg[PLLA_FRAC]= 0x5A000000 | Frac ;
|
||||
usleep(10);
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
@ -178,6 +179,7 @@ int clkgpio::SetCenterFrequency(uint64_t Frequency)
|
|||
//Choose best PLLDiv and Div
|
||||
ComputeBestLO(Frequency);
|
||||
SetClkDivFrac(PllFixDivider,0); // NO MASH !!!!
|
||||
SetFrequency(Frequency);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -200,7 +202,9 @@ void clkgpio::SetAdvancedPllMode(bool Advanced)
|
|||
{
|
||||
SetPllNumber(clk_plla,0); // Use PPL_A , Do not USE MASH which generates spurious
|
||||
gpioreg[0x104/4]=0x5A00020A; // Enable Plla_PER
|
||||
usleep(100);
|
||||
gpioreg[PLLA_PER]=0x5A000002; // Div ?
|
||||
usleep(100);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -361,32 +365,45 @@ uint64_t pwmgpio::GetPllFrequency(int PllNo)
|
|||
|
||||
int pwmgpio::SetFrequency(uint64_t Frequency)
|
||||
{
|
||||
|
||||
double Freqresult=(double)Pllfrequency/(double)Frequency;
|
||||
Prediv=2; // Fixe for now , need investigation if not 32 !!!! FixMe !
|
||||
double Freqresult=(double)Pllfrequency/(double)(Frequency*Prediv);
|
||||
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");
|
||||
fprintf(stderr,"PWM clk=%d / %d\n",FreqDivider,FreqFractionnal);
|
||||
clk.gpioreg[PWMCLK_DIV] = 0x5A000000 | ((FreqDivider)<<12) | FreqFractionnal;
|
||||
|
||||
usleep(100);
|
||||
clk.gpioreg[PWMCLK_CNTL]= 0x5A000000 | (Mash << 9) | pllnumber|(1 << 4) ; //4 is STAR CLK
|
||||
usleep(100);
|
||||
usleep(100);
|
||||
fprintf(stderr,"PWM Reg %x\n",clk.gpioreg[PWMCLK_CNTL]);
|
||||
|
||||
SetPrediv(Prediv);
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int pwmgpio::SetMode(int Mode) //Mode should be only for SYNC or a Data serializer : Todo
|
||||
int pwmgpio::SetPrediv(int predivisor) //Mode should be only for SYNC or a Data serializer : Todo
|
||||
{
|
||||
gpioreg[PWM_RNG1] = 32;// 250 -> 8KHZ
|
||||
Prediv=predivisor;
|
||||
if(Prediv>32)
|
||||
{
|
||||
fprintf(stderr,"PWM Prediv is max 32\n");
|
||||
Prediv=2;
|
||||
}
|
||||
fprintf(stderr,"PWM Prediv %d\n",Prediv);
|
||||
gpioreg[PWM_RNG1] = Prediv;// 250 -> 8KHZ
|
||||
usleep(100);
|
||||
gpioreg[PWM_RNG2] = 32;// 32 Mandatory for Serial Mode without gap
|
||||
gpioreg[PWM_RNG2] = Prediv;// 32 Mandatory for Serial Mode without gap
|
||||
|
||||
gpioreg[PWM_FIFO]=0xAAAAAAAA;
|
||||
//gpioreg[PWM_FIFO]=0xAAAAAAAA;
|
||||
|
||||
gpioreg[PWM_DMAC] = PWMDMAC_ENAB | PWMDMAC_THRSHLD;
|
||||
usleep(100);
|
||||
//gpioreg[PWM_CTL] = PWMCTL_CLRF;
|
||||
|
||||
gpioreg[PWM_CTL] = PWMCTL_USEF1 | PWMCTL_PWEN1; //PWM0 in Repeat mode
|
||||
|
||||
gpioreg[PWM_CTL] = PWMCTL_CLRF;
|
||||
usleep(100);
|
||||
gpioreg[PWM_CTL] = PWMCTL_USEF1 | PWMCTL_PWEN1;
|
||||
usleep(100);
|
||||
|
||||
return 0;
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ class gpio
|
|||
#define BCM2708_DMA_DST_IGNOR (1<<7)
|
||||
#define BCM2708_DMA_NO_WIDE_BURSTS (1<<26)
|
||||
#define BCM2708_DMA_WAIT_RESP (1<<3)
|
||||
#define BCM2708_DMA_SET_INT (1<<0)
|
||||
|
||||
#define BCM2708_DMA_D_DREQ (1<<6)
|
||||
#define BCM2708_DMA_PER_MAP(x) ((x)<<16)
|
||||
|
@ -36,6 +37,7 @@ class gpio
|
|||
#define DMA_CS_RESET (1<<31)
|
||||
#define DMA_CS_ABORT (1<<30)
|
||||
#define DMA_CS_DISDEBUG (1<<28)
|
||||
#define DMA_CS_INT (1<<2)
|
||||
#define DMA_CS_END (1<<1)
|
||||
#define DMA_CS_ACTIVE (1<<0)
|
||||
#define DMA_CS_PRIORITY(x) ((x)&0xf << 16)
|
||||
|
@ -192,6 +194,7 @@ class pwmgpio:public gpio
|
|||
clkgpio clk;
|
||||
int pllnumber;
|
||||
int Mash;
|
||||
int Prediv; //Range of PWM
|
||||
uint64_t Pllfrequency;
|
||||
public:
|
||||
pwmgpio();
|
||||
|
@ -199,7 +202,7 @@ class pwmgpio:public gpio
|
|||
int SetPllNumber(int PllNo,int MashType);
|
||||
uint64_t GetPllFrequency(int PllNo);
|
||||
int SetFrequency(uint64_t Frequency);
|
||||
int SetMode(int Mode);
|
||||
int SetPrediv(int predivisor);
|
||||
};
|
||||
|
||||
//******************************* PCM GPIO (I2S) ***********************************
|
||||
|
|
|
@ -12,7 +12,7 @@ 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::SetFrequency(0);
|
||||
|
||||
/*
|
||||
double FloatMult=((double)TuneFrequency)/(double)(XOSC_FREQUENCY);
|
||||
|
@ -28,9 +28,10 @@ ngfmdmasync::ngfmdmasync(uint64_t TuneFrequency,uint32_t SampleRate,int Channel,
|
|||
*/
|
||||
|
||||
pwmgpio::SetPllNumber(clk_osc,1);
|
||||
//pwmgpio::SetPllNumber(clk_plld,1);
|
||||
|
||||
pwmgpio::SetFrequency(SampleRate);
|
||||
pwmgpio::SetMode(0);
|
||||
|
||||
|
||||
|
||||
|
||||
SetDmaAlgo();
|
||||
|
@ -84,7 +85,7 @@ void ngfmdmasync::SetDmaAlgo()
|
|||
|
||||
// Delay
|
||||
|
||||
cbp->info = /*BCM2708_DMA_SRC_IGNOR | */BCM2708_DMA_NO_WIDE_BURSTS | BCM2708_DMA_WAIT_RESP | BCM2708_DMA_D_DREQ | BCM2708_DMA_PER_MAP(DREQ_PWM);
|
||||
cbp->info = /*BCM2708_DMA_SRC_IGNOR |*/ 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(cbarray); // Data is not important as we use it only to feed the PWM
|
||||
cbp->dst = 0x7E000000 + (PWM_FIFO<<2) + PWM_BASE ;
|
||||
cbp->length = 4;
|
||||
|
@ -106,24 +107,4 @@ void ngfmdmasync::SetFrequencySample(uint32_t Index,int Frequency)
|
|||
PushSample(Index);
|
||||
}
|
||||
|
||||
void ngfmdmasync::FillMemory(uint32_t MultInt,uint32_t FirstFrac)
|
||||
{
|
||||
|
||||
//if(FirstFrac<usermemsize) FirstFrac=usermemsize;
|
||||
uint32_t tempmul=MultInt;
|
||||
for (uint32_t samplecnt = 0; samplecnt < usermemsize/2; samplecnt++)
|
||||
{
|
||||
//uint32_t Frac=(FirstFrac+samplecnt*((samplecnt%2==0)?1:-1))&0xFFFFF;
|
||||
uint32_t Frac=(FirstFrac+samplecnt/10)%(1<<20); //10times less than symbolrate
|
||||
//fprintf(stderr,"Frac %d\n",Frac);
|
||||
if(Frac==0)
|
||||
{
|
||||
fprintf(stderr,"Cross Int\n");
|
||||
tempmul=MultInt+1;
|
||||
}
|
||||
//usermem[samplecnt*2]=(0x5a<<24) | (0x21<<12) | tempmul;
|
||||
//usermem[samplecnt*2+1]=0x5A000000 | Frac;
|
||||
usermem[samplecnt*2]=0x5A000000 | FirstFrac;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ class ngfmdmasync:public bufferdma,public clkgpio,public pwmgpio
|
|||
ngfmdmasync(uint64_t TuneFrequency,uint32_t SampleRate,int Channel,uint32_t FifoSize);
|
||||
~ngfmdmasync();
|
||||
void SetDmaAlgo();
|
||||
void FillMemory(uint32_t MultInt,uint32_t FirstFrac);
|
||||
|
||||
void SetPhase(bool inversed);
|
||||
void SetFrequencySample(uint32_t Index,int Frequency);
|
||||
};
|
||||
|
|
|
@ -10,8 +10,8 @@ int main(int argc, char* argv[])
|
|||
|
||||
generalgpio generalio;
|
||||
generalio.enableclk();
|
||||
/*
|
||||
clkgpio clk;
|
||||
|
||||
/*clkgpio clk;
|
||||
clk.SetPllNumber(clk_plld,1);
|
||||
clk.SetAdvancedPllMode(true);
|
||||
clk.SetCenterFrequency(144100000);
|
||||
|
@ -20,28 +20,30 @@ int main(int argc, char* argv[])
|
|||
clk.SetFrequency(i);
|
||||
usleep(10);
|
||||
}
|
||||
sleep(5);
|
||||
*/
|
||||
sleep(5);*/
|
||||
|
||||
//dma mydma(14,32,16);
|
||||
//bufferdma mydma(14,16,2,1);
|
||||
|
||||
ngfmdmasync ngfmtest(144100000,5000,14,128);
|
||||
|
||||
for(int i=0;i<256;i++)
|
||||
|
||||
ngfmdmasync ngfmtest(144100000,200000,14,512);
|
||||
|
||||
for(int i=0;i<1000000;)
|
||||
{
|
||||
//usleep(10);
|
||||
int Index=ngfmtest.GetUserMemIndex();
|
||||
//printf("GetIndex=%d\n",Index);
|
||||
if(Index>=0)
|
||||
{
|
||||
ngfmtest.SetFrequencySample(Index,i*10);
|
||||
//ngfmtest.SetFrequencySample(Index,((i%10000)>5000)?1000:0);
|
||||
ngfmtest.SetFrequencySample(Index,i%100000);
|
||||
i++;
|
||||
|
||||
}
|
||||
else
|
||||
usleep(10);
|
||||
}
|
||||
fprintf(stderr,"End\n");
|
||||
sleep(10);
|
||||
|
||||
ngfmtest.stop();
|
||||
|
||||
|
||||
|
|
Ładowanie…
Reference in New Issue