WAV-аудиоплеер и треск при чтении с SD-карты по SPI

Обсуждаем контроллеры компании Atmel.
Ответить
Нашел транзистор. Понюхал.
Аватара пользователя
Сообщения: 190
Зарегистрирован: Вт янв 26, 2010 21:49:41
Откуда: モスクワ

Сообщение Zwanzig »

Всем привет! Пытаюсь собрать музыкальную шкатулку для любимой девушки, столкнулся с весьма странной проблемой.
ATmega32, к её PWM-выходам (OC1A/OC1B) подключен динамик (как в схеме Elm ChaN, прикрепил). На аппаратном SPI висит SD-карта.
С выводом 8-ми битного аудио на один выход PWM всё было окей, но как-то только решил запилить такой варик, чтобы получить 16 бит - появились искажения (к сожалению, звуковые файлы тут не прикрепить, так что дропбокс).

Теперь к подробностям. Эти искажения не такие сильные и на фоне музыки их почти не слышно. На прикреплённой записи я специально выводил... кхм, меандр с очень низкой частотой, а по факту - просто постоянный высокий уровень на выходе ШИМ (0xFFFF). Так вот, уровень этого треска коррелирует с уровнем сигнала (я пробовал также пилу, и громкость треска нарастала и падала). Т.к. максимальная громкость получается когда на выходе 0хFFFF, могу сделать вывод, что этот треск - короткие провалы до нуля.

Кроме того, я по сделанной записи замерил его частоту, и она получилась равной... ровно 256 семплам из буфера. Т.е., этот провал до нуля происходит каждые 256 семплов. Частота треска зависит от заданной частоты дискретизации, т.е. от частоты срабатывания сравнения таймера 2, но это не главное. В основном цикле каждые 256 семплов происходит обращение к SD через pf_read. Когда я закомментил обращения к SD (естественно, оставив первое, чтобы загрузить буфер и тупо выводить его по кругу), весь треск исчез. Т.е., этот чёртов провал по ходу возникает именно в момент обращения к карте памяти по SPI и чтении следующей порции данных.

Честно говоря, теряюсь в догадках, как слаботочный SPI может создавать какие-то наводки на мощные выходы ШИМа. У них даже порты разные, ШИМ на PortD, SPI на PortB. К тому же, как я уже написал, в версии с одним выходом на 8 бит такой проблемы не возникало. Если что, собрано всё на отладочной плате Pinboard, т.е. все фильтры по питанию и прочее стоит. Питается от USB компа.

Недокод:

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

#include <avr/interrupt.h>
#include "diskio.h"
#include "pff.h"
#include <util/delay.h>
 
unsigned char buffer[512];   /* буфер в который копируется инфа с флешки */
volatile unsigned int count; //счетчик скопированных данных
 
ISR(TIMER2_COMP_vect) //прерывание в котором выводим данные в PWM таймера 1
{
	unsigned int temp;
	temp = (unsigned int)((buffer[count+1]<<8) + buffer[count] + 32768);
    OCR1A = temp & 0xFF;  // выводим LSB
    OCR1B = temp >> 8; 	// выводим MSB
    count += 2;			// устанавливаем указатель на следующий семпл
    if (count >= 512) count = 0;// если 512 обнуляем 
}
 
int main()
{    
_delay_ms(700);
unsigned int br;         /* счетчик чтения/записи файла */      
unsigned char buf = 0;   //переменная определяющая какая часть буфера читается
FATFS fs;         /* Рабочая область (file system object) для логических дисков */
 
DDRD=(1<<PD5)|(1<<PD4);  	// устанавливаем пины PWM как выходы
DDRA = 0b00001111; 			// светодиоды состояния
 
// Timer/Counter 1 initialization
TCCR1A=(1<<COM1A1)|(1<<COM1B1)|(1<<WGM10); 	// clear output pin on compare (OC1A и OC1B), fast PWM 8 bit
TCCR1B=(1<<WGM12)|(1<<CS10); 	// fast PWM 8 bit + no prescaling (PWM freq = 65k)
OCR1A = 128;
OCR1B = 128;
 
// Timer/Counter 2 initialization
// Clock source: System Clock
// Clock value: 2 MHz
// Mode: CTC top=OCR2
TCCR2=(1<<WGM21)|(1<<CS21); // CTC mode, prescaler = 8 // 0x0B;
OCR2=250; //настройка регистра сравнения для 8кГц
//OCR2=91;    //для 22кГц
//OCR2 = 63; // для 32 кГц 
sei();
// Timer(s)/Counter(s) Interrupt(s) initialization
 
if(disk_initialize()==0) //инициализируем флешку
{
  PORTA = 1;
  pf_mount(&fs);  //монтируем файловую систему      
  pf_open("1.WAV");  //открываем вавку 
  pf_lseek(44);     //перемещаем указатель на 44  
  pf_read(buffer, 512, &br); //в первый раз заглатываем сразу 512байт
  PORTA = 2;
  TIMSK=(1<<OCIE2); //врубаем музон
  while(1) 
  {
     if(!buf && count>255) //если воспроизвелось больше 255 байт,  
     {                     
        pf_read(&buffer[0], 256, &br);//то читаем в первую половину буфера инфу с флешки
        buf=1; 
        if (br < 256) //если буфер не содержит 256 значений значит конец файла
  			break;
     }  
     if(buf && count<256)
     {
        pf_read(&buffer[256], 256, &br); // читаем во вторую часть буфера с флешки
        buf = 0; 
        if (br < 256)
          break;
     }
 
  }
  TIMSK = 0x00; //глушим все
  PORTA = 5;
  _delay_ms(1000);
  pf_mount(0x00); //демонтируем фат
  PORTA = 3;
}
else
  PORTA = 4;
 
while (1)
      {
 	PORTA = 15;
 
      }
}
Вложения
схема.png
(3.71 КБ) 536 скачиваний
Реклама
Мудрый кот
Сообщения: 1849
Зарегистрирован: Вс дек 25, 2016 08:34:54

Сообщение Dimon456 »

Zwanzig писал(а):temp = (unsigned int)((buffer[count+1]<<8) + buffer[count] + 32768);
OCR1A = temp & 0xFF; // выводим LSB
OCR1B = temp >> 8; // выводим MSB
Что за 32768?

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

        OCR1A = buffer[count]; //выводим LSB
        count++;
        OCR1B = buffer[count]; //выводим MSB
Реклама
Нашел транзистор. Понюхал.
Аватара пользователя
Сообщения: 190
Зарегистрирован: Вт янв 26, 2010 21:49:41
Откуда: モスクワ

Сообщение Zwanzig »

Dimon456 писал(а):Что за 32768?
Преобразование к беззнаковому целому. Семплы в 16-ти битные вавки пишутся в signed int, для ШИМа с фактическим диапазоном значений 0..65535 приходится их вот так пересчитывать.

Хотя странно, что в плеере ChaN'а, который я брал за основу, никаких преобразований не проводится:

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

#if MODE >= 1	/* Dual output */
	subi	r24, 2				;Check availability of the sampling data
	brcs	9f				;/
	sts	FifoCt, r24			;Save FIFO data counter
	ld	r24, Z+				;Get R-ch/LSB data and send it to PWM
	out	_SFR_IO_ADDR(OCR1A), r24	;/
	ld	r24, Z+				;Get L-ch/MSB data and send it to PWM
	out	_SFR_IO_ADDR(OCR1B), r24	;/
В любом случае, у меня при попытке вывода значений напрямую в ШИМ звук выводится с ужасным эффектом, похожим на дисторшн. А в случае с пересчётом в unsigned всё просто идеально, но на фоне слышно это дурацкое жужжание. :cry:
Мудрый кот
Сообщения: 1849
Зарегистрирован: Вс дек 25, 2016 08:34:54

Сообщение Dimon456 »

Zwanzig писал(а):Семплы в 16-ти битные вавки пишутся в signed int, для ШИМа с фактическим диапазоном значений 0..65535 приходится их вот так пересчитывать.
Ну вы даете.
При тактовой частоте 16МГц

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

PCM Mono 8Bit 11025Hz отлично
PCM Stereo 8Bit 11025Hz отлично
PCM Mono 8Bit 22050Hz отлично
PCM Stereo 8Bit 22050Hz отлично
PCM Mono 8Bit 32000Hz работает
PCM Stereo 8Bit 32000Hz уже нет не тянет
PCM Mono 8Bit 44100Hz не тянет
PCM Stereo 8Bit 44100Hz вообще ни как
И полагаю, что плеере ChaN'а

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

R-ch - правый канал 
L-ch - левый канал
Реклама
Эиком - электронные компоненты и радиодетали
Друг Кота
Аватара пользователя
Сообщения: 7077
Зарегистрирован: Пт ноя 11, 2016 05:48:09
Откуда: Сердце Пармы

Сообщение Ivanoff-iv »

я вот тоже прикидываю, как 16бит через PWM с хоть сколько нибудь приемлемой частотой выдавать?
16000000/(2^16)=244Гц...

Добавлено after 2 minutes 12 seconds:
или это не 16 бит или ЦАП, но я не припомню, чтобы в меге32 был встроенный...
Для тех, кто не учил магию мир полон физики :)
Безграмотно вопрошающим про силовую или высоковольтную электронику я не отвечаю, а то ещё посадят за участие в (само)убиении оболтуса...
Реклама
Нашел транзистор. Понюхал.
Аватара пользователя
Сообщения: 190
Зарегистрирован: Вт янв 26, 2010 21:49:41
Откуда: モスクワ

Сообщение Zwanzig »

Я тоже сначала удивлялся, как же. Уже расстроился и смирился с 8 битами. Потому что если использовать T1 с 16-ти битным ШИМом, то действительно максимальная частота 244 Гц.
Но ChaN пошёл другим путём. Он использовал два 8-ми битных выхода таймера (OC1A и OC1B), подключив второй через резистор в ~8 кОм. Тогда получается, что ступеньки на втором выходе будут в 8 раз меньше как-то так (это я расписываю своё примерное понимание, просьба ногами не пинать :) ). Таким образом, для вывода MSB используется прямой выход (OC1B), а LSB выводится через резистор с OC1A. Ну и получаем при смешивании что-то около 16 бит (+/-2 LSB ошибки будут, конечно, из-за неточности резисторов и прочих факторов).

Кто хочет подробностей, подобная технология описана и здесь, например. Т.е., возможно такое. Сорт оф симбиоз R2R ladder и PWM. Звук после изменения схемы действительно стал почти идеальным, по сравнению с 8 битами-то. :))

Я же описал, что проблема локализована. Она кроется в вызове pf_read при воспроизведении. Если убрать pf_read из цикла, то треск прекращается. Тогда давайте и думать исходя из этого: каким образом чтение данных по SPI может вызвать сбои в работе PWM?
СпойлерК слову, насчёт этого
Dimon456 писал(а):PCM Mono 8Bit 11025Hz отлично
PCM Stereo 8Bit 11025Hz отлично
PCM Mono 8Bit 22050Hz отлично
PCM Stereo 8Bit 22050Hz отлично
PCM Mono 8Bit 32000Hz работает
PCM Stereo 8Bit 32000Hz уже нет не тянет
PCM Mono 8Bit 44100Hz не тянет
PCM Stereo 8Bit 44100Hz вообще ни как
Я смотрел по тактам в дизассемблере, в прерывании ЦП проводит 1/7 общего времени. Это при частоте дискретизации 22 кГц. И это при моём кривожопом быдлокоде для конвертации в unsigned. Поэтому даже если увеличить частоту до 44,1, утилизация процессора конкретно для вывода звука не превысит 30%. Оставшихся 70% вполне хватит для наполнения буфера.
Так что не знаю, откуда вы это взяли - по моим подсчётам, это не так. :wink:
Реклама
Друг Кота
Аватара пользователя
Сообщения: 7077
Зарегистрирован: Пт ноя 11, 2016 05:48:09
Откуда: Сердце Пармы

Сообщение Ivanoff-iv »

интересно, технология понятна, только не в 8, а в 256 раз.
могут ли быть наводки по питанию/земле? на всякий случай попробуй наушниками через конденсатор сесть на ноги питания и МК и карточки (поочереди)...
Для тех, кто не учил магию мир полон физики :)
Безграмотно вопрошающим про силовую или высоковольтную электронику я не отвечаю, а то ещё посадят за участие в (само)убиении оболтуса...
ARV
Ум, честь и совесть. И скромность.
Аватара пользователя
Сообщения: 18678
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск

Сообщение ARV »

я не уверен, но подозреваю, что проблема зарыта где-то здесь: длительность считывания 256 байт и 512 байт библиотечкой PetitFatFS одинаковая, потому что считывание с карты всегда ведется блоками по 512 байт, даже если надо считать 1. поэтому вы ничего не выигрываете своей "двойной буфферизацией" (т.е. чтением по половинкам буфера), и даже скорее проигрываете. соответственно, возникают паузы в подаче данных на ЦАП, а оттуда и искажения. поэтому у вас и пропадают проблемы, если чтение из цикла убрать.
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Контактная информация:
Нашел транзистор. Понюхал.
Аватара пользователя
Сообщения: 190
Зарегистрирован: Вт янв 26, 2010 21:49:41
Откуда: モスクワ

Сообщение Zwanzig »

ARV писал(а):возникают паузы в подаче данных на ЦАП, а оттуда и искажения
Я исключил эту возможность. Во-первых, я понижал частоту дискретизации до 8 кГц — при таких параметрах у МК на 16 МГц точно будет достаточно времени, чтобы получить с карты 1-2 блока. Во-вторых, такой проблемы просто не возникало бы при подаче постоянного сигнала на уровне 0xFFFF — буфер кольцевой, нулям там просто неоткуда взяться.

Я вообще не могу придумать никакой софтовой причины, по которой такое может происходить. Казалось бы, если в буфере сплошные 0xFFFF — выводи себе и выводи, какой треск? Но он всё равно откуда-то берётся. А для "наводок" уж больно сильный треск получается. :dont_know:
Ivanoff-iv писал(а):интересно, технология понятна, только не в 8, а в 256 раз.
могут ли быть наводки по питанию/земле? на всякий случай попробуй наушниками через конденсатор сесть на ноги питания и МК и карточки (поочереди)...
Да, точно, 256.
Вечером попробую. Но не верю. Там на плате везде фильтры стоят нормальные, питание разведено хорошо...
Друг Кота
Аватара пользователя
Сообщения: 3832
Зарегистрирован: Сб сен 10, 2011 17:46:25

Сообщение oleg110592 »

в плеере ChaN'а, который я брал за основу
Заметна разница:
у Чена

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

BYTE Buff[256];		/* Wave output FIFO */
у автора

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

unsigned char buffer[512];   /* буфер в который копируется инфа с флешки */
у Чена

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

btr = (sz > 1024) ? 1024 : (WORD)sz;/* A chunk of audio data */
res = pf_read(0, btr, &rb);	/* Forward the data into audio FIFO */
if (rb != 1024) break;		/* Break on error or end of data */
у автора

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

pf_read(&buffer[0], 256, &br);//то читаем в первую половину буфера инфу с флешки
pf_read(&buffer[256], 256, &br); // читаем во вторую часть буфера с флешки
смотрим документацию:
pf_read
The pf_read function reads data from the file.
FRESULT pf_read (
void* buff, /* [OUT] Pointer to the read buffer */
UINT btr, /* [IN] Number of bytes to read */
UINT* br /* [OUT] Number of bytes read */
);
If a NULL is given to the buff, the read data bytes are forwarded to the outgoing stream instead of the memory. The streaming function depends on each project will be typically built-in the disk_readp() function.
Уже расстроился и смирился с 8 битами. Потому что если использовать T1 с 16-ти битным ШИМом, то действительно максимальная частота 244 Гц.
У Чена
The ATtinyX5 series (25/45/85) 8-pin AVR microcontroller has two fast PWM outputs in 250kHz carrier frequency.
В этих тини есть PLL в ATmega32 нет.

з.ы.8 бит ,битрейт 32кГц вполне неплохо звучит (imho):
https://www.youtube.com/watch?time_cont ... jrAGShRw7g
Друг Кота
Аватара пользователя
Сообщения: 7077
Зарегистрирован: Пт ноя 11, 2016 05:48:09
Откуда: Сердце Пармы

Сообщение Ivanoff-iv »

я тоже про эти тиньки сразу подумал, в них таймер можно от 64МГц тактировать, но и в этом случае частота дискретизации при 16 бит до 1кГц не доходит...
да, на встроенном осцилляторе (8МГц, тини 2313) можно получить 2*8бит*32кГц. а если побаловаться с OSCCAL'ом и разогнать мк, то и 44,1кГц получается. :)
пс: 16 бит не пробовал... думаю, если скорость СПИ позволит, то не принципиально, сейчас недотого, но как время будет - обязательно попробую.
Для тех, кто не учил магию мир полон физики :)
Безграмотно вопрошающим про силовую или высоковольтную электронику я не отвечаю, а то ещё посадят за участие в (само)убиении оболтуса...
Мудрый кот
Сообщения: 1849
Зарегистрирован: Вс дек 25, 2016 08:34:54

Сообщение Dimon456 »

Но не все так плохо, путем внешнего кварца меги 8 48 168 гонятся до 27МГц, выше не пробовал.
Можно применить более продвинутые контроллеры, ни знаю на счет STM8, но STM32 гонится за 100МГц.
Нашел транзистор. Понюхал.
Аватара пользователя
Сообщения: 190
Зарегистрирован: Вт янв 26, 2010 21:49:41
Откуда: モスクワ

Сообщение Zwanzig »

Проблема не в коде. И остальное, что у меги нет PLL и т.п., всё что здесь писали — не имеет значения.

Сегодня одолжил у друга осциллограф и обнаружил, что на питании присутствуют пульсации с амплитудой 100 мВ. Такие же пульсации в 100 мВ получаются и на динамике.
В пульсациях видно как тактовый сигнал SPI на 8 МГц, но там амплитуда небольшая. Основной размах получается раз в ~0,02 секунды, когда в цикле идёт обращение к SD-карте. Т.е., видимо при чтении с карты она резко начинает потреблять много тока и даёт такие просадки по питанию, которые потом так отражаются на звуке.

Пробовал прислонять всякие конденсаторы 0,1-0,47 мкФ прямо к ногам питания МК и SD — не помогает, пульсации становятся меньше на 5-10 мВ и всё, но шум остаётся.

Пока немного в ступоре. На пинборде от DiHalt стоят электролиты по входу 100 мкФ, рядом с МК походу никаких фильтров, судя по схеме. SD запитана через LDO-регулятор и там висят ёмкости, т.е. по идее особого влияния на Vcc она оказывать не должна. Но оказывает почему-то. И в большие непонятки меня вводит то, что подключение плёночного конденсатора прямо на ноги МК ничего не меняет. Как тогда фильтровать питание вообще?
Друг Кота
Аватара пользователя
Сообщения: 7077
Зарегистрирован: Пт ноя 11, 2016 05:48:09
Откуда: Сердце Пармы

Сообщение Ivanoff-iv »

а "наушник плюс конденсатор" эти щелчки в питании не обнаружили?
победить можно так: в питание карты электролит ~500мкФ плюс керамика, минус карты развести на общую точку, питание на карту (и её конденсаторы) подавать через небольшой резистор или дросселёк.
на мк поставить свои конденсаторы.
Для тех, кто не учил магию мир полон физики :)
Безграмотно вопрошающим про силовую или высоковольтную электронику я не отвечаю, а то ещё посадят за участие в (само)убиении оболтуса...
Друг Кота
Аватара пользователя
Сообщения: 3832
Зарегистрирован: Сб сен 10, 2011 17:46:25

Сообщение oleg110592 »

на всякий - тут плеер мега16 с практическими расчетами, используется один буфер 256 байт, делится пополам по 128 байт, по очереди - в одну половину считывается с карты, с другой воспроизводит
http://chipenable.ru/index.php/programm ... a-ch3.html
Мудрый кот
Сообщения: 1849
Зарегистрирован: Вс дек 25, 2016 08:34:54

Сообщение Dimon456 »

ТС, провел экспериментик.
Используемый контроллер STM32F100RBT6B.
Тактовая частота SYSCLK_Frequency 48МГц
Использовался DMA(Direct Memory Access) — Контроллер прямого доступа к памяти.
Звук выводился через 12-bit D/A converters выводы STM32 PA4 PA5.

Запись звучания STM32 велась на линейный вход компа, ни каких фильтров на выводах STM32 PA4 PA5, кроме сопротивлений по 13кОм, не стояло.
Питание STM32 от USB порта компа, ни каких фильтров по питанию не было.

Вот тут результат.
Ответить

Вернуться в «AVR»