Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: прерывания от таймеров в SAM
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
Страницы: 1, 2
gladov
Цитата(aaarrr @ Aug 3 2006, 19:41) *
P.S. Этот таймер далеко не так прост, как может показаться на первый взгляд. Использовать прерывание в данном случае я бы однозначно не рекомендовал.
P.P.S. Но раз уж взялись - придется только добить.


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

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

Цитата(gladov @ Dec 3 2006, 13:37) *
Если меняю режим на EDGE то прерывание просто не запускается. Вообще.

Режим EDGE для системного прерывания использовать не совсем корректно, так как у него может быть несколько источников, объединенных через логическое ИЛИ. То есть, если при выходе из обработчика останется активным хотя бы один из источников, дальнейшая работа будет заблокирована, что Вы, возможно, и наблюдаете.
gladov
Цитата(aaarrr @ Dec 4 2006, 04:27) *
Вопрос в том, действительно ли прерывание RTT нормально работает в режиме LEVEL. Как я уже писал раньше, оно снимается через 2 цикла SCLK, то есть обработчик может вызываться несколько раз подряд, пока линия прерывания остается активной. А если количество вызовов будет нечетным, то на внешнем поведении светодиодов это не отразится smile.gif


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

Цитата(gladov @ Dec 3 2006, 13:37) *
Если меняю режим на EDGE то прерывание просто не запускается. Вообще.
Режим EDGE для системного прерывания использовать не совсем корректно, так как у него может быть несколько источников, объединенных через логическое ИЛИ. То есть, если при выходе из обработчика останется активным хотя бы один из источников, дальнейшая работа будет заблокирована, что Вы, возможно, и наблюдаете.


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

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

Код
*AT91C_RTTC_RTMR = 0x00008000 | AT91C_RTTC_RTTINCIEN | AT91C_RTTC_RTTRST


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

Имеет смысл посмотреть свежую errat'у - там, кажется, упоминался RTT.
gladov
Цитата(aaarrr @ Dec 5 2006, 00:05) *
Сейчас уже не помню, в чем было дело, но кажется прерывание работало только при инициализации таймера одной командой -

Код
*AT91C_RTTC_RTMR = 0x00008000 | AT91C_RTTC_RTTINCIEN | AT91C_RTTC_RTTRST


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

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


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

Инициализация одной строкой тоже не помогла - не сбрасывается он корректно! Ну и черт с ним. Проехали и забыли. Будем считать это багом, хотя я ни разу еще в железках не нарывался на недокументированные ошибки...
Сергей Борщ
Цитата(gladov @ Dec 5 2006, 10:47) *
Инициализация одной строкой тоже не помогла - не сбрасывается он корректно! Ну и черт с ним. Проехали и забыли. Будем считать это багом, хотя я ни разу еще в железках не нарывался на недокументированные ошибки...
Отлаживаете через JTAG? Учитываете, что кнопка "сброс" в оболочке сбрасывает только ядро, но не периферию, т.е. если перед нажатием кнопки "сброс" таймер был включен, то он продолжает тикать? Учитываете, что если открыто окно с регистрами периферии, это вызывает их чтение и сброс некоторых флагов (и другие действия по чтению некоторых регистров)?
gladov
Цитата(Сергей Борщ @ Dec 5 2006, 19:35) *
Цитата(gladov @ Dec 5 2006, 10:47) *

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


Нет, JTAG'а нет вообще. А сброс непричем, т.к. я же в начале программы даю резет для RTT.
Сергей Борщ
Цитата(gladov @ Dec 5 2006, 18:43) *
Нет, JTAG'а нет вообще. А сброс непричем, т.к. я же в начале программы даю резет для RTT.
Тогда не представляю :-(
gladov
Итак, подводим итоги. Может быть кому-нибудь пригодится. Вообще-то я пришел к выводу, что RTT в sam'ах кривоват. И кривой он из-за своей природы, т.к. тактируется от RC-цепочки, котороая по-определению нестабильна в той или иной степени. Поэтому использовать его как средство для отсчета равных точных промежутков времени (как обычно используют таймеры) не получается. А раз так, то и прерывания от него особо не нужны... Но мне все-таки было интересно из принципа доковырять этот девайс до максимальной ясности.
При использовании прерываний по уровню все работает (см. посты от aaarrr). С прерываниями по фронту есть проблема, но ее решать смысла нет, т.к. (опять же см. aaarrr) системные прерывания по фронту включать крайне нежелательно. А проблема в том, что сброс RTT, а именно бит RTTRST, не сбрасывает бит RTTINC в регистре RTSR. Поэтому после сброса ядра процессора бит RTTINC может оказаться в активном состоянии, следовательно, фронта никогда не произойдет, поэтому и прерывание не стработает, а тогда не будет чтения из регистра RTSR и бит RTTINC не сбросится. Выход - после сброса RTT читать RTSR один раз чтобы принудительно сбросить флаг инкремента.
Спасибо всем за помощь в изучении проблемы cheers.gif
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.