Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronic Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

Register Log in

How to play audio files from SD card using PIC microcontroller

Status
Not open for further replies.

Akhil Mohan

Member level 3
Joined
May 13, 2011
Messages
57
Helped
2
Reputation
4
Reaction score
2
Trophy points
1,288
Activity points
1,744
Hello,

For my project, I want to play some audio files from the SD card. I want to control these audio files using a PIC micro controller (I have a PIC 16F877A uc).
I need a great help to do this.

I am a beginner in PIC programming field and I don't know how much complex the task is? But anyway hope for the best.

Another way to do this using a voice controller IC like APR9600, but a second person may not know how to add new audio files to IC. This is why I want to try using a SD card with an interface to PC so that it is easy to change the file if necessary :)

Thanks in advance,
Akhil
 

vinodstanur

Advanced Member level 3
Joined
Oct 31, 2009
Messages
750
Helped
114
Reputation
234
Reaction score
114
Trophy points
1,333
Location
Kerala (INDIA)
Activity points
7,049
The main problem is RAM in PIC16F877A. Generally, u need RAM of above 512 bytes for efficient FAT file system access. Better solution is go for PIC18F series.
-----------------------------------
I had done a digital voice recorder and play back system with MMC and PIC16F877A but it doesn't have any file system. It just write and read from a particular sector to its last sector.(i think u had seen that video).I didn't used RAM buffer but continuously read bytes and send each byte to PWM just after reading the byte. I am posting the code at the bottom.
-----------------------------------
And i also wrote code to access FAT filesystem using PIC16F877A. But i doubt that the code is less efficient and may not be good for audio streaming. I can display ASCII-text files(copied to FAT16 mmc) in an LCD using PIC16F877A. The difficult part is reading the FAT(file allocation table) in the MMC (to get next sector address of the playing file) after streaming each cluster. If u could do it in most efficient manner, then i think u can play an audio using PIC16F877A. Any way, i stopped my activities since its our exam time, and i will continue after exam. My aim is to play wav files in FAT16 mmc using this PIC.
----------------------------------
Code:
///////////////////////////////////////////////////////////////////////
// [U]my first digital voice recorder using PIC16F877A and MMC[/U]//
//   push button at RE0 to select play or record mode           //
// http://www.youtube.com/watch?v=Mn1VsM-i8QI             //
///////////////////////////////////////////////////////////////////////
#include<pic.h>
#define _XTAL_FREQ 20e6
#define CS RC2
#define RS RB2
#define EN RB1
#define fst cmd(0x80)
#define snd cmd(0xc0)
unsigned int i;
unsigned char j,k,rec,dat,tempbuf,readdata,u;
unsigned int count;unsigned long int wcount;
unsigned long int mul=1,arg=0;
	const char *q="VINOD ";
/*-----------------LCD BEGIN----------------------------*/
void LCD_STROBE(void)
	 {
	EN = 1;
	__delay_us(0.5);
	EN = 0;
	}
void data(unsigned char c)
	{ 
	RS=1;
	__delay_us(40); PORTD = ( c >> 4 );LCD_STROBE();
	PORTD = ( c );LCD_STROBE(); 
	}
void cmd(unsigned char c)
	{
	 RS=0;
	__delay_us(40); PORTD = ( c >> 4 );LCD_STROBE();
	PORTD = ( c  );LCD_STROBE();
	}
void clear(void)
	{
	 cmd(0x01);
	__delay_ms(2);
	}
void lcd_init()
	{ 
	__delay_ms(20);
	cmd(0x30 );
	__delay_ms(1);
	cmd(0x30 );
	__delay_ms(1);
	cmd(0x30 );
	cmd(0x28 ); // Function set (4-bit interface, 2 lines, 5*7Pixels)
	cmd(0x28 ); // Function set (4-bit interface, 2 lines, 5*7Pixels)
	cmd(0x28 ); // Function set (4-bit interface, 2 lines, 5*7Pixels)
	cmd(0x0c); // Make cursorinvisible
	clear();
	clear(); // Clear screen 
	cmd(0x6); // Set entry Mode
	}
void string(const char *q)
	{
	clear();
	while(*q) {data(*q++);}
	}


void istring(unsigned int q)
	{
	cmd(0x81);
	data(48+(q/100));q%=100;
	data(48+(q/10));q%=10;
	data(48+(q));
	__delay_ms(500);
	}
/*-----------------------LCD END--------------------*/

/*-----------------------USRT BEGIN--------------------*/
void usrt_init()
	{

	TRISC6=0;
	TXSTA=0b00100110;
	RCSTA=0b11010000;
	SPBRG=10;
	}
void printf(const char *p)
	{
	while(*p)
		{
		TXREG=*p;
		while(TRMT==0);
		p++;
		}
	}
void txd(unsigned char vv)
        {
        TXREG=vv;
        while(TRMT==0);
        }
  /*-----------------------USRT END-------------------*/
  
/*----------------------PWM BEGINS--------------------*/
void pwm_init()
{
TRISC1=0;
T2CKPS1=0;T2CKPS0=0;
PR2=0x50;
CCPR2L=0x17;
TMR2ON=1;
CCP2CON=0b00001100;
}
void pwm_disable(){CCP2CON=0b00000000;}
void pwm_enable(){CCP2CON=0b00001100;}

/*--------------------PWM END------------------------*/

/*-------------------mmc BEGIN-----------------------*/
void spi_init()
	{
	TRISC4=1;
	RC2=1;RC3=0;RC5=0;
	TRISC2=TRISC3=TRISC5=0;
	SSPCON=0b00100010;
	SSPEN=1;
	SMP=1;
	CKE=1;
	CKP=0;
	}

 void spi_write(unsigned char kk)
	 {
	  SSPBUF=kk;
	  while(BF==0);
	 }
 void spi_read()
	{
   	SSPBUF=0xff;
	while(BF==0);
	readdata=SSPBUF;
	}

void command(char command, unsigned long int fourbyte_arg, char CRCbits )
	{
	spi_write(0xff);
	spi_write(0b01000000|command);
	spi_write((unsigned char)(fourbyte_arg >> 24));
	spi_write((unsigned char)fourbyte_arg >> 16);
	spi_write((unsigned char)(fourbyte_arg >> 8));
	spi_write((unsigned char)fourbyte_arg);
	spi_write(CRCbits);
	spi_read();
	}

void mmc_init()
{	
	CS=1;
	for(u=0;u<50;u++){spi_write(0xff);}
	CS=0;
	__delay_ms(1);
	command(0,0,0x95);
	count=0;
	while((readdata!=1)&&(count<1000)){spi_read();count++;}
	if(count>=1000){string("CARD ERROR-CMD0 ");while(1);}
	command(1,0,0xff);
	count=0;
	while((readdata!=0)&&(count<1000)){command(1,0,0xff);spi_read();count++;}
	if(count>=1000){string("CARD ERROR-CMD1 ");while(1);}
	command(16,512,0xff);
	count=0;
	while((readdata!=0)&&(count<1000)){spi_read();count++;}
	if(count>=1000){string("CARD ERROR-CMD16");while(1);}
	string("MMC INITIALIZED!");__delay_ms(1000);
	SSPCON=SSPCON&0b11111101;
}

void write()
	{
	pwm_disable();	
	/*write*/
	command(25,arg,0xff);
	while(readdata!=0){spi_read();string("WRITE ERROR");}
	string("WRITING MMC");
h:	spi_write(0xff);
	spi_write(0xff);
	spi_write(0b11111100);
	for(int g=0;g<512;g++)
		{
		ADGO=1;
		while(ADGO);
		spi_write(ADRESL);	PORTD=~ADRESL;
		}
	spi_write(0xff);
	spi_write(0xff);
	spi_read();
	while((readdata&0b00011111)!=0x05){spi_read();}
	while(readdata!=0xff){spi_read();}
	if(RE0==1)
	{
	spi_write(0xff);
	spi_write(0xff);
	spi_write(0b11111101); //stop token
	spi_read();spi_read();
	while(readdata!=0xff){spi_read();}
	goto exit1;
	}
	goto h;
exit1:;
	}
void read()
	{
	pwm_enable();

	command(18,(arg),0xff);
	while(readdata!=0){spi_read();	string("READ ERROR");}
	string("READING MMC");
g:	while(readdata!=0xfe){spi_read();}
	for(int g=0;g<512;g++)
		{
		spi_read();		__delay_us(16.5);
		CCPR2L=readdata;
		PORTD=~readdata;
	
		}
	spi_write(0xff);
	spi_write(0xff);
	if(RE0==1)
		{
		command(12,arg,0xff);
		spi_read();
		while(readdata!=0){spi_read();}
		while(readdata!=0xff){spi_read();}
		goto exit2;
		}
	goto g;
exit2:pwm_disable();
	}
/*--------------------mmc end----------------------*/

/*-----------------ADC functions-------------------*/
void adc_init()
{
TRISA0=1;
ADCON0=0b10000001;
ADCON1=0b10001110;
}
main()
{
CS=1;PORTD=0;
TRISC4=0;TRISC5=0;TRISD=0;TRISB2=0;TRISB1=0;
TRISE0=1;
lcd_init();
adc_init();
usrt_init();
spi_init();
mmc_init();
pwm_init();
lcd_init();
count=0;
CS=0;
mul=1;arg=0;
while(1)
	{
arg=0;
fst;
string("READ MODE");
__delay_ms(1000);
read();
arg=0;
fst;
string("WRITE MODE");
__delay_ms(1000);
write();
	}
}
I am not telling that this is an efficient code, now i think i can modify it much more. In above program, i am waiting for ADC to complete, without doing any job. I think its better to send converted Digital value to MMC while ADC starts next conversion. Similarly, much modifications could be done to make it more efficient.
 
Last edited:

eagv

Newbie level 3
Joined
May 20, 2010
Messages
3
Helped
0
Reputation
0
Reaction score
0
Trophy points
1,281
Activity points
1,299
The main problem is RAM in PIC16F877A. Generally, u need RAM of above 512 bytes for efficient FAT file system access. Better solution is go for PIC18F series.
-----------------------------------
I had done a digital voice recorder and play back system with MMC and PIC16F877A but it doesn't have any file system. It just write and read from a particular sector to its last sector.(i think u had seen that video).I didn't used RAM buffer but continuously read bytes and send each byte to PWM just after reading the byte. I am posting the code at the bottom.
-----------------------------------
And i also wrote code to access FAT filesystem using PIC16F877A. But i doubt that the code is less efficient and may not be good for audio streaming. I can display ASCII-text files(copied to FAT16 mmc) in an LCD using PIC16F877A. The difficult part is reading the FAT(file allocation table) in the MMC (to get next sector address of the playing file) after streaming each cluster. If u could do it in most efficient manner, then i think u can play an audio using PIC16F877A. Any way, i stopped my activities since its our exam time, and i will continue after exam. My aim is to play wav files in FAT16 mmc using this PIC.
----------------------------------
Code:
///////////////////////////////////////////////////////////////////////
// [U]my first digital voice recorder using PIC16F877A and MMC[/U]//
//   push button at RE0 to select play or record mode           //
// http://www.youtube.com/watch?v=Mn1VsM-i8QI             //
///////////////////////////////////////////////////////////////////////
#include<pic.h>
#define _XTAL_FREQ 20e6
#define CS RC2
#define RS RB2
#define EN RB1
#define fst cmd(0x80)
#define snd cmd(0xc0)
unsigned int i;
unsigned char j,k,rec,dat,tempbuf,readdata,u;
unsigned int count;unsigned long int wcount;
unsigned long int mul=1,arg=0;
	const char *q="VINOD ";
/*-----------------LCD BEGIN----------------------------*/
void LCD_STROBE(void)
	 {
	EN = 1;
	__delay_us(0.5);
	EN = 0;
	}
void data(unsigned char c)
	{ 
	RS=1;
	__delay_us(40); PORTD = ( c >> 4 );LCD_STROBE();
	PORTD = ( c );LCD_STROBE(); 
	}
void cmd(unsigned char c)
	{
	 RS=0;
	__delay_us(40); PORTD = ( c >> 4 );LCD_STROBE();
	PORTD = ( c  );LCD_STROBE();
	}
void clear(void)
	{
	 cmd(0x01);
	__delay_ms(2);
	}
void lcd_init()
	{ 
	__delay_ms(20);
	cmd(0x30 );
	__delay_ms(1);
	cmd(0x30 );
	__delay_ms(1);
	cmd(0x30 );
	cmd(0x28 ); // Function set (4-bit interface, 2 lines, 5*7Pixels)
	cmd(0x28 ); // Function set (4-bit interface, 2 lines, 5*7Pixels)
	cmd(0x28 ); // Function set (4-bit interface, 2 lines, 5*7Pixels)
	cmd(0x0c); // Make cursorinvisible
	clear();
	clear(); // Clear screen 
	cmd(0x6); // Set entry Mode
	}
void string(const char *q)
	{
	clear();
	while(*q) {data(*q++);}
	}


void istring(unsigned int q)
	{
	cmd(0x81);
	data(48+(q/100));q%=100;
	data(48+(q/10));q%=10;
	data(48+(q));
	__delay_ms(500);
	}
/*-----------------------LCD END--------------------*/

/*-----------------------USRT BEGIN--------------------*/
void usrt_init()
	{

	TRISC6=0;
	TXSTA=0b00100110;
	RCSTA=0b11010000;
	SPBRG=10;
	}
void printf(const char *p)
	{
	while(*p)
		{
		TXREG=*p;
		while(TRMT==0);
		p++;
		}
	}
void txd(unsigned char vv)
        {
        TXREG=vv;
        while(TRMT==0);
        }
  /*-----------------------USRT END-------------------*/
  
/*----------------------PWM BEGINS--------------------*/
void pwm_init()
{
TRISC1=0;
T2CKPS1=0;T2CKPS0=0;
PR2=0x50;
CCPR2L=0x17;
TMR2ON=1;
CCP2CON=0b00001100;
}
void pwm_disable(){CCP2CON=0b00000000;}
void pwm_enable(){CCP2CON=0b00001100;}

/*--------------------PWM END------------------------*/

/*-------------------mmc BEGIN-----------------------*/
void spi_init()
	{
	TRISC4=1;
	RC2=1;RC3=0;RC5=0;
	TRISC2=TRISC3=TRISC5=0;
	SSPCON=0b00100010;
	SSPEN=1;
	SMP=1;
	CKE=1;
	CKP=0;
	}

 void spi_write(unsigned char kk)
	 {
	  SSPBUF=kk;
	  while(BF==0);
	 }
 void spi_read()
	{
   	SSPBUF=0xff;
	while(BF==0);
	readdata=SSPBUF;
	}

void command(char command, unsigned long int fourbyte_arg, char CRCbits )
	{
	spi_write(0xff);
	spi_write(0b01000000|command);
	spi_write((unsigned char)(fourbyte_arg >> 24));
	spi_write((unsigned char)fourbyte_arg >> 16);
	spi_write((unsigned char)(fourbyte_arg >> 8));
	spi_write((unsigned char)fourbyte_arg);
	spi_write(CRCbits);
	spi_read();
	}

void mmc_init()
{	
	CS=1;
	for(u=0;u<50;u++){spi_write(0xff);}
	CS=0;
	__delay_ms(1);
	command(0,0,0x95);
	count=0;
	while((readdata!=1)&&(count<1000)){spi_read();count++;}
	if(count>=1000){string("CARD ERROR-CMD0 ");while(1);}
	command(1,0,0xff);
	count=0;
	while((readdata!=0)&&(count<1000)){command(1,0,0xff);spi_read();count++;}
	if(count>=1000){string("CARD ERROR-CMD1 ");while(1);}
	command(16,512,0xff);
	count=0;
	while((readdata!=0)&&(count<1000)){spi_read();count++;}
	if(count>=1000){string("CARD ERROR-CMD16");while(1);}
	string("MMC INITIALIZED!");__delay_ms(1000);
	SSPCON=SSPCON&0b11111101;
}

void write()
	{
	pwm_disable();	
	/*write*/
	command(25,arg,0xff);
	while(readdata!=0){spi_read();string("WRITE ERROR");}
	string("WRITING MMC");
h:	spi_write(0xff);
	spi_write(0xff);
	spi_write(0b11111100);
	for(int g=0;g<512;g++)
		{
		ADGO=1;
		while(ADGO);
		spi_write(ADRESL);	PORTD=~ADRESL;
		}
	spi_write(0xff);
	spi_write(0xff);
	spi_read();
	while((readdata&0b00011111)!=0x05){spi_read();}
	while(readdata!=0xff){spi_read();}
	if(RE0==1)
	{
	spi_write(0xff);
	spi_write(0xff);
	spi_write(0b11111101); //stop token
	spi_read();spi_read();
	while(readdata!=0xff){spi_read();}
	goto exit1;
	}
	goto h;
exit1:;
	}
void read()
	{
	pwm_enable();

	command(18,(arg),0xff);
	while(readdata!=0){spi_read();	string("READ ERROR");}
	string("READING MMC");
g:	while(readdata!=0xfe){spi_read();}
	for(int g=0;g<512;g++)
		{
		spi_read();		__delay_us(16.5);
		CCPR2L=readdata;
		PORTD=~readdata;
	
		}
	spi_write(0xff);
	spi_write(0xff);
	if(RE0==1)
		{
		command(12,arg,0xff);
		spi_read();
		while(readdata!=0){spi_read();}
		while(readdata!=0xff){spi_read();}
		goto exit2;
		}
	goto g;
exit2:pwm_disable();
	}
/*--------------------mmc end----------------------*/

/*-----------------ADC functions-------------------*/
void adc_init()
{
TRISA0=1;
ADCON0=0b10000001;
ADCON1=0b10001110;
}
main()
{
CS=1;PORTD=0;
TRISC4=0;TRISC5=0;TRISD=0;TRISB2=0;TRISB1=0;
TRISE0=1;
lcd_init();
adc_init();
usrt_init();
spi_init();
mmc_init();
pwm_init();
lcd_init();
count=0;
CS=0;
mul=1;arg=0;
while(1)
	{
arg=0;
fst;
string("READ MODE");
__delay_ms(1000);
read();
arg=0;
fst;
string("WRITE MODE");
__delay_ms(1000);
write();
	}
}
I am not telling that this is an efficient code, now i think i can modify it much more. In above program, i am waiting for ADC to complete, without doing any job. I think its better to send converted Digital value to MMC while ADC starts next conversion. Similarly, much modifications could be done to make it more efficient.


Hi Vinodstanur, I was wondering if you figured out your problem.. I too have problems reading the next cluster from the FAT table... it kind of slows down audio playback since it takes a while to read 512 bytes from the FAT. For this reason, I cannot hear fluid, constant audio streaming each time the pic looks for the next cluster.

Did you find a way or another method to overcome this problem? Or could you provide me with any suggestion?

Thank you!
 

eagv

Newbie level 3
Joined
May 20, 2010
Messages
3
Helped
0
Reputation
0
Reaction score
0
Trophy points
1,281
Activity points
1,299
Thanks, this helped me figure it out!
 

amnamirza901

Newbie level 1
Joined
Jul 25, 2012
Messages
1
Helped
0
Reputation
0
Reaction score
0
Trophy points
1,281
Activity points
1,286
hi i want to ask if i have counting .wav files upto 999 in sd card is it possible to access these files with some switch and trigger means there would be thre switches so one is up second is down and third is reset so up goes to next counting voice down goes to previous counting voice and reset goes to start of couting voice but it all happen on switch strike please tll me is it possible in this way
 

Status
Not open for further replies.

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Top