|
|
  |
Схема перключения задач "scmRTOS_CONTEXT_SWITCH_SCHEME == 1", Порт под msp430X |
|
|
|
Mar 5 2010, 12:26
|
Группа: Участник
Сообщений: 7
Регистрация: 20-05-09
Из: Харьков
Пользователь №: 49 299

|
Выявил неприятное поведение при переключении задач в ОС, порт под msp430X. Использую схему переключения задач Код #define scmRTOS_CONTEXT_SWITCH_SCHEME 1 В обработчике прерывания используется обвертка TISRW или TISRW_SS. При выходе из обработчика прерывания вызывается планировщик Kernel.SchedISR(); Код INLINE void ISR_Exit() { DisableInterrupts(); if(--Kernel.ISR_NestCount) return; Kernel.SchedISR(); } Установиться флаг прерывания, и должно сработать прерывание по переключению задач. Но, пока мы находились в предыдущем обработчике, приходит время сработать системному таймеру (его обработчику). Выходит, по выходу из прерывания мы попадаем в более приоритетное прерывание от таймера, а в нем разрешаются прерывания Код #if scmRTOS_SYSTIMER_NEST_INTS_ENABLE == 1 ENABLE_NESTED_INTERRUPTS(); #endif и вот уже здесь вызовется обработчик прерывания по переключению задачи. Ни к чему хорошему это не приводит, так как переменная ядра Kernel.ISR_NestCount будет инкрементирована и после переключения задач уже запорченой. Как результат из задачи, куда мы переключились мы уже никогда не выйдем - зависнем. Я правильно понял, что при scmRTOS_CONTEXT_SWITCH_SCHEME = 1 в других прерываниях никогда нельзя разрешать вложенных прерываний? Не только в системном таймере, а в любом прерывании, особенно если в нем используется TISRW или TISRW_SS?
|
|
|
|
|
Mar 7 2010, 06:35
|

Adept
     
Группа: Свой
Сообщений: 3 469
Регистрация: 6-12-04
Из: Novosibirsk
Пользователь №: 1 343

|
Цитата(Sergey Bold @ Mar 5 2010, 18:26)  Ни к чему хорошему это не приводит, так как переменная ядра Kernel.ISR_NestCount будет инкрементирована и после переключения задач уже запорченой. Как результат из задачи, куда мы переключились мы уже никогда не выйдем - зависнем. Я правильно понял, что при scmRTOS_CONTEXT_SWITCH_SCHEME = 1 в других прерываниях никогда нельзя разрешать вложенных прерываний? Не только в системном таймере, а в любом прерывании, особенно если в нем используется TISRW или TISRW_SS? Интересный эффект. Навскидку, обычные прерывания (без контакта с ядром ос) не должны портить картину - ну, возникло внутри них прерывание переключения контекста, управление ушло в другой процесс... когда оно обратно вернется в этот прерванный, выполнение продолжится в этом прерывании. Т.е. с точки зрения целостности выполнения кода ничего фатального нет (хотя надо, конечно, проверять, возможно есть какие-то побочные эффекты). Но вот точки зрения программы это все очень неправильно и нехорошо. Во-первых, прерывание вместо того, чтобы выполниться быстренько, просто "зависло" на непредсказуемое время. Во-вторых, прерывания, как правило не очень реентерабельны. В общем, лучше так не делать. И вообще, я бы рекомендовал следующее - если процессор аппаратно не поддерживает какие-то средства, то надо очень хорошо подумать при использовании программных "костылей", которые как-то выполняют требуемую функциональность. Это касается, как раз, прерываний: использование отдельного стека на процессоре, где нет аппаратной поддержки отдельного стека прерываний и вложенных прерываний при одноуровнвом неприоритетном контроллере прерываний. В частности, обсуждаемый MSP430 как раз не имеет ни того, ни другого. Использование отдельного стека прерываний следует применять очень осторожно и соблюдая следующую рекомендацию: не писать в теле обработчика прерываний код, а поместить этот код в отдельную вызываемую функцию (ни в коем случае не встраиваемую, чтобы компилятор не видел ее потрохов в точке вызова) и в теле обработчика сделать вызов. Это на практике гарантирует, что компилятор не производит никаких финтов с указателем стека до вызова переключателя стеков (которые, если имеют место, то приводят к фатальным последствиям). Но лично я придерживаюсь другого подхода - не делать ISR длинным (долгим), выполнить в нем минимум функций и как можно быстрее отдать управление в основную программу (дабы не держать другие ISR) - это позволяет, как правило, и не расходовать много стека в ISR, поэтому необходимости в переключении на отдельный стек в прерывании не возникает. С вложенными прерываниями - ровно то же самое. Если процессор не имеет аппаратного приоритетного контроллера прерываний, то надо несколько раз подумать об использовании вложенных прерываний. И не только с осью, но и без нее (лично налетал еще на AVR по внешнему прерыванию (в котором было разрешение вложенных сделано), когда из-за помехи на входной пин валился "лес" импульсов и прерывание получилось существенно рекурсивным, а стек не резиновым оказался  ). Стратегия та же самая - обеспечивать короткое время реакции на прерывание не путем разрешения вложенных, а тем, чтобы сделать прерывания короткими и быстрыми. Ну, а если все же жизнь или предпочтения заставляют пользоваться программными аналогами отсутствующих средств, то надо хорошенько взвешивать решения и действовать осторожно, понимая, что это, в общем-то, не что иное, как хаки.
--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
|
|
|
|
|
Mar 8 2010, 13:31
|

Adept
     
Группа: Свой
Сообщений: 3 469
Регистрация: 6-12-04
Из: Novosibirsk
Пользователь №: 1 343

|
Цитата(AHTOXA @ Mar 8 2010, 00:40)  В случае с msp-gcc - не гарантирует  Именно поэтому пришлось ввести доп. #define TISRW_SS_STACK_PAD, чтоб хоть как-то этим управлять. (Но это для просто msp). Т.е. если просто вызов: Код OS_INTERRUPT void SomeISR() { TISRW_SS isrw;
some_fun(); } то все равно резервирует зачем-то в стеке место?
--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
|
|
|
|
|
Mar 9 2010, 07:25
|

фанат дивана
     
Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684

|
Цитата(dxp @ Mar 8 2010, 18:31)  все равно резервирует зачем-то в стеке место? Да. Для массивного деструктора TISRW_SS. вот это: Код interrupt(ADC_VECTOR) ADC12ISR(void) { OS::TISRW_SS ISRW; adc.isr_handler(); } даёт вот что: Код 000016fa <ADC12ISR()>: 16fa: 0f 12 push r15 16fc: 0e 12 push r14 16fe: 0d 12 push r13 1700: 0c 12 push r12 1702: 21 83 decd r1 1704: 3f 40 ec 06 mov #1772, r15;#0x06ec 1708: df 53 00 00 inc.b 0(r15) ;0x0000(r15) 170c: df 93 00 00 cmp.b #1, 0(r15);r3 As==01, 0x0000(r15) 1710: 1e 24 jz $+62 ;abs 0x174e 1712: 3f 40 a0 02 mov #672, r15;#0x02a0 1716: b0 12 8a 12 call #0x128a 171a: 32 c2 dint 171c: 3f 40 ec 06 mov #1772, r15;#0x06ec 1720: ff 53 00 00 add.b #-1, 0(r15);r3 As==11, 0x0000(r15) 1724: 20 20 jnz $+66 ;abs 0x1766 1726: 5f 42 e0 06 mov.b &0x06e0,r15 172a: 0f 5f rla r15 172c: 1f 4f e2 06 mov 1762(r15),r15;0x06e2(r15) 1730: 2f 4f mov @r15, r15 1732: 01 4f mov r15, r1 1734: 5f 42 e1 06 mov.b &0x06e1,r15 1738: b0 12 7c 1a call #0x1a7c 173c: 5f 92 e0 06 cmp.b &0x06e0,r15 1740: 12 24 jz $+38 ;abs 0x1766 1742: c2 4f ed 06 mov.b r15, &0x06ed 1746: f2 d0 03 00 bis.b #3, &0x0059;#0x0003 174a: 59 00 174c: 0c 3c jmp $+26 ;abs 0x1766 174e: 5f 42 e0 06 mov.b &0x06e0,r15 1752: 0f 5f rla r15 1754: 1e 4f e2 06 mov 1762(r15),r14;0x06e2(r15) 1758: 0f 41 mov r1, r15 175a: 8e 4f 00 00 mov r15, 0(r14);0x0000(r14) 175e: 3f 40 fc 09 mov #2556, r15;#0x09fc 1762: 01 4f mov r15, r1 1764: d6 3f jmp $-82 ;abs 0x1712 1766: 21 53 incd r1 1768: 3c 41 pop r12 176a: 3d 41 pop r13 176c: 3e 41 pop r14 176e: 3f 41 pop r15 1770: 00 13 reti
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
Mar 9 2010, 09:35
|
Группа: Участник
Сообщений: 7
Регистрация: 20-05-09
Из: Харьков
Пользователь №: 49 299

|
C переключением стека в прерывании для msp430 действительно как-то многовато кода получается, его не использую. Его упомянул в связи с тем, что и для TISRW и для TISRW_SS в моем случае одинаковый эффект. Как только в обработчике используется TISRW и разрешаются прерывания, то с большой вероятностью зависнет. По этому, использовать схему переключения по прерыванию решил и дальше. Ну а в обработчиках либо не использовать TISRW, либо не разрешать прерываний (я раньше использовал).
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|