AR1000 FM Module

Dear sir

Neeed some friend advise about AR1000 FM recevier module

Now I am try interface FM Module with AVR , But don’t underdstand

the parameter 18 byte and Step seek stantion

Code

18 Byte

uint16_t register_values[18] = {0xffff,0x5b15,0xF4B9,0x8012,0x0400,0x28aa,0x4400,0x1ee7,0x7141,0x007d,0x82ce,0x4f55,0x970c,0xb845,0xfc2d,0x8097,0x04a1,0xdf6a};

and

//----------------------------------------------------------------------------------//

void seek(void)

{

printf(“\n\t Seeking \n”);

register_values[02] = 0xB480; //set tune to 900kHz

register_values[03] = 0xA001; //turn off seek, seek up, set threshold to 1

ar1000calibration(register_values);

register_values[03] = 0xE001; //turns on seek

ar1000calibration(register_values);

//there are many other functions in registers R02 and R03,

//for example the R03 value also changes the volume of the

//reciever and the R02 value also activates the tune bit

}

Actually, I too am having fun and games with the fm radio module. The actual module comes with an AR1010 (which is exactly like the AR1000) but without the RDS functionality, shame, that would have been fun to play with).

The datasheet is truely one of the worst I have ever seen. It doesn’t even make sense. It’s not clear from the table which bits are which, and the unused ones aren’t documented as “unusued”, so in each 16 bit register you’re not really sure what is what. Oh, and the actual registers don’t actually add up either. So you’re not really sure about which one the STC bit is hiding in.

Even the “default” register values use bit positions that aren’t documented.

To top it off, the document says that the “register map” (which you would hope would explain everything) is “at the end of the document”. Naturally the document page numbers say “Page X of 27” and the document goes to page 26. Page 27 is missing entirely.

Sparkfun aren’t allowed to publish the datasheet (like they do for most datasheets), but personally if I were Airoha it would be more because the datasheet is quite frankly terrible than any copyright reasons.

But enough complaining. Has anyone got this little guy working? It would be nice to actually use all the functionality and even get a version with the RDS stuff going.

With the sparkfun code, I can get the occasional crackly station, but any use of not dumping all registers out (1-18 then 0) doesn’t seem to work.

Any help, or reverse engineering to understand the datasheet would be much appreciated.

kind regards

Ian.

I have some wonder ,

Example

If i would like to seek to 100.0 MHZ and 88.5 MHZ … How to use parameter for seek

3 Day tried to write software…

J.nut

arampee@jnutthailand.com

http://www.jnutthailand.com

Now It work

but I don’t know ,how to read signal strange,

And I have some problem . I sent frequency to address(2) and I read back , but not correct

#include 	<avr/io.h>
#include 	<avr/interrupt.h>
#include 	<string.h>
#include 	<stdio.h>
#include 	"mydefs.h"
#include 	<util/delay.h>

#include 	"i2c.h"
#include 	"lcd.h"
#include 	"delay_function.h"

uint16_t  	fre;

#define		step 	5

#define	SLA_W	0x20
#define SLA_R	0x21

uint16_t register_values[18] = {
					0xffff,0x5b15,0xF4B9,0x8012,
					0x0400,0x28aa,0x4400,0x1ee7,
					0x7141,0x007d,0x82ce,0x4f55,
					0x970c,0xb845,0xfc2d,0x8097,
					0x04a1,0xdf6a
};
uint8_t v2[22] = {	0x0,0xC,0xD,0xE,0xF,0xE,0xF,0xE,0xF,0xF,0xF,
					0xF,0xF,0xE,0xF,0xE,0xF,0xE,0xF,0xF,0xF,0xF};
					
uint8_t v1[22] = { 	0xF,0xF,0xF,0xF,0xF,0xE,0xE,0xD,0xD,0xB,0xA,
					0x9,0x7,0x6,0x6,0x5,0x5,0x3,0x3,0x2,0x1,0x0};
//----------------------------------------------------------------------------------//
//----------------------------------------------------------------------------------//
//----------------------------------------------------------------------------------//
//----------------------------------------------------------------------------------//
void init_ar1000(uint16_t values[])
{
// 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

	uint8_t addr;
	
	for(addr = 1; addr < 18; addr++)
	{
	
		TWI_start ();
		TWI_send (SLA_W,0);
		TWI_send (addr,0);		//addr
		
		TWI_send ((values[addr] & 0xff00) >>8,0);
		TWI_send ((values[addr] & 0x00ff),0);
		TWI_stop ();
	}
	
	TWI_start ();
	TWI_send (SLA_W,0);
	TWI_send (0,0);				//address 0
	// send R0
	TWI_send ((values[0]&0xff00)>>8,0);
	TWI_send ((values[0]&0x00ff),0);
		
	TWI_stop ();
}
//-------------------------------------------------------------------------------//
void write (uint8_t addr, uint16_t value)
{
	uint8_t value1,value2;

	value1 = (value & 0xff00) >>8;
	value2 = (value & 0x00ff);
	
	TWI_start ();
	TWI_send (SLA_W,0);
	TWI_send (addr,0);		//addr
	// send value
	TWI_send (value1,0);
	TWI_send (value2,1);
	TWI_stop ();
}
//-------------------------------------------------------------------------------//
uint16_t readAR1000 (uint8_t addr)
{
	uint16_t	dat;
	
	TWI_start ();
	TWI_send (SLA_W,0);
	TWI_send (addr,0);		//addr
	
		TWI_start ();
		TWI_send (SLA_R,0);

		dat = TWI_read (0);
		dat <<= 8;
		dat |= TWI_read (1);
		TWI_stop ();
		
	return dat + 690;
}
//-------------------------------------------------------------------------------//
//-------------------------------------------------------------------------------//
//-------------------------------------------------------------------------------//
void setAR1000 (uint16_t freq)
{
	//unsigned int x = 880;
	//freq = x;
		
	freq -= 690;
	//clear tune bit and chan bits
	register_values[2] &= ~(0x01FF | 0x0200);	
	
	//set chan bits
	register_values[2] =  freq;
	
	//clear seek bit
	register_values[3] &= ~(1 << 14);
	
	//set space = 100k (seek stepping increments in 100k steps)
	register_values[3] |= (1 <<13);
 
	//send the registers to the chip
	write (2,register_values[2]);
	write (3,register_values[3]);
	
	//set tune bit
	register_values[2] |= 0x200;
	write (2,register_values[2]);

}
//---------------------------------------------------------------------------------//
void show_frequency (uint16_t freq)
{
	uint8_t 	display_bit[5];
 
	display_bit[0] = freq / 1000 ;
  
	if ( display_bit[0] == 0 ) 
		display_bit[0] = 0x20;
	else 
		display_bit[0] += 0x30;

	display_bit[1] = (freq / 100)%10 +0x30;
	display_bit[2] = (freq / 10)%10 +0x30;
  
	display_bit[3] = fre%10+0x30;
	display_bit[4] = 0x30;
  
	LCD_write_english_string(0,2," ");
	LCD_write_char(display_bit[0]);
	LCD_write_char(display_bit[1]);
	LCD_write_char(display_bit[2]);
	LCD_write_english_string(30,2,".");
	LCD_write_char(display_bit[3]);
	LCD_write_char(display_bit[4]);
	LCD_write_english_string(48,2," MHZ");
}
//---------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------//
// Volume Control
// there are two different fields about volume control in AR1000E
//  Volume   :  D7  ~D10 in register R3
//  Volume2 :  D12~D15 in register R14
//  22 combinations of ( volume2 + volume)  are  recommended.
//  
// 
void set_vol (uint8_t vol)
{
	register_values[1]  |= 0x0200;
	write(1, register_values[1]);
	
	register_values[3] = (register_values[3] & ~0x0780) | (v1[vol] << 7); 
	write(3, register_values[3]);
	
	register_values[14] = (register_values[14] & ~0xF000)| (v2[vol] << 12);
	write(14, register_values[14]);
	
	 // clear hmute bit
    register_values[1] &= ~0x0200;
    write(1,register_values[1]);

	
}
//---------------------------------------------------------------------------------//

void init(void)
{
	DDRB = 0XFF;
	PORTB = 0XFF;
  
	DDRD = 0B11100000;
	PORTD = 0XFF;
  
	SPSR |= (1<<SPI2X);           		// 
	SPCR |= (1<<SPE)|(1<<MSTR);     	// 
	
		
	LCD_DDR |= LCD_RST | LCD_DC | LCD_CE | SPI_MOSI | SPI_CLK;	
	
	SFIOR=0x00; 
	
	TWCR = 0x00;
	TWBR = 64;
	

	sei ();
  
	LCD_init(); 
}
//---------------------------------------------------------------------------------//
int main(void)
{

	unsigned int x;
	
	init ();

	fre = 880;			//default 87.50 MHZ
	
	init_ar1000(register_values);
	
	set_vol (20);
	
	setAR1000 (fre);		//100.0 MHZ
		
	LCD_write_english_string(0,0,"FM STEREO");
	//fre = read(2);
	show_frequency(fre);
	LCD_write_inverse_string(0,5," UP ");
	LCD_write_inverse_string(48,5," DOWN ");

	while(1)
	{
		if ((PIND&0x0c) == 0x04)
		{
			delay_nms(500);
			delay_nms(500);
			
			if ( (PIND&0x0c) == 0x04)
			{
				LCD_write_english_string(48,5," DOWN " );
				delay_nms(200);
				
				if(bit_is_clear(PIND, 3))
				{
            
					fre -=step;
					if ( fre <= 875 ) 
						fre = 1080;
          
				setAR1000 (fre);
				
				x = fre;
				//x = readAR1000 (2);
				
				show_frequency(x);
				delay_nms(200);
				delay_nms(200);
				loop_until_bit_is_set(PIND, 3);
				LCD_write_inverse_string(48,5," DOWN ");
				}

			}
		}	
    
		if ( (PIND&0x0c) == 0x08)
		{
			delay_nms(500);
			delay_nms(500);
			if ( (PIND&0x0c) == 0x08)
			{
          
				LCD_write_english_string(0,5," UP ");
				delay_nms(200);        
               
				fre +=step;
				if ( fre >= 1080) 
				fre = 875;
				setAR1000 (fre);
				
				x = fre;
				//x = readAR1000 (2);
				show_frequency(x);
				delay_nms(200);
				delay_nms(200);
  
            loop_until_bit_is_set(PIND, 2);
			LCD_write_inverse_string(0,5," UP ");
			}
		}	

	}
}

Now I try to debug

I read register it not correct

Example Register R17 = 0xDF67, I read R17 = 0xDFFF. I don’t know why low byte = 0xFF;

my code

//-------------------------------------------------------------------------------//
uint16_t readAR1000 (uint8_t addr)
{
	uint16_t	dat;
	uint8_t 	val;
	
	TWI_start ();
	TWI_send (SLA_W,0);
	TWI_send (addr,0);		//addr
	
		TWI_start ();
		TWI_send (SLA_R,0);

		dat = TWI_read (0);
		dat <<= 8;

		val = TWI_read (1);
		TWI_stop ();
		
	return (dat | val);
}
//-------------------------------------------------------------------------------//
uint8_t htoasc (uint8_t hex)
{
	hex &= 0x0f;
	
	if (hex > 9)
	{
		hex += 'A' - 10;
	}
	else
	{
		hex += '0';
	}
	return hex;
}
//-------------------------------------------------------------------------------//
void debug_register (uint8_t reg)
{
	uint16_t y;

	y= readAR1000 (reg);
	
	LCD_write_english_string(0,3," ");
	LCD_write_char(htoasc(y >> 12));
	LCD_write_char(htoasc(y >> 8));
	LCD_write_char(htoasc(y >> 4));
	LCD_write_char(htoasc(y & 0x0f));
}

Now I am finish work with FM AR1010

please see

http://www.jnutthailand.com/hobby/hobby.htm

and

http://www.youtube.com/watch?v=Txtr4X0xhfc

J.nut

Thanks J.Nut, I appreciate you posting some code.

You have made some good discoveries about this chip; the datasheet doesn’t make it clear that some registers are actually left justified rather than right justified within the 16 bit register.

kind regards

Ian.

I finally got mine going

http://web.ncf.ca/fp927/electronics/sound/

Very nice

J.nut

arampee@jnutthailand.com

After many hours of playing with the AR1010 I have it working quite well. It took some time to get the seek function working but it does it now in both directions. I’m using the PIC 16f873.

Rick

Hi guys…

First thanks for the info posted here. It has been a great help. Now, I understand this thread is a little old, but I have found (sorta) the missing page with the Register Table.

The PG that Sparkfun sent me was version 0.80. I found version 0.81 online at this address: http://www.docin.com/p-34190202.html

The good news is document is complete and in english, the bad news is the rest of the page is in chinese (which my comp is reading as a bunch of squares) and the document is posting in a Flash window, so it seems impossible to save locally. Also the doc is 28 pages long instead of 27, so there is more info in other areas of the doc.

I managed to save that last page to a PDF via a screen cap if anyone wants it. If someone is able to save the complete doc from that page, please let us know! :slight_smile:

I plan on doing the control using a PIC chip as well. This is going into a Car PC project for my summer car.

Mark

canuckmark:
The PG that Sparkfun sent me was version 0.80. I found version 0.81 online at this address: http://www.docin.com/p-34190202.html

I managed to save that last page to a PDF via a screen cap if anyone wants it. If someone is able to save the complete doc from that page, please let us know! :slight_smile:

I’ve now grabbed the complete document from that crummy site, and saved it as a quite nice PDF file here.

If anyone wants it, give me a shout! No NDA required for this one.

Cheers

Mark

mlord1:
I’ve now grabbed the complete document from that crummy site, and saved it as a quite nice PDF file here.

If anyone wants it, give me a shout! No NDA required for this one.

I also now have a working implementation, using an FTDI USB/serial breakout board to interface the AR1010 module to a PC. The control is done by bitbanging over three CBUS pins, usiing the AR1010’s 3-wire protocol. The audio simply connects to the PC’s sound card LINE-IN with a standard miniplug cable.

For [Linux] software, I wrote a small FTDI bitbang program in C, which can read/write registers of the AR1010. Then there’s a bash shell script to actually initialize and control the radio, calling the C program to do the low-level register accesses.

The script implements the high/low “automatic” tuning optimization, stereo/mono handling, volume control, and both direct and preset tuning for “known local stations”.

The idea, is that the script is then used from a crontab entry, for automatic recording of radio programmes at specific times/days. Like a PVR for radio rather than television.

Works great!

I’ll post code eventually, but if anyone wants it sooner, PM/email me.

Cheers

Mark

canuckmark,

Thanks for posting that link. It’s one of the worst datasheets I’ve ever seen - but that version has a register table at the end which I do wish I had when I was trying to make it work before!

cheers

Ian.

Here are my efforts:

http://rtr.ca/fmradio/

It also has the PDF version of the 0.81 programmer’s guide there,

with a readable version of that “missing” register summary page.

Cheers

mlord1:
Here are my efforts:

http://rtr.ca/fmradio/

Now updated with photos of the final build, and a **.zip** of everything for those who don't grok **.tgz** files. ;)

-ml

Has anyone been successful at getting this FM module to work on the arduino (or arduino mega would be great)? I have the Arduino Mega and have been plugging away at this thing for days. This thread is the best resource I have found anywhere so it seems like the place to ask.

Hi,

you can watch my radio in action (AR1010 + Atmega8).

http://www.youtube.com/watch?v=4kpT-557ERk

My library is in the attached file. Please do not delete author names in the source code. The details of the project is in my web site (http://www.berik.net in Turkish).

Enjoy.

Cem

Can anybody help with this module and an Arduino @ 3.3v 8MHz.

I can read the Device ID fine but when I send the initialisation sequence nothing happens and future reads of the Device ID are corrupt.

The module works when tested with anomaly’s code on the 16f877.