|
Скорость работы PIO - почему такая маленькая?, на AT91SAM7S |
|
|
|
May 21 2006, 15:34
|

Профессионал
    
Группа: Свой
Сообщений: 1 065
Регистрация: 8-10-05
Из: Kiev, UA
Пользователь №: 9 380

|
Цитата 1. Регистры PIO стоит писать напрямую, без использования библиотечных функций. Это каким же образом? Смотрим библиотечную функцию: Код __inline void AT91F_PIO_SetOutput( AT91PS_PIO pPio, // pointer to a PIO controller unsigned int flag) // output to be set { pPio->PIO_SODR = flag; } Куда уж быстрее... Другое дело она по каким-то причинам не отработала как inline (директива не обязательная к исполнению). Мне думаеться здесь отсутствие инлайна, оптимизации и while(1) как неоптимальный вечный цикл - лучше поменять на for(;;). А также не слова не сказано про установки частоты.
--------------------
Вони шукають те, чого нема, Щоб довести, що його не існує.
|
|
|
|
|
May 21 2006, 15:44
|
Гуру
     
Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448

|
ИМХО, библиотечными функциями можно пользоваться только в том случае, если они были написаны собственноручно или хотя бы проверены. Нормальных готовых библиотек не видел ни у одного производителя. Цитата(beer_warrior @ May 21 2006, 19:34)  Мне думаеться здесь отсутствие инлайна, оптимизации и while(1) как неоптимальный вечный цикл - лучше поменять на for(;;). За использование цикла for в embedded приложениях я бы увольнял без выходного пособия. Цитата(beer_warrior @ May 21 2006, 19:34)  А также не слова не сказано про установки частоты.  Ну да, не сказано. Сказано, что остальное работает быстро. Вообще, в таких случаях asm листинг первым делом смотреть нужно...
|
|
|
|
|
May 21 2006, 16:06
|

Профессионал
    
Группа: Свой
Сообщений: 1 065
Регистрация: 8-10-05
Из: Kiev, UA
Пользователь №: 9 380

|
Цитата ИМХО, библиотечными функциями можно пользоваться только в том случае, если они были написаны собственноручно или хотя бы проверены. Нормальных готовых библиотек не видел ни у одного производителя. Вчера вечером нарыл одну кривизну в lib_AT91SAM7S64.h, но огорчаться не стоит, это же не компилированная хрень, а просто набор макросов. Не всегда удобных Цитата За использование цикла for в embedded приложениях я бы увольнял без выходного пособия. Это почему? И именно в embedded? Цитата Ну да, не сказано. Сказано, что остальное работает быстро. Посмотрел пост про таймеры и понял, что таки да, грабли в установках клоков. Цитата Вообще, в таких случаях asm листинг первым делом смотреть нужно... sure
--------------------
Вони шукають те, чого нема, Щоб довести, що його не існує.
|
|
|
|
|
May 21 2006, 16:21
|
Гуру
     
Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448

|
Цитата(beer_warrior @ May 21 2006, 20:06)  Это почему? И именно в embedded? Тут вопрос перетекает в религиозную плоскость  Моё ИМХО: Все, что можно реализовать циклом for, реализуется циклом do..while с такой же или большей эффективностью. Да и читаемость выше. А embedded потому, что в маленьких задачах на "больших" машинах на эффективность можно и забить. Цитата(beer_warrior @ May 21 2006, 20:06)  Посмотрел пост про таймеры и понял, что таки да, грабли в установках клоков. Да не скажите, я вот ничего не понял: установил человек режим тактирования и включил прерывания по сравнению с непонятно чем, и получил в результате 180Гц. Я ж не телепат
|
|
|
|
|
May 21 2006, 17:05
|
Частый гость
 
Группа: Свой
Сообщений: 172
Регистрация: 23-04-06
Пользователь №: 16 404

|
Цитата(GetSmart @ May 21 2006, 20:23)  Вы ещё подеритесь, господа, из-за чужой глупости. Ну даже если обкекаться то АРМ не может выдавать такое медленное переключение в при компиляции такого простого кода - 730 Гц !!! Это просто немыслимо! Я бы ещё чуть-чуть поверил если 730 КГц. Но и это для САМа маловероятно. Испытал я данную констукцию у себя для интереса, компилятор WinARM, на кварце 18.432 (MSK 73.9232) при компиляции без оптимизации (-O0) даёт приетно 0.5 Мгц при компиляции с оптимизацией (-O2) скважность сигнала уже не 0.5 да и форма на моем домашнем осцилографе сильно непрямоугольная F > 2-4 mhz (больше он у меня не берёт)
|
|
|
|
|
May 21 2006, 17:24
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
Цитата(aaarrr @ May 21 2006, 18:44)  Цитата(beer_warrior @ May 21 2006, 19:34)  Мне думаеться здесь отсутствие инлайна, оптимизации и while(1) как неоптимальный вечный цикл - лучше поменять на for(;;).
За использование цикла for в embedded приложениях я бы увольнял без выходного пособия. Можете обы не волноваться :-) оба приведенных примера относятся к седой старине 80x годов (но успешно до сих пор кочуют по книжкам в качестве 'откровений') когда еще существовали неоптимизирующие однопроходные компиляторы на которые for( ; ; ){} вместо while( 1 ){} и do{}while() вместо for(){} ложились естественее. Все давно в прошлом.
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
May 21 2006, 17:40
|
Знающий
   
Группа: Свой
Сообщений: 550
Регистрация: 16-06-04
Из: Казань
Пользователь №: 32

|
действительно, надо бы в генерируемый ассемблерный код иногда всё-таки заглядывать  IAR, да и любой другой серьёзный компилятор, не делает никакой разницы между while(1), do...while(1) и for(;;). Он успешно оптимизирует и куда более навороченные конструкции. По теме: PIO Clock не влияет на скорость и вообще на возможность переключения состояний ног. Если не нужны внешние прерывания, его можно не включать.
--------------------
Главная линия этого опуса ясна мне насквозь!
|
|
|
|
|
May 21 2006, 18:05
|
Гуру
     
Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448

|
По поводу do..while. Хочу тоько заметить, что: Код a = 10; do { ... } while(--a); Будет оптимально откомпилирован в ADS всегда, а Код for(a = 10; a != 0; a--) { ... } - только при включенной оптимизации. То, что while(1), do...while(1) и for(;;) дадут один и тот же код, ясно и дураку. Тем не менее, организовывать бесконечный цикл при помощи for(;;) я считаю дикостью. P.S. Книжки я не читаю, все вышесказанное - мое личное ИМХО.
|
|
|
|
|
May 21 2006, 19:05
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
Цитата(vet @ May 21 2006, 21:24)  Напротив, для себя пришёл к выводу, что самым грамотным способом организации бесконечного цикла нужно считать for(;;) - в этой конструкции нет константы, чистый синтаксис. Для бесконечного это действительно единсвенно однозначно понимаемый и безвариантно реализуемый вариант. Цитата(aaarrr @ May 21 2006, 21:05)  Хочу тоько заметить, что: Код a = 10; do { ... } while(--a); Будет оптимально откомпилирован в ADS всегда, а Код for(a = 10; a != 0; a--) { ... } C компиляцией, считаем, разобрались. А Вы действительно искренне считаете, что первый вариант читабельнее? Особенно, когда тело цикла одним взгядом не окидывается :-) Ну и по поводу возможности всегда заменить на do{} - а что если тело цикла не надо выполнить НИ РАЗУ, дополнительнвй if() будем вешать снаружи за ради следования идее?
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
May 21 2006, 19:20
|

Профессионал
    
Группа: Свой
Сообщений: 1 065
Регистрация: 8-10-05
Из: Kiev, UA
Пользователь №: 9 380

|
Цитата Можете обы не волноваться :-) оба приведенных примера относятся к седой старине 80x годов (но успешно до сих пор кочуют по книжкам в качестве 'откровений') когда еще существовали неоптимизирующие однопроходные компиляторы на которые for( ; ; ){} вместо while( 1 ){} и do{}while() вместо for(){} ложились естественее. Все давно в прошлом. Как ни странно, мне встречались варианты, когда while(1) совершал кучу ужимок и прыжков, for(;;) в любом случае дает goto label, даже без оптимизации. Каждый раз копаться в листингах для выяснения этого вопроса достаточно лениво, а компиляторы у нас эмбеддеров меняються часто
--------------------
Вони шукають те, чого нема, Щоб довести, що його не існує.
|
|
|
|
|
May 21 2006, 20:23
|
Частый гость
 
Группа: Свой
Сообщений: 187
Регистрация: 22-06-04
Пользователь №: 127

|
Цитата(sff @ May 21 2006, 21:05)  Цитата(GetSmart @ May 21 2006, 20:23)  Вы ещё подеритесь, господа, из-за чужой глупости. Ну даже если обкекаться то АРМ не может выдавать такое медленное переключение в при компиляции такого простого кода - 730 Гц !!! Это просто немыслимо! Я бы ещё чуть-чуть поверил если 730 КГц. Но и это для САМа маловероятно.
Испытал я данную констукцию у себя для интереса, компилятор WinARM, на кварце 18.432 (MSK 73.9232) при компиляции без оптимизации (-O0) даёт приетно 0.5 Мгц при компиляции с оптимизацией (-O2) скважность сигнала уже не 0.5 да и форма на моем домашнем осцилографе сильно непрямоугольная F > 2-4 mhz (больше он у меня не берёт) Померил на своей плате с таким же кварцем и MCK 48 Мгц (IAR EWAVR 4.30A). ................................................................................ ........... #define EXT_OC 18432000 // Exetrnal ocilator MAINCK #define MCK 48054857 // MCK (PLLRC div by 2) ................................................................................ ........... while(1) { AT91F_PIO_ClearOutput( AT91C_BASE_PIOA, LED0 ) ; AT91F_PIO_SetOutput( AT91C_BASE_PIOA, LED0 ) ; } Получилось: при исполнении из RAM: частота 5,34 Мгц и скважность 67%, джиттер не заметен. Т.е. 3 такта MCK - низкий уровень, 6 тактов - высокий. при исполнении из FLASH: частота 4,00 Мгц и скважность 67%, джиттер не заметен. Т.е. 4 такта MCK - низкий уровень, 8 тактов - высокий.
Эскизы прикрепленных изображений
|
|
|
|
|
May 21 2006, 20:36
|
Гуру
     
Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448

|
Цитата(zltigo @ May 21 2006, 23:05)  Для бесконечного это действительно единсвенно однозначно понимаемый и безвариантно реализуемый вариант. Учение Маркса всесильно, потому что оно верно! Цитата(zltigo @ May 21 2006, 23:05)  А Вы действительно искренне считаете, что первый вариант читабельнее? Особенно, когда тело цикла одним взгядом не окидывается :-) Да, я действительно так считаю, и особенно в случае с длинным циклом. Неудобно мне хранить в памяти полное описание из for, тогда как для do..while нужно помнить лишь начальное состояние или условие выполнения. Встречный вопрос: а как быть, если управляющая переменная меняется в теле цикла? Цитата(zltigo @ May 21 2006, 23:05)  Ну и по поводу возможности всегда заменить на do{} - а что если тело цикла не надо выполнить НИ РАЗУ, дополнительнвй if() будем вешать снаружи за ради следования идее? Ну почему же, цикл while{} я считаю вполне кошерным, просто забыл упомянуть об этом в посте выше. Так что дополнительные if'ы не понадобятся.
|
|
|
|
|
May 21 2006, 21:13
|

Профессионал
    
Группа: Свой
Сообщений: 1 065
Регистрация: 8-10-05
Из: Kiev, UA
Пользователь №: 9 380

|
2 aaarrr Скоро модераторы надают нам по ушам.... и правильно сделают кстати  Но все же посоветую взять десяток С компилеров и пособирать два цикла for и while c разными уровнями оптимизации. О результах докладывать не обязательно  (Сам for недолюбливал до поры). Представьте себе Кэрниган и Ричи о чем-то думали и Страуструп через 20 лет с их мнением согласился.
--------------------
Вони шукають те, чого нема, Щоб довести, що його не існує.
|
|
|
|
|
May 21 2006, 21:14
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
Цитата(aaarrr @ May 21 2006, 23:36)  Ну почему же, цикл while{} я считаю вполне кошерным И чем он кошернее вырожденного случая for( ; x; ){} ? И чем потенциальная возможность задания, например, начального значения сносит крышу компилятору? Дело обстоит скорее наоборот - указание всего в одной конструкции только дополнительно увязывает все вместе и потенциально облегчает генерацию кода.
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
May 22 2006, 02:08
|
Местный
  
Группа: Свой
Сообщений: 204
Регистрация: 5-01-06
Пользователь №: 12 860

|
Цитата(Pasha 111 @ May 21 2006, 20:27)  Сделал такую вот программу:
void main() { AT91F_PMC_EnablePeriphClock(AT91C_BASE_PMC, 1 << AT91C_ID_PIOA); AT91F_PIO_CfgOutput(AT91C_BASE_PIOA, 1 << 17);
while(1) { AT91F_PIO_ClearOutput(AT91C_BASE_PIOA, 1 << 17); AT91F_PIO_SetOutput(AT91C_BASE_PIOA, 1 << 17); } }
Почему скорость переключения такая маленькая (~730 Гц)?? Прога в целом работает быстро, а вот PIO почему-то тормозит. Можно как-то выставить частоту для PIO? ИМХО если переключать быстрее, чем работает периферия, можно добиться такого состояния, что на выходе все время будет 0 (или 1, как получится). Переключение будет только в момент прерывания.
|
|
|
|
|
May 22 2006, 05:15
|
Гуру
     
Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448

|
Цитата(zltigo @ May 22 2006, 01:14)  И чем он кошернее вырожденного случая for( ; x; ){} ? Хотя бы тем, что ошибку в Код while(0x01); {} человек заметит с большей вероятностью, чем в Код for(;;); {} Компилятору действительно все равно, речь о читабельности и восприятии.
|
|
|
|
|
May 22 2006, 06:06
|
Частый гость
 
Группа: Свой
Сообщений: 172
Регистрация: 23-04-06
Пользователь №: 16 404

|
Цитата(ANT @ May 22 2006, 00:23)  while(1) { AT91F_PIO_ClearOutput( AT91C_BASE_PIOA, LED0 ) ; AT91F_PIO_SetOutput( AT91C_BASE_PIOA, LED0 ) ; } Получилось: при исполнении из RAM: частота 5,34 Мгц и скважность 67%, джиттер не заметен. Т.е. 3 такта MCK - низкий уровень, 6 тактов - высокий. при исполнении из FLASH: частота 4,00 Мгц и скважность 67%, джиттер не заметен. Т.е. 4 такта MCK - низкий уровень, 8 тактов - высокий. Есть подозрение что простой джам искажает сигнал так как его тоже надо учитывать =) лучше мерить что-то типа while(1) { AT91F_PIO_ClearOutput( AT91C_BASE_PIOA, LED0 ) ; AT91F_PIO_SetOutput( AT91C_BASE_PIOA, LED0 ) ; AT91F_PIO_ClearOutput( AT91C_BASE_PIOA, LED0 ) ; AT91F_PIO_SetOutput( AT91C_BASE_PIOA, LED0 ) ; AT91F_PIO_ClearOutput( AT91C_BASE_PIOA, LED0 ) ; AT91F_PIO_SetOutput( AT91C_BASE_PIOA, LED0 ) ; AT91F_PIO_ClearOutput( AT91C_BASE_PIOA, LED0 ) ; AT91F_PIO_SetOutput( AT91C_BASE_PIOA, LED0 ) ; }
|
|
|
|
|
May 22 2006, 12:53
|
Частый гость
 
Группа: Свой
Сообщений: 187
Регистрация: 22-06-04
Пользователь №: 127

|
Цитата(sff @ May 22 2006, 10:06)  лучше мерить что-то типа
while(1) { AT91F_PIO_ClearOutput( AT91C_BASE_PIOA, LED0 ) ; AT91F_PIO_SetOutput( AT91C_BASE_PIOA, LED0 ) ;
AT91F_PIO_ClearOutput( AT91C_BASE_PIOA, LED0 ) ; AT91F_PIO_SetOutput( AT91C_BASE_PIOA, LED0 ) ;
AT91F_PIO_ClearOutput( AT91C_BASE_PIOA, LED0 ) ; AT91F_PIO_SetOutput( AT91C_BASE_PIOA, LED0 ) ;
AT91F_PIO_ClearOutput( AT91C_BASE_PIOA, LED0 ) ; AT91F_PIO_SetOutput( AT91C_BASE_PIOA, LED0 ) ;
} Да, проверил и убедился в Вашей правоте, получилось, что на установку и сброс вывода (при выполнении из RAM) уходит по 3 такта, а еще три такта - на возврат к началу цикла. Теоретически, генерируемая частота может достигать в этом случае 48МГц/(3+3)=8МГц.
|
|
|
|
|
May 22 2006, 19:24
|

Частый гость
 
Группа: Свой
Сообщений: 154
Регистрация: 6-11-05
Из: Москва
Пользователь №: 10 515

|
Здравствуйте, уважаемые коллеги  По поводу таймера (TC0). Я писал так TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK TC_IER = AT91C_TC_CPCS При этом скорость таймера была 180 Гц. Подробное изучение докумнетации привело меня вот к чему: AT91C_TC_CLKS_TIMER_DIV1_CLOCK - делитель частоты MCK (это и так было ясно), а вот AT91C_TC_CPCS означает, что прерывание будет сработано тогда, когда сначение счётчика таймера (TC_CV) станет равно значению регистра C таймера (TC_RC). Так вот TC0_RC по умолчаниб равен 0, т.е. по сути прерывания срабатывали при переполнении таймера (он 16-ти битный), т.е. у меня 180 раз в секунду набегало 65536 тиков  Проблема решилась следующим образом: TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK | AT91C_TC_CPCTRG AT91C_TC_CPCTRG означает, что при равенстве значения в регистре С и в счётчике, счётчик будет обнуляться! Т.е. выставляя значение регистра C от 0 до 65535 могу выбирать скорость вызовов прерываний (если 0xFFFF - 180 Гц, то можно посчитать, сколько нужно для N герц, например мне нужно было 1 кГц - это число 0x2E14) По поводу PIO. Выполнение происходило в интеррапте другого таймера, да ещё и в режиме отладки на wiggler'е  Вот так вот. P.S. Только не бейте больно
Сообщение отредактировал Pasha 111 - May 22 2006, 19:26
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|