// 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)
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.25*(1<<i); j; j--);
}
void modulate(int m, double filteredFreq)
{
ACCESS(CM_GP0DIV) = (0x5a << 24) + filteredFreq + m;
//ACCESS(CM_GP0DIV) = (0x5a << 24) + 0x5000 + m;
//
}
void playWav(char* filename, double freq)
{
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),freq);
}
}
}
//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;
};
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);
}
//Messy code...
double freq = 100;
if (argc==3)
freq = atof(argv[2]);
if (freq < 87.5 || freq > 108.0)
freq = 100;
double pureFreq = round((500/freq) * 16 * 16 * 16);
setup_fm();
modulate(0,pureFreq);
if (argc==3) //We must have 3 args due to the mod :P
playWav(argv[1], pureFreq);
else
fprintf(stderr, "Usage: program wavfile.wav frequency\n\nWhere wavfile is 16 bit 44.1kHz Mono\nAnd the frequency between 87.5 and 108.0\n");
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