Палыч 10 20 мая, 2008 Опубликовано 20 мая, 2008 · Жалоба Прямой вызов - не проходит, надо чтобы из того вернулась и вошла в новое. Почему - "не проходит"? Перед вызовом - разрешил прерывания - и все дела... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
SapegoAL 0 20 мая, 2008 Опубликовано 20 мая, 2008 · Жалоба Почему - "не проходит"? Перед вызовом - разрешил прерывания - и все дела... Надо выйти из предыдущего прерывания. Можно это конечно сделать и ручками, но зачем? Я, к примеру задействовал незадействованый таймер. Приведу пример ... #pragma vector=TIMER1_COMPA_vect, INT7_vect // Отображение картинки Master, Slave __interrupt static void Regeneration(void) { ... NPrer_COMPA++; if(NPrer_COMPA==16)TIMSK0=2; // Выполнить прерывание } ... #pragma vector=TIMER0_COMPA_vect // Исполнение комманд __interrupt static void ShowActive(void) { .... TIMSK0=0; // Запретить прерывание __enable_interrupt(); .... } Таким образом у меня второе прерывание выполняется 1 раз за 16 прерываний первого и может длиться несколько прерываний первого. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Палыч 10 20 мая, 2008 Опубликовано 20 мая, 2008 · Жалоба Надо выйти из предыдущего прерывания. Зачем? Экономия стека? Можно вызывать и не процедуру обработки прерывания, а обыкновенную процедуру... Из предыдущего прерывания выходить и входить в новое - вовсе не обязательно! От этого ничего не изменится Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
galjoen 0 20 мая, 2008 Опубликовано 20 мая, 2008 · Жалоба Не, такой пример не пойдет, разобъют сразу тупым и в тоже время справедливым вопросом - почему бы не выполнить хороший кусок работы в основном цикле программы. :) Не. В основном цикле не пойдёт. Вдруг там уже что-то выполняется, тогда туда и вернёмся. Кроме того написано, что нужно быстро - каждый такт на счету. Т.е. видимо нужно сделать что-то более приоритетное чем основной цикл, но менее приоритетное, чем прерывания (некоторые). Например рассчёт CRC блока, который в флешку записать надо. В таких случаях приходится и с возможностью рекурсии бороться, и со стеком колдовать, и смотреть кого это мы прервали то. Только на асме такое делается (я делал). А тут видимо на C, используя прерывания, такое же хотят сделать. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
_Pasha 0 20 мая, 2008 Опубликовано 20 мая, 2008 · Жалоба Привет, телепаты :) 1. Какая у Вас мега в проекте? <удалил чушь> Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Палыч 10 20 мая, 2008 Опубликовано 20 мая, 2008 · Жалоба Т.е. видимо нужно сделать что-то более приоритетное чем основной цикл, но менее приоритетное, чем прерывания (некоторые). О чём речь? Ну, нет в AVR приоритетов выполняемого кода! Или прерывания разрешены - прерывания возможны, или они запрещены - тогда прерывание никакое не произайдет! Reset - не всчёт! Нельзя в AVR выполнять код при разрешенных прирываниях, и, чтобы при этом одни прерывания могли прервать выполнение, а другие - нет (если они, конечно, все разрешены)! Приоритеты прерываний - это "из другой оперы"... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
SapegoAL 0 20 мая, 2008 Опубликовано 20 мая, 2008 · Жалоба Вот уж не знаю как вам объяснить. :) Ещё раз! Обзовём процедуры прерывания по мере их написания в моём предыдущем посте - 1 и 2. Представьте, что прерывание 1 выполняется каждую мс. Соответственно п2 исполняется каждые 16мс. Предположем, что длительность исполнения п1 составляет 100мкс, а длительность п2 составляет 10мс. В вашем варианте, если не принять специальных мер прервётся исполнение процедуры1, после начала исполнения процедуры2. Мало этого во много раз возростёт контекст в п1, что совершенно неоправдано увеличит загрузку процессора, так как они часто вызываются. Неисключено, что может произойти крах, так как выход из п1 завершён не будет, а будет повторный вход. Ну и как минимум будет оверхед по стеку. Итак недостатки я перечислил - какие преимущества? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Rst7 5 20 мая, 2008 Опубликовано 20 мая, 2008 · Жалоба Давайте я попробую все-таки подробностей добавить. Есть 4 задачи. В порядке возрастания приоритетов: 1. Основной поток (тот который main()). На данный момент там банальный for(;;). Чего там будет, я пока не знаю, и поэтому, этот поток трогать мне нельзя. 2. Задача обработки. Длительная, выполняется намного дольше, чем промежуток между вызовами задач 3,4. Во время выполнения должны уметь получать управление задачи 3,4, причем с минимальным временем отклика (особенно 4). Запуск задачи происходит от события. По окончанию обработки задача засыпает до следующего события. 3. Задача - не самое приоритетное прерывание. От таймера, но вызывается часто - 256/512 тактов. В задаче - по быстренькому опрос периферии и по результатам - возможна генерация события для задачи 2. Во время выполнения этой задачи необходимо обеспечить возможность быстрого реагирования на прерывание для задачи 4. 4. Самое приоритетное прерывание. Входит, выполняет дело, по результатам дела генерирует или не генерирует событие, выходит. Да, забыл. Задача 1 тоже потом может будет генерить события для задачи 2, а может и не будет. Для такого менеджмента задач идеально использовать RTOS, но есть одно но - пока переключаются контексты поезд задачи 4 уходит далеко - в смысле, время реакции не устраивает. Значит, надо делать подобие RTOS, но с минимальными временами нахождения в состояниях c запретом прерываний. План у меня таков - задача 2 - это обработчик прерывания, запрос на выполнение которого я могу создать в любой момент (это генерация события), а вот обработать - только тогда, когда не выполняются задачи 3 или 4 (и не находимся внутри задачи 2, дабы не допустить вложенности). Для этого мне и необходимо раздельное управление флагом запроса и битом разрешения прерывания. Вариант со счетчиком плохо проходит в связи с тем, что увеличение/уменьшение счетчика требует сохранения SREG (с последующим восстановлением) и работу с самим счетчиком до разрешения прерываний. Вот примерно такой код #define TASK2_LOCK GPIOR0_Bit0 #define TASK3_LOCK GPIOR0_Bit1 #define DISABLE_TASK2() {asm("PUSH R16");ACSR=(1<<ACD)|(1<<ACIS1);asm("POP R16");} #define ENABLE_TASK2() {asm("PUSH R16");ACSR=(1<<ACD)|(1<<ACIS1)|(1<<ACIE);asm("POP R16");} #define WAKEUP_TASK2() {ACSR=(1<<ACD)|(1<<ACIS1)|(1<<ACIS0);} #pragma diag_suppress=Ta006 __interrupt void TASK2(void) { __no_operation(); //.... //....много всякой долгой каки... main(); //Например так //.... __no_operation(); } #pragma diag_default=Ta006 #pragma vector=ANA_COMP_vect __interrupt __raw void TASK2dispatch(void) { DISABLE_TASK2(); TASK2_LOCK=1; __enable_interrupt(); ((void(*)(void))TASK2)(); __disable_interrupt(); TASK2_LOCK=0; 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) 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 (!TASK2_LOCK) ENABLE_TASK2(); } А вот чего выходит после компилятора RSEG CODE:CODE:NOROOT(1) // 176 __interrupt void TASK2(void) TASK2: // 177 { 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 // 178 __no_operation(); NOP // 179 //.... // 180 //....много всякой долгой каки... // 181 main(); //Например так RCALL main // 182 //.... // 183 __no_operation(); NOP // 184 } 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 // 185 #pragma diag_default=Ta006 // 186 // 187 // 188 #pragma vector=ANA_COMP_vect RSEG CODE:CODE:NOROOT(1) // 189 __interrupt __raw void TASK2dispatch(void) TASK2dispatch: // 190 { // 191 DISABLE_TASK2(); PUSH R16 LDI R16, 130 OUT 0x30, R16 POP R16 // 192 TASK2_LOCK=1; SBI 0x1E, 0x00 // 193 __enable_interrupt(); SEI // 194 ((void(*)(void))TASK2)(); RCALL TASK2 // 195 __disable_interrupt(); CLI // 196 TASK2_LOCK=0; CBI 0x1E, 0x00 // 197 ENABLE_TASK2(); PUSH R16 LDI R16, 138 OUT 0x30, R16 POP R16 // 198 } RETI REQUIRE _A_ACSR REQUIRE _A_GPIOR0 // 199 // 200 #pragma diag_suppress=Ta006 RSEG CODE:CODE:NOROOT(1) // 201 __interrupt void TASK3(void) TASK3: // 202 { ST -Y, R16 // 203 __no_operation(); NOP // 204 //.... // 205 //....не очень много всякой долгой каки... // 206 if (PINB_Bit0) WAKEUP_TASK2(); //К примеру SBIS 0x03, 0x00 RJMP ??TASK3_0 LDI R16, 131 OUT 0x30, R16 // 207 //.... // 208 __no_operation(); ??TASK3_0: NOP // 209 } LD R16, Y+ RETI REQUIRE _A_ACSR REQUIRE _A_PINB // 210 #pragma diag_default=Ta006 // 211 // 212 #pragma vector=TIMER0_OVF_vect RSEG CODE:CODE:NOROOT(1) // 213 __interrupt __raw void TASK3dispatch(void) TASK3dispatch: // 214 { // 215 if (TASK3_LOCK) return; SBIC 0x1E, 0x01 RJMP ??TASK3dispatch_0 // 216 TASK3_LOCK=1; SBI 0x1E, 0x01 // 217 DISABLE_TASK2(); PUSH R16 LDI R16, 130 OUT 0x30, R16 POP R16 // 218 __enable_interrupt(); SEI // 219 ((void(*)(void))TASK3)(); RCALL TASK3 // 220 __disable_interrupt(); CLI // 221 TASK3_LOCK=0; CBI 0x1E, 0x01 // 221 if (!TASK2_LOCK) ENABLE_TASK2(); SBIC 0x1E, 0x00 RJMP ??TASK3dispatch_0 PUSH R16 LDI R16, 138 OUT 0x30, R16 POP R16 ??TASK3dispatch_0: RETI REQUIRE _A_ACSR REQUIRE _A_GPIOR0 // 222 } // 223 // 224 #pragma vector=INT0_vect RSEG CODE:CODE:NOROOT(1) // 225 __interrupt void TASK4(void) TASK4: // 226 { ST -Y, R17 ST -Y, R16 IN R17, 0x3F // 227 //Тут тоже колдовство, запрещаем все прерывания, например // 228 TIMSK0=0; LDI R16, 0 STS 110, R16 // 229 //Запрещаем и TASK2 // 230 DISABLE_TASK2(); PUSH R16 LDI R16, 130 OUT 0x30, R16 POP R16 // 231 __enable_interrupt(); SEI // 232 //Чего-то делаем, тут еще бывает INT1, но это уже не суть // 233 __disable_interrupt(); CLI // 234 if (PINB_Bit1) WAKEUP_TASK2(); //К примеру SBIS 0x03, 0x01 RJMP ??TASK4_0 LDI R16, 131 OUT 0x30, R16 // 235 TIMSK0=1<<TOV0; ??TASK4_0: LDI R16, 1 STS 110, R16 // 236 if (!TASK2_LOCK) ENABLE_TASK2(); SBIC 0x1E, 0x00 RJMP ??TASK4_1 PUSH R16 LDI R16, 138 OUT 0x30, R16 POP R16 // 237 } ??TASK4_1: OUT 0x3F, R17 LD R16, Y+ LD R17, Y+ RETI Вариант с прерываниями хорош еще и тем, что в задаче 1 я могу выполнить WAKEUP_TASK2();ENABLE_TASK2() - и сразу полетит выполять задачу 2. Все приоритеты красиво соблюдаются. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Палыч 10 20 мая, 2008 Опубликовано 20 мая, 2008 · Жалоба В вашем варианте, если не принять специальных мер прервётся исполнение процедуры1, после начала исполнения процедуры2. Мало этого во много раз возростёт контекст в п1, что совершенно неоправдано увеличит загрузку процессора, так как они часто вызываются. Неисключено, что может произойти крах, так как выход из п1 завершён не будет, а будет повторный вход. Ну и как минимум будет оверхед по стеку. Как сделать так, чтобы контекст не возрастал - уже обсуждалось... Крах при повторном входе? С чего бы это? Обсуждение, кажется, ушло в сторону от заданного вопроса... Как я понял автора (пост №21): ему нужно изменить счетчики до возврата в основную программу, но чтобы при этом была возможность прерывания выполнять. Самое простое решение - прерывания разрешить. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
galjoen 0 20 мая, 2008 Опубликовано 20 мая, 2008 · Жалоба Приоритеты прерываний - это "из другой оперы"... Именно такую задачу я имел ввиду и решал (с приоритетами прерываний). Для этого обработчики располагаются во FLASH определённым образом. Чем выше приоритет, тем в более младших адресах обработчик. Основной цикл (низший приоритет) в самых старших адресах. При входе в обработчик - прерывания с младшими приоритетами запрещаются. В обработчике прерывания - прерывания разрешены. По адресу возврата (реально нужен только старший байт) в стеке перед выходом определяется какие прерывания разрешить (дополнительно к уже разрешённым). Т.е. получается система прерываний (и выполняемого кода) с приоритетами. И без RTOS. Из-за этого быстро между задачами переключается. В простых случаях (мало приоритетов) можно флагами обойтись. А для флагов какой-нибудь неиспользуемый регистр ввода-вывода (адрес до 0x20) использовать - для скорости. Я обычно там где такого специального нет (в AT90 есть) регистры адреса EEPROM использую. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
singlskv 0 20 мая, 2008 Опубликовано 20 мая, 2008 · Жалоба Не знаю точно поможет ли это Вам в конкретной задачке, но я бы размышлял примерно так: >>4. Самое приоритетное прерывание. Входит, выполняет дело, по результатам дела генерирует или >>не генерирует событие, выходит. Ну вот это явно претендент на свое собственное прерывание. >>3. Задача - не самое приоритетное прерывание. От таймера, но вызывается часто - 256/512 тактов. В >>задаче - по быстренькому опрос периферии и по результатам - возможна генерация события для >>задачи 2. Во время выполнения этой задачи необходимо обеспечить возможность быстрого >>реагирования на прерывание для задачи 4. типичное таймерное прерывание, для разрешения других прерываний достаточно "легко" делается сохранение контекста(если конечно задачка действительно простенькая...) задачки 1 и 2 разумнее(скорее всего, делать в основном цикле), для задачки N2 возможно подойдет просто опрос полингом флага другого таймера(специально закрепленного за этой задачкой) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ReAl 0 20 мая, 2008 Опубликовано 20 мая, 2008 · Жалоба Как раз от компаратора в scmRTOS и используют, но вроде как внешне что то к выводу компаратора припаивать надо... Лучше обратиться к первоисточнику. К сожалению адреса не знаю - но по моему в форуме про RTOS тема травой не заростает.Ничего припаивать не надо. Но одна нога занята. Один из входов компаратора ставится на внутренний ИОН, второй остаётся на ножке, ножка ставится на выход. Этого достаточно. В порт avr-gcc в примеры внесён ещё и другой вариант - используется прерывание SPM_ready (считается, что не используется при работе приложения, а не загрузчика). При необходимости вызвать прерывание поднимается бит SPMIE, в обработчике он сбрасывается. Ничего плохого в таком варианте не вижу. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
singlskv 0 20 мая, 2008 Опубликовано 20 мая, 2008 · Жалоба Если свободен пин nSS(SPI SlaveSelect) я бы еще подумал насчет него... ну типа: Thus, when interrupt-driven SPI transmission is used in Master mode, and there exists a possibility that SS is driven low, the interrupt should always check that the MSTR bit is still set. If the MSTR bit has been cleared by a slave select, it must be set by the user to re-enable SPI Master mode. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
defunct 0 20 мая, 2008 Опубликовано 20 мая, 2008 · Жалоба Не. В основном цикле не пойдёт. Вдруг там уже что-то выполняется, тогда туда и вернёмся. Кроме того написано, что нужно быстро - каждый такт на счету. Смотря как построен основной цикл. У меня в основном цикле выполняется диспетчер задач, точнее даже диспетчер функций-обработчиков событий. Т.к. задачи выполняются бесконечно, а функции - конечно и быстро. Функции делятся по приоритетам. Приоритет драйверов периферии (диспетчер крутит их постоянно) и пользовательские приоритеты. Работает все это как часы. Никаких проблем с сохранением контекстов, никаких накладных расходов на отдельные стеки задач. В прерываниях устаналивается готовность соотв. функций. В основном цикле - производится запуск обработчика события. Насчет каждый такт на счету - не верю, не может каждый такт быть на счету для чего-то настолько длительного, что ест аж 4 периода таймера и в то же время настолько редкого, что происходит раз в 100 периодов таймера. Нестукуется с таким событием понятие каждый такт на счету. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ReAl 0 20 мая, 2008 Опубликовано 20 мая, 2008 · Жалоба Кстати, я очень обижен на атмел в том, что битики force output compare у таймеров не вызывают соответствующее прерывание output compare :-( Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться