Страница 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 писал(а):
Aheir писал(а):Из своего опыта - я как раз с двумя буферами делал. Когда вычитывал один из них до половины, начинал заполнять другой... Достаточно было буферов небольшого размера, все работало совершенно без сбоев.



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


а я даже мультики воспроизводил на экране 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 писал(а):Из своего опыта - я как раз с двумя буферами делал. Когда вычитывал один из них до половины, начинал заполнять другой... Достаточно было буферов небольшого размера, все работало совершенно без сбоев.



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


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