|
|
  |
Keil RTX-166 Tiny, проблема с переключением стеков... |
|
|
|
May 30 2007, 12:34
|

инопланетянин
  
Группа: Свой
Сообщений: 236
Регистрация: 24-12-06
Из: Питер
Пользователь №: 23 832

|
Добрый день! Я решил использовать RTOS от Keil RTX-166 Tiny для Infineon, потому что эта ОСь халявная и очень простая(на мой взгляд). Но в ней есть документированная проблема следующего характера: Используется переключение стэка при смене задач, и вследствии проблемы с автоматическими переменными внутри функции самой задачи. Дается 2 варианта решения проблемы: 1 - не использовать автоматичесие переменные. 2 - работать с ними в критической секции(заморозка планировщика). У меня такой вопрос - эта система ПОЛНОЕ говно или я чего-то не понимаю? Ведь для того, чтобы вызвать любую функцию, в теле задачи мне придется помещать её в крит. секцию или делать все переменные внутри функции статическими. И так для каждой ф-ции с нестатическими переменными. Как мне кажется, одинаково как пичканье программы повсюду крит. секциями, так и ф-ций статическими переменными является дурным тоном(и не только). Что посоветуете в данном случае? Текст нотации от Keil: Цитата 1. Problems with pointers to stack based variables ================================================== The RTX166 Tiny uses a stack swapping method to reduce the required stack space of the whole system. However, due to the stack swapping, the addresses of automatic variables change during program execution. This can cause problems with the program execution when you use a pointer to an automatic variable in your program.
There are a couple of ways arround that problem as explained in the follwoing sample program.
#pragma MOD167 #include <string.h> #include <reg167.h> #include <intrins.h>
#define TIM_INT_ENABLE T0IE /* same configuration as in CPUTIMER.INC */
/*****************************/ /* RTX166 Tiny Task Function */ /*****************************/ void job (void) _task_ 0 { char a[16]; /* stack based variable */ static char b[16]; /* static variable */
strcpy (a, "Hello World"); /* this can fail since the address of the variable 'a' can change due to stack swapping during a task switch */
/* as a work-around you can disable the RTX166 Tiny Timer Interrupt */ TIM_INT_ENABLE = 0; /* disable RTX166 Tiny Timer */ _nop_ (); /* two NOP's to make sure that 166/167 */ _nop_ (); /* hardware has disabled the interrupt */ strcpy (a, "Hello World"); /* now it works, since there can be not RTX166 Tiny task switch */ TIM_INT_ENABLE = 1; /* enable RTX166 Tiny Timer */
/* another solution is to use static variables instead of stack based variables as in the following example */ strcpy (b, "Hello World"); /* this will always work. The variable 'b' is a static variable which has a fixed memory location */ }
|
|
|
|
|
May 30 2007, 13:34
|

инопланетянин
  
Группа: Свой
Сообщений: 236
Регистрация: 24-12-06
Из: Питер
Пользователь №: 23 832

|
Цитата(DimaM @ May 30 2007, 17:06)  я кстати тоже собираюсь эту операционку использовать, однако еще не попробовал. Я её чуть-чуть попробовал Вот и думаю стоит ли использовать дальше или сразу остановится. Цитата(DimaM @ May 30 2007, 17:06)  по поводу " Problems with pointers to stack based variables " то мне кажется речь идет только об указателях внутри функций это ограничение, но не смертельно. другое дело - я не до конца понял что они называю автоматическими переменными ? Тема такая: Автоматическая переменная - это обычная переменная, которая размещается в стеке (вообщем все мы на заре начинали работать с auto переменными не задумываясь об этом  ). Тип она может иметь абсолютно любой, в том числе и указатель и объект класса и.т.д. Цитата(DimaM @ May 30 2007, 17:06)  образуются они только тогда когда с указателями работаешь или еще в каких то случаях? Это не зависит от способа работы. А по поводу "не смертельно": Я стараюсь при написании программ сводить на минимум количество глобальных и статических переменных, и использовать их только в крайней необходимости. Глобальные лучше вообще не использовать(по крайней мере в ООП). А с этой ОСью придется почти все переменные делать СТАТИЧЕСКИМ или ГЛОБАЛЬНЫМИ(что еще хуже) Другой подход - критические секции(отключении планировщика) тоже перспектива так себе. Существуют рекомендации также по минимизации количества/времени критических секций, потому что они отрубают систему. Если ими весь код натыркан то возникает вопрос: ЗАЧЕМ ВООБЩЕ СИСТЕМА, если она большинство времени заморожена? Вообщем у меня пока пессимистический настрой к этой системе.
|
|
|
|
|
May 30 2007, 20:51
|
Частый гость
 
Группа: Участник
Сообщений: 103
Регистрация: 17-12-06
Из: село
Пользователь №: 23 615

|
сначала просто подумал про указателеи что только они должны быть статическими. согласен что делать все переменные статическими глупо. но если локальные переменные могут быть изменены вызовами функция то это какая то фигня мне что то не верится
|
|
|
|
|
May 30 2007, 23:34
|

инопланетянин
  
Группа: Свой
Сообщений: 236
Регистрация: 24-12-06
Из: Питер
Пользователь №: 23 832

|
Цитата(DimaM @ May 31 2007, 00:51)  но если локальные переменные могут быть изменены вызовами функция то это какая то фигня мне что то не верится  На сайте Keil.com есть аппноут по поводу проблем, которые могут возникать с функцией printf как раз из-за локальных переменных. Разумеется эта ф-ция не единственная жертва, просто как мне кажется, у людей чаще возникает вопрос: Почему с RTX166 Tiny глючит printf? потому, что ф-ция printf связана с портом RS(ждет завершения putchar) и тут-то планировщик делает свое черное дело  когда поджимает другая задача. Там предлагается отключение системного таймера на время выполнения функции. Бред! Думаю есть еще такие выходы из проблемы: 1 - использовать кооперативную планировку(с добровольной передачей управления другой задаче) Тогда все приемущества циклической планировки x на 0. Плохо, но можно. Зато не надо парится со статикой и системным таймером! 2 - Выбрать период таймаута задачи заведомо большим чем самая длинная ф-ция. Более бредовый подход, т.к. мало кто знает скока будет в данный момент работать ф-ция (из разряда "Знал бы прикуп, жил бы в Сочи") 3 - Забросить к черту эту систему и перейти на UCOS (сложно, зато универсально и возможностей на порядок больше) 4 - Ждать предложений по решению проблемы
|
|
|
|
|
May 31 2007, 09:25
|
Частый гость
 
Группа: Участник
Сообщений: 103
Регистрация: 17-12-06
Из: село
Пользователь №: 23 615

|
Цитата(Legotron @ May 31 2007, 03:34)  1 - использовать кооперативную планировку(с добровольной передачей управления другой задаче) Тогда все приемущества циклической планировки x на 0. Плохо, но можно. Зато не надо парится со статикой и системным таймером! 2 - Выбрать период таймаута задачи заведомо большим чем самая длинная ф-ция. Более бредовый подход, т.к. мало кто знает скока будет в данный момент работать ф-ция (из разряда "Знал бы прикуп, жил бы в Сочи") 3 - Забросить к черту эту систему и перейти на UCOS (сложно, зато универсально и возможностей на порядок больше) 4 - Ждать предложений по решению проблемы ucos это как раз то что я выбрал пока на цену не смотрел, посмотрел и метнулся к keil хорошо хоть ваш пост прочитал теперь следующий мой выбор FreeRTOS вариант 1 это еще ничего, но не очень интересно 2 и 4 вообще расматривать бесполезно
|
|
|
|
|
Jun 7 2007, 11:41
|
Гуру
     
Группа: Свой
Сообщений: 3 020
Регистрация: 7-02-07
Пользователь №: 25 136

|
Цитата(Legotron @ May 30 2007, 16:34)  У меня такой вопрос - эта система ПОЛНОЕ говно или я чего-то не понимаю? Вы чего-то не понимаете. Я с успехом использовал RTX-166 Tiny. Конечно, нельзя брать адрес от автоматической переменной, но меня это не смутило. Честно говоря, даже не могу вспомнить, когда мне приходилось в последний раз брать адрес локальной переменной. Кстати, вполне ясно, что мы получаем в обмен на это ограничение: не нужно выделять стек отдельно под каждую задачу, так как суммарный расход стека равен сумме расходов для каждой задачи. В общем, изрядная экономия. Цитата(Legotron @ May 31 2007, 03:34)  Там предлагается отключение системного таймера на время выполнения функции. Бред! Совсем не бред. Вполне нормальное решение. Оберните printf макросом, который будет отключать и включать прерывание таймера, и используйте этот макрос. Цитата(Legotron @ May 31 2007, 03:34)  2 - Выбрать период таймаута задачи заведомо большим чем самая длинная ф-ция. Более бредовый подход, т.к. мало кто знает скока будет в данный момент работать ф-ция (из разряда "Знал бы прикуп, жил бы в Сочи") Не получится. Поскольку вызовы функции не синхронизируются с таймером, прерывание от таймера может произойти в любой момент. Следовательно, увеличение периода таймера не избавит от этой проблемы, просто она будет происходить реже. Честно говоря, меня несколько задел такой "наезд" на RTX-166 Tiny. Не подходит - не используйте. Нужен совет - пожалуйста. А огульно обзывать вполне приличный софт полным г. - это перебор.
|
|
|
|
|
Jun 7 2007, 12:28
|
Частый гость
 
Группа: Участник
Сообщений: 103
Регистрация: 17-12-06
Из: село
Пользователь №: 23 615

|
Цитата(scifi @ Jun 7 2007, 15:41)  Я с успехом использовал RTX-166 Tiny. Конечно, нельзя брать адрес от автоматической переменной, но меня это не смутило. Честно говоря, даже не могу вспомнить, когда мне приходилось в последний раз брать адрес локальной переменной. Кстати, вполне ясно, что мы получаем в обмен на это ограничение: не нужно выделять стек отдельно под каждую задачу, так как суммарный расход стека равен сумме расходов для каждой задачи. В общем, изрядная экономия. поскольку вы успешно использовали RTX-166 Tiny можете ли вы посказать могут ли изменится локальные переменные в функциях после переключения задачь. почему может быть неправильная работа с адресами локальных переменных как узнать что еще где то кроме printf используется работа с локальными адресами
|
|
|
|
|
Jun 7 2007, 12:37
|
Местный
  
Группа: Свой
Сообщений: 421
Регистрация: 25-12-04
Пользователь №: 1 675

|
Цитата Совсем не бред. Вполне нормальное решение. Оберните printf макросом, который будет отключать и включать прерывание таймера, и используйте этот макрос. А лучше вовсе не использовать printf. Есть sprintf - печатайте в разных задачах в свои буфера, потом выводите их своей функцией куда угодно (и синхронизируйте как нравится).
|
|
|
|
|
Jun 7 2007, 13:32
|
Гуру
     
Группа: Свой
Сообщений: 3 020
Регистрация: 7-02-07
Пользователь №: 25 136

|
Цитата(DimaM @ Jun 7 2007, 16:28)  поскольку вы успешно использовали RTX-166 Tiny можете ли вы посказать могут ли изменится локальные переменные в функциях после переключения задачь. почему может быть неправильная работа с адресами локальных переменных как узнать что еще где то кроме printf используется работа с локальными адресами Всё просто. При переключении задач RTX-166 Tiny двигает в памяти стек активной задачи, соответственно настраивая указатель стека. В результате адреса переменных, находящихся в стеке, меняются. Однако содержимое переменных остаётся прежним. Следовательно, нельзя в коде использовать указатели на автоматические переменные, поскольку адреса этих переменных могут измениться в самый неподходящий момент. Функции printf, scanf, sprintf, scanf, как и все функции с переменным числом аргументов, используют в своём коде указатели на автоматические переменные для доступа к ним: достаточно взглянуть на реализацию макросов va_start, va_arg, va_end. Следовательно, перед вызовом таких функций надо запрещать прерывания таймера переключения задач.
|
|
|
|
|
  |
2 чел. читают эту тему (гостей: 2, скрытых пользователей: 0)
Пользователей: 0
|
|
|