Страница 1 из 2

ATMEGA+SD+WAV

Добавлено: Вт фев 22, 2011 01:09:57
SABRAT
Возникла проблемка при воспроизведении WAV с SD карты.
Исходные данные:
Atmega64 11.059200 МГц
Аудио выход OC0(PortB.4) через RC -> УНЧ
Вывод по средствам ШИМ (Fast PWM 8-bit Timer/Counter 0)
Работа с SD(FAT16) при использовании библиотеки Elm-Chan
Звуковой файл WAV PCM 8 бит 11.025 кГц (без RIFF заголовка, формат данных unsigned)
Компилятор WinAVR-20100110

Код(только то что касается вывода звука):

#define BUF_SIZE 512

unsigned char sound_buf[BUF_SIZE];
int count_buff;

ISR(TIMER2_COMP_vect) // Выполняется с частотой 11.025 кГц
{
cli();
OCR0=sound_buf[count_buff]; //Выводим очередной байт из звукового буфера в ШИМ
count_buff++; // Следующий....


TCNT2 = 0xC2; //init //Инициализация значения счётчика TC2
OCR2 = 0x32; //11.025

sei();

if(count_buff==BUF_SIZE+1)
{
count_buff=0;
res = pf_read(sound_buf, BUF_SIZE, &s1);//Считаем следующие 512 байт из 1.wav
}


}

Суть проблемы вот в чём. Собственно качество воспроизведения полностью перекрывает мои задачи, но есть одно НО.
Во время воспроизведения отчётливо слышны периодичесские "потрескивания". Опытным путём (смена частоты дискретизации и размера буффера)
было установлено, что они возникают в момент считывания (обновления буфера).

Вопрос:
Как можно исправить данную ситуацию. Возможно я плохо продумал алгоритм и есть у кого-то отработанные варианты
или кто-то уже наступал на подобные грабли?

Заранее благодарю за помощь!

С ув. SABRAT

Re: ATMEGA+SD+WAV

Добавлено: Вт фев 22, 2011 08:39:29
kaspersky89
Было дело, разрабатывал речевой информатор для автомобиля. Тоже были щелчки, в самом начале воспроизведения, и по ходу самого воспроизведения. Правдо у меня звук не через ШИМ выводился, а посредством ЦАП на резисторах. Сейчас времени нету, нужно на работу, вечером скину часть исходников, может поможет чем.

Re: ATMEGA+SD+WAV

Добавлено: Вт фев 22, 2011 08:47:43
asteroid7
Вас спасёт кольцевой буфер на 256 байт, где есть голова и хвост. В голову грузятся значения WAV файла, с хвоста считываются в прерывании ISR(TIMER2_COMP_vect). Обратите особое внимание на проверки по опустошению и переполнению кольцевого буфера. Там есть "критические секции".

Т.е. в основном цикле программы считывается сектор в 512 файловый буфер, а оттуда в своём цикле грузится в кольцевой буфер. При переполнении последнего - отдыхаем, ожидая прерывания таймера.

Скорости mega64/11059200/PWM 8 bit 22 kHz мне хватало для воспроизведения с SD FAT16/32 (elm-chan) WAV файлов с дискретизацией 11/22/44 кГц стерео.

Re: ATMEGA+SD+WAV

Добавлено: Вт фев 22, 2011 08:53:33
urry
считывать в буфер нужно непркрывно, пока есть возможность (пока не наехали на другой указатель). Буфер должен быть кольцевым.
Пример здесь http://vrtp.ru/index.php?showtopic=14534

упс, уже опоздал

Re: ATMEGA+SD+WAV

Добавлено: Вт фев 22, 2011 12:38:58
SABRAT
Благодарю за ответы.
Извиняюсь за наглость, а можно кусочек кода а не весь проэкт?

Re: ATMEGA+SD+WAV

Добавлено: Вт фев 22, 2011 17:29:21
kaspersky89
Как и обещал привожу кусок кода отвечающего за воспроизведение, там где кольцевой буфер, без него никуда. Может будет полезен, там немного прокомментировал. Вобщем кто захочет, разберётся.
Mega32 16Mhz компилятор-IAR

Код: Выделить всё

unsigned int                    countmus=0,i;  
volatile unsigned char          data[256]; //Буфер для считывания звука с карты
unsigned char			song;
unsigned char			play,is_play;
unsigned char			gotoNextSong;

typedef struct
{
	unsigned char id_riff[4];	// 4 byte
	unsigned long len_riff;		// 4 byte

	unsigned char id_chuck[4];	// 4 byte
	unsigned char fmt[4];		// 4 byte
	unsigned long len_chuck;	// 4 byte

	unsigned int  type;			// 2 byte
	unsigned int  channels;		// 2 byte
	unsigned long freq;			// 4 byte
	unsigned long bytes;		// 4 byte
	unsigned int  align;		// 2 byte
	unsigned int  bits;			// 2 byte

	unsigned char id_data[4];	// 4 byte
	unsigned long len_data;		// 4 byte
} TitleWave;// 44 byte

unsigned char			song;
unsigned char			play;
unsigned char			gotoNextSong;
__flash char			FileNames [10][11] =
{
	"muson01.wav","muson02.wav","muson03.wav","muson04.wav","muson05.wav",
	"muson06.wav","muson07.wav","muson08.wav","muson09.wav","muson10.wav"
};
unsigned char WaveComp (char const __flash name[])
{
	//~~~~~~~~~~~~~
	FILE		*f;
	TitleWave	tw;
	//~~~~~~~~~~~~~

	f = fopenc(name,READ);
	if ( f==0 ) return (1);									// ?? ??????? ????
	fread(&tw,sizeof(TitleWave),1,f);
	fclose(f);
	
	if ( strncmp_G(tw.id_riff,"RIFF",4) != 0 ) return (1);	// ?? ?????? ????????????? RIFF
	if ( strncmp_G(tw.id_chuck,"WAVE",4) != 0 ) return (1);	// ?? ?????? ????????????? CHUCK
	if ( strncmp_G(tw.fmt,"fmt ",4)!= 0 ) return (1);		// ?? ?????? ????????????? FMT
	if ( tw.type != 1 ) return (1);							// ??? ?????? - ?? ???????
	if ( tw.channels != 1 ) return (1);						// ?? ????
	if ( tw.freq != 16000 ) return (1);						// ?? 16000 ???
	if ( tw.bytes != 16000 ) return (1);
	if ( tw.bits != 8 ) return (1);							// ?? 8 ???
	if ( strncmp_G(tw.id_data,"data",4)!= 0 )return (1);	// ?? ?????? ????????????? DATA
	
	return (0);
}
        
        

/*
=====================
	MAIN.
=====================
*/
void main ()
{
    //~~~~~~~~~~
	FILE	*fp;
	//~~~~~~~~~~
        PORTA_Bit4 = 1; 
        while (!initialize_media());
        PORTA_Bit4 = 0; 
        ACSR &=~(1 << ACD);	//disable comparator! for safe power
		
	Init_port();
	
    PCMDDR = 0xFF;  //порт на котором весит ЦАП
	PCMPort = 0x00;

    MCUCR |= (1 << SE);
    TCCR0 |= (1 << CS01);
	TCNT0 = 140;
	TIMSK |= (1 << TOIE0);


        SEI();
		
        play=1; // разрешаем воспроизведение
        song=0; // трэк под индексом 0       


	while(1)
	{

               		if (play)//---------------------------------------------
		{
			// Запускаем таимер 0
			TCCR0 |= (1 << CS01);
			TCNT0 = 140;
			// Включаем на нём прерывание
			TIMSK |= (1 << TOIE0);
			
			if (!WaveComp (FileNames[song])) // Если тип трэка тот что нужен
			{
				fp = fopenc(FileNames[song], READ); // открывем его на чтение
				while ( ((fp -> position) < (fp -> length)) && !gotoNextSong ) // пока не дошли до конца
				{
                                 if (!countmus){
                                     for (i=0;i<256;i++)
                                     data[i]=fgetc(fp);  // заполняем побайтно буфер
                                     }                   // тем что прочитали из трэка
				};
                 SLEEP();
				fclose(fp); // если дошли до конца , закрываем файл
				if (!gotoNextSong) play = 0;
				gotoNextSong = 0;
			}
			else song = 0;
			
			// Тормозим таймер и прерывание на нём
			TCCR0 &= ~(1 << CS01);
			TIMSK &= ~(1 << TOIE0);
		};//------------------------------------------------------------
               

        } 
}

#pragma vector = TIMER0_OVF_vect
__interrupt void Timer0_Ovf (void)
{
         PCMPort=data[countmus]; 
         if (countmus<255) countmus++;
         else countmus=0;
         TCNT0 = 140;

}


};


Re: ATMEGA+SD+WAV

Добавлено: Ср фев 23, 2011 21:32:22
phanis
Можно на 2 половины поделить буфер пример

Код: Выделить всё

//IAR 5.50
#define ENABLE_BIT_DEFINITIONS
#include <ioavr.h>



#define OUT1   3  //
#define OUT2   4  // 

#define SD_CS 0
#define SDI   5  //
#define SDO   6  // 
#define SCK   7  // 


#define AUDIO_BUFFER 32
#define CENTER AUDIO_BUFFER>>1

#define SD_CS_OFF()		PORTB |= 1<<SD_CS
#define SD_CS_ON()		PORTB &= 0xFF-(1<<SD_CS)


#define TRUE  1
#define FALSE 0

	
	#define uchar	unsigned char
	#define uint	unsigned int	
	#define ulong	unsigned long
	#define schar	char
	#define sint	int	
	#define slong	long
 


#define START_TIMER_0  TCCR0B = 0x02 //start timer 
#define STOP_TIMER_0   TCCR0B = 0x00


//void putchar(char TX);


void PLAY_WAV(void);

unsigned char	audio_data_count;
unsigned char	play;
//unsigned char	temp_uart;
unsigned char	SOUND_N;


#include "flash\file_sys.h"
#include "flash\file_sys.c"




void main(void)
{ 
  asm("cli");

        PORTB |= (1<<SDO)|(1<<SDI)|(1<<SD_CS);        
        DDRB |= (1<<SCK)|(1<<SDO)|(1<<SD_CS)|(1<<OUT1)|(1<<OUT2); 
        USICR = (1<<USIWM0)|(1<<USICS1)|(1<<USICLK);
            
    TIMSK  = 0x02; //timer interrupt sources

//UBRRL = 0x67; //set baud rate lower

//UCSRC = 0x06;
//UCSRB = 0x98; //enable
 



 TCCR1A = 0xA1;
 
    
SOUND_N=0x30;
  

asm("sei");
while(1)
{
        _FF_buff[0 ]=SOUND_N;
        _FF_buff[1 ]=0x20;
        _FF_buff[2 ]=0x20;
        _FF_buff[3 ]=0x20;
        _FF_buff[4 ]=0x20;
        _FF_buff[5 ]=0x20;
        _FF_buff[6 ]=0x20;
        _FF_buff[7 ]=0x20;
        _FF_buff[8 ]='W';
        _FF_buff[9 ]='A';
        _FF_buff[10]='V';
	_FF_buff[11]= 0 ;

    

        
      

PLAY_WAV();
SOUND_N++;

if (!SOUND_N) SOUND_N=0x30;

}
}

void PLAY_WAV()
 {
int i=4096;
char i2;

STOP_TIMER_0;

if( fopenc() )

	                 {
					

					    while(i--)   
						{if ( ((rp -> position) < (rp -> length))  )
						{
						   GET_BYTE();					
						   if(i<AUDIO_BUFFER) _FF_buff[i]=0x00; 
					     }
						}
						

					     audio_data_count=0;
						 
						 play=0;
                                                 
                                                 TCCR1B = 0x09; //start Timer
		
					  START_TIMER_0;
					     
						 while ( ((rp -> position) < (rp -> length))  )
				          { 

 switch (play)
					 	    {
					  		
							case 1:
							       {
								    play=0;
									for (i2=0;i2<CENTER;i2++)  _FF_buff[i2]=GET_BYTE();
									}break; 	
					   
					   		case 2:{
							        play=0;
							        for (i2=CENTER;i2<AUDIO_BUFFER;i2++)   _FF_buff[i2]=GET_BYTE();
									}break;	
							   		   
                           } 
		
			           }
			  
                           
		              
					   }
TCCR1B = 0x00; //start Timer
	
//STAT=0;
					   
STOP_TIMER_0;
                      
SD_CS_OFF(); 	

}

#pragma vector = TIMER0_OVF0_vect
__interrupt void Timer0_Ovf (void)

{
TCNT0 = 0xd5; //reload counter value

 OCR1AL  = (0x80+_FF_buff[audio_data_count+1]);;
 OCR1BL  =_FF_buff[audio_data_count] ;

 audio_data_count+=2;
 switch(audio_data_count)
       {
        case AUDIO_BUFFER: 
        {
           play=2;
  audio_data_count=0;
        }break;
        case CENTER: play=1; break;
	  
	  }
}

Re: ATMEGA+SD+WAV

Добавлено: Чт фев 24, 2011 00:09:04
БАТАРЕЙКУС
необязательно делать кольцевой буфер. намного проще считывать скажем 500байт по очереди. считал воспроизвёл считал воспроизвёл итд. а на последок 12 байт считываешь в буфер и пака SD-карта недоступна эти байты потихоньку выкидываешь. нужно лишь помнить что время обновления буфера у SD-карта около 500мксек. это я замерял на ММС 32Мб от нокиа 6230. такой метод я использовал для своего плеера WAV-16КГц/8бит, на PIC16F876A, который гораздо медленней и обделённый ОЗУ по сравнению с AVR

Re: ATMEGA+SD+WAV

Добавлено: Чт фев 24, 2011 13:47:46
SABRAT
БАТАРЕЙКУС писал(а):необязательно делать кольцевой буфер. намного проще считывать скажем 500байт по очереди. считал воспроизвёл считал воспроизвёл итд.
Как раз при таком варианте, в паузе при считывании очередных 500 байт происходит "треск" в воспроизведении звука.
У Вас не так?

Re: ATMEGA+SD+WAV

Добавлено: Чт фев 24, 2011 21:49:59
БАТАРЕЙКУС
SABRAT писал(а): Как раз при таком варианте, в паузе при считывании очередных 500 байт происходит "треск" в воспроизведении звука.
У Вас не так?
зачем вам считывать 500байт?????
обьесняю алгоритм, допустим вы сделали WAV-16КГц/8бит. это соответствует периуду 62,5 мксек между сменами байтов в модуле ШИМ или ЦАП (через что воспроизводится звук). 62,5 мксек это достаточно много особенно для Атмеги.
512/16 = 32. - 512 байт в секторе, 16-за раз скачиваемых байт в буфер Атмеги, 32- прохода
512/32 = 16. - 512 байт в секторе, 32-за раз скачиваемых байт в буфер Атмеги, 16- прохода
можете использовать первый или второй вариант в зависимости возможностей.

итого получается вы считали 16 байт за раз, между временим пака воспроизводится байт. и ожидаете его окончания, затем заменяете в ШИМ-модуле байт и снова ждёте 62,5 мксек и так пака буфер в Атмеге не опустеет, при записи последнего байта из ОЗУ Атмеги, программа снова считывает 16 байт и так 32 раза. Последний раз, когда программа 32-ой раз считывает 16 байт с сектора SD-карты(32х16=512) у вас в ОЗУ Атмеги остаются 16 байт звука. а SD-карты карта обновляет свой буфер.(это 500мксек). и пака SD-карты недоступна Атмега потихоньку растрачивает байты из своего ОЗУ. кагда весе байты из ОЗУ Атмеги улетят в ШИМ, буфер SD-карты будет обновлён, так как 62,5мксек Х 16 = 1000мксек. что гораздо больше времени обновления буфер SD-карты.

Re: ATMEGA+SD+WAV

Добавлено: Сб фев 26, 2011 18:38:36
HeLiO
БАТАРЕЙКУС писал(а):
SABRAT писал(а): Как раз при таком варианте, в паузе при считывании очередных 500 байт происходит "треск" в воспроизведении звука.
У Вас не так?
зачем вам считывать 500байт?????
обьесняю алгоритм, допустим вы сделали WAV-16КГц/8бит. это соответствует периуду 62,5 мксек между сменами байтов в модуле ШИМ или ЦАП (через что воспроизводится звук). 62,5 мксек это достаточно много особенно для Атмеги.
512/16 = 32. - 512 байт в секторе, 16-за раз скачиваемых байт в буфер Атмеги, 32- прохода
512/32 = 16. - 512 байт в секторе, 32-за раз скачиваемых байт в буфер Атмеги, 16- прохода
можете использовать первый или второй вариант в зависимости возможностей.

итого получается вы считали 16 байт за раз, между временим пака воспроизводится байт. и ожидаете его окончания, затем заменяете в ШИМ-модуле байт и снова ждёте 62,5 мксек и так пака буфер в Атмеге не опустеет, при записи последнего байта из ОЗУ Атмеги, программа снова считывает 16 байт и так 32 раза. Последний раз, когда программа 32-ой раз считывает 16 байт с сектора SD-карты(32х16=512) у вас в ОЗУ Атмеги остаются 16 байт звука. а SD-карты карта обновляет свой буфер.(это 500мксек). и пака SD-карты недоступна Атмега потихоньку растрачивает байты из своего ОЗУ. кагда весе байты из ОЗУ Атмеги улетят в ШИМ, буфер SD-карты будет обновлён, так как 62,5мксек Х 16 = 1000мксек. что гораздо больше времени обновления буфер SD-карты.



вот полностью согласен. Ну нафига устраивать геморрой с буфером в 512 кб (ппц просто) и каким то кольцевыми буфeрАми?! я настраивал звук на 8 бит МК с 256 байтами оперативки из которых я мог использовать только 140 - и всё работало да еще ГЭПЭЭСКА была прикручена)
суть в том чтобы в прерывании сбрасывать счетчик кидать в ШИМ байт звука (уже заранее вкусно приготовленный), потом считать следующий и ждать наступление следующего прерывания. ВСЁ!! Да , еще есть момент когда кончается сектор. Ну тоже не проблема - считали 512 байт, потом 2 КС потом ждём 0xFE , пришёл, читаем байт и ждём конца прерывания -у меня держало даже 44 khz mono при таком раскладе (держало бы и стерео да другой хрени навалом было :) )

Re: ATMEGA+SD+WAV

Добавлено: Пн фев 28, 2011 23:34:55
Aheir
Из своего опыта - я как раз с двумя буферами делал. Когда вычитывал один из них до половины, начинал заполнять другой... Достаточно было буферов небольшого размера, все работало совершенно без сбоев.

Re: ATMEGA+SD+WAV

Добавлено: Ср мар 02, 2011 22:23:37
HeLiO
Aheir писал(а):Из своего опыта - я как раз с двумя буферами делал. Когда вычитывал один из них до половины, начинал заполнять другой... Достаточно было буферов небольшого размера, все работало совершенно без сбоев.

см сообщение выше

Re: ATMEGA+SD+WAV

Добавлено: Ср мар 02, 2011 23:47:18
БАТАРЕЙКУС
HeLiO писал(а):
Aheir писал(а):Из своего опыта - я как раз с двумя буферами делал. Когда вычитывал один из них до половины, начинал заполнять другой... Достаточно было буферов небольшого размера, все работало совершенно без сбоев.

см сообщение выше
а я даже мультики воспроизводил на экране WG-12864. нарисованные программой KS0108_3_4 скачанной с http://ikarab.narod.ru/KS0108.html.

Re: ATMEGA+SD+WAV

Добавлено: Пт мар 04, 2011 11:48:00
SABRAT
Благодарю всех за ответы! Всё получилось!!! Сделал с двумя буферами по 128 байт. Если кому интересно - могу выложить проэктик.

Re: ATMEGA+SD+WAV

Добавлено: Пт мар 04, 2011 15:03:21
Gura
SABRAT писал(а):Благодарю всех за ответы! Всё получилось!!! Сделал с двумя буферами по 128 байт. Если кому интересно - могу выложить проэктик.
Конечно интересно-выкладывай! 8)

Re: ATMEGA+SD+WAV

Добавлено: Сб мар 05, 2011 00:35:05
HeLiO
БАТАРЕЙКУС писал(а):
HeLiO писал(а):
см сообщение выше
а я даже мультики воспроизводил на экране WG-12864. нарисованные программой KS0108_3_4 скачанной с http://ikarab.narod.ru/KS0108.html.
ненавижу эту хрень, делаю только на работе эти проги для МК, а дома музыку пишу)) вот до чего ккризис доводит..)))

Re: ATMEGA+SD+WAV

Добавлено: Сб мар 05, 2011 00:36:05
HeLiO
SABRAT писал(а):Благодарю всех за ответы! Всё получилось!!! Сделал с двумя буферами по 128 байт. Если кому интересно - могу выложить проэктик.
а чего не с 1680- ю байтами?

Re: ATMEGA+SD+WAV

Добавлено: Сб мар 05, 2011 10:29:11
SABRAT
вот выкладываю...получилосьчто-то вроде библиотеки, писал под WinAVR

Re: ATMEGA+SD+WAV

Добавлено: Сб мар 05, 2011 19:17:15
Aheir
HeLiO писал(а):
Aheir писал(а):Из своего опыта - я как раз с двумя буферами делал. Когда вычитывал один из них до половины, начинал заполнять другой... Достаточно было буферов небольшого размера, все работало совершенно без сбоев.

см сообщение выше
Да умница, умница, я ж пишу: "Из своего опыта" - делюсь, так сказать, не претендуя на истину.