Перейти к содержанию
    

прерывания от таймеров в SAM

Кто-нибудь может скинуть рабочий код для 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;
}

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Кто-нибудь может скинуть рабочий код для 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();
    }
}

При этом если не читать PIVR флаг прерывания не снимается.
Да, именно. НЕ СНИМАЕТСЯ ЕСЛИ НЕ ЧИТАТЬ PIVR. Я вот удивляюсь - а документацию кто читать должен? Уже на gaw.ru и перевод сделали для тех, кому лень выучить необходимые для пониманий 90% текста 50 слов и сочетаний по-английски.

Отсюда вопрос каким образом от данного таймера получить интервал прерываний больший 20-разрядной части

1) Уменьшить MCLK

2) Организовать в прерывании этого таймера хоть 128-битный программный счетчик.

и зачем вообще нужен PICNT?

Для формирования периодических прерываний с постоянным интервалом. Например системный таймер RTOS, который обычно генерит прерывания с частотой 100-1000Гц.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1) Уменьшить MCLK

2) Организовать в прерывании этого таймера хоть 128-битный программный счетчик.

Я вобщем не спрашивал как организовать счетчик. Просто я так понял что больший интервал аппаратных прерываний чем записывается в PIVR получить нельзя.

 

Для формирования периодических прерываний с постоянным интервалом. Например системный таймер RTOS, который обычно генерит прерывания с частотой 100-1000Гц.

Не понял. При чем здесь счетчик переполнений? Он же сбрасывается при считывании PIVR?

 

Что касается документации то да, признаю, я часто бываю невнимателен.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Я вобщем не спрашивал как организовать счетчик. Просто я так понял что больший интервал аппаратных прерываний чем записывается в PIVR получить нельзя.
Да, нельзя. Тогда я не понял вопроса. А какой таймер позволяет делать больший чем разрядность таймера?

 

Не понял. При чем здесь счетчик переполнений? Он же сбрасывается при считывании PIVR?
Извиняюсь, я тоже бываю невнимателен. Почему-то показалось, что вопрос был про PIT вообще. Видимо чтобы узнать сколько прерываний было потеряно если это прерывание было запрещено надолго и потом программно вызвать обработчик нужное количество раз:

    volatile dword Tmp = AT91C_BASE_PITC->PITC_PIVR >> 20;
    while(Tmp--) {
        SystemTimer_ISR();
    }

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Да, нельзя. Тогда я не понял вопроса. А какой таймер позволяет делать больший чем разрядность таймера?

Ну вообще-то полная разрядность таймера PIT 20 + 12 :) Хотя если подумать для чего сделан данный таймер то вобщем достаточно и 20 разрядов. Жаль только частота фиксированная.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

P.P.S. Но раз уж взялись - придется только добить.

 

А поясните, пожалуйста, почему этот таймер не так прост и не рекомендуется использовать прерывания? Тоже только недано начал ковырять АРМ на AT91SAMx256 борде. И тоже попробовал поднять RTT. Поллинг работает, а прерывание стартует только в режиме LEVEL, но почему-то :wacko: рабоает нормально без запрета прерывания в прерывании и последующем его разрешении в основном цикле. Если меняю режим на 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;
}

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А поясните, пожалуйста, почему этот таймер не так прост и не рекомендуется использовать прерывания? Тоже только недано начал ковырять АРМ на AT91SAMx256 борде. И тоже попробовал поднять RTT. Поллинг работает, а прерывание стартует только в режиме LEVEL, но почему-то :wacko: рабоает нормально без запрета прерывания в прерывании и последующем его разрешении в основном цикле.

Вопрос в том, действительно ли прерывание RTT нормально работает в режиме LEVEL. Как я уже писал раньше, оно снимается через 2 цикла SCLK, то есть обработчик может вызываться несколько раз подряд, пока линия прерывания остается активной. А если количество вызовов будет нечетным, то на внешнем поведении светодиодов это не отразится :)

 

Если меняю режим на EDGE то прерывание просто не запускается. Вообще.

Режим EDGE для системного прерывания использовать не совсем корректно, так как у него может быть несколько источников, объединенных через логическое ИЛИ. То есть, если при выходе из обработчика останется активным хотя бы один из источников, дальнейшая работа будет заблокирована, что Вы, возможно, и наблюдаете.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вопрос в том, действительно ли прерывание RTT нормально работает в режиме LEVEL. Как я уже писал раньше, оно снимается через 2 цикла SCLK, то есть обработчик может вызываться несколько раз подряд, пока линия прерывания остается активной. А если количество вызовов будет нечетным, то на внешнем поведении светодиодов это не отразится :)

 

Согласен полностью :blush:

 

Если меняю режим на EDGE то прерывание просто не запускается. Вообще.

Режим EDGE для системного прерывания использовать не совсем корректно, так как у него может быть несколько источников, объединенных через логическое ИЛИ. То есть, если при выходе из обработчика останется активным хотя бы один из источников, дальнейшая работа будет заблокирована, что Вы, возможно, и наблюдаете.

 

Почему системное прерывание не желательно использовать по фронту понятно, но я больше никакие системные прерывания кроме RTT не разрешаю. Конечно они могут быть у какой-либо периферии разрешены после старта (я конечно весь DS пока не прочитал), но здравый смысл подсказывает, что после старта вся периферия должна быть выключена.

 

Выяснились новые подробности. Если перед основным циклом прочесть RTTC_RTSR то все работает как часы, из чего я делаю вывод, что иногда при старте прерывание от RTT уже активно! Сбросить его некому, т.к. у меня чтение его производится только из прерывания. Отсюда вопрос: а почему оно может быть активно после старта? Я же делаю ему (RTT) резет! Может я что-то не так инициализирую?

В принципе, глюк ясен и понятен. Как бороться тоже ясно и вопрос почти снят, но хочется узнать где же были грабли....

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Сейчас уже не помню, в чем было дело, но кажется прерывание работало только при инициализации таймера одной командой -

 

*AT91C_RTTC_RTMR = 0x00008000 | AT91C_RTTC_RTTINCIEN | AT91C_RTTC_RTTRST

 

- а когда сброс выполнялся отдельно, то возникали проблемы.

 

Имеет смысл посмотреть свежую errat'у - там, кажется, упоминался RTT.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Сейчас уже не помню, в чем было дело, но кажется прерывание работало только при инициализации таймера одной командой -

 

*AT91C_RTTC_RTMR = 0x00008000 | AT91C_RTTC_RTTINCIEN | AT91C_RTTC_RTTRST

 

- а когда сброс выполнялся отдельно, то возникали проблемы.

 

Имеет смысл посмотреть свежую errat'у - там, кажется, упоминался RTT.

 

errat'у свежую смотрел, но там написано только что SR нельзя часто опрашивать, иначе он теряет события. На этот глюк я тоже нарывался :)

 

Инициализация одной строкой тоже не помогла - не сбрасывается он корректно! Ну и черт с ним. Проехали и забыли. Будем считать это багом, хотя я ни разу еще в железках не нарывался на недокументированные ошибки...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Инициализация одной строкой тоже не помогла - не сбрасывается он корректно! Ну и черт с ним. Проехали и забыли. Будем считать это багом, хотя я ни разу еще в железках не нарывался на недокументированные ошибки...
Отлаживаете через JTAG? Учитываете, что кнопка "сброс" в оболочке сбрасывает только ядро, но не периферию, т.е. если перед нажатием кнопки "сброс" таймер был включен, то он продолжает тикать? Учитываете, что если открыто окно с регистрами периферии, это вызывает их чтение и сброс некоторых флагов (и другие действия по чтению некоторых регистров)?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Инициализация одной строкой тоже не помогла - не сбрасывается он корректно! Ну и черт с ним. Проехали и забыли. Будем считать это багом, хотя я ни разу еще в железках не нарывался на недокументированные ошибки...

Отлаживаете через JTAG? Учитываете, что кнопка "сброс" в оболочке сбрасывает только ядро, но не периферию, т.е. если перед нажатием кнопки "сброс" таймер был включен, то он продолжает тикать? Учитываете, что если открыто окно с регистрами периферии, это вызывает их чтение и сброс некоторых флагов (и другие действия по чтению некоторых регистров)?

 

Нет, JTAG'а нет вообще. А сброс непричем, т.к. я же в начале программы даю резет для RTT.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Нет, JTAG'а нет вообще. А сброс непричем, т.к. я же в начале программы даю резет для RTT.
Тогда не представляю :-(
Изменено пользователем Сергей Борщ

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

Спасибо всем за помощь в изучении проблемы :cheers:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

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

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...