diff --git a/src/Makefile b/src/Makefile index e894812..211b671 100644 --- a/src/Makefile +++ b/src/Makefile @@ -4,7 +4,7 @@ LDFLAGS = -lm -lrt -lpthread CCP = c++ CC = cc -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 fskburst.h fskburst.cpp ookburst.cpp ookburst.h atv.h atv.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 fskburst.h fskburst.cpp ookburst.cpp ookburst.h atv.h atv.cpp util.h $(CC) $(CFLAGS) -c -o mailbox.o mailbox.c $(CC) $(CFLAGS) -c -o raspberry_pi_revision.o raspberry_pi_revision.c $(CCP) $(CXXFLAGS) -c dsp.cpp iqdmasync.cpp ngfmdmasync.cpp fmdmasync.cpp dma.cpp gpio.cpp serialdmasync.cpp phasedmasync.cpp amdmasync.h amdmasync.cpp fskburst.cpp ookburst.cpp atv.cpp diff --git a/src/amdmasync.cpp b/src/amdmasync.cpp index fc51c53..934d1c9 100644 --- a/src/amdmasync.cpp +++ b/src/amdmasync.cpp @@ -72,39 +72,17 @@ void amdmasync::SetDmaAlgo() //@0 //Set Amplitude by writing to PADS - cbp->info = 0;//BCM2708_DMA_NO_WIDE_BURSTS | BCM2708_DMA_WAIT_RESP ; - cbp->src = mem_virt_to_phys(&usermem[samplecnt*registerbysample]); - cbp->dst = 0x7E000000+(PADS_GPIO_0<<2)+PADS_GPIO; - cbp->length = 4; - cbp->stride = 0; - cbp->next = mem_virt_to_phys(cbp + 1); + SetEasyCB(cbp,samplecnt*registerbysample,dma_pad,1); cbp++; //@1 //Set Amplitude to FSEL for amplitude=0 - cbp->info = 0;//BCM2708_DMA_NO_WIDE_BURSTS | BCM2708_DMA_WAIT_RESP ; - cbp->src = mem_virt_to_phys(&usermem[samplecnt*registerbysample+1]); - cbp->dst = 0x7E000000 + (GPFSEL0<<2)+GENERAL_BASE; - cbp->length = 4; - cbp->stride = 0; - cbp->next = mem_virt_to_phys(cbp + 1); + SetEasyCB(cbp,samplecnt*registerbysample+1,dma_fsel,1); cbp++; // Delay - if(syncwithpwm) - cbp->info = BCM2708_DMA_NO_WIDE_BURSTS | BCM2708_DMA_WAIT_RESP |BCM2708_DMA_D_DREQ | BCM2708_DMA_PER_MAP(DREQ_PWM); - else - 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 - if(syncwithpwm) - cbp->dst = 0x7E000000 + (PWM_FIFO<<2) + PWM_BASE ; - else - 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); + SetEasyCB(cbp,samplecnt*registerbysample,syncwithpwm?dma_pwm:dma_pcm,1); cbp++; } diff --git a/src/atv.cpp b/src/atv.cpp index 74cf13d..98557c8 100644 --- a/src/atv.cpp +++ b/src/atv.cpp @@ -77,6 +77,10 @@ void atv::SetDmaAlgo() uint32_t level1 = mem_virt_to_phys(&usermem[(usermemsize - 2)]); uint32_t level4 = mem_virt_to_phys(&usermem[(usermemsize - 3)]); + uint32_t index_level0 = usermemsize - 1; + uint32_t index_level1 = usermemsize - 2; + uint32_t index_level4 = usermemsize - 3; + int shortsync_0 = 2; int shortsync_1 = 30; @@ -96,272 +100,65 @@ void atv::SetDmaAlgo() //2us 0,30us 1 //@0 //SYNC preegalisation 2us - cbp->info = 0; //BCM2708_DMA_NO_WIDE_BURSTS | BCM2708_DMA_WAIT_RESP ; - cbp->src = level0; //Amp 0 - cbp->dst = 0x7E000000 + (PADS_GPIO_0 << 2) + PADS_GPIO; - cbp->length = 4; - cbp->stride = 0; - cbp->next = mem_virt_to_phys(cbp + 1); - cbp++; - - // Delay - if (syncwithpwm) - cbp->info = BCM2708_DMA_NO_WIDE_BURSTS | BCM2708_DMA_WAIT_RESP | BCM2708_DMA_D_DREQ | BCM2708_DMA_PER_MAP(DREQ_PWM); - else - 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 - if (syncwithpwm) - cbp->dst = 0x7E000000 + (PWM_FIFO << 2) + PWM_BASE; - else - cbp->dst = 0x7E000000 + (PCM_FIFO_A << 2) + PCM_BASE; - cbp->length = 4 * shortsync_0; //2us - cbp->stride = 0; - cbp->next = mem_virt_to_phys(cbp + 1); - cbp++; + SetEasyCB(cbp++, index_level0, dma_pad, 1); + SetEasyCB(cbp++, 0, syncwithpwm ? dma_pwm : dma_pcm, shortsync_0); //SYNC preegalisation 30us - cbp->info = 0; //BCM2708_DMA_NO_WIDE_BURSTS | BCM2708_DMA_WAIT_RESP ; - cbp->src = level1; //Amp 1 - cbp->dst = 0x7E000000 + (PADS_GPIO_0 << 2) + PADS_GPIO; - cbp->length = 4; - cbp->stride = 0; - cbp->next = mem_virt_to_phys(cbp + 1); - cbp++; - - // Delay - if (syncwithpwm) - cbp->info = BCM2708_DMA_NO_WIDE_BURSTS | BCM2708_DMA_WAIT_RESP | BCM2708_DMA_D_DREQ | BCM2708_DMA_PER_MAP(DREQ_PWM); - else - 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 - if (syncwithpwm) - cbp->dst = 0x7E000000 + (PWM_FIFO << 2) + PWM_BASE; - else - cbp->dst = 0x7E000000 + (PCM_FIFO_A << 2) + PCM_BASE; - cbp->length = 4 * shortsync_1; //30us - cbp->stride = 0; - cbp->next = mem_virt_to_phys(cbp + 1); - cbp++; + SetEasyCB(cbp++, index_level1, dma_pad, 1); + SetEasyCB(cbp++, 0, syncwithpwm ? dma_pwm : dma_pcm, shortsync_1); } //SYNC top trame 5*4*2frameCB for (int i = 0; i < 5; i++) { - cbp->info = 0; //BCM2708_DMA_NO_WIDE_BURSTS | BCM2708_DMA_WAIT_RESP ; - cbp->src = level0; //Amp 0 27us - cbp->dst = 0x7E000000 + (PADS_GPIO_0 << 2) + PADS_GPIO; - cbp->length = 4; - cbp->stride = 0; - cbp->next = mem_virt_to_phys(cbp + 1); - cbp++; + SetEasyCB(cbp++, index_level0, dma_pad, 1); + SetEasyCB(cbp++, 0, syncwithpwm ? dma_pwm : dma_pcm, longsync_0); - // Delay - if (syncwithpwm) - cbp->info = BCM2708_DMA_NO_WIDE_BURSTS | BCM2708_DMA_WAIT_RESP | BCM2708_DMA_D_DREQ | BCM2708_DMA_PER_MAP(DREQ_PWM); - else - 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 - if (syncwithpwm) - cbp->dst = 0x7E000000 + (PWM_FIFO << 2) + PWM_BASE; - else - cbp->dst = 0x7E000000 + (PCM_FIFO_A << 2) + PCM_BASE; - cbp->length = 4 * longsync_0; //27us - cbp->stride = 0; - cbp->next = mem_virt_to_phys(cbp + 1); - cbp++; - - cbp->info = 0; //BCM2708_DMA_NO_WIDE_BURSTS | BCM2708_DMA_WAIT_RESP ; - cbp->src = level1; //Amp 1 5us - cbp->dst = 0x7E000000 + (PADS_GPIO_0 << 2) + PADS_GPIO; - cbp->length = 4; - cbp->stride = 0; - cbp->next = mem_virt_to_phys(cbp + 1); - cbp++; - - // Delay - if (syncwithpwm) - cbp->info = BCM2708_DMA_NO_WIDE_BURSTS | BCM2708_DMA_WAIT_RESP | BCM2708_DMA_D_DREQ | BCM2708_DMA_PER_MAP(DREQ_PWM); - else - 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 - if (syncwithpwm) - cbp->dst = 0x7E000000 + (PWM_FIFO << 2) + PWM_BASE; - else - cbp->dst = 0x7E000000 + (PCM_FIFO_A << 2) + PCM_BASE; - cbp->length = 4 * longsync_1; //5us - cbp->stride = 0; - cbp->next = mem_virt_to_phys(cbp + 1); - cbp++; + SetEasyCB(cbp++, index_level1, dma_pad, 1); + SetEasyCB(cbp++, 0, syncwithpwm ? dma_pwm : dma_pcm, longsync_1); } //postegalisation ; copy paste from preegalisation //5*4*2CB - for (int i = 0; i < 5 /*-i*/; i++) + for (int i = 0; i < 5 + frame; i++) { //2us 0,30us 1 //@0 //SYNC preegalisation 2us - cbp->info = 0; //BCM2708_DMA_NO_WIDE_BURSTS | BCM2708_DMA_WAIT_RESP ; - cbp->src = level0; //Amp 0 - cbp->dst = 0x7E000000 + (PADS_GPIO_0 << 2) + PADS_GPIO; - cbp->length = 4; - cbp->stride = 0; - cbp->next = mem_virt_to_phys(cbp + 1); - cbp++; - - // Delay - if (syncwithpwm) - cbp->info = BCM2708_DMA_NO_WIDE_BURSTS | BCM2708_DMA_WAIT_RESP | BCM2708_DMA_D_DREQ | BCM2708_DMA_PER_MAP(DREQ_PWM); - else - 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 - if (syncwithpwm) - cbp->dst = 0x7E000000 + (PWM_FIFO << 2) + PWM_BASE; - else - cbp->dst = 0x7E000000 + (PCM_FIFO_A << 2) + PCM_BASE; - cbp->length = 4 * shortsync_0; //2us - cbp->stride = 0; - cbp->next = mem_virt_to_phys(cbp + 1); - cbp++; + SetEasyCB(cbp++, index_level0, dma_pad, 1); + SetEasyCB(cbp++, 0, syncwithpwm ? dma_pwm : dma_pcm, shortsync_0); //SYNC preegalisation 30us - cbp->info = 0; //BCM2708_DMA_NO_WIDE_BURSTS | BCM2708_DMA_WAIT_RESP ; - cbp->src = level1; //Amp 1 - cbp->dst = 0x7E000000 + (PADS_GPIO_0 << 2) + PADS_GPIO; - cbp->length = 4; - cbp->stride = 0; - cbp->next = mem_virt_to_phys(cbp + 1); - cbp++; - - // Delay - if (syncwithpwm) - cbp->info = BCM2708_DMA_NO_WIDE_BURSTS | BCM2708_DMA_WAIT_RESP | BCM2708_DMA_D_DREQ | BCM2708_DMA_PER_MAP(DREQ_PWM); - else - 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 - if (syncwithpwm) - cbp->dst = 0x7E000000 + (PWM_FIFO << 2) + PWM_BASE; - else - cbp->dst = 0x7E000000 + (PCM_FIFO_A << 2) + PCM_BASE; - cbp->length = 4 * shortsync_1; //30us - cbp->stride = 0; - cbp->next = mem_virt_to_phys(cbp + 1); - cbp++; + SetEasyCB(cbp++, index_level1, dma_pad, 1); + SetEasyCB(cbp++, 0, syncwithpwm ? dma_pwm : dma_pcm, shortsync_1); } + //(304+305)*(4+52*2+2)CB - for (int line = 0; line < 305/* 317 + frame*/; line++) + for (int line = 0; line < 305 /* 317 + frame*/; line++) { //@0 //SYNC 0/ 5us - cbp->info = 0; //BCM2708_DMA_NO_WIDE_BURSTS | BCM2708_DMA_WAIT_RESP ; - cbp->src = level0; //Amp 0 - cbp->dst = 0x7E000000 + (PADS_GPIO_0 << 2) + PADS_GPIO; - cbp->length = 4; - cbp->stride = 0; - cbp->next = mem_virt_to_phys(cbp + 1); - cbp++; + SetEasyCB(cbp++, index_level0, dma_pad, 1); + SetEasyCB(cbp++, 0, syncwithpwm ? dma_pwm : dma_pcm, normalsync_0); - // Delay - if (syncwithpwm) - cbp->info = BCM2708_DMA_NO_WIDE_BURSTS | BCM2708_DMA_WAIT_RESP | BCM2708_DMA_D_DREQ | BCM2708_DMA_PER_MAP(DREQ_PWM); - else - 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 - if (syncwithpwm) - cbp->dst = 0x7E000000 + (PWM_FIFO << 2) + PWM_BASE; - else - cbp->dst = 0x7E000000 + (PCM_FIFO_A << 2) + PCM_BASE; - cbp->length = 4 * normalsync_0; //4us - cbp->stride = 0; - cbp->next = mem_virt_to_phys(cbp + 1); - cbp++; - - //@0 //SYNC 1/ 5us - cbp->info = 0; //BCM2708_DMA_NO_WIDE_BURSTS | BCM2708_DMA_WAIT_RESP ; - cbp->src = level1; //Amp 1 - cbp->dst = 0x7E000000 + (PADS_GPIO_0 << 2) + PADS_GPIO; - cbp->length = 4; - cbp->stride = 0; - cbp->next = mem_virt_to_phys(cbp + 1); - cbp++; - - // Delay - if (syncwithpwm) - cbp->info = BCM2708_DMA_NO_WIDE_BURSTS | BCM2708_DMA_WAIT_RESP | BCM2708_DMA_D_DREQ | BCM2708_DMA_PER_MAP(DREQ_PWM); - else - 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 - if (syncwithpwm) - cbp->dst = 0x7E000000 + (PWM_FIFO << 2) + PWM_BASE; - else - cbp->dst = 0x7E000000 + (PCM_FIFO_A << 2) + PCM_BASE; - cbp->length = 4 * normalsync_1; //5us; - cbp->stride = 0; - cbp->next = mem_virt_to_phys(cbp + 1); - cbp++; + SetEasyCB(cbp++, index_level1, dma_pad, 1); + SetEasyCB(cbp++, 0, syncwithpwm ? dma_pwm : dma_pcm, normalsync_1); for (uint32_t samplecnt = 0; samplecnt < 52; samplecnt++) //52 us { - //sampletab[samplecnt * registerbysample] = (0x5A << 24) + (3 & 0x7) + (1 << 4) + (0 << 3); // Amplitude PAD - //@0 - //DATA IN / 1us - cbp->info = 0; //BCM2708_DMA_NO_WIDE_BURSTS | BCM2708_DMA_WAIT_RESP ; - //if(line<20) cbp->src=level1; - //if((line>=20)&&(line<40)) cbp->src=level4; - //if(line>=20) - cbp->src = mem_virt_to_phys(&usermem[samplecnt + line * 52 + frame * 312 * 52]); - - cbp->dst = 0x7E000000 + (PADS_GPIO_0 << 2) + PADS_GPIO; - cbp->length = 4; - cbp->stride = 0; - cbp->next = mem_virt_to_phys(cbp + 1); - cbp++; - - // Delay - if (syncwithpwm) - cbp->info = BCM2708_DMA_NO_WIDE_BURSTS | BCM2708_DMA_WAIT_RESP | BCM2708_DMA_D_DREQ | BCM2708_DMA_PER_MAP(DREQ_PWM); - else - 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 - if (syncwithpwm) - cbp->dst = 0x7E000000 + (PWM_FIFO << 2) + PWM_BASE; - else - cbp->dst = 0x7E000000 + (PCM_FIFO_A << 2) + PCM_BASE; - cbp->length = 4; //1us - cbp->stride = 0; - cbp->next = mem_virt_to_phys(cbp + 1); - cbp++; + SetEasyCB(cbp++, samplecnt + line * 52 + frame * 312 * 52, dma_pad, 1); + SetEasyCB(cbp++, 0, syncwithpwm ? dma_pwm : dma_pcm, 1); } //FRONT PORSH //SYNC 2us - cbp->info = 0; //BCM2708_DMA_NO_WIDE_BURSTS | BCM2708_DMA_WAIT_RESP ; - cbp->src = level1; //Amp 1 - cbp->dst = 0x7E000000 + (PADS_GPIO_0 << 2) + PADS_GPIO; - cbp->length = 4; - cbp->stride = 0; - cbp->next = mem_virt_to_phys(cbp + 1); - cbp++; - - // Delay - if (syncwithpwm) - cbp->info = BCM2708_DMA_NO_WIDE_BURSTS | BCM2708_DMA_WAIT_RESP | BCM2708_DMA_D_DREQ | BCM2708_DMA_PER_MAP(DREQ_PWM); - else - 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 - if (syncwithpwm) - cbp->dst = 0x7E000000 + (PWM_FIFO << 2) + PWM_BASE; - else - cbp->dst = 0x7E000000 + (PCM_FIFO_A << 2) + PCM_BASE; - cbp->length = 4 * frontsync_1; //2us - cbp->stride = 0; - cbp->next = mem_virt_to_phys(cbp + 1); - cbp++; + SetEasyCB(cbp++, index_level1, dma_pad, 1); + SetEasyCB(cbp++, 0, syncwithpwm ? dma_pwm : dma_pcm, frontsync_1); } } cbp--; cbp->next = mem_virt_to_phys(cbarray); // We loop to the first CB - fprintf(stderr,"Last cbp : %d \n",((unsigned int)(cbp)-(unsigned int)(cbarray))/sizeof(dma_cb_t)); + fprintf(stderr, "Last cbp : %d \n", ((unsigned int)(cbp) - (unsigned int)(cbarray)) / sizeof(dma_cb_t)); } void atv::SetFrame(unsigned char *Luminance, size_t Lines) @@ -370,23 +167,12 @@ void atv::SetFrame(unsigned char *Luminance, size_t Lines) { for (size_t x = 0; x < 52; x++) { - int AmplitudePAD = (Luminance[i * 52 + x]/255.0) * 6.0 + 1; //1 to 7 - // usermem[i* 52 + x] = (0x5A << 24) + (AmplitudePAD & 0x7) + (1 << 4) + (0 << 3); // Amplitude PAD - if (i % 2 == 0) // First field - usermem[i* 52 /2 + x] = (0x5A << 24) + (AmplitudePAD & 0x7) + (1 << 4) + (0 << 3); // Amplitude PAD - else - usermem[(i-1)* 52/2 + x+52*312] = (0x5A << 24) + (AmplitudePAD & 0x7) + (1 << 4) + (0 << 3); // Amplitude PAD - - } - /*for (size_t x = 0; x < 52; x++) - { - int AmplitudePAD = (Luminance[i * 52 + x]/255.0) * 6 + 1; //1 to 7 + int AmplitudePAD = (Luminance[i * 52 + x] / 255.0) * 6.0 + 1; //1 to 7 - if (i % 2 == 0) // First field - usermem[i * 52 / 2 + x] = (0x5A << 24) + (AmplitudePAD & 0x7) + (1 << 4) + (0 << 3); // Amplitude PAD - else //second field - usermem[i * 52 / 2 + Lines / 2 + x] = (0x5A << 24) + (AmplitudePAD & 0x7) + (1 << 4) + (0 << 3); // Amplitude PAD + if (i % 2 == 0) // First field + usermem[i * 52 / 2 + x] = (0x5A << 24) + (AmplitudePAD & 0x7) + (1 << 4) + (0 << 3); // Amplitude PAD + else + usermem[(i - 1) * 52 / 2 + x + 52 * 312] = (0x5A << 24) + (AmplitudePAD & 0x7) + (1 << 4) + (0 << 3); // Amplitude PAD } - */ } } diff --git a/src/dma.cpp b/src/dma.cpp index b9ca0ac..a542735 100644 --- a/src/dma.cpp +++ b/src/dma.cpp @@ -18,6 +18,7 @@ This program is free software: you can redistribute it and/or modify #include "dma.h" #include "stdio.h" +#include "util.h" extern "C" { @@ -166,6 +167,33 @@ bool dma::isunderflow() return ((dma_reg.gpioreg[DMA_CS+channel*0x40]&DMA_CS_INT)>0); } +bool dma::SetCB(dma_cb_t *cbp,uint32_t dma_flag,uint32_t src,uint32_t dst,uint32_t repeat) +{ + cbp->info = dma_flag; + cbp->src = src; + cbp->dst = dst; + cbp->length = 4*repeat; + cbp->stride = 0; + cbp->next = mem_virt_to_phys(cbp + 1); + return true; +} + +bool dma::SetEasyCB(dma_cb_t *cbp,uint32_t index,dma_common_reg dst,uint32_t repeat) +{ + uint32_t flag=BCM2708_DMA_NO_WIDE_BURSTS | BCM2708_DMA_WAIT_RESP; + uint32_t src=mem_virt_to_phys(&usermem[index]); + switch(dst) + { + case dma_pllc_frac :break; + case dma_fsel:break; + case dma_pad:break; + case dma_pwm : flag|=BCM2708_DMA_D_DREQ | BCM2708_DMA_PER_MAP(DREQ_PWM);break; + case dma_pcm : flag|=BCM2708_DMA_D_DREQ | BCM2708_DMA_PER_MAP(DREQ_PCM_TX);break; + } + SetCB(cbp,flag,src,dst,repeat); + return true; +} + //**************************************** BUFFER DMA ******************************************************** bufferdma::bufferdma(int Channel,uint32_t tbuffersize,uint32_t tcbbysample,uint32_t tregisterbysample):dma(Channel,tbuffersize*tcbbysample,tbuffersize*tregisterbysample) { diff --git a/src/dma.h b/src/dma.h index 78b715b..350cbc2 100644 --- a/src/dma.h +++ b/src/dma.h @@ -1,35 +1,35 @@ #ifndef DEF_DMA #define DEF_DMA + #include "stdint.h" #include "gpio.h" - +#include "util.h" // ---- 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. */ +#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. */ -#define BCM2708_DMA_SRC_IGNOR (1<<11) -#define BCM2708_DMA_SRC_INC (1<<8) -#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_SRC_IGNOR (1 << 11) +#define BCM2708_DMA_SRC_INC (1 << 8) +#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_D_DREQ (1 << 6) +#define BCM2708_DMA_PER_MAP(x) ((x) << 16) +#define BCM2708_DMA_END (1 << 1) +#define BCM2708_DMA_RESET (1 << 31) +#define BCM2708_DMA_INT (1 << 2) -#define BCM2708_DMA_D_DREQ (1<<6) -#define BCM2708_DMA_PER_MAP(x) ((x)<<16) -#define BCM2708_DMA_END (1<<1) -#define BCM2708_DMA_RESET (1<<31) -#define BCM2708_DMA_INT (1<<2) - -#define DMA_CS (0x00/4) -#define DMA_CONBLK_AD (0x04/4) -#define DMA_DEBUG (0x20/4) +#define DMA_CS (0x00 / 4) +#define DMA_CONBLK_AD (0x04 / 4) +#define DMA_DEBUG (0x20 / 4) //Page 61 #define DREQ_PCM_TX 2 @@ -41,81 +41,78 @@ #define DREQ_SPI_SLAVE_TX 8 #define DREQ_SPI_SLAVE_RX 9 - class dma { - protected: - struct { - int handle; /* From mbox_open() */ - unsigned mem_ref; /* From mem_alloc() */ - unsigned bus_addr; /* From mem_lock() */ - uint8_t *virt_addr; /* From mapmem() */ - } mbox; + protected: + struct + { + int handle; /* From mbox_open() */ + unsigned mem_ref; /* From mem_alloc() */ + unsigned bus_addr; /* From mem_lock() */ + uint8_t *virt_addr; /* From mapmem() */ + } mbox; - typedef struct { - uint32_t info, src, dst, length, - stride, next, pad[2]; - } dma_cb_t; //8*4=32 bytes + typedef struct + { + uint32_t info, src, dst, length, + stride, next, pad[2]; + } dma_cb_t; //8*4=32 bytes - typedef struct { - uint8_t *virtaddr; - uint32_t physaddr; - } page_map_t; + typedef struct + { + uint8_t *virtaddr; + uint32_t physaddr; + } page_map_t; - page_map_t *page_map; + page_map_t *page_map; - uint8_t *virtbase; - int NumPages=0; + uint8_t *virtbase; + int NumPages = 0; int channel; //DMA Channel dmagpio dma_reg; uint32_t mem_flag; //Cache or not depending on Rpi1 or 2/3 uint32_t dram_phys_base; - - public: - dma_cb_t *cbarray; + public: + dma_cb_t *cbarray; uint32_t cbsize; - uint32_t *usermem; + uint32_t *usermem; uint32_t usermemsize; - bool Started=false; + bool Started = false; - dma(int Channel,uint32_t CBSize,uint32_t UserMemSize); - ~dma(); - uint32_t mem_virt_to_phys(volatile void *virt); - uint32_t mem_phys_to_virt(volatile uint32_t phys); + dma(int Channel, uint32_t CBSize, uint32_t UserMemSize); + ~dma(); + uint32_t mem_virt_to_phys(volatile void *virt); + uint32_t mem_phys_to_virt(volatile uint32_t phys); void GetRpiInfo(); - int start(); - int stop(); + int start(); + int stop(); int getcbposition(); bool isrunning(); bool isunderflow(); - + bool SetCB(dma_cb_t *cbp, uint32_t dma_flag, uint32_t src, uint32_t dst, uint32_t repeat); + bool SetEasyCB(dma_cb_t *cbp, uint32_t index, dma_common_reg dst, uint32_t repeat); }; -#define PHYSICAL_BUS 0x7E000000 - -class bufferdma:public dma +class bufferdma : public dma { - protected: - - + protected: uint32_t current_sample; uint32_t last_sample; uint32_t sample_available; - - public: + + public: uint32_t buffersize; uint32_t cbbysample; uint32_t registerbysample; uint32_t *sampletab; - - public: - bufferdma(int Channel,uint32_t tbuffersize,uint32_t tcbbysample,uint32_t tregisterbysample); + + public: + bufferdma(int Channel, uint32_t tbuffersize, uint32_t tcbbysample, uint32_t tregisterbysample); void SetDmaAlgo(); int GetBufferAvailable(); int GetUserMemIndex(); int PushSample(int Index); - }; #endif diff --git a/src/gpio.h b/src/gpio.h index 7738434..d703a11 100644 --- a/src/gpio.h +++ b/src/gpio.h @@ -3,182 +3,188 @@ #include "stdint.h" #include - +#define PHYSICAL_BUS 0x7E000000 class gpio { - - public: - volatile uint32_t *gpioreg=NULL; + + public: + volatile uint32_t *gpioreg = NULL; uint32_t gpiolen; - gpio(uint32_t base, uint32_t len); - ~gpio(); - uint32_t GetPeripheralBase(); + gpio(uint32_t base, uint32_t len); + ~gpio(); + uint32_t GetPeripheralBase(); }; +#define DMA_BASE (0x00007000) +#define DMA_LEN 0xF00 -#define DMA_BASE (0x00007000 ) -#define DMA_LEN 0xF00 +#define BCM2708_DMA_SRC_IGNOR (1 << 11) +#define BCM2708_DMA_SRC_INC (1 << 8) +#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_SRC_IGNOR (1<<11) -#define BCM2708_DMA_SRC_INC (1<<8) -#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) +#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 BCM2708_DMA_D_DREQ (1<<6) -#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) +#define DMA_CONBLK_AD (0x04 / 4) +#define DMA_DEBUG (0x20 / 4) -#define DMA_CS (0x00/4) -#define DMA_CONBLK_AD (0x04/4) -#define DMA_DEBUG (0x20/4) - -#define DMA_CS_RESET (1<<31) -#define DMA_CS_ABORT (1<<30) -#define DMA_CS_DISDEBUG (1<<29) -#define DMA_CS_WAIT_FOR_OUTSTANDING_WRITES (1<<28) -#define DMA_CS_INT (1<<2) -#define DMA_CS_END (1<<1) -#define DMA_CS_ACTIVE (1<<0) +#define DMA_CS_RESET (1 << 31) +#define DMA_CS_ABORT (1 << 30) +#define DMA_CS_DISDEBUG (1 << 29) +#define DMA_CS_WAIT_FOR_OUTSTANDING_WRITES (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) #define DMA_CS_PANIC_PRIORITY(x) ((x)&0xf << 20) -class dmagpio:public gpio +class dmagpio : public gpio { - - public: - dmagpio(); - - + + public: + dmagpio(); }; //************************************ GENERAL GPIO *************************************** -#define GENERAL_BASE (0x00200000) -#define GENERAL_LEN 0xB4 +#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 (0x98/4) -#define GPPUDCLK1 (0x9C/4) +#define GPFSEL0 (0x00 / 4) +#define GPFSEL1 (0x04 / 4) +#define GPFSEL2 (0x08 / 4) +#define GPPUD (0x94 / 4) +#define GPPUDCLK0 (0x98 / 4) +#define GPPUDCLK1 (0x9C / 4) -enum {fsel_input,fsel_output,fsel_alt5,fsel_alt4,fsel_alt0,fsel_alt1,fsel_alt2,fsel_alt3}; - -class generalgpio:public gpio +enum { - - public: - generalgpio(); + 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(); - int setpulloff(uint32_t gpio); + int setpulloff(uint32_t gpio); }; // Add for PLL frequency CTRL wihout divider // https://github.com/raspberrypi/linux/blob/rpi-4.9.y/drivers/clk/bcm/clk-bcm2835.c // See interesting patch for jitter https://github.com/raspberrypi/linux/commit/76527b4e6a5dbe55e0b2d8ab533c2388b36c86be -#define GENMASK(h, l) (((U32_C(1) << ((h) - (l) + 1)) - 1) << (l)) +#define GENMASK(h, l) (((U32_C(1) << ((h) - (l) + 1)) - 1) << (l)) -#define CLK_BASE (0x00101000) -#define CLK_LEN 0x1660 +#define CLK_BASE (0x00101000) +#define CLK_LEN 0x1660 -#define CORECLK_CNTL (0x08/4) -#define CORECLK_DIV (0x0c/4) -#define GPCLK_CNTL (0x70/4) -#define GPCLK_DIV (0x74/4) -#define GPCLK_CNTL_2 (0x80/4) -#define GPCLK_DIV_2 (0x84/4) -#define EMMCCLK_CNTL (0x1C0/4) -#define EMMCCLK_DIV (0x1C4/4) +#define CORECLK_CNTL (0x08 / 4) +#define CORECLK_DIV (0x0c / 4) +#define GPCLK_CNTL (0x70 / 4) +#define GPCLK_DIV (0x74 / 4) +#define GPCLK_CNTL_2 (0x80 / 4) +#define GPCLK_DIV_2 (0x84 / 4) +#define EMMCCLK_CNTL (0x1C0 / 4) +#define EMMCCLK_DIV (0x1C4 / 4) -#define CM_VPUCTL 0x008 -#define CM_VPUDIV 0x00c -#define CM_SYSCTL 0x010 -#define CM_SYSDIV 0x014 -#define CM_PERIACTL 0x018 -#define CM_PERIADIV 0x01c -#define CM_PERIICTL 0x020 -#define CM_PERIIDIV 0x024 -#define CM_H264CTL 0x028 -#define CM_H264DIV 0x02c -#define CM_ISPCTL 0x030 -#define CM_ISPDIV 0x034 -#define CM_V3DCTL 0x038 -#define CM_V3DDIV 0x03c -#define CM_CAM0CTL 0x040 -#define CM_CAM0DIV 0x044 -#define CM_CAM1CTL 0x048 -#define CM_CAM1DIV 0x04c -#define CM_CCP2CTL 0x050 -#define CM_CCP2DIV 0x054 -#define CM_DSI0ECTL 0x058 -#define CM_DSI0EDIV 0x05c -#define CM_DSI0PCTL 0x060 -#define CM_DSI0PDIV 0x064 -#define CM_DPICTL 0x068 -#define CM_DPIDIV 0x06c -#define CM_GP0CTL 0x070 -#define CM_GP0DIV 0x074 -#define CM_GP1CTL 0x078 -#define CM_GP1DIV 0x07c -#define CM_GP2CTL 0x080 -#define CM_GP2DIV 0x084 -#define CM_HSMCTL 0x088 -#define CM_HSMDIV 0x08c -#define CM_OTPCTL 0x090 -#define CM_OTPDIV 0x094 -#define CM_PCMCTL 0x098 -#define CM_PCMDIV 0x09c -#define CM_PWMCTL 0x0a0 -#define CM_PWMDIV 0x0a4 -#define CM_SLIMCTL 0x0a8 -#define CM_SLIMDIV 0x0ac -#define CM_SMICTL 0x0b0 -#define CM_SMIDIV 0x0b4 +#define CM_VPUCTL 0x008 +#define CM_VPUDIV 0x00c +#define CM_SYSCTL 0x010 +#define CM_SYSDIV 0x014 +#define CM_PERIACTL 0x018 +#define CM_PERIADIV 0x01c +#define CM_PERIICTL 0x020 +#define CM_PERIIDIV 0x024 +#define CM_H264CTL 0x028 +#define CM_H264DIV 0x02c +#define CM_ISPCTL 0x030 +#define CM_ISPDIV 0x034 +#define CM_V3DCTL 0x038 +#define CM_V3DDIV 0x03c +#define CM_CAM0CTL 0x040 +#define CM_CAM0DIV 0x044 +#define CM_CAM1CTL 0x048 +#define CM_CAM1DIV 0x04c +#define CM_CCP2CTL 0x050 +#define CM_CCP2DIV 0x054 +#define CM_DSI0ECTL 0x058 +#define CM_DSI0EDIV 0x05c +#define CM_DSI0PCTL 0x060 +#define CM_DSI0PDIV 0x064 +#define CM_DPICTL 0x068 +#define CM_DPIDIV 0x06c +#define CM_GP0CTL 0x070 +#define CM_GP0DIV 0x074 +#define CM_GP1CTL 0x078 +#define CM_GP1DIV 0x07c +#define CM_GP2CTL 0x080 +#define CM_GP2DIV 0x084 +#define CM_HSMCTL 0x088 +#define CM_HSMDIV 0x08c +#define CM_OTPCTL 0x090 +#define CM_OTPDIV 0x094 +#define CM_PCMCTL 0x098 +#define CM_PCMDIV 0x09c +#define CM_PWMCTL 0x0a0 +#define CM_PWMDIV 0x0a4 +#define CM_SLIMCTL 0x0a8 +#define CM_SLIMDIV 0x0ac +#define CM_SMICTL 0x0b0 +#define CM_SMIDIV 0x0b4 /* no definition for 0x0b8 and 0x0bc */ -#define CM_TCNTCTL 0x0c0 -# define CM_TCNT_SRC1_SHIFT 12 -#define CM_TCNTCNT 0x0c4 -#define CM_TECCTL 0x0c8 -#define CM_TECDIV 0x0cc -#define CM_TD0CTL 0x0d0 -#define CM_TD0DIV 0x0d4 -#define CM_TD1CTL 0x0d8 -#define CM_TD1DIV 0x0dc -#define CM_TSENSCTL 0x0e0 -#define CM_TSENSDIV 0x0e4 -#define CM_TIMERCTL 0x0e8 -#define CM_TIMERDIV 0x0ec -#define CM_UARTCTL 0x0f0 -#define CM_UARTDIV 0x0f4 -#define CM_VECCTL 0x0f8 -#define CM_VECDIV 0x0fc -#define CM_PULSECTL 0x190 -#define CM_PULSEDIV 0x194 -#define CM_SDCCTL 0x1a8 -#define CM_SDCDIV 0x1ac -#define CM_ARMCTL 0x1b0 -#define CM_AVEOCTL 0x1b8 -#define CM_AVEODIV 0x1bc -#define CM_EMMCCTL 0x1c0 -#define CM_EMMCDIV 0x1c4 +#define CM_TCNTCTL 0x0c0 +#define CM_TCNT_SRC1_SHIFT 12 +#define CM_TCNTCNT 0x0c4 +#define CM_TECCTL 0x0c8 +#define CM_TECDIV 0x0cc +#define CM_TD0CTL 0x0d0 +#define CM_TD0DIV 0x0d4 +#define CM_TD1CTL 0x0d8 +#define CM_TD1DIV 0x0dc +#define CM_TSENSCTL 0x0e0 +#define CM_TSENSDIV 0x0e4 +#define CM_TIMERCTL 0x0e8 +#define CM_TIMERDIV 0x0ec +#define CM_UARTCTL 0x0f0 +#define CM_UARTDIV 0x0f4 +#define CM_VECCTL 0x0f8 +#define CM_VECDIV 0x0fc +#define CM_PULSECTL 0x190 +#define CM_PULSEDIV 0x194 +#define CM_SDCCTL 0x1a8 +#define CM_SDCDIV 0x1ac +#define CM_ARMCTL 0x1b0 +#define CM_AVEOCTL 0x1b8 +#define CM_AVEODIV 0x1bc +#define CM_EMMCCTL 0x1c0 +#define CM_EMMCDIV 0x1c4 +#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 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 CM_PLLA (0x104/4) +#define CM_PLLA (0x104 / 4) /* # define CM_PLL_ANARST BIT(8) # define CM_PLLA_HOLDPER BIT(7) @@ -190,210 +196,228 @@ class generalgpio:public gpio # define CM_PLLA_HOLDDSI0 BIT(1) # define CM_PLLA_LOADDSI0 BIT(0) */ -#define CM_PLLC (0x108/4) -#define CM_PLLD (0x10c/4) -#define CM_PLLH (0x110/4) -#define CM_PLLB (0x170/4) +#define CM_PLLC (0x108 / 4) +#define CM_PLLD (0x10c / 4) +#define CM_PLLH (0x110 / 4) +#define CM_PLLB (0x170 / 4) +#define A2W_PLLA_ANA0 (0x1010 / 4) +#define A2W_PLLC_ANA0 (0x1030 / 4) +#define A2W_PLLD_ANA0 (0x1050 / 4) +#define A2W_PLLH_ANA0 (0x1070 / 4) +#define A2W_PLLB_ANA0 (0x10f0 / 4) +#define A2W_PLL_KA_SHIFT 7 +#define A2W_PLL_KI_SHIFT 19 +#define A2W_PLL_KP_SHIFT 15 +#define PLLA_CTRL (0x1100 / 4) +#define PLLA_FRAC (0x1200 / 4) +#define PLLA_DSI0 (0x1300 / 4) +#define PLLA_CORE (0x1400 / 4) +#define PLLA_PER (0x1500 / 4) +#define PLLA_CCP2 (0x1600 / 4) -#define A2W_PLLA_ANA0 (0x1010/4) -#define A2W_PLLC_ANA0 (0x1030/4) -#define A2W_PLLD_ANA0 (0x1050/4) -#define A2W_PLLH_ANA0 (0x1070/4) -#define A2W_PLLB_ANA0 (0x10f0/4) -#define A2W_PLL_KA_SHIFT 7 -#define A2W_PLL_KI_SHIFT 19 -#define A2W_PLL_KP_SHIFT 15 +#define PLLB_CTRL (0x11e0 / 4) +#define PLLB_FRAC (0x12e0 / 4) +#define PLLB_ARM (0x13e0 / 4) +#define PLLB_SP0 (0x14e0 / 4) +#define PLLB_SP1 (0x15e0 / 4) +#define PLLB_SP2 (0x16e0 / 4) -#define PLLA_CTRL (0x1100/4) -#define PLLA_FRAC (0x1200/4) -#define PLLA_DSI0 (0x1300/4) -#define PLLA_CORE (0x1400/4) -#define PLLA_PER (0x1500/4) -#define PLLA_CCP2 (0x1600/4) +#define PLLC_CTRL (0x1120 / 4) +#define PLLC_FRAC (0x1220 / 4) +#define PLLC_CORE2 (0x1320 / 4) +#define PLLC_CORE1 (0x1420 / 4) +#define PLLC_PER (0x1520 / 4) +#define PLLC_CORE0 (0x1620 / 4) -#define PLLB_CTRL (0x11e0/4) -#define PLLB_FRAC (0x12e0/4) -#define PLLB_ARM (0x13e0/4) -#define PLLB_SP0 (0x14e0/4) -#define PLLB_SP1 (0x15e0/4) -#define PLLB_SP2 (0x16e0/4) +#define PLLD_CTRL (0x1140 / 4) +#define PLLD_FRAC (0x1240 / 4) +#define PLLD_DSI0 (0x1340 / 4) +#define PLLD_CORE (0x1440 / 4) +#define PLLD_PER (0x1540 / 4) +#define PLLD_DSI1 (0x1640 / 4) -#define PLLC_CTRL (0x1120/4) -#define PLLC_FRAC (0x1220/4) -#define PLLC_CORE2 (0x1320/4) -#define PLLC_CORE1 (0x1420/4) -#define PLLC_PER (0x1520/4) -#define PLLC_CORE0 (0x1620/4) +#define PLLH_CTRL (0x1160 / 4) +#define PLLH_FRAC (0x1260 / 4) +#define PLLH_AUX (0x1360 / 4) +#define PLLH_RCAL (0x1460 / 4) +#define PLLH_PIX (0x1560 / 4) +#define PLLH_STS (0x1660 / 4) -#define PLLD_CTRL (0x1140/4) -#define PLLD_FRAC (0x1240/4) -#define PLLD_DSI0 (0x1340/4) -#define PLLD_CORE (0x1440/4) -#define PLLD_PER (0x1540/4) -#define PLLD_DSI1 (0x1640/4) - -#define PLLH_CTRL (0x1160/4) -#define PLLH_FRAC (0x1260/4) -#define PLLH_AUX (0x1360/4) -#define PLLH_RCAL (0x1460/4) -#define PLLH_PIX (0x1560/4) -#define PLLH_STS (0x1660/4) - -#define XOSC_CTRL (0x1190/4) +#define XOSC_CTRL (0x1190 / 4) #define XOSC_FREQUENCY 19200000 //Parent PLL -enum {clk_gnd,clk_osc,clk_debug0,clk_debug1,clk_plla,clk_pllc,clk_plld,clk_hdmi}; - -class clkgpio:public gpio +enum { - protected: - int pllnumber; + clk_gnd, + clk_osc, + clk_debug0, + clk_debug1, + clk_plla, + clk_pllc, + clk_plld, + clk_hdmi +}; + +class clkgpio : public gpio +{ + protected: + int pllnumber; int Mash; uint64_t Pllfrequency; - bool ModulateFromMasterPLL=false; - uint64_t CentralFrequency=0; - generalgpio gengpio; - double clk_ppm=0; - public: - int PllFixDivider=8; //Fix divider from the master clock in advanced mode + bool ModulateFromMasterPLL = false; + uint64_t CentralFrequency = 0; + generalgpio gengpio; + double clk_ppm = 0; - clkgpio(); + public: + int PllFixDivider = 8; //Fix divider from the master clock in advanced mode + + clkgpio(); ~clkgpio(); - int SetPllNumber(int PllNo,int MashType); + int SetPllNumber(int PllNo, int MashType); uint64_t GetPllFrequency(int PllNo); void print_clock_tree(void); - int SetFrequency(double Frequency); - int SetClkDivFrac(uint32_t Div,uint32_t Frac); + int SetFrequency(double Frequency); + int SetClkDivFrac(uint32_t Div, uint32_t Frac); void SetPhase(bool inversed); void SetAdvancedPllMode(bool Advanced); - int SetCenterFrequency(uint64_t Frequency,int Bandwidth); + int SetCenterFrequency(uint64_t Frequency, int Bandwidth); double GetFrequencyResolution(); double GetRealFrequency(double Frequency); - int ComputeBestLO(uint64_t Frequency,int Bandwidth); - int SetMasterMultFrac(uint32_t Mult,uint32_t Frac); + int ComputeBestLO(uint64_t Frequency, int Bandwidth); + int SetMasterMultFrac(uint32_t Mult, uint32_t Frac); uint32_t GetMasterFrac(double Frequency); - void enableclk(int gpio); + void enableclk(int gpio); void disableclk(int gpio); void Setppm(double ppm); void SetppmFromNTP(); - void SetPLLMasterLoop(int Ki,int Kp,int Ka); - + void SetPLLMasterLoop(int Ki, int Kp, int Ka); }; - - - //************************************ PWM GPIO *************************************** -#define PWM_BASE (0x0020C000) -#define PWM_LEN 0x28 +#define PWM_BASE (0x0020C000) +#define PWM_LEN 0x28 -#define PWM_CTL (0x00/4) -#define PWM_DMAC (0x08/4) -#define PWM_RNG1 (0x10/4) -#define PWM_RNG2 (0x20/4) -#define PWM_FIFO (0x18/4) +#define PWM_CTL (0x00 / 4) +#define PWM_DMAC (0x08 / 4) +#define PWM_RNG1 (0x10 / 4) +#define PWM_RNG2 (0x20 / 4) +#define PWM_FIFO (0x18 / 4) -#define PWMCLK_CNTL (40) // Clk register -#define PWMCLK_DIV (41) // Clk register +#define PWMCLK_CNTL (40) // Clk register +#define PWMCLK_DIV (41) // Clk register +#define PWMCTL_MSEN2 (1 << 15) +#define PWMCTL_USEF2 (1 << 13) +#define PWMCTL_RPTL2 (1 << 10) +#define PWMCTL_MODE2 (1 << 9) +#define PWMCTL_PWEN2 (1 << 8) -#define PWMCTL_MSEN2 (1<<15) -#define PWMCTL_USEF2 (1<<13) -#define PWMCTL_RPTL2 (1<<10) -#define PWMCTL_MODE2 (1<<9) -#define PWMCTL_PWEN2 (1<<8) - -#define PWMCTL_MSEN1 (1<<7) -#define PWMCTL_CLRF (1<<6) -#define PWMCTL_USEF1 (1<<5) -#define PWMCTL_POLA1 (1<<4) -#define PWMCTL_RPTL1 (1<<2) -#define PWMCTL_MODE1 (1<<1) -#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 +#define PWMCTL_MSEN1 (1 << 7) +#define PWMCTL_CLRF (1 << 6) +#define PWMCTL_USEF1 (1 << 5) +#define PWMCTL_POLA1 (1 << 4) +#define PWMCTL_RPTL1 (1 << 2) +#define PWMCTL_MODE1 (1 << 1) +#define PWMCTL_PWEN1 (1 << 0) +#define PWMDMAC_ENAB (1 << 31) +#define PWMDMAC_THRSHLD ((15 << 8) | (15 << 0)) +enum pwmmode { - protected: + pwm1pin, + pwm2pin, + pwm1pinrepeat +}; + +class pwmgpio : public gpio +{ + protected: clkgpio clk; int pllnumber; int Mash; int Prediv; //Range of PWM uint64_t Pllfrequency; - bool ModulateFromMasterPLL=false; - int ModePwm=pwm1pin; - generalgpio gengpio; - public: - pwmgpio(); + bool ModulateFromMasterPLL = false; + int ModePwm = pwm1pin; + generalgpio gengpio; + + public: + pwmgpio(); ~pwmgpio(); - int SetPllNumber(int PllNo,int MashType); + int SetPllNumber(int PllNo, int MashType); uint64_t GetPllFrequency(int PllNo); int SetFrequency(uint64_t Frequency); - int SetPrediv(int predivisor); + int SetPrediv(int predivisor); void SetMode(int Mode); - void enablepwm(int gpio,int PwmNumber); + void enablepwm(int gpio, int PwmNumber); void disablepwm(int gpio); }; //******************************* PCM GPIO (I2S) *********************************** -#define PCM_BASE (0x00203000) -#define PCM_LEN 0x24 +#define PCM_BASE (0x00203000) +#define PCM_LEN 0x24 -#define PCM_CS_A (0x00/4) -#define PCM_FIFO_A (0x04/4) -#define PCM_MODE_A (0x08/4) -#define PCM_RXC_A (0x0c/4) -#define PCM_TXC_A (0x10/4) -#define PCM_DREQ_A (0x14/4) -#define PCM_INTEN_A (0x18/4) -#define PCM_INT_STC_A (0x1c/4) -#define PCM_GRAY (0x20/4) +#define PCM_CS_A (0x00 / 4) +#define PCM_FIFO_A (0x04 / 4) +#define PCM_MODE_A (0x08 / 4) +#define PCM_RXC_A (0x0c / 4) +#define PCM_TXC_A (0x10 / 4) +#define PCM_DREQ_A (0x14 / 4) +#define PCM_INTEN_A (0x18 / 4) +#define PCM_INT_STC_A (0x1c / 4) +#define PCM_GRAY (0x20 / 4) -#define PCMCLK_CNTL (38) // Clk register -#define PCMCLK_DIV (39) // Clk register +#define PCMCLK_CNTL (38) // Clk register +#define PCMCLK_DIV (39) // Clk register -class pcmgpio:public gpio +class pcmgpio : public gpio { - protected: + protected: clkgpio clk; int pllnumber; int Mash; int Prediv; //Range of PCM - + uint64_t Pllfrequency; int SetPrediv(int predivisor); - - public: - pcmgpio(); + + public: + pcmgpio(); ~pcmgpio(); - int SetPllNumber(int PllNo,int MashType); + int SetPllNumber(int PllNo, int MashType); uint64_t GetPllFrequency(int PllNo); int SetFrequency(uint64_t Frequency); int ComputePrediv(uint64_t Frequency); - }; //******************************* PAD GPIO (Amplitude) *********************************** #define PADS_GPIO (0x00100000) -#define PADS_GPIO_LEN (0x40/4) +#define PADS_GPIO_LEN (0x40 / 4) -#define PADS_GPIO_0 (0x2C/4) -#define PADS_GPIO_1 (0x30/4) -#define PADS_GPIO_2 (0x34/4) +#define PADS_GPIO_0 (0x2C / 4) +#define PADS_GPIO_1 (0x30 / 4) +#define PADS_GPIO_2 (0x34 / 4) -class padgpio:public gpio +class padgpio : public gpio { - - public: - padgpio(); + + public: + padgpio(); ~padgpio(); int setlevel(int level); }; +enum dma_common_reg +{ + dma_pllc_frac = 0x7E000000 + (PLLC_FRAC << 2) + CLK_BASE, + dma_pwm = 0x7E000000 + (PWM_FIFO << 2) + PWM_BASE, + dma_pcm = 0x7E000000 + (PCM_FIFO_A << 2) + PCM_BASE, + dma_fsel = 0x7E000000 + (GPFSEL0 << 2) + GENERAL_BASE, + dma_pad = 0x7E000000 + (PADS_GPIO_0 << 2) + PADS_GPIO +}; + #endif diff --git a/src/iqdmasync.cpp b/src/iqdmasync.cpp index d533344..5304750 100644 --- a/src/iqdmasync.cpp +++ b/src/iqdmasync.cpp @@ -81,55 +81,20 @@ void iqdmasync::SetDmaAlgo() for (uint32_t samplecnt = 0; samplecnt < buffersize; samplecnt++) { - - - //@0 - //Set Amplitude by writing to PADS - cbp->info = BCM2708_DMA_NO_WIDE_BURSTS | BCM2708_DMA_WAIT_RESP ; - cbp->src = mem_virt_to_phys(&usermem[samplecnt*registerbysample+1]); - cbp->dst = 0x7E000000+(PADS_GPIO_0<<2)+PADS_GPIO; - cbp->length = 4; - cbp->stride = 0; - cbp->next = mem_virt_to_phys(cbp + 1); + SetEasyCB(cbp,samplecnt*registerbysample+1,dma_pad,1); cbp++; //@2 Write a frequency sample : Order of DMA CS influence maximum rate : here 0,2,1 is the best : why !!!!!! - - cbp->info = BCM2708_DMA_NO_WIDE_BURSTS | BCM2708_DMA_WAIT_RESP ; - cbp->src = mem_virt_to_phys(&usermem[samplecnt*registerbysample]); - cbp->dst = 0x7E000000 + (PLLC_FRAC<<2) + CLK_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); + SetEasyCB(cbp,samplecnt*registerbysample,dma_pllc_frac,1); cbp++; //@1 //Set Amplitude to FSEL for amplitude=0 - cbp->info = BCM2708_DMA_NO_WIDE_BURSTS | BCM2708_DMA_WAIT_RESP ; - cbp->src = mem_virt_to_phys(&usermem[samplecnt*registerbysample+2]); - cbp->dst = 0x7E000000 + (GPFSEL0<<2)+GENERAL_BASE; - cbp->length = 4; - cbp->stride = 0; - cbp->next = mem_virt_to_phys(cbp + 1); + SetEasyCB(cbp,samplecnt*registerbysample+2,dma_fsel,1); cbp++; - - - - + //@3 Delay - if(syncwithpwm) - cbp->info = BCM2708_DMA_NO_WIDE_BURSTS | BCM2708_DMA_WAIT_RESP |BCM2708_DMA_D_DREQ | BCM2708_DMA_PER_MAP(DREQ_PWM); - else - 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(&usermem[(samplecnt+1)*registerbysample]);//mem_virt_to_phys(cbarray); // Data is not important as we use it only to feed the PWM - if(syncwithpwm) - cbp->dst = 0x7E000000 + (PWM_FIFO<<2) + PWM_BASE ; - else - cbp->dst = 0x7E000000 + (PCM_FIFO_A<<2) + PCM_BASE ; - cbp->length = 4; - cbp->stride = 0; - cbp->next = mem_virt_to_phys(cbp + 1); + SetEasyCB(cbp,samplecnt*registerbysample,syncwithpwm?dma_pwm:dma_pcm,1); //fprintf(stderr,"cbp : sample %x src %x dest %x next %x\n",samplecnt,cbp->src,cbp->dst,cbp->next); cbp++; diff --git a/src/librpitx.h b/src/librpitx.h index 6d6554c..465fcbf 100644 --- a/src/librpitx.h +++ b/src/librpitx.h @@ -26,4 +26,4 @@ This program is free software: you can redistribute it and/or modify #include "fskburst.h" #include "dsp.h" #include "ookburst.h" -#include "atv.h" \ No newline at end of file +#include "atv.h" diff --git a/src/ngfmdmasync.cpp b/src/ngfmdmasync.cpp index cd72709..6c18115 100644 --- a/src/ngfmdmasync.cpp +++ b/src/ngfmdmasync.cpp @@ -74,31 +74,12 @@ void ngfmdmasync::SetDmaAlgo() // Write a frequency sample - - cbp->info = BCM2708_DMA_NO_WIDE_BURSTS | BCM2708_DMA_WAIT_RESP ; - cbp->src = mem_virt_to_phys(&usermem[samplecnt*registerbysample]); - cbp->dst = 0x7E000000 + (PLLC_FRAC<<2) + CLK_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); + SetEasyCB(cbp,samplecnt*registerbysample,dma_pllc_frac,1); cbp++; - + // Delay - if(syncwithpwm) - cbp->info = BCM2708_DMA_NO_WIDE_BURSTS | BCM2708_DMA_WAIT_RESP |BCM2708_DMA_D_DREQ | BCM2708_DMA_PER_MAP(DREQ_PWM); - else - 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 - if(syncwithpwm) - cbp->dst = 0x7E000000 + (PWM_FIFO<<2) + PWM_BASE ; - else - 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); + SetEasyCB(cbp,samplecnt*registerbysample,syncwithpwm?dma_pwm:dma_pcm,1); cbp++; } @@ -119,7 +100,7 @@ void ngfmdmasync::SetFrequencySample(uint32_t Index,float Frequency) void ngfmdmasync::SetFrequencySamples(float *sample,size_t Size) { size_t NbWritten=0; - int OSGranularity=100; + int OSGranularity=200; long int start_time; long time_difference=0; @@ -133,19 +114,20 @@ void ngfmdmasync::SetFrequencySamples(float *sample,size_t Size) int TimeToSleep=1e6*((int)buffersize*3/4-Available)/SampleRate-OSGranularity; // Sleep for theorically fill 3/4 of Fifo if(TimeToSleep>0) { - //fprintf(stderr,"buffer size %d Available %d SampleRate %d Sleep %d\n",buffersize,Available,SampleRate,TimeToSleep); + fprintf(stderr,"buffer size %d Available %d SampleRate %d Sleep %d\n",buffersize,Available,SampleRate,TimeToSleep); usleep(TimeToSleep); } else { - //fprintf(stderr,"No Sleep %d\n",TimeToSleep); + fprintf(stderr,"No Sleep %d\n",TimeToSleep); sched_yield(); } clock_gettime(CLOCK_REALTIME, &gettime_now); time_difference = gettime_now.tv_nsec - start_time; if(time_difference<0) time_difference+=1E9; - //fprintf(stderr,"Measure samplerate=%d\n",(int)((GetBufferAvailable()-Available)*1e9/time_difference)); - Available=GetBufferAvailable(); + int NewAvailable=GetBufferAvailable(); + fprintf(stderr,"Newavailable %d Measure samplerate=%d\n",NewAvailable,(int)((GetBufferAvailable()-Available)*1e9/time_difference)); + Available=NewAvailable; int Index=GetUserMemIndex(); int ToWrite=((int)Size-(int)NbWritten)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(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*(16+1); - cbp->stride = 0; - cbp->next = mem_virt_to_phys(cbp + 1); - cbp++; + SetEasyCB(cbp++,0,dma_pwm,16+1); } else { - 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 PCM - cbp->dst = 0x7E000000 + (PCM_FIFO_A<<2) + PCM_BASE ; - cbp->length = 4*(64+1); - 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++; + SetEasyCB(cbp++,0,dma_pcm,64+1); + } for (uint32_t samplecnt = 0; samplecnt < buffersize-2; samplecnt++) { - - + //Set Amplitude to FSEL for amplitude=0 - cbp->info = BCM2708_DMA_NO_WIDE_BURSTS | BCM2708_DMA_WAIT_RESP ; - cbp->src = mem_virt_to_phys(&usermem[samplecnt*registerbysample]); - cbp->dst = 0x7E000000 + (GPFSEL0<<2)+GENERAL_BASE; - cbp->length = 4; - cbp->stride = 0; - cbp->next = mem_virt_to_phys(cbp + 1); - cbp++; - - + SetEasyCB(cbp++,samplecnt*registerbysample,dma_fsel,1); // Delay - if(syncwithpwm) - cbp->info = BCM2708_DMA_NO_WIDE_BURSTS | BCM2708_DMA_WAIT_RESP |BCM2708_DMA_D_DREQ | BCM2708_DMA_PER_MAP(DREQ_PWM); - else - 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 - if(syncwithpwm) - cbp->dst = 0x7E000000 + (PWM_FIFO<<2) + PWM_BASE ; - else - 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 %d pointer %p src %x dest %x next %x\n",samplecnt,cbp,cbp->src,cbp->dst,cbp->next); - cbp++; + SetEasyCB(cbp++,samplecnt*registerbysample,syncwithpwm?dma_pwm:dma_pcm,1); + } lastcbp=cbp; // Last CBP before stopping : disable output sampletab[buffersize*registerbysample-1]=(Originfsel & ~(7 << 12)) | (0 << 12); //Disable Clk - cbp->info = BCM2708_DMA_NO_WIDE_BURSTS | BCM2708_DMA_WAIT_RESP ; - cbp->src = mem_virt_to_phys(&usermem[(buffersize*registerbysample-1)]); - cbp->dst = 0x7E000000 + (GPFSEL0<<2)+GENERAL_BASE; - cbp->length = 4; - cbp->stride = 0; + SetEasyCB(cbp,buffersize*registerbysample-1,dma_fsel,1); cbp->next = 0; // Stop DMA - - //fprintf(stderr,"Last cbp %p: src %x dest %x next %x\n",cbp,cbp->src,cbp->dst,cbp->next); + } void ookburst::SetSymbols(unsigned char *Symbols,uint32_t Size) { diff --git a/src/serialdmasync.cpp b/src/serialdmasync.cpp index 675fe45..50b580c 100644 --- a/src/serialdmasync.cpp +++ b/src/serialdmasync.cpp @@ -62,17 +62,10 @@ void serialdmasync::SetDmaAlgo() 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++; + SetEasyCB(cbp,samplecnt*registerbysample,dma_pwm,1); + cbp++; - } + } cbp--; cbp->next = mem_virt_to_phys(cbarray); // We loop to the first CB diff --git a/src/util.h b/src/util.h new file mode 100644 index 0000000..55c120c --- /dev/null +++ b/src/util.h @@ -0,0 +1,14 @@ +#ifndef DEF_UTIL +#define DEF_UTIL + +#include +#include + +void dbg_printf(const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + vfprintf(stderr, fmt, args); + va_end(args); +} +#endif \ No newline at end of file