|
Стек для прерываний, и недостаток таймеров |
|
|
|
Jul 26 2009, 20:51
|
Местный
  
Группа: Участник
Сообщений: 421
Регистрация: 2-01-08
Пользователь №: 33 778

|
Кто нибудь делал отдельный стек для прерываний? есть ли смысл? код думаю писать как то так, Код handler: sts stack-0, r16 sts stack-1, r17 in r16, __SP_L_ in r17, __SP_H_ sts stack-2, r16 sts stack-3, r17 ldi r16, lo8(stack-4) ldi r17, hi8(stack-4) out __SP_L__, r16 out __SP_H__, r17 //здесь код обработчика прерывания // востановление писать лень ) тут все понятно reti_ Не слишком ли будет тяжеловесно? хотя это не главный вопрос, основная сложность с компилятором (GCC) как его заставить генерировать обработчтки в таком виде? можно __attribute__ ((__naked__)) но тогда надо как то следить за тем какие регистры были использованы, не сохранять же все. Похоже надо начинать смотреть исходники GCC. Правка: push/pop и st/ld длятся все по 2 такта, можно просто заменить все push на sts с фиксированными адресами ... потерь в скорости не будет.
Сообщение отредактировал amaora - Jul 26 2009, 21:17
|
|
|
|
|
 |
Ответов
|
Jul 26 2009, 20:58
|
Местный
  
Группа: Участник
Сообщений: 421
Регистрация: 2-01-08
Пользователь №: 33 778

|
И вопрос второй, в atmega16 три таймера, а что если надо больше? нулевой занят планировщиком для прееключения задач, первый планирую для ШИМ, второй для часов с отдельным 32.768 кГц резонатором. А надо вот ещё опрашивать небольшую клавиатуру с частотой от 60..120 Гц. Что можно сделать? сменить MCU не вариант. Цитата(aaarrr @ Jul 27 2009, 00:55)  Вот на этот вопрос Вам и надо сначала найти ответ. Я лично не вижу ни малейшего смысла. Не хочется держать на стеке каждой задачи пустое место размером ~20 байт. Пока сложно сказать хватит ли 1кб на все.
Сообщение отредактировал amaora - Jul 26 2009, 20:59
|
|
|
|
|
Jul 27 2009, 09:35
|
Местный
  
Группа: Свой
Сообщений: 327
Регистрация: 12-04-05
Из: Новосибирск
Пользователь №: 4 057

|
Цитата(defunct @ Jul 27 2009, 05:01)  Возьмите за основу кооперативную ОС, - один общий стек на все задачи и прерывания. А разве в кооперативной ОС один стек на все задачи? Насколько я понимаю, кооперативная ОС отличается от некооперативной тем, что в первом случае, задача сама решает, когда передать управление другой задаче, а во втором - ОС насильно прерывает одну задачу и передает управление другой. Или я ошибаюсь в терминологии?
|
|
|
|
|
Jul 27 2009, 11:01
|

кекс
     
Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326

|
Цитата(Zlumd @ Jul 27 2009, 12:35)  А разве в кооперативной ОС один стек на все задачи? Да. Иначе какой в ней смысл и преимущество над вытесняющей ОС? Цитата Насколько я понимаю, кооперативная ОС отличается от некооперативной тем, что в первом случае, задача сама решает, когда передать управление другой задаче, а во втором - ОС насильно прерывает одну задачу и передает управление другой. Или я ошибаюсь в терминологии? В общем верно, если "передать управление другой задаче" заменить на "передать управление системе". Теперь, возьмем во внимание, - если задача сама решает когда передать управление системе, то что мешает ее построить в виде конечной функции, а планировщику периодически эту функцию вызывать? Цитата(SasaVitebsk @ Jul 27 2009, 13:04)  Я бы тоже. Да ещё бы ввёл флаг-байт с временными метками... ну типа светодиодиком помигать с частотой 2Гц либо 1Гц и т.д. Не проще на один таймер посадить только планировщик. Который бы вызывал остальные задачи ровно тогда когда их нужно вызывать?
|
|
|
|
|
Jul 28 2009, 01:05
|
Местный
  
Группа: Свой
Сообщений: 327
Регистрация: 12-04-05
Из: Новосибирск
Пользователь №: 4 057

|
Цитата(defunct @ Jul 27 2009, 18:01)  Да. Иначе какой в ней смысл и преимущество над вытесняющей ОС? Преимущество в том, что нужно тратить меньше усилий по разделению доступа к общим ресурсам. Например, если какая-то многобайтовая переменная используется в обоих задачах, то в вытесняющей ОС при изменении этой переменной приходится запрещать прерывания, а в кооперативной этого не надо делать. Цитата(defunct @ Jul 27 2009, 18:01)  В общем верно, если "передать управление другой задаче" заменить на "передать управление системе". Теперь, возьмем во внимание, - если задача сама решает когда передать управление системе, то что мешает ее построить в виде конечной функции, а планировщику периодически эту функцию вызывать? Так это не несколько паралельно выполняющихся задач. Это одна задача. Каждая задача подразумевает сохранение всех локальных переменных, которые лежат в стеке, при переключении с задачи на задачу.
|
|
|
|
|
Jul 28 2009, 01:33
|

кекс
     
Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326

|
Цитата(Zlumd @ Jul 28 2009, 04:05)  Так это не несколько паралельно выполняющихся задач. Это одна задача. Как не крути а процессор один, и для него любая программа будет одной задачей. Вопрос в абстрагировании. Ниже приведено две реализации одного и того же: 1) Код task() { while( true) { wait_sema( sema_x); do_stuff(); } } 2) Код task() { if ( sema_x) do_stuff(); } Пусть памяти всего 1KB, и есть 3 таска. Во втором варианте каждый таск может запросто взять и пользовать например 512 байт под временный буфер, в первом же 3x512B > 1KB и приехали. Цитата Каждая задача подразумевает сохранение всех локальных переменных, которые лежат в стеке, при переключении с задачи на задачу Дайте каждой задаче static контекст с которым она работает, оформите как обычную функцию, массивные временные переменные/буферы выделяйте в стеке, и вызывайте их все поочереди(и/или по условию) и получите много задач, "параллельно" выполняющихся (находящихся в разной стадии исполнения), плюс оптимальное распределение памяти.
|
|
|
|
|
Jul 28 2009, 06:01
|
Местный
  
Группа: Свой
Сообщений: 327
Регистрация: 12-04-05
Из: Новосибирск
Пользователь №: 4 057

|
Цитата(defunct @ Jul 28 2009, 08:33)  Как не крути а процессор один, и для него любая программа будет одной задачей. Вопрос в абстрагировании. Ниже приведено две реализации одного и того же: 1) Код task() { while( true) { wait_sema( sema_x); do_stuff(); } } 2) Код task() { if ( sema_x) do_stuff(); } Пусть памяти всего 1KB, и есть 3 таска. Во втором варианте каждый таск может запросто взять и пользовать например 512 байт под временный буфер, в первом же 3x512B > 1KB и приехали. Так очень неудобно код писать. Что делать если хочется посидеть в do_stuff() примерно минуту ? Цитата(defunct @ Jul 28 2009, 08:33)  Дайте каждой задаче static контекст с которым она работает, оформите как обычную функцию, массивные временные переменные/буферы выделяйте в стеке, и вызывайте их все поочереди(и/или по условию) и получите много задач, "параллельно" выполняющихся (находящихся в разной стадии исполнения), плюс оптимальное распределение памяти. Static - это необоснованный расход памяти. Вот пример: Код Thread1() { func1(); func2(); func3(); func4(); func5(); func6(); func7(); func8(); } Пусть в каждой фунции func1...func8 есть локальные переменные по 100 байт в каждой. Если все staticами объявить, то Thread1 800 байт памяти отъест, если auto - то всего 100 байт. Может быть у нас терминология не совпадает? Я так понимаю, что задачи в вытесняющей ОС - это эквивалент Thread в программировании под Windows. А задачи в кооперативной ОС - это эквивалент Fiber. Я правильно понимаю?
|
|
|
|
|
Jul 28 2009, 23:02
|

кекс
     
Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326

|
Цитата(Zlumd @ Jul 28 2009, 09:01)  Так очень неудобно код писать. Что делать если хочется посидеть в do_stuff() примерно минуту ? Например сделать свою реализацию ks_wait() / ks_yeild() - которая будет запускать оставшиеся задачи прямо из текущей. Есть конечно и другой вариант, - разбить do_stuff() на две части, и запускать вторую часть через минуту после первой. Цитата Static - это необоснованный расход памяти. Именно. А Вы же собрались стек статически распределить. Плюс вероятно еще и контекст регистров каждого таска хранить, статически. В Вашем случае потерь памяти будет куда больше, чем если просто выделить ровно столько памяти сколько нужно для полезных данных. Цитата Пусть в каждой фунции func1...func8 есть локальные переменные по 100 байт в каждой. Если все staticами объявить, то Thread1 800 байт памяти отъест, если auto - то всего 100 байт. Не нужно бездумно объявлять все статиками. Делайте статиком только, то что должно быть статиком. Например задача обработки принятого пакета данных - вырождается в 1. вынуть пакет из очереди, 2. обработать 3. засунуть в другую очередь. 4. Гото 1. Сколько же нужно данных хранить статически для этой задачи? Помоему очевидно, если обеспечить непрерывное выполнение с п.1. до п.3. то статически хранить потребуется всего лишь два указателя на входную и выходную очереди. Цитата Может быть у нас терминология не совпадает? Я так понимаю, что задачи в вытесняющей ОС - это эквивалент Thread в программировании под Windows. А задачи в кооперативной ОС - это эквивалент Fiber. Я правильно понимаю? И да и нет. Насчет первого утверждения - сравнение Thread с таском вытесняющей ОС подходящее. Что же касается сравнения с Fiber в кооперативной ОС, ну не совсем оно то, хотя близко: 1. Никто не заставляет App управлять процессом, процессом запуска (schedule'ом) может заниматься ядро ОС, задача лишь обязана вернуть управление этому ядру - либо нативно - выход из функции, либо непосредственным вызовом соответствующей системной функции. 2. Никто не заставляет наделять задачу в кооперативной ОС своим стеком. В связи с тем, что задача сама отдает управление ОС когда ей удобно, - все задачи могут ужиться с одним общим стеком. Цитата(amaora @ Jul 28 2009, 10:43)  Во первых если задаче надо так много памяти то очень вероятно, что она долго не будет возвращать управление системе. Почему же, вот примеры где может потребоваться большой буфер, но не нужно много времени: - банальный ping - чтение/запись внешней флешки - обработка модбас пакета и т.д. все где имеет место запрос-ответ. Цитата Во вторых если в системе много ввода/вывода, то что регулярно делать if (data_ready) do_stuff() ? не лучше ли wait_for_event() который блокирует задачу (выводит из планирования), а потом в прерывании она снова ставится в очередь. Так и код проще выглядит. Бесспорно так лучше, абсолютно согласен. Но это же концепции не меняет, соответвующий if просто уйдет "в недра" планировщика, а задача будет состоять из одного только do_stuff(). ks_run( do_stuff, &do_stuff_context, <event_id>, <timeout> );
|
|
|
|
Сообщений в этой теме
amaora Стек для прерываний, и недостаток таймеров Jul 26 2009, 20:51 aaarrr Цитата(amaora @ Jul 27 2009, 00:51) есть ... Jul 26 2009, 20:55 aaarrr Цитата(amaora @ Jul 27 2009, 00:58) А над... Jul 26 2009, 21:19    prottoss Цитата(defunct @ Jul 27 2009, 19:01) Не п... Jul 27 2009, 14:39     defunct Цитата(prottoss @ Jul 27 2009, 17:39) Кла... Jul 27 2009, 15:00      _Pasha Цитата(defunct @ Jul 28 2009, 04:33) Дайт... Jul 28 2009, 01:55 prottoss Цитата(amaora @ Jul 27 2009, 04:58) И воп... Jul 27 2009, 07:49  SasaVitebsk Цитата(prottoss @ Jul 27 2009, 10:49) Я б... Jul 27 2009, 10:04 _Pasha Цитата(amaora @ Jul 26 2009, 23:51) Кто н... Jul 27 2009, 05:47 amaora Хорошо, с клавиатурой ясно, надо как то усложнить ... Jul 27 2009, 15:56 _Pasha Цитата(amaora @ Jul 27 2009, 18:56) А вот... Jul 27 2009, 16:54  amaora Цитата(_Pasha @ Jul 27 2009, 20:54) Имхо,... Jul 28 2009, 07:43   _Pasha Цитата(amaora @ Jul 28 2009, 10:43) С эти... Jul 29 2009, 10:32
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|