Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: AT91SAM9G45
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
Gevork
Добрый день. Столкнулся с такой проблеммой при подключении параллельного АЦП к портам процессора, не могу выжать с них больше 1.5 мГц. В МК STM скорость работы портов настраивается регистрами вроде бы как до 50мГц, неужели в данном случа компания Atmel не предусмотрела это и больше чем 1.5 мГц не вытянуть ? Или мб я не нашел данные регисты?
Работаю в режиме standalone программирование в среде IAR. Заранеее спасибо.
DmitryM
Цитата(Gevork @ Feb 16 2012, 15:01) *
при подключении параллельного АЦП к портам процессора, не могу выжать с них больше 1.5 МГц.

В каком режиме подключение? SMC зависит от настроек, максимально работает на частоте MCK/2 {66МГц}, ноги ввода вывода смотрите пп. 46.9. Подробнее информация о поключении АЦП.
Gevork
Цитата(DmitryM @ Feb 16 2012, 15:44) *
В каком режиме подключение? SMC зависит от настроек, максимально работает на частоте MCK/2 {66МГц}, ноги ввода вывода смотрите пп. 46.9. Подробнее информация о поключении АЦП.

АЦП внешняя параллельная. Имеет 12 бит данных и сигнал CLK, все это подключенно к порту E. Тактирование АЦП ведется с порта процессора =) Только всё равно н епонялтно как указывать максимальную частоту работ, можно ли поподробней плс.
scifi
Цитата(Gevork @ Feb 16 2012, 16:01) *
В МК STM скорость работы портов настраивается регистрами вроде бы как до 50мГц...

Кстати, это настраивается крутизна фронтов (то есть мощность драйвера). Ясно, что крутизна также зависит от ёмкости нагрузки. Поэтому даже в режиме 2 МГц можно получить 10 МГц.
В STM32F1xx GPIO сидит на APB, то есть тактируется медленнее процессора и есть задержки при доступе к регистрам. В STM32F2xx GPIO тактируется на частоте процессора, и задержек там нет.
DmitryM
Цитата(Gevork @ Feb 16 2012, 16:22) *
все это подключенно к порту E.

Обычный ного-дрыг, тогда в классическом варианте, когда процессор ничем больше не занят и остальная периферия не используется см пп.49.6 МСК/2 т.е. 66МГц. Как Вы получили 1,5МГц?
P.S. PE0 & PE31 могут сами генерировать сигналы PCK частоты кратной MCK, SCLK, PLL. Может с них начать оценку частотный характеристик?
Gevork
Цитата(DmitryM @ Feb 16 2012, 19:50) *
Обычный ного-дрыг, тогда в классическом варианте, когда процессор ничем больше не занят и остальная периферия не используется см пп.49.6 МСК/2 т.е. 66МГц. Как Вы получили 1,5МГц?
P.S. PE0 & PE31 могут сами генерировать сигналы PCK частоты кратной MCK, SCLK, PLL. Может с них начать оценку частотный характеристик?


В нашем случае контроллер ввода-вывода PIO настроен на частоту работы 12 МГц. Это реализовано с помощью регистра PMC_PCER, который разрешает или запрещает подачу Master Clock на PIO. В свою очередь, Master Clock тактируется от внешнего тактового генератора 12 МГц и не изменяется. Регистров настройки другой (большей 12 МГц) частоты PIO в даташите мы не обнаружили. Т.е. реально получается для приема 12 бит АЦП скорость 1.5 МГц для ногодрыгания каждой ножки.

Кто подскажет варианты выхода из данной ситуации??? Подскажите регистры настройки частоты PIO, чтобы выжать ногодрыгание и прием данных с 12 бит АЦП хотя бы 50 МГц (как у STM32).

В файле "Optimizing Power Consumption of AT91SAM9261-based Systems" с официального сайта Atmel http://www.atmel.com/Images/doc6217.pdf на странице 2 приведена блок-диаграмма системного контроллера. Согласно этой схеме PIO тактируется от PMC контроллера, который может умножать или делить частоту PLL (для PCK и MCK до 400 МГц).

Так почему-же мы не можем настроить частоту ногодрыгания равную частоте работы процессора???
aaarrr
PIO тактируется от MCK, последний может иметь частоту до 133MHz (см. Figure 26-1). Просто настройте его.

А вообще, не дело это - пытаться окучивать скоростную периферию ногодрыгом.
Gevork
Цитата(aaarrr @ Feb 24 2012, 15:02) *
PIO тактируется от MCK, последний может иметь частоту до 133MHz (см. Figure 26-1). Просто настройте его.

А вообще, не дело это - пытаться окучивать скоростную периферию ногодрыгом.

Простите, но вопрос состоит не что именно сделать, а как это сделать ?
aaarrr
Цитата(Gevork @ Feb 25 2012, 00:21) *
Простите, но вопрос состоит не что именно сделать, а как это сделать ?

Как сделать буквально по шагам расписано в документации (26.9 Programming Sequence).
Gevork
Цитата(aaarrr @ Feb 24 2012, 23:37) *
Как сделать буквально по шагам расписано в документации (26.9 Programming Sequence).

Простите тупого, но никак не получается, на какое то время данная проблема отпала, но вскоре опять всплыла. Опишите пожалуйста поподробней как все же это реализовать, если не сложно хотелось бы увидеть код как это сделать, как я понял надо что то указать непосредственно прямо в main.c при инициализации порта(бита).
aaarrr
Цитата(Gevork @ May 15 2012, 15:05) *
как я понял надо что то указать непосредственно прямо в main.c при инициализации порта(бита).

Нет, при инициализации PIO ничего делать не надо.

Опишите, что у вас настроено сейчас по части:
1. PLL
2. MMU/Cache
Gevork
Цитата(aaarrr @ May 15 2012, 14:27) *
Нет, при инициализации PIO ничего делать не надо.

Опишите, что у вас настроено сейчас по части:
1. PLL
2. MMU/Cache

Мммм, простите еще раз дурака. но помоему ничего не указанно, программа что не на есть простая, одна нога тупо дрыгается (тактируя АЦП) а лругие 12 побитово считывают данные с выходов АЦП по спаду CLK(т е по спаду того вывода) ....
Извиняюсь за тупость.
aaarrr
Тогда лучше прицепите сюда архив с проектом - посмотрим.
Gevork
Цитата(aaarrr @ May 15 2012, 14:44) *
Тогда лучше прицепите сюда архив с проектом - посмотрим.

Извиняюсь за неподчищенный код=(
Второй архив вроде бы почище.
aaarrr
Проект посмотрел. Что можно сказать:

1. PLL настроена, ничего менять не надо.

2. Если хотите выжать предельную скорость, то в опциях оптимизации следует выбрать "speed", а не "size".

3. В данном случае п.2 скажется слабо, т.к. подобная "сборка" данных убьет любую производительность:
CODE

#define ADC1_B1 AT91C_PIO_PE17
#define ADC1_B2 AT91C_PIO_PE27
#define ADC1_B3 AT91C_PIO_PE26
#define ADC1_B4 AT91C_PIO_PE28
#define ADC1_B5 AT91C_PIO_PE21
#define ADC1_B6 AT91C_PIO_PE23
#define ADC1_B7 AT91C_PIO_PE15
#define ADC1_B8 AT91C_PIO_PE7
#define ADC1_B9 AT91C_PIO_PE24
#define ADC1_B10 AT91C_PIO_PE12
#define ADC1_B11 AT91C_PIO_PE9
#define ADC1_B12 AT91C_PIO_PE5

...

for(i = 0; i<1000; i++)
{

AT91C_BASE_PIOE->PIO_SODR=ADC_CLK;




if(AT91C_BASE_PIOE->PIO_PDSR & ADC1_B12){D12=1;}else{D12=0;}
if(AT91C_BASE_PIOE->PIO_PDSR & ADC1_B11){D11=1;}else{D11=0;}
if(AT91C_BASE_PIOE->PIO_PDSR & ADC1_B10){D10=1;}else{D10=0;}
if(AT91C_BASE_PIOE->PIO_PDSR & ADC1_B9){D9=1;}else{D9=0;}
if(AT91C_BASE_PIOE->PIO_PDSR & ADC1_B8){D8=1;}else{D8=0;}
if(AT91C_BASE_PIOE->PIO_PDSR & ADC1_B7){D7=1;}else{D7=0;}
if(AT91C_BASE_PIOE->PIO_PDSR & ADC1_B6){D6=1;}else{D6=0;}
if(AT91C_BASE_PIOE->PIO_PDSR & ADC1_B5){D5=1;}else{D5=0;}
if(AT91C_BASE_PIOE->PIO_PDSR & ADC1_B4){D4=1;}else{D4=0;}
if(AT91C_BASE_PIOE->PIO_PDSR & ADC1_B3){D3=1;}else{D3=0;}
if(AT91C_BASE_PIOE->PIO_PDSR & ADC1_B2){D2=1;}else{D2=0;}
if(AT91C_BASE_PIOE->PIO_PDSR & ADC1_B1){D1=1;}else{D1=0;}

DATA[i] = (
(D12<<11)
|((D11<<10)
|((D10<<9)
|((D9<<8)
|((D8<<7)
|((D7<<6)
|((D6<<5)
|((D5<<4)
|((D4<<3)
|((D3<<2)
|((D2<<1)
|((D1)
))))))))))));


AT91C_BASE_PIOE->PIO_CODR=ADC_CLK;
}


Что не так с этим кодом:

3.1. Каждое обращение к AT91C_BASE_PIOE->PIO_PDSR приводит к новому чтению порта. Считайте значение порта в переменную и работайте с ней:
Код
unsigned int x = AT91C_BASE_PIOE->PIO_PDSR;

if(x & ADC1_B12) ...
if(x & ADC1_B11) ...

3.2. Обилие локальных переменных только запутает компилятор. Будьте проще:
CODE

#define _ADC1_B1 17
#define _ADC1_B2 27
#define _ADC1_B3 26
#define _ADC1_B4 28
#define _ADC1_B5 21
#define _ADC1_B6 23
#define _ADC1_B7 15
#define _ADC1_B8 7
#define _ADC1_B9 24
#define _ADC1_B10 12
#define _ADC1_B11 9
#define _ADC1_B12 5

#define SWAP_BITS(x, s, d) ((((x) >> (s)) & 1) << (d))


for(i = 0; i<1000; i++)
{
unsigned int X;

AT91C_BASE_PIOE->PIO_SODR=ADC_CLK;

X = AT91C_BASE_PIOE->PIO_PDSR;

DATA[i] = SWAP_BITS(X, _ADC1_B1, 0) | SWAP_BITS(X, _ADC1_B2, 1) | SWAP_BITS(X, _ADC1_B3, 2) |
SWAP_BITS(X, _ADC1_B4, 3) | SWAP_BITS(X, _ADC1_B5, 4) | SWAP_BITS(X, _ADC1_B6, 5) |
SWAP_BITS(X, _ADC1_B7, 6) | SWAP_BITS(X, _ADC1_B8, 7) | SWAP_BITS(X, _ADC1_B9, 8) |
SWAP_BITS(X, _ADC1_B10, 9) | SWAP_BITS(X, _ADC1_B11, 10) | SWAP_BITS(X, _ADC1_B12, 11);

AT91C_BASE_PIOE->PIO_CODR=ADC_CLK;
}

Это дает не только более короткий текст программы (что тоже немаловажно), но и позволяет компилятору показать себя во всей красе.

3.3. Наиболее скоростным решением будет перекодировка при помощи заранее созданных таблиц. А еще лучше было бы развести шину данных АЦП по порядку, а не вразнобой.

4. Включите кэш. На данном этапе можно ограничиться кэшем инструкций (достаточно вызвать CP15_EnableIcache() в main).
Про кэш данных и MMU могу рассказать позже, но здесь лучше вникать в происходящее, а не просто копировать-вставлять.
Gevork
Огромное спасибо за помощь буду пробовать!!!!
Я так же понял что с порта не выжать больше 20 МГц, правильно ?
Тогда вопрос еще один пример кода для аппаратного SPI master для 1 Мгц это же реально, нужно просто получать данные с последовательной АЦП и всё ? Есть ли у кого то простенький код для этого ? стандартный пример Atmel уж очень муторный да и библиотеки какие то ппц водянистые не поймешь что да как .....
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.