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

Здравствуйте!

 

Пишу под AT91sam7s64.

 

Столкнулся с такой проблемой:

Я пользуюсь 2 таймерами TC1 и TC2 в режиме захвата.

Таймера настроены на захват регистра А и рестарт по сравнению с регистром С .

Таймера запущены синхронно и значения регистра С одинаковы.

 

На таймера есть прерывания по захвату А и сравнению С, по сравнению прерывания возникают одновримено.

 

Все вроде работает неоприледен время, а потом тупо перестает заходить в обработчик прерываний одного из таймеров (рас 1 рас 2 ..) .

 

Не заходит, пока не поставлю в дебаге точку останова, непосредственно в том обработчике.

После чего все начинает снова работать не оприделеное время и так по колу.

 

static void ISR_TC1(void)
{
   unsigned int uiSR = AT91C_BASE_TC1->TC_SR;
    if( (uiSR & AT91C_TC_CPCS) )
   {
       uiOverTC1++;
   }
   if( uiSR & AT91C_TC_LDRAS )
   {
       unsigned int uiRA = AT91C_BASE_TC1->TC_RA;  
       if (uiStartT1 <3 )
         {
             Timer1[uiStartT1].uiRA = uiRA;
             Timer1[uiStartT1].uiOver = uiOverTC1; 
             Timer1[uiStartT1].bZap = true;
             uiStartT1++;
         }
   }
   
}
void InitTC1ForFreq()
{
   
    //AIC configure.
    AT91C_BASE_AIC->AIC_IDCR = 1 << AT91C_ID_TC1;     // Disable the interrupt first
    AT91C_BASE_AIC->AIC_SMR[AT91C_ID_TC1] = AT91C_AIC_SRCTYPE_POSITIVE_EDGE | AT91C_AIC_PRIOR_HIGHEST;
    AT91C_BASE_AIC->AIC_SVR[AT91C_ID_TC1] = (unsigned int) ISR_TC1;
    AT91C_BASE_AIC->AIC_ICCR = 1 << AT91C_ID_TC1;     // Clear interrupt
    AT91C_BASE_AIC->AIC_IECR = 1 << AT91C_ID_TC1;     // Enables interrupts
    
   
    
    // Enable PWMC peripheral clock
    AT91C_BASE_PMC->PMC_PCER = 1 << AT91C_ID_TC1;
    
    // Disable TC clock
    AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS;

    // Disable interrupts
    AT91C_BASE_TC1->TC_IDR = 0xFFFFFFFF;

    // Clear status register
    AT91C_BASE_TC1->TC_SR;

    // Set mode
    AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK | // MCK/2
                             AT91C_TC_BURST_NONE |
                             AT91C_TC_EEVTEDG_NONE |
                             AT91C_TC_CPCTRG |
                             AT91C_TC_ABETRG |    
                             AT91C_TC_LDRA_RISING; // each edge of TIOA 
                        
    AT91C_BASE_TC1->TC_RC = 0xffff;
    
    // Enable interrpt
    AT91C_BASE_TC1->TC_IER = AT91C_TC_CPCS | // Counter compare CR
                             AT91C_TC_LDRAS;  // RA Loading
    
    // Start TC1  
    AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
    
    // Atach to PIO for TIOA1
    AT91C_BASE_PIOA->PIO_BSR = AT91C_PA15_TIOA1;
    AT91C_BASE_PIOA->PIO_PER = AT91C_PA15_TIOA1;
}
////////////////////////////////////////////////////////////////////////////////
// Timer 2  IntL
////////////////////////////////////////////////////////////////////////////////

unsigned int uiOverTC2 = 0;       //  ïåðåïîâíåííÿ òàéìåðà
unsigned int uiTC2LastRA = 0;
static void ISR_TC2(void)
{
   unsigned int uiSR = AT91C_BASE_TC2->TC_SR;
    if( (uiSR & AT91C_TC_CPCS) )
   {
       uiOverTC2++;
   }
   if( (uiSR & AT91C_TC_LDRAS) )
   {
       unsigned int uiRA = AT91C_BASE_TC2->TC_RA;  
       if (uiStartT2 <3 )
       {
           Timer2[uiStartT2].uiRA = uiRA;
           Timer2[uiStartT2].uiOver = uiOverTC2; 
           Timer2[uiStartT2].bZap = true;
           uiStartT2++;
       }
   }
   
}
void InitTC2ForFreq()
{
   

    //AIC configure.
    AT91C_BASE_AIC->AIC_IDCR = 1 << AT91C_ID_TC2;     // Disable the interrupt first
    AT91C_BASE_AIC->AIC_SMR[AT91C_ID_TC2] = AT91C_AIC_SRCTYPE_POSITIVE_EDGE | AT91C_AIC_PRIOR_HIGHEST;
    AT91C_BASE_AIC->AIC_SVR[AT91C_ID_TC2] = (unsigned int) ISR_TC2;
    AT91C_BASE_AIC->AIC_ICCR = 1 << AT91C_ID_TC2;     // Clear interrupt
    AT91C_BASE_AIC->AIC_IECR = 1 << AT91C_ID_TC2;     // Enables interrupts
    
   
    
    // Enable PWMC peripheral clock
    AT91C_BASE_PMC->PMC_PCER = 1 << AT91C_ID_TC2;
    
    // Disable TC clock
    AT91C_BASE_TC2->TC_CCR = AT91C_TC_CLKDIS;

    // Disable interrupts
    AT91C_BASE_TC2->TC_IDR = 0xFFFFFFFF;

    // Clear status register
    AT91C_BASE_TC2->TC_SR;

    // Set mode
    AT91C_BASE_TC2->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK | // MCK/2
                             AT91C_TC_BURST_NONE |
                             AT91C_TC_EEVTEDG_NONE |
                             AT91C_TC_CPCTRG |
                             AT91C_TC_ABETRG |    
                             AT91C_TC_LDRA_RISING; // each edge of TIOA 
                        
    AT91C_BASE_TC2->TC_RC = 0xffff;
                        
    // Enable interrpt
    AT91C_BASE_TC2->TC_IER = AT91C_TC_CPCS | // Counter 
                            AT91C_TC_LDRAS;  // RA Loading
    
    // Start TC1  
    AT91C_BASE_TC2->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
    
    //synhron timers
    AT91C_BASE_TCB->TCB_BCR = AT91C_TCB_SYNC;
    
    // Atach to PIO for TIOA2
    AT91C_BASE_PIOA->PIO_BSR = AT91C_PA26_TIOA2;
    AT91C_BASE_PIOA->PIO_PER = AT91C_PA26_TIOA2;
}

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


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

Заметил что когда перестает заходить в прерывание ТС1 то сбрасывается флаг AIC_IPR но AIC_IMR остается установленным соответствующего таймера. Почему не знаю.

 

Да и не всегда точка останова спасает.

 

 

Почему прерывание T1 перестает обрабатываться и почему? :help:

 

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


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

Почему прерывание T1 перестает обрабатываться и почему? :help:

JTAG отключить не пробовали? Ну и до кучи поставьте AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL вместо AT91C_AIC_SRCTYPE_POSITIVE_EDGE.

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


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

Ну и до кучи поставьте AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL вместо AT91C_AIC_SRCTYPE_POSITIVE_EDGE.

 

Вроде помогло.

Но обясните почему не работало с AT91C_AIC_SRCTYPE_POSITIVE_EDGE ?

 

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


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

Но обясните почему не работало с AT91C_AIC_SRCTYPE_POSITIVE_EDGE ?

Чисто теоретически это возможно, если при обработке прерывания от TC по какой-либо причине не считывается TC_SR - линия прерывания останется в активном состоянии, логика AIC будет сброшена, прерывания работать перестанут. К такому же эффекту может привести и запись ICCR.

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


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

Вроде помогло.

Но обясните почему не работало с AT91C_AIC_SRCTYPE_POSITIVE_EDGE ?

А у меня была обратная проблема с USART - возникало Spurious Interrupt из-за AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE пришлось сменить на AT91C_AIC_SRCTYPE_POSITIVE_EDGE.

Но в таймерах я всегда AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE использовал изначально и проблем не было таких.

 

А вообще SAM7S довольно глючный контроллер... errata "радует", хотя по TC там нет ничего.

 

Да... и, если в IAR пишется, то почему бы не пользоваться стандарными библиотечными функциями :rolleyes: :

AT91F_PMC_EnablePeriphClock ( AT91C_BASE_PMC, 1<< AT91C_ID_TC1 );

AT91F_AIC_ConfigureIt ( AT91C_BASE_AIC, AT91C_ID_TC1, TIMER1_INTERRUPT_LEVEL,AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE, TimerIRQHandler1 );

 

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


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

А у меня была обратная проблема с USART - возникало Spurious Interrupt из-за AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE пришлось сменить на AT91C_AIC_SRCTYPE_POSITIVE_EDGE.

Spurious Interrupt возникает по вполне определенным причинам и не является проблемой, если, конечно, не снабжено зависающей заглушкой (в атмеловских примерах встречался такой маразм).

 

Да... и, если в IAR пишется, то почему бы не пользоваться стандарными библиотечными функциями :rolleyes: :

К IAR'у, слава богу, данные функции никакого отношения не имеют. Для записи значения в регистр можно обойтись и без "библиотек".

А если нужно что-то сложнее, то надежнее использовать собственную голову, дабы не украшать программу подобными чудесами программистской мысли:

//*----------------------------------------------------------------------------
//* \fn    AT91F_SSC_SetBaudrate
//* \brief Set the baudrate according to the CPU clock
//*----------------------------------------------------------------------------
__inline void AT91F_SSC_SetBaudrate (
        AT91PS_SSC pSSC,        // \arg pointer to a SSC controller
        unsigned int mainClock, // \arg peripheral clock
        unsigned int speed)     // \arg SSC baudrate
{
        unsigned int baud_value;
        //* Define the baud rate divisor register
        if (speed == 0)
           baud_value = 0;
        else
        {
           baud_value = (unsigned int) (mainClock * 10)/(2*speed);
           if ((baud_value % 10) >= 5)
                  baud_value = (baud_value / 10) + 1;
           else
                  baud_value /= 10;
        }

        pSSC->SSC_CMR = baud_value;
}

 

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


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

Spurious Interrupt возникает по вполне определенным причинам и не является проблемой, если, конечно, не снабжено зависающей заглушкой (в атмеловских примерах встречался такой маразм).

 

 

К IAR'у, слава богу, данные функции никакого отношения не имеют. Для записи значения в регистр можно обойтись и без "библиотек".

А если нужно что-то сложнее, то надежнее использовать собственную голову, дабы не украшать программу подобными чудесами программистской мысли:

//*----------------------------------------------------------------------------
//* \fn    AT91F_SSC_SetBaudrate
//* \brief Set the baudrate according to the CPU clock
//*----------------------------------------------------------------------------
__inline void AT91F_SSC_SetBaudrate (
        AT91PS_SSC pSSC,        // \arg pointer to a SSC controller
        unsigned int mainClock, // \arg peripheral clock
        unsigned int speed)     // \arg SSC baudrate
{
...
}

 

Проблему с Spurious Interrupt я и решил убиранием заглушки плюс AT91C_AIC_SRCTYPE_POSITIVE_EDGE.

 

Согласен, что не все функции библиотечные хороши, что там может быть заложена "бомба" ))), но куда нагляднее и красив код:

 

AT91F_AIC_Configure(AT91C_BASE_AIC, irq_id, DEBUG_INTERRUPT_LEVEL,DEBUG_INTERRUPT_LEVEL, AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE, newHandler );

AT91F_AIC_EnableIt (AT91C_BASE_AIC, irq_id);

 

ЧЕМ вот это нагромождение:

/////////// AIC

 

unsigned int mask ;

 

mask = 0x1 << irq_id ;

//* Disable the interrupt on the interrupt controller

pAic->AIC_IDCR = mask ;

//* Save the interrupt handler routine pointer and the interrupt priority

pAic->AIC_SVR[irq_id] = (unsigned int) newHandler ;

//* Store the Source Mode Register

pAic->AIC_SMR[irq_id] = src_type | priority ;

//* Clear the interrupt on the interrupt controller

pAic->AIC_ICCR = mask ;

 

// AT91F_AIC_EnableIt

//* Enable the interrupt on the interrupt controller

pAic->AIC_IECR = 0x1 << irq_id ;

 

Тем более, к примеру, короткие функции все inline и очень наглядны для работы, чем вписывать регистры:

 

//*----------------------------------------------------------------------------

//* \fn AT91F_UDP_EpSet

//* \brief Set flag in the endpoint CSR register

//*----------------------------------------------------------------------------

__inline void AT91F_UDP_EpSet(

AT91PS_UDP pUDP, // \arg pointer to a UDP controller

unsigned char endpoint, // \arg endpoint number

unsigned int flag) // \arg flag to be cleared

{

pUDP->UDP_CSR[endpoint] |= flag;

}

 

//*----------------------------------------------------------------------------

//* \fn AT91F_UDP_EpStatus

//* \brief Return the endpoint CSR register

//*----------------------------------------------------------------------------

__inline unsigned int AT91F_UDP_EpStatus(

AT91PS_UDP pUDP, // \arg pointer to a UDP controller

unsigned char endpoint) // \arg endpoint number

{

return pUDP->UDP_CSR[endpoint];

}

 

//*----------------------------------------------------------------------------

//* \fn AT91F_UDP_GetInterruptMaskStatus

//* \brief Return UDP Interrupt Mask Status

//*----------------------------------------------------------------------------

__inline unsigned int AT91F_UDP_GetInterruptMaskStatus( // \return UDP Interrupt Mask Status

AT91PS_UDP pUdp) // \arg pointer to a UDP controller

{

return pUdp->UDP_IMR;

}

 

А если в 10 местах использовать инит AIC, то совсем некрасиво.

 

Когда вы пользуетесь вызовами функций драйверов сети, i2c например, вы же не обращаетесь в регистры каждый раз напрямую игнорируя библиотечные вызовы. Есть библиотека(не важно эта или другая) и если что-то исправить надо в вызываемых функциях, то можно подправить исходник.

Чем сложнее процессор или контроллер, тем больше кода инита периферии и т.д., если сравнить с AVR, где раз два и сделал все что надо ).

 

Если данные библиотека не так удачна, то можно свою написать с основными для себя функциями и потом их везде использовать.

 

PS: Впрочем, я уж очень сгустил краски в ответе. Но я при написании стараюсь сразу убрать все прямые обращения к регистрам в свои библиотеки ))).

Если места не хватает, то да... приходиться потрошить все и убирать лишние библиотечные вызовы, но с такими объемами FLASH на ARM такие проблемы только на AVR мелких решать приходится ))).

 

Так что никак не могу сказать, что вы правы на все 100.

Изменено пользователем EugenB2

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


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

ЧЕМ вот это нагромождение:

Зато в этом нагромождении видно что и как делается.

 

Тем более, к примеру, короткие функции все inline и очень наглядны для работы, чем вписывать регистры:

 

//*----------------------------------------------------------------------------

//* \fn AT91F_UDP_EpSet

//* \brief Set flag in the endpoint CSR register

//*----------------------------------------------------------------------------

__inline void AT91F_UDP_EpSet(

AT91PS_UDP pUDP, // \arg pointer to a UDP controller

unsigned char endpoint, // \arg endpoint number

unsigned int flag) // \arg flag to be cleared

{

pUDP->UDP_CSR[endpoint] |= flag;

}

Хороший пример "бомбы". Так работать с CSR можно далеко не всегда. А по названию функции нельзя догадаться об особенностях ее работы.

 

Когда вы пользуетесь вызовами функций драйверов сети, i2c например, вы же не обращаетесь в регистры каждый раз напрямую игнорируя библиотечные вызовы. Есть библиотека(не важно эта или другая) и если что-то исправить надо в вызываемых функциях, то можно подправить исходник.

Чем сложнее процессор или контроллер, тем больше кода инита периферии и т.д., если сравнить с AVR, где раз два и сделал все что надо ).

Если вы заметили, в этой "библиотеке" совершенно проигнорирована хоть сколько-нибудь сложная периферия (EMAC, UDP, CAN). А использовать библиотечные функции для установки бита в регистре - это, по-моему, совершенный маразм, только усложняющий чтение программы.

 

P.S. Я совсем не против написания библиотек для периферии, просто at91lib - это отличный пример того, как этого делать не надо.

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


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

JTAG отключить не пробовали?

Здравствуйте! Какраз столкнулся с такой проблемой - когда прошиваю программу через J-Link, и запускаю в С-SPY, то почему-то отказываются работать прерывания. Зато если тут-же нажать Reset на плате - все начинает работать как надо. IAR 4.40, отладочная плата AT91SAM7X-ЕК. С чем это может быть связано? Программу гружу во флеш. В mac файле никакой работы с прерываниями не обнаружил...

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


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

Сброс логики AIC'а (8 последовательных чтений AIC_IVR, если не в protect mode записей EOICR) при инициализации делаете?

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


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

Нет. Не делаю. Первый раз такой способ вижу. Но мне идея понравилась. Написал такое:

   for(char i=8; i--;  )
   {
     tim = AT91C_BASE_AIC->AIC_IVR;
     AT91C_BASE_AIC->AIC_EOICR = tim;
   }
  tim = AT91C_BASE_AIC->AIC_FVR;
  AT91C_BASE_AIC->AIC_EOICR = tim;

Заработало. Правда работает и если оставлять лишь последнюю строку. Но к сожалению это все работает в простой тестовой проге, а в нужной мне - грабли остались. Теперь вылетает в dabt или pabt. Буду искать дальше. Спасибо!

=====================================UPDATED================================

В основной проге убрал модификаторы __irq __arm от объявления процедуры прерывания - и заработало!! ))

Что я делаю не так? (с)

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


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

Заработало. Правда работает и если оставлять лишь последнюю строку.

Торопился и наврал в предыдущем посте: конечно, надо писать EOICR. IVR трогать не надо.

 

В основной проге убрал модификаторы __irq __arm от объявления процедуры прерывания - и заработало!! ))

Что я делаю не так? (с)

Со стартапом своим разбирайтесь. Наверняка в нем присутствует обертка для прерываний, поэтому и заработало.

Помимо модификаторов, скорее всего, придется ликвидировать записи EOICR.

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


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

Да. Точно. За основу то взял пример стандартный... Когда не знаешь, да еще и забудешь.. таких делов можно наворотить. =P

И все-таки после брейкпоинта прерывания иногда умирают. Хотя флаги в AIC_IPR и AIC_IMR стоят. CPSR_I=0. Ну ладно, это не критично - отлажусь на осциллографе и консоли.

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


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

И все-таки после брейкпоинта прерывания иногда умирают.

А protect mode используете?

 

Ну ладно, это не критично - отлажусь на осциллографе и консоли.

Это хороший, правильный способ.

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


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

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

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

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

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

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

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

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

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

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