Свежие обсуждения
Микроконтроллеры

Оцифровка сигнала [под управлением atmega]

ATMega16 управляет внешним АЦП TLV1570 по встроенному SPI и пытаемся оцифровать гармонический сигнал с частотами до 20кгц.

Немного о TLV1570 - 8ми канальный 10ти разрядный последовательный АЦП 1.25MSPS. Входные напряжения: 0 .. 5В

По теореме Котельникова, частота дискретизации: Fдиcкр > 2Fmax
В моём случае 2Fmax = 40кГц, а частота дискретизации АЦП по даташиту считается так: Fдискр = 1/16*Fsclk (на каждую выборку нужно передать 2 байта) (в обвязке к ATMega стоит резонатор на 16МГц, при настройках SPI получил: Fsclk = 4Mhz ) => Fдиск = 1\16*4Mhz = 250кГц

Т.е. мы укладываемся с головой. Частота дискретизации 250 кГц, а сигнал 20кГц

Код прошивки такой:


while (1) {
for (i=0;i<100;i++) {
ADC_CS = 0;
adc_result_hi[i] = spi(0x00);
adc_result_low[i] = spi(0x60);
ADC_CS = 1;
}

for (i=0;i<100;i++){ putchar(adc_result_hi[i]);
putchar(adc_result_low[i]);
}
}
* я сначала собираю отсчеты по 100 точек и сохраняю их в буффер, а затем отправляю по UART на COM порт в ПК. (так быстрее производительность, т.к. отправка по уарту занимает значительное время)

Просимулировал этот код в VMLAB, получил следующие тайминги:

С учетом всех погрешностей на запись в переменные и т.п - получил, что снятие одного отсчета займет 10мкс - т.е. частота дискретизации 100кГц - все равно укладываемся.

Итак, на практике вот что я получаю:

Оцифровка сигнала частотой 10кГц амплитуда около 1В:

Здесь около 10ти точек на период. Качество оцифровки неудовлетворительное.

Сразу же в настройках SPI выставил галочку SCLK x2 Rate - т.е. удвоили частоту тактирующего импульса (я предполагал что и качество оцифровки увеличится в 2 раза)

Вот как получилось с этой настройкой:

Оцифровка сигнала частотой 10кГц амплитуда около 1В (SPI SCLK x2 rate):


Получилось 13 точек на период - совсем небольшой прирост =(

Мучил код, пробывал и так и сяк, симулировал.
Вот как получается, если после получения отсчета от АЦП - сразу выплевывать его на UART:


while (1) {

ADC_CS = 0;
putchar(spi(0x00));
putchar(spi(0x60));
ADC_CS = 1;

}



Совсем не так как хотелось бы.

* Сигнал с меньшей частотой оцифровывает прелестно. Вот пример оцифровки синуса с частотой 1кГц:

Здесь меня всё устраивает. Около 90 точек на период. Качество отличное

Прошу помощи - оцифровкой занимаюсь в первый раз, как быть, вроде бы всё правильно - а на деле выходит совсем не то. Возможно код можно ещё как то более оптимизировать, или ещё где ошибку сделал? Прошу совета.

 

Кусок инициализации SPI покажите.
Вообще симулятор может просто-напросто наврать. 10 кгц - частота немалая. То, что при удвоении частоты получили всего 30% по точкам - тонкий намек

 

Инициализация SPI:

PORTB=0x00;
DDRB=0xB0;

SPCR=0x54;
SPSR=0x00;

* SPI без прерываний настроен - я пробывал и с прерываниями - результат одинаков. Для SPI SLCK x2 rate ствил:

SPCR=0x54;
SPSR=0x01;

 

ОК. Попробуйте еще обойтись без функции spi(...), т.е. реализовать обмен "руками" (в даташите по Меге16 есть подробное описание). Еще лучше бы написать этот кусок на ассемблере - по моим прикидкам у вас интервалы между обменами не должны превышать 16 команд, а с вызовом функции вы в них наверняка не уложитесь.

 

На C уже пробывал "руками" как в даташите написано:

SPDR=data;
while ((SPSR & (1SPIF))==0);

результат тот же