Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Хочется программно инициировать прерывание
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > AVR
Страницы: 1, 2
Дон Амброзио
У меня для "быстрых" потоков, которые должны вызваться не позднее одного тика таймера после возникновения Event-а, требующего их вмешательства, есть регистр , в котором каждый битик является Ready-флагом соответствующего потока. И перед выходом из ISR системного таймера я проверяю не стоит ли Ready-флажок какого-нить потока. Если стоит, то запускаю соответ.поток в порядке приоритета (от 7 к 0 )
Dog Pawlowa
Цитата(defunct @ May 21 2008, 02:30) *
Ну так ведь ничто не мешает этот автомат сделать в основном цикле. Ввести там сколько надо приоритетов 10-100-1000 (на скоко памяти хватит) и следовать им.

Автоматами только в основном цикле, как правило, не обойтись. У меня обычно автоматы и на процессах в прерываниях.

Признаюсь, что тоже отношусь к темным, которые не понимают, зачем это все нужно. Приоритеты двух прерываний реализуются (извращенно smile.gif )несимметричностью разрешения прерывания (в одном ISR разрешаем, в другом нет), защита от переполнения стека в случае длинного и/или чрезмерно частого более приоритетного прерывания реализуется счетчиком низкоприоритетного прерывания.

__interrupt void low_priority_interrupt()
{ interrupt_no++;
if (interrupt_no>1) DISABLE_HIGH_PRIORITY_INTERRUPT();
__enable_interrupt();
...
}
Ну и попытка все устройства сделать на AVR , выжимая все соки? Даже в 8080 была система приоритетных прерываний, что других контроллеров не существует?
Rst7
Ну вообщем, проверил на железе - не приводит к установке флага прерывания от компаратора дрыг режимом фронт/спад. Плохо, конечно. Пришлось перенести на прерывание от EEPROM и завести флаг запроса. Теперь это выглядит примерно так
Код
#define TASK2_LOCK GPIOR0_Bit0
#define TASK3_LOCK GPIOR0_Bit1
#define TASK2_WAKEUP GPIOR0_Bit2

#define DISABLE_TASK2() {EECR_EERIE=0;}
#define ENABLE_TASK2() {EECR_EERIE=1;}
#define WAKEUP_TASK2() {TASK2_WAKEUP=1;}

#pragma diag_suppress=Ta006
__interrupt void TASK2(void)
{
  __no_operation();
  //....
  //....много всякой долгой каки...
  main(); //Например так
  //....
  __no_operation();
}
#pragma diag_default=Ta006


#pragma vector=EE_RDY_vect
__interrupt __raw void TASK2dispatch(void)
{
  DISABLE_TASK2();
  TASK2_LOCK=1;
  TASK2_WAKEUP=0;
  __enable_interrupt();
  ((void(*)(void))TASK2)();  
  __disable_interrupt();
  TASK2_LOCK=0;
  if (TASK2_WAKEUP) ENABLE_TASK2();
}

#pragma diag_suppress=Ta006
__interrupt void TASK3(void)
{
  __no_operation();
  //....
  //....не очень много всякой долгой каки...
  if (PINB_Bit0) WAKEUP_TASK2(); //К примеру
  //....
  __no_operation();
}
#pragma diag_default=Ta006

#pragma vector=TIMER0_OVF_vect
__interrupt __raw void TASK3dispatch(void)
{
  if (TASK3_LOCK) return;
  TASK3_LOCK=1;
  DISABLE_TASK2();
  __enable_interrupt();
  ((void(*)(void))TASK3)();  
  __disable_interrupt();
  TASK3_LOCK=0;
  if (TASK2_LOCK) return;
  if (TASK2_WAKEUP) ENABLE_TASK2();
}

#pragma vector=INT0_vect
__interrupt void TASK4(void)
{
  //Тут тоже колдовство, запрещаем все прерывания, например
  TIMSK0=0;
  //Запрещаем и TASK2
  DISABLE_TASK2();
  __enable_interrupt();
  //Чего-то делаем, тут еще бывает INT1, но это уже не суть
  __disable_interrupt();
  if (PINB_Bit1) WAKEUP_TASK2(); //К примеру
  TIMSK0=1<<TOV0;
  if (TASK3_LOCK) return;
  if (TASK2_LOCK) return;
  if (TASK2_WAKEUP) ENABLE_TASK2();
}


И код
Код
        RSEG CODE:CODE:NOROOT(1)
//   48 __interrupt void TASK2(void)
TASK2:
//   49 {
        ST      -Y, R24
        ST      -Y, R31
        ST      -Y, R30
        ST      -Y, R3
        ST      -Y, R2
        ST      -Y, R1
        ST      -Y, R0
        ST      -Y, R23
        ST      -Y, R22
        ST      -Y, R21
        ST      -Y, R20
        ST      -Y, R19
        ST      -Y, R18
        ST      -Y, R17
        ST      -Y, R16
        IN      R24, 0x3F
//   50   __no_operation();
        NOP
//   51   //....
//   52   //....много всякой долгой каки...
//   53   main(); //Например так
        RCALL   main
//   54   //....
//   55   __no_operation();
        NOP
//   56 }
        OUT     0x3F, R24
        LD      R16, Y+
        LD      R17, Y+
        LD      R18, Y+
        LD      R19, Y+
        LD      R20, Y+
        LD      R21, Y+
        LD      R22, Y+
        LD      R23, Y+
        LD      R0, Y+
        LD      R1, Y+
        LD      R2, Y+
        LD      R3, Y+
        LD      R30, Y+
        LD      R31, Y+
        LD      R24, Y+
        RETI
//   57 #pragma diag_default=Ta006
//   58
//   59
//   60 #pragma vector=EE_RDY_vect

        RSEG CODE:CODE:NOROOT(1)
//   61 __interrupt __raw void TASK2dispatch(void)
TASK2dispatch:
//   62 {
//   63   DISABLE_TASK2();
        CBI     0x1F, 0x03
//   64   TASK2_LOCK=1;
        SBI     0x1E, 0x00
//   65   TASK2_WAKEUP=0;
        CBI     0x1E, 0x02
//   66   __enable_interrupt();
        SEI
//   67   ((void(*)(void))TASK2)();  
        RCALL   TASK2
//   68   __disable_interrupt();
        CLI
//   69   TASK2_LOCK=0;
        CBI     0x1E, 0x00
//   70   if (TASK2_WAKEUP) ENABLE_TASK2();
        SBIC    0x1E, 0x02
        SBI     0x1F, 0x03
//   71 }
??TASK2dispatch_0:
        RETI
        REQUIRE _A_EECR
        REQUIRE _A_GPIOR0
//   72
//   73 #pragma diag_suppress=Ta006

        RSEG CODE:CODE:NOROOT(1)
//   74 __interrupt void TASK3(void)
TASK3:
//   75 {
//   76   __no_operation();
        NOP
//   77   //....
//   78   //....не очень много всякой долгой каки...
//   79   if (PINB_Bit0) WAKEUP_TASK2(); //К примеру
        SBIC    0x03, 0x00
        SBI     0x1E, 0x02
//   80   //....
//   81   __no_operation();
??TASK3_0:
        NOP
//   82 }
        RETI
        REQUIRE _A_GPIOR0
        REQUIRE _A_PINB
//   83 #pragma diag_default=Ta006
//   84
//   85 #pragma vector=TIMER0_OVF_vect

        RSEG CODE:CODE:NOROOT(1)
//   86 __interrupt __raw void TASK3dispatch(void)
TASK3dispatch:
//   87 {
//   88   if (TASK3_LOCK) return;
        SBIC    0x1E, 0x01
        RJMP    ??TASK3dispatch_0
//   89   TASK3_LOCK=1;
        SBI     0x1E, 0x01
//   90   DISABLE_TASK2();
        CBI     0x1F, 0x03
//   91   __enable_interrupt();
        SEI
//   92   ((void(*)(void))TASK3)();  
        RCALL   TASK3
//   93   __disable_interrupt();
        CLI
//   94   TASK3_LOCK=0;
        CBI     0x1E, 0x01
//   95   if (TASK2_LOCK) return;
        SBIC    0x1E, 0x00
        RJMP    ??TASK3dispatch_0
//   96   if (TASK2_WAKEUP) ENABLE_TASK2();
        SBIC    0x1E, 0x02
        SBI     0x1F, 0x03
??TASK3dispatch_0:
        RETI
        REQUIRE _A_EECR
        REQUIRE _A_GPIOR0
//   97 }
//   98
//   99 #pragma vector=INT0_vect

        RSEG CODE:CODE:NOROOT(1)
//  100 __interrupt void TASK4(void)
TASK4:
//  101 {
        ST      -Y, R17
        ST      -Y, R16
        IN      R17, 0x3F
//  102   //Тут тоже колдовство, запрещаем все прерывания, например
//  103   TIMSK0=0;
        LDI     R16, 0
        STS     110, R16
//  104   //Запрещаем и TASK2
//  105   DISABLE_TASK2();
        CBI     0x1F, 0x03
//  106   __enable_interrupt();
        SEI
//  107   //Чего-то делаем, тут еще бывает INT1, но это уже не суть
//  108   __disable_interrupt();
        CLI
//  109   if (PINB_Bit1) WAKEUP_TASK2(); //К примеру
        SBIC    0x03, 0x01
        SBI     0x1E, 0x02
//  110   TIMSK0=1<<TOV0;
??TASK4_0:
        LDI     R16, 1
        STS     110, R16
//  111   if (TASK3_LOCK) return;
        SBIC    0x1E, 0x01
        RJMP    ??TASK4_1
//  112   if (TASK2_LOCK) return;
        SBIC    0x1E, 0x00
        RJMP    ??TASK4_1
//  113   if (TASK2_WAKEUP) ENABLE_TASK2();
        SBIC    0x1E, 0x02
        SBI     0x1F, 0x03
??TASK4_1:
        OUT     0x3F, R17
        LD      R16, Y+
        LD      R17, Y+
        RETI


В принципе, из-за того, что управление прерыванием доступно через SBI/CBI время нахождения в состоянии с запрещенным прерыванием даже уменьшилось... Красота только пропала wink.gif
galjoen
Цитата(Rst7 @ May 21 2008, 09:48) *
Код
#pragma vector=TIMER0_OVF_vect
__interrupt __raw void TASK3dispatch(void)
{
  if (TASK3_LOCK) return;
  TASK3_LOCK=1;
  DISABLE_TASK2();
  __enable_interrupt();
  ((void(*)(void))TASK3)();  
  __disable_interrupt();
  TASK3_LOCK=0;
  if (TASK2_LOCK) return;
  if (TASK2_WAKEUP) ENABLE_TASK2();
}

Не совсем понял вот этот кусок, поэтому м.б. задам глупый вопрос.
Код
  if (TASK3_LOCK) return;
  TASK3_LOCK=1;

Это видимо антирекурсия, так?
Почему вы, любитель красоты в программировании (я наверное такой-же) использовали для этого лишний бит (#define TASK3_LOCK GPIOR0_Bit1), а не сам бит разрешения прерывания TOIE0 из регистра TIMSK? Это из-за того, что в вашем процессоре он не доступен командами cbi, sbic и поэтому требует вспомогательного регистра (и его сохранения) в т.ч. для проверки в прерывании INT0? Зато прерывания от таймера вообще возникать не будут - уменьшение времени нахождения с запрещёнными прерываниями ну и красота.
SasaVitebsk
В принципе предложений накидали. smile.gif Обсуждать подход автора, считаю глупым, так как он к нам за этим не обращался, к тому же постановка вопроса близка и понятна мне.

В XMEGA будет проще данную проблему решать. smile.gif
Dog Pawlowa
Цитата(SasaVitebsk @ May 21 2008, 10:15) *
Обсуждать подход автора, считаю глупым, так как он к нам за этим не обращался, к тому же постановка вопроса близка и понятна мне.

А поговорить? smile.gif
Rst7
Цитата
Зато прерывания от таймера вообще возникать не будут - уменьшение времени нахождения с запрещёнными прерываниями ну и красота.


В общем итоге - с запрещением через TIMSK хуже.

Цитата
В XMEGA будет проще данную проблему решать.


А то, там костыль есть для генерации эвентов вручную. О нас подумали wink.gif

Цитата
А поговорить?


Неси литру, поговорим smile.gif
sKWO
Цитата(Rst7 @ May 21 2008, 08:48) *
В принципе, из-за того, что управление прерыванием доступно через SBI/CBI время нахождения в состоянии с запрещенным прерыванием даже уменьшилось... Красота только пропала wink.gif

Это уже есть мысль. Круто
Да и не сказалбы я что красота пропала
Есть в общем над чем поломать голову и поучиться a14.gif
galjoen
М.б. конечно я уже надоел своим занудством, но...
Цитата(Rst7 @ May 21 2008, 11:37) *
В общем итоге - с запрещением через TIMSK хуже.

Мне вот это всё не нравится (некрасивым кажется):
Код
//   88   if (TASK3_LOCK) return; // вот это (лишних 12 тактов при возникновении прерывания от таймера при  TASK3_LOCK=1)
        SBIC    0x1E, 0x01
        RJMP    ??TASK3dispatch_0
//   89     TASK3_LOCK=1;
        SBI     0x1E, 0x01
//   90   DISABLE_TASK2();
        CBI     0x1F, 0x03
//   91   __enable_interrupt();
        SEI
//   92   ((void(*)(void))TASK3)(); // и ОСОБЕННО это (3+4=7 тактов лишних при КАЖДОМ вызове)
        RCALL   TASK3
//   93   __disable_interrupt();
        CLI
//   94   TASK3_LOCK=0;
        CBI     0x1E, 0x01
//   95   if (TASK2_LOCK) return;
        SBIC    0x1E, 0x00
        RJMP    ??TASK3dispatch_0
//   96   if (TASK2_WAKEUP) ENABLE_TASK2();
        SBIC    0x1E, 0x02
        SBI     0x1F, 0x03
??TASK3dispatch_0:

Всё это ведь сделано что-бы регистры при возникновении прерывания при TASK3_LOCK=1 не сохранялись. А если в прерывании от таймера __interrupt void использовать, а там и TASK3_LOCK=1 устанавливать (для INT0), и TIMSK запрещать (всего 3 такта лишних)? Вроде по всем параметрам лучше. Ну а главное красивее smile.gif .
Rst7
Цитата
Мне вот это всё не нравится (некрасивым кажется):


Ну попробуйте переделать. Рыба, которую я привел - она компилируется...
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.