From 25e5869d2e68f187bf32e3bf2338bac3e57b1e74 Mon Sep 17 00:00:00 2001 From: F5OEO Date: Fri, 2 Sep 2016 09:59:25 +0000 Subject: [PATCH] Clear code, work on DMA timing and calibration --- src/RpiDma.c | 1 + src/RpiDma.h | 37 ++-- src/RpiGpio.c | 4 +- src/RpiGpio.h | 11 ++ src/RpiTx.c | 528 ++++++++++++++++++++------------------------------ src/RpiTx.h | 5 +- 6 files changed, 243 insertions(+), 343 deletions(-) diff --git a/src/RpiDma.c b/src/RpiDma.c index 2927d74..c23ff43 100644 --- a/src/RpiDma.c +++ b/src/RpiDma.c @@ -89,6 +89,7 @@ char InitDma(void *FunctionTerminate, int* skipSignals) printf("Failed to open mailbox\n"); return(0); } + printf("%d Size NUM PAGES %d PAGE_SIZE %d\n",(sizeof(struct control_data_s)),NUM_PAGES,PAGE_SIZE); mbox.mem_ref = mem_alloc(mbox.handle, NUM_PAGES* PAGE_SIZE, PAGE_SIZE, mem_flag); /* TODO: How do we know that succeeded? */ //printf("mem_ref %x\n", mbox.mem_ref); diff --git a/src/RpiDma.h b/src/RpiDma.h index 79b13e4..70078a8 100644 --- a/src/RpiDma.h +++ b/src/RpiDma.h @@ -24,7 +24,7 @@ uint32_t mem_phys_to_virt(volatile uint32_t phys); #define NUM_CB_PWM_FREQUENCY 8 //#define MBFILE DEVICE_FILE_NAME /* From mailbox.h */ #define NUM_SAMPLES_MAX (4000) -#define CBS_SIZE_BY_SAMPLE (5) +#define CBS_SIZE_BY_SAMPLE (3) #define NUM_CBS_MAIN ((NUM_SAMPLES_MAX * CBS_SIZE_BY_SAMPLE)) #define NUM_CBS (NUM_CBS_MAIN) @@ -38,6 +38,7 @@ uint32_t mem_phys_to_virt(volatile uint32_t phys); #define BCM2708_DMA_PER_MAP(x) ((x)<<16) #define BCM2708_DMA_END (1<<1) #define BCM2708_DMA_RESET (1<<31) +#define BCM2708_DMA_ABORT (1<<30) #define BCM2708_DMA_INT (1<<2) #define DMA_CS (0x00/4) @@ -46,6 +47,14 @@ uint32_t mem_phys_to_virt(volatile uint32_t phys); #define BUS_TO_PHYS(x) ((x)&~0xC0000000) +#define DMA_CS_RESET (1<<31) +#define DMA_CS_ABORT (1<<30) +#define DMA_CS_DISDEBUG (1<<28) +#define DMA_CS_END (1<<1) +#define DMA_CS_ACTIVE (1<<0) +#define DMA_CS_PRIORITY(x) ((x)&0xf << 16) +#define DMA_CS_PANIC_PRIORITY(x) ((x)&0xf << 20) + #define PAGE_SIZE 4096 #define PAGE_SHIFT 12 #define NUM_PAGES ((sizeof(struct control_data_s) + PAGE_SIZE - 1) >> PAGE_SHIFT) @@ -93,31 +102,25 @@ page_map_t *page_map; uint8_t *virtbase; +#define PWM_STEP_MAXI 200 + typedef struct { - //uint32_t Frequency1; - //uint32_t Frequency2; + + uint32_t FrequencyTab[PWM_STEP_MAXI]; uint32_t Amplitude1; uint32_t Amplitude2; - uint32_t PWMF1; - uint32_t PWMF2; - uint32_t WaitForThisSample; - uint32_t PCMRegister; - uint32_t FrequencyTab[200]; - uint32_t debugSet; - uint32_t debugClear; + } sample_t; struct control_data_s { dma_cb_t cb[NUM_CBS];//+1 ?? - dma_cb_t cbdma2[NUM_CB_PWM_FREQUENCY]; + sample_t sample[NUM_SAMPLES_MAX]; - uint32_t GpioDebugPWMF; - uint32_t GpioDebugSampleRate; - uint32_t SharedFrequency1; - uint32_t SharedFrequency2; - uint32_t DmaPwmfControlRegister; - uint32_t SharedFrequencyTab[100]; + + + + }; struct control_data_s *ctl; diff --git a/src/RpiGpio.c b/src/RpiGpio.c index 2949b3f..13f9744 100644 --- a/src/RpiGpio.c +++ b/src/RpiGpio.c @@ -20,14 +20,14 @@ char InitGpio() { BCM2708_PERI_BASE = info.peripheralBase ; dram_phys_base = 0x40000000; - mem_flag = 0x0c; + mem_flag = MEM_FLAG_L1_NONALLOCATING|MEM_FLAG_HINT_PERMALOCK|MEM_FLAG_NO_INIT;//0x0c; } if((info.peripheralBase==RPI_BROADCOM_2836_PERIPHERAL_BASE)||(info.peripheralBase==RPI_BROADCOM_2837_PERIPHERAL_BASE)) { BCM2708_PERI_BASE = info.peripheralBase ; dram_phys_base = 0xc0000000; - mem_flag = 0x04; + mem_flag = MEM_FLAG_L1_NONALLOCATING/*MEM_FLAG_DIRECT*/|MEM_FLAG_HINT_PERMALOCK|MEM_FLAG_NO_INIT;//0x04; } } diff --git a/src/RpiGpio.h b/src/RpiGpio.h index e909fe5..1ac83a8 100644 --- a/src/RpiGpio.h +++ b/src/RpiGpio.h @@ -93,4 +93,15 @@ int gpioSetMode(unsigned gpio, unsigned mode); #define GPFSEL0 (0x00/4) #define GPFSEL1 (0x04/4) #define GPFSEL2 (0x08/4) + +// ---- Memory allocating defines +// https://github.com/raspberrypi/firmware/wiki/Mailbox-property-interface +#define MEM_FLAG_DISCARDABLE (1 << 0) /* can be resized to 0 at any time. Use for cached data */ +#define MEM_FLAG_NORMAL (0 << 2) /* normal allocating alias. Don't use from ARM */ +#define MEM_FLAG_DIRECT (1 << 2) /* 0xC alias uncached */ +#define MEM_FLAG_COHERENT (2 << 2) /* 0x8 alias. Non-allocating in L2 but coherent */ +#define MEM_FLAG_L1_NONALLOCATING (MEM_FLAG_DIRECT | MEM_FLAG_COHERENT) /* Allocating in L2 */ +#define MEM_FLAG_ZERO ( 1 << 4) /* initialise buffer to all zeros */ +#define MEM_FLAG_NO_INIT ( 1 << 5) /* don't initialise (default is initialise to all ones */ +#define MEM_FLAG_HINT_PERMALOCK (1 << 6) /* Likely to be locked for long periods of time. */ #endif diff --git a/src/RpiTx.c b/src/RpiTx.c index 99bcb16..1dc0227 100644 --- a/src/RpiTx.c +++ b/src/RpiTx.c @@ -65,7 +65,6 @@ Optimize CPU on PWMFrequency #define SCHED_PRIORITY 30 //Linux scheduler priority. Higher = more realtime -//#define WITH_MEMORY_BUFFER #define PROGRAM_VERSION "0.2" @@ -84,6 +83,12 @@ Optimize CPU on PWMFrequency #define HEADER_SIZE 44 +// DMA TIMING : depends on Pi Model : Calibration is better +#define FREQ_DELAY_TIME 0 +int FREQ_MINI_TIMING=157; +int PWMF_MARGIN = 1120; //A Margin for now at 1us with PCM ->OK +int globalppmpll=0; + typedef unsigned char uchar; // 8 bit typedef unsigned short uint16; // 16 bit typedef unsigned int uint; // 32 bits @@ -120,33 +125,25 @@ static void udelay(int us) static void stop_dma(void) { - #ifdef WITH_MEMORY_BUFFER - //pthread_cancel(th1); - EndOfApp=1; - pthread_join(th1, NULL); - #endif + if (FileInHandle != -1) { close(FileInHandle); FileInHandle = -1; } if (dma_reg) { //Stop Main DMA - dma_reg[DMA_CS+DMA_CHANNEL*0x40] = BCM2708_DMA_INT | BCM2708_DMA_END; + //STop DMA + dma_reg[DMA_CS+DMA_CHANNEL*0x40] |= DMA_CS_ABORT; udelay(100); - dma_reg[DMA_CS+DMA_CHANNEL*0x40] = BCM2708_DMA_RESET; + dma_reg[DMA_CS+DMA_CHANNEL*0x40]&= ~DMA_CS_ACTIVE; + dma_reg[DMA_CS+DMA_CHANNEL*0x40] |= DMA_CS_RESET; udelay(100); - //Stop DMA PWMFrequency - /* - dma_reg[DMA_CS+DMA_CHANNEL_PWMFREQUENCY*0x40] = BCM2708_DMA_INT | BCM2708_DMA_END; - udelay(100); - dma_reg[DMA_CS+DMA_CHANNEL_PWMFREQUENCY*0x40] = BCM2708_DMA_RESET; - udelay(100); - */ + //printf("Reset DMA Done\n"); clk_reg[GPCLK_CNTL] = 0x5A << 24 | 0 << 9 | 1 << 4 | 6; //NO MASH !!! udelay(500); - gpio_reg[GPFSEL0] = (gpio_reg[GPFSEL0] & ~(7 << 12)) | (0 << 12); //DISABLE CLOCK - In case used by digilite + gpio_reg[GPFSEL0] = (gpio_reg[GPFSEL0] & ~(7 << 12)) | (0 << 12); //DISABLE CLOCK - clk_reg[PWMCLK_CNTL] = 0x5A000006 | (0 << 9) ; udelay(500); clk_reg[PCMCLK_CNTL] = 0x5A000006; @@ -201,7 +198,7 @@ void setSchedPriority(int priority) } uint32_t DelayFromSampleRate=0; -int Instrumentation=1; +int Instrumentation=0; int UsePCMClk=0; uint32_t Originfsel=0; @@ -224,18 +221,12 @@ int SetupGpioClock(uint32_t SymbolRate,double TuningFrequency) if(UsePCMClk==1) gpio_reg[GPFSEL0] = (Originfsel & ~(7 << 12)) | (4 << 12); //ENABLE CLOCK ON GPIO CLK - /* - gpio_reg[GPFSEL0] = (gpio_reg[GPFSEL0] & ~(7 << 12)) | (4 << 12); //ENABLE CLOCK ON GPIO CLK - usleep(1000); - clk_reg[GPCLK_CNTL] = 0x5A << 24 |0<<4 | PLL_1GHZ; - usleep(1000); - clk_reg[GPCLK_CNTL] = 0x5A << 24 | MASH << 9 | 1 << 4 | PLL_1GHZ; // MASH 1 - */ // ------------------- MAKE MAX OUTPUT CURRENT FOR GPIO ----------------------- char OutputPower=7; pad_gpios_reg[PADS_GPIO_0] = 0x5a000000 + (OutputPower&0x7) + (1<<4) + (0<<3); // Set output power for I/Q GPIO18/GPIO19 +#ifdef USE_PCM //------------------- Init PCM ------------------ pcm_reg[PCM_CS_A] = 1; // Disable Rx+Tx, Enable PCM block udelay(100); @@ -247,8 +238,7 @@ int SetupGpioClock(uint32_t SymbolRate,double TuningFrequency) FreqDividerPCM=(int) ((double)PllFreq1GHZ/(SymbolRate*NbStepPCM/**PwmNumberStep*/)); FreqFractionnalPCM=4096.0 * (((double)PllFreq1GHZ/(SymbolRate*NbStepPCM/**PwmNumberStep*/))-FreqDividerPCM); - //FreqDividerPCM=(int) ((double)PllFreq1GHZ/(1000000L*NbStepPCM/**PwmNumberStep*/)); //SET TO 10MHZ = 100ns - //FreqFractionnalPCM=4096.0 * (((double)PllFreq1GHZ/(1000000L*NbStepPCM/**PwmNumberStep*/))-FreqDividerPCM); + printf("SampleRate=%d\n",SymbolRate); if((FreqDividerPCM>4096)||(FreqDividerPCM<2)) printf("Warning : SampleRate is not valid\n"); clk_reg[PCMCLK_DIV] = 0x5A000000 | ((FreqDividerPCM)<<12) | FreqFractionnalPCM; @@ -256,17 +246,7 @@ int SetupGpioClock(uint32_t SymbolRate,double TuningFrequency) //printf("Div PCM %d FracPCM %d\n",FreqDividerPCM,FreqFractionnalPCM); DelayFromSampleRate=(1e9/(SymbolRate)); - //printf("Delay PCM (min step)=%d\n",DelayFromSampleRate); - //uint32_t DelayFromSampleRate=(1000000.0-2080.0)/27.4425; - //uint32_t DelayFromSampleRate=1000000; - //uint32_t DelayFromSampleRate=round((1000000-(2300))/27.4425); - //TimeDelay=0 : 2.08us - //TimeDelay=10000 : 280us - //TimdeDelay=100000 :2774us - //TimdeDelay=1000000 : 27400 us - //uint32_t DelayFromSampleRate=5000; - //printf("DelaySample %d Delay %d\n",DelayFromSampleRate,(int)(27.4425*DelayFromSampleRate+2300)); - + pcm_reg[PCM_TXC_A] = 0<<31 | 1<<30 | 0<<20 | 0<<16; // 1 channel, 8 bits udelay(100); @@ -282,10 +262,10 @@ int SetupGpioClock(uint32_t SymbolRate,double TuningFrequency) clk_reg[PCMCLK_CNTL] = 0x5A000010 |(1 << 9)| PLL_1GHZ /*PLL_1GHZ*/; // Source=PLLC and enable udelay(100); pcm_reg[PCM_CS_A] |= 1<<2; //START TX PCM - +#endif // FIN PCM - //INIT PWM in Serial Mode + //INIT PWM in Serial Mode : WE USE PWM OUPUT if(UsePCMClk==0) { gpioSetMode(18, 2); /* set to ALT5, PWM1 : RF On PIN */ @@ -310,7 +290,7 @@ int SetupGpioClock(uint32_t SymbolRate,double TuningFrequency) } // FIN INIT PWM - //******************* INIT CLK MODE + //******************* INIT CLK MODE : WE OUTPUT CLK INSTEAD OF PWM OUTPUT if(UsePCMClk==1) { clk_reg[GPCLK_CNTL] = 0x5A000000 | (MASH << 9) |PllNumber/*PLL_1GHZ*/ ; @@ -319,6 +299,8 @@ int SetupGpioClock(uint32_t SymbolRate,double TuningFrequency) udelay(300); clk_reg[GPCLK_CNTL] = 0x5A000010 | (MASH << 9) | PllNumber /*PLL_1GHZ*/; //MASH3 : A TESTER SI MIEUX en MASH1 } + + ctl = (struct control_data_s *)virtbase; // Struct ctl is mapped to the memory allocated by RpiDMA (Mailbox) dma_cb_t *cbp = ctl->cb; @@ -333,30 +315,16 @@ int SetupGpioClock(uint32_t SymbolRate,double TuningFrequency) uint32_t phys_gpio_pads_addr =0x7e10002c; uint32_t phys_pcm_clock = 0x7e10109c ; uint32_t phys_pcm_clock_div_addr = 0x7e10109c;//CLOCK Frequency Setting - uint32_t phys_DmaPwmfRegCtrl = 0x7e007000+DMA_CHANNEL_PWMFREQUENCY*0x100+0x4; + uint32_t phys_gpfsel = 0x7E200000 ; int samplecnt; - gpioSetMode(27,1); // OSCILO SUR PIN 27 - ctl->GpioDebugSampleRate=1<<27; // GPIO 27/ PIN 13 HEADER IS DEBUG SIGNAL OF SAMPLERATE - ctl->DmaPwmfControlRegister=mem_virt_to_phys((void *)(ctl->cbdma2) ); - + for (samplecnt = 0; samplecnt < NUM_SAMPLES ; samplecnt++) { - //ctl->sample[samplecnt].WaitForThisSample=DelayFromSampleRate; - ctl->sample[samplecnt].PCMRegister=0x5A000000 | ((FreqDividerPCM)<<12) | FreqFractionnalPCM; -//@0 - cbp->info = 0;//BCM2708_DMA_WAIT_RESP|BCM2708_DMA_NO_WIDE_BURSTS;//BCM2708_DMA_NO_WIDE_BURSTS /*| BCM2708_DMA_WAIT_RESP | */; - cbp->src = mem_virt_to_phys(&ctl->GpioDebugSampleRate); //Clear - if(Instrumentation==1) - cbp->dst = phys_gpio_clear_addr; - else - cbp->dst = dummy_gpio; - cbp->length = 4; - cbp->stride = 0; - cbp->next = mem_virt_to_phys(cbp + 1); - cbp++; -//@1 + + +//@0 //Set Amplitude by writing to PWM_SERIAL via PADS cbp->info = 0;//BCM2708_DMA_NO_WIDE_BURSTS | BCM2708_DMA_WAIT_RESP ; cbp->src = mem_virt_to_phys(&ctl->sample[samplecnt].Amplitude1); @@ -365,7 +333,7 @@ int SetupGpioClock(uint32_t SymbolRate,double TuningFrequency) cbp->stride = 0; cbp->next = mem_virt_to_phys(cbp + 1); cbp++; -//@2 +//@1 //Set Amplitude by writing to PWM_SERIAL via Patern cbp->info = 0;//BCM2708_DMA_NO_WIDE_BURSTS | BCM2708_DMA_WAIT_RESP ; cbp->src = mem_virt_to_phys(&ctl->sample[samplecnt].Amplitude2); @@ -377,80 +345,25 @@ int SetupGpioClock(uint32_t SymbolRate,double TuningFrequency) cbp->stride = 0; cbp->next = mem_virt_to_phys(cbp + 1); cbp++; -//@3 +//2 //Set PWMFrequency - cbp->info =/*BCM2708_DMA_NO_WIDE_BURSTS |BCM2708_DMA_WAIT_RESP|*/BCM2708_DMA_SRC_INC; + cbp->info =/*BCM2708_DMA_NO_WIDE_BURSTS*/ BCM2708_DMA_SRC_INC|BCM2708_DMA_NO_WIDE_BURSTS; + // BCM2708_DMA_WAIT_RESP : without 160ns, with 300ns cbp->src = mem_virt_to_phys(&ctl->sample[samplecnt].FrequencyTab[0]); if(UsePCMClk==0) cbp->dst = phys_pwm_clock_div_addr; if(UsePCMClk==1) cbp->dst = phys_clock_div_addr; - cbp->length = 4;//mem_virt_to_phys(&ctl->sample[samplecnt].PWMF1); //Be updated by main DMA + cbp->length = 4; //Be updated by main DMA cbp->stride = 0; cbp->next = mem_virt_to_phys(cbp + 1); cbp++; -//@4 - cbp->info =0;// BCM2708_DMA_WAIT_RESP|BCM2708_DMA_NO_WIDE_BURSTS ; //A - cbp->src = mem_virt_to_phys(&ctl->GpioDebugSampleRate); //Set - - if(Instrumentation==1) - cbp->dst = phys_gpio_set_addr; - else - cbp->dst = dummy_gpio; - cbp->length = 4; - cbp->stride = 0; - cbp->next = mem_virt_to_phys(cbp + 1); - cbp++; -//@5 - //SET PCM_FIFO TO WAIT - - /*cbp->info = 0;//BCM2708_DMA_NO_WIDE_BURSTS | BCM2708_DMA_WAIT_RESP|BCM2708_DMA_D_DREQ |BCM2708_DMA_PER_MAP(2); - cbp->src = mem_virt_to_phys(virtbase); //Dummy DATA - cbp->dst = dummy_gpio;//phys_pcm_fifo_addr; - cbp->length = 4; - cbp->stride = 0; - cbp->next = mem_virt_to_phys(cbp + 1); - cbp++;*/ } cbp--; cbp->next = mem_virt_to_phys((void*)virtbase); -// *************************************** DMA CHANNEL 2 : PWM FREQUENCY ********************************************* -// !!!!!!!!!!!!!!!!!!!!!!!!!!!! NOT USED ANYMORE ************************************************************ - cbp = ctl->cbdma2; - //printf("DMA2 %x\n",mem_virt_to_phys(&ctl->cb[NUM_CBS_MAIN])); - - gpioSetMode(17,1); // OSCILO SUR PIN 17 - ctl->GpioDebugPWMF=1<<17; // GPIO 17/ PIN 11 HEADER IS DEBUG SIGNAL OF PWMFREQUENCY - -//@0 = CBS_MAIN+0 1280 ns for 2 instructions - cbp->info = BCM2708_DMA_NO_WIDE_BURSTS /*| BCM2708_DMA_WAIT_RESP | */; - cbp->src = mem_virt_to_phys(&ctl->GpioDebugPWMF); //Clear - cbp->dst = phys_gpio_set_addr; - cbp->length = 4; - cbp->stride = 0; - cbp->next = mem_virt_to_phys(cbp + 1); - cbp++; - -//@1 = CBS_MAIN+1 Length*27ns - cbp->info =BCM2708_DMA_WAIT_RESP |/*BCM2708_DMA_NO_WIDE_BURSTS| BCM2708_DMA_WAIT_RESP|*//*(0x8<< 21) |*/ BCM2708_DMA_SRC_INC; - cbp->src = mem_virt_to_phys(&ctl->SharedFrequencyTab[0]);//mem_virt_to_phys(&ctl->SharedFrequencyTab[0]);//mem_virt_to_phys(&ctl->SharedFrequency1); - cbp->dst = phys_pwm_clock_div_addr; - cbp->length = ctl->sample[0].PWMF1; //Be updated by main DMA - cbp->stride = 0; - cbp->next = mem_virt_to_phys(cbp + 1); - cbp++; -//@2 = CBS_MAIN+2 - //** PWM LOW - cbp->info = BCM2708_DMA_NO_WIDE_BURSTS /*| BCM2708_DMA_WAIT_RESP |*/ ; //A - cbp->src = mem_virt_to_phys(&ctl->GpioDebugPWMF); //Set - cbp->dst = phys_gpio_clear_addr; - cbp->length = 4; - cbp->stride = 0; - cbp->next = mem_virt_to_phys(ctl->cbdma2); // Loop to begin of DMA 2 - // ------------------------------ END DMA INIT --------------------------------- dma_reg[DMA_CS+DMA_CHANNEL*0x40] = BCM2708_DMA_RESET; @@ -461,18 +374,7 @@ int SetupGpioClock(uint32_t SymbolRate,double TuningFrequency) udelay(100); dma_reg[DMA_DEBUG+DMA_CHANNEL*0x40] = 7; // clear debug error flags udelay(100); - // START DMA will be later when data coming in - //dma_reg[DMA_CS+DMA_CHANNEL*0x40] = 0x10FF0001; // go, mid priority, wait for outstanding writes :7 Seems Max Priorit - //WAIT FOR OUTSTADING_WRITE make 50ns de plus pour ecrire dans un registre - //printf("END INIT SSTV\n"); - /*dma_reg[DMA_CS+DMA_CHANNEL_PWMFREQUENCY*0x40] = BCM2708_DMA_RESET; - udelay(1000); - dma_reg[DMA_CS+DMA_CHANNEL_PWMFREQUENCY*0x40] = BCM2708_DMA_INT | BCM2708_DMA_END; - udelay(100); - dma_reg[DMA_CONBLK_AD+DMA_CHANNEL_PWMFREQUENCY*0x40]=mem_virt_to_phys((void *)(ctl->cbdma2) ); - udelay(100); - dma_reg[DMA_DEBUG+DMA_CHANNEL_PWMFREQUENCY*0x40] = 7; // clear debug error flags - */ + return 1; } @@ -514,36 +416,24 @@ void IQToFreqAmp(int I,int Q,double *Frequency,int *Amp,int SampleRate) } -// A utility function to swap to integers -void swap (uint32_t *a, uint32_t *b) -{ - int temp = *a; - *a = *b; - *b = temp; -} - - -// A function to generate a random permutation of arr[] -void randomize ( uint32_t arr[], int n ) -{ - // Use a different seed value so that we don't get same - // result each time we run this program - srand ( time(NULL) ); - - // Start from the last element and swap one by one. We don't - // need to run for the first element that's why i > 0 - int i; - for ( i = n-1; i > 0; i--) - { - - // Pick a random index from 0 to i - int j = rand() % (i+1); - - // Swap arr[i] with the element at random index - swap(&arr[i], &arr[j]); - } -} + +inline void shuffle_int(uint32_t list[], size_t len) +{ + int j; + uint32_t tmp; + while(len) + { + j = rand() % (len+1); + if (j != len - 1) + { + tmp = list[j]; + list[j] = list[len - 1]; + list[len - 1] = tmp; + } + len--; + } +} inline void FrequencyAmplitudeToRegister(double TuneFrequency,uint32_t Amplitude,int NoSample,uint32_t WaitNanoSecond,uint32_t SampleRate,char NoUsePWMF,int debug) { @@ -559,10 +449,8 @@ inline void FrequencyAmplitudeToRegister(double TuneFrequency,uint32_t Amplitude 0xAAAA8000,0xAAAAA000,0xAAAAA800,0xAAAAAA00, 0xAAAAAA80,0xAAAAAAA0,0xAAAAAAA8,0xAAAAAAAA,0xAAAAAAAA}; - static double FixedNumberStepForGpio=(1280.0)/27.0; // Gpio set is 1280ns, Wait is Number of 27ns - #define STEP_AVERAGE_AMPLITUDE 1000 - static uint32_t HistoryAmplitude[STEP_AVERAGE_AMPLITUDE]; - static uint32_t OldAmplitude=0; + + static char First=1; ctl = (struct control_data_s *)virtbase; // Struct ctl is mapped to the memory allocated by RpiDMA (Mailbox) @@ -576,27 +464,9 @@ inline void FrequencyAmplitudeToRegister(double TuneFrequency,uint32_t Amplitude // WITH DMA_CTL WITHOUT BCM2708_DMA_WAIT_RESP // Time = NBStep * 157 ns + 1360 ns - #define FREQ_MINI_TIMING 157 - #define FREQ_DELAY_TIME 0 - //#define PWMF_MARGIN 2700 //A Margin for now at 1us with PCM - //#define PWMF_MARGIN 2400 //A Margin for now at 1us with PCM ->OK - #define PWMF_MARGIN 2198 // Seems to work well with SSTV - #define PWM_STEP_MAXI 200 + - // WITH BCM2708_DMA_WAIT_RESP - // Time = NBStep * 420 ns + 420 ns - // GOOD BY EXPERIMENT - /*#define FREQ_MINI_TIMING 500 - #define FREQ_DELAY_TIME 500 - #define PWMF_MARGIN (1000) //A Margin for now at 1us - #define PWM_STEP_MAXI 200 - */ - - /*#define FREQ_MINI_TIMING 420 - #define FREQ_DELAY_TIME 0 - #define PWMF_MARGIN (3000) //A Margin for now at 1us - #define PWM_STEP_MAXI 200 - */ + if(WaitNanoSecond==0) { if(SampleRate!=0) @@ -604,19 +474,8 @@ inline void FrequencyAmplitudeToRegister(double TuneFrequency,uint32_t Amplitude } PwmNumberStep=WaitNanoSecond/FREQ_MINI_TIMING; - //if((PwmNumberStep%2)!=0) PwmNumberStep++; // Paire - - /* - if(WaitNanoSecond(FREQ_DELAY_TIME+PWMF_MARGIN)) - PwmNumberStep=(WaitNanoSecond-FREQ_DELAY_TIME-PWMF_MARGIN)/FREQ_MINI_TIMING; - else - PwmNumberStep=2; // Mini - */ if(PwmNumberStep>PWM_STEP_MAXI) PwmNumberStep=PWM_STEP_MAXI; - //PwmNumberStep=100; - //printf("Waitnano %d NbStep=%d\n",WaitNanoSecond,PwmNumberStep); // ********************************** PWM FREQUENCY PROCESSING ***************************** @@ -630,8 +489,6 @@ inline void FrequencyAmplitudeToRegister(double TuneFrequency,uint32_t Amplitude uint32_t FreqDividerf1=(FreqFractionnalf2!=4095)?FreqDividerf2:FreqDividerf2+1; uint32_t FreqFractionnalf1=(FreqFractionnalf2!=4095)?FreqFractionnalf2+1:0; - //FreqDividerf2=FreqDividerf2*2;//debug - double f1=PllUsed/(FreqDividerf1+(double)FreqFractionnalf1/4096.0); double f2=PllUsed/(FreqDividerf2+(double)FreqFractionnalf2/4096.0); // f2 is the higher frequency double FreqTuningUp=PllUsed/(FreqDividerf2+(double)FreqFractionnalf2/4096.0); @@ -667,7 +524,7 @@ inline void FrequencyAmplitudeToRegister(double TuneFrequency,uint32_t Amplitude NbF2=0; NbF1F2=0; - //if(CompteurDebug%2000==0) printf("PwmNumberStep %d PWMFrequency %d\n",PwmNumberStep,PWMFrequency); + int AdaptPWMFrequency; if((PwmNumberStep-PWMFrequency-(PWMF_MARGIN+FREQ_DELAY_TIME)/FREQ_MINI_TIMING)>PwmNumberStep/2) { @@ -676,7 +533,7 @@ inline void FrequencyAmplitudeToRegister(double TuneFrequency,uint32_t Amplitude AdaptPWMFrequency=PWMFrequency; NbF1=0; NbF2=(PWMF_MARGIN+FREQ_DELAY_TIME)/FREQ_MINI_TIMING; - //NbF2=0; + } else // SWAP F1 AND F2 { @@ -684,13 +541,13 @@ inline void FrequencyAmplitudeToRegister(double TuneFrequency,uint32_t Amplitude RegisterF2=0x5A000000 | (FreqDividerf1<<12) | (FreqFractionnalf1); RegisterF1=0x5A000000 | (FreqDividerf2<<12) | (FreqFractionnalf2); AdaptPWMFrequency=PwmNumberStep-PWMFrequency; - NbF1=0;//(PWMF_MARGIN+FREQ_DELAY_TIME)/FREQ_MINI_TIMING; + NbF1=0; NbF2=(PWMF_MARGIN+FREQ_DELAY_TIME)/FREQ_MINI_TIMING; } i=0; NbF1F2=NbF1+NbF2; - //if((CompteurDebug%DEBUG_RATE)==0) printf("F1 %d \n",AdaptPWMFrequency); + if(NoUsePWMF==1) { RegisterF1=0x5A000000 | (FreqDividerf1<<12) | (FreqFractionnalf1); @@ -716,46 +573,22 @@ inline void FrequencyAmplitudeToRegister(double TuneFrequency,uint32_t Amplitude } } if (Randomize) - randomize(ctl->sample[NoSample].FrequencyTab,i); + shuffle_int(ctl->sample[NoSample].FrequencyTab,i); + //SHould finished by F2 ctl->sample[NoSample].FrequencyTab[i++]=RegisterF2; NbF2++; NbF1F2++; } - //if((CompteurDebug%DEBUG_RATE)==0) printf("NbF1=%d NbF2=%d i=%d\n",NbF1,NbF2,i); - - cbpwrite=cbp+3; + cbpwrite=cbp+2; cbpwrite->length=i*4; - //ctl->sample[NoSample].PWMF1=i*4;//((PWMFrequency-FixedNumberStepForGpio)/4)*4; - //ctl->sample[NoSample].PWMF2=0; + // ****************************** AMPLITUDE PROCESSING ********************************************** - // ---------------- MAKE AN AVERAGE AMPLITUDE --------------------- - /* - if(First==1) - { - memset(HistoryAmplitude,0,STEP_AVERAGE_AMPLITUDE*sizeof(uint32_t)); - First=0; - } - memcpy(HistoryAmplitude,HistoryAmplitude+1,(STEP_AVERAGE_AMPLITUDE-1)*sizeof(uint32_t)); - HistoryAmplitude[STEP_AVERAGE_AMPLITUDE-1]=Amplitude; - static uint32_t AverageAmplitude; - static int StepAmplitude; - AverageAmplitude=0; - - for(StepAmplitude=0;StepAmplitude32767)?32767:Amplitude; int IntAmplitude=(Amplitude*7.0)/32767.0; // Convert to 8 amplitude step @@ -784,103 +617,136 @@ inline void FrequencyAmplitudeToRegister(double TuneFrequency,uint32_t Amplitude static int OldIntAmplitude=0; - /*if(((OldIntAmplitude!=0)&&(IntAmplitude==0))||((OldIntAmplitude==0)&&(IntAmplitude!=0))) - { - cbpwrite=cbp+1; - cbpwrite->next=mem_virt_to_phys(cbpwrite + 1); //Set Patern - } - else - { - cbpwrite=cbp+1; - cbpwrite->next=mem_virt_to_phys(cbpwrite + 2); //DOn't set patern - } - OldIntAmplitude=IntAmplitude; */ - - //IntAmplitude=IntAmplitude+3; // Make a little more gain if amplitude not 0 + if(IntAmplitude>7) IntAmplitude=7; - //printf("%d\n",IntAmplitude); - ctl->sample[NoSample].Amplitude1=0x5a000000 + (IntAmplitude&0x7) + (1<<4) + (0<<3); // Set output power for I/Q GPIO18/GPIO19;//TEST +1 + + ctl->sample[NoSample].Amplitude1=0x5a000000 + (IntAmplitude&0x7) + (1<<4) + (0<<3); - static uint32_t phys_pwm_fifo_addr = 0x7e20c000 + 0x18;//PWM Fifo - static uint32_t dummy_gpio = 0x7e20b000; - static uint32_t phys_gpio_pads_addr =0x7e10002c; - /* - cbpwrite=cbp+1; - cbpwrite->dst= phys_gpio_pads_addr; - cbpwrite=cbp+2; - cbpwrite->dst=phys_pwm_fifo_addr; - */ - - // ****************************** WAIT PROCESSING ********************************************** - - if(WaitNanoSecond!=0) //ModeRF - { - /*if(WaitNanoSecondnext=mem_virt_to_phys(cbp + 6); - printf("WaitNano Mini %d\n",WaitNanoSecond); - } - else - cbp->next=mem_virt_to_phys(cbp + 1); - */ - static uint32_t NbRepeat; - static int Relicat=0; - NbRepeat=WaitNanoSecond/DelayFromSampleRate; // 1GHZ/(SAMPLERATE*NbStepPCM) - Relicat+=(WaitNanoSecond%DelayFromSampleRate); - if(Relicat>=DelayFromSampleRate) - { - Relicat=Relicat-DelayFromSampleRate; - NbRepeat+=1; - } - if((DelayFromSampleRate+Relicat)<0) - { - Relicat=DelayFromSampleRate+Relicat; - NbRepeat-=1; - } - - //static uint32_t NbRepeat=1; - - // cbpwrite=cbp+5; // Set a repeat to wait PCM - // cbpwrite->length=4*(NbRepeat); //-> OK - - //printf("NbRepeat %d Relicat %d WaitNanoSecond%d DelayFromSampleRate%d\n",NbRepeat,Relicat,WaitNanoSecond,DelayFromSampleRate); - } } -// Call ntp_adjtime() to obtain the latest calibration coefficient. -void update_ppm(double ppm) + + + + +int GetDMADelay(int Step) +{ + + //Calibrate DMA Rate + // ===================================================== + static volatile uint32_t cur_cb,last_cb; + struct timespec gettime_now; + int32_t start_time,time_difference; + int last_sample; + int this_sample; + int free_slots; + + dma_cb_t *cbp = ctl->cb; + cur_cb = (uint32_t)virtbase; // DMA AT 1st CBS + dma_reg[DMA_CONBLK_AD+DMA_CHANNEL*0x40]=mem_virt_to_phys((void*)cur_cb); + usleep(100); + int samplecnt; + for (samplecnt = 0; samplecnt < NUM_SAMPLES ; samplecnt++) + { + + cbp+=2; + cbp->length = (uint32_t)4L*Step; + cbp++; + } + + dma_reg[DMA_CS+DMA_CHANNEL*0x40] = DMA_CS_PRIORITY(7) | DMA_CS_PANIC_PRIORITY(7) | DMA_CS_DISDEBUG |DMA_CS_ACTIVE; // START DMA : go, mid priority, wait for outstanding writes :7 Seems Max Priority + usleep(5000); //Wait to be sure DMA is running stable + int i; + int SumDelay=0; + for(i=0;i<10;i++) + { + + + + last_cb = mem_phys_to_virt((uint32_t)(dma_reg[DMA_CONBLK_AD+DMA_CHANNEL*0x40])); + last_sample = (last_cb - (uint32_t)virtbase) / (sizeof(dma_cb_t) * CBS_SIZE_BY_SAMPLE); + + clock_gettime(CLOCK_REALTIME, &gettime_now); + start_time = gettime_now.tv_nsec; + + // ONE SAMPLE SHOULD BE MINIMUM AROUND Time = NBStep * 157 ns + 1360 ns +1360*4 ns = 6us and MAX 200*157+1360*5 = 35us + // Sleep at 80% de DELAY*NUM_SAMPLE + // BY removing 2 CBP = 300ns gain + do + { + usleep(10); + cur_cb = mem_phys_to_virt((uint32_t)(dma_reg[DMA_CONBLK_AD+DMA_CHANNEL*0x40])); + this_sample = (cur_cb - (uint32_t)virtbase) / (sizeof(dma_cb_t) * CBS_SIZE_BY_SAMPLE); + free_slots = this_sample - last_sample; + if (free_slots < 0) // WARNING : ORIGINAL CODE WAS < strictly + free_slots += NUM_SAMPLES; + clock_gettime(CLOCK_REALTIME, &gettime_now); + + } + while(free_slots<=NUM_SAMPLES*0.6); + + + + time_difference = gettime_now.tv_nsec - start_time; + if(time_difference<0) time_difference+=1E9; + + //printf("Delay = %d\n",time_difference/free_slots); + + SumDelay+=time_difference/free_slots; + } + + //STop DMA + dma_reg[DMA_CS+DMA_CHANNEL*0x40] |= DMA_CS_ABORT;//BCM2708_DMA_INT | BCM2708_DMA_END; + udelay(100); + dma_reg[DMA_CS+DMA_CHANNEL*0x40]&= ~DMA_CS_ACTIVE; + dma_reg[DMA_CS+DMA_CHANNEL*0x40] |= DMA_CS_RESET; //BCM2708_DMA_ABORT|BCM2708_DMA_RESET; + udelay(100); + + return SumDelay/10; +} + +int CalibrateSystem(int *ppm,int *BaseDelayDMA,int *StepDelayDMA) { struct timex ntx; int status; - double ppm_new; + //Calibrate Clock system (surely depends also on PLL PPM + // ===================================================== ntx.modes = 0; /* only read */ - status = ntp_adjtime(&ntx); + status = ntp_adjtime(&ntx); + double clockppm; - if (status != TIME_OK) { - //cerr << "Error: clock not synchronized" << endl; - //return; - } + if (status != TIME_OK) + { + printf("Error: NTP\n"); + return 0; + } + clockppm = (double)ntx.freq/(double)(1 << 16); + if(abs(clockppm)<200) + *ppm=clockppm; + //printf("Clock PPM = %f\n",ppm); + int i; + int BaseDelay=0; + BaseDelay=GetDMADelay(0); - ppm_new = (double)ntx.freq/(double)(1 << 16); /* frequency scale */ - if (abs(ppm_new)>200) { - printf( "Warning: absolute ppm value is greater than 200 and is being ignored!\n"); - } else { - if (ppm!=ppm_new) { - printf(" Obtained new ppm value: %f\n",ppm_new); - } - ppm=ppm_new; - } + *BaseDelayDMA=BaseDelay; + *StepDelayDMA=(GetDMADelay(PWM_STEP_MAXI/2)-(*BaseDelayDMA))/(PWM_STEP_MAXI/2); + //for(i=1;i<200;i+=10) + //printf("Step %d =%d\n",i,(GetDMADelay(i)-BaseDelay)/i); + return 1; } -int pitx_init(int SampleRate, double TuningFrequency, int* skipSignals) -{ +int pitx_init(int SampleRate, double TuningFrequency, int* skipSignals,int SetDma) +{ InitGpio(); InitDma(terminate, skipSignals); - + if(SetDma) DMA_CHANNEL=SetDma; SetupGpioClock(SampleRate,TuningFrequency); - +//int FREQ_MINI_TIMING=157; +//int PWMF_MARGIN = 1120; //A Margin for now at 1us with PCM ->OK + + if(CalibrateSystem(&globalppmpll,&PWMF_MARGIN,&FREQ_MINI_TIMING)) + printf("Calibrate : ppm=%d DMA %dns:%dns\n",globalppmpll,FREQ_MINI_TIMING,PWMF_MARGIN); //printf("Timing : 1 cyle=%dns 1sample=%dns\n",NBSAMPLES_PWM_FREQ_MAX*400*3,(int)(1e9/(float)SampleRate)); return 1; } @@ -907,6 +773,8 @@ PROGRAM_VERSION); } /* end function print_usage */ + + double GlobalTuningFrequency; int HarmonicNumber =1; @@ -968,10 +836,10 @@ int main(int argc, char* argv[]) float SetFrequency=1e6;//1MHZ float ppmpll=0.0; char NoUsePwmFrequency=0; - + int SetDma=0; while(1) { - a = getopt(argc, argv, "i:f:m:s:p:hld:w:c:r"); + a = getopt(argc, argv, "i:f:m:s:p:hld:w:c:ra:"); if(a == -1) { @@ -1009,7 +877,7 @@ int main(int argc, char* argv[]) case 'l': // loop mode loop_mode_flag = 1; break; - case 'd': // loop mode + case 'd': // Dma Sample Burst DmaSampleBurstSize = atoi(optarg); NUM_SAMPLES=4*DmaSampleBurstSize; break; @@ -1025,6 +893,15 @@ int main(int argc, char* argv[]) Randomize=1; break; + case 'a': // DMA Channel 1-14 + if((atoi(optarg)>0)&&(atoi(optarg)<15)) + { + SetDma=atoi(optarg); + //DMA_CHANNEL=SetDma; Should be set after initdma + } + else + SetDma=0; + break; case -1: break; case '?': @@ -1063,18 +940,19 @@ int main(int argc, char* argv[]) } resetFile(); - return pitx_run(Mode, SampleRate, SetFrequency, ppmpll, NoUsePwmFrequency, readFile, resetFile, NULL); + return pitx_run(Mode, SampleRate, SetFrequency, ppmpll, NoUsePwmFrequency, readFile, resetFile, NULL,SetDma); } int pitx_run( const char Mode, int SampleRate, const float SetFrequency, - const float ppmpll, + float ppmpll, const char NoUsePwmFrequency, ssize_t (*readWrapper)(void *buffer, size_t count), void (*reset)(void), - int* skipSignals) + int* skipSignals, + int SetDma) { int i; //char pagemap_fn[64]; @@ -1099,7 +977,7 @@ int pitx_run( fprintf(stdout,"rpitx Version %s compiled %s (F5OEO Evariste) running on ",PROGRAM_VERSION,__DATE__); // Init Plls Frequency using ppm (or default) - + if(ppmpll!=0) ppmpll=(float)globalppmpll; // Use calibrate only if not setting by user PllFreq500MHZ=PLL_FREQ_500MHZ; PllFreq500MHZ+=PllFreq500MHZ * (ppmpll / 1000000.0); @@ -1123,7 +1001,7 @@ int pitx_run( if((Mode==MODE_RF)||(Mode==MODE_RFA)) { //TabRfSample=malloc(DmaSampleBurstSize*sizeof(samplerf_t)); - SampleRate=100000L; //NOT USED BUT BY CALCULATING TIMETOSLEEP IN RF MODE + SampleRate=50000L; //NOT USED BUT BY CALCULATING TIMETOSLEEP IN RF MODE } if(Mode==MODE_VFO) SampleRate=50000L; //50000 BY EXPERIMENT @@ -1138,7 +1016,7 @@ int pitx_run( pitx_SetTuneFrequency(SetFrequency*1000.0); - pitx_init(SampleRate, GlobalTuningFrequency, skipSignals); + pitx_init(SampleRate, GlobalTuningFrequency, skipSignals,SetDma); static volatile uint32_t cur_cb,last_cb; @@ -1178,7 +1056,12 @@ int pitx_run( if(Init==0) { - TimeToSleep=(1e6*(NUM_SAMPLES-free_slots*2))/SampleRate; // Time to sleep in us + if((Mode==MODE_RF)||(Mode==MODE_RFA)) + { + TimeToSleep=100; //Max 100KHZ + } + else + TimeToSleep=(1e6*(NUM_SAMPLES-free_slots*2))/SampleRate; // Time to sleep in us //printf("TimeToSleep%d\n",TimeToSleep); } else @@ -1232,7 +1115,8 @@ int pitx_run( //dma_reg[DMA_CS+DMA_CHANNEL_PWMFREQUENCY*0x40] = 0x10880001; //Start Main DMA - dma_reg[DMA_CS+DMA_CHANNEL*0x40] = 0x10FF0001; // go, mid priority, wait for outstanding writes :7 Seems Max Priority + dma_reg[DMA_CS+DMA_CHANNEL*0x40] = DMA_CS_PRIORITY(7) | DMA_CS_PANIC_PRIORITY(7) | DMA_CS_DISDEBUG |DMA_CS_ACTIVE; + Init=0; @@ -1386,7 +1270,7 @@ int pitx_run( { // SHOULD NOT EXEED 200 STEP*500ns; SAMPLERATE SHOULD BE MAX TO HAVE PRECISION FOR PCM // BUT FIFO OF PCM IS 16 : SAMPLERATE MAYBE NOT EXCESS 16*80000 ! CAREFULL BUGS HERE - #define MAX_DELAY_WAIT 25000 + #define MAX_DELAY_WAIT (PWM_STEP_MAXI/2*FREQ_MINI_TIMING-PWMF_MARGIN) static int CompteSample=0; static uint32_t TimeRemaining=0; static samplerf_t SampleRf; diff --git a/src/RpiTx.h b/src/RpiTx.h index 0e1e4f8..c68486f 100644 --- a/src/RpiTx.h +++ b/src/RpiTx.h @@ -2,7 +2,7 @@ #define RPITX_H #include -int pitx_init(int SampleRate, double TuningFrequency, int* skipSignals); +int pitx_init(int SampleRate, double TuningFrequency, int* skipSignals,int SetDma); int pitx_SetTuneFrequencyu(uint32_t Frequency); #define MODE_IQ 0 @@ -21,7 +21,8 @@ int pitx_run( ssize_t (*readWrapper)(void *buffer, size_t count), // Wrapper to reset file for looping void (*reset)(void), - int* skipSignals + int* skipSignals, + int SetDma );