From 31fbc3409cf24e999c568d5361417591339a7cc5 Mon Sep 17 00:00:00 2001 From: James Peroulas Date: Wed, 15 Feb 2017 22:09:21 -0800 Subject: [PATCH] First pass at enabling RPi2/3 operation. --- PiCW.cpp | 156 ++++++++++++++++++------------- mailbox.c | 274 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ mailbox.h | 48 ++++++++++ makefile | 16 +++- 4 files changed, 428 insertions(+), 66 deletions(-) create mode 100644 mailbox.c create mode 100644 mailbox.h diff --git a/PiCW.cpp b/PiCW.cpp index 07a78f1..20208d0 100644 --- a/PiCW.cpp +++ b/PiCW.cpp @@ -50,7 +50,9 @@ #include #include -//using namespace std; +#include "mailbox.h" + +using namespace std; #define ABORT(a) exit(a) // Used for debugging @@ -67,15 +69,17 @@ // compensated for in the main loop. #define F_PWM_CLK_INIT (31156186.6125761) -// WSRP nominal symbol time -//#define WSPR_SYMTIME (8192.0/12000.0) -// How much random frequency offset should be added to WSPR transmissions -// if the --offset option has been turned on. -//#define WSPR_RAND_OFFSET 80 -//#define WSPR15_RAND_OFFSET 8 +// Choose proper base address depending on RPI1/RPI2 setting from makefile. +#ifdef RPI2 +#define BCM2708_PERI_BASE 0x3f000000 +#define MEM_FLAG 0x04 +#pragma message "Raspberry Pi 2/3 detected." +#else +#define BCM2708_PERI_BASE 0x20000000 +#define MEM_FLAG 0x0c +#pragma message "Raspberry Pi 1 detected." +#endif -#define BCM2708_PERI_BASE 0x20000000 -#define GPIO_BASE (BCM2708_PERI_BASE + 0x200000) /* GPIO controller */ #define PAGE_SIZE (4*1024) #define BLOCK_SIZE (4*1024) @@ -85,23 +89,33 @@ volatile unsigned *allof7e = NULL; // GPIO setup macros. Always use INP_GPIO(x) before using OUT_GPIO(x) or SET_GPIO_ALT(x,y) #define INP_GPIO(g) *(gpio+((g)/10)) &= ~(7<<(((g)%10)*3)) -#define OUT_GPIO(g) *(gpio+((g)/10)) |= (1<<(((g)%10)*3)) -#define SET_GPIO_ALT(g,a) *(gpio+(((g)/10))) |= (((a)<=3?(a)+4:(a)==4?3:2)<<(((g)%10)*3)) +//#define OUT_GPIO(g) *(gpio+((g)/10)) |= (1<<(((g)%10)*3)) +//#define SET_GPIO_ALT(g,a) *(gpio+(((g)/10))) |= (((a)<=3?(a)+4:(a)==4?3:2)<<(((g)%10)*3)) -#define GPIO_SET *(gpio+7) // sets bits which are 1 ignores bits which are 0 -#define GPIO_CLR *(gpio+10) // clears bits which are 1 ignores bits which are 0 -#define GPIO_GET *(gpio+13) // sets bits which are 1 ignores bits which are 0 +//#define GPIO_SET *(gpio+7) // sets bits which are 1 ignores bits which are 0 +//#define GPIO_CLR *(gpio+10) // clears bits which are 1 ignores bits which are 0 +//#define GPIO_GET *(gpio+13) // sets bits which are 1 ignores bits which are 0 #define ACCESS(base) *(volatile int*)((long int)allof7e+base-0x7e000000) #define SETBIT(base, bit) ACCESS(base) |= 1<=mbox.pool_size) { + cerr << "Error: unable to allocated more pages!" << endl; + ABORT(-1); + } + unsigned offset = mbox.pool_cnt*4096; + *vAddr = (void*)(((unsigned)mbox.virt_addr) + offset); + *pAddr = (void*)(((unsigned)mbox.bus_addr) + offset); + //printf("getRealMemoryPageFromPool bus_addr=%x virt_addr=%x\n", (unsigned)*pAddr,(unsigned)*vAddr); + mbox.pool_cnt++; +} - munlock(vAddr, 4096); // unlock ram. - - free(vAddr); +void deallocMemPool() +{ + if(mbox.virt_addr) //it will be 0 by default as in .bss + { + unmapmem(mbox.virt_addr, mbox.pool_size*4096); + mem_unlock(mbox.handle, mbox.mem_ref); + mem_free(mbox.handle, mbox.mem_ref); + } } // Transmit tone tone_freq for tsym seconds. @@ -205,22 +235,22 @@ void txSym( // Configure the transmission for this iteration // Set GPIO pin to transmit f0 bufPtr++; - while( ACCESS(DMABASE + 0x04 /* CurBlock*/) == (long int)(instrs[bufPtr].p)) usleep(100); + while( ACCESS(DMA_PHYS_BASE + 0x04 /* CurBlock*/) == (long int)(instrs[bufPtr].p)) usleep(100); ((struct CB*)(instrs[bufPtr].v))->SOURCE_AD = (long int)constPage.p + f0_idx*4; // Wait for n_f0 PWM clocks bufPtr++; - while( ACCESS(DMABASE + 0x04 /* CurBlock*/) == (long int)(instrs[bufPtr].p)) usleep(100); + while( ACCESS(DMA_PHYS_BASE + 0x04 /* CurBlock*/) == (long int)(instrs[bufPtr].p)) usleep(100); ((struct CB*)(instrs[bufPtr].v))->TXFR_LEN = n_f0; // Set GPIO pin to transmit f1 bufPtr++; - while( ACCESS(DMABASE + 0x04 /* CurBlock*/) == (long int)(instrs[bufPtr].p)) usleep(100); + while( ACCESS(DMA_PHYS_BASE + 0x04 /* CurBlock*/) == (long int)(instrs[bufPtr].p)) usleep(100); ((struct CB*)(instrs[bufPtr].v))->SOURCE_AD = (long int)constPage.p + f1_idx*4; // Wait for n_f1 PWM clocks bufPtr=(bufPtr+1) % (1024); - while( ACCESS(DMABASE + 0x04 /* CurBlock*/) == (long int)(instrs[bufPtr].p)) usleep(100); + while( ACCESS(DMA_PHYS_BASE + 0x04 /* CurBlock*/) == (long int)(instrs[bufPtr].p)) usleep(100); ((struct CB*)(instrs[bufPtr].v))->TXFR_LEN = n_f1; // Update counters @@ -231,7 +261,7 @@ void txSym( void unSetupDMA(){ //printf("exiting\n"); - struct DMAregs* DMA0 = (struct DMAregs*)&(ACCESS(DMABASE)); + struct DMAregs* DMA0 = (struct DMAregs*)&(ACCESS(DMA_PHYS_BASE)); DMA0->CS =1<<31; // reset dma controller // Turn off GPIO clock ACCESS(CM_GP0CTL) = @@ -311,7 +341,7 @@ void setupDMA( signal (SIGQUIT, handSig); // Allocate a page of ram for the constants - getRealMemPage(&constPage.v, &constPage.p); + getRealMemPageFromPool(&constPage.v, &constPage.p); // Create 1024 instructions allocating one page at a time. // Even instructions target the GP0 Clock divider @@ -319,7 +349,7 @@ void setupDMA( int instrCnt = 0; while (instrCnt<1024) { // Allocate a page of ram for the instructions - getRealMemPage(&instrPage.v, &instrPage.p); + getRealMemPageFromPool(&instrPage.v, &instrPage.p); // make copy instructions // Only create as many instructions as will fit in the recently @@ -331,7 +361,7 @@ void setupDMA( instrs[instrCnt].v = (void*)((long int)instrPage.v + sizeof(struct CB)*i); instrs[instrCnt].p = (void*)((long int)instrPage.p + sizeof(struct CB)*i); instr0->SOURCE_AD = (unsigned long int)constPage.p+2048; - instr0->DEST_AD = PWMBASE+0x18 /* FIF1 */; + instr0->DEST_AD = PWM_PHYS_BASE+0x18 /* FIF1 */; instr0->TXFR_LEN = 4; instr0->STRIDE = 0; //instr0->NEXTCONBK = (int)instrPage.p + sizeof(struct CB)*(i+1); @@ -355,27 +385,27 @@ void setupDMA( ((struct CB*)(instrs[1023].v))->NEXTCONBK = (long int)instrs[0].p; // set up a clock for the PWM - ACCESS(CLKBASE + 40*4 /*PWMCLK_CNTL*/) = 0x5A000026; // Source=PLLD and disable + ACCESS(CLK_PHYS_BASE + 40*4 /*PWMCLK_CNTL*/) = 0x5A000026; // Source=PLLD and disable usleep(1000); - //ACCESS(CLKBASE + 41*4 /*PWMCLK_DIV*/) = 0x5A002800; - ACCESS(CLKBASE + 41*4 /*PWMCLK_DIV*/) = 0x5A002000; // set PWM div to 2, for 250MHz - ACCESS(CLKBASE + 40*4 /*PWMCLK_CNTL*/) = 0x5A000016; // Source=PLLD and enable + //ACCESS(CLK_PHYS_BASE + 41*4 /*PWMCLK_DIV*/) = 0x5A002800; + ACCESS(CLK_PHYS_BASE + 41*4 /*PWMCLK_DIV*/) = 0x5A002000; // set PWM div to 2, for 250MHz + ACCESS(CLK_PHYS_BASE + 40*4 /*PWMCLK_CNTL*/) = 0x5A000016; // Source=PLLD and enable usleep(1000); // set up pwm - ACCESS(PWMBASE + 0x0 /* CTRL*/) = 0; + ACCESS(PWM_PHYS_BASE + 0x0 /* CTRL*/) = 0; usleep(1000); - ACCESS(PWMBASE + 0x4 /* status*/) = -1; // clear errors + ACCESS(PWM_PHYS_BASE + 0x4 /* status*/) = -1; // clear errors usleep(1000); // Range should default to 32, but it is set at 2048 after reset on my RPi. - ACCESS(PWMBASE + 0x10)=32; - ACCESS(PWMBASE + 0x20)=32; - ACCESS(PWMBASE + 0x0 /* CTRL*/) = -1; //(1<<13 /* Use fifo */) | (1<<10 /* repeat */) | (1<<9 /* serializer */) | (1<<8 /* enable ch */) ; + ACCESS(PWM_PHYS_BASE + 0x10)=32; + ACCESS(PWM_PHYS_BASE + 0x20)=32; + ACCESS(PWM_PHYS_BASE + 0x0 /* CTRL*/) = -1; //(1<<13 /* Use fifo */) | (1<<10 /* repeat */) | (1<<9 /* serializer */) | (1<<8 /* enable ch */) ; usleep(1000); - ACCESS(PWMBASE + 0x8 /* DMAC*/) = (1<<31 /* DMA enable */) | 0x0707; + ACCESS(PWM_PHYS_BASE + 0x8 /* DMAC*/) = (1<<31 /* DMA enable */) | 0x0707; //activate dma - struct DMAregs* DMA0 = (struct DMAregs*)&(ACCESS(DMABASE)); + struct DMAregs* DMA0 = (struct DMAregs*)&(ACCESS(DMA_PHYS_BASE)); DMA0->CS =1<<31; // reset DMA0->CONBLK_AD=0; DMA0->TI=0; @@ -417,7 +447,7 @@ void setup_io( PROT_READ|PROT_WRITE, MAP_SHARED|MAP_FIXED, mem_fd, - GPIO_BASE + GPIO_PHYS_BASE ); if ((long)gpio_map < 0) { @@ -578,7 +608,7 @@ void parse_commandline( std::cout << "Warning: ppm value is being ignored!" << std::endl; ppm=0.0; } - if (isnan(tone_freq)) { + if (std::isnan(tone_freq)) { std::cerr << "Error: must specify TX frequency (try --help)" << std::endl; ABORT(-1); } @@ -1122,9 +1152,9 @@ int main(const int argc, char * const argv[]) { } // Configure GPIO4 - SETBIT(GPFSEL0 , 14); - CLRBIT(GPFSEL0 , 13); - CLRBIT(GPFSEL0 , 12); + SETBIT(GPIO_PHYS_BASE , 14); + CLRBIT(GPIO_PHYS_BASE , 13); + CLRBIT(GPIO_PHYS_BASE , 12); struct PageInfo constPage; struct PageInfo instrPage; struct PageInfo instrs[1024]; diff --git a/mailbox.c b/mailbox.c new file mode 100644 index 0000000..8336eba --- /dev/null +++ b/mailbox.c @@ -0,0 +1,274 @@ +/* +Copyright (c) 2012, Broadcom Europe Ltd. +All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the copyright holder nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mailbox.h" + +#define PAGE_SIZE (4*1024) + +void *mapmem(unsigned base, unsigned size) +{ + int mem_fd; + unsigned offset = base % PAGE_SIZE; + base = base - offset; + /* open /dev/mem */ + if ((mem_fd = open("/dev/mem", O_RDWR|O_SYNC) ) < 0) { + printf("can't open /dev/mem\nThis program should be run as root. Try prefixing command with: sudo\n"); + exit (-1); + } + void *mem = mmap( + 0, + size, + PROT_READ|PROT_WRITE, + MAP_SHARED/*|MAP_FIXED*/, + mem_fd, + base); +#ifdef DEBUG + printf("base=0x%x, mem=%p\n", base, mem); +#endif + if (mem == MAP_FAILED) { + printf("mmap error %d\n", (int)mem); + exit (-1); + } + close(mem_fd); + return (char *)mem + offset; +} + +void *unmapmem(void *addr, unsigned size) +{ + int s = munmap(addr, size); + if (s != 0) { + printf("munmap error %d\n", s); + exit (-1); + } + + return NULL; +} + +/* + * use ioctl to send mbox property message + */ + +static int mbox_property(int file_desc, void *buf) +{ + int ret_val = ioctl(file_desc, IOCTL_MBOX_PROPERTY, buf); + + if (ret_val < 0) { + printf("ioctl_set_msg failed:%d\n", ret_val); + } + +#ifdef DEBUG + unsigned *p = buf; int i; unsigned size = *(unsigned *)buf; + for (i=0; i= 0) { + //printf("Using mbox device " DEVICE_FILE_NAME ".\n"); + return file_desc; + } + + // Try to create one + unlink(LOCAL_DEVICE_FILE_NAME); + if(mknod(LOCAL_DEVICE_FILE_NAME, S_IFCHR|0600, makedev(MAJOR_NUM_A, 0)) >= 0 && + (file_desc = open(LOCAL_DEVICE_FILE_NAME, 0)) >= 0) { + //printf("Using local mbox device file with major %d.\n", MAJOR_NUM_A); + return file_desc; + } + + unlink(LOCAL_DEVICE_FILE_NAME); + if(mknod(LOCAL_DEVICE_FILE_NAME, S_IFCHR|0600, makedev(MAJOR_NUM_B, 0)) >= 0 && + (file_desc = open(LOCAL_DEVICE_FILE_NAME, 0)) >= 0) { + //printf("Using local mbox device file with major %d.\n", MAJOR_NUM_B); + return file_desc; + } + + return -1; +} + +void mbox_close(int file_desc) { + close(file_desc); +} diff --git a/mailbox.h b/mailbox.h new file mode 100644 index 0000000..d1e49f2 --- /dev/null +++ b/mailbox.h @@ -0,0 +1,48 @@ +/* +Copyright (c) 2012, Broadcom Europe Ltd. +All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the copyright holder nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include + +// Newer kernels (>= 4.1) use major 249, older ones major 100. +#define MAJOR_NUM_A 249 +#define MAJOR_NUM_B 100 +#define IOCTL_MBOX_PROPERTY _IOWR(MAJOR_NUM_B, 0, char *) +#define DEVICE_FILE_NAME "/dev/vcio" +#define LOCAL_DEVICE_FILE_NAME "/tmp/mbox" + +int mbox_open(); +void mbox_close(int file_desc); + +unsigned get_version(int file_desc); +unsigned mem_alloc(int file_desc, unsigned size, unsigned align, unsigned flags); +unsigned mem_free(int file_desc, unsigned handle); +unsigned mem_lock(int file_desc, unsigned handle); +unsigned mem_unlock(int file_desc, unsigned handle); +void *mapmem(unsigned base, unsigned size); +void *unmapmem(void *addr, unsigned size); + +unsigned execute_code(int file_desc, unsigned code, unsigned r0, unsigned r1, unsigned r2, unsigned r3, unsigned r4, unsigned r5); +unsigned execute_qpu(int file_desc, unsigned num_qpus, unsigned control, unsigned noflush, unsigned timeout); +unsigned qpu_enable(int file_desc, unsigned enable); diff --git a/makefile b/makefile index 60c6f0f..6e57a74 100644 --- a/makefile +++ b/makefile @@ -1,9 +1,19 @@ prefix=/usr/local +archis = $(if $(findstring $(1),$(shell uname -m)),$(2)) +pi_version_flag = $(if $(call archis,armv7,dummy-text),-DRPI2,-DRPI1) + all: PiCW -PiCW: PiCW.cpp - g++-4.7 -D_GLIBCXX_DEBUG -std=c++11 -Wall -Werror -fmax-errors=5 -lm PiCW.cpp -pthread -oPiCW +mailbox.o: mailbox.c mailbox.h + g++ -c -Wall -lm mailbox.c + +PiCW: PiCW.cpp mailbox.o + g++ -D_GLIBCXX_DEBUG -std=c++11 -Wall -Werror -fmax-errors=5 -lm mailbox.o PiCW.cpp -pthread -oPiCW + +clean: + -rm PiCW + -rm mailbox.o .PHONY: install install: PiCW @@ -11,5 +21,5 @@ install: PiCW .PHONY: uninstall uninstall: - rm -f $(prefix)/bin/PiCW + -rm -f $(prefix)/bin/PiCW