реклама на сайте
подробности

 
 
3 страниц V  < 1 2 3  
Reply to this topicStart new topic
> AT90USB1287 не отрабатывает внешние прерывания, В чем дело?
alux
сообщение Sep 5 2008, 09:12
Сообщение #31


Знающий
****

Группа: Свой
Сообщений: 589
Регистрация: 24-04-05
Пользователь №: 4 447



Цитата(ReAl @ Sep 5 2008, 10:33) *
не рекомендую разрешать прерывания до запуска OS::Run() - потребности в этом нет, а что-то левое может и вылезти.
Этот вопрос я уже поднимал
ранее:

Потребность иногда есть, например, когда необходимо проинициализировать АЦП, а SPI настроен по прерыванию:
Код
.........................
__enable_interrupt();    // set the Global Interrupt Enable Bit
  ad7799_Init();
  
  TCCR0B = 0x03;          // Start System Timer f_clk/64
  TIMSK0 |= (1<<TOIE0);   // Разрешить прерывания Timer0 по переполнению (OVF)
                          // Период переполнения Timer0 при f_clk=7.3728 Mhz 2.222 ms
  OS::Run();              //                            при f_clk=20 Mhz 0.8192 ms
}

Получается сразу после ad7799_Init(); до запуска ОС нужно сделать __disable_interrupt(); ?

Почему из POWER_DOWN не вызывается обработчик внешнего прерывания INT6 , настроенный по низкому уровню?
Вызов ISR контролирую по изменению вывода BEEP:
Код
#pragma vector=INT6_vect
OS_INTERRUPT void INT6_ISR()
{
  OS::TISRW_SS ISRW;

  DISABLE_INT6;            // Prevent further external interrupts

  Int6.SignalISR();  
PORTC |= (1<<BEEP);
}
Go to the top of the page
 
+Quote Post
alux
сообщение Sep 6 2008, 08:33
Сообщение #32


Знающий
****

Группа: Свой
Сообщений: 589
Регистрация: 24-04-05
Пользователь №: 4 447



Второй раз наступаю на одни и те же грабли:
Код
void TLCD::OnOff(bool On)
{
  if(On)
  {;}
  else
  {
    TCritSect cs;       <<<<<<<<<<<!!!!!!!!!!!!!!!!!!!!!!!!
    ks0108ClearScreen();            // display clear
.............................................................................
    PORTD |= (1<<SHDN);     // Отключить аналоговую периферию
    SELECT_POWERDOWN;
    __sleep();
    
    SELECT_IDLE;
    PORTD &= ~(1<<SHDN);    // Включить аналоговую периферию
    powerdown.Signal();     // Сигнал для инициализации меню после выхода из Power_Down
  }
}

Когда входим в Power Down, прерывания запрещены (TCritSect cs;). Поэтому не вызывается обработчик прерывания.
Прошу прощения, за свою невнимательность. И код в предыдущем посте я привел без этого момента smile.gif
Go to the top of the page
 
+Quote Post
ReAl
сообщение Sep 6 2008, 12:53
Сообщение #33


Нечётный пользователь.
******

Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417



Цитата(alux @ Sep 5 2008, 12:12) *
Потребность иногда есть, например, когда необходимо проинициализировать АЦП, а SPI настроен по прерыванию:
Код
.........................
__enable_interrupt();
  ad7799_Init();
  
  TCCR0B = 0x03;    
  TIMSK0 |= (1<<TOIE0);
  OS::Run();
}

А почему бы не сделать это в начале функции процесса, которого этот АЦП интересует?
Код
template<> OS_PROCESS void TProc1::Exec()
{
    ad7799_Init();
    for(;;) {
        // ну а тут как обычно
    }
}



Цитата(alux @ Sep 5 2008, 12:12) *
Получается сразу после ad7799_Init(); до запуска ОС нужно сделать __disable_interrupt(); ?
Уже не нужно. Т.е. количественно ситуацию это изменит, качественно - нет.
Смотрим.
Пусть между разрешением прерываний и началом нормальной работы ОС возникает какое-то "осевое" прерывание, то же клавиатурное INT6 (маловероятно? ну тогда пусть от UART, в который кто-то ломится).
В начале обработчика стоит OS::TISRW_SS ISRW;, смотрим код конструктора
Код
    class TISRW_SS
    {
    public:
        INLINE  TISRW_SS()  { ISR_Enter(); }
        INLINE  ~TISRW_SS() { ISR_Exit();  }

    private:
        //-----------------------------------------------------
        INLINE void ISR_Enter() // volatile
        {
            if(Kernel.ISR_NestCount++ == 0)
            {
                 SavedSP.DataSP   = GetDataSP();
                 SavedSP.ReturnSP = GetReturnSP();
                 SetISRStackPointers();                     // <---- ОЙ !!!
            }
        }
        . . .
    };

// А вот и ОЙ !!!
INLINE inline void SetISRStackPointers()
{
    ABS_WORD(28) = reinterpret_cast<word>(__segment_end("CSTACK"));
    SP = reinterpret_cast<word>(__segment_end("RSTACK")) - 1;
}
Итого обработчик прерывания переключил стек на осноной стек программы (он всё равно не используется при нормальном выполнении программы с scmRTOS. И имеет возможность затереть, например, находящийся там адрес возврата из того же любимого ad7799_Init();.
Конечно, может повезти. И обработчик прерывания не затрёт основной стек.
Но заглянем в другие порты - во многих (AVR/GCC, MSP430/*, ARM7) функция ISR_Enter() сделана одинаково и вот так:
Код
        INLINE void ISR_Enter()
        {
            if(Kernel.ISR_NestCount++ == 0)
            {
                Kernel.ProcessTable[Kernel.CurProcPriority]->StackPointer = GetStackPointer();
                SetISRStackPointer();
            }
        }
В данном случае вместо записанного конструктором процесса адреса "сэмулированного" тем же конструктором начального стекового кадра процесса будет записан адрес где-то в серёдке основного стека и OS::Run() для OS_Start() даст этот адрес.


--------------------
Ну, я пошёл… Если что – звоните…
Go to the top of the page
 
+Quote Post

3 страниц V  < 1 2 3
Reply to this topicStart new topic
2 чел. читают эту тему (гостей: 2, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 20th July 2025 - 07:34
Рейтинг@Mail.ru


Страница сгенерированна за 0.01404 секунд с 7
ELECTRONIX ©2004-2016