Прошу прощения за многобукв, но сразу решил написать, как всё работает.
Делаю тут свой приборчик на базе AT91SAM7S64, который должен оцифровывать аналоговый сигнал с частотой 500 кГц. Но у меня получается только в районе 370 кГц

Атмел заявляет, что в её камне АЦП в режиме 8 бит делает 533 кГц. Это при максимальной частоте контроллера АЦП = 8 МГц и времени преобразования = 15 тактов (8000000 / 15 = 533333) (см. 37.9 ADC Characteristics)
Соответственно, хочу ещё и DMA использовать, чтобы всё хорошо было

DMA (он же PDC) для АЦП в атмеле так устроен: как обычно, задаёте указатель на массив в один регистр, размер массива - в другой. Дальше запускаете АЦ преобразование. Когда оно завершится, и будет выставлен соответствующий бит в регистре статуса, DMA контроллер сам перепишет полученное значение в массив. Но запускать АЦ преобразование нужно самому, DMA контроллер этого не делает.
Зато у самого АЦП есть замечательная возможность включить внешний триггер запуска АЦ преобразования от сигнала TIOA любого из таймеров Timer Counter. Для этого, как пишут в datasheet'е, нужно TimerCounter выставить в режим Waveform Mode.
Итак, настраиваю АЦП контроллер: включён внешний триггер от TIOA1, разрешение 8 бит, PRESCAL = 2, STARTUP = 19, SHTIM = 15
Код
// Включаем частоту для АЦП
AT91C_BASE_PMC->PMC_PCER = 1 << AT91C_ID_ADC;
while((AT91C_BASE_PMC->PMC_PCSR & (1 << AT91C_ID_ADC)) != (1 << AT91C_ID_ADC));
// Сбрасываем АЦП
AT91C_BASE_ADC->ADC_CR = AT91C_ADC_SWRST;
// Делитель
uint32 PRESCAL = 2;
// Время запуска
uint32 STARTUP = 19;
// Время преобразования
uint32 SHTIM = 15;
// Настраиваем АЦП
AT91C_BASE_ADC->ADC_MR =
AT91C_ADC_TRGEN_EN | AT91C_ADC_TRGSEL_TIOA1 |
AT91C_ADC_LOWRES |
(PRESCAL << 8) & AT91C_ADC_PRESCAL |
(STARTUP << 16) & AT91C_ADC_STARTUP |
(SHTIM << 24) & AT91C_ADC_SHTIM;
AT91C_BASE_PMC->PMC_PCER = 1 << AT91C_ID_ADC;
while((AT91C_BASE_PMC->PMC_PCSR & (1 << AT91C_ID_ADC)) != (1 << AT91C_ID_ADC));
// Сбрасываем АЦП
AT91C_BASE_ADC->ADC_CR = AT91C_ADC_SWRST;
// Делитель
uint32 PRESCAL = 2;
// Время запуска
uint32 STARTUP = 19;
// Время преобразования
uint32 SHTIM = 15;
// Настраиваем АЦП
AT91C_BASE_ADC->ADC_MR =
AT91C_ADC_TRGEN_EN | AT91C_ADC_TRGSEL_TIOA1 |
AT91C_ADC_LOWRES |
(PRESCAL << 8) & AT91C_ADC_PRESCAL |
(STARTUP << 16) & AT91C_ADC_STARTUP |
(SHTIM << 24) & AT91C_ADC_SHTIM;
Получаю:
ADCClock = MCK / ((PRESCAL + 1) * 2) = 48054857 / ((2 + 1) * 2) = 8009142 Hz (8 MHz)
Startup Time = (STARTUP + 1) * 8 / ADCClock = (19 + 1) * 8 / 8009142 = 19,97 мкс (по документации время запуска спящего канала макс. 20 мкс)
Sample & Hold Time = SHTIM / ADCClock = 15 / 8009142, частота 8009142 / 15 = 533942 Hz
Частота процессора у меня
MCK = PLL / 2 = (18432000 * 73 / 14) / 2 = 48054857 Hz
Включаю нужный канал (как написано в даташите, DMA контроллер переписывает данные только от активных каналов)
Код
AT91C_BASE_ADC->ADC_CHER = AT91C_ADC_CH5;
Настраиваю DMA:
Код
// Буфер
uint8 buf[8192];
// Отключаем приёмник
PDC_ADC->PDC_PTCR = AT91C_PDC_RXTDIS;
// Отключаем передатчик
PDC_ADC->PDC_PTCR = AT91C_PDC_TXTDIS;
// Устанавливаем буфер чтения для PDC
PDC_ADC->PDC_RPR = (uint32)buf;
PDC_ADC->PDC_RCR = sizeof(buf);
// Включаем приёмник
PDC_ADC->PDC_PTCR = AT91C_PDC_RXTEN;
uint8 buf[8192];
// Отключаем приёмник
PDC_ADC->PDC_PTCR = AT91C_PDC_RXTDIS;
// Отключаем передатчик
PDC_ADC->PDC_PTCR = AT91C_PDC_TXTDIS;
// Устанавливаем буфер чтения для PDC
PDC_ADC->PDC_RPR = (uint32)buf;
PDC_ADC->PDC_RCR = sizeof(buf);
// Включаем приёмник
PDC_ADC->PDC_PTCR = AT91C_PDC_RXTEN;
Теперь настраиваю таймер: частота MCK / 2, режим Waveform, способ счёта - пилообразный с автоматическим сбросом значения счётчика при достижении регистра RC, RA Compare Effect on TIOA = set, RC Compare Effect on TIA = clear
Код
// Включаем частоту таймера
AT91C_BASE_PMC->PMC_PCER = 1 << AT91C_ID_TC1;
while((AT91C_BASE_PMC->PMC_PCSR & (1 << AT91C_ID_TC1)) != (1 << AT91C_ID_TC1));
// Настраиваем таймер на формирование П-образного сигнала на TIOA
AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK |
AT91C_TC_WAVE | AT91C_TC_WAVESEL_UP_AUTO |
AT91C_TC_ACPA_SET | AT91C_TC_ACPC_CLEAR);
AT91C_BASE_PMC->PMC_PCER = 1 << AT91C_ID_TC1;
while((AT91C_BASE_PMC->PMC_PCSR & (1 << AT91C_ID_TC1)) != (1 << AT91C_ID_TC1));
// Настраиваем таймер на формирование П-образного сигнала на TIOA
AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK |
AT91C_TC_WAVE | AT91C_TC_WAVESEL_UP_AUTO |
AT91C_TC_ACPA_SET | AT91C_TC_ACPC_CLEAR);
То есть в регистре RC задаю период пилообразного счёта, при этом TIOA при достижении RC (то есть в начале каждого периода) задаётся как низкий уровень, а при достижении RA - становится высоким.
Теперь нужно задать RA, RC, запустить таймер и ждать, когда массив заполнится

Хочу, например, 500 кГц, тогда RC = MCK / 2 / 500000 = 48054857 / 2 / 500000 = 48
Тогда RA = RC / 2 = 24, то есть в середине пилы будет выставляться высокий TIOA1 (в этот момент должен происходить запуск преобразования), а в конце - низкий. DMA сделает всё остальное.
Так и делаю:
Код
// Частота АЦ преобразований
uint32 freq = 500000;
// Период таймера, соответствующий 1 периоду преобразования
uint32 period = MCK / 2 / freq;
// Задаём регистры A и C
AT91C_BASE_TC1->TC_RC = period;
AT91C_BASE_TC1->TC_RA = period / 2;
// Запускаем таймер
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
// Ждём заполнения буфера
while(PDC_ADC->PDC_RCR);
// Смотрим результат
// ....
uint32 freq = 500000;
// Период таймера, соответствующий 1 периоду преобразования
uint32 period = MCK / 2 / freq;
// Задаём регистры A и C
AT91C_BASE_TC1->TC_RC = period;
AT91C_BASE_TC1->TC_RA = period / 2;
// Запускаем таймер
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
// Ждём заполнения буфера
while(PDC_ADC->PDC_RCR);
// Смотрим результат
// ....
Так вот изменяя freq опытным путём понял, что максимальная частота составляет где-то 370000. У меня есть опорный сигнал 1 кГц 3.3В, соответственно могу посчитать сколько байт из массива buf должны быть почти 0 (< 10), а сколько почти 255 (>245) при заданной частоте freq. Кодга ставлю freq больше 370000, то в массиве buf получается одно и тоже, как будто freq всё ещё 370000.
Что я делаю не так?
P.S. Пробовал даже разгонять проц до MCK=64 МГц (с изменением PRESCAL с 2 на 3 разумеется, чтобы 8 МГц получить) - всё тоже самое.