This week only. Pastebin PRO Accounts Christmas Special! Don't miss out!Want more features on Pastebin? Sign Up, it's FREE!
Guest

modified pifm

By: a guest on Dec 10th, 2012  |  syntax: C  |  size: 8.24 KB  |  views: 497  |  expires: Never
download  |  raw  |  embed  |  report abuse  |  print
Text below is selected. Please press Ctrl+C to copy to your clipboard. (⌘+C on Mac)
  1. // To run:
  2. //  wget -O - http://beta.etherpad.org/p/pihackfm/export/txt 2>/dev/null | gcc -lm -std=c99 -g -xc - && time ./a.out
  3. // Access from ARM Running Linux
  4.  
  5. #define BCM2708_PERI_BASE        0x20000000
  6. #define GPIO_BASE                (BCM2708_PERI_BASE + 0x200000) /* GPIO controller */
  7.  
  8.  
  9. #include <stdio.h>
  10. #include <string.h>
  11. #include <stdlib.h>
  12. #include <dirent.h>
  13. #include <math.h>
  14. #include <fcntl.h>
  15. #include <assert.h>
  16. #include <sys/mman.h>
  17. #include <sys/types.h>
  18. #include <sys/stat.h>
  19.  
  20. #include <unistd.h>
  21.  
  22. #define PAGE_SIZE (4*1024)
  23. #define BLOCK_SIZE (4*1024)
  24.  
  25. //added by rgrasell@gmail.com
  26. int freq_const;
  27. //added by rgrasell@gmail.com
  28.  
  29. int  mem_fd;
  30. char *gpio_mem, *gpio_map;
  31. char *spi0_mem, *spi0_map;
  32.  
  33.  
  34. // I/O access
  35. volatile unsigned *gpio;
  36. volatile unsigned *allof7e;
  37.  
  38. // GPIO setup macros. Always use INP_GPIO(x) before using OUT_GPIO(x) or SET_GPIO_ALT(x,y)
  39. #define INP_GPIO(g) *(gpio+((g)/10)) &= ~(7<<(((g)%10)*3))
  40. #define OUT_GPIO(g) *(gpio+((g)/10)) |=  (1<<(((g)%10)*3))
  41. #define SET_GPIO_ALT(g,a) *(gpio+(((g)/10))) |= (((a)<=3?(a)+4:(a)==4?3:2)<<(((g)%10)*3))
  42.  
  43. #define GPIO_SET *(gpio+7)  // sets   bits which are 1 ignores bits which are 0
  44. #define GPIO_CLR *(gpio+10) // clears bits which are 1 ignores bits which are 0
  45. #define GPIO_GET *(gpio+13)  // sets   bits which are 1 ignores bits which are 0
  46.  
  47. #define ACCESS(base) *(volatile int*)((int)allof7e+base-0x7e000000)
  48. #define SETBIT(base, bit) ACCESS(base) |= 1<<bit
  49. #define CLRBIT(base, bit) ACCESS(base) &= ~(1<<bit)
  50.  
  51. void setup_io();
  52.  
  53.  
  54. #define CM_GP0CTL (0x7e101070)
  55. #define GPFSEL0 (0x7E200000)
  56. #define CM_GP0DIV (0x7e101074)
  57. #define DMABASE (0x7E007000)
  58.  
  59. struct GPCTL {
  60.     char SRC         : 4;
  61.     char ENAB        : 1;
  62.     char KILL        : 1;
  63.     char             : 1;
  64.     char BUSY        : 1;
  65.     char FLIP        : 1;
  66.     char MASH        : 2;
  67.     unsigned int     : 13;
  68.     char PASSWD      : 8;
  69. };
  70.  
  71. void setup_fm()
  72. {
  73.  
  74.     allof7e = (unsigned *)mmap(
  75.                   NULL,
  76.                   0x01000000,  //len
  77.                   PROT_READ|PROT_WRITE,
  78.                   MAP_SHARED,
  79.                   mem_fd,
  80.                   0x20000000  //base
  81.               );
  82.  
  83.     if ((int)allof7e==-1) exit(-1);
  84.  
  85.     SETBIT(GPFSEL0 , 14);
  86.     CLRBIT(GPFSEL0 , 13);
  87.     CLRBIT(GPFSEL0 , 12);
  88.  
  89.  
  90.     struct GPCTL setupword = {6/*SRC*/, 1, 0, 0, 0, 1,0x5a};
  91.  
  92.     ACCESS(CM_GP0CTL) = *((int*)&setupword);
  93.  
  94.  
  95. }
  96.  
  97. /*
  98. void delay(int i) {
  99.     for(volatile unsigned int j = 1<<i; j; j--);
  100. }
  101. */
  102.  
  103. void delay( int i)
  104. {
  105.     for(volatile unsigned int j = 1.25*(1<<i); j; j--);
  106. }
  107.  
  108.  
  109. //function slightly modified by rgrasell@gmail.com to allow for changing frequencies
  110. void modulate(int m)
  111. {
  112.     ACCESS(CM_GP0DIV) = (0x5a << 24) + freq_const  + m;
  113. }
  114.  
  115.  
  116. void playWav(char* filename)
  117. {
  118.     int fp = open(filename, 'r');
  119.     int sz = lseek(fp, 0L, SEEK_END);
  120.     lseek(fp, 0L, SEEK_SET);
  121.    
  122.     short* data = (short*)malloc(sz);
  123.     read(fp, data, sz);
  124.     unsigned int rnd=1;
  125.    
  126.     for (int j=22; j<sz/2; j++){ //while (read(fp, &data, 2)) {
  127.         float dval = (float)(data[j])/65536.0*25.0;
  128.         int intval = (int)(floor(dval));
  129.         float frac = dval - (float)intval;
  130.         unsigned int fracval = (unsigned int)(frac*((float)(1<<16))*((float)(1<<16)));
  131.  
  132.         for (int i=0; i<270; i++) {
  133.           rnd = (rnd >> 1) ^ (-(rnd & 1u) & 0xD0000001u);
  134.           modulate( intval + (fracval>rnd?1:0));
  135.         }
  136.         //printf("%8f  %8x %8f  %08x\n", dval, intval,  frac, fracval);
  137.         //delay(9);
  138.     }
  139.  
  140. }
  141.  
  142. //the plan is:
  143. //use PWM to trigger DMA transfer
  144.  
  145. struct CB {
  146.     unsigned int TI;
  147.     unsigned int SOURCE_AD;
  148.     unsigned int DEST_AD;
  149.     unsigned int TXFR_LEN;
  150.     unsigned int STRIDE;
  151.     unsigned int NEXTCONBK;
  152. };
  153.  
  154. struct DMAregs {
  155.     unsigned int CS;
  156.     unsigned int CONBLK_AD;
  157.     unsigned int TI;
  158.     unsigned int SOURCE_AD;
  159.     unsigned int DEST_AD;
  160.     unsigned int TXFR_LEN;
  161.     unsigned int STRIDE;
  162.     unsigned int NEXTCONBK;
  163.     unsigned int DEBUG;
  164. };
  165.  
  166. /*
  167. //TODO! Make DMA work. We decided that this needs to be a kernel mode driver
  168. void setupDMA(){
  169.    
  170.  
  171. DMAregs* DMA0 = &(ACCESS(DMABASE ));
  172.  
  173.  
  174. //activate
  175. DMA0->CS = (1<<20) | (1<<20) | 1
  176. }
  177. */
  178.  
  179.  
  180. int main(int argc, char **argv)
  181. {
  182.     int g,rep;
  183.  
  184.     // Set up gpi pointer for direct register access
  185.     setup_io();
  186.  
  187.     // Switch GPIO 7..11 to output mode
  188.  
  189.     /************************************************************************\
  190.      * You are about to change the GPIO settings of your computer.          *
  191.      * Mess this up and it will stop working!                               *
  192.      * It might be a good idea to 'sync' before running this program        *
  193.      * so at least you still have your code changes written to the SD-card! *
  194.     \************************************************************************/
  195.  
  196.     // Set GPIO pins 7-11 to output
  197.     for (g=7; g<=11; g++) {
  198.         INP_GPIO(g); // must use INP_GPIO before we can use OUT_GPIO
  199.         //OUT_GPIO(g);
  200.     }
  201.  
  202.     setup_fm();
  203.     modulate(0);
  204.  
  205.  
  206.    //if statement modified by rgrasell@gmail.com to check for new argument, and to set freq_const
  207.     if (argc==3){
  208.       float temp = 500.0 / atof(argv[2]);
  209.       temp *= (16*16*16);
  210.       freq_const = (int)temp;
  211.       playWav(argv[1]);
  212.    }
  213.     else
  214.       fprintf(stderr, "Usage:   program wavfile.wav frequency \n\nWhere wavfile is 16 bit 44.1kHz Monon and frequency is a floating point number\n");
  215.    
  216.     return 0;
  217.    
  218.     //setup_DMA()
  219.  
  220.     /*
  221.     int lastregs[9*15];
  222.     int inuse[9*15];
  223.     memset(&inuse, 0, 9*15*4);
  224.     for(int i = 0; i < 1000000; i++)
  225.         for (int ch = 0; ch <= 14; ch++)
  226.             for (int reg = 0; reg <= 0x20/4; reg++) {
  227.                 int curr = ACCESS((DMABASE + 0x100*ch + reg*4));
  228.                 if (lastregs[ch*9+reg] != curr) {
  229.                     inuse[ch*9+reg]++;
  230.                     lastregs[ch*9+reg] = curr;
  231.                 }
  232.  
  233.                     //printf("addr %#010x:  %#010x\n",0x100*ch + reg, ACCESS(DMABASE + 0x100*ch + reg));
  234.             }
  235.  
  236.  
  237.     for (int ch = 0; ch <= 14; ch++)
  238.         for (int reg = 0; reg <= 0x20/4; reg++)
  239.             printf("addr %#010x inuse:  %#010x\n",0x100*ch + reg, inuse[ch*9+reg]);
  240.     */
  241.  
  242.     printf("addr %#010x:  %#010x\n",0x200, ACCESS(DMABASE + 0x200));
  243.     while(!(ACCESS(DMABASE + 0x200) & 0xF << 16));
  244.     printf("addr %#010x:  %#010x\n",0x200, ACCESS(DMABASE + 0x200));
  245.  
  246.  
  247.     /* printf("start\n");
  248.      // frequency counter on gpio 7
  249.      int oldval=0;
  250.      for (int i=0; i<1000000;) {
  251.         int newval = GPIO_GET & 1<<10;
  252.         if (oldval^newval) {
  253.             oldval=newval;
  254.             i++;
  255.             }
  256.  
  257.      };
  258.      printf("done\n");
  259.      return 0;
  260.      */
  261.  
  262.  
  263.     //Sawtooth wave!
  264.     while(1) {
  265.         for(int i = -40; i <= 40; i++) {
  266.             modulate(i);
  267.             printf("Modulating: %d\n", i);
  268.             delay(25);
  269.         }
  270.     }
  271.  
  272.     for (rep=0; rep<10; rep++) {
  273.         for (g=7; g<=11; g++) {
  274.             GPIO_SET = 1<<g;
  275.         }
  276.         sleep(1);
  277.         for (g=7; g<=11; g++) {
  278.             GPIO_CLR = 1<<g;
  279.         }
  280.         sleep(1);
  281.     }
  282.  
  283.     return 0;
  284.  
  285. } // main
  286.  
  287.  
  288. //
  289. // Set up a memory regions to access GPIO
  290. //
  291. void setup_io()
  292. {
  293.     /* open /dev/mem */
  294.     if ((mem_fd = open("/dev/mem", O_RDWR|O_SYNC) ) < 0) {
  295.         printf("can't open /dev/mem \n");
  296.         exit (-1);
  297.     }
  298.  
  299.     /* mmap GPIO */
  300.  
  301.     // Allocate MAP block
  302.     if ((gpio_mem = malloc(BLOCK_SIZE + (PAGE_SIZE-1))) == NULL) {
  303.         printf("allocation error \n");
  304.         exit (-1);
  305.     }
  306.  
  307.     // Make sure pointer is on 4K boundary
  308.     if ((unsigned long)gpio_mem % PAGE_SIZE)
  309.         gpio_mem += PAGE_SIZE - ((unsigned long)gpio_mem % PAGE_SIZE);
  310.  
  311.     // Now map it
  312.     gpio_map = (unsigned char *)mmap(
  313.                    gpio_mem,
  314.                    BLOCK_SIZE,
  315.                    PROT_READ|PROT_WRITE,
  316.                    MAP_SHARED|MAP_FIXED,
  317.                    mem_fd,
  318.                    GPIO_BASE
  319.                );
  320.  
  321.     if ((long)gpio_map < 0) {
  322.         printf("mmap error %d\n", (int)gpio_map);
  323.         exit (-1);
  324.     }
  325.  
  326.     // Always use volatile pointer!
  327.     gpio = (volatile unsigned *)gpio_map;
  328.  
  329.  
  330. } // setup_io
clone this paste RAW Paste Data