Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Несколько вопросов начинающего
Форум разработчиков электроники ELECTRONIX.ru > Cистемный уровень проектирования > Операционные системы > FreeRTOS
Страницы: 1, 2, 3
MiklPolikov
И ещё вопрос по флагам событий :
Я верно понимаю, что xEventGroupWaitBits работает только по факту наличия флага, сделать так чтоб работало по моменту выставления способа не предусмотрено ? Иными словами : пользователь жмёт кнопку, при этом выставляются и снимаются флаги "кнопка была нажата" "кнопка была отпущена". В задаче нужно чтоб программа проходила строку xEventGroupWaitBits после нажатия, а при следующем попадании на неё же ждала следующего отпускания + нажатия. Сбрасывать флаги нельзя, т.к. они используются в других функциях.
_Артём_
Цитата(MiklPolikov @ Feb 14 2014, 11:21) *
Код
/*volatile*/  xSemaphoreHandle    x_RTC_Second_Change;  //разве тут не нужен volatile ?
//.....
xSemaphoreGiveFromISR(x_RTC_Second_Change,&xHigherPriorityTaskWoken);

Не нужен volatile, потому что xSemaphoreHandle - это указатель и он в прерывании не изменяется.
MiklPolikov
Ещё один вопрос, по архитектуре кода :

Перевожу свои старые коды без ОС на FreeRTOS. К примеру есть функция, инициализирующая SD карту, в ней в каких-то циклах ожидание чего-то.
Как теперь с этим поступить наиболее правильно ?
а) Вставить в функцию команды переключения контекста. Функция будет вызываться в задаче, но выполняться будет не быстро, т.к. функция чего-то ждёт внутри себя.
С одной стороны контекст будет переключатся, т.е. система в целом работать правильно, но с другой та задача, которая функцию вызвала, будет останавливаться на этой функции на большое время, что на мой взгляд криво.
б) Сделать из функции отдельную задачу. Создавать её когда надо проинициализировать карту, когда инициализация прошла удалять, а о том что инициализация прошла узнавать через эвенты или симафоры.

Заранее спасибо.
DASM
Б
kolobok0
Цитата(MiklPolikov @ Apr 24 2014, 18:41) *
...есть функция, инициализирующая SD карту...


в) всю работу с карточкой убрать в нитку. обслуживать запросы можно и синхронно и асинхронно - в зависимости от дальнейшей надобности.
MiklPolikov
Цитата(kolobok0 @ Apr 24 2014, 22:54) *
в) всю работу с карточкой убрать в нитку. обслуживать запросы можно и синхронно и асинхронно - в зависимости от дальнейшей надобности.


Объясните пожалуйста на пальцах, что значит "убрать в нитку" и "обслуживать запросы синхронно и асинхронно" ?
Это всё значит сделать один линейный код в одной задаче ? Но тогда непонятно во-первых как переходить в разные места этого кода так что бы не было путаного синтаксиса, а во-вторых придётся в одном коде смешивать и хардварную часть, и высокоуровневую аппаратно-независимую, а зачем это надо ?
kolobok0
Цитата(MiklPolikov @ Apr 24 2014, 23:25) *
Объясните пожалуйста на пальцах, что значит "убрать в нитку" и "обслуживать запросы синхронно и асинхронно" ?
..один линейный код в одной задаче ?...


если юзаете ось, то во фриртосе есть понятие поток. вам ничего не мешает отдельно поток завести на ваши медленно играющие проблемы.
асинхронно (по отношению к этому потоку) вы сможете вызывать необходимые вам функции (рядом с потоком лежащие и реализующие
синхонизацию).
Вам никто не мешает порождать, посылать запрос, ждать, по возврату управления удалять объект синхронизации. это есть
синхронное обращение. как пример см. стэки изернет, синхроные натификэшены во всяких форточках и иже...

вам никто не мешает, завести объект синхронизации в вызывающем коде, передать его на вызове и продолжать работу
периодически проверяя обратный натификэшен. как пример реализации см. те же форточки раздел асинхронный доступ
к файлам, портам и т.д., либо в других осях - типа новела, льюникса, юникса и т.д...

про линейный код нифига не понял.
как пример разжовывания на пальцах(да и пользительно под форточками) - почитайте толковую книгу
"WINDOWS для профессионалов" автор Джеффри Рихтер

там есть и асинхронный пласт и синхронный...возможно не по теме но как консерватория - вполне...
juvf
Цитата(kolobok0 @ Apr 25 2014, 00:54) *
в) всю работу с карточкой убрать в нитку. обслуживать запросы можно и синхронно и асинхронно - в зависимости от дальнейшей надобности.

на сколько я понял вопрос в другом. Какая разница что в какой нитке? Допустим есть отдельняя нитка в которой ведется работа с SD Картой. есть функция, инициализирующая SD карту, в ней в каких-то циклах ожидание чего-то.
Как теперь с этим поступить наиболее правильно?
Когда идет инициализация, то процессор простаивает. как правильно организовать работу, чтобы во время ожиданий процессор не простаивал?

если сделать так
while(waitForSdCard);

то процессор будет стоять в этом месте (ну если конечно более приоритетные задачи не прервыт эту задачу).

самое простое сделать ожидание через vTaskDelay();

Код
for(int i = 0; i<100; i++)
{
   if(waitForSdCard)
   {
   //дождались... дальше пишем код
   }
   vTaskDelay(10);
}
//сюда попадем, если недождались. исключение


Если то событие, которое ожидаем, может сегенрировать прерыванеи, то можно сделать двоичный симафор (или эвэнт). из прерывания выдавать симафор. тогда

Цитата
if(xSemaphoreTake(smSdCardReady, 1000) == pdPASS)//ждём симафор
{ //дождались... дальше пишем код

}
else
{
//сюда попадем, если недождались. исключение
}


MiklPolikov
Ещё один вопрос:

Требуется экономить потребляемый ток.
Раньше, без ОС, в тех местах кода, где надо чего-то ждать,я использовал какой-то из спящих режимов, а дождавшись вновь увеличивал частоту.
Сейчас всё ожидание, очевидно, будет в задаче Idle. В ней я могу снизить тактовую частоту. А вот как её обратно повысить ? Я ведь не знаю ни когда это потребуется, ни где программа окажется когда выйдет из IDLE . Как быть ?
kolobok0
Цитата(juvf @ Apr 26 2014, 08:18) *
...Когда идет инициализация, то процессор простаивает. как правильно организовать работу...


Вы вот прочитали но не поняли скорее всего, что я написал выше.
Окейно. по другому..
откуда это у Вас?

"Когда идет инициализация, то процессор простаивает"

я бы сказал заблуждение... Или логику так построили? Ну а кто мешает по другому, религия если только???

вот у меня паралельно идёт инициализация(читай подъём или инициализация) железа...uSD, Ehernet, ADC, стэки, оси, MODBAUS,
запуск ниток, изернет клиенты-сервера, wifi (и прочий звериниц), всё это делается параллельно
(ну есть конечно же последовательные действия), но они не создают узких мест для общей картины а больше, как это лучше
сказать - по общей готовности все подождут самого отстающего...
ну и принимается решения для подключения или отключения функционала блоков или логики...
MiklPolikov
Цитата(Lagman @ Apr 30 2014, 15:27) *

Это то что нужно ! Огромное спасибо !!!

Кое-что непонятно, поясните пожалуйста :
Тут
http://www.freertos.org/low-power-tickless-rtos.html
сказано, что функция portSUPPRESS_TICKS_AND_SLEEP( xIdleTime ) не определена, пользователю предлагается написать её самому , приведён пример возможного кода.
А я вижу в FreeRTOS V8.0.0 что эта функция уже есть написанная, и в ней вызываются функции
configPRE_SLEEP_PROCESSING( xModifiableIdleTime );
configPOST_SLEEP_PROCESSING( xExpectedIdleTime );
которые я должен написать сам.
Вопрос : почему в описании по ссылке сказано, что portSUPPRESS_TICKS_AND_SLEEP нужно писать самому ?
Lagman
Я сильно не вникал т.к. не использую режимы энергосбережения, но из написанного на оф.сайте я понял, что если для процессора есть пример с энергосбережением то можно его использовать или написать свою ф-ю.
MiklPolikov
Может кто подскажет :
Есть задача, которая создаёт несколько других задач, и после этого становится не нужна.
Если в конце задачи в бесконечном цикле vTaskDelay то всё хорошо. А если задача сама себя удаляет vTaskDelete(NULL); , то программа оказывается в Hardfault_Handler. Почему так происходит ? Задачи создаю с проверкой Task_Handle==NULL и запрещением переключения контекста на время проверки и создания.
MiklPolikov
Разобрался, дело было в недостаточном стеке задачи. В vApplicationStackOverflowHook программа не попадала, сразу HardFault.

Ещё один вопрос :
Как сохранить неизменной частоту системных тиков при изменении тактовой частоты процессора ? Никаких готовых инструментов не нашёл. Нужно перенастраивать таймер вручную ? А после этого операционка его обратно не перенастроит сама зачем-нибудь ?
juvf
2MiklPolikov
по существу не скажу. такого опыта не имею.
ps: я смотрю на вопросы... и любопытстов всё больше и больше.... динамическое создание задач, самоудаление задач, налету изменение системного тика....
Что за проект? Что вы делаете?
kostyan
2MiklPolikov, фриртос - это операционка с открытым кодом.

Открыл свой проект, нашел в FreeRTOSConfig.h:
#define configCPU_CLOCK_HZ ( SystemCoreClock )

Сделал поиск по configCPU_CLOCK_HZ в проекте.

Нашел что юзается дефайн в "__weak void vPortSetupTimerInterrupt( void )". Сделал иерархию вызова функции: portBASE_TYPE xPortStartScheduler( void ) <- void vTaskStartScheduler( void )

Следовательно, дефолтные настройки системного таймера применяются ровно один раз в проекте. Если вы хотите менять частоту процессора - то в том же коде перенастаивайте таймер системного тика, и будет вам счастье. Пост писал, гораздо дольше чем залез в код и нашел ответы на ваши вопросы.
MiklPolikov
Цитата(juvf @ May 7 2014, 11:43) *
2MiklPolikov
по существу не скажу. такого опыта не имею.
ps: я смотрю на вопросы... и любопытстов всё больше и больше.... динамическое создание задач, самоудаление задач, налету изменение системного тика....
Что за проект? Что вы делаете?


Например разрабатываю диктофоны, которые производят Телесистемы в Зеленограде.
И другие проекты подобного характера. Иными словами, я делаю "гаджеты".

Цитата(kostyan @ May 7 2014, 16:04) *
2MiklPolikov, фриртос - это операционка с открытым кодом.

Открыл свой проект, нашел в FreeRTOSConfig.h:
#define configCPU_CLOCK_HZ ( SystemCoreClock )

Сделал поиск по configCPU_CLOCK_HZ в проекте.

Нашел что юзается дефайн в "__weak void vPortSetupTimerInterrupt( void )". Сделал иерархию вызова функции: portBASE_TYPE xPortStartScheduler( void ) <- void vTaskStartScheduler( void )

Следовательно, дефолтные настройки системного таймера применяются ровно один раз в проекте. Если вы хотите менять частоту процессора - то в том же коде перенастаивайте таймер системного тика, и будет вам счастье. Пост писал, гораздо дольше чем залез в код и нашел ответы на ваши вопросы.


Да, я то же это находил.
Но подумал, вдруг есть неочевидные для меня тонкости.
MiklPolikov
Коллеги, ещё один вопрос :

Верно ли я понимаю, что значение, которое возвращает xTaskGetTickCount(); периодически сбрасывается в 0 и начинает расти заново, т.к. переполняется 32х разрядная переменная, которая считает тики , и стало быть, при использовании xTaskGetTickCount(); я должен обрабатывать этот сброс в 0 ?
А все функции операционки которые работают со временем (задержка, взять симофор и т.п. ) , то же обрабатывают сброс счётчика тиков в 0 ?

МП
juvf
Цитата(MiklPolikov @ May 27 2014, 19:11) *
переполняется 32х разрядная переменная

32-х битная или 16
Код
#if( configUSE_16_BIT_TICKS == 1 )
    typedef uint16_t TickType_t;
    #define portMAX_DELAY 0xffff
#else
    typedef uint32_t TickType_t;
    #define portMAX_DELAY 0xffffffffUL
#endif


Цитата
стало быть, при использовании xTaskGetTickCount(); я должен обрабатывать этот сброс в 0 ?
а зачем?

Цитата
А все функции операционки которые работают со временем (задержка, взять симофор и т.п. ) , то же обрабатывают сброс счётчика тиков в 0 ?
ээээ.... а это зачем?
зарядили симофор на 100. в счетчик симофора 100. каждый тик из счетчика симофора вычитаем 1. как 0 стал - обработали. вобще счетчик тика тут не причем. (код ос не смотрел, но я бы так сделал)

допустим typedef uint16_t TickType_t;. текущее значение 0xfffe. зафиксировали. прошло 100 тиков. счетчик стал 0х0062. Для вычисления периода времени из нового значения вычитаем старое, т.е. 0х0062 - 0xfffe, для типов uint16_t разница равно 100 dec.

MiklPolikov
juvf, спасибо !
Я всегда работал со временем другим способом, и в нём приходилось проверять, не начался ли счёт с 0

И ещё вопрос. Правильно ли я понимаю работу ОС в целом ? :

В устройстве две SD карты. Задача инициализации написана одна, она создаётся в двух экземплярах, в задачу передаётся параметр № карты.
Задача вызывает какие-то функции с локальными переменными, те то же вызывают функции и т.д.
Правильно ли я понимаю, что при переключении контекста все эти локальные переменные сохраняются в стеке задачи, т.е. физически копируются из одной области памяти в другую ?
Если локальные переменные в функциях определены как static, это не влияет на сохранение в стеке ?
Получается, что на переписывание контекста в стек и обратно уходит много времени, и стало быть надо стремится сокращать количество локальных переменных ? Все большие массивы нужно определять как глобальные переменные, и работать с ними как с ресурсом ?
juvf
я думаю что ос работает не так. есть две задачи. у каждой свой стек. локальные переменные создаются и удаляются в стеке задачи не во время переключения, а во время работы задачи, по мере необходимости.есть указатель на вершину стека. при переключении контекста локальные переменные в каждой задаче ни куда не копируются. копируется только указатель на вершину стека. Т.е. кагбэ ос переключается на др стек. Поэтому от размера стека задачи и от кол-ва локальных переменных время переключение контекста не зависит.
Newegor
Цитата(MiklPolikov @ May 29 2014, 22:50) *
juvf, спасибо !
Я всегда работал со временем другим способом, и в нём приходилось проверять, не начался ли счёт с 0

И ещё вопрос. Правильно ли я понимаю работу ОС в целом ? :

В устройстве две SD карты. Задача инициализации написана одна, она создаётся в двух экземплярах, в задачу передаётся параметр № карты.
Задача вызывает какие-то функции с локальными переменными, те то же вызывают функции и т.д.
Правильно ли я понимаю, что при переключении контекста все эти локальные переменные сохраняются в стеке задачи, т.е. физически копируются из одной области памяти в другую ?
Если локальные переменные в функциях определены как static, это не влияет на сохранение в стеке ?
Получается, что на переписывание контекста в стек и обратно уходит много времени, и стало быть надо стремится сокращать количество локальных переменных ? Все большие массивы нужно определять как глобальные переменные, и работать с ними как с ресурсом ?

По поводу переписывания контекства juvf Вам уже ответил. Контекст не переписывается, а переключается.
А вот использование static, без понимания, я бы не рекомендовал. При создании такой переменной ее экземпляр будет один и тот же на все задачи. И это может привести к печальным последствиям, если это не учитывать.
MiklPolikov
Цитата(Newegor @ May 30 2014, 11:00) *
А вот использование static, без понимания, я бы не рекомендовал. При создании такой переменной ее экземпляр будет один и тот же на все задачи.


Newegor, спасибо за информацию про static !

У меня вот это работает, только если возвращаемая переменная static . А если нет, то функция возвращает 0. Как я понимаю, это потому что существование переменной прекращаеся чуть раньше чем программа вышла из функции, и возвращать оказывается нечего.

Код
char do_something(void)
{
       chatic char result;

        //.................
  
       return result;
}
Lagman
эта функция или прототип функции объявлен до вызова?
msalov
Цитата(MiklPolikov @ May 27 2014, 16:11) *
Коллеги, ещё один вопрос :

Верно ли я понимаю, что значение, которое возвращает xTaskGetTickCount(); периодически сбрасывается в 0 и начинает расти заново, т.к. переполняется 32х разрядная переменная, которая считает тики , и стало быть, при использовании xTaskGetTickCount(); я должен обрабатывать этот сброс в 0 ?
А все функции операционки которые работают со временем (задержка, взять симофор и т.п. ) , то же обрабатывают сброс счётчика тиков в 0 ?

МП


Если ваша задержка меньше разрядности счётчика, то 0 обрабатывать не нужно. Но если больше - обязательно (или разбивать на части).

Пример: пусть счётчик 16-битный. Начальное значение 2, а задержка - 70000 (0x11170). Если взять просто сумму получим 0x11172, из-за переполнения получим в итоге 0x1172, что даст реальную задержку 4464 вместо 70000. Если промахнуться с разрядностью переменной, с которой будет сравниваться счётчик - можно никогда не выйти из цикла ожидания.
juvf
Цитата(MiklPolikov @ May 30 2014, 14:23) *
У меня вот это работает, только если возвращаемая переменная static . А если нет, то функция возвращает 0. Как я понимаю, это потому что существование переменной прекращаеся чуть раньше чем программа вышла из функции, и возвращать оказывается нечего.

Код
char do_something(void)
{
       chatic char result;

        //.................
  
       return result;
}

нет, не так работает си/с++. если резалт не статик, то при покидании функции переменная резалт удалится из стека, но её значение не потеряется а нормально вернётся. может у вас в одной задаче резальт считается и равен 0, в другой задаче резалт неравен нулю. в итоге, когда статик, то оба резалта не равны нулю, а одному значению. а когда не статик, то один экземпляр равен нулю. ..... вобщем это гадание на кофейной гуще. что то не так у вас. попробуйте запустить только одну задачу и проверит статик и нестатик - результат должен быть одинаковый, потом 1-ую задачу выкл, и включить вторую - проверить.....
MiklPolikov
Цитата(juvf @ May 30 2014, 14:09) *
нет, не так работает си/с++. если резалт не статик, то при покидании функции переменная резалт удалится из стека, но её значение не потеряется а нормально вернётся. может у вас в одной задаче резальт считается и равен 0, в другой задаче резалт неравен нулю. в итоге, когда статик, то оба резалта не равны нулю, а одному значению. а когда не статик, то один экземпляр равен нулю. ..... вобщем это гадание на кофейной гуще. что то не так у вас. попробуйте запустить только одну задачу и проверит статик и нестатик - результат должен быть одинаковый, потом 1-ую задачу выкл, и включить вторую - проверить.....


Я даже без ОС в самом простом линейном коде наблюдаю что функция возвращает только 0 если локальная переменная в ней не static.
Lagman
Цитата(MiklPolikov @ May 30 2014, 14:53) *
Я даже без ОС в самом простом линейном коде наблюдаю что функция возвращает только 0 если локальная переменная в ней не static.

http://electronix.ru/forum/index.php?showt...t&p=1259306
MiklPolikov
Цитата(Lagman @ May 30 2014, 13:29) *
эта функция или прототип функции объявлен до вызова?


Это функция.
Lagman
%)
Я знаю что это функция.
juvf
Цитата(MiklPolikov @ May 30 2014, 16:53) *
Я даже без ОС в самом простом линейном коде наблюдаю что функция возвращает только 0 если локальная переменная в ней не static.

даже не чего подсказат. си/с++ не так работает. отправлять вас читать книжки "Учимся писать на СИ" как-то неприлично. может компилятор кривой, может вы что-то путаете.

Как же вообще у вас FreeRTOS работает? например функция создания задач

Код
signed portBASE_TYPE xTaskGenericCreate( pdTASK_CODE pxTaskCode, const signed char * const pcName, unsigned short usStackDepth, void *pvParameters, unsigned portBASE_TYPE uxPriority, xTaskHandle *pxCreatedTask, portSTACK_TYPE *puxStackBuffer, const xMemoryRegion * const xRegions )
{
signed  xReturn;
...
return  xReturn;
}
ни каких статиков. и др функции возвращающие не void без всяких статиков.
AHTOXA
Цитата(MiklPolikov @ May 30 2014, 14:23) *
У меня вот это работает, только если возвращаемая переменная static . А если нет, то функция возвращает 0. Как я понимаю, это потому что существование переменной прекращаеся чуть раньше чем программа вышла из функции, и возвращать оказывается нечего.
Код
char do_something(void)
{
       chatic char result;

        //.................
  
       return result;
}

Так не бывает. Тем более с переменной типа char. Она помещается в регистр, поэтому не может прекратить своё существование.
Попробуйте убрать статик и назначить переменной какое-то значение по умолчанию, типа
Код
char do_something(void)
{
       char result = 123;

        //.................
  
       return result;
}

И посмотрите, что получится. Если функция будет возвращать 123, значит вы просто забыли присвоить значение переменной result:)
MiklPolikov
Цитата(AHTOXA @ May 31 2014, 16:35) *
Так не бывает. Тем более с переменной типа char. Она помещается в регистр, поэтому не может прекратить своё существование.


Спасибо. Моя проблема скорее всего была связана с изменением переменных в прерывании, директива static иногда работала как volatile.

MiklPolikov
Коллеги, доброго времени суток.

Не могу до конца понять как работают программные таймеры.
Что такое "очередь таймера" и в каких случаях она переполняется ?
Вот например, мне нужно, что бы таймер начал считать с 0, а если уже считал то сбросился в 0 и начал с 0.
BaseType_t xTimerReset( TimerHandle_t xTimer, TickType_t xBlockTime );
Делает именно это или что-то другое ?
Что такое xBlockTime , почему про неё сказано , что "это то время, которое задача будет заблокирована, пока команда не запишется в очередь таймера" ? Таймер можно как-нибудь просто сбросить в 0 не блокируя задачу, в которой это делается ?
Xenia
Цитата(MiklPolikov @ Jul 12 2014, 04:58) *
Не могу до конца понять как работают программные таймеры.
Что такое "очередь таймера" и в каких случаях она переполняется ?
Вот например, мне нужно, что бы таймер начал считать с 0, а если уже считал то сбросился в 0 и начал с 0.


Полагаю, что термин "очередь таймера" относится не к аппаратному таймеру, как таковому, а к планировщику задач операционной системы разделенного времени. Т.е. в отсутствие операционной системы у таймеров нет никаких очередей.

Судя по всему, под очередью понимается та задача/процедура, на которую таймер должен переключиться при выходе из своей процедуры прерывания. Т.е. по сути это чисто программная задача, а не аппаратная. Причем, место следующего возврата должно быть определено еще до запуска таймера, поскольку после того, как произойдет по нему прерывание, будет некогда искать того, кто стоит в очереди первым. В прерывании вообще нельзя долго находиться, а уж тем более выяснять там какие-то вопросы, которые обязаны были быть решены заранее.

Изменения в самой очереди, по-видимому, происходят только тогда, когда ставится новая задача или снимается/завершается старая. Т.е. только в этот момент в порядке очередности задач могут произойти какие-то изменения, тогда как задача таймера - чистое переключение.

В общем случае каких-то стандартов тут нет, т.к. авторы операционной системы вольны создать планировщик задач исключительно по своему вкусу, в том числе и вводить для его описания свои термины. Говорят, что когда-то номер/адрес следующего задания хранили прямо в самом таймере, используя его старшие разряды, которые обычно не используются. Но с тех пор и таймеры стали другими, и задачи стали сложнее, а потому нынче задачи обычно переключают по таблице, малость смахивающую на таблицу прерываний. Что-то более определенное сказать не могу, т.к. свою операционную системы вы не назвали. Хотя, судя по названию процедуры BaseType_t xTimerReset, у вас FreeRTOS.
juvf
Цитата(Xenia @ Jul 12 2014, 19:32) *
Судя по всему, под очередью понимается та задача/процедура, на которую таймер должен переключиться при выходе из своей процедуры прерывания. Т.е. по сути это чисто программная задача, а не аппаратная. Причем, место следующего возврата должно быть определено еще до запуска таймера, поскольку после того, как произойдет по нему прерывание, будет некогда искать того, кто стоит в очереди первым. В прерывании вообще нельзя долго находиться, а уж тем более выяснять там какие-то вопросы, которые обязаны были быть решены заранее.
мимо laughing.gif
не нужны ни какие места возврата.

Цитата
Не могу до конца понять как работают программные таймеры.
Открываем журнал КиТ №10 2011, страница 93. Читаем....

Цитата
Что такое "очередь таймера" и в каких случаях она переполняется ?

Очередь команд таймеров
Для совершения операций запуска, оста-
нова, сброса, изменения периода и удале-
ния таймеров во FreeRTOS предоставляется
набор API-функций, которые могут вызы-
ваться из задач и обработчиков прерываний,
а также из функций таймеров. Вызов этих
API-функций не воздействует напрямую
на задачу обслуживания таймеров. Вместо
этого он приводит к записи команды в оче-
редь, которую в дальнейшем мы будем на-
зывать очередью команд таймеров. Задача
обслуживания таймеров считывает команды
из очереди и выполняет их.

....
conf igTIMER_QUEUE_LENGTH. Размер
очереди команд — устанавливает макси-
мальное число невыполненных команд,
которые могут храниться в очереди, пре-
жде чем задача обслуживания таймеров их
выполнит.



Цитата
Что такое xBlockTime
смотрим там же...
xBlockTime — определяет время тайм-
аута — максимальное время нахождения
вызывающей xTimerChangePeriod() задачи
в блокированном состоянии, если очередь
команд полностью заполнена и нет воз-
можности поместить в нее команду об из-
менении периода таймера.

У вас очередь 5 команд. вызвали из других задач 5 разных команд. Потом из текущей вызываем xTimerChangePeriod(). Что должно произойти? Функция xTimerChangePeriod должна поместить в очередь таймера новую команду изменения периода, но очередь заполнина. Что делать? Текущая задача переходит в блокированное состояние на время xBlockTime или до тех пор, пока в очереди не появиться свободное место.


Цитата
Вот например, мне нужно, что бы таймер начал считать с 0, а если уже считал то сбросился в 0 и начал с 0.
BaseType_t xTimerReset( TimerHandle_t xTimer, TickType_t xBlockTime );
Делает именно это или что-то другое ?
там же, в ките, всёже на русском и могучем...
Сброс таймера
Сброс таймера осуществляется с помощью
API-функции xTimerReset(). Ее прототип:
portBASE_TYPE xTimerReset( xTimerHandle xTimer, portTickType
xBlockTime );
...
Операция сброса может применяться как
к активному таймеру, так и к находящему-
ся в пассивном состоянии. В случае если
таймер находился в пассивном состоянии,
вызов xTimerReset() будет эквивалентен вы-
зову xTimerStart(), то есть таймер будет за-
пущен. Если таймер уже отсчитывал время
в момент вызова xTimerReset() (то есть на-
ходился в активном состоянии), то вызов
xTimerReset() приведет к тому, что таймер
заново начнет отсчет времени с момента вы-
зова xTimerReset().



Цитата
Таймер можно как-нибудь просто сбросить в 0 не блокируя задачу, в которой это делается ?

Скорее нельзя. ..... ээээ.... напрямую нет, или да.... вобщем сброс таймера - это запись команды сброса таймера в очередь таймеров. Если у вас 1 таймер... пара мест вызова API для таймера, в которые вы попадаете раз в год и очередь таймера 100 команд, то с вероятностью близкой к 1.0 ваша задача не будет блокирована вызовом xTimerReset(). Если у вас 100 таймеров, 1000 мест вызова API для таймеров... и/или вы ограниченны в длине очереди команд таймера, то можно сделать какойнить финт... типа: сделать задачу сброса таймера. эта задача будет ждать флага/эвента. Основная задача выставляет флаг/запускает эвент сброса таймера и работает дальше, а задача сброса таймера вызывает xTimerReset(). Если очередь таймера полна, то задача сброса таймера блокируется, а основная задача работает. Задача сброса должна быть приоритетом выше.
MiklPolikov
Цитата(juvf @ Dec 23 2013, 21:33) *
Про зачистку памяти.....

Ту память, которую занимала прибитая задача, зачистит idle. А ту память которую выделили задаче до создания задачи, нужно руками зачищать.

например death.c
Код
void vCreateSuicidalTasks( unsigned portBASE_TYPE uxPriority )
{
unsigned portBASE_TYPE *puxPriority;

        /* Create the Creator tasks - passing in as a parameter the priority at which
        the suicidal tasks should be created. */
        puxPriority = ( unsigned portBASE_TYPE * ) pvPortMalloc( sizeof( unsigned portBASE_TYPE ) );
        *puxPriority = uxPriority;

        xTaskCreate( vCreateTasks, "CREATOR", deathSTACK_SIZE, ( void * ) puxPriority, uxPriority, NULL );

        /* Record the number of tasks that are running now so we know if any of the
        suicidal tasks have failed to be killed. */
        uxTasksRunningAtStart = uxTaskGetNumberOfTasks();
}

Если задача vCreateTasks сама себя удалит, или её удалит кто-то другой, то память, веделенная вызовом pvPortMalloc не освободится. Нужно позаботится об её освобождении. Поэтому в задаче vCreateTasks делается ручная зачистка

Код
unsigned portBASE_TYPE uxPriority; //создается новая переменная на стеке
...

        uxPriority = *( unsigned portBASE_TYPE * ) pvParameters; //копируется данные из динамической выделенной памяти pvParameters в uxPriority
        vPortFree( pvParameters ); //удаляется динамически выделенная память.


Помогите пожалуйста разобраться с vPortFree.
Вот допустим, я удаляю задачу.
Что делать дальше ? Нужно передать в vPortFree в качестве параметра хендлер этой задачи, и тогда память, которую занимала задача, освободится ?
А если задача удаляет саму себя, перед этим присваивая значение NULL хэндлеру ?
Можно ли перед этим, прямо внутри задачи, запустить vPortFree ?
И как после этого задача продолжит работать , т.е. выполнит два последних действия
v_Task_Handle=NULL;
vTaskDelete(NULL);
если у задачи уже нет никакой памяти, т.е. в эту память может записаться что угодно ?
DASM
Читаю все это и волосы дыбом. Тем более что и работаю с этим. Почему программист должен думать об освобождении памяти? Почему многопоточность не поддерживается средствами языка? Почему до сих пор все сидят на древних языках вроде С и С++ (он недалеко ушел от С, пусть и поддерживает ООП, но все равно с ним обрушить любую систему на ура можно. Есть ли нормальные реализации Явы или С шарп для контроллеров? Иначе это хождение по граблям будет вечным. 15 лет в теме и все одно и тоже. И памяти то уже достаточно для Явы например, и все равно. От слов «указатель» и «приведение типов» тошнит уже в век, когда объемы флеш и озу - ничто, а время на выпуск - все, это анахронизм какой то
MiklPolikov
Цитата(DASM @ Jul 17 2014, 20:10) *
Читаю все это и волосы дыбом. Тем более что и работаю с этим. Почему программист должен думать об освобождении памяти? Почему многопоточность не поддерживается средствами языка? Почему до сих пор все сидят на древних языках вроде С и С++ (он недалеко ушел от С, пусть и поддерживает ООП, но все равно с ним обрушить любую систему на ура можно. Есть ли нормальные реализации Явы или С шарп для контроллеров? Иначе это хождение по граблям будет вечным. 15 лет в теме и все одно и тоже. И памяти то уже достаточно для Явы например, и все равно. От слов «указатель» и «приведение типов» тошнит уже в век, когда объемы флеш и озу - ничто, а время на выпуск - все, это анахронизм какой то


Если бы озу было "ничто", то я бы вообще не делал динамическое создание/удаление задач.
Если Вы знаете как надо, то скажите основные ключевые слова.
Есть проц STM32L151 . Выбран как самый малопотребляющий, т.е. ни на что более мощное перейти нельзя.
DASM
Если бы я знал «как надо» то не сидел бы тут… увы я знаю только как не надо. Сколько у меня было этих «плавающих» указателей, сколько геммора с потоками (не надо говорить, что все просто, одна инверсия приоритетов чего стоит. В итоге над основной идеей подумать времени мало.
Lagman
ключевые слова malloc, free и их реализация в порте FreeRTOS для нужного процессора. http://microsin.ru/content/view/1308/44/
DASM
Кому они ключевые ? Да хоть new, хоть malloc - суть одна - любой залетевший дятел разрушит все. Посмотрите примеры программ на Java - там нет этого дебилизма. С++ позволит даже такое *(int *)0x40001234 = 0; На Яве вам никто не позволит пользоваться указателями, оных и нету, и никто не позволит приводить типы с уменьшением точности. С++ - это очень старый язык, он неплох для своих лет, но уже 2014 на дворе. Тот же ассемблер завуалированный.
juvf
Цитата(MiklPolikov @ Jul 17 2014, 19:17) *
Помогите пожалуйста разобраться с vPortFree.
Вот допустим, я удаляю задачу.
Что делать дальше ?
Во первых вы должны понимать что такое динамическое выделение памяти и для чего оно нужно. как работает стек и куча. В 2-х словах не объяснить.

Цитата
Нужно передать в vPortFree в качестве параметра хендлер этой задачи
ненужно.

вы знаете как работают функции malloc() и free()? Для чего они нужны? Как работают операторы new и delete? Если знаете, то не должно возникнуть вопросов по vPortFree. vPortFree - работает аналогично. Если не знаете или плохо знаете, лучше не заморачивайтесь и работайте на стеке, т.е. без vPortFree pvPortMalloc, иначе выстрел в ногу гарантирован. Зачем вам динамическая память? Если нужны динамические задачи - делайте динамические задачи. Но зачем в динамических задачах использовать динамическую память?

Цитата
Можно ли перед этим, прямо внутри задачи, запустить vPortFree ?
И как после этого задача продолжит работать , т.е. выполнит два последних действия
v_Task_Handle=NULL;
vTaskDelete(NULL);


Ещё раз....
1) выделяем в КУЧЕ 100 байт
void *p = pvPortMalloc( 100 );

2)создадим задачу и передаем в неё в качестве параметра указатель на выделенный блок памяти в куче.
xTaskCreate( myTask, "Leningrad", 30, p, 5, NULL ); - создали задачу myTask, присвоили ей имя Leningrad, размер стека 30( байт или чего-то там, см доки, для стм32 вроде 30*4), приоритет задачи 5. Вот здесь выделяется для нужд задачи 120 байт (30*4) - это стек задачи. Это от дельная память от блока в 100 байт.

3)внутри задачи удаляем задачу vTaskDelete(). Задача остановиться и прекратит работать. Но 120 байт стека и 100 байт в куче не освободятся.

4)Происходит вызов idle. idle высвобождает 120 байт стека задачи.

Но 100 байт выделеных с помощью pvPortMalloc ни кто не зачистит. Более того ни кто не знает - нужно ли эту память зачищать? может далее по алгоримту ваша программа будет работать так

5)создадим другую задачу и передадим в неё в качестве параметра указатель на выделенный блок памяти в куче. В этом блоке нужная информация
xTaskCreate( yourTask, "Moskow", 50, p, 4, NULL ); и более того может быть 100 байт использоваться сразу в 10 задачах. одну задачу удалили- но остальные задачи пользуют эту память.

Если у вас блок в 100 байт использует всего 1 задача и после удаления эти данные ненужны, то руками удалите pvPortFree(). Если удаляете внутри задачи, то перед vTaskDelete()
Код
//полезный код задачи использующий эти 100 байт
pvPortFree(*vParam);//высвобождение памяти выделенной в куче, но не высвобождение памяти стека, т.е. 120 байт продлолжают использоваться
//возможно ещё какойто полезный код, но здесь уже нельзя использовать эти 100 байт
vTaskDelete(NULL);
}
ну вот как-то так.

ps если у вас сценарий, как в последнем моём примере, то зачем вам вообще динамика? пишите в статике, будет вам автоматическая зачистка
Код
void myTask(void *context)
{
uint8_t array[100]; //выделение 100 байт на СТЕКЕ задачи
//полезный код
vTaskDelete(NULL);
}
//создаем задачу
xTaskCreate( myTask, "Leningrad", 30 + 25, 0, 5, NULL );// создали задачу и выделили под стек на 100 байт больше
При таком написании поле удаления задачи idle автоматически зачистит стек задачи? т.е. 120+100 байт, а куча не используется.
DASM
Цитата(juvf @ Jul 17 2014, 23:30) *
Более того ни кто не знает - нужно ли эту память зачищать?

Если на нее никто не ссылается - сборщик мусора освободит ее. Если среда выполнения поддерживает это. Программист менее всего должен думать КОГДА освободить память. По-сути в нормальной серьезной программе с асинхронными обработчиками он даже и не может этого знать. Отсюда все эти Unhandled exception - а в области MCU - просто hard fault (и то если это Кортекс итп, а обычно просто крик в форуме "виснет, помогите"
MiklPolikov
Цитата(juvf @ Jul 17 2014, 23:30) *
ps если у вас сценарий, как в последнем моём примере, то зачем вам вообще динамика? пишите в статике, будет вам автоматическая зачистка[code]void myTask(void *context)


Видимо я плохо объяснил.
Речь не о памяти, занятой при выполнении задачи. Речь о стеке самой задачи. После удаления задачи память освобождается не сразу, а только в задаче idle . Если я сразу после удаления создаю новую задачу , а программа между этими двумя действиями не попадает в Idle task , то памяти может не хватить. Вопрос : как освободить память менее криво, чем вызывать между удалением и созданием vTaskDeleay ? Ну неужели не предусмотрено простого способа ?
juvf
Цитата(MiklPolikov @ Jul 18 2014, 01:47) *
Видимо я плохо объяснил.
Речь не о памяти, занятой при выполнении задачи. Речь о стеке самой задачи. После удаления задачи память освобождается не сразу, а только в задаче idle . Если я сразу после удаления создаю новую задачу , а программа между этими двумя действиями не попадает в Idle task , то памяти может не хватить. Вопрос : как освободить память менее криво, чем вызывать между удалением и созданием vTaskDeleay? Ну неужели не предусмотрено простого способа ?

хороший вопрос. теоретически можно 100 раз создать задачу и 100 раз удалить, и при этом не разу не попав в idle.
MiklPolikov
Цитата(juvf @ Jul 18 2014, 00:09) *
хороший вопрос. теоретически можно 100 раз создать задачу и 100 раз удалить, и при этом не разу не попав в idle.

Вы начали меня понимать !
Lagman
Цитата(DASM @ Jul 17 2014, 23:26) *
Кому они ключевые ? Да хоть new, хоть malloc - суть одна - любой залетевший дятел разрушит все. Посмотрите примеры программ на Java - там нет этого дебилизма. С++ позволит даже такое *(int *)0x40001234 = 0; На Яве вам никто не позволит пользоваться указателями, оных и нету, и никто не позволит приводить типы с уменьшением точности. С++ - это очень старый язык, он неплох для своих лет, но уже 2014 на дворе. Тот же ассемблер завуалированный.

Пользуйте BASIC и не будете так нервничать sm.gif

Цитата(DASM @ Jul 17 2014, 23:39) *
Программист менее всего должен думать КОГДА освободить память. По-сути в нормальной серьезной программе с асинхронными обработчиками он даже и не может этого знать.

Вот к чему мир катится, программисты превращаются в кодеров, которым не надо будет думать sm.gif и программы с миганием светодиодов для микроконтроллеров будут весить под несколько гигабайт sm.gif
juvf
Цитата(DASM @ Jul 18 2014, 01:39) *
Если на нее никто не ссылается - сборщик мусора освободит ее. Если среда выполнения поддерживает это. Программист менее всего должен думать КОГДА освободить память. По-сути в нормальной серьезной программе с асинхронными обработчиками он даже и не может этого знать. Отсюда все эти Unhandled exception - а в области MCU - просто hard fault (и то если это Кортекс итп, а обычно просто крик в форуме "виснет, помогите"

в мэтро может и не должен знать. а в реалтайм - не то что должен - ОБЯЗАН знать. Прогер должен занать, что вот в этом месте код исполняется 100 тактов, и что никакие сборщики мусора его не прервут.

так то это очередной вброс говна в вентилятор на тему c++ vs java. а ветка про FreeRTOS. Предлагаю дальнейшее обсуждение языков для мк перенести в более подходящее место и не засорять эту тему.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.