ATMEGA+SD+WAV

Вопросы настройки, программирования, прошивки микроконтроллеров и микросхем программируемой логики
SABRAT
Первый раз сказал Мяу!
Сообщения: 28
Зарегистрирован: Вт июн 24, 2008 17:17:08
Откуда: Киев

ATMEGA+SD+WAV

Сообщение 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
kaspersky89
Родился
Сообщения: 12
Зарегистрирован: Пн янв 03, 2011 12:02:45
Откуда: Брянск
Контактная информация:

Re: ATMEGA+SD+WAV

Сообщение kaspersky89 »

Было дело, разрабатывал речевой информатор для автомобиля. Тоже были щелчки, в самом начале воспроизведения, и по ходу самого воспроизведения. Правдо у меня звук не через ШИМ выводился, а посредством ЦАП на резисторах. Сейчас времени нету, нужно на работу, вечером скину часть исходников, может поможет чем.
Аватара пользователя
asteroid7
Опытный кот
Сообщения: 703
Зарегистрирован: Вс янв 18, 2009 21:12:49

Re: ATMEGA+SD+WAV

Сообщение asteroid7 »

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

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

Скорости mega64/11059200/PWM 8 bit 22 kHz мне хватало для воспроизведения с SD FAT16/32 (elm-chan) WAV файлов с дискретизацией 11/22/44 кГц стерео.
Аватара пользователя
urry
Сверлит текстолит когтями
Сообщения: 1262
Зарегистрирован: Пн дек 08, 2008 10:58:48
Откуда: Винница
Контактная информация:

Re: ATMEGA+SD+WAV

Сообщение urry »

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

упс, уже опоздал
SABRAT
Первый раз сказал Мяу!
Сообщения: 28
Зарегистрирован: Вт июн 24, 2008 17:17:08
Откуда: Киев

Re: ATMEGA+SD+WAV

Сообщение SABRAT »

Благодарю за ответы.
Извиняюсь за наглость, а можно кусочек кода а не весь проэкт?
kaspersky89
Родился
Сообщения: 12
Зарегистрирован: Пн янв 03, 2011 12:02:45
Откуда: Брянск
Контактная информация:

Re: ATMEGA+SD+WAV

Сообщение 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;

}


};

phanis
Вымогатель припоя
Сообщения: 513
Зарегистрирован: Сб фев 19, 2011 18:04:08
Откуда: Татарстан, пос. Актюбинский
Контактная информация:

Re: ATMEGA+SD+WAV

Сообщение 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;
    
     }
}
Аватара пользователя
БАТАРЕЙКУС
Потрогал лапой паяльник
Сообщения: 346
Зарегистрирован: Сб фев 07, 2009 19:21:25

Re: ATMEGA+SD+WAV

Сообщение БАТАРЕЙКУС »

необязательно делать кольцевой буфер. намного проще считывать скажем 500байт по очереди. считал воспроизвёл считал воспроизвёл итд. а на последок 12 байт считываешь в буфер и пака SD-карта недоступна эти байты потихоньку выкидываешь. нужно лишь помнить что время обновления буфера у SD-карта около 500мксек. это я замерял на ММС 32Мб от нокиа 6230. такой метод я использовал для своего плеера WAV-16КГц/8бит, на PIC16F876A, который гораздо медленней и обделённый ОЗУ по сравнению с AVR
Мечтатель - не тот, кто сидит на диване и думает о несбыточном, а тот, кто всеми силами стремится воплотить несбыточное в реальность.
SABRAT
Первый раз сказал Мяу!
Сообщения: 28
Зарегистрирован: Вт июн 24, 2008 17:17:08
Откуда: Киев

Re: ATMEGA+SD+WAV

Сообщение SABRAT »

БАТАРЕЙКУС писал(а):необязательно делать кольцевой буфер. намного проще считывать скажем 500байт по очереди. считал воспроизвёл считал воспроизвёл итд.


Как раз при таком варианте, в паузе при считывании очередных 500 байт происходит "треск" в воспроизведении звука.
У Вас не так?
Аватара пользователя
БАТАРЕЙКУС
Потрогал лапой паяльник
Сообщения: 346
Зарегистрирован: Сб фев 07, 2009 19:21:25

Re: ATMEGA+SD+WAV

Сообщение БАТАРЕЙКУС »

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-карты.
Мечтатель - не тот, кто сидит на диване и думает о несбыточном, а тот, кто всеми силами стремится воплотить несбыточное в реальность.
HeLiO
Первый раз сказал Мяу!
Сообщения: 29
Зарегистрирован: Пн дек 27, 2010 14:37:38

Re: ATMEGA+SD+WAV

Сообщение 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 при таком раскладе (держало бы и стерео да другой хрени навалом было :) )
Аватара пользователя
Aheir
Модератор
Сообщения: 4517
Зарегистрирован: Пн апр 03, 2006 11:43:25
Откуда: Санкт - Петербург
Контактная информация:

Re: ATMEGA+SD+WAV

Сообщение Aheir »

Из своего опыта - я как раз с двумя буферами делал. Когда вычитывал один из них до половины, начинал заполнять другой... Достаточно было буферов небольшого размера, все работало совершенно без сбоев.
Оптимизм х (Опыт + Знания) = const
HeLiO
Первый раз сказал Мяу!
Сообщения: 29
Зарегистрирован: Пн дек 27, 2010 14:37:38

Re: ATMEGA+SD+WAV

Сообщение HeLiO »

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



см сообщение выше
Аватара пользователя
БАТАРЕЙКУС
Потрогал лапой паяльник
Сообщения: 346
Зарегистрирован: Сб фев 07, 2009 19:21:25

Re: ATMEGA+SD+WAV

Сообщение БАТАРЕЙКУС »

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



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


а я даже мультики воспроизводил на экране WG-12864. нарисованные программой KS0108_3_4 скачанной с http://ikarab.narod.ru/KS0108.html.
Мечтатель - не тот, кто сидит на диване и думает о несбыточном, а тот, кто всеми силами стремится воплотить несбыточное в реальность.
SABRAT
Первый раз сказал Мяу!
Сообщения: 28
Зарегистрирован: Вт июн 24, 2008 17:17:08
Откуда: Киев

Re: ATMEGA+SD+WAV

Сообщение SABRAT »

Благодарю всех за ответы! Всё получилось!!! Сделал с двумя буферами по 128 байт. Если кому интересно - могу выложить проэктик.
Gura
Родился
Сообщения: 9
Зарегистрирован: Пн дек 15, 2008 18:26:49

Re: ATMEGA+SD+WAV

Сообщение Gura »

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

Конечно интересно-выкладывай! 8)
HeLiO
Первый раз сказал Мяу!
Сообщения: 29
Зарегистрирован: Пн дек 27, 2010 14:37:38

Re: ATMEGA+SD+WAV

Сообщение HeLiO »

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



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


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

ненавижу эту хрень, делаю только на работе эти проги для МК, а дома музыку пишу)) вот до чего ккризис доводит..)))
HeLiO
Первый раз сказал Мяу!
Сообщения: 29
Зарегистрирован: Пн дек 27, 2010 14:37:38

Re: ATMEGA+SD+WAV

Сообщение HeLiO »

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

а чего не с 1680- ю байтами?
SABRAT
Первый раз сказал Мяу!
Сообщения: 28
Зарегистрирован: Вт июн 24, 2008 17:17:08
Откуда: Киев

Re: ATMEGA+SD+WAV

Сообщение SABRAT »

вот выкладываю...получилосьчто-то вроде библиотеки, писал под WinAVR
Вложения
Sound-lib.rar
(1.25 КБ) 564 скачивания
Аватара пользователя
Aheir
Модератор
Сообщения: 4517
Зарегистрирован: Пн апр 03, 2006 11:43:25
Откуда: Санкт - Петербург
Контактная информация:

Re: ATMEGA+SD+WAV

Сообщение Aheir »

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



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


Да умница, умница, я ж пишу: "Из своего опыта" - делюсь, так сказать, не претендуя на истину.
Оптимизм х (Опыт + Знания) = const
Закрыто

Вернуться в «Микроконтроллеры и ПЛИС»