/** * Map all devices into userspace memory. * * @param ws2811 ws2811 instance pointer. * * @returns 0 on success, -1 otherwise. */ static int map_registers(ws2811_t *ws2811) { ws2811_device_t *device = ws2811->device; uint32_t dma_addr = dmanum_to_phys(ws2811->dmanum); uint32_t base = board_info_peripheral_base_addr(); if (!dma_addr) { return -1; } device->dma = mapmem(dma_addr, sizeof(dma_t)); if (!device->dma) { return -1; } device->pwm = mapmem(PWM_OFFSET + base, sizeof(pwm_t)); if (!device->pwm) { return -1; } device->gpio = mapmem(GPIO_OFFSET + base, sizeof(gpio_t)); if (!device->gpio) { return -1; } device->cm_pwm = mapmem(CM_PWM_OFFSET + base, sizeof(cm_pwm_t)); if (!device->cm_pwm) { return -1; } return 0; }
void dispmanxtest() { DISPMANX_DISPLAY_HANDLE_T display; int ret; DISPMANX_MODEINFO_T displayinfo; DISPMANX_RESOURCE_HANDLE_T res; int width = 1024; int height = 576; uint32_t vc_image_ptr; DISPMANX_UPDATE_HANDLE_T update; VC_RECT_T dst_rect,src_rect; DISPMANX_ELEMENT_HANDLE_T element; bcm_host_init(); display = vc_dispmanx_display_open(0); ret = vc_dispmanx_display_get_info( display, &displayinfo); assert(ret==0); printf("display is %dx%d\n",displayinfo.width,displayinfo.height); res = vc_dispmanx_resource_create(VC_IMAGE_YUV420,width,height,&vc_image_ptr); vc_image_ptr = vc_dispmanx_resource_get_image_handle(res); printf("vc_image_ptr %x\n",vc_image_ptr); assert(res); update = vc_dispmanx_update_start(10); assert(update); vc_dispmanx_rect_set(&src_rect,0,0,width<<16,height<<16); vc_dispmanx_rect_set(&dst_rect,0,(displayinfo.height - height)/2,width-32,height); element = vc_dispmanx_element_add(update,display,2000,&dst_rect,res,&src_rect,DISPMANX_PROTECTION_NONE,NULL,NULL,DISPMANX_NO_ROTATE); ret = vc_dispmanx_update_submit_sync(update); assert(ret==0); uint8_t *rawfb = (uint8_t*)mapmem(vc_image_ptr,0x1000); for (int i=0; i<0x100; i++) { printf("%02x ",rawfb[i]); } printf("\n"); unmapmem(rawfb,0x1000); puts("sleeping"); sleep(10); update = vc_dispmanx_update_start(10); assert(update); ret = vc_dispmanx_element_remove(update,element); assert(ret==0); ret = vc_dispmanx_update_submit_sync(update); assert(ret==0); ret = vc_dispmanx_resource_delete(res); assert(ret==0); ret = vc_dispmanx_display_close(display); assert(ret==0); }
// Execute a nop control list to prove that we have contol. void testControlLists() { // First we allocate and map some videocore memory to build our control list in. // ask the blob to allocate us 256 bytes with 4k alignment, zero it. unsigned int handle = mem_alloc(mbox, 0x100, 0x1000, MEM_FLAG_COHERENT | MEM_FLAG_ZERO); if (!handle) { printf("Error: Unable to allocate memory"); return; } // ask the blob to lock our memory at a single location at give is that address. uint32_t bus_addr = mem_lock(mbox, handle); // map that address into our local address space. uint8_t *list = (uint8_t*) mapmem(bus_addr, 0x100); // Now we construct our control list. // 255 nops, with a halt somewhere in the middle for(int i = 0; i < 0xff; i++) { list[i] = 1; // NOP } list[0xbb] = 0; // Halt. // And then we setup the v3d pipeline to execute the control list. printf("V3D_CT0CS: 0x%08x\n", v3d[V3D_CT0CS]); printf("Start Address: 0x%08x\n", bus_addr); // Current Address = start of our list (bus address) v3d[V3D_CT0CA] = bus_addr; // End Address = just after the end of our list (bus address) // This also starts execution. v3d[V3D_CT0EA] = bus_addr + 0x100; // print status while running printf("V3D_CT0CS: 0x%08x, Address: 0x%08x\n", v3d[V3D_CT0CS], v3d[V3D_CT0CA]); // Wait a second to be sure the contorl list execution has finished while(v3d[V3D_CT0CS] & 0x20); // print the status again. printf("V3D_CT0CS: 0x%08x, Address: 0x%08x\n", v3d[V3D_CT0CS], v3d[V3D_CT0CA]); // Release memory; unmapmem((void *) list, 0x100); mem_unlock(mbox, handle); mem_free(mbox, handle); }
char InitDma(void *FunctionTerminate) { //printf("Init DMA\n"); // Catch all signals possible - it is vital we kill the DMA engine // on process exit! int i; for (i = 0; i < 64; i++) { struct sigaction sa; memset(&sa, 0, sizeof(sa)); sa.sa_handler = FunctionTerminate;//terminate; sigaction(i, &sa, NULL); } NUM_SAMPLES = NUM_SAMPLES_MAX; /* Use the mailbox interface to the VC to ask for physical memory */ /*unlink(MBFILE); if (mknod(MBFILE, S_IFCHR|0600, makedev(100, 0)) < 0) { printf("Failed to create mailbox device\n"); return 0; } */ mbox.handle = mbox_open(); if (mbox.handle < 0) { printf("Failed to open mailbox\n"); return(0); } 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); mbox.bus_addr = mem_lock(mbox.handle, mbox.mem_ref); //printf("bus_addr = %x\n", mbox.bus_addr); mbox.virt_addr = mapmem(BUS_TO_PHYS(mbox.bus_addr), NUM_PAGES* PAGE_SIZE); //printf("virt_addr %p\n", mbox.virt_addr); virtbase = (uint32_t *)mbox.virt_addr; //printf("virtbase %p\n", virtbase); return(1); }
int main(int argc, char **argv) { mbox = mbox_open(); // The blob now has this nice handy call which powers up the v3d pipeline. qpu_enable(mbox, 1); // map v3d's registers into our address space. v3d = (unsigned *) mapmem(0x20c00000, 0x1000); if(v3d[V3D_IDENT0] != 0x02443356) { // Magic number. printf("Error: V3D pipeline isn't powered up and accessable.\n"); exit(-1); } // We now have access to the v3d registers, we should do something. testTriangle(); return 0; }
/* Initialise this library. */ int bcm2835_init(void) { int memfd; int ok; FILE *fp; if (debug) { bcm2835_peripherals = (uint32_t*)BCM2835_PERI_BASE; bcm2835_pads = bcm2835_peripherals + BCM2835_GPIO_PADS/4; bcm2835_clk = bcm2835_peripherals + BCM2835_CLOCK_BASE/4; bcm2835_gpio = bcm2835_peripherals + BCM2835_GPIO_BASE/4; bcm2835_pwm = bcm2835_peripherals + BCM2835_GPIO_PWM/4; bcm2835_spi0 = bcm2835_peripherals + BCM2835_SPI0_BASE/4; bcm2835_bsc0 = bcm2835_peripherals + BCM2835_BSC0_BASE/4; bcm2835_bsc1 = bcm2835_peripherals + BCM2835_BSC1_BASE/4; bcm2835_st = bcm2835_peripherals + BCM2835_ST_BASE/4; return 1; /* Success */ } /* Figure out the base and size of the peripheral address block // using the device-tree. Required for RPi2, optional for RPi 1 */ if ((fp = fopen(BMC2835_RPI2_DT_FILENAME , "rb"))) { unsigned char buf[4]; fseek(fp, BMC2835_RPI2_DT_PERI_BASE_ADDRESS_OFFSET, SEEK_SET); if (fread(buf, 1, sizeof(buf), fp) == sizeof(buf)) bcm2835_peripherals_base = (uint32_t *)(buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3] << 0); fseek(fp, BMC2835_RPI2_DT_PERI_SIZE_OFFSET, SEEK_SET); if (fread(buf, 1, sizeof(buf), fp) == sizeof(buf)) bcm2835_peripherals_size = (buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3] << 0); fclose(fp); } /* else we are prob on RPi 1 with BCM2835, and use the hardwired defaults */ /* Now get ready to map the peripherals block * If we are not root, try for the new /dev/gpiomem interface and accept * the fact that we can only access GPIO * else try for the /dev/mem interface and get access to everything */ memfd = -1; ok = 0; if (geteuid() == 0) { /* Open the master /dev/mem device */ if ((memfd = open("/dev/mem", O_RDWR | O_SYNC) ) < 0) { fprintf(stderr, "bcm2835_init: Unable to open /dev/mem: %s\n", strerror(errno)) ; goto exit; } /* Base of the peripherals block is mapped to VM */ bcm2835_peripherals = mapmem("gpio", bcm2835_peripherals_size, memfd, (uint32_t)bcm2835_peripherals_base); if (bcm2835_peripherals == MAP_FAILED) goto exit; /* Now compute the base addresses of various peripherals, // which are at fixed offsets within the mapped peripherals block // Caution: bcm2835_peripherals is uint32_t*, so divide offsets by 4 */ bcm2835_gpio = bcm2835_peripherals + BCM2835_GPIO_BASE/4; bcm2835_pwm = bcm2835_peripherals + BCM2835_GPIO_PWM/4; bcm2835_clk = bcm2835_peripherals + BCM2835_CLOCK_BASE/4; bcm2835_pads = bcm2835_peripherals + BCM2835_GPIO_PADS/4; bcm2835_spi0 = bcm2835_peripherals + BCM2835_SPI0_BASE/4; bcm2835_bsc0 = bcm2835_peripherals + BCM2835_BSC0_BASE/4; /* I2C */ bcm2835_bsc1 = bcm2835_peripherals + BCM2835_BSC1_BASE/4; /* I2C */ bcm2835_st = bcm2835_peripherals + BCM2835_ST_BASE/4; ok = 1; } else { /* Not root, try /dev/gpiomem */ /* Open the master /dev/mem device */ if ((memfd = open("/dev/gpiomem", O_RDWR | O_SYNC) ) < 0) { fprintf(stderr, "bcm2835_init: Unable to open /dev/gpiomem: %s\n", strerror(errno)) ; goto exit; } /* Base of the peripherals block is mapped to VM */ bcm2835_peripherals_base = 0; bcm2835_peripherals = mapmem("gpio", bcm2835_peripherals_size, memfd, (uint32_t)bcm2835_peripherals_base); if (bcm2835_peripherals == MAP_FAILED) goto exit; bcm2835_gpio = bcm2835_peripherals; ok = 1; } exit: if (memfd >= 0) close(memfd); if (!ok) bcm2835_close(); return ok; }
int main(int argc, char **argv) { parseargs(argc, argv); mbox.handle = mbox_open(); if (mbox.handle < 0) fatal("Failed to open mailbox\n"); unsigned mbox_board_rev = get_board_revision(mbox.handle); printf("MBox Board Revision: %#x\n", mbox_board_rev); get_model(mbox_board_rev); unsigned mbox_dma_channels = get_dma_channels(mbox.handle); printf("DMA Channels Info: %#x, using DMA Channel: %d\n", mbox_dma_channels, DMA_CHAN_NUM); printf("Using hardware: %5s\n", delay_hw == DELAY_VIA_PWM ? "PWM" : "PCM"); printf("Number of channels: %5d\n", (int)num_channels); printf("PWM frequency: %5d Hz\n", 1000000/CYCLE_TIME_US); printf("PWM steps: %5d\n", NUM_SAMPLES); printf("Maximum period (100 %%): %5dus\n", CYCLE_TIME_US); printf("Minimum period (%1.3f%%): %5dus\n", 100.0*SAMPLE_US / CYCLE_TIME_US, SAMPLE_US); printf("DMA Base: %#010x\n", DMA_BASE); setup_sighandlers(); /* map the registers for all DMA Channels */ dma_virt_base = map_peripheral(DMA_BASE, (DMA_CHAN_SIZE * (DMA_CHAN_MAX + 1))); /* set dma_reg to point to the DMA Channel we are using */ dma_reg = dma_virt_base + DMA_CHAN_NUM * (DMA_CHAN_SIZE / sizeof(dma_reg)); pwm_reg = map_peripheral(PWM_BASE, PWM_LEN); pcm_reg = map_peripheral(PCM_BASE, PCM_LEN); clk_reg = map_peripheral(CLK_BASE, CLK_LEN); gpio_reg = map_peripheral(GPIO_BASE, GPIO_LEN); /* Use the mailbox interface to the VC to ask for physical memory */ mbox.mem_ref = mem_alloc(mbox.handle, NUM_PAGES * PAGE_SIZE, PAGE_SIZE, mem_flag); /* TODO: How do we know that succeeded? */ dprintf("mem_ref %u\n", mbox.mem_ref); mbox.bus_addr = mem_lock(mbox.handle, mbox.mem_ref); dprintf("bus_addr = %#x\n", mbox.bus_addr); mbox.virt_addr = mapmem(BUS_TO_PHYS(mbox.bus_addr), NUM_PAGES * PAGE_SIZE); dprintf("virt_addr %p\n", mbox.virt_addr); if ((unsigned long)mbox.virt_addr & (PAGE_SIZE-1)) fatal("pi-blaster: Virtual address is not page aligned\n"); /* we are done with the mbox */ mbox_close(mbox.handle); mbox.handle = -1; //fatal("TempFatal\n"); init_ctrl_data(); init_hardware(); init_channel_pwm(); // Init pin2gpio array with 0/false values to avoid locking all of them as PWM. init_pin2gpio(); // Only calls update_pwm after ctrl_data calculates the pin mask to unlock all pins on start. init_pwm(); unlink(DEVFILE); if (mkfifo(DEVFILE, 0666) < 0) fatal("pi-blaster: Failed to create %s: %m\n", DEVFILE); if (chmod(DEVFILE, 0666) < 0) fatal("pi-blaster: Failed to set permissions on %s: %m\n", DEVFILE); printf("Initialised, "); if (daemonize) { if (daemon(0,1) < 0) fatal("pi-blaster: Failed to daemonize process: %m\n"); else printf("Daemonized, "); } printf("Reading %s.\n", DEVFILE); go_go_go(); return 0; }
/** * Allocate and initialize memory, buffers, pages, PWM, DMA, and GPIO. * * @param ws2811 ws2811 instance pointer. * * @returns 0 on success, -1 otherwise. */ int ws2811_init(ws2811_t *ws2811) { ws2811_device_t *device = NULL; int chan; // Zero mbox; non-zero values indicate action needed on cleanup memset(&mbox, 0, sizeof(mbox)); ws2811->device = malloc(sizeof(*ws2811->device)); if (!ws2811->device) { return -1; } device = ws2811->device; // Determine how much physical memory we need for DMA mbox.size = PWM_BYTE_COUNT(max_channel_led_count(ws2811), ws2811->freq) + + sizeof(dma_cb_t); // Round up to page size multiple mbox.size = (mbox.size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1); // Use the mailbox interface to request memory from the VideoCore // We specifiy (-1) for the handle rather than calling mbox_open() // so multiple users can share the resource. mbox.handle = -1; // mbox_open(); mbox.mem_ref = mem_alloc(mbox.handle, mbox.size, PAGE_SIZE, board_info_sdram_address() == 0x40000000 ? 0xC : 0x4); if (mbox.mem_ref == (unsigned) ~0) { return -1; } mbox.bus_addr = mem_lock(mbox.handle, mbox.mem_ref); if (mbox.bus_addr == (unsigned) ~0) { mem_free(mbox.handle, mbox.size); return -1; } mbox.virt_addr = mapmem(BUS_TO_PHYS(mbox.bus_addr), mbox.size); // Initialize all pointers to NULL. Any non-NULL pointers will be freed on cleanup. device->pwm_raw = NULL; device->dma_cb = NULL; for (chan = 0; chan < RPI_PWM_CHANNELS; chan++) { ws2811->channel[chan].leds = NULL; } // Allocate the LED buffers for (chan = 0; chan < RPI_PWM_CHANNELS; chan++) { ws2811_channel_t *channel = &ws2811->channel[chan]; channel->leds = malloc(sizeof(ws2811_led_t) * channel->count); if (!channel->leds) { goto err; } memset(channel->leds, 0, sizeof(ws2811_led_t) * channel->count); } device->dma_cb = (dma_cb_t *)mbox.virt_addr; device->pwm_raw = (uint8_t *)mbox.virt_addr + sizeof(dma_cb_t); pwm_raw_init(ws2811); memset((dma_cb_t *)device->dma_cb, 0, sizeof(dma_cb_t)); // Cache the DMA control block bus address device->dma_cb_addr = addr_to_bus(device->dma_cb); // Map the physical registers into userspace if (map_registers(ws2811)) { goto err; } // Initialize the GPIO pins if (gpio_init(ws2811)) { unmap_registers(ws2811); goto err; } // Setup the PWM, clocks, and DMA if (setup_pwm(ws2811)) { unmap_registers(ws2811); goto err; } return 0; err: ws2811_cleanup(ws2811); return -1; }
char InitDma(void *FunctionTerminate) { DMA_CHANNEL=4; if (system("rm -f linuxversion.txt") != 0) { fprintf(stderr, "rm failed\n"); } if (system("uname -r >> linuxversion.txt") != 0) { fprintf(stderr, "uname failed\n"); } char *line = NULL; size_t size; // int fLinux=open("Flinuxversion.txt", "r'); FILE * flinux=fopen("linuxversion.txt", "r"); if (getline(&line, &size, flinux) == -1) { printf("Could no get Linux version\n"); } else { if(line[0]=='3') { printf("Wheezy\n"); DMA_CHANNEL=DMA_CHANNEL_WHEEZY; } if(line[0]=='4') { printf("Jessie\n"); DMA_CHANNEL=DMA_CHANNEL_JESSIE; } } //printf("Init DMA\n"); // Catch all signals possible - it is vital we kill the DMA engine // on process exit! int i; for (i = 0; i < 64; i++) { struct sigaction sa; memset(&sa, 0, sizeof(sa)); sa.sa_handler = FunctionTerminate;//terminate; sigaction(i, &sa, NULL); } //NUM_SAMPLES = NUM_SAMPLES_MAX; /* Use the mailbox interface to the VC to ask for physical memory */ /* unlink(MBFILE); if (mknod(MBFILE, S_IFCHR|0600, makedev(100, 0)) < 0) { printf("Failed to create mailbox device\n"); return 0; }*/ mbox.handle = mbox_open(); if (mbox.handle < 0) { printf("Failed to open mailbox\n"); return(0); } 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); mbox.bus_addr = mem_lock(mbox.handle, mbox.mem_ref); //printf("bus_addr = %x\n", mbox.bus_addr); mbox.virt_addr = mapmem(BUS_TO_PHYS(mbox.bus_addr), NUM_PAGES* PAGE_SIZE); //printf("virt_addr %p\n", mbox.virt_addr); virtbase = (uint8_t *)((uint32_t *)mbox.virt_addr); //printf("virtbase %p\n", virtbase); return(1); }
/** * Allocate and initialize memory, buffers, pages, PWM, DMA, and GPIO. * * @param ws2811 ws2811 instance pointer. * * @returns 0 on success, -1 otherwise. */ int ws2811_init(ws2811_t *ws2811) { ws2811_device_t *device; const rpi_hw_t *rpi_hw; int chan; ws2811->rpi_hw = rpi_hw_detect(); if (!ws2811->rpi_hw) { return -1; } rpi_hw = ws2811->rpi_hw; ws2811->device = malloc(sizeof(*ws2811->device)); if (!ws2811->device) { return -1; } device = ws2811->device; // Determine how much physical memory we need for DMA device->mbox.size = PWM_BYTE_COUNT(max_channel_led_count(ws2811), ws2811->freq) + sizeof(dma_cb_t); // Round up to page size multiple device->mbox.size = (device->mbox.size + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1); device->mbox.handle = mbox_open(); if (device->mbox.handle == -1) { return -1; } device->mbox.mem_ref = mem_alloc(device->mbox.handle, device->mbox.size, PAGE_SIZE, rpi_hw->videocore_base == 0x40000000 ? 0xC : 0x4); if (device->mbox.mem_ref == 0) { return -1; } device->mbox.bus_addr = mem_lock(device->mbox.handle, device->mbox.mem_ref); if (device->mbox.bus_addr == (uint32_t) ~0UL) { mem_free(device->mbox.handle, device->mbox.size); return -1; } device->mbox.virt_addr = mapmem(BUS_TO_PHYS(device->mbox.bus_addr), device->mbox.size); // Initialize all pointers to NULL. Any non-NULL pointers will be freed on cleanup. device->pwm_raw = NULL; device->dma_cb = NULL; for (chan = 0; chan < RPI_PWM_CHANNELS; chan++) { ws2811->channel[chan].leds = NULL; } // Allocate the LED buffers for (chan = 0; chan < RPI_PWM_CHANNELS; chan++) { ws2811_channel_t *channel = &ws2811->channel[chan]; channel->leds = malloc(sizeof(ws2811_led_t) * channel->count); if (!channel->leds) { goto err; } memset(channel->leds, 0, sizeof(ws2811_led_t) * channel->count); if (!channel->strip_type) { channel->strip_type=WS2811_STRIP_RGB; } } device->dma_cb = (dma_cb_t *)device->mbox.virt_addr; device->pwm_raw = (uint8_t *)device->mbox.virt_addr + sizeof(dma_cb_t); pwm_raw_init(ws2811); memset((dma_cb_t *)device->dma_cb, 0, sizeof(dma_cb_t)); // Cache the DMA control block bus address device->dma_cb_addr = addr_to_bus(device, device->dma_cb); // Map the physical registers into userspace if (map_registers(ws2811)) { goto err; } // Initialize the GPIO pins if (gpio_init(ws2811)) { unmap_registers(ws2811); goto err; } // Setup the PWM, clocks, and DMA if (setup_pwm(ws2811)) { unmap_registers(ws2811); goto err; } return 0; err: ws2811_cleanup(ws2811); return -1; }
int EtherInit(unsigned char *myadr) { uint32_t pcicsr; uint16_t val; volatile struct ex_upd *upd; #ifndef _STANDALONE uint32_t id; #endif if (pcicheck()) { printf("pcicheck failed\n"); return 0; } #ifndef _STANDALONE pcicfgread(&mytag, 0, &id); #endif for (excard = &excards[0]; excard->did != -1; excard++) { #ifdef _STANDALONE if (pcifinddev(0x10b7, excard->did, &mytag) == 0) goto found; #else if (id == (0x10b7 | (excard->did << 16))) goto found; #endif } printf("no ex\n"); return 0; found: pcicfgread(&mytag, 0x10, &iobase); iobase &= ~3; #ifndef _STANDALONE dmamem = mapmem(DMABASE, DMASIZE); if (!dmamem) return 0; #endif /* enable bus mastering in PCI command register */ if (pcicfgread(&mytag, 0x04, (int *)&pcicsr) || pcicfgwrite(&mytag, 0x04, pcicsr | 4)) { printf("cannot enable DMA\n"); return 0; } ex_reset(); if (excard->mii) ether_medium = ETHERMEDIUM_MII; else { ex_probemedia(); if (ether_medium < 0) return 0; } val = ex_read_eeprom(EEPROM_OEM_ADDR0); myethaddr[0] = val >> 8; myethaddr[1] = val & 0xff; val = ex_read_eeprom(EEPROM_OEM_ADDR1); myethaddr[2] = val >> 8; myethaddr[3] = val & 0xff; val = ex_read_eeprom(EEPROM_OEM_ADDR2); myethaddr[4] = val >> 8; myethaddr[5] = val & 0xff; memcpy(myadr, myethaddr, 6); upd = RECVBUF_VIRT; upd->upd_nextptr = RECVBUF_PHYS; upd->upd_pktstatus = 1500; upd->upd_frags[0].fr_addr = RECVBUF_PHYS + 100; upd->upd_frags[0].fr_len = 1500 | EX_FR_LAST; ex_init(); #if defined(_STANDALONE) && !defined(SUPPORT_NO_NETBSD) strncpy(bi_netif.ifname, "ex", sizeof(bi_netif.ifname)); bi_netif.bus = BI_BUS_PCI; bi_netif.addr.tag = mytag; BI_ADD(&bi_netif, BTINFO_NETIF, sizeof(bi_netif)); #endif return 1; }
int main(int argc, char *argv[]) { int mb = mbox_open(); /* Enable QPU for execution */ int qpu_enabled = !qpu_enable(mb, 1); if (!qpu_enabled) { printf("Unable to enable QPU. Check your firmware is latest."); goto cleanup; } /* Allocate GPU memory and map it into ARM address space */ unsigned size = 4096; unsigned align = 4096; unsigned handle = mem_alloc(mb, size, align, GPU_MEM_FLG); if (!handle) { printf("Failed to allocate GPU memory."); goto cleanup; } void *gpu_pointer = (void *)mem_lock(mb, handle); void *arm_pointer = mapmem((unsigned)gpu_pointer+GPU_MEM_MAP, size); unsigned *p = (unsigned *)arm_pointer; /* +---------------+ <----+ | QPU Code | | | ... | | +---------------+ <--+ | | Uniforms | | | +---------------+ | | | QPU0 Uniform -----+ | | QPU0 Start -------+ | ... | | QPUn Uniform | | QPUn PC -------+ +---------------+ */ /* Copy QPU program into GPU memory */ unsigned *qpu_code = p; memcpy(p, program, sizeof program); p += (sizeof program)/(sizeof program[0]); /* Build Uniforms */ unsigned *qpu_uniform = p; *p++ = 1; /* Build QPU Launch messages */ unsigned *qpu_msg = p; *p++ = as_gpu_address(qpu_uniform); *p++ = as_gpu_address(qpu_code); int i; for (i=0; i<16+1+2; i++) { printf("%08x: %08x\n", gpu_pointer+i*4, ((unsigned *)arm_pointer)[i]); } printf("qpu exec %08x\n", gpu_pointer + ((void *)qpu_msg - arm_pointer)); /* Launch QPU program and block till its done */ unsigned r = execute_qpu(mb, GPU_QPUS, as_gpu_address(qpu_msg), 1, 10000); printf("%d\n", r); cleanup: /* Release GPU memory */ if (arm_pointer) { unmapmem(arm_pointer, size); } if (handle) { mem_unlock(mb, handle); mem_free(mb, handle); } /* Release QPU */ if (qpu_enabled) { qpu_enable(mb, 0); } /* Release mailbox */ mbox_close(mb); }
// Initialise this library. int bcm2835_init(void) { struct timeval tv ; if (debug) { bcm2835_peripherals = (uint32_t*)BCM2835_PERI_BASE; bcm2835_pads = bcm2835_peripherals + BCM2835_GPIO_PADS; bcm2835_clk = bcm2835_peripherals + BCM2835_CLOCK_BASE; bcm2835_gpio = bcm2835_peripherals + BCM2835_GPIO_BASE; bcm2835_pwm = bcm2835_peripherals + BCM2835_GPIO_PWM; bcm2835_spi0 = bcm2835_peripherals + BCM2835_SPI0_BASE; bcm2835_bsc0 = bcm2835_peripherals + BCM2835_BSC0_BASE; bcm2835_bsc1 = bcm2835_peripherals + BCM2835_BSC1_BASE; bcm2835_st = bcm2835_peripherals + BCM2835_ST_BASE; return 1; // Success } // Figure out the base and size of the peripheral address block, based on whether we are on a RPI2 or not, // using the device-tree FILE *fp = fopen(BMC2835_RPI2_DT_FILENAME , "rb"); if (fp) { unsigned char buf[4]; fseek(fp, BMC2835_RPI2_DT_PERI_BASE_ADDRESS_OFFSET, SEEK_SET); if (fread(buf, 1, sizeof(buf), fp) == sizeof(buf)) bcm2835_peripherals_base = (uint32_t *)(buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3] << 0); fseek(fp, BMC2835_RPI2_DT_PERI_SIZE_OFFSET, SEEK_SET); if (fread(buf, 1, sizeof(buf), fp) == sizeof(buf)) bcm2835_peripherals_size = (buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3] << 0); fclose(fp); } // else we are prob on RPi 1 with BCM2835, and use the hardwired defaults // Now get ready to map the peripherals block int memfd = -1; int ok = 0; // Open the master /dev/memory device if ((memfd = open("/dev/mem", O_RDWR | O_SYNC) ) < 0) { fprintf(stderr, "bcm2835_init: Unable to open /dev/mem: %s\n", strerror(errno)) ; goto exit; } // Base of the peripherals block is mapped to VM bcm2835_peripherals = (uint32_t *)mapmem("gpio", bcm2835_peripherals_size, memfd, (uint32_t)bcm2835_peripherals_base); if (bcm2835_peripherals == MAP_FAILED) goto exit; // Now compute the base addresses of various peripherals, which are at fixed offsets within the mapped peripherals block bcm2835_gpio = bcm2835_peripherals + BCM2835_GPIO_BASE; bcm2835_pwm = bcm2835_peripherals + BCM2835_GPIO_PWM; bcm2835_clk = bcm2835_peripherals + BCM2835_CLOCK_BASE; bcm2835_pads = bcm2835_peripherals + BCM2835_GPIO_PADS; bcm2835_spi0 = bcm2835_peripherals + BCM2835_SPI0_BASE; bcm2835_bsc0 = bcm2835_peripherals + BCM2835_BSC0_BASE; // I2C bcm2835_bsc1 = bcm2835_peripherals + BCM2835_BSC1_BASE; // I2C bcm2835_st = bcm2835_peripherals + BCM2835_ST_BASE; ok = 1; exit: if (memfd >= 0) close(memfd); if (!ok) bcm2835_close(); gettimeofday (&tv, NULL) ; epoch = (tv.tv_sec * 1000000 + tv.tv_usec) / 1000 ; return ok; }
// Render a single triangle to memory. void testTriangle() { // Like above, we allocate/lock/map some videocore memory // I'm just shoving everything in a single buffer because I'm lazy // 8Mb, 4k alignment unsigned int handle = mem_alloc(mbox, 0x800000, 0x1000, MEM_FLAG_COHERENT | MEM_FLAG_ZERO); if (!handle) { printf("Error: Unable to allocate memory"); return; } uint32_t bus_addr = mem_lock(mbox, handle); uint8_t *list = (uint8_t*) mapmem(bus_addr, 0x800000); uint8_t *p = list; // Configuration stuff // Tile Binning Configuration. // Tile state data is 48 bytes per tile, I think it can be thrown away // as soon as binning is finished. addbyte(&p, 112); addword(&p, bus_addr + 0x6200); // tile allocation memory address addword(&p, 0x8000); // tile allocation memory size addword(&p, bus_addr + 0x100); // Tile state data address addbyte(&p, 30); // 1920/64 addbyte(&p, 17); // 1080/64 (16.875) addbyte(&p, 0x04); // config // Start tile binning. addbyte(&p, 6); // Primitive type addbyte(&p, 56); addbyte(&p, 0x32); // 16 bit triangle // Clip Window addbyte(&p, 102); addshort(&p, 0); addshort(&p, 0); addshort(&p, 1920); // width addshort(&p, 1080); // height // State addbyte(&p, 96); addbyte(&p, 0x03); // enable both foward and back facing polygons addbyte(&p, 0x00); // depth testing disabled addbyte(&p, 0x02); // enable early depth write // Viewport offset addbyte(&p, 103); addshort(&p, 0); addshort(&p, 0); // The triangle // No Vertex Shader state (takes pre-transformed vertexes, // so we don't have to supply a working coordinate shader to test the binner. addbyte(&p, 65); addword(&p, bus_addr + 0x80); // Shader Record // primitive index list addbyte(&p, 32); addbyte(&p, 0x04); // 8bit index, trinagles addword(&p, 3); // Length addword(&p, bus_addr + 0x70); // address addword(&p, 2); // Maximum index // End of bin list // Flush addbyte(&p, 5); // Nop addbyte(&p, 1); // Halt addbyte(&p, 0); int length = p - list; assert(length < 0x80); // Shader Record p = list + 0x80; addbyte(&p, 0x01); // flags addbyte(&p, 6*4); // stride addbyte(&p, 0xcc); // num uniforms (not used) addbyte(&p, 3); // num varyings addword(&p, bus_addr + 0xfe00); // Fragment shader code addword(&p, bus_addr + 0xff00); // Fragment shader uniforms addword(&p, bus_addr + 0xa0); // Vertex Data // Vertex Data p = list + 0xa0; // Vertex: Top, red addshort(&p, (1920/2) << 4); // X in 12.4 fixed point addshort(&p, 200 << 4); // Y in 12.4 fixed point addfloat(&p, 1.0f); // Z addfloat(&p, 1.0f); // 1/W addfloat(&p, 1.0f); // Varying 0 (Red) addfloat(&p, 0.0f); // Varying 1 (Green) addfloat(&p, 0.0f); // Varying 2 (Blue) // Vertex: bottom left, Green addshort(&p, 560 << 4); // X in 12.4 fixed point addshort(&p, 800 << 4); // Y in 12.4 fixed point addfloat(&p, 1.0f); // Z addfloat(&p, 1.0f); // 1/W addfloat(&p, 0.0f); // Varying 0 (Red) addfloat(&p, 1.0f); // Varying 1 (Green) addfloat(&p, 0.0f); // Varying 2 (Blue) // Vertex: bottom right, Blue addshort(&p, 1360 << 4); // X in 12.4 fixed point addshort(&p, 800 << 4); // Y in 12.4 fixed point addfloat(&p, 1.0f); // Z addfloat(&p, 1.0f); // 1/W addfloat(&p, 0.0f); // Varying 0 (Red) addfloat(&p, 0.0f); // Varying 1 (Green) addfloat(&p, 1.0f); // Varying 2 (Blue) // Vertex list p = list + 0x70; addbyte(&p, 0); // top addbyte(&p, 1); // bottom left addbyte(&p, 2); // bottom right // fragment shader p = list + 0xfe00; addword(&p, 0x958e0dbf); addword(&p, 0xd1724823); /* mov r0, vary; mov r3.8d, 1.0 */ addword(&p, 0x818e7176); addword(&p, 0x40024821); /* fadd r0, r0, r5; mov r1, vary */ addword(&p, 0x818e7376); addword(&p, 0x10024862); /* fadd r1, r1, r5; mov r2, vary */ addword(&p, 0x819e7540); addword(&p, 0x114248a3); /* fadd r2, r2, r5; mov r3.8a, r0 */ addword(&p, 0x809e7009); addword(&p, 0x115049e3); /* nop; mov r3.8b, r1 */ addword(&p, 0x809e7012); addword(&p, 0x116049e3); /* nop; mov r3.8c, r2 */ addword(&p, 0x159e76c0); addword(&p, 0x30020ba7); /* mov tlbc, r3; nop; thrend */ addword(&p, 0x009e7000); addword(&p, 0x100009e7); /* nop; nop; nop */ addword(&p, 0x009e7000); addword(&p, 0x500009e7); /* nop; nop; sbdone */ // Render control list p = list + 0xe200; // Clear color addbyte(&p, 114); addword(&p, 0xff000000); // Opaque Black addword(&p, 0xff000000); // 32 bit clear colours need to be repeated twice addword(&p, 0); addbyte(&p, 0); // Tile Rendering Mode Configuration addbyte(&p, 113); addword(&p, bus_addr + 0x10000); // framebuffer addresss addshort(&p, 1920); // width addshort(&p, 1080); // height addbyte(&p, 0x04); // framebuffer mode (linear rgba8888) addbyte(&p, 0x00); // Do a store of the first tile to force the tile buffer to be cleared // Tile Coordinates addbyte(&p, 115); addbyte(&p, 0); addbyte(&p, 0); // Store Tile Buffer General addbyte(&p, 28); addshort(&p, 0); // Store nothing (just clear) addword(&p, 0); // no address is needed // Link all binned lists together for(int x = 0; x < 30; x++) { for(int y = 0; y < 17; y++) { // Tile Coordinates addbyte(&p, 115); addbyte(&p, x); addbyte(&p, y); // Call Tile sublist addbyte(&p, 17); addword(&p, bus_addr + 0x6200 + (y * 30 + x) * 32); // Last tile needs a special store instruction if(x == 29 && y == 16) { // Store resolved tile color buffer and signal end of frame addbyte(&p, 25); } else { // Store resolved tile color buffer addbyte(&p, 24); } } } int render_length = p - (list + 0xe200); // Run our control list printf("Binner control list constructed\n"); printf("Start Address: 0x%08x, length: 0x%x\n", bus_addr, length); v3d[V3D_CT0CA] = bus_addr; v3d[V3D_CT0EA] = bus_addr + length; printf("V3D_CT0CS: 0x%08x, Address: 0x%08x\n", v3d[V3D_CT0CS], v3d[V3D_CT0CA]); // Wait for control list to execute while(v3d[V3D_CT0CS] & 0x20); printf("V3D_CT0CS: 0x%08x, Address: 0x%08x\n", v3d[V3D_CT0CS], v3d[V3D_CT0CA]); printf("V3D_CT1CS: 0x%08x, Address: 0x%08x\n", v3d[V3D_CT1CS], v3d[V3D_CT1CA]); v3d[V3D_CT1CA] = bus_addr + 0xe200; v3d[V3D_CT1EA] = bus_addr + 0xe200 + render_length; while(v3d[V3D_CT1CS] & 0x20); printf("V3D_CT1CS: 0x%08x, Address: 0x%08x\n", v3d[V3D_CT1CS], v3d[V3D_CT1CA]); v3d[V3D_CT1CS] = 0x20; // just dump the frame to a file FILE *f = fopen("frame.data", "w"); fwrite(list + 0x10000, (1920*1080*4), 1, f); fclose(f); printf("frame buffer memory dumpped to frame.data\n"); // Release resources unmapmem((void *) list, 0x800000); mem_unlock(mbox, handle); mem_free(mbox, handle); }
int main(int argc, char **argv) { int fd; int ac; isdn_ioctl_struct ioctl_s; isdnloop_cdef newcard; isdnloop_sdef startparm; cmd = strrchr(argv[0], '/'); cmd = (cmd == NULL) ? argv[0] : cmd + 1; if (argc > 1) { if (!strcmp(argv[1], "-d")) { strcpy(ioctl_s.drvid, argv[2]); arg_ofs = 3; } else { ioctl_s.drvid[0] = '\0'; arg_ofs = 1; } } else usage(); ac = argc - (arg_ofs - 1); fd = open("/dev/isdnctrl", O_RDWR); if (fd < 0) { perror(ctrldev); exit(-1); } #ifdef __DEBUGVAR__ if (!strcmp(argv[arg_ofs], "dump")) { char *p; ioctl_s.arg = (ulong) & dbg; if ((ioctl(fd, ISDNLOOP_IOCTL_DEBUGVAR + IIOCDRVCTL, &ioctl_s)) < 0) { perror("ioctl DEBUGVAR"); exit(-1); } close(fd); p = mapmem(dbg.dev, sizeof(icn_dev)); dump_dev((icn_dev *) p); p = mapmem(dbg.card, sizeof(icn_card)); dump_card((icn_card *) p); return 0; } #endif if (!strcmp(argv[arg_ofs], "leased")) { if (ac == 3) { ioctl_s.arg = 0; if ((!strcmp(argv[arg_ofs + 1], "on")) || (!strcmp(argv[arg_ofs + 1], "yes"))) ioctl_s.arg = 1; if ((ioctl(fd, ISDNLOOP_IOCTL_LEASEDCFG + IIOCDRVCTL, &ioctl_s)) < 0) { perror("ioctl LEASEDCFG"); exit(-1); } close(fd); return 0; } } if (!strcmp(argv[arg_ofs], "add")) { if (ac >= 2) { ioctl_s.arg = (unsigned long) &newcard; newcard.id1[0] = 0; strncpy(newcard.id1, argv[arg_ofs + 1], sizeof(newcard.id1) - 1); if ((ioctl(fd, ISDNLOOP_IOCTL_ADDCARD + IIOCDRVCTL, &ioctl_s)) < 0) { perror("ioctl ADDCARD"); exit(-1); } close(fd); return 0; } } if (!strcmp(argv[arg_ofs], "start")) { int needed = 99; if (ac > 2) { if (!(strcmp(argv[arg_ofs + 1], "1tr6"))) { needed = 4; startparm.ptype = ISDN_PTYPE_1TR6; } if (!(strcmp(argv[arg_ofs + 1], "dss1"))) { needed = 6; startparm.ptype = ISDN_PTYPE_EURO; } if (ac >= needed) { strcpy(startparm.num[0], argv[arg_ofs + 2]); if (needed > 4) { strcpy(startparm.num[1], argv[arg_ofs + 3]); strcpy(startparm.num[2], argv[arg_ofs + 4]); } ioctl_s.arg = (unsigned long) &startparm; if (ioctl(fd, ISDNLOOP_IOCTL_STARTUP + IIOCDRVCTL, &ioctl_s) < 0) { perror("\nioctl STARTUP"); exit(-1); } printf("done\n"); close(fd); return 0; } } usage(); } usage(); return 0; }
// Initialise this library. int bcm2835_init(void) { if (debug) { bcm2835_pads = (uint32_t*)BCM2835_GPIO_PADS; bcm2835_clk = (uint32_t*)BCM2835_CLOCK_BASE; bcm2835_gpio = (uint32_t*)BCM2835_GPIO_BASE; bcm2835_pwm = (uint32_t*)BCM2835_GPIO_PWM; bcm2835_spi0 = (uint32_t*)BCM2835_SPI0_BASE; bcm2835_bsc0 = (uint32_t*)BCM2835_BSC0_BASE; bcm2835_bsc1 = (uint32_t*)BCM2835_BSC1_BASE; bcm2835_st = (uint32_t*)BCM2835_ST_BASE; return 1; // Success } int memfd = -1; int ok = 0; // Open the master /dev/memory device if ((memfd = open("/dev/mem", O_RDWR | O_SYNC) ) < 0) { fprintf(stderr, "bcm2835_init: Unable to open /dev/mem: %s\n", strerror(errno)) ; goto exit; } // GPIO: bcm2835_gpio = (volatile uint32_t *)mapmem("gpio", BCM2835_BLOCK_SIZE, memfd, BCM2835_GPIO_BASE); if (bcm2835_gpio == MAP_FAILED) goto exit; // PWM bcm2835_pwm = (volatile uint32_t *)mapmem("pwm", BCM2835_BLOCK_SIZE, memfd, BCM2835_GPIO_PWM); if (bcm2835_pwm == MAP_FAILED) goto exit; // Clock control (needed for PWM) bcm2835_clk = (volatile uint32_t *)mapmem("clk", BCM2835_BLOCK_SIZE, memfd, BCM2835_CLOCK_BASE); if (bcm2835_clk == MAP_FAILED) goto exit; bcm2835_pads = (volatile uint32_t *)mapmem("pads", BCM2835_BLOCK_SIZE, memfd, BCM2835_GPIO_PADS); if (bcm2835_pads == MAP_FAILED) goto exit; bcm2835_spi0 = (volatile uint32_t *)mapmem("spi0", BCM2835_BLOCK_SIZE, memfd, BCM2835_SPI0_BASE); if (bcm2835_spi0 == MAP_FAILED) goto exit; // I2C bcm2835_bsc0 = (volatile uint32_t *)mapmem("bsc0", BCM2835_BLOCK_SIZE, memfd, BCM2835_BSC0_BASE); if (bcm2835_bsc0 == MAP_FAILED) goto exit; bcm2835_bsc1 = (volatile uint32_t *)mapmem("bsc1", BCM2835_BLOCK_SIZE, memfd, BCM2835_BSC1_BASE); if (bcm2835_bsc1 == MAP_FAILED) goto exit; // ST bcm2835_st = (volatile uint32_t *)mapmem("st", BCM2835_BLOCK_SIZE, memfd, BCM2835_ST_BASE); if (bcm2835_st == MAP_FAILED) goto exit; ok = 1; exit: if (memfd >= 0) close(memfd); if (!ok) bcm2835_close(); return ok; }
int tx(uint32_t carrier_freq, char *audio_file, uint16_t pi, char *ps, char *rt, float ppm, char *control_pipe) { // Catch all signals possible - it is vital we kill the DMA engine // on process exit! for (int i = 0; i < 64; i++) { struct sigaction sa; memset(&sa, 0, sizeof(sa)); sa.sa_handler = terminate; sigaction(i, &sa, NULL); } dma_reg = map_peripheral(DMA_VIRT_BASE, DMA_LEN); pwm_reg = map_peripheral(PWM_VIRT_BASE, PWM_LEN); clk_reg = map_peripheral(CLK_VIRT_BASE, CLK_LEN); gpio_reg = map_peripheral(GPIO_VIRT_BASE, GPIO_LEN); // Use the mailbox interface to the VC to ask for physical memory. mbox.handle = mbox_open(); if (mbox.handle < 0) fatal("Failed to open mailbox. Check kernel support for vcio / BCM2708 mailbox.\n"); printf("Allocating physical memory: size = %d ", NUM_PAGES * 4096); if(! (mbox.mem_ref = mem_alloc(mbox.handle, NUM_PAGES * 4096, 4096, MEM_FLAG))) { fatal("Could not allocate memory.\n"); } // TODO: How do we know that succeeded? printf("mem_ref = %u ", mbox.mem_ref); if(! (mbox.bus_addr = mem_lock(mbox.handle, mbox.mem_ref))) { fatal("Could not lock memory.\n"); } printf("bus_addr = %x ", mbox.bus_addr); if(! (mbox.virt_addr = mapmem(BUS_TO_PHYS(mbox.bus_addr), NUM_PAGES * 4096))) { fatal("Could not map memory.\n"); } printf("virt_addr = %p\n", mbox.virt_addr); // GPIO4 needs to be ALT FUNC 0 to output the clock gpio_reg[GPFSEL0] = (gpio_reg[GPFSEL0] & ~(7 << 12)) | (4 << 12); // Program GPCLK to use MASH setting 1, so fractional dividers work clk_reg[GPCLK_CNTL] = 0x5A << 24 | 6; udelay(100); clk_reg[GPCLK_CNTL] = 0x5A << 24 | 1 << 9 | 1 << 4 | 6; ctl = (struct control_data_s *) mbox.virt_addr; dma_cb_t *cbp = ctl->cb; uint32_t phys_sample_dst = CM_GP0DIV; uint32_t phys_pwm_fifo_addr = PWM_PHYS_BASE + 0x18; // Calculate the frequency control word // The fractional part is stored in the lower 12 bits uint32_t freq_ctl = ((float)(PLLFREQ / carrier_freq)) * ( 1 << 12 ); for (int i = 0; i < NUM_SAMPLES; i++) { ctl->sample[i] = 0x5a << 24 | freq_ctl; // Silence // Write a frequency sample cbp->info = BCM2708_DMA_NO_WIDE_BURSTS | BCM2708_DMA_WAIT_RESP; cbp->src = mem_virt_to_phys(ctl->sample + i); cbp->dst = phys_sample_dst; cbp->length = 4; cbp->stride = 0; cbp->next = mem_virt_to_phys(cbp + 1); cbp++; // Delay cbp->info = BCM2708_DMA_NO_WIDE_BURSTS | BCM2708_DMA_WAIT_RESP | BCM2708_DMA_D_DREQ | BCM2708_DMA_PER_MAP(5); cbp->src = mem_virt_to_phys(mbox.virt_addr); cbp->dst = phys_pwm_fifo_addr; cbp->length = 4; cbp->stride = 0; cbp->next = mem_virt_to_phys(cbp + 1); cbp++; } cbp--; cbp->next = mem_virt_to_phys(mbox.virt_addr); // Here we define the rate at which we want to update the GPCLK control // register. // // Set the range to 2 bits. PLLD is at 500 MHz, therefore to get 228 kHz // we need a divisor of 500000 / 2 / 228 = 1096.491228 // // This is 1096 + 2012*2^-12 theoretically // // However the fractional part may have to be adjusted to take the actual // frequency of your Pi's oscillator into account. For example on my Pi, // the fractional part should be 1916 instead of 2012 to get exactly // 228 kHz. However RDS decoding is still okay even at 2012. // // So we use the 'ppm' parameter to compensate for the oscillator error float divider = (500000./(2*228*(1.+ppm/1.e6))); uint32_t idivider = (uint32_t) divider; uint32_t fdivider = (uint32_t) ((divider - idivider)*pow(2, 12)); printf("ppm corr is %.4f, divider is %.4f (%d + %d*2^-12) [nominal 1096.4912].\n", ppm, divider, idivider, fdivider); pwm_reg[PWM_CTL] = 0; udelay(10); clk_reg[PWMCLK_CNTL] = 0x5A000006; // Source=PLLD and disable udelay(100); // theorically : 1096 + 2012*2^-12 clk_reg[PWMCLK_DIV] = 0x5A000000 | (idivider<<12) | fdivider; udelay(100); clk_reg[PWMCLK_CNTL] = 0x5A000216; // Source=PLLD and enable + MASH filter 1 udelay(100); pwm_reg[PWM_RNG1] = 2; udelay(10); pwm_reg[PWM_DMAC] = PWMDMAC_ENAB | PWMDMAC_THRSHLD; udelay(10); pwm_reg[PWM_CTL] = PWMCTL_CLRF; udelay(10); pwm_reg[PWM_CTL] = PWMCTL_USEF1 | PWMCTL_PWEN1; udelay(10); // Initialise the DMA dma_reg[DMA_CS] = BCM2708_DMA_RESET; udelay(10); dma_reg[DMA_CS] = BCM2708_DMA_INT | BCM2708_DMA_END; dma_reg[DMA_CONBLK_AD] = mem_virt_to_phys(ctl->cb); dma_reg[DMA_DEBUG] = 7; // clear debug error flags dma_reg[DMA_CS] = 0x10880001; // go, mid priority, wait for outstanding writes uint32_t last_cb = (uint32_t)ctl->cb; // Data structures for baseband data float data[DATA_SIZE]; int data_len = 0; int data_index = 0; // Initialize the baseband generator if(fm_mpx_open(audio_file, DATA_SIZE) < 0) return 1; // Initialize the RDS modulator char myps[9] = {0}; set_rds_pi(pi); set_rds_rt(rt); uint16_t count = 0; uint16_t count2 = 0; int varying_ps = 0; if(ps) { set_rds_ps(ps); printf("PI: %04X, PS: \"%s\".\n", pi, ps); } else { printf("PI: %04X, PS: <Varying>.\n", pi); varying_ps = 1; } printf("RT: \"%s\"\n", rt); // Initialize the control pipe reader if(control_pipe) { if(open_control_pipe(control_pipe) == 0) { printf("Reading control commands on %s.\n", control_pipe); } else { printf("Failed to open control pipe: %s.\n", control_pipe); control_pipe = NULL; } } printf("Starting to transmit on %3.1f MHz.\n", carrier_freq/1e6); for (;;) { // Default (varying) PS if(varying_ps) { if(count == 512) { snprintf(myps, 9, "%08d", count2); set_rds_ps(myps); count2++; } if(count == 1024) { set_rds_ps("RPi-Live"); count = 0; } count++; } if(control_pipe && poll_control_pipe() == CONTROL_PIPE_PS_SET) { varying_ps = 0; } usleep(5000); uint32_t cur_cb = mem_phys_to_virt(dma_reg[DMA_CONBLK_AD]); int last_sample = (last_cb - (uint32_t)mbox.virt_addr) / (sizeof(dma_cb_t) * 2); int this_sample = (cur_cb - (uint32_t)mbox.virt_addr) / (sizeof(dma_cb_t) * 2); int free_slots = this_sample - last_sample; if (free_slots < 0) free_slots += NUM_SAMPLES; while (free_slots >= SUBSIZE) { // get more baseband samples if necessary if(data_len == 0) { if( fm_mpx_get_samples(data) < 0 ) { terminate(0); } data_len = DATA_SIZE; data_index = 0; } float dval = data[data_index] * (DEVIATION / 10.); data_index++; data_len--; int intval = (int)((floor)(dval)); //int frac = (int)((dval - (float)intval) * SUBSIZE); ctl->sample[last_sample++] = (0x5A << 24 | freq_ctl) + intval; //(frac > j ? intval + 1 : intval); if (last_sample == NUM_SAMPLES) last_sample = 0; free_slots -= SUBSIZE; } last_cb = (uint32_t)mbox.virt_addr + last_sample * sizeof(dma_cb_t) * 2; } return 0; }