Цитата(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() даст этот адрес.