|
|
  |
прерывания от таймеров в SAM, опять затупил :( |
|
|
|
Sep 11 2006, 12:43
|
Знающий
   
Группа: Свой
Сообщений: 550
Регистрация: 16-06-04
Из: Казань
Пользователь №: 32

|
Цитата(SpiritDance @ Sep 11 2006, 16:28)  Кто-нибудь может скинуть рабочий код для PIT? так инициализируется таймер в uCOS-II: Код static void Tmr_TickInit (void) { INT32U counts;
/* Set the vector address for PIT */ AT91C_BASE_AIC->AIC_SVR[AT91C_ID_SYS] = (INT32U)Tmr_TickISR_Handler; AT91C_BASE_AIC->AIC_SMR[AT91C_ID_SYS] = AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE | AT91C_AIC_PRIOR_LOWEST; AT91C_BASE_AIC->AIC_ICCR = 1 << AT91C_ID_SYS; AT91C_BASE_AIC->AIC_IECR = 1 << AT91C_ID_SYS;
counts = (F_MCK / 16 / OS_TICKS_PER_SEC) - 1; AT91C_BASE_PITC->PITC_PIMR = AT91C_PITC_PITEN | AT91C_PITC_PITIEN | counts; }
--------------------
Главная линия этого опуса ясна мне насквозь!
|
|
|
|
|
Sep 11 2006, 19:38
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
Цитата(SpiritDance @ Sep 11 2006, 15:28)  Кто-нибудь может скинуть рабочий код для PIT? Код //Инициализация #define MAINCLK 4032000L #define PLLMUL 36 #define PLLDIV 3 #define MCK ((MAINCLK * PLLMUL) / PLLDIV)
#define RTOS_TICK_RATE 100 // Hz
// RTOS Timer AT91C_BASE_PITC->PITC_PIMR = (((MCK / 16) / RTOS_TICK_RATE - 1) & AT91C_PITC_PIV) \ | (1 * AT91C_PITC_PITEN) | (1 * AT91C_PITC_PITIEN);
AT91C_BASE_AIC->AIC_SMR[AT91C_ID_SYS] = AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE | AT91C_AIC_PRIOR_LOWEST; AT91C_BASE_AIC->AIC_SVR[AT91C_ID_SYS] = (uint32_t)OS::SystemTimer_Wrapper;
AT91C_BASE_AIC->AIC_IECR = (1<<AT91C_ID_SYS); //обработчик: OS_INTERRUPT void OS::SystemTimer_Wrapper() { volatile dword Tmp = AT91C_BASE_PITC->PITC_PIVR >> 20; while(Tmp--) { SystemTimer_ISR(); } } Цитата(SpiritDance @ Sep 11 2006, 15:28)  При этом если не читать PIVR флаг прерывания не снимается. Да, именно. НЕ СНИМАЕТСЯ ЕСЛИ НЕ ЧИТАТЬ PIVR. Я вот удивляюсь - а документацию кто читать должен? Уже на gaw.ru и перевод сделали для тех, кому лень выучить необходимые для пониманий 90% текста 50 слов и сочетаний по-английски. Цитата(SpiritDance @ Sep 11 2006, 15:28)  Отсюда вопрос каким образом от данного таймера получить интервал прерываний больший 20-разрядной части 1) Уменьшить MCLK 2) Организовать в прерывании этого таймера хоть 128-битный программный счетчик. Цитата(SpiritDance @ Sep 11 2006, 15:28)  и зачем вообще нужен PICNT? Для формирования периодических прерываний с постоянным интервалом. Например системный таймер RTOS, который обычно генерит прерывания с частотой 100-1000Гц.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Sep 12 2006, 11:57
|

Дух погибшего транзистора
   
Группа: Свой
Сообщений: 877
Регистрация: 6-09-05
Из: Москва
Пользователь №: 8 288

|
Цитата 1) Уменьшить MCLK 2) Организовать в прерывании этого таймера хоть 128-битный программный счетчик. Я вобщем не спрашивал как организовать счетчик. Просто я так понял что больший интервал аппаратных прерываний чем записывается в PIVR получить нельзя. Цитата Для формирования периодических прерываний с постоянным интервалом. Например системный таймер RTOS, который обычно генерит прерывания с частотой 100-1000Гц. Не понял. При чем здесь счетчик переполнений? Он же сбрасывается при считывании PIVR? Что касается документации то да, признаю, я часто бываю невнимателен.
--------------------
Yes, there are two paths you can go by But in the long run Theres still time to change the road youre on.
|
|
|
|
|
Sep 12 2006, 13:04
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
Цитата(SpiritDance @ Sep 12 2006, 14:57)  Я вобщем не спрашивал как организовать счетчик. Просто я так понял что больший интервал аппаратных прерываний чем записывается в PIVR получить нельзя. Да, нельзя. Тогда я не понял вопроса. А какой таймер позволяет делать больший чем разрядность таймера? Цитата Не понял. При чем здесь счетчик переполнений? Он же сбрасывается при считывании PIVR? Извиняюсь, я тоже бываю невнимателен. Почему-то показалось, что вопрос был про PIT вообще. Видимо чтобы узнать сколько прерываний было потеряно если это прерывание было запрещено надолго и потом программно вызвать обработчик нужное количество раз: Код volatile dword Tmp = AT91C_BASE_PITC->PITC_PIVR >> 20; while(Tmp--) { SystemTimer_ISR(); }
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Dec 3 2006, 13:37
|
Частый гость
 
Группа: Свой
Сообщений: 169
Регистрация: 10-11-05
Из: Воронеж
Пользователь №: 10 687

|
Цитата(aaarrr @ Aug 3 2006, 19:41)  P.S. Этот таймер далеко не так прост, как может показаться на первый взгляд. Использовать прерывание в данном случае я бы однозначно не рекомендовал. P.P.S. Но раз уж взялись - придется только добить. А поясните, пожалуйста, почему этот таймер не так прост и не рекомендуется использовать прерывания? Тоже только недано начал ковырять АРМ на AT91SAMx256 борде. И тоже попробовал поднять RTT. Поллинг работает, а прерывание стартует только в режиме LEVEL, но почему-то  рабоает нормально без запрета прерывания в прерывании и последующем его разрешении в основном цикле. Если меняю режим на EDGE то прерывание просто не запускается. Вообще. Если кому не напряжно глянуть в мои каракули, может подскажете где грабли? Код // Initialize the timer AT91F_RTTC_CfgPMC(); //Enable a clock source AT91F_RTTClearAlarmINT(AT91C_BASE_RTTC); AT91F_RTTSetPrescaler(AT91C_BASE_RTTC, 0x4000); AT91F_RTTRestart(AT91C_BASE_RTTC); AT91F_RTTSetRttIncINT(AT91C_BASE_RTTC);
// AIC initialization AT91F_AIC_CfgPMC(); AT91F_AIC_ConfigureIt(AT91C_BASE_AIC, AT91C_ID_SYS, AT91C_AIC_PRIOR_LOWEST, // AT91C_AIC_SRCTYPE_HIGH_LEVEL, AT91C_AIC_SRCTYPE_POSITIVE_EDGE, (void (*)())isr_system); AT91F_AIC_EnableIt(AT91C_BASE_AIC, AT91C_ID_SYS);
// Loop forever while (1) { int c;
c = AT91F_RTTReadValue(AT91C_BASE_RTTC); if (c != cval) { cval = c; if (AT91F_PIO_IsOutputDataStatusSet(AT91C_BASE_PIOB, led_mask[1])) AT91F_PIO_ClearOutput(AT91C_BASE_PIOB, led_mask[1]); else AT91F_PIO_SetOutput(AT91C_BASE_PIOB, led_mask[1]); } } Код __irq void isr_system() { if (AT91F_PIO_IsOutputDataStatusSet(AT91C_BASE_PIOB, led_mask[3])) AT91F_PIO_ClearOutput(AT91C_BASE_PIOB, led_mask[3]); else AT91F_PIO_SetOutput(AT91C_BASE_PIOB, led_mask[3]);
//If this is RTT interrupt if (AT91F_RTTGetStatus(AT91C_BASE_RTTC) != 0) { if (AT91F_PIO_IsOutputDataStatusSet(AT91C_BASE_PIOB, led_mask[0])) AT91F_PIO_ClearOutput(AT91C_BASE_PIOB, led_mask[0]); else AT91F_PIO_SetOutput(AT91C_BASE_PIOB, led_mask[0]); } AT91C_BASE_AIC->AIC_EOICR = 0; }
|
|
|
|
|
Dec 4 2006, 04:27
|
Гуру
     
Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448

|
Цитата(gladov @ Dec 3 2006, 13:37)  А поясните, пожалуйста, почему этот таймер не так прост и не рекомендуется использовать прерывания? Тоже только недано начал ковырять АРМ на AT91SAMx256 борде. И тоже попробовал поднять RTT. Поллинг работает, а прерывание стартует только в режиме LEVEL, но почему-то  рабоает нормально без запрета прерывания в прерывании и последующем его разрешении в основном цикле. Вопрос в том, действительно ли прерывание RTT нормально работает в режиме LEVEL. Как я уже писал раньше, оно снимается через 2 цикла SCLK, то есть обработчик может вызываться несколько раз подряд, пока линия прерывания остается активной. А если количество вызовов будет нечетным, то на внешнем поведении светодиодов это не отразится  Цитата(gladov @ Dec 3 2006, 13:37)  Если меняю режим на EDGE то прерывание просто не запускается. Вообще. Режим EDGE для системного прерывания использовать не совсем корректно, так как у него может быть несколько источников, объединенных через логическое ИЛИ. То есть, если при выходе из обработчика останется активным хотя бы один из источников, дальнейшая работа будет заблокирована, что Вы, возможно, и наблюдаете.
|
|
|
|
|
Dec 4 2006, 22:55
|
Частый гость
 
Группа: Свой
Сообщений: 169
Регистрация: 10-11-05
Из: Воронеж
Пользователь №: 10 687

|
Цитата(aaarrr @ Dec 4 2006, 04:27)  Вопрос в том, действительно ли прерывание RTT нормально работает в режиме LEVEL. Как я уже писал раньше, оно снимается через 2 цикла SCLK, то есть обработчик может вызываться несколько раз подряд, пока линия прерывания остается активной. А если количество вызовов будет нечетным, то на внешнем поведении светодиодов это не отразится  Согласен полностью Цитата(gladov @ Dec 3 2006, 13:37)  Если меняю режим на EDGE то прерывание просто не запускается. Вообще. Режим EDGE для системного прерывания использовать не совсем корректно, так как у него может быть несколько источников, объединенных через логическое ИЛИ. То есть, если при выходе из обработчика останется активным хотя бы один из источников, дальнейшая работа будет заблокирована, что Вы, возможно, и наблюдаете. Почему системное прерывание не желательно использовать по фронту понятно, но я больше никакие системные прерывания кроме RTT не разрешаю. Конечно они могут быть у какой-либо периферии разрешены после старта (я конечно весь DS пока не прочитал), но здравый смысл подсказывает, что после старта вся периферия должна быть выключена. Выяснились новые подробности. Если перед основным циклом прочесть RTTC_RTSR то все работает как часы, из чего я делаю вывод, что иногда при старте прерывание от RTT уже активно! Сбросить его некому, т.к. у меня чтение его производится только из прерывания. Отсюда вопрос: а почему оно может быть активно после старта? Я же делаю ему (RTT) резет! Может я что-то не так инициализирую? В принципе, глюк ясен и понятен. Как бороться тоже ясно и вопрос почти снят, но хочется узнать где же были грабли....
|
|
|
|
|
Dec 5 2006, 00:05
|
Гуру
     
Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448

|
Сейчас уже не помню, в чем было дело, но кажется прерывание работало только при инициализации таймера одной командой - Код *AT91C_RTTC_RTMR = 0x00008000 | AT91C_RTTC_RTTINCIEN | AT91C_RTTC_RTTRST - а когда сброс выполнялся отдельно, то возникали проблемы. Имеет смысл посмотреть свежую errat'у - там, кажется, упоминался RTT.
|
|
|
|
|
Dec 5 2006, 11:47
|
Частый гость
 
Группа: Свой
Сообщений: 169
Регистрация: 10-11-05
Из: Воронеж
Пользователь №: 10 687

|
Цитата(aaarrr @ Dec 5 2006, 00:05)  Сейчас уже не помню, в чем было дело, но кажется прерывание работало только при инициализации таймера одной командой - Код *AT91C_RTTC_RTMR = 0x00008000 | AT91C_RTTC_RTTINCIEN | AT91C_RTTC_RTTRST - а когда сброс выполнялся отдельно, то возникали проблемы. Имеет смысл посмотреть свежую errat'у - там, кажется, упоминался RTT. errat'у свежую смотрел, но там написано только что SR нельзя часто опрашивать, иначе он теряет события. На этот глюк я тоже нарывался Инициализация одной строкой тоже не помогла - не сбрасывается он корректно! Ну и черт с ним. Проехали и забыли. Будем считать это багом, хотя я ни разу еще в железках не нарывался на недокументированные ошибки...
|
|
|
|
|
Dec 5 2006, 19:35
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
Цитата(gladov @ Dec 5 2006, 10:47)  Инициализация одной строкой тоже не помогла - не сбрасывается он корректно! Ну и черт с ним. Проехали и забыли. Будем считать это багом, хотя я ни разу еще в железках не нарывался на недокументированные ошибки... Отлаживаете через JTAG? Учитываете, что кнопка "сброс" в оболочке сбрасывает только ядро, но не периферию, т.е. если перед нажатием кнопки "сброс" таймер был включен, то он продолжает тикать? Учитываете, что если открыто окно с регистрами периферии, это вызывает их чтение и сброс некоторых флагов (и другие действия по чтению некоторых регистров)?
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Dec 5 2006, 19:43
|
Частый гость
 
Группа: Свой
Сообщений: 169
Регистрация: 10-11-05
Из: Воронеж
Пользователь №: 10 687

|
Цитата(Сергей Борщ @ Dec 5 2006, 19:35)  Цитата(gladov @ Dec 5 2006, 10:47)  Инициализация одной строкой тоже не помогла - не сбрасывается он корректно! Ну и черт с ним. Проехали и забыли. Будем считать это багом, хотя я ни разу еще в железках не нарывался на недокументированные ошибки...
Отлаживаете через JTAG? Учитываете, что кнопка "сброс" в оболочке сбрасывает только ядро, но не периферию, т.е. если перед нажатием кнопки "сброс" таймер был включен, то он продолжает тикать? Учитываете, что если открыто окно с регистрами периферии, это вызывает их чтение и сброс некоторых флагов (и другие действия по чтению некоторых регистров)? Нет, JTAG'а нет вообще. А сброс непричем, т.к. я же в начале программы даю резет для RTT.
|
|
|
|
|
Dec 6 2006, 10:23
|
Частый гость
 
Группа: Свой
Сообщений: 169
Регистрация: 10-11-05
Из: Воронеж
Пользователь №: 10 687

|
Итак, подводим итоги. Может быть кому-нибудь пригодится. Вообще-то я пришел к выводу, что RTT в sam'ах кривоват. И кривой он из-за своей природы, т.к. тактируется от RC-цепочки, котороая по-определению нестабильна в той или иной степени. Поэтому использовать его как средство для отсчета равных точных промежутков времени (как обычно используют таймеры) не получается. А раз так, то и прерывания от него особо не нужны... Но мне все-таки было интересно из принципа доковырять этот девайс до максимальной ясности. При использовании прерываний по уровню все работает (см. посты от aaarrr). С прерываниями по фронту есть проблема, но ее решать смысла нет, т.к. (опять же см. aaarrr) системные прерывания по фронту включать крайне нежелательно. А проблема в том, что сброс RTT, а именно бит RTTRST, не сбрасывает бит RTTINC в регистре RTSR. Поэтому после сброса ядра процессора бит RTTINC может оказаться в активном состоянии, следовательно, фронта никогда не произойдет, поэтому и прерывание не стработает, а тогда не будет чтения из регистра RTSR и бит RTTINC не сбросится. Выход - после сброса RTT читать RTSR один раз чтобы принудительно сбросить флаг инкремента. Спасибо всем за помощь в изучении проблемы
|
|
|
|
|
  |
2 чел. читают эту тему (гостей: 2, скрытых пользователей: 0)
Пользователей: 0
|
|
|