Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: прерывания от таймеров в SAM
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
Страницы: 1, 2
SpiritDance
Что-то с самом у меня не клеится. Не пионимаю как организовать прерывание по переполнению таймера.
вобщем что понятно. нужно проинициализировать aic и поставить таймер в режим сравнения. в регистр сравнения rc таймера записать максимальное значение 0xFFFF
Код
void set_timer_channel1_to_timer_mode(void)
{
    /* */
    //AT91C_BASE_AIC->AIC_SMR[AT91C_ID_TC1] = PRIORITY_TIMER1 | AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE;
    AT91C_BASE_AIC->AIC_SMR[AT91C_ID_TC1] = PRIORITY_TIMER1 | AT91C_AIC_SRCTYPE_INT_EDGE_TRIGGERED;

    AT91C_BASE_AIC->AIC_SVR[AT91C_ID_TC1] = (unsigned int)ih_timer1_overload;
    /* ðàçðåøàåì ïðåðûâàíèå îò êàíàëà 1 òàéìåðà-ñ÷åò÷èêà */
    AT91C_BASE_AIC->AIC_IECR = (1 << AT91C_ID_TC1);

    /* ïîäêëþ÷àåì ê êàíàëó ñèñòåìíóþ ÷àñòîòó è âêëþ÷àåì âûâîä */
    AT91F_PMC_EnablePeriphClock(AT91C_BASE_PMC, 1 << AT91C_ID_TC1);

    /*  */
    AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK
                             |
                             AT91C_TC_WAVE
                             |
                             AT91C_TC_WAVESEL_UP_AUTO;


    AT91C_BASE_TC1->TC_RC = 0xFFFF;
    AT91C_BASE_TC1->TC_IER = AT91C_TC_CPCS;

    /* çàïóñêàåì òàéìåð */
    AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
}


далее пишется простенький обработчик
Код
void ih_timer1_overload(void) __irq
{
//    Time = AT91C_BASE_AIC->AIC_IVR;                 //automatic clear current interrupt
    AT91C_BASE_AIC->AIC_ICCR = (1 << AT91C_ID_TC1);  //clear current interrupt
  
    //if(AT91C_BASE_TC1->TC_SR & AT91C_TC_CPCS)
    {
        Time   = 0xFFFF;
        ReloadCountTime++;
        ReloadCountPulses = 0;
    }
}


Что не понятно.
1. Надо ли очищать какой-то флаг источника прерываний в САМе? То есть правильно ли я делаю что пишу первую(закоментированную) или вторую строчки обработчика?

2. Каким образом таймер генерит прерывания и выбирается их конкретный источник (сравнение по ra rb rc, захват и пр.) в даташите по этому поводу очень грамотно написано
Цитата
Interrupt
The TC has an interrupt line connected to the Advanced Interrupt Controller (AIC). Handling the
TC interrupt requires programming the AIC before configuring the TC.

Круто ничего не скажешь... дальше то что?angry.gif
по поводу определения истьочника подозреваю надо читать статус. Но генерятся то прерывания когда?

3 Прерывание вызывается но только один раз. Подозреваю это из-за того что я что-то упустил с источниками прерываний. Или вообще что-то упустил. При этом я вижу в эмуляторе что флаг cpcs в регистре статуса не изменяется. При каких условиях сбрасывается CPCS?

Памажите а?
SpiritDance
Кстати при выборе TC_IER = AT91C_TC_COVFS прерывание тоже 1 раз вызывается. и флаг преполнения после первого вызова торчит постоянно. В чем проблема?
aaarrr
Цитата(SpiritDance @ Jun 26 2006, 13:41) *
1. Надо ли очищать какой-то флаг источника прерываний в САМе? То есть правильно ли я делаю что пишу первую(закоментированную) или вторую строчки обработчика?

2. Каким образом таймер генерит прерывания и выбирается их конкретный источник (сравнение по ra rb rc, захват и пр.) в даташите по этому поводу очень грамотно написано

3 Прерывание вызывается но только один раз. Подозреваю это из-за того что я что-то упустил с источниками прерываний. Или вообще что-то упустил. При этом я вижу в эмуляторе что флаг cpcs в регистре статуса не изменяется. При каких условиях сбрасывается CPCS?


1. Нужно читать TC_SR. Раскомментируйте вторую строку и добавьте в конце AT91C_BASE_AIC->AIC_EOICR = 0x00;
2. Если активен один или несколько источников в таймере, то будет вызвано прерывание.
3. см. п.1

Документация у атмела совершенно нормальная, тщательнее надо smile.gif
SpiritDance
БЛИИИИН я пропустил этот ;*№* EOICR. А уж было думал пойти повесится. Спасибо.

Цитата(aaarrr @ Jun 26 2006, 14:36) *
Документация у атмела совершенно нормальная, тщательнее надо smile.gif

Ничего не говорю против, документация - лучшая из того что наблюдается в АРМах. Только вот... некоторые моменты расписаны очень подробно а некоторые как-то не очень.
AVR
Спасите, я тоже уже готов повеситься. Не могу понять как заставить срабатывать прерывание по RTT. Таймер запускается и считает ~1 раз в секунду, но самого прерывание не происходит... Возможно чего-нибудь очень важное забыл настроить... help.gif
ЗЫ Отлаживаю на реальном sam7s64 через Wiggler в CW 1.6
Код
int y = 0;
void IntHandler()
{
    y++;
}

int main(void)
{
    struct x a;
  int i;
    AIC_SVR12 = (int)IntHandler;
    AIC_SMR12 |= 1;
    RTT_VR = 0;
    RTT_MR = 0x00008000 | RTT_MR_RTTINCIEN | RTT_MR_RTTRST;
    AIC_IECR |= 1<<12;
    PMC_PCER = (1<<2);
    int w = 0;
    debug_printf("Initialized!\n");
    while(1)
    {
        if(w != RTT_VR)
        {
            debug_printf("New value of RTT_VR = %4i; y = %4i\n", RTT_VR, y);
            w = RTT_VR;
        }
    }
  return 0;
}

Лог:
Код
Initialized!
New value of RTT_VR =    1; y =    0
New value of RTT_VR =    2; y =    0
New value of RTT_VR =    3; y =    0
SpiritDance
Какой-то не такой у вас файл описаний smile.gif , возьмите лучше это.
На вскидку помарки в коде

В прерывании не читается SR

PIO включать не обязательно
PMC_PCER = (1<<2);

Регистр VR - read-only.

на всякий случай
volatile int y

12 соответсвует AT91C_ID_TC0, а RTT я что то вообще не нашел.
AVR
SpiritDance, ничего не помогло... sad.gif
PeripheralID для RTT тоже не нашел... wacko.gif
Приведите, пожалуйста, пример наипростейшей инициализации прерывания от таймера.
ЗЫ
К IAR конечно есть примеры, в которых это всё расписано, но в них я не вижу ничего принципиально отличного от того что у меня... =(
ЗЫЗЫ
Вот в AVRке достаточно SEI и просто записать битик разрешающий то или иное прерывание... smile.gif
aaarrr
Цитата(AVR @ Jul 28 2006, 00:46) *
PeripheralID для RTT тоже не нашел... wacko.gif

Эх, господа... RTT является частью System Controller'а, соответственно его PID - AT91C_ID_SYS.
SpiritDance
Цитата(AVR @ Jul 28 2006, 00:46) *
SpiritDance, ничего не помогло... sad.gif

И не должно было. ID то не тот. И AIC вы не на то прерывание инициализируете, и хендлер не туда записываете. Я только указал на то на что можно было еще наступить.

aaarrr
Очередное спасибо за то что несете свет в наше темное царство. smile.gif
AVR
Не получается... sad.gif
Код
volatile int x, y;
void IntHandler()
{
    x = AIC_IVR;
    y++;
    x = RTT_SR;
    AIC_EOICR = 0x777;
}

...

    AIC_SVR2 = (int)IntHandler;
    RTT_MR = 0x00008000 | RTT_MR_RTTINCIEN | RTT_MR_RTTRST;
    AIC_IECR |= 2;
    AIC_ISCR |= 2;
    AIC_SMR1 = (1<<5) | 7;
aaarrr
Цитата(AVR @ Jul 29 2006, 14:29) *
Не получается... sad.gif


Во-первых, функция обработки прерывания должна иметь соответствующий
модификатор - __irq, __interrupt и т.п., не знаю, что должно быть в CW.
Далее, читать AIC_IVR не нужно, AIC_IECR - это write-only регистр, писать
в AIC_ISCR ничего не нужно. Кроме того, Вы пишите AIC_SMR1 вместо AIC_SMR2.

Теперь примеры кода.

Номер 1, с level sensetive прерыванием. Здесь требуется дополнительная проверка
в основном цикле, так как прерывание RTT снимается аж через 2 цикла SCLK после
чтения статуса.
Код
void rtt_init(void)
{
    *AT91C_RTTC_RTMR = 0x00008000 | AT91C_RTTC_RTTINCIEN | AT91C_RTTC_RTTRST;

    AT91C_BASE_AIC->AIC_SVR[AT91C_ID_SYS] = (u_int)rtt_handler;
    AT91C_BASE_AIC->AIC_IECR = (0x01 << AT91C_ID_SYS);
}

void main(void)
{
    while(0x01)
    {
        if((*AT91C_RTTC_RTSR & AT91C_RTTC_RTTINC) == 0x00)
            *AT91C_RTTC_RTMR |= AT91C_RTTC_RTTINCIEN;

        ...
    }
}

__irq void rtt_handler(void)
{
    u_int a;

    a = *AT91C_RTTC_RTSR;
    y++;
    *AT91C_RTTC_RTMR &= ~AT91C_RTTC_RTTINCIEN;
    *AT91C_AIC_EOICR = a;
}


Номер 2, с edge sensetive прерыванием. Проще, но вылезут проблемы
при использовании других источников для SYS_IRQ.

Код
void rtt_init(void)
{
    *AT91C_RTTC_RTMR = 0x00008000 | AT91C_RTTC_RTTINCIEN | AT91C_RTTC_RTTRST;

    AT91C_BASE_AIC->AIC_SVR[AT91C_ID_SYS] = (u_int)rtt_handler;
    AT91C_BASE_AIC->AIC_SMR[AT91C_ID_SYS] = (0x01 << 0x05);
    AT91C_BASE_AIC->AIC_IECR = (0x01 << AT91C_ID_SYS);
}

__irq void rtt_handler(void)
{
    u_int a;

    a = *AT91C_RTTC_RTSR;
    y++;
    *AT91C_AIC_EOICR = a;
}
AVR
Спасибо, aaarrr.
Код
#include "AT91SAM7S64.h"
#include "system.h"
typedef unsigned char byte;
byte sw = 0;

__irq void IRQ_1()
{
    unsigned int a;
    a = *AT91C_RTTC_RTSR;
    sw = !sw;
    if(sw) AT91C_BASE_PIOA->PIO_CODR = BIT30;
    else AT91C_BASE_PIOA->PIO_SODR = BIT30;
    AT91C_BASE_RTTC->RTTC_RTMR &= ~AT91C_RTTC_RTTINCIEN;
    AT91C_BASE_AIC->AIC_EOICR = a;
}

int main()
{
    AT91C_BASE_PMC->PMC_PCER = 1<<AT91C_ID_PIOA;
    AT91C_BASE_PIOA->PIO_PER |= BIT30;
    AT91C_BASE_PIOA->PIO_OER |= BIT30;
    AT91C_BASE_PIOA->PIO_CODR |= BIT30;
    AT91C_BASE_RTTC->RTTC_RTMR = 0x00008000 | AT91C_RTTC_RTTINCIEN | AT91C_RTTC_RTTRST;
    AT91C_BASE_AIC->AIC_SVR[AT91C_ID_SYS] = (unsigned int)IRQ_1;
    AT91C_BASE_AIC->AIC_SMR[AT91C_ID_SYS] = (0x01 << 0x05);
    AT91C_BASE_AIC->AIC_IECR = (0x01 << AT91C_ID_SYS);
    while(1);
}

Всё это запустил на sam7s64 через wiggler в iar.
По-прежнему прерывание не происходит, хотя таймер тикает ~раз в секунду...
Возможно ли что всё дело в самом sam7s64? Данный код я запускаю из RAM - может ли это повлиять на работоспособность блока прерываний?
aaarrr
Ну уж одно прерывание в данном случае должно произойти.
Уберите из обработчика строку AT91C_BASE_RTTC->RTTC_RTMR &= ~AT91C_RTTC_RTTINCIEN;
aaarrr
Смотрите внимательнее, оба примера рабочие.

Да, а вы уверены, что прерывание вам действительно нужно? Я бы думал, что прерывания нужнее DBGU, если он используется, конечно.
SpiritDance
Почему вы так |= работаете с регистрами в АРМ.
Уних несколько хитреее чем в АВР все устроено. Для каждого набора бит, отвечающих за какие-либо периферийные функции существует три регистра, например для PIO:
1 SODR - чтобы установить высокий уровень на выводе нужно записать в соответсвующий бит еденицу.
2 CODR - чтобы сбросить вывод в низкий уровень нужно записать в соответсвующий бит ЕДЕНИЦУ
3 ODSR - чтобы узнать в каком состоянии нходится соответсвующий вывод, сконфигурированный как выход, нужно прочитать этот регистр.
Всегда читайте access type для регистров прежде чем что-либо с ними сделать. Прерывание должно работать.
AVR
Цитата(aaarrr @ Aug 3 2006, 03:43) *
Смотрите внимательнее, оба примера рабочие.

Я проклят, не работает... sad.gif
Если заменить while(true) на
static int x;
if(x != AT91C_BASE_RTTC->RTTC_RTVR)
{
x = AT91C_BASE_RTTC->RTTC_RTVR;
sw = !sw;
if(sw) AT91C_BASE_PIOA->PIO_CODR = BIT30;
else AT91C_BASE_PIOA->PIO_SODR = BIT30;
}
то светодиод, повешенный на соответсвующий вывод мигает с частотой ~1 Гц...
Если же закоментировать и надеяться только на прерывание, то ничего не происходит вообще.
Цитата
Да, а вы уверены, что прерывание вам действительно нужно? Я бы думал, что прерывания нужнее DBGU, если он используется, конечно.

Таймер я выбрал как самое простейшее что может вызыввать прерывания.
Если же я не могу осилить даже простой таймер, то про DBGU вообще мечтать не приходится... sad.gif
AVR
Попробовал модифицировать пример AT91SAM7S64-PeriodicIntervalTimer-IAR4_30A-1_21 в котором таймер срабатывает каждые 200 мс. Добавил мигание светодиодом в обработчик прерывания и... тоже не работает. Но ведь это же провереный код, а тоже не работает. Как быть?... =( help.gif
ЗЫ Уже готов вены резать...
aaarrr
Вены резать рано. Рабочий код должен выглядеть примерно так:
Код
#include "AT91SAM7S64.h"
#include "system.h"
typedef unsigned char byte;
byte sw = 0;

__irq void IRQ_1()
{
    unsigned int a;

    a = *AT91C_RTTC_RTSR;
    sw = !sw;
    if(sw) AT91C_BASE_PIOA->PIO_CODR = BIT30;
    else AT91C_BASE_PIOA->PIO_SODR = BIT30;
    AT91C_BASE_AIC->AIC_EOICR = a;
}

int main()
{
    AT91C_BASE_PIOA->PIO_PER = BIT30;
    AT91C_BASE_PIOA->PIO_OER = BIT30;
    AT91C_BASE_PIOA->PIO_CODR = BIT30;

    AT91C_BASE_RTTC->RTTC_RTMR = 0x00008000 | AT91C_RTTC_RTTINCIEN | AT91C_RTTC_RTTRST;

    AT91C_BASE_AIC->AIC_SVR[AT91C_ID_SYS] = (unsigned int)IRQ_1;
    AT91C_BASE_AIC->AIC_SMR[AT91C_ID_SYS] = (0x01 << 0x05);
    AT91C_BASE_AIC->AIC_IECR = (0x01 << AT91C_ID_SYS);

    while(1);
}

Это ^^^ работает?

P.S. Этот таймер далеко не так прост, как может показаться на первый взгляд. Использовать прерывание в данном случае я бы однозначно не рекомендовал.
P.P.S. Но раз уж взялись - придется только добить.
AVR
Цитата(aaarrr @ Aug 3 2006, 23:41) *
Это ^^^ работает?
P.S. Этот таймер далеко не так прост, как может показаться на первый взгляд. Использовать прерывание в данном случае я бы однозначно не рекомендовал.

Нет, это тоже не работает. Пробовал этот код запускать из RAM из под IAR через Wiggler - не работает. Пробовал выводить в формате raw-binary и через SAM-BA - программа хоть и записалась и после проверки выдало что запись совпала, но не работает вообще, даже не начинает выполняться...
Похоже, дело в самом SAM7S... Хотя всё должно быть рабочим, т.к. платка заводского изготовления от Olimex SAM7-H64 и ничего кроме светодиодика я пока не припаивал (причем не на саму платку, а через разъемы на отдельной макетке), т.е. повредить я сам не мог... Даже не знаю как быть...
SpiritDance
Ну глюки в армах вобщем привычное дело.
У меня вот недавно глючило прерывание по переполнению от tc1 - вызывалось в 2 раза чаще предполагаемого и флаг OVR был нулю равным, хотя с другими каналами все работало. пришлось по сравнению прерывание делать.
А не позднее как вчера генератор внутренний сдох при экспирементах с внешним генератором.
aaarrr
Цитата
Похоже, дело в самом SAM7S...

Цитата
Ну глюки в армах вобщем привычное дело.

Сказки не надо рассказывать. 99% всех проблем - от кривых рук.
SpiritDance
Руки у меня действительно не самые прямые но когда код работает на 2 каналах и не работает как надо на третьем оставшемся тут уж не до сказок. А вообще может его статикой вынесло - черт его знает.
Я пробоавал только на одном проце.
Хотя согласен с Вами - большинство проблем из-за человеческих ошибок. И здесь возможно присутмтвует некая тупая до безобразия ошибка. В стартапе например.
AVR
Цитата(SpiritDance @ Aug 4 2006, 22:55) *
Хотя согласен с Вами - большинство проблем из-за человеческих ошибок. И здесь возможно присутмтвует некая тупая до безобразия ошибка. В стартапе например.
Всё возможно, но я по причине своего нубства не могу найти где эта ошибка... sad.gif
Приложил этот многострадальный проектик (для IAR-ARM 4.40A).
Проверьте, пожалуйста, будет ли он работать на Вашем SAM7S64?
aaarrr
К сожалению, у меня нет IAR'а, но есть некоторые соображения:
- Глобально прерывания разрешены?
- Если используется level sensetive режим, то прерывание RTT нужно запрещать внутри обработчика, в противном случае оно может сработать несколько раз.
- и т.д.
AVR
Цитата(aaarrr @ Aug 5 2006, 22:32) *
К сожалению, у меня нет IAR'а, но есть некоторые соображения:
- Глобально прерывания разрешены?

Честно говоря, не нашел как можно разрешить глобально прерывания. Правда нашел как их можно глобально запретить AIC_DCR.GMSK, но дебаггер показывает что бит запрета не установлен, т.е. всё по идее должно работать.
Также обратил внимание что у меня всё время активны биты регистра AIC_IPR, которые соотвествуют SYSIRQ и AIC-IRQ1. AIC_IMR показывает что они разрешены, но ничего не происходит... Один раз проскочило что в AIC_IVR был адрес обработчика прерывания, т.е. вроде как должно разродиться, но...
Судя по картинке, всё что необходимо уже настроено...
Нажмите для просмотра прикрепленного файла

Цитата
- Если используется level sensetive режим, то прерывание RTT нужно запрещать внутри обработчика, в противном случае оно может сработать несколько раз.

Сработало бы хоть один разок... smile.gif
aaarrr
Глобально запретить прерывания можно на уровне ядра - достаточно бит I в CPSR установить. Добавьте в main вызов __enable_interrupt().
GetSmart
А забавно будет если AVR не знал, что нужно хоть раз активировать __enable_interrupt().
AVR
Цитата(GetSmart @ Aug 6 2006, 02:07) *
А забавно будет если AVR не знал, что нужно хоть раз активировать __enable_interrupt().

Это действительно забавно, именно это я и забыл, хотя на AVRах никогда не забывал вызывать именно эту функцию в IAR-AVR laugh.gif blush.gif
ЗЫ
Теперь у меня программа натыкается на то что показано на рисунке, а это бесконечный цикл.
Возможно нужно #pragma vector какое-нибудь добавить?...
aaarrr
Цитата
Теперь у меня программа натыкается на то что показано на рисунке, а это бесконечный цикл.


Поздравляю. А то, что этот бесконечный цикл находится на месте вектора irq, не наводит на размышления?

По-идее, там должно быть что-нибудь вроде этого:
Код
ldr    pc, [pc, #-0xf20]

Т.е. чтение PC из AIC_IVR.
AVR
Цитата(aaarrr @ Aug 6 2006, 02:30) *
Поздравляю. А то, что этот бесконечный цикл находится на месте вектора irq, не наводит на размышления?
По-идее, там должно быть что-нибудь вроде этого:
Код
ldr    pc, [pc, #-0xf20]

Т.е. чтение PC из AIC_IVR.

Точно, всё аналогично AVRкам, тоже надо добавить прагму vector = 0x18 перед обработчиком IRQ =)
AVR
Ура! Огромное спасибо всем за помощь! Срабатывает, и не раз =) Тему можно закрыть.
ЗЫ
Сегодня я самый счастливый нуб на свете =)
aaarrr
Цитата
Точно, всё аналогично AVRкам, тоже надо добавить прагму vector = 0x18 перед обработчиком IRQ =)

Что-то меня настораживает. Все же на 0x18 должно быть ldr pc, [pc, #-0xf20], или что-нибудь не столь лаконичное, но аналогичное по смыслу.
А pragma vector = 0x18 - какая-то вредная штуковина, ИМХО.
AVR
Цитата(aaarrr @ Aug 6 2006, 02:56) *
Что-то меня настораживает. Все же на 0x18 должно быть ldr pc, [pc, #-0xf20], или что-нибудь не столь лаконичное, но аналогичное по смыслу.
А pragma vector = 0x18 - какая-то вредная штуковина, ИМХО.

Не, всё на самом деле нормально, теперь по адресу 0x18 висит инструкция ldr pc, [pc, #+24]
А использование pragma vector = 0x18 прописано в справке на iccarm для обработчиков прерываний.
GetSmart
Я тоже начинал с такого варианта прерываний. Он простой и файл стартап не нужно исправлять. Особенно если в системе только одно прерывание от таймера, то лучше вообще не мудрить.
aaarrr
Ну если так проще, тогда ладно.

P.S. Интересно, кто-нибудь еще использовал в своих проектах RTT?
AVR
Цитата(aaarrr @ Aug 6 2006, 04:05) *
P.S. Интересно, кто-нибудь еще использовал в своих проектах RTT?

У меня ещё вопрос возник: почему atmel называет это риалтайм таймером, если к нему подается только источник SLCK, частота которого только приблизительно равна 32768 Гц. Часы на таком явно не организовать... Есть ли возможность настроить на другой источник тактов?
ЗЫ
Можно ли и как заставить SAM7S пропускать MCK на один из выходов PIO, чтобы, например, тактировать внешнюю периферию такую как CPLD?
ЗЫЗЫ
Посоветуйте, пожалуйста, какую-нибудь микросхему SRAM в DIP корпусе на 64 КБайт.
aaarrr
Цитата(AVR @ Aug 6 2006, 16:20) *
Есть ли возможность настроить на другой источник тактов?

Нет.

Цитата(AVR @ Aug 6 2006, 16:20) *
Можно ли и как заставить SAM7S пропускать MCK на один из выходов PIO, чтобы, например, тактировать внешнюю периферию такую как CPLD?

Можно. Почитайте про Programmable Clock Output в PMC.
AVR
Что нужно сделать, чтобы срабатывали несколько разных перерываний? Ведь тогда получается разные обработчики должны начинаться на 0x18, а одновременно это невозможно... Для чего тогда нужен AIC, если он сам автоматом не загружает в PC адрес нужно обработчика... blink.gif
Сергей Борщ
Цитата(AVR @ Aug 8 2006, 14:57) *
Что нужно сделать, чтобы срабатывали несколько разных перерываний? Ведь тогда получается разные обработчики должны начинаться на 0x18, а одновременно это невозможно... Для чего тогда нужен AIC, если он сам автоматом не загружает в PC адрес нужно обработчика... blink.gif

Код
__arm __irq void IRQ_Handler(void) {
     void (*AT91C_AIC_IVR)();
     AT91C_BASE_AIC->AT91C_AIC_EOICR = 0;
}

что-то вроде этого. Или же по адресу 0x18 в асмовом файле разместить
Код
        LDR        PC, AT91C_AIC_IVR
и каждый обработчик оформлять как __arm __irq не забывая в конце каждого обработчика вставлять AT91C_BASE_AIC->AT91C_AIC_EOICR = 0;
AVR
Сергей Борщ, спасибо a14.gif
Timofey
Прошу прощения, что поднимаю старую тему и за очередной глупый для Вашего внимания вопрос, но ... объясните мне пожалуйста, в чем причина?
Использую таймер и он в обработчике виснет:


void channal (void)
{
for (int chan=0;chan<9;chan++){
while (!((AT91C_BASE_SPI->SPI_SR) & AT91C_SPI_TXEMPTY));
AT91F_SPI_CfgPCS(AT91C_BASE_SPI,0);
AT91F_SPI_PutChar (AT91C_BASE_SPI, SPI_SEND[chan],0 );
while (!((AT91C_BASE_SPI->SPI_SR) & AT91C_SPI_TXEMPTY));
AT91F_SPI_CfgPCS(AT91C_BASE_SPI,0);
AT91F_SPI_PutChar (AT91C_BASE_SPI, SPI_SEND[chan],0 );
while (!((AT91C_BASE_SPI->SPI_SR) & AT91C_SPI_TXEMPTY));
AT91F_SPI_CfgPCS(AT91C_BASE_SPI,0);
AT91F_SPI_PutChar (AT91C_BASE_SPI, SPI_SEND[chan],0 );
while (!((AT91C_BASE_SPI->SPI_SR) & AT91C_SPI_TXEMPTY));
tin=AT91F_SPI_GetChar(AT91C_BASE_SPI);
DATA[shet_i][chan]=tin & 0x0FFE;


switch (BUFF_STATUS[5]){
case 0x01:
DATA[shet_i][chan]=filt_niz_chas(DATA[shet_i][chan]);
break;

case 0x10:
DATA[shet_i][chan]=filt_vis_chas(DATA[shet_i][chan]);
break;

case 0x11:
DATA[shet_i][chan]=filt_niz_chas(DATA[shet_i][chan]);
DATA[shet_i][chan]=filt_vis_chas(DATA[shet_i][chan]);
break;
}

if (DATA[shet_i][chan]>max_data[chan]) max_data[chan]=DATA[shet_i][chan]; //находим максимум

BUFF_STATUS[(chan+7)*2+1]=max_data[chan];
BUFF_STATUS[(chan+7)*2]=max_data[chan] >> 8;
}



}


void Periodic_Interval_Timer_handler (void)
{
unsigned int status;

status = AT91C_BASE_PITC->PITC_PIVR;
status =status;

AT91F_PIO_ClearOutput(AT91C_BASE_PIOA, LED1);
spiflag=1;
channal();
AT91C_BASE_AIC->AIC_EOICR=0x00;
AT91F_PIO_SetOutput(AT91C_BASE_PIOA, LED1);
}


Инициализация таймера:
AT91F_PMC_EnablePeriphClock ( AT91C_BASE_PMC, 1 << AT91C_ID_PIOA ) ;
AT91F_AIC_ConfigureIt ( AT91C_BASE_AIC,
AT91C_ID_SYS,
RTTC_INTERRUPT_LEVEL,
AT91C_AIC_SRCTYPE_EXT_LOW_LEVEL,
Periodic_Interval_Timer_handler);
AT91C_BASE_PITC->PITC_PIMR = AT91C_PITC_PITEN | AT91C_PITC_PITIEN | PIV_2_MS;
AT91F_AIC_EnableIt (AT91C_BASE_AIC, AT91C_ID_SYS);



PIV_2_MS=467 //по моим подсчетам должно быть в районе 156 мксек, верно?


Вобщем при запуске программы лампочка загорается и почти мгновенно тухнет. Еле заметишь, вобщем такое ощущение что заходит один раз в прерывание и там остается, выполнив все. Частота SPI 15 МГц. По приблизительным подсчетам вся программа должна успевать выполнятся до следующего прерывания. Или я ошибаюсь? И вобще нужны ли ожидания перед отправкой 16-ти бит в SPI? Может эти вайлы вобще нафиг выкинуть? На shet_i не обращайте внимания, он обрабатывается в другой части программы, до которой не доходит.
Если закоментировать строку channal() то все работает .... то есть лампочка тускло так горит ....
Ставил __irq компилятор выдает ошибку: Error[Pe167]: argument of type "void (__arm __irq __atpcs *)(void)" is incompatible with parameter of type "void (*)()"
Прошу сильно не ругаться, и смеятся не до колик, собственно я еще полный ламер, а даташит читать - с английским не важнец .... Кстати, может кто нить подскажет где можно в Екатеринбурге купить книжку по SAM7 на РУССКОМ? Или может через инет заказать ....
AVR
Цитата(Timofey @ Aug 16 2006, 09:33) *
Если закоментировать строку channal() то все работает .... то есть лампочка тускло так горит ....
Ставил __irq компилятор выдает ошибку: Error[Pe167]: argument of type "void (__arm __irq __atpcs *)(void)" is incompatible with parameter of type "void (*)()"

Я, конечно, и сам ламер, но всё же есть некоторые догадки...
По всей видимости, функция "channal" выполняется слишком долго (вообще помещать такие страшные функции в обработчики это не очень хорошо smile.gif ), попробуйте вынести её в основной цикл программы, а при срабатывании прерывания по таймеру просто инкрементируйте некую переменную, которая сообщит программе в основном цикле о том, что нужно вызвать channal (и при этом декрементируйте эту переменную). Если эта переменная будет больше единицы, значит channal выполняется дольше чем нужно.
ЗЫ
Попробуйте добавить такой код. Саму же функцию обработчика определенного прерывания нужно оформить как обычную функцию без __irq
Код
#pragma vector = 0x18
__irq __arm void IRQ()
{
    void (*IRQ_Handler)() = (void(*)())AT91C_BASE_AIC->AIC_IVR;
    IRQ_Handler();
    AT91C_BASE_AIC->AIC_EOICR = 0;
}
Timofey
Цитата(AVR @ Aug 17 2006, 02:14) *
По всей видимости, функция "channal" выполняется слишком долго (вообще помещать такие страшные функции в обработчики это не очень хорошо smile.gif ), попробуйте вынести её в основной цикл программы, а при срабатывании прерывания по таймеру просто инкрементируйте некую переменную, которая сообщит программе в основном цикле о том, что нужно вызвать channal (и при этом декрементируйте эту переменную).

За код спасибо. На счет того что в прерывании лучше вобще ничего делать, я знаю, но дело в том что больше никак. Мне нужно все это делать именно в прерывании ... В этом то и фишка ...
SpiritDance
Исходные данные

Инициализация
Код
void init_interrupt_PIT(t_uint32 Interval, void InterruptHandler(void))
{
    volatile t_uint32 temp;

//    if (InterruptHandler != NULL)
//    {
        AT91F_AIC_ConfigureIt(AT91C_BASE_AIC, AT91C_ID_SYS,
                              PIT_PRIORITY, AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE,
                              InterruptHandler);
//    }
//    else
//    {
//        AT91F_AIC_ConfigureIt(AT91C_BASE_AIC, AT91C_ID_SYS,
//                              PIT_PRIORITY, AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE,
//                              (void(*)(void))ih_PIT);
//    }
    temp = AT91C_BASE_PITC->PITC_PIVR;
    AT91C_BASE_PITC->PITC_PIMR = temp;

    AT91C_BASE_PITC->PITC_PIMR = (Interval & AT91C_PITC_PIV)
                               |
                               AT91C_PITC_PITEN
                               |
                               AT91C_PITC_PITIEN;
}

Вызов
Код
    init_interrupt_PIT(0x000000FF, (void(*)(void))ih_fromPIT);

Обработчик
Код
void ih_fromPIT(void) __irq
{
    if (AT91C_BASE_PITC->PITC_PISR & AT91C_PITC_PITS )
    {
        g_systemSignals.displayStart = 1;        
    }    
    /* îáðàáîò÷èê çàâåðøåí */
    AT91C_BASE_AIC->AIC_EOICR = 0;
}

Других обработчиков от системного контроллера нет.

Вопрос. Почему обработчик ни разу не вызывается? Что я не понимаю?
SpiritDance
Кто-нибудь может скинуть рабочий код для PIT?
Странно но заработало вот так (я там кстати включить прерывание забыл blush.gif )
Код
void init_interrupt_PIT(t_uint32 Interval, void InterruptHandler(void))
{
    if (InterruptHandler != NULL)
    {
        AT91F_AIC_ConfigureIt(AT91C_BASE_AIC, AT91C_ID_SYS,
                              PIT_PRIORITY, AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE,
                              InterruptHandler);
    }
    else
    {
        AT91F_AIC_ConfigureIt(AT91C_BASE_AIC, AT91C_ID_SYS,
                              PIT_PRIORITY, AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE,
                              (void(*)(void))ih_PIT);
    }
    AT91F_AIC_EnableIt(AT91C_BASE_AIC, AT91C_ID_SYS);

    AT91C_BASE_PITC->PITC_PIMR = (((__int64)(MCK / 16) * Interval / 1000000) & AT91C_PITC_PIV)
                               |
                               AT91C_PITC_PITEN
                               |
                               AT91C_PITC_PITIEN;
}

void ih_fromPIT(void) __irq
{
    volatile t_uint32 temp = 0;
    if (AT91C_BASE_PITC->PITC_PISR & AT91C_PITC_PITS )
    {
        g_systemSignals.displayStart = 1;
        temp = AT91C_BASE_PITC->PITC_PIVR;
    }    
    /* îáðàáîò÷èê çàâåðøåí */
    AT91C_BASE_AIC->AIC_EOICR = temp;
}

При этом если не читать PIVR флаг прерывания не снимается.
Отсюда вопрос каким образом от данного таймера получить интервал прерываний больший 20-разрядной части и зачем вообще нужен PICNT?
vet
Цитата(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;
}
Сергей Борщ
Цитата(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Гц.
SpiritDance
Цитата
1) Уменьшить MCLK
2) Организовать в прерывании этого таймера хоть 128-битный программный счетчик.

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

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

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

Что касается документации то да, признаю, я часто бываю невнимателен.
Сергей Борщ
Цитата(SpiritDance @ Sep 12 2006, 14:57) *
Я вобщем не спрашивал как организовать счетчик. Просто я так понял что больший интервал аппаратных прерываний чем записывается в PIVR получить нельзя.
Да, нельзя. Тогда я не понял вопроса. А какой таймер позволяет делать больший чем разрядность таймера?

Цитата
Не понял. При чем здесь счетчик переполнений? Он же сбрасывается при считывании PIVR?
Извиняюсь, я тоже бываю невнимателен. Почему-то показалось, что вопрос был про PIT вообще. Видимо чтобы узнать сколько прерываний было потеряно если это прерывание было запрещено надолго и потом программно вызвать обработчик нужное количество раз:
Код
    volatile dword Tmp = AT91C_BASE_PITC->PITC_PIVR >> 20;
    while(Tmp--) {
        SystemTimer_ISR();
    }
SpiritDance
Цитата(Сергей Борщ @ Sep 12 2006, 17:04) *
Да, нельзя. Тогда я не понял вопроса. А какой таймер позволяет делать больший чем разрядность таймера?

Ну вообще-то полная разрядность таймера PIT 20 + 12 smile.gif Хотя если подумать для чего сделан данный таймер то вобщем достаточно и 20 разрядов. Жаль только частота фиксированная.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.