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

Хочется программно инициировать прерывание

Насчет каждый такт на счету - не верю, не может каждый такт быть на счету для чего-то настолько длительного, что ест аж 4 периода таймера и в то же время настолько редкого, что происходит раз в 100 периодов таймера. Нестукуется с таким событием понятие каждый такт на счету.
Ну и почему же это не стыкуется ?

допустим хочу:

- передачу по SPI на максимальной скорости(кб этак 250-500 в сек) но при этом чтобы

джиттер был минимален и предсказуем

- опрос кнопок(типа процесс в 100 раз более медленный)

- запись в EEPROM когда надо(тоже не быстро).

- итд итп

 

ну и кто мешает это все совместить ?

 

 

Кстати, я очень обижен на атмел в том, что битики force output compare у таймеров не вызывают соответствующее прерывание output compare :-(
А Вы ими пробовали вобще пользоваться ? (битиками)

я нет, поэтому и интересно...

но кстати таймером тож можно чего-нить такое намутить, тока топикстартер не сознается какие

узлы кроме комаратора у него еще не задействованны...

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


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

Ну и почему же это не стыкуется ?

Несктыкуется это событие (длиной в 4 периода таймера) с надобностью обработки в прерывании.

 

допустим хочу:

- передачу по SPI на максимальной скорости(кб этак 250-500 в сек) но при этом чтобы

джиттер был минимален и предсказуем

- опрос кнопок(типа процесс в 100 раз более медленный)

- запись в EEPROM когда надо(тоже не быстро).

- итд итп

 

ну и кто мешает это все совместить ?

Ничто и не помешает все это совместить если обработку события длиной в 4 периода таймера кинуть в основной цикл.

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


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

Несктыкуется это событие (длиной в 4 периода таймера) с надобностью обработки в прерывании.

Ничто и не помешает все это совместить если обработку события длиной в 4 периода таймера кинуть в основной цикл.

А кто сказал что это событие обязательно нужно обработать за один присест ?

Вне зависимости от того где оно будет обрабатывться, всегда есть возможность

обработать его по частям.

Те просто делаем автомат обработки события с внутренним разбиением на части...

 

Те например пусть нам нужно записать X байт в EEPROM,

запись каждого байта это процесс который может растянуться на очень много периодов

нашего таймера, но у нас автомат который запустил запись X байтов и пока они все не записались

он не освободился.

Ну конечно если там голые рассчеты без всяких ожиданий то они конечно должны

жить в главном цикле...

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


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

Несктыкуется это событие (длиной в 4 периода таймера) с надобностью обработки в прерывании.

Тут прерывание ТОЛЬКО для того, чтоб приоритет этого события поднять, а основной цикл отдать кому то другому (на, делай в нём что хочешь, всё равно мне не навредишь).

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


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

Те просто делаем автомат обработки события с внутренним разбиением на части...

Ну так ведь ничто не мешает этот автомат сделать в основном цикле. Ввести там сколько надо приоритетов 10-100-1000 (на скоко памяти хватит) и следовать им.

 

Тут прерывание ТОЛЬКО для того, чтоб приоритет этого события поднять

Если только для этого, то обрабатывать можно в том же прерывании, зачем еще одно плодить?

результат одинаковый будет.

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


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

У меня для "быстрых" потоков, которые должны вызваться не позднее одного тика таймера после возникновения Event-а, требующего их вмешательства, есть регистр , в котором каждый битик является Ready-флагом соответствующего потока. И перед выходом из ISR системного таймера я проверяю не стоит ли Ready-флажок какого-нить потока. Если стоит, то запускаю соответ.поток в порядке приоритета (от 7 к 0 )

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


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

Ну так ведь ничто не мешает этот автомат сделать в основном цикле. Ввести там сколько надо приоритетов 10-100-1000 (на скоко памяти хватит) и следовать им.

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

 

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

 

__interrupt void low_priority_interrupt()

{ interrupt_no++;

if (interrupt_no>1) DISABLE_HIGH_PRIORITY_INTERRUPT();

__enable_interrupt();

...

}

Ну и попытка все устройства сделать на AVR , выжимая все соки? Даже в 8080 была система приоритетных прерываний, что других контроллеров не существует?

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


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

Ну вообщем, проверил на железе - не приводит к установке флага прерывания от компаратора дрыг режимом фронт/спад. Плохо, конечно. Пришлось перенести на прерывание от 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 время нахождения в состоянии с запрещенным прерыванием даже уменьшилось... Красота только пропала ;)

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


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

#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? Зато прерывания от таймера вообще возникать не будут - уменьшение времени нахождения с запрещёнными прерываниями ну и красота.

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


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

В принципе предложений накидали. :) Обсуждать подход автора, считаю глупым, так как он к нам за этим не обращался, к тому же постановка вопроса близка и понятна мне.

 

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

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


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

Обсуждать подход автора, считаю глупым, так как он к нам за этим не обращался, к тому же постановка вопроса близка и понятна мне.

А поговорить? :)

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


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

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

 

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

 

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

 

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

 

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

 

Неси литру, поговорим :)

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


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

В принципе, из-за того, что управление прерыванием доступно через SBI/CBI время нахождения в состоянии с запрещенным прерыванием даже уменьшилось... Красота только пропала ;)

Это уже есть мысль. Круто

Да и не сказалбы я что красота пропала

Есть в общем над чем поломать голову и поучиться :a14:

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


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

М.б. конечно я уже надоел своим занудством, но...

В общем итоге - с запрещением через 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 такта лишних)? Вроде по всем параметрам лучше. Ну а главное красивее :) .

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


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

Мне вот это всё не нравится (некрасивым кажется):

 

Ну попробуйте переделать. Рыба, которую я привел - она компилируется...

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


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

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

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

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

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

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

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

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

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

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