Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // To run:
- // wget -O - http://beta.etherpad.org/p/pihackfm/export/txt 2>/dev/null | gcc -lm -std=c99 -g -xc - && time ./a.out
- // Access from ARM Running Linux
- #define BCM2708_PERI_BASE 0x20000000
- #define GPIO_BASE (BCM2708_PERI_BASE + 0x200000) /* GPIO controller */
- #include <stdio.h>
- #include <string.h>
- #include <stdlib.h>
- #include <dirent.h>
- #include <math.h>
- #include <fcntl.h>
- #include <assert.h>
- #include <sys/mman.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <unistd.h>
- #define PAGE_SIZE (4*1024)
- #define BLOCK_SIZE (4*1024)
- //added by rgrasell@gmail.com
- int freq_const;
- //added by rgrasell@gmail.com
- int mem_fd;
- char *gpio_mem, *gpio_map;
- char *spi0_mem, *spi0_map;
- // I/O access
- volatile unsigned *gpio;
- volatile unsigned *allof7e;
- // 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 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*)((int)allof7e+base-0x7e000000)
- #define SETBIT(base, bit) ACCESS(base) |= 1<<bit
- #define CLRBIT(base, bit) ACCESS(base) &= ~(1<<bit)
- void setup_io();
- #define CM_GP0CTL (0x7e101070)
- #define GPFSEL0 (0x7E200000)
- #define CM_GP0DIV (0x7e101074)
- #define DMABASE (0x7E007000)
- struct GPCTL {
- char SRC : 4;
- char ENAB : 1;
- char KILL : 1;
- char : 1;
- char BUSY : 1;
- char FLIP : 1;
- char MASH : 2;
- unsigned int : 13;
- char PASSWD : 8;
- };
- void setup_fm()
- {
- allof7e = (unsigned *)mmap(
- NULL,
- 0x01000000, //len
- PROT_READ|PROT_WRITE,
- MAP_SHARED,
- mem_fd,
- 0x20000000 //base
- );
- if ((int)allof7e==-1) exit(-1);
- SETBIT(GPFSEL0 , 14);
- CLRBIT(GPFSEL0 , 13);
- CLRBIT(GPFSEL0 , 12);
- struct GPCTL setupword = {6/*SRC*/, 1, 0, 0, 0, 1,0x5a};
- ACCESS(CM_GP0CTL) = *((int*)&setupword);
- }
- /*
- void delay(int i) {
- for(volatile unsigned int j = 1<<i; j; j--);
- }
- */
- void delay( int i)
- {
- for(volatile unsigned int j = 1.25*(1<<i); j; j--);
- }
- //function slightly modified by rgrasell@gmail.com to allow for changing frequencies
- void modulate(int m)
- {
- ACCESS(CM_GP0DIV) = (0x5a << 24) + freq_const + m;
- }
- void playWav(char* filename)
- {
- int fp = open(filename, 'r');
- int sz = lseek(fp, 0L, SEEK_END);
- lseek(fp, 0L, SEEK_SET);
- short* data = (short*)malloc(sz);
- read(fp, data, sz);
- unsigned int rnd=1;
- for (int j=22; j<sz/2; j++){ //while (read(fp, &data, 2)) {
- float dval = (float)(data[j])/65536.0*25.0;
- int intval = (int)(floor(dval));
- float frac = dval - (float)intval;
- unsigned int fracval = (unsigned int)(frac*((float)(1<<16))*((float)(1<<16)));
- for (int i=0; i<270; i++) {
- rnd = (rnd >> 1) ^ (-(rnd & 1u) & 0xD0000001u);
- modulate( intval + (fracval>rnd?1:0));
- }
- //printf("%8f %8x %8f %08x\n", dval, intval, frac, fracval);
- //delay(9);
- }
- }
- //the plan is:
- //use PWM to trigger DMA transfer
- struct CB {
- unsigned int TI;
- unsigned int SOURCE_AD;
- unsigned int DEST_AD;
- unsigned int TXFR_LEN;
- unsigned int STRIDE;
- unsigned int NEXTCONBK;
- };
- struct DMAregs {
- unsigned int CS;
- unsigned int CONBLK_AD;
- unsigned int TI;
- unsigned int SOURCE_AD;
- unsigned int DEST_AD;
- unsigned int TXFR_LEN;
- unsigned int STRIDE;
- unsigned int NEXTCONBK;
- unsigned int DEBUG;
- };
- /*
- //TODO! Make DMA work. We decided that this needs to be a kernel mode driver
- void setupDMA(){
- DMAregs* DMA0 = &(ACCESS(DMABASE ));
- //activate
- DMA0->CS = (1<<20) | (1<<20) | 1
- }
- */
- int main(int argc, char **argv)
- {
- int g,rep;
- // Set up gpi pointer for direct register access
- setup_io();
- // Switch GPIO 7..11 to output mode
- /************************************************************************\
- * You are about to change the GPIO settings of your computer. *
- * Mess this up and it will stop working! *
- * It might be a good idea to 'sync' before running this program *
- * so at least you still have your code changes written to the SD-card! *
- \************************************************************************/
- // Set GPIO pins 7-11 to output
- for (g=7; g<=11; g++) {
- INP_GPIO(g); // must use INP_GPIO before we can use OUT_GPIO
- //OUT_GPIO(g);
- }
- setup_fm();
- modulate(0);
- //if statement modified by rgrasell@gmail.com to check for new argument, and to set freq_const
- if (argc==3){
- float temp = 500.0 / atof(argv[2]);
- temp *= (16*16*16);
- freq_const = (int)temp;
- playWav(argv[1]);
- }
- else
- fprintf(stderr, "Usage: program wavfile.wav frequency \n\nWhere wavfile is 16 bit 44.1kHz Monon and frequency is a floating point number\n");
- return 0;
- //setup_DMA()
- /*
- int lastregs[9*15];
- int inuse[9*15];
- memset(&inuse, 0, 9*15*4);
- for(int i = 0; i < 1000000; i++)
- for (int ch = 0; ch <= 14; ch++)
- for (int reg = 0; reg <= 0x20/4; reg++) {
- int curr = ACCESS((DMABASE + 0x100*ch + reg*4));
- if (lastregs[ch*9+reg] != curr) {
- inuse[ch*9+reg]++;
- lastregs[ch*9+reg] = curr;
- }
- //printf("addr %#010x: %#010x\n",0x100*ch + reg, ACCESS(DMABASE + 0x100*ch + reg));
- }
- for (int ch = 0; ch <= 14; ch++)
- for (int reg = 0; reg <= 0x20/4; reg++)
- printf("addr %#010x inuse: %#010x\n",0x100*ch + reg, inuse[ch*9+reg]);
- */
- printf("addr %#010x: %#010x\n",0x200, ACCESS(DMABASE + 0x200));
- while(!(ACCESS(DMABASE + 0x200) & 0xF << 16));
- printf("addr %#010x: %#010x\n",0x200, ACCESS(DMABASE + 0x200));
- /* printf("start\n");
- // frequency counter on gpio 7
- int oldval=0;
- for (int i=0; i<1000000;) {
- int newval = GPIO_GET & 1<<10;
- if (oldval^newval) {
- oldval=newval;
- i++;
- }
- };
- printf("done\n");
- return 0;
- */
- //Sawtooth wave!
- while(1) {
- for(int i = -40; i <= 40; i++) {
- modulate(i);
- printf("Modulating: %d\n", i);
- delay(25);
- }
- }
- for (rep=0; rep<10; rep++) {
- for (g=7; g<=11; g++) {
- GPIO_SET = 1<<g;
- }
- sleep(1);
- for (g=7; g<=11; g++) {
- GPIO_CLR = 1<<g;
- }
- sleep(1);
- }
- return 0;
- } // main
- //
- // Set up a memory regions to access GPIO
- //
- void setup_io()
- {
- /* open /dev/mem */
- if ((mem_fd = open("/dev/mem", O_RDWR|O_SYNC) ) < 0) {
- printf("can't open /dev/mem \n");
- exit (-1);
- }
- /* mmap GPIO */
- // Allocate MAP block
- if ((gpio_mem = malloc(BLOCK_SIZE + (PAGE_SIZE-1))) == NULL) {
- printf("allocation error \n");
- exit (-1);
- }
- // Make sure pointer is on 4K boundary
- if ((unsigned long)gpio_mem % PAGE_SIZE)
- gpio_mem += PAGE_SIZE - ((unsigned long)gpio_mem % PAGE_SIZE);
- // Now map it
- gpio_map = (unsigned char *)mmap(
- gpio_mem,
- BLOCK_SIZE,
- PROT_READ|PROT_WRITE,
- MAP_SHARED|MAP_FIXED,
- mem_fd,
- GPIO_BASE
- );
- if ((long)gpio_map < 0) {
- printf("mmap error %d\n", (int)gpio_map);
- exit (-1);
- }
- // Always use volatile pointer!
- gpio = (volatile unsigned *)gpio_map;
- } // setup_io
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement