SparkFun Forums 

Where electronics enthusiasts find answers.

Have questions about a SparkFun product or board? This is the place to be.
#103924
I just picked up the AR1010 FM receiver breakout board from sparkfun and I'm having trouble figuring out how to connect the 2-Wire interface to my Arduino.

I think I'm supposed to connect the DATA pin to analog pin 4 and the CLK pin to analog pin 5, but I don't know what pull up resistors to use or how to connect them properly (3.3V or 5V)?

I have the power connected to 3.3V and the CS pin is not connected to anything.

I'm stuck, so I'd really appreciate some help asap.

http://www.sparkfun.com/commerce/produc ... ts_id=8972
#104169
DATA -> ANALOG IN 4 (Arduino)
CLK -> ANALOG IN 5 (Arduino)
CS -> NONE
ROUT -> RSH (3.5 Jack)
LOUT -> TSH (3.5 Jack)
GND -> GND (Arduino)
VCC -> 3V3 (Arduino)
GND (3.5 Jack) -> GND (Arduino)

If you have the 3.5 Audio Jack breakout board they reversed 4 of the connections. TSH is TIP and RSH is RNG. The instructions above are for the breakout board. If you're not using it then use TIP for LOUT and RNG for ROUT.

The OpAmp wasn't necessary for me. I have it plugged into the AUX IN on my desktop speakers and it sounds great, very loud. I suspect this might not be the case if plugged it into head phones, but I haven't confirmed this.
Last edited by zeropointo on Tue Jun 29, 2010 2:41 pm, edited 2 times in total.
#104172
I modified the sample "Example AR1000 ATMega168" code for use with the Arduino IDE. A couple things had to happen. The printf function needed to be fixed and the setup and loop functions needed to be added.

This code is very hacked together, because I'm not even close to finished with it. It works though.

Use the Serial Monitor or Putty to send the following commands:

u = volume up
d = volume down
n = sudo seek next
p = sudo seek prev
+ = station increment +2, wrap, filter
- = station deincrement -2, wrap, filter
[ = station increment no wrap, no wrap, no filter
] = station deincrement no wrap, no filter

To set the station by frequency type the freq followed by #.

Examples:
92.1#
921#

You'll want to change the stations in the filter and sudo seek to whatever your local stations are. Also, [ and ] arn't for normal use. US stations are in increments of 200khz (.2) between 87.9Mhz and 107.9Mhz.

If you get the example codes seek function working please let me know what you changed.
Last edited by zeropointo on Tue Jun 29, 2010 12:43 pm, edited 1 time in total.
#104173
Code: Select all
/*
    9-27-09
    Copyright Spark Fun Electronics© 2009
    Nathan Seidle
    spark at sparkfun.com

    Example Interface to AR1000
	Using ATmega168 at 8MHz

    Modified for Arduino:
    6/29/2010
    Robert Bennett
    zeropointo at sparkfun.com
*/ 

#include <stdio.h>
#include <avr/io.h>
#include "i2c.h"

#define FOSC 8000000
#define BAUD 9600
#define MYUBRR 103

#define sbi(port, bit_mask)   ((port) |= (uint8_t)(1 << bit_mask))
#define cbi(port, bit_mask)   ((port) &= (uint8_t)~(1 << bit_mask))

#define STATUS_LED 5

#define AR1000_W 0x20 //Write address of AR1000
#define AR1000_R 0x21//read address

#define ADDR_STATUS	0x13 // the address of arStatus register
#define MASK_STC (1<<5) //0x0020  // Seek/Tune/PowerOn complete  D5 in  adress 13H 
#define MASK_SF	 (1<<4) //0x0010  //  Seek Fail D4 in address 13H
#define MASK_ST	 (1<<3) //0x0008  //  Stereo  D3 in address 13H
#define MASK_READCHAN 0xFF80 // D7~D15 in address 13H
#define SHIFT_READCHAN 7

#define AR1000_MUTE_ON  { uint16_t temp = ar1000_read(1); ar1000_write(1, temp | (1<<1)); } //Reg_Data[1].BIT.B1 = ON;
#define AR1000_MUTE_OFF { uint16_t temp = ar1000_read(1); ar1000_write(1, temp & ~(1<<1)); } //Reg_Data[1].BIT.B1 = OFF;}

#define AR1000_TUNE_ON 	{ uint16_t temp = ar1000_read(2); ar1000_write(2, temp | (1<<9)); } // Reg_Data[2].BIT.B9 = ON;
#define AR1000_TUNE_OFF { uint16_t temp = ar1000_read(2); ar1000_write(2, temp & ~(1<<9)); } //Reg_Data[2].BIT.B9 = OFF;

#define AR1000_SEEK_ON 	{ uint16_t temp = ar1000_read(3); ar1000_write(3, temp | (1<<14)); } //Reg_Data[3].BIT.B14 = ON;}
#define AR1000_SEEK_OFF { uint16_t temp = ar1000_read(3); ar1000_write(3, temp & ~(1<<14)); } //Reg_Data[3].BIT.B14 = OFF;}

//I2CDEBUG will turn on '!' serial characters and TWI arStatus debugging
//Comment out the define to turn off debug characters
//#define I2CDEBUG 

//Define functions
//======================
void i2c_SendStart(void);
void i2c_SendStop(void);
void i2c_WaitForComplete(void);
unsigned char i2c_SendByte(unsigned char data);
unsigned char i2c_ReceiveByte(unsigned char ackFlag);

void ioinit(void);
static int uart_putchar(char c, FILE *stream);
uint8_t uart_getchar(void);
int uart_gethex(uint8_t length_to_read);

//static FILE mystdout = FDEV_SETUP_STREAM(uart_putchar, NULL, _FDEV_SETUP_WRITE);

void delay_ms(uint16_t x); 
void delay_us(uint16_t x);

uint16_t ar1000_read(uint8_t address);
void ar1000_write(char reg_address, uint16_t reg_value);
void ar1000_readall(void);
void ar1000_write_array(void);
void ar1000_init(void);
void ar1000_setvolume(uint8_t volume_level);
void ar1000_status(void);
void ar1000_tuneto(uint16_t freq_kHz);
void ar1000_tune_hilo(uint16_t freq_kHz);
void ar1000_seek(void);
uint16_t ar1000_rssi(void);

void print_array(void);
void set_array_value(void);

//RSSI 49-54 is pretty good. 34-41 is complete static

//Register conaining default values for the AR1000, these are the default values from the programming guide.
uint16_t register_values[18] = 
{	
	
	0xFFFF, //R0
	0x5B15, //R1
	0xF4B9, //R2 Tune/Channel
	0x8012, //R3 seekTHD = 18
	0x0400, //R4
	0x28AA, //R5
	0x4400, //R6
	0x1EE7,	// R7
	0x7141,	// R8
	0x007D,	// R9
	0x82C6,	// R10  disable wrap
	0x4F55,	// R11. <--- (disable xo_output)
	0x970C,	// R12.
	0xB845,	// R13
	0xFC2D,	// R14 : Volume control 2
	0x8097,	// R15
	0x04A1,	// R16
	0xDF6A	// R17
	
	//Bad values from the Airoha example code - they don't work for me
	/*0xFF7B,	// R0 -- the first writable register .  (disable xo_en)
	0x5B15,		// R1
	0xD0B9,		// R2 
	0xA010,		// R3  seekTHD = 16
	0x0780,		// R4
	0x28AB,		// R5
	0x6400,		// R6
	0x1EE7,		// R7
	0x7141,		// R8
	0x007D,		// R9
	0x82C6,		// R10  disable wrap
	0x4F55,		// R11. <--- (disable xo_output)
	0x970C,		// R12.
	0xB845,		// R13
	0xFC2D,		// R14 : Volume control 2
	0x8097,		// R15
	0x04A1,		// R16
	0xDF6A	*/  // R17
};

// volume control (increasing)
unsigned char AR1000vol[22] =
{ 
	0x0F,	// step 0
	0xCF,	// 1
	0xDF,	// 2
	0xEF,	// 3
	0xFF,	// 4
	0xEE,	// 5
	0xFE,	// 6
	0xED,	// 7
	0xFD,	// 8
	0xFB,	// 9
	0xFA,	// 10
	0xF9,	// 11
	0xF7,	// 12
	0xE6,	// 13
	0xF6,	// 14
	0xE5,	// 15
	0xF5,	// 16
	0xE3,	// 17
	0xF3,	// 18
	0xF2,	// 19
	0xF1,	// 20
	0xF0	// 21 <------ default setting
};

//======================

// create a FILE structure to reference our UART output function
static FILE uartout = {0} ;
char vol = 15;
char buffer[256] = "initialvalue";
char *pos = buffer;
int station = 879;

void setup(){

   // Start the UART
   Serial.begin(9600) ;

   // fill in the UART file descriptor with pointer to writer.
   fdev_setup_stream (&uartout, uart_putchar, NULL, _FDEV_SETUP_WRITE);
   
   ioinit(); //Setup IO pins and defaults
   
   ar1000_tuneto(917);
}

void loop(){
  // Load serial data into buffer
  if(Serial.available()){
    *pos = Serial.read();
    if(*pos != '.' && *pos != '#'){
      pos++;
    }
  }
  
  // reset pointer and tune radio
  if(*pos == '#'){
    *pos = '\0';
    pos = buffer;
    Serial.print("Tuning: ");
    Serial.println(buffer);
    station = atoi(buffer);
    ar1000_tuneto(station);
  }
  
  // next station no wrap, no filter
  if(buffer[0] == ']'){
    pos = buffer;
    *pos = ' ';
    Serial.print("Tuning: ");
    if(station < MAX_S16)station++;
    Serial.println(station, DEC);
    ar1000_tuneto(station);
  }
  
  // previous station no wrap, no filter
  if(buffer[0] == '['){
    pos = buffer;
    *pos = ' ';
    Serial.print("Tuning: ");
    if(station > 0) station--;
    Serial.println(station, DEC);
    ar1000_tuneto(station);
  }
  
  // next station incremental, filtered
  if(buffer[0] == '='){
    pos = buffer;
    *pos = ' ';
    Serial.print("Tuning: ");
    station += 2;
    // god filter
    while(station == 881 || station == 953 || station == 967 || station == 997 || station == 999 || station == 1003)
      station += 2;
    if(station > 1079) station = 879;
    Serial.println(station, DEC);
    ar1000_tuneto(station);
  }
  
  // previous station incremental, filtered
  if(buffer[0] == '-'){
    pos = buffer;
    *pos = ' ';
    Serial.print("Tuning: ");
    station -= 2;
    // god filter
    while(station == 881 || station == 953 || station == 967 || station == 997 || station == 999 || station == 1003)
      station -= 2;
    if(station < 879) station = 1079;
    Serial.println(station, DEC);
    ar1000_tuneto(station);
  }
  
  // sudo seek next, filtered
  if(buffer[0] == 'n'){
    pos = buffer;
    *pos = ' ';
    Serial.print("Tuning: ");
    station += 2;
    // sudo seek w/ idiot filter
    while(station != 889 && station != 897 && station != 905 && station != 917 && station != 921 && station != 929 && station != 941 && station != 949 && station != 959 && station != 965 && station != 975 && station != 991 && station != 1007 && station != 1013 && station != 1017 && station != 1047 && station != 1061 && station != 1073){
      station += 2;
      if(station > 1079) station = 879;
      delay(100); // for fun
      ar1000_tuneto(station); // seems dumb, but large changes cause signal lose for some reason
    }
    Serial.println(station, DEC);
  }
  
  // sudo seek previous, filtered
  if(buffer[0] == 'p'){
    pos = buffer;
    *pos = ' ';
    Serial.print("Tuning: ");
    station -= 2;
    // sudo seek w/ idiot filter
    while(station != 889 && station != 897 && station != 905 && station != 917 && station != 921 && station != 929 && station != 941 && station != 949 && station != 959 && station != 965 && station != 975 && station != 991 && station != 1007 && station != 1013 && station != 1017 && station != 1047 && station != 1061 && station != 1073){
      station -= 2;
      if(station < 879) station = 1079;
      delay(100); // for fun
      ar1000_tuneto(station); // seems dumb, but large changes cause signal lose for some reason
    }
    Serial.println(station, DEC);
  }
  
  // increase volume 21 MAX
  if(buffer[0] == 'u'){
    pos = buffer;
    *pos = ' ';
    if(vol < 21)
      vol++;
    Serial.print("Volume: ");
    Serial.println(vol, DEC);
    ar1000_setvolume(vol);
  }
  
  // decrease volume 0 MIN
  if(buffer[0] == 'd'){
    pos = buffer;
    *pos = ' ';
    if(vol > 0)
      vol--;
    Serial.print("Volume: ");
    Serial.println(vol, DEC);
    ar1000_setvolume(vol);
  }
  
}

uint16_t ar1000_rssi(void)
{
#define ADDR_RSSI	0x12 
#define MASK_RSSI 	0xFE00
#define SHIFT_RSSI  9

	uint16_t rssi;
	
	rssi = ar1000_read(ADDR_RSSI);
	rssi &= MASK_RSSI;
	rssi >>= 9;

	return(rssi);
}

// Volume Control
// There are two different fields about volume control in AR1000F
//  Volume : D7~D10 in register R3
//  Volume2 : D12~D15 in register R14
//  22 combinations of (volume2 + volume) are recommended.
void ar1000_setvolume(uint8_t volume_level)
{
	uint16_t reg3, reg14;
	
	reg3 = ar1000_read(3) & 0xF87F; //Zero out bits D7-D10
	reg3 |= ( (AR1000vol[volume_level] & 0x0F) << 7); //Mask in D7-D10
	
	reg14 = ar1000_read(14) & 0x0FFF; //Zero out bits D12-D15
	reg14 |= ((AR1000vol[volume_level] & 0xF0) << 8); //Mask in D12-D15
	
	ar1000_write(3, reg3);
	ar1000_write(14, reg14);
}

//Tunes the AR1000 to a given station.
//Calculate AR1000 CHAN id  :  Freq (MHz) = 69 + 0.1*CHAN
//Example, sending 973 will tune to 97.3MHz
void ar1000_tuneto(uint16_t freq_kHz)
{
	uint16_t channel, temp;

	/*
	1) Set hmute Bit 
	2) Clear TUNE Bit 
	3) Clear SEEK Bit
	4) Set BAND/SPACE/CHAN Bits
	5) Enable TUNE Bit 
	6) Wait STC flag (Seek/Tune Comlete, in Status Register
	7) Clear hmute Bit 
	8) Update Functions (optional) 
	*/

	//Clear tune bit
	AR1000_TUNE_OFF;

	//Set Channel
	channel = freq_kHz - 690;
	temp = ar1000_read(2); //Read 
	temp &= 0xFE00; //Mask
	temp |= channel;
	ar1000_write(2, temp); //Write
	
	//Enable tune bit
	AR1000_TUNE_ON;
	
	//Wait for tune to stabilize (STC flag)
	temp = 0;
	while(temp == 0)
	{
		temp = ar1000_read(ADDR_STATUS) & MASK_STC;
//		printf("!");
	}
	
}

//This is some weird function in AR1000 example code provided by Airoha
//Looks like it takes the RSSI into account and then fine tunes the station
//I can't hear much of a difference, but it looks fancy.
void ar1000_tune_hilo(uint16_t freq_kHz)
{
	uint16_t temp;

	AR1000_MUTE_ON; //Set mute ON before TUNE
	AR1000_SEEK_OFF; //Clear seek

	//Read Low-Side LO Injection
	//R11 --> clear  D15,  clear D0/D2,  D3 is the same as default
	temp = ar1000_read(11) & 0x7FFA;
	ar1000_write(11, temp);

	//TUNE to FreqKHz with current setting
	ar1000_tuneto(freq_kHz); //This function turns on TUNE and waits for STC flag
	//Low-side TUNE Ends 

	printf("\nLow complete");

	uint16_t arStatus = ar1000_read(ADDR_RSSI);
	uint16_t rssi = (arStatus & MASK_RSSI);

	printf("\nRSSI 1 = %d", rssi >> SHIFT_RSSI);

	//Read Hi-Side LO Injection
	// R11-->set D15, set D0/D2,  D3 is the same as default
	temp = ar1000_read(11) | 0x8005;
	ar1000_write(11, temp);
	
	//TUNE to FreqKHz with current setting
	ar1000_tuneto(freq_kHz); //This function turns on TUNE and waits for STC flag
	//High-side TUNE Ends 

	printf("\nHigh complete");
	

	arStatus = ar1000_read(ADDR_RSSI);
	printf("\nRSSI 2 = %d", (arStatus & MASK_RSSI) >> SHIFT_RSSI);
	rssi = rssi - (arStatus & MASK_RSSI);	
	if (rssi < 0) //errata in 0.82
	{ 	
		// LO
		// R11--> clear D15, set D0/D2, D3 is the same as default
		temp = (ar1000_read(11) & 0x7FFF) | 0x0005;
		ar1000_write(11, temp);
	}
	else
	{ 
		//HI
		//R11-->  set D15, clear D0/D2, D3 is the same as default
		temp = (ar1000_read(11) | 0x8000) & 0xFFFA;
		ar1000_write(11, temp);
	}

	//Fine-tune!!
	//TUNE to FreqKHz with current setting
	ar1000_tune_hilo(freq_kHz); //This function turns on TUNE and waits for STC flag

	AR1000_MUTE_OFF;

	printf("\nLow/Hi tuning complete");

}

//Starts scanning the stations for a minimum set threshold. I found the bit to enable
//wrapping so the every time the function is called, it searches up, and wrap back to 88MHz
//if it doesn't find a good station.
void ar1000_seek(void)
{
	#define ADDR_SEEK_SETTING	0x11
	#define SEEK_SETTING	0x2000
	#define SEEK_MASK		0xC3FF
	#define SEEK_TH_MASK	0xFF80
	#define SEEK_TH			5 //A higher threshold causes stronger stations to be found
	
	uint16_t temp;
	
	char space = 1; //0.1MHz scanning
	char updown = 1; //Seek up
	char band = 0; //US/Europe radio band
	
	AR1000_MUTE_ON;
	AR1000_TUNE_OFF;
	AR1000_SEEK_OFF;
	
	//Enable wrap during seek - I found bit D3 enables wrap, by trial and error. Seems to work
	temp = ar1000_read(10) | (1<<3); //0x82C6 = 1000 0010 1100 0110
	ar1000_write(10, temp);
	
	//Setting before seek
	temp = (ar1000_read(17) & SEEK_MASK) | SEEK_SETTING;
	ar1000_write(17, temp);

	printf("\n\nBegin searching:");

	AR1000_SEEK_ON;
	temp = ar1000_read(3);
	if(space == 1)	temp |= (1<<13); //Set space
	if(updown == 1)	temp |= (1<<15); //Set seek up or down
	temp = (temp & 0xE7FF) | band; //Set Band
	temp &= SEEK_TH_MASK; //Clear out the seek threshold
	temp |= SEEK_TH; //Set threshold
	ar1000_write(3, temp);
	
	//Wait for tune to stabilize (STC flag)
	temp = 0;
	while(temp == 0)
	{
		temp = ar1000_read(ADDR_STATUS) & MASK_STC;
//		printf(".");
	}

	temp = ar1000_read(ADDR_STATUS) & MASK_SF;
	if(temp != 0)
	{
		printf("\nSeek failed!");
		return;
	}
	printf("\nSeek success!");
	
	temp = ar1000_read(ADDR_STATUS) & MASK_READCHAN;
	uint16_t freq_kHz = 690 + (temp >> SHIFT_READCHAN); //Determine what channel we found
	
	printf("\nNow on channel %d.%dMHz", freq_kHz / 10, freq_kHz % 10);

	//Restore setting after seek
	ar1000_write(17, register_values[17]);

	//Fine-tune with auto hilo rejection
	ar1000_tuneto(freq_kHz);

	AR1000_MUTE_OFF;     
}

//This function reads in an address and array value, and stores the value into the array address
//it does not change the values in the ar1000, you will need to use the "send array valus"
//function in order to send the new values to the ar1000	
void set_array_value(void)
{
	uint8_t array_address;
	uint16_t array_value;
	
	printf("\n\nArray Address (2 digit hex value): ");
	array_address = uart_gethex(2);
	printf("\nArray Address is: %x", array_address);
    
   	printf("\n\nArray value (4 digit hex value): ");
	array_value = uart_gethex(4);
        printf("\nArray value is: %x", array_value);
    
        register_values[array_address] = array_value;
}

void print_array(void)
{
	//prints the values of the array that is used to control the radio
	
	printf("\n\nArray position: value\n");

	for(int i = 0 ; i < 18 ; i++)
		printf("0x%.2X: 0x%.4X\n", i, register_values[i]);
}

//Reads a memory register from the AR1000
uint16_t ar1000_read(uint8_t address_to_read)
{
	char byte1 = 0, byte2 = 0;
	char ack;
	
AGAIN:
	i2c_SendStart(); //Send start condition 
	ack = i2c_SendByte(AR1000_W);	 //Send slave device address with write
	ack &= i2c_SendByte(address_to_read);	//Send address to read
	if(ack == 0)
	{
		#ifdef I2CDEBUG
			printf("!"); //No ACK!
		#endif
		goto AGAIN;
	}
	
	
	i2c_SendStart(); //Send start condition 
	i2c_SendByte(AR1000_R);	 //Ask device to read the value at the requested address
	
	if(inb(TWSR) == TW_MR_SLA_ACK)
	{
		byte1 = i2c_ReceiveByte(TRUE);
		byte2 = i2c_ReceiveByte(TRUE);
	}
	else
	{
		// device did not ACK it's address,
		// data will not be transferred
		// return error
		//retval = I2C_ERROR_NODEV;
		printf("\n\tAck failed!");
	}

	i2c_SendStop();
	
	//Combine two bytes into one 16-bit word
	int16_t temp = byte1 << 8;	
	temp |= byte2;
	
	return(temp);
}

void ar1000_write(char reg_address, uint16_t reg_value)
{
	char ack;
	uint8_t value1 = (reg_value & 0xFF00) >> 8;
	uint8_t value2 = (reg_value & 0x00FF);

AGAIN:
	i2c_SendStart(); //Send start condition 
	ack = i2c_SendByte(AR1000_W);	
	ack &= i2c_SendByte(reg_address); //Send address to write to
	ack &= i2c_SendByte(value1); //Send the two data bytes to be stored
	ack &= i2c_SendByte(value2);
	i2c_SendStop();

	if(ack == 0)
	{
		#ifdef I2CDEBUG
			printf("!"); //No ACK!
		#endif
		goto AGAIN;
	}
}

void ar1000_write_array(void)
{
	// This code writes the array values to the ar1000, it is used to calibrate the ar1000
	// on power up and it can send the modified array values needed for the seeking tuning etc
	
	//The example AR1000 code disables the analog and digital blocks
	// then write to the 0x01 to 0x11 registers
	// then enables the analog and digital blocks - so that's what we will do as well

	//Write the first register
	ar1000_write(0, register_values[0] & 0xFFFE); //<--- Notice we force the enable bit to zero

	for(int i = 1 ; i < 18 ; i++)
		ar1000_write(i, register_values[i]); //Write registers 1 to 17 to AR1000
	
	ar1000_write(0, register_values[0]); //Re-write the first register, this will set the enable bit
}

//Reads and prints all 16 registers (16-bits wide) of the AR1000
void ar1000_readall(void)
{
	uint16_t x, register_value;
	for(x = 0 ; x < 0x1D ; x++)
	{
		register_value = ar1000_read(x);
		printf("0x%.2X: 0x%.4X\n", x, register_value);
	}
}

void ar1000_init(void)
{
	delay_ms(100); //Wait for power to stabilize
	
	ar1000_write_array(); //Init the AR1000 by writing the initial recommended values

	uint16_t arStatus = 0;
	while(arStatus == 0)
	{
		arStatus = ar1000_read(ADDR_STATUS);
	
		printf("\nAR1000 arStatus : 0x%04X", arStatus);

		arStatus = arStatus & MASK_STC;
		delay_ms(10);
	}
}

//Read the arStatus register (0x13) of the AR1000
void ar1000_status(void)
{
	uint16_t arStatus;
	
	arStatus = ar1000_read(ADDR_STATUS);
	
	printf("\n\nAR1000 arStatus : 0x%04X", arStatus);
	
	uint16_t channel = arStatus & MASK_READCHAN;
	channel >>= SHIFT_READCHAN;
	channel += 690;
	printf("\nChannel : %02d.%01dMHz", channel / 10, channel % 10);
	
	if(arStatus & MASK_STC) 
		printf(" (Seek/Tune Complete)");
	else
		printf(" (Seek/Tune Incomplete)");
	
	if(arStatus & MASK_SF) 
		printf(" (Seek Fail)");
	else
		printf(" (Seek Successful)");
		
	if(arStatus & MASK_ST) 
		printf(" (Stereo)");
	else
		printf(" (Mono)");
}

//Setup for UART and IO pins
void ioinit (void)
{
	
	//1 = output, 0 = input
    DDRB = 0b11111111; //All outputs
    DDRC = 0b11111111; //All outputs
    //DDRD = 0b11111110; //PORTD (RX on PD0)
    
//  stdout = &mystdout; //Required for printf init

    // The uart is the standard output device STDOUT.
    stdout = &uartout ;
/*
	UBRR0H = (MYUBRR) >> 8;
	UBRR0L = MYUBRR;

	UCSR0B = (1<<RXEN0)|(1<<TXEN0);
	UCSR0C = (3<<UCSZ00);
	UCSR0A = (1<<U2X0);
*/
	//Init timer 0 for delay_us timing
	//8,000,000 / 8 = 1,000,000
        TCCR0B = (1<<CS01); //Set Prescaler to 8. CS01=1
	
	//initialize I2C hardware
	TWCR = 0x00;
	TWBR = 64;
	//TWSR = (1 << TWPS1);
	cbi(TWCR, TWEA);
	sbi(TWCR, TWEN);
	
	ar1000_init(); //Initialize AR1000
}

/*
static int uart_putchar(char c, FILE *stream)
{
    if (c == '\n') uart_putchar('\r', stream);
  
    loop_until_bit_is_set(UCSR0A, UDRE0);
    UDR0 = c;
    
    return 0;
}
*/

// create a output function
// This works because Serial.write, although of
// type virtual, already exists.
static int uart_putchar (char c, FILE *stream)
{
    Serial.write(c) ;
    return 0 ;
}

/*
uint8_t uart_getchar(void)
{
    while( !(UCSR0A & (1<<RXC0)) );
    return(UDR0);
}
*/

uint8_t uart_getchar(void){
  UDR0 = Serial.read();
  return(UDR0);
}

//Reads in ASCII characters, converts to decimal and returns decimal variable
//length_to_read is how many characters we want to read, "A33C" would be four characters long
int uart_gethex(uint8_t length_to_read)
{
	int decimal_value = 0;
	unsigned char input_character;

	for(uint8_t x = 0 ; x < length_to_read ; x++)
	{
		decimal_value <<= 4; //Every time we loop, make room for another 4-bit hex value to be masked into decimal_value
		
		input_character = uart_getchar();
		printf("%c", input_character);	

		//Check the character for validity
		if( (input_character >= '0') && (input_character <= '9') ) 
			decimal_value |= (input_character - '0');
		
		else if( (input_character >= 'a') && (input_character <= 'f') )
			decimal_value |= (input_character - 'a');
		
		else
		{
			//We have a non-legal character. Handle the exception however you want
			return(0);
		}
	}

	return(decimal_value);
}

//General short delays
//general short delays
//Uses internal timer do a fairly accurate 1us
//Because we are using 16MHz and a prescalar of 8 on Timer0, we have to double x
void delay_us(uint16_t x)
{
	while(x > 256)
	{
		TIFR0 = (1<<TOV0); //Clear any interrupt flags on Timer0
		TCNT0 = 0; //Preload Timer0 for 256 clicks. Should be 1us per click
		while( (TIFR0 & (1<<TOV0)) == 0);
		
		x -= 256;
	}

	TIFR0 = (1<<TOV0); //Clear any interrupt flags on Timer0
	TCNT0 = 256 - x; //256 - 125 = 131 : Preload Timer0 for x clicks. Should be 1us per click
	while( (TIFR0 & (1<<TOV0)) == 0);
}

//General short delays
void delay_ms(uint16_t x)
{
	for ( ; x > 0 ; x--)
		delay_us(1000);
}

//==========================
//
//I2C functions
//
//==========================

void i2c_SendStart(void)
{
	// send start condition
	TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN);

	i2c_WaitForComplete();
}

void i2c_SendStop(void)
{
	// transmit stop condition
	TWCR = (1<<TWSTO);
}

void i2c_WaitForComplete(void)
{
	// wait for any previous i2c stuff to complete before sending new data
	while (!(TWCR & (1<<TWINT)));
}

unsigned char i2c_SendByte(unsigned char data)
{
	// save data to the TWDR
	TWDR = data;
	// begin send
	TWCR = (1<<TWINT)|(1<<TWEN);

	// wait until transmission completed
	while(!(TWCR & (1<<TWINT)));

	// check value of TWI Status Register. Mask prescaler bits
	uint8_t twst = TWSR & 0xF8;
	
	#ifdef I2CDEBUG
		printf("twst: 0x%02X\n\n", twst);
	#endif
	
	if( twst == 0x18) return 1; //SKA+W was tranmitted, ACK received
	if( twst == 0x28) return 1; //Data was tranmitted, ACK received
	return 0;
}

unsigned char i2c_ReceiveByte(unsigned char ackFlag)
{
	// begin receive over i2c
	if( ackFlag )
	{
		// ackFlag = TRUE: ACK the recevied data
		outb(TWCR, (inb(TWCR)&TWCR_CMD_MASK)|BV(TWINT)|BV(TWEA));
	}
	else
	{
		// ackFlag = FALSE: NACK the recevied data
		outb(TWCR, (inb(TWCR)&TWCR_CMD_MASK)|BV(TWINT));
	}

	i2c_WaitForComplete();

	// retieve received data byte from i2c TWDR
	return( inb(TWDR) );
}

#104176
Here's a list of the local stations I can pick up with this module.

88.1 WLGH Smile FM: Michigans Positive Hits (R)
88.9 WDBM The Impact: MSU Student Radio
89.7 WLNZ: LCC Radio
90.5 WKAR: NPR and Classical Radio
91.7 WUOM Michigan Radio: Your NPR News Station
92.1 WQTX: 92-X Classic Hits
92.9 WJZL: Lansing's Smooth Jazz
94.1 WVIC The Edge
94.9 WMMQ: Lansing's Classic Rock
95.3 W237BY Air 1 Radio (R)
95.9 Dead Air
96.5 WQHH Power: Hip-Hop & R&B
96.7 WUFN Family Life Radio (R)
97.5 WJIM Now FM: Hit Music Station
99.1 WFMK: Best Variety of Lite Rock
99.7 WUGN Family Life Radio (R)
99.9 WUGN Family Life Radio (R)
100.3 W262BD Air1 Radio (R)
100.7 WITL: Today's Best Country
101.3 WBFX The Fox
101.7 WHZZ Mike FM
104.7 W284AH Home.fm: Music That Makes You Feel Good
106.1 WJXQ Q106: Lansing's Rock Station
107.3 WBBL The Ball: West Michigan's Sports Leader

R = Religious, I filtered these out.

Guide:
http://www.michiguide.com/dials/fm.html