Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Keil RTX-166 Tiny
Форум разработчиков электроники ELECTRONIX.ru > Cистемный уровень проектирования > Операционные системы
Legotron
Добрый день!

Я решил использовать 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 */
}
DimaM
я кстати тоже собираюсь эту операционку использовать, однако еще не попробовал.

по поводу " Problems with pointers to stack based variables "
то мне кажется речь идет только об указателях внутри функций
это ограничение, но не смертельно.
другое дело - я не до конца понял что они называю автоматическими переменными ?
образуются они только тогда когда с указателями работаешь или еще в каких то случаях?

кстати, если у кого есть исходники для этой RTX для ARM пришлите пожалуйста на мейл
dmilioukov на yahoo.com
Legotron
Цитата(DimaM @ May 30 2007, 17:06) *
я кстати тоже собираюсь эту операционку использовать, однако еще не попробовал.

Я её чуть-чуть попробовал smile.gif
Вот и думаю стоит ли использовать дальше или сразу остановится.
Цитата(DimaM @ May 30 2007, 17:06) *
по поводу " Problems with pointers to stack based variables "
то мне кажется речь идет только об указателях внутри функций
это ограничение, но не смертельно.
другое дело - я не до конца понял что они называю автоматическими переменными ?

Тема такая:
Автоматическая переменная - это обычная переменная, которая размещается в стеке (вообщем все мы на заре начинали работать с auto переменными не задумываясь об этом smile.gif ). Тип она может иметь абсолютно любой, в том числе и указатель и объект класса и.т.д.
Цитата(DimaM @ May 30 2007, 17:06) *
образуются они только тогда когда с указателями работаешь или еще в каких то случаях?

Это не зависит от способа работы.

А по поводу "не смертельно":
Я стараюсь при написании программ сводить на минимум количество глобальных и статических переменных, и использовать их только в крайней необходимости. Глобальные лучше вообще не использовать(по крайней мере в ООП).
А с этой ОСью придется почти все переменные делать СТАТИЧЕСКИМ или ГЛОБАЛЬНЫМИ(что еще хуже)

Другой подход - критические секции(отключении планировщика) тоже перспектива так себе.
Существуют рекомендации также по минимизации количества/времени критических секций, потому что они отрубают систему. Если ими весь код натыркан то возникает вопрос: ЗАЧЕМ ВООБЩЕ СИСТЕМА, если она большинство времени заморожена?

Вообщем у меня пока пессимистический настрой к этой системе. mad.gif
DimaM
сначала просто подумал про указателеи что только они должны быть статическими.
согласен что делать все переменные статическими глупо.
но если локальные переменные могут быть изменены вызовами функция то это какая то фигня мне что то не верится 07.gif
Legotron
Цитата(DimaM @ May 31 2007, 00:51) *
но если локальные переменные могут быть изменены вызовами функция то это какая то фигня мне что то не верится 07.gif

На сайте Keil.com есть аппноут по поводу проблем, которые могут возникать с функцией printf как раз из-за локальных переменных. Разумеется эта ф-ция не единственная жертва, просто как мне кажется, у людей чаще возникает вопрос: Почему с RTX166 Tiny глючит printf? потому, что ф-ция printf связана с портом RS(ждет завершения putchar) и тут-то планировщик делает свое черное дело smile.gif когда поджимает другая задача. Там предлагается отключение системного таймера на время выполнения функции. Бред!

Думаю есть еще такие выходы из проблемы:

1 - использовать кооперативную планировку(с добровольной передачей управления другой задаче)
Тогда все приемущества циклической планировки x на 0. Плохо, но можно. Зато не надо парится со статикой и системным таймером!
2 - Выбрать период таймаута задачи заведомо большим чем самая длинная ф-ция. Более бредовый подход, т.к. мало кто знает скока будет в данный момент работать ф-ция (из разряда "Знал бы прикуп, жил бы в Сочи")
3 - Забросить к черту эту систему и перейти на UCOS (сложно, зато универсально и возможностей на порядок больше)
4 - Ждать предложений по решению проблемы
DimaM
Цитата(Legotron @ May 31 2007, 03:34) *
1 - использовать кооперативную планировку(с добровольной передачей управления другой задаче)
Тогда все приемущества циклической планировки x на 0. Плохо, но можно. Зато не надо парится со статикой и системным таймером!
2 - Выбрать период таймаута задачи заведомо большим чем самая длинная ф-ция. Более бредовый подход, т.к. мало кто знает скока будет в данный момент работать ф-ция (из разряда "Знал бы прикуп, жил бы в Сочи")
3 - Забросить к черту эту систему и перейти на UCOS (сложно, зато универсально и возможностей на порядок больше)
4 - Ждать предложений по решению проблемы

ucos это как раз то что я выбрал пока на цену не смотрел, посмотрел и метнулся к keil
хорошо хоть ваш пост прочитал
теперь следующий мой выбор FreeRTOS
вариант 1 это еще ничего, но не очень интересно
2 и 4 вообще расматривать бесполезно
scifi
Цитата(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. Не подходит - не используйте. Нужен совет - пожалуйста. А огульно обзывать вполне приличный софт полным г. - это перебор.
DimaM
Цитата(scifi @ Jun 7 2007, 15:41) *
Я с успехом использовал RTX-166 Tiny. Конечно, нельзя брать адрес от автоматической переменной, но меня это не смутило. Честно говоря, даже не могу вспомнить, когда мне приходилось в последний раз брать адрес локальной переменной.
Кстати, вполне ясно, что мы получаем в обмен на это ограничение: не нужно выделять стек отдельно под каждую задачу, так как суммарный расход стека равен сумме расходов для каждой задачи. В общем, изрядная экономия.

поскольку вы успешно использовали RTX-166 Tiny можете ли вы посказать

могут ли изменится локальные переменные в функциях после переключения задачь.

почему может быть неправильная работа с адресами локальных переменных

как узнать что еще где то кроме printf используется работа с локальными адресами
Andrew2000
Цитата
Совсем не бред. Вполне нормальное решение. Оберните printf макросом, который будет отключать и включать прерывание таймера, и используйте этот макрос.

А лучше вовсе не использовать printf. Есть sprintf - печатайте в разных задачах в свои буфера, потом выводите их своей функцией куда угодно (и синхронизируйте как нравится).
scifi
Цитата(DimaM @ Jun 7 2007, 16:28) *
поскольку вы успешно использовали RTX-166 Tiny можете ли вы посказать
могут ли изменится локальные переменные в функциях после переключения задачь.
почему может быть неправильная работа с адресами локальных переменных
как узнать что еще где то кроме printf используется работа с локальными адресами

Всё просто. При переключении задач RTX-166 Tiny двигает в памяти стек активной задачи, соответственно настраивая указатель стека. В результате адреса переменных, находящихся в стеке, меняются. Однако содержимое переменных остаётся прежним. Следовательно, нельзя в коде использовать указатели на автоматические переменные, поскольку адреса этих переменных могут измениться в самый неподходящий момент.
Функции printf, scanf, sprintf, scanf, как и все функции с переменным числом аргументов, используют в своём коде указатели на автоматические переменные для доступа к ним: достаточно взглянуть на реализацию макросов va_start, va_arg, va_end. Следовательно, перед вызовом таких функций надо запрещать прерывания таймера переключения задач.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.