|
Несколько вопросов начинающего |
|
|
|
 |
Ответов
(1 - 99)
|
Nov 17 2013, 23:54
|

Гуру
     
Группа: Свой
Сообщений: 2 015
Регистрация: 23-01-07
Из: Москва
Пользователь №: 24 702

|
Вопрос 3: Почему 2 задачи работают, а если запускаю 3 то не работает ничего ? Использую heap_2 Где взять файл Errors.h , в котором должны быть коды ошибок возвращаемые xTaskCreate ? Код #define configUSE_PREEMPTION 1 #define configUSE_IDLE_HOOK 0 #define configUSE_TICK_HOOK 0 #define configCPU_CLOCK_HZ ( ( unsigned long ) 16000000 ) #define configTICK_RATE_HZ ( ( portTickType ) 1000 ) #define configMAX_PRIORITIES ( ( unsigned portBASE_TYPE ) 5 ) #define configMINIMAL_STACK_SIZE ( ( unsigned short ) 128 ) #define configTOTAL_HEAP_SIZE ( ( size_t ) ( 17*128) ) #define configMAX_TASK_NAME_LEN ( 16 ) #define configUSE_TRACE_FACILITY 0 #define configUSE_16_BIT_TICKS 0 #define configIDLE_SHOULD_YIELD 1
/////////
void Task1 (void *pvParameters) { static char x; while(1) { x++; } }
void Task2 (void *pvParameters) { static char x; while(1) { x++; } }
void Task3 (void *pvParameters) { static char x; while(1) { x++; } }
int main() { xTaskCreate(Task1,(signed char*)"Task1", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY + 1, NULL); xTaskCreate(Task2,(signed char*)"Task2", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY + 1, NULL); xTaskCreate(Task3,(signed char*)"Task3", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY + 1, NULL); vTaskStartScheduler();
}
--------------------
Если у Вас нет практического опыта в данной теме- не вступайте в дискуссию и не пишите никаких теоретических рассуждений! Заранее спасибо !
|
|
|
|
|
Nov 18 2013, 19:32
|
Знающий
   
Группа: Свой
Сообщений: 875
Регистрация: 28-10-05
Пользователь №: 10 245

|
Цитата(MiklPolikov @ Nov 17 2013, 01:35)  Вопрос 2 :
Есть USB библиотека. К ней я обращаюсь при помощи всего трёх функций USB_INIT(), USB_RECEIVE(char *p_data), USB_TRANSMIT(char *p_data); Переписывать всю библиотеку под операционку разумеется желания нет. Как правильнее всего применить эту библиотеку в проекте, где я решил использовать freeRTOS ? Будет ли правильно просто вставить эти функции в какие-то задачи, чтоб они там вызывались ? Мой вопрос не "будет ли работать ?" а "как вообще это надо сделать по всем правилам ?" Можно прям так и использовать, только преимуществ от rtos вы не получите. Обрамляете вызовы своих функций (порт USB наверно один) в семафоры или мутексы, чтобы не было двойных вызов (хотя в вытесняющем режиме этого может и не произойти) и обращений к одному железу. В №3 надо попробовать увеличить configTOTAL_HEAP_SIZE. В №4 http://microsin.ru/content/view/1309/44/ по умолчанию никому не надо.
|
|
|
|
|
Nov 18 2013, 20:41
|

Гуру
     
Группа: Свой
Сообщений: 2 015
Регистрация: 23-01-07
Из: Москва
Пользователь №: 24 702

|
Цитата(Lagman @ Nov 18 2013, 23:32)  Можно прям так и использовать, только преимуществ от rtos вы не получите. Обрамляете вызовы своих функций (порт USB наверно один) в семафоры или мутексы, чтобы не было двойных вызов (хотя в вытесняющем режиме этого может и не произойти) и обращений к одному железу. Спасибо. Преимущества получу. У меня же не одна USB задача , и работа с USB занимает малую часть все логики программы. С вопросом 3 разобрался сам. Не хватает размера кучи. #define configMINIMAL_STACK_SIZE ( ( unsigned short ) 128 ) означает стек глубиной 128 4х байтных слов, т.к. процессор 32х разрядный. А #define configTOTAL_HEAP_SIZE ( ( size_t ) ( 17*128) ) означает размер кучи всего 17 * 128 = 2176 байт. Т.е. хватит на 4 задачи, 2 из которых это задача таймера(точно не знаю, по-моему она создаётся после запуска шедуллера и сразу удаляется) и задача бездействия. Вопрос 5: Я правильно понимаю, что при создании каждой задачи правильнее указывать какой-то определённый размер стека, который на самом деле нужен, а не одно и то же значение configMINIMAL_STACK_SIZE ?
--------------------
Если у Вас нет практического опыта в данной теме- не вступайте в дискуссию и не пишите никаких теоретических рассуждений! Заранее спасибо !
|
|
|
|
|
Nov 18 2013, 21:28
|
Знающий
   
Группа: Свой
Сообщений: 875
Регистрация: 28-10-05
Пользователь №: 10 245

|
Цитата(MiklPolikov @ Nov 19 2013, 00:41)  Спасибо. Преимущества получу. У меня же не одна USB задача , и работа с USB занимает малую часть все логики программы.
Вопрос 5: Я правильно понимаю, что при создании каждой задачи правильнее указывать какой-то определённый размер стека, который на самом деле нужен, а не одно и то же значение configMINIMAL_STACK_SIZE ? Высокоприоритетные задачи не дадут выполняться менее приоритетным, и когда высокоприоритетные "простаивают" (без оптимизации) ожидание в цикле то все остальные тоже ждут, а если оптимизировать и сказать например vTaskDelay то выполняться будет менее приоритетная задача. http://microsin.net/programming/ARM/freertos-part1.htmlЦитата Каждая задача имеет собственное уникальное хранилище состояния, выделенное ядром при создании задачи. Значение параметра usStackDepth говорит ядру, какой величины стек необходимо создать.
Значение usStackDepth указывает количество слов, которое можно сохранить в стеке, а не количество байт. Например, если стек имеет ширину 32 бита, и переданное значение usStackDepth равно 100, то под стек будет выделено 400 байт (100 * 4 байт). Глубина стека, умноженная на его ширину, не должна превышать максимальное значение, которое может содержать переменная типа size_t.
Размер стека, используемого для задачи ожидания (idle task, об этой задаче подробнее говорится далее), задается константой configMINIMAL_STACK_SIZE. Значение, назначенное этой константе в демо-приложении FreeRTOS (для определенной архитектуры микроконтроллера) может быть использовано как минимально рекомендованное для любой задачи. Если Ваша программа использует пространство в стеке, то нужно указать для константы configMINIMAL_STACK_SIZE увеличенное значение.
Нет простого способа узнать, какого размера стек нужен для задачи. Этот размер можно вычислить, но в большинстве случаев можно просто назначить подходящее значение, подобранное опытным путем, либо взятое приблизительно. Подобрать правильный размер стека важно, чтобы обеспечить адекватное использование RAM без ненужных затрат. Часть 6 содержит информацию о том, как запросить размер стека, используемого задачей.
|
|
|
|
|
Nov 21 2013, 16:49
|
практикующий тех. волшебник
    
Группа: Участник
Сообщений: 1 190
Регистрация: 9-09-05
Пользователь №: 8 417

|
Цитата(MiklPolikov @ Nov 21 2013, 15:47)  ...Более изящного пути нет ? не знаю как на счёт изяществ, но... в серверном мире(как пример) просматриваются следующие модели: 1) когда логика отрабатывает по запросам пользователя. Этот вариант смахивает на Ваш. У Вас пользователь = это обращение к карточке. 2) когда есть поток(и) обрабатывающие запросы от любых пользователей к определённым ресурсам. 3) смешенная. 1 вариант не плохо применять в разрезе секьюрности(можно потоку(ам) наследовать уровень доступа самого залогиневшегося пользователя). минусы - вы тратите доп. ресурсы на подъём и порождения необходимых дочерних потоков, если такие требуются. слабая диспетчеризация доступа к ресурсам и т.п.. 2 вариант просче масштабировать от нагрузке. можно это делать на автоматике даже. при этом можно время подготовки выделяемых ресурсов убрать в фоновый режим. минус - вы должны не забывать об уровне прав и отношений в системе пользователя к устройствам и операциям. возвращаясь к вопросу. кмк можно породить необходимое кол-во потоков для обработки ваших нужд, и передавать в поток конкретную очередь команд обращений к данному девайсу. При этом, если задач нет - потоки ожидают на семафорах(либо других элементах синхронизации). При поступлении задачи - необходимый(ые) потоки просыпаются, делают работу и опять уходят на ожидание. ЗЫ Пример: на одной из серверных осей(НЕ форточки), разграничение доступа к БД было на уровне потоков. Доступ к БД, по условию задачи, возможен был только со стороны сервера. Обращение к БД было инкапсулировано в один поток. Код обращения к БД резко сократился - механизмы транзакций(сервер считался защищён с точки зрения отказов железа) и блокировки не использовались. Быстродействие повысилось. Т.к. читала и писала одна и та-же "правая рука", то целостность базы была обеспечена априори. Т.е. на лету можно было делать бэкапы в фоновом режиме, заливку данных, сжатие данных, печать любых отчётов за 0 минут 0 секунд.
Сообщение отредактировал kolobok0 - Nov 21 2013, 16:57
|
|
|
|
|
Dec 9 2013, 03:15
|

Гуру
     
Группа: Свой
Сообщений: 2 015
Регистрация: 23-01-07
Из: Москва
Пользователь №: 24 702

|
Ещё вопрос, №7
Правильно ли я понимаю, что любой переход задачи в блокированное состояние, будь то вызов vTaskDelay() , попытка взять симофор, взять элемент из пустой очереди и т.п. эквивалентен форсированному переключению контекста ? Иными словами, Если у меня во всех задачах либо форсированное переключение контекста, либо какие угодно переводы задачи в блокированное состояние, то я могу быть уверен в том что моя программа "крутится" с максимально возможной скоростью при данной частоте процессора, и системный квант времени фактически ни на что не влияет ?
--------------------
Если у Вас нет практического опыта в данной теме- не вступайте в дискуссию и не пишите никаких теоретических рассуждений! Заранее спасибо !
|
|
|
|
|
Dec 9 2013, 22:23
|
практикующий тех. волшебник
    
Группа: Участник
Сообщений: 1 190
Регистрация: 9-09-05
Пользователь №: 8 417

|
Цитата(MiklPolikov @ Dec 9 2013, 07:15)  ...что любой переход задачи...Если у меня во всех задачах либо форсированное переключение ..либо ..переводы задачи в блокированное состояние..уверен в том что .."крутится" с максимально возможной скоростью при данной частоте процессора, и системный квант времени .. ни на что не влияет ? т.к. фриртос вытесняющая, если мне не изменяет память по поводу потрохов, то да. При обращении к ядру оси по делам диспетчиризации, будет произведён анализ на предмет изменения статуса данного потока и если есть более приоритетные по условиям, то произойдёт переключения на следующий в очереди ожидания поток. я так понимаешь, что не было попытки заглянуть внутрь оси и разобраться  самое лучшее именно та ки поступить... по поводу максимально возможного - тут всё верно, но немножко оговорочка: теоретически можно поставить колом и даннй механизм, который будет конечно же дышать, но будет бОльшее выполнение кол-во кода при одном и том же конечном функционале. Но думаю 1) накладные расходы (по сравнению с полезным выполнением, будут минимальны) 2) вопрос спускается к устройству оси. И если Вы ей "доверяете" - то оставте это дело ей. Если нет - переписывайте, либо изучайте вопрос уже более глубже(сравнивая оси, выбирая и корректируя на более оптимальный олгаритм шедуллер и иже). 3) ИМХО - достаточно при написании кода относится к оси почти как к НЕ вытесняющей. Т.е. помнить о шедуллере и писать код менее "жадным" к выполнению. Т.е. там где нет необходимости постоянно поллить - перейти на прерывания (идеально чтоб всё было на прерываниях. от аппаратуры и при передачи самих данных.) По поводу таймера: Рекомендую посчитать в тактах МК время кванта тиканья системного таймера. если у Вас всё по умолчанию, тиканье с частотой 1ms и частота ядра 168Мгц, то на один квант приходится около 168000 тактов МК. Что более чем достаточно для многих задач, с "бесконечными циклами выполняющихся за 10 секунд"  т.е. вероятность того, что Вы получите прерывание потока именно таким способом сводится к минимуму, по большому счёту... хотя зависит от задач
Сообщение отредактировал kolobok0 - Dec 9 2013, 22:26
|
|
|
|
|
Dec 11 2013, 04:28
|

Профессионал
    
Группа: Свой
Сообщений: 1 261
Регистрация: 14-05-09
Из: Челябинск
Пользователь №: 49 045

|
Цитата(MiklPolikov @ Dec 9 2013, 09:15)  Правильно ли я понимаю, что любой переход задачи в блокированное состояние, будь то вызов vTaskDelay() , попытка взять симофор, взять элемент из пустой очереди и т.п. эквивалентен форсированному переключению контекста ? Нет ни какого форсированного переключения контекста. Есть переключение контекста. При вызове vTaskDelay() ( или попытка взять семафор, взять элемент из пустой очереди и т.п.) планировщик проверит нет ли менее приоритетных задач, готовых к выполнению. Если есть, то будет обычное переключение контекста на др. задачу. Если нет задач, готовых к выполнению, то произойдет переключение контекста на пустую(фоновую) задачу (idle task). Пустую задачу можно определить самому. Цитата то я могу быть уверен в том что моя программа "крутится" с максимально возможной скоростью при данной частоте процессора, и системный квант времени фактически ни на что не влияет ? Системный квант влияет... чем меньше квант, тем чаще вызывается планировщик. я так понял что вы беспокоитесь о том, что переключение контекста может происходить только при взове планировщика во время системного кванта. Да... во FreeRTOS так и делается. Допустим системный квант будет 1 раз в сек. При вызове vTaskDelay() переключение контекста произойдет сразуже, не дожидпясь ситемного тика (конца секунды). При попытке захватить семафор.... если семафор занят.... то сразу будет вызван планировщик, т.е. сразу произойдет переключение контекста. Т.е. если пренебречь временем обработки прерывания системного кванта, то системный квант времени фактически ни на что не влияет. НО! Есть маленький нюанс: Допустим у вас 2 полезные задачи. обе заблокированны. одна ждёт семафор1, другая семафор2. Выполняется idle задача. Если семафор1 выдается в прерывании по приходу, например байта по УАРТ, то в обработчике прерывания УАРТ нужно руками прописывать переключение контекста. см. portEND_SWITCHING_ISR(). Если этого не сделать, то по приходу байта будет выдан семафор, но переключения контекста с задачи idle на задачу 1 не произойдет. Переключение контекста случится по системному тику (в конце секунды). Вот в таком случает системный квант будет влиять на скорость работы программы. ps почитайте http://kit-e.ru/assets/listalka/Kurniz/Kurniz.pdf там все азы и буки по фриртос да и вообще по ртос, всё разжованно и по полочкам.
|
|
|
|
|
Dec 23 2013, 10:38
|

Гуру
     
Группа: Свой
Сообщений: 2 015
Регистрация: 23-01-07
Из: Москва
Пользователь №: 24 702

|
Вопрос про удаление задач. Как это организовать правильно, или правильно ли я вообще подхожу к созданию алгоритма ? Есть 3 задачи v_Task1, Vtask2, Vtask3. В любой момент времени может потребоваться создать любую задачу , или может потребоваться любую удалить. Если задача создаётся, то нужно во-первых быть уверенным что она уже не создана(а что будет если создать заново той же самой командой ?), а во-вторых удалить две другие задачи. Делаю так : В начале задачи v_Task1 пишу Код if(v_Task2_Handle!=NULL) vTaskDelete(&v_Task2_Handle); if(v_Task3_Handle!=NULL) vTaskDelete(&v_Task3_Handle); аналогично в остальных задачах. Но вот беда : если переключение контекста произойдёт после проверки условия v_Task2_Handle ! = NULL , задача v_Task2 где-то удалится, а потом программа вернётся в Task1 и снова попытается удалить уже удалённую задачу, то Task1 удалит сама себя, т.к. v_Task2_Handle уже == NUL Задачи хочу именно удалять для экономии стека. да и запускать их надо каждый раз с начала. Вопрос: как это сделать по-человечески ?
--------------------
Если у Вас нет практического опыта в данной теме- не вступайте в дискуссию и не пишите никаких теоретических рассуждений! Заранее спасибо !
|
|
|
|
|
Dec 23 2013, 16:00
|

Гуру
     
Группа: Свой
Сообщений: 2 015
Регистрация: 23-01-07
Из: Москва
Пользователь №: 24 702

|
juvf, спасибо ! У меня ещё вопрос . В документации пишут, что vTaskDelay не освобождает память. занятую задачей память нужно освободить как-то вручную, до вызова vTaskDelay. За примером отсылают к death.c https://code.google.com/p/freertos-atmega32...ull/death.c?r=2Смотрю на код, и не понимаю, где там освобождается память ? По-моему просто вызывается vTaskDelay. И вообще, как можно освободить память задачи, которая ещё не удалена ? Ведь если не удалена, значит ещё работает .
--------------------
Если у Вас нет практического опыта в данной теме- не вступайте в дискуссию и не пишите никаких теоретических рассуждений! Заранее спасибо !
|
|
|
|
|
Dec 23 2013, 17:33
|

Профессионал
    
Группа: Свой
Сообщений: 1 261
Регистрация: 14-05-09
Из: Челябинск
Пользователь №: 49 045

|
не путай vTaskDelay и vTaskDelete. vTaskDelay - не удаляет задачу, а задерживает. Про зачистку памяти..... Цитата Замечание: idle задача ответственна за освобождение выделенной памяти задач, которые были удалены. Поэтому важно, чтобы idle задача имела микроконтроллерное время на работу, если ваше приложение делает какие-нибудь вызовы vTaskDelete (). Память, выделенная коду задачи автоматически не освобождается, и должна быть освобождена прежде, чем задача будет удалена. Ту память, которую занимала прибитая задача, зачистит 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 ); //удаляется динамически выделенная память.
|
|
|
|
|
Dec 24 2013, 02:29
|

Гуру
     
Группа: Свой
Сообщений: 2 015
Регистрация: 23-01-07
Из: Москва
Пользователь №: 24 702

|
juvf, огромное спасибо !!! Наблюдения : Разбирался с переполнением стека. vApplicationStackOverflowHook иногда работает, иногда нет. А если вставить вот такую функцию-заглушку перед каждым созданием новой задачи, она даст 100% верный результат. vTaskDelay(1); нужен для того что бы запустить Idle Task которая память освободит если этого ещё не случилось после удаления задач. В худшем случае программа просто зацыклится внутри этой функции, и я буду точно знать в какой момент память кончилась. Код //функция- костыль ////////////////////////////////////// void CHECK_FREE_MEMORY(void) { xxx=xPortGetFreeHeapSize(); while(xxx<256) { xxx=xPortGetFreeHeapSize(); vTaskDelay(1); } }
--------------------
Если у Вас нет практического опыта в данной теме- не вступайте в дискуссию и не пишите никаких теоретических рассуждений! Заранее спасибо !
|
|
|
|
|
Dec 24 2013, 03:20
|

Профессионал
    
Группа: Свой
Сообщений: 1 261
Регистрация: 14-05-09
Из: Челябинск
Пользователь №: 49 045

|
Цитата(MiklPolikov @ Dec 24 2013, 07:29)  vApplicationStackOverflowHook иногда работает, иногда нет. У vApplicationStackOverflowHook есть два режима. см КОМПОНЕНТЫ И ТЕХНОЛОГИИ • № 11 '2011, стр 104, "Контроль переполнения стерка". Пробуй Метод контроля переполнения стека № 2. Ну и как я понял проблема в том, что не хватает памяти в общем стеке для создания новой задачи. А vApplicationStackOverflowHook контролирует переполнение стека не общего, а стека задачи самой задачей. Цитата А если вставить вот такую функцию-заглушку перед каждым созданием новой задачи, она даст 100% верный результат. ээээ..... не совсем понятно что делает заглушка? Проверяет есть ли 256 байт или 256*size_t байт доступно в общем стеке? Не нашол описание на xPortGetFreeHeapSize(). какую модель памяти используешь? на оф сайте Цитата The xPortGetFreeHeapSize() API function returns the total amount of heap space that remains unallocated (allowing the configTOTAL_HEAP_SIZE setting to be optimised), but does not provided information on how the unallocated memory is fragmented into smaller blocks. Т.е. у тебя может быть в общей куче 500 байт свободно, 50 блоков по 10 байт. ни одну новую задачу создать не возможно. Память фрагментирована. Твой костыль тут не поможет. Поможет возвращяемое значение xTaskCreate()Цитата Возвращает: pdPASS - если задача успешно создана и добавлена в список готовых, иначе возвращает код ошибки, определенный в файле errors. h
|
|
|
|
|
Jan 6 2014, 06:57
|

Профессионал
    
Группа: Свой
Сообщений: 1 261
Регистрация: 14-05-09
Из: Челябинск
Пользователь №: 49 045

|
Цитата(MiklPolikov @ Jan 6 2014, 05:32)  Стало любопытно, каким образом память становится фрагментирована на куски по 10 байт ? После того как была удалена задача со стеком 60 байт, и создана новая задача со стеком 50 , стек которой заполнил освободившуюся "дырку"? Да Цитата А она потом сама автоматически дефрагментируется ? Нет Дружище..... тебя уже не раз отсылали к статьям Курниц. Там же ответы на все твои вопросы. На русском разжовано и с картинками выложенно. По поводу фрагментации памяти см КиТ №5 2011 стр 99. Там не совсем свежее описание, нет модели 4, но 1-3 модели описанны хорошо.
|
|
|
|
|
Jan 6 2014, 08:12
|

Гуру
     
Группа: Свой
Сообщений: 2 015
Регистрация: 23-01-07
Из: Москва
Пользователь №: 24 702

|
Цитата(juvf @ Jan 6 2014, 10:57)  Дружище..... тебя уже не раз отсылали к статьям Курниц. Там же ответы на все твои вопросы. На русском разжовано и с картинками выложенно. По поводу фрагментации памяти см КиТ №5 2011 стр 99. Там не совсем свежее описание, нет модели 4, но 1-3 модели описанны хорошо. Конечно же я их прочитал. И не только их. Ну всего же не запомнишь...
--------------------
Если у Вас нет практического опыта в данной теме- не вступайте в дискуссию и не пишите никаких теоретических рассуждений! Заранее спасибо !
|
|
|
|
|
Jan 6 2014, 14:44
|

Гуру
     
Группа: Свой
Сообщений: 2 015
Регистрация: 23-01-07
Из: Москва
Пользователь №: 24 702

|
У меня новый вопрос. Правильно ли я отдаю симафор из прерывания и переключаю в нём контекст ? Такая проблема : работает, но через 5 минут(точной привязки ко времени нет) начинает работать неправильно. Остальные задачи начинают тормозить, будто бы задача забирающая симафор vRTC_Read_Time_Task начала использовать всё машинное время. Второй день не могу даже точно понять что происходит . Заранее спасибо !!! Код ////////////////////////////читаем время из RTC сразу после выдачи симафора из ежесекундного прерывания////////////////////////////////////// void vRTC_Read_Time_Task (void * pvParameters) { while(1) { xSemaphoreTake( x_RTC_Second_Change, portMAX_DELAY ); /* ..................... */ }
///////прерывание RTC ALARM 1 раз в секунду//////////////////////////////////////////////// void RTC_Alarm_IRQHandler(void) { portBASE_TYPE pxHigherPriorityTaskWoken; EXTI->PR|=(1<<17); RTC->ISR&=~RTC_ISR_ALRAF; //сбрасываем флаги прерывания xSemaphoreGiveFromISR(x_RTC_Second_Change,&pxHigherPriorityTaskWoken); if(pxHigherPriorityTaskWoken==pdTRUE) taskYIELD(); //переключаем контекст }
--------------------
Если у Вас нет практического опыта в данной теме- не вступайте в дискуссию и не пишите никаких теоретических рассуждений! Заранее спасибо !
|
|
|
|
|
Jan 6 2014, 23:04
|
практикующий тех. волшебник
    
Группа: Участник
Сообщений: 1 190
Регистрация: 9-09-05
Пользователь №: 8 417

|
Цитата(MiklPolikov @ Jan 7 2014, 01:06)  Код ..vSemaphoreCreateBinary( x_RTC_Second_Change );... вот тут есть инфа о различиях и правильном применении семафоров. семафорыобратите внимание на другие способы создания семафоров(и способы работы с ними - рисунки 30 и 31), например xSemaphoreCreateCounting если интенсив у Вас большой - то возможно это Ваш случай.
|
|
|
|
|
Jan 7 2014, 00:38
|

Гуру
     
Группа: Свой
Сообщений: 2 015
Регистрация: 23-01-07
Из: Москва
Пользователь №: 24 702

|
Цитата(kolobok0 @ Jan 7 2014, 03:04)  вот тут есть инфа о различиях и правильном применении семафоров. семафорыобратите внимание на другие способы создания семафоров(и способы работы с ними - рисунки 30 и 31), например xSemaphoreCreateCounting если интенсив у Вас большой - то возможно это Ваш случай. Знаю про другие способы создания симафора. Но это не даёт ответа на вопрос, из-за чего именно происходит глюк. И увеличение частоты выдающего симафор прерывания в 1000 раз не учащает появление глюка. Изучил глюк получше : Во время глюка иногда попадаю в HardFault_Handler, иногда просто операционка начинает работать не так. В HardFault_Handler под отладкой вижу, что одна задача как будто вызвала саму себя, хотя код в задачах самый простой и линейный, никакой рекурсии. Глюк происходит, только если в задаче есть строчка xSemaphoreTake( x_RTC_Second_Change, portMAX_DELAY ); Т.е. будто бы проблема связана с тем что контекст захотел переключится после выдачи симафора в прерывании. При этом переключаю я контекст taskYIELD() в конце прерывания или не переключаю ни на что не влияет.
Эскизы прикрепленных изображений
--------------------
Если у Вас нет практического опыта в данной теме- не вступайте в дискуссию и не пишите никаких теоретических рассуждений! Заранее спасибо !
|
|
|
|
|
Jan 7 2014, 08:19
|

Профессионал
    
Группа: Свой
Сообщений: 1 261
Регистрация: 14-05-09
Из: Челябинск
Пользователь №: 49 045

|
Цитата(MiklPolikov @ Jan 6 2014, 20:44)  Код ///////прерывание RTC ALARM 1 раз в секунду//////////////////////////////////////////////// void RTC_Alarm_IRQHandler(void) { portBASE_TYPE pxHigherPriorityTaskWoken; EXTI->PR|=(1<<17); RTC->ISR&=~RTC_ISR_ALRAF; //сбрасываем флаги прерывания xSemaphoreGiveFromISR(x_RTC_Second_Change,&pxHigherPriorityTaskWoken); if(pxHigherPriorityTaskWoken==pdTRUE) taskYIELD(); //переключаем контекст } Какой камень? А вроде не правильное переключение контекста, у меня чото не задружило переключение taskYIELD() для NIOS и для STM32. Так Код void USART1_IRQHandler(void) { static uint8_t byte; [b]static [/b]portBASE_TYPE xHigherPriorityTaskWoken; xHigherPriorityTaskWoken = pdFALSE; if(USART1_SR_bit.RXNE == 1) { // byte = USART1_DR; xQueueSendToBackFromISR(uart485Queue, &byte, &xHigherPriorityTaskWoken); } [b]portEND_SWITCHING_ISR(xHigherPriorityTaskWoken == pdTRUE);[/b] } лучше xHigherPriorityTaskWoken сделать статиком ну и определи configASSERT, может косяк выскочит из-за конфига ртос
|
|
|
|
|
Jan 7 2014, 20:05
|

Гуру
     
Группа: Свой
Сообщений: 2 015
Регистрация: 23-01-07
Из: Москва
Пользователь №: 24 702

|
Цитата(juvf @ Jan 7 2014, 12:19)  Какой камень? А вроде не правильное переключение контекста, у меня чото не задружило переключение taskYIELD() для NIOS и для STM32. Так лучше xHigherPriorityTaskWoken сделать статиком ну и определи configASSERT, может косяк выскочит из-за конфига ртос STM32L151 Сделал xHigherPriorityTaskWoken статиком Заменил taskYIELD(); на portYIELD_FROM_ISR(xHigherPriorityTaskWoken == pdTRUE); (это то же самое что у Вас portEND_SWITCHING_ISR ) Сделал через очередь xQueueSendFromISR Ничего не изменилось. Что такое configASSERT не понимаю. Объясните пожалуйста в двух словах. Прочитал про него на сайте Freertos, вижу как определён. А что он делает-то и как его "определить" ? #define configASSERT( ( x ) ) if( ( x ) == 0 ) vAssertCalled( __FILE__, __LINE__ ) И ещё : где взять 100% правильный файл FreeRtosConfig.h для STM32L151 Keil FreeRTOS V7.6.0 ? В разных примерах есть "вроде бы подходящие" файлы, и с ними до сих пор работало. Ну а какой точно нужен ? Может в этом дело ?
--------------------
Если у Вас нет практического опыта в данной теме- не вступайте в дискуссию и не пишите никаких теоретических рассуждений! Заранее спасибо !
|
|
|
|
|
Jan 9 2014, 03:22
|

Профессионал
    
Группа: Свой
Сообщений: 1 261
Регистрация: 14-05-09
Из: Челябинск
Пользователь №: 49 045

|
Цитата(MiklPolikov @ Jan 8 2014, 02:05)  Что такое configASSERT не понимаю. Объясните пожалуйста в двух словах. Прочитал про него на сайте Freertos, вижу как определён. А что он делает-то и как его "определить" ? #define configASSERT( ( x ) ) if( ( x ) == 0 ) vAssertCalled( __FILE__, __LINE__ ) configASSERT - это проверка правильности настройки фрииртос. этот дефайн отнимает немного процесорного времени и нужен только для начального дебага(проверки) ртос. Когда гдето ртос начинает глючить, есть вероятность что не правильно что-то заданно. например у меня было #define configMAX_PRIORITIES ( ( unsigned portBASE_TYPE ) 5 ) создал задачу с приоритетом 5. вроде работало, но иногда сбоило. определил configASSERT в FreeRtosConfig.h Код #define configASSERT( x ) if( ( x ) == 0 ) { taskDISABLE_INTERRUPTS(); for(;; ); } сразу при создании задачи застрял в одном месте ртос с коментами типа "попытка создать задачу с приоритетом >= 5". оказалось что configMAX_PRIORITIES должен быть на 1 выше самого высокого приоритета задачи. Потом во фрииртос сложная замута с приоритетами задач и прерываний. В стм32 ещё приоритеты прерываний в обратном порядке. Чтобы ртос коректно крутилась нужно правильно назначить configKERNEL_INTERRUPT_PRIORITY и configMAX_SYSCALL_INTERRUPT_PRIORITY..... для stm32 это вообще квест.... попробую объяснить. В демках так Код /* This is the raw value as per the Cortex-M3 NVIC. Values can be 255 (lowest) to 0 (1?) (highest). */ #define configKERNEL_INTERRUPT_PRIORITY 255 /* !!!! configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to zero !!!! See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html. */ #define configMAX_SYSCALL_INTERRUPT_PRIORITY 191 /* equivalent to 0xb0, or priority 11. */
/* This is the value being used as per the ST library which permits 16 priority values, 0 to 15. This must correspond to the configKERNEL_INTERRUPT_PRIORITY setting. Here 15 corresponds to the lowest NVIC value of 255. */ #define configLIBRARY_KERNEL_INTERRUPT_PRIORITY 15 configKERNEL_INTERRUPT_PRIORITY - с этим всё понятно. ядру низший приоритет. #define configMAX_SYSCALL_INTERRUPT_PRIORITY 191 /* equivalent to 0xb0, or priority 11. */ - вот это загадка. 191 в хексе = 0xbf. для моего stm32 в назначении приоритета учавствует только старшая тетрада. поэтому bf equivalent to 0xb0. 0 отбрасываем.... приоритет 0хb, или 11. Так вот.... если вы используете прерывания, пишете обработчики прерывания, и если в обработчике прерывания нет API, то прерывание может быть с любым приоритетом. А если из обработчика прерывания есть вызов API, то источник прерывания должен быть с приоритетом не выше configMAX_SYSCALL_INTERRUPT_PRIORITY, в моем случае не выше 11. Т.е. у вас приоритет для RTC_Alarm_IRQHandler должен быть равен или ниже configMAX_SYSCALL_INTERRUPT_PRIORITY. 0 - вроде как высший приоритет в стм32. т.е. если configMAX_SYSCALL_INTERRUPT_PRIORITY=191, то приоритет RTC_Alarm_IRQHandler должен быть от 15 до 11 включительно. configASSERT также проверит приоритеты прерываний. В моем компиляторе нет макросов __FILE__, __LINE__, да и выводить не куда. поэтому у меня вечный вайл for( ;; ); Цитата И ещё : где взять 100% правильный файл FreeRtosConfig.h для STM32L151 Keil FreeRTOS V7.6.0 ? Ну так а чего там может быть правильно и неправильно. разберись с каждой строчкой и сделай свой. Не сложно вроде.
|
|
|
|
|
Jan 11 2014, 11:55
|
Знающий
   
Группа: Свой
Сообщений: 875
Регистрация: 28-10-05
Пользователь №: 10 245

|
Цитата(MiklPolikov @ Jan 11 2014, 13:09)  juvf, огромное спасибо, сделал приоритет прерывания от RTC 12 и проблема исчезла !!!
Что делает это configMAX_SYSCALL_INTERRUPT_PRIORITY так и не могу понять. Как понимаю из документации, прерывания выше этого приоритета используются самой операционкой, поэтому они и должны быть выше всех остальных. Но почему их так много, 11 ? Ведь операционка использует всего 3 прерывания, вот эти #define xPortSysTickHandler SysTick_Handler #define xPortPendSVHandler PendSV_Handler #define vPortSVCHandler SVC_Handler В СТМ какие прерывания более приоритетны? И 11 это не значит их количество, это приоритет прерывания. http://microsin.net/programming/ARM/freertos-part3.html ищите пункт 3.5 и ниже. так же читайте про приоритеты прерываний для вашего процессора.
|
|
|
|
|
Jan 11 2014, 12:15
|

Гуру
     
Группа: Свой
Сообщений: 2 015
Регистрация: 23-01-07
Из: Москва
Пользователь №: 24 702

|
Цитата(Lagman @ Jan 11 2014, 15:55)  В СТМ какие прерывания более приоритетны? И 11 это не значит их количество, это приоритет прерывания. http://microsin.net/programming/ARM/freertos-part3.html ищите пункт 3.5 и ниже. так же читайте про приоритеты прерываний для вашего процессора. Понимаю что 11 это не количество прерываний а приоритет. Но ведь выходит, что операционка резервирует для своих нужд все приоритеты выше 11, т.е. 11 разных приоритетов , и возникает вопрос почему так много, если реально используется меньше прерываний.
--------------------
Если у Вас нет практического опыта в данной теме- не вступайте в дискуссию и не пишите никаких теоретических рассуждений! Заранее спасибо !
|
|
|
|
|
Jan 11 2014, 12:27
|
Знающий
   
Группа: Свой
Сообщений: 875
Регистрация: 28-10-05
Пользователь №: 10 245

|
Цитата(MiklPolikov @ Jan 11 2014, 16:15)  Понимаю что 11 это не количество прерываний а приоритет. Но ведь выходит, что операционка резервирует для своих нужд все приоритеты выше 11, т.е. 11 разных приоритетов , и возникает вопрос почему так много, если реально используется меньше прерываний. никто ничего не резервирует, просто приоритеты от 11 до 15 могут использовать функционал freertos, а которые выше приоритетом от 0 до 10 уже не могут и не могут быть прерваны тиком freertos. ну и наверно в cortex m3 может быть много прерываний с одинаковым приоритетом, ведь векторов прерываний не 15.
|
|
|
|
|
Jan 13 2014, 08:52
|

Гуру
     
Группа: Свой
Сообщений: 2 015
Регистрация: 23-01-07
Из: Москва
Пользователь №: 24 702

|
Ещё один вопрос : Почему в задачу vApplicationStackOverflowHook вместо указателя на название задачи стек которой переполнился передаётся 0 ? Раньше работало, и я мог увидеть название задачи. Вопрос : что могло изменится ? Заранее спасибо !
Эскизы прикрепленных изображений
--------------------
Если у Вас нет практического опыта в данной теме- не вступайте в дискуссию и не пишите никаких теоретических рассуждений! Заранее спасибо !
|
|
|
|
|
Feb 4 2014, 20:46
|

Гуру
     
Группа: Свой
Сообщений: 2 015
Регистрация: 23-01-07
Из: Москва
Пользователь №: 24 702

|
Вопрос по организации алгоритма :
Допустим начала работать задача А(была создана, была разблокирована), и пока она работает должны заблокироваться задачи Б, С, Д. Когда задача А завершила работу, Б С Д должны разблокироваться. Как это принято делать так, что бы было наименее путано ? Сделать очередь из одного элемента, из которой задачи Б С Д читают этот элемент без удаления, а задача А его либо удаляет либо возвращает ? Нет ли способа проверять внутри задачи Д чему равен хэндлер задачи А, так что бы когда он не NULL задача Д блокировалась бы, а когда снова стал NULL разблокировалась бы?
Спасибо.
--------------------
Если у Вас нет практического опыта в данной теме- не вступайте в дискуссию и не пишите никаких теоретических рассуждений! Заранее спасибо !
|
|
|
|
|
Feb 5 2014, 02:25
|

Профессионал
    
Группа: Свой
Сообщений: 1 261
Регистрация: 14-05-09
Из: Челябинск
Пользователь №: 49 045

|
для этого существуют эвэнты. в v8.0 наконецто их добавили. задачи Б, С, Д блокируй в ожидании установки флага (эвента). Задачи Б, С, Д могут ждать одного флага, а можно для каждой задачи сделать отдельный флаг в группе флагов. А с проверкой хэндлера..... дак это прийдется в задачах Б, С, Д с какимто периодом проверять хендлер. С таким же успехом можно завести глобальную переменную и проверять её в Б, С, Д и не заморачиваться с хендлером.
|
|
|
|
|
Feb 5 2014, 13:16
|
Участник

Группа: Участник
Сообщений: 41
Регистрация: 26-11-07
Пользователь №: 32 693

|
Цитата(MiklPolikov @ Feb 5 2014, 00:46)  Вопрос по организации алгоритма :
Допустим начала работать задача А(была создана, была разблокирована), и пока она работает должны заблокироваться задачи Б, С, Д. Когда задача А завершила работу, Б С Д должны разблокироваться. Как это принято делать так, что бы было наименее путано ? Сделать очередь из одного элемента, из которой задачи Б С Д читают этот элемент без удаления, а задача А его либо удаляет либо возвращает ? Нет ли способа проверять внутри задачи Д чему равен хэндлер задачи А, так что бы когда он не NULL задача Д блокировалась бы, а когда снова стал NULL разблокировалась бы?
Спасибо. Может просто сделать приоритет А выше других?
|
|
|
|
|
Feb 12 2014, 19:37
|

Гуру
     
Группа: Свой
Сообщений: 2 015
Регистрация: 23-01-07
Из: Москва
Пользователь №: 24 702

|
Ещё вопрос: Как я понял , для того что бы использовать флаги событий нужно добавить в FreeRTOSConfig.h следующие строки, без них не компилируется. Из каких соображений нужно выбирать то, что я отметил //// ? Рассуждаю так : configTIMER_TASK_PRIORITY 0 самый верхний приоритет для того что бы всё что с этим будет связано обрабатывалось быстрее моих задач, так будет работать гарантированно однозначно. configTIMER_QUEUE_LENGTH 1 маленькая длинна очереди т.к. приоритет всё равно самый верхний, очередь не должна переполнится Заранее спасибо за ответ ! Цитата #define INCLUDE_xEventGroupSetBitFromISR 1 #define configUSE_TIMERS 1 #define configTIMER_TASK_PRIORITY 0 //// #define configTIMER_QUEUE_LENGTH 1 //// #define configTIMER_TASK_STACK_DEPTH configMINIMAL_STACK_SIZE //// #define INCLUDE_xTimerPendFunctionCallFromISR 1
--------------------
Если у Вас нет практического опыта в данной теме- не вступайте в дискуссию и не пишите никаких теоретических рассуждений! Заранее спасибо !
|
|
|
|
|
Feb 14 2014, 07:21
|

Гуру
     
Группа: Свой
Сообщений: 2 015
Регистрация: 23-01-07
Из: Москва
Пользователь №: 24 702

|
Настроил как написал выше, и вроде бы всё хорошо. Ещё один вопрос, мучает уже давно : Почему в примерах в объявлениях семафоров , мьютиксов и т.п. нет директивы volatile, и почему без неё работает когда семафор выдаётся в прерывании ? Заранее спасибо за объяснение ! Код /*volatile*/ xSemaphoreHandle x_RTC_Second_Change; //разве тут не нужен volatile ?
//.....
xSemaphoreGiveFromISR(x_RTC_Second_Change,&xHigherPriorityTaskWoken);
--------------------
Если у Вас нет практического опыта в данной теме- не вступайте в дискуссию и не пишите никаких теоретических рассуждений! Заранее спасибо !
|
|
|
|
|
Apr 24 2014, 14:41
|

Гуру
     
Группа: Свой
Сообщений: 2 015
Регистрация: 23-01-07
Из: Москва
Пользователь №: 24 702

|
Ещё один вопрос, по архитектуре кода :
Перевожу свои старые коды без ОС на FreeRTOS. К примеру есть функция, инициализирующая SD карту, в ней в каких-то циклах ожидание чего-то. Как теперь с этим поступить наиболее правильно ? а) Вставить в функцию команды переключения контекста. Функция будет вызываться в задаче, но выполняться будет не быстро, т.к. функция чего-то ждёт внутри себя. С одной стороны контекст будет переключатся, т.е. система в целом работать правильно, но с другой та задача, которая функцию вызвала, будет останавливаться на этой функции на большое время, что на мой взгляд криво. б) Сделать из функции отдельную задачу. Создавать её когда надо проинициализировать карту, когда инициализация прошла удалять, а о том что инициализация прошла узнавать через эвенты или симафоры.
Заранее спасибо.
--------------------
Если у Вас нет практического опыта в данной теме- не вступайте в дискуссию и не пишите никаких теоретических рассуждений! Заранее спасибо !
|
|
|
|
|
Apr 25 2014, 18:08
|
практикующий тех. волшебник
    
Группа: Участник
Сообщений: 1 190
Регистрация: 9-09-05
Пользователь №: 8 417

|
Цитата(MiklPolikov @ Apr 24 2014, 23:25)  Объясните пожалуйста на пальцах, что значит "убрать в нитку" и "обслуживать запросы синхронно и асинхронно" ? ..один линейный код в одной задаче ?... если юзаете ось, то во фриртосе есть понятие поток. вам ничего не мешает отдельно поток завести на ваши медленно играющие проблемы. асинхронно (по отношению к этому потоку) вы сможете вызывать необходимые вам функции (рядом с потоком лежащие и реализующие синхонизацию). Вам никто не мешает порождать, посылать запрос, ждать, по возврату управления удалять объект синхронизации. это есть синхронное обращение. как пример см. стэки изернет, синхроные натификэшены во всяких форточках и иже... вам никто не мешает, завести объект синхронизации в вызывающем коде, передать его на вызове и продолжать работу периодически проверяя обратный натификэшен. как пример реализации см. те же форточки раздел асинхронный доступ к файлам, портам и т.д., либо в других осях - типа новела, льюникса, юникса и т.д... про линейный код нифига не понял. как пример разжовывания на пальцах(да и пользительно под форточками) - почитайте толковую книгу "WINDOWS для профессионалов" автор Джеффри Рихтер там есть и асинхронный пласт и синхронный...возможно не по теме но как консерватория - вполне...
|
|
|
|
|
Apr 26 2014, 04:18
|

Профессионал
    
Группа: Свой
Сообщений: 1 261
Регистрация: 14-05-09
Из: Челябинск
Пользователь №: 49 045

|
Цитата(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 { //сюда попадем, если недождались. исключение }
|
|
|
|
|
Apr 29 2014, 20:36
|
практикующий тех. волшебник
    
Группа: Участник
Сообщений: 1 190
Регистрация: 9-09-05
Пользователь №: 8 417

|
Цитата(juvf @ Apr 26 2014, 08:18)  ...Когда идет инициализация, то процессор простаивает. как правильно организовать работу... Вы вот прочитали но не поняли скорее всего, что я написал выше. Окейно. по другому.. откуда это у Вас? "Когда идет инициализация, то процессор простаивает" я бы сказал заблуждение... Или логику так построили? Ну а кто мешает по другому, религия если только??? вот у меня паралельно идёт инициализация(читай подъём или инициализация) железа...uSD, Ehernet, ADC, стэки, оси, MODBAUS, запуск ниток, изернет клиенты-сервера, wifi (и прочий звериниц), всё это делается параллельно (ну есть конечно же последовательные действия), но они не создают узких мест для общей картины а больше, как это лучше сказать - по общей готовности все подождут самого отстающего... ну и принимается решения для подключения или отключения функционала блоков или логики...
|
|
|
|
|
Apr 30 2014, 12:56
|

Гуру
     
Группа: Свой
Сообщений: 2 015
Регистрация: 23-01-07
Из: Москва
Пользователь №: 24 702

|
Цитата(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 нужно писать самому ?
--------------------
Если у Вас нет практического опыта в данной теме- не вступайте в дискуссию и не пишите никаких теоретических рассуждений! Заранее спасибо !
|
|
|
|
|
May 7 2014, 12:13
|

Гуру
     
Группа: Свой
Сообщений: 2 015
Регистрация: 23-01-07
Из: Москва
Пользователь №: 24 702

|
Цитата(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 )
Следовательно, дефолтные настройки системного таймера применяются ровно один раз в проекте. Если вы хотите менять частоту процессора - то в том же коде перенастаивайте таймер системного тика, и будет вам счастье. Пост писал, гораздо дольше чем залез в код и нашел ответы на ваши вопросы. Да, я то же это находил. Но подумал, вдруг есть неочевидные для меня тонкости.
--------------------
Если у Вас нет практического опыта в данной теме- не вступайте в дискуссию и не пишите никаких теоретических рассуждений! Заранее спасибо !
|
|
|
|
|
May 27 2014, 09:01
|

Гуру
     
Группа: Свой
Сообщений: 2 015
Регистрация: 23-01-07
Из: Москва
Пользователь №: 24 702

|
Коллеги, ещё один вопрос :
Верно ли я понимаю, что значение, которое возвращает xTaskGetTickCount(); периодически сбрасывается в 0 и начинает расти заново, т.к. переполняется 32х разрядная переменная, которая считает тики , и стало быть, при использовании xTaskGetTickCount(); я должен обрабатывать этот сброс в 0 ? А все функции операционки которые работают со временем (задержка, взять симофор и т.п. ) , то же обрабатывают сброс счётчика тиков в 0 ?
МП
--------------------
Если у Вас нет практического опыта в данной теме- не вступайте в дискуссию и не пишите никаких теоретических рассуждений! Заранее спасибо !
|
|
|
|
|
May 28 2014, 00:41
|

Профессионал
    
Группа: Свой
Сообщений: 1 261
Регистрация: 14-05-09
Из: Челябинск
Пользователь №: 49 045

|
Цитата(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.
|
|
|
|
|
May 29 2014, 15:40
|

Гуру
     
Группа: Свой
Сообщений: 2 015
Регистрация: 23-01-07
Из: Москва
Пользователь №: 24 702

|
juvf, спасибо ! Я всегда работал со временем другим способом, и в нём приходилось проверять, не начался ли счёт с 0
И ещё вопрос. Правильно ли я понимаю работу ОС в целом ? :
В устройстве две SD карты. Задача инициализации написана одна, она создаётся в двух экземплярах, в задачу передаётся параметр № карты. Задача вызывает какие-то функции с локальными переменными, те то же вызывают функции и т.д. Правильно ли я понимаю, что при переключении контекста все эти локальные переменные сохраняются в стеке задачи, т.е. физически копируются из одной области памяти в другую ? Если локальные переменные в функциях определены как static, это не влияет на сохранение в стеке ? Получается, что на переписывание контекста в стек и обратно уходит много времени, и стало быть надо стремится сокращать количество локальных переменных ? Все большие массивы нужно определять как глобальные переменные, и работать с ними как с ресурсом ?
--------------------
Если у Вас нет практического опыта в данной теме- не вступайте в дискуссию и не пишите никаких теоретических рассуждений! Заранее спасибо !
|
|
|
|
|
May 30 2014, 02:50
|
Участник

Группа: Участник
Сообщений: 71
Регистрация: 2-03-06
Из: Минск
Пользователь №: 14 879

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

Гуру
     
Группа: Свой
Сообщений: 2 015
Регистрация: 23-01-07
Из: Москва
Пользователь №: 24 702

|
Цитата(Newegor @ May 30 2014, 11:00)  А вот использование static, без понимания, я бы не рекомендовал. При создании такой переменной ее экземпляр будет один и тот же на все задачи. Newegor, спасибо за информацию про static ! У меня вот это работает, только если возвращаемая переменная static . А если нет, то функция возвращает 0. Как я понимаю, это потому что существование переменной прекращаеся чуть раньше чем программа вышла из функции, и возвращать оказывается нечего. Код char do_something(void) { chatic char result;
//................. return result; }
--------------------
Если у Вас нет практического опыта в данной теме- не вступайте в дискуссию и не пишите никаких теоретических рассуждений! Заранее спасибо !
|
|
|
|
|
May 30 2014, 05:35
|
Знающий
   
Группа: Свой
Сообщений: 526
Регистрация: 24-08-07
Из: Беларусь, Минск
Пользователь №: 30 045

|
Цитата(MiklPolikov @ May 27 2014, 16:11)  Коллеги, ещё один вопрос :
Верно ли я понимаю, что значение, которое возвращает xTaskGetTickCount(); периодически сбрасывается в 0 и начинает расти заново, т.к. переполняется 32х разрядная переменная, которая считает тики , и стало быть, при использовании xTaskGetTickCount(); я должен обрабатывать этот сброс в 0 ? А все функции операционки которые работают со временем (задержка, взять симофор и т.п. ) , то же обрабатывают сброс счётчика тиков в 0 ?
МП Если ваша задержка меньше разрядности счётчика, то 0 обрабатывать не нужно. Но если больше - обязательно (или разбивать на части). Пример: пусть счётчик 16-битный. Начальное значение 2, а задержка - 70000 (0x11170). Если взять просто сумму получим 0x11172, из-за переполнения получим в итоге 0x1172, что даст реальную задержку 4464 вместо 70000. Если промахнуться с разрядностью переменной, с которой будет сравниваться счётчик - можно никогда не выйти из цикла ожидания.
|
|
|
|
|
May 30 2014, 05:59
|

Профессионал
    
Группа: Свой
Сообщений: 1 261
Регистрация: 14-05-09
Из: Челябинск
Пользователь №: 49 045

|
Цитата(MiklPolikov @ May 30 2014, 14:23)  У меня вот это работает, только если возвращаемая переменная static . А если нет, то функция возвращает 0. Как я понимаю, это потому что существование переменной прекращаеся чуть раньше чем программа вышла из функции, и возвращать оказывается нечего. Код char do_something(void) { chatic char result;
//................. return result; } нет, не так работает си/с++. если резалт не статик, то при покидании функции переменная резалт удалится из стека, но её значение не потеряется а нормально вернётся. может у вас в одной задаче резальт считается и равен 0, в другой задаче резалт неравен нулю. в итоге, когда статик, то оба резалта не равны нулю, а одному значению. а когда не статик, то один экземпляр равен нулю. ..... вобщем это гадание на кофейной гуще. что то не так у вас. попробуйте запустить только одну задачу и проверит статик и нестатик - результат должен быть одинаковый, потом 1-ую задачу выкл, и включить вторую - проверить.....
|
|
|
|
|
May 30 2014, 06:43
|

Гуру
     
Группа: Свой
Сообщений: 2 015
Регистрация: 23-01-07
Из: Москва
Пользователь №: 24 702

|
Цитата(juvf @ May 30 2014, 14:09)  нет, не так работает си/с++. если резалт не статик, то при покидании функции переменная резалт удалится из стека, но её значение не потеряется а нормально вернётся. может у вас в одной задаче резальт считается и равен 0, в другой задаче резалт неравен нулю. в итоге, когда статик, то оба резалта не равны нулю, а одному значению. а когда не статик, то один экземпляр равен нулю. ..... вобщем это гадание на кофейной гуще. что то не так у вас. попробуйте запустить только одну задачу и проверит статик и нестатик - результат должен быть одинаковый, потом 1-ую задачу выкл, и включить вторую - проверить..... Я даже без ОС в самом простом линейном коде наблюдаю что функция возвращает только 0 если локальная переменная в ней не static.
--------------------
Если у Вас нет практического опыта в данной теме- не вступайте в дискуссию и не пишите никаких теоретических рассуждений! Заранее спасибо !
|
|
|
|
|
May 31 2014, 06:38
|

Профессионал
    
Группа: Свой
Сообщений: 1 261
Регистрация: 14-05-09
Из: Челябинск
Пользователь №: 49 045

|
Цитата(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 без всяких статиков.
|
|
|
|
|
May 31 2014, 08:25
|

фанат дивана
     
Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684

|
Цитата(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:)
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
Jul 12 2014, 00:58
|

Гуру
     
Группа: Свой
Сообщений: 2 015
Регистрация: 23-01-07
Из: Москва
Пользователь №: 24 702

|
Коллеги, доброго времени суток.
Не могу до конца понять как работают программные таймеры. Что такое "очередь таймера" и в каких случаях она переполняется ? Вот например, мне нужно, что бы таймер начал считать с 0, а если уже считал то сбросился в 0 и начал с 0. BaseType_t xTimerReset( TimerHandle_t xTimer, TickType_t xBlockTime ); Делает именно это или что-то другое ? Что такое xBlockTime , почему про неё сказано , что "это то время, которое задача будет заблокирована, пока команда не запишется в очередь таймера" ? Таймер можно как-нибудь просто сбросить в 0 не блокируя задачу, в которой это делается ?
--------------------
Если у Вас нет практического опыта в данной теме- не вступайте в дискуссию и не пишите никаких теоретических рассуждений! Заранее спасибо !
|
|
|
|
|
Jul 12 2014, 13:32
|

Гуру
     
Группа: Модератор FTP
Сообщений: 4 479
Регистрация: 20-02-08
Из: Москва
Пользователь №: 35 237

|
Цитата(MiklPolikov @ Jul 12 2014, 04:58)  Не могу до конца понять как работают программные таймеры. Что такое "очередь таймера" и в каких случаях она переполняется ? Вот например, мне нужно, что бы таймер начал считать с 0, а если уже считал то сбросился в 0 и начал с 0. Полагаю, что термин "очередь таймера" относится не к аппаратному таймеру, как таковому, а к планировщику задач операционной системы разделенного времени. Т.е. в отсутствие операционной системы у таймеров нет никаких очередей. Судя по всему, под очередью понимается та задача/процедура, на которую таймер должен переключиться при выходе из своей процедуры прерывания. Т.е. по сути это чисто программная задача, а не аппаратная. Причем, место следующего возврата должно быть определено еще до запуска таймера, поскольку после того, как произойдет по нему прерывание, будет некогда искать того, кто стоит в очереди первым. В прерывании вообще нельзя долго находиться, а уж тем более выяснять там какие-то вопросы, которые обязаны были быть решены заранее. Изменения в самой очереди, по-видимому, происходят только тогда, когда ставится новая задача или снимается/завершается старая. Т.е. только в этот момент в порядке очередности задач могут произойти какие-то изменения, тогда как задача таймера - чистое переключение. В общем случае каких-то стандартов тут нет, т.к. авторы операционной системы вольны создать планировщик задач исключительно по своему вкусу, в том числе и вводить для его описания свои термины. Говорят, что когда-то номер/адрес следующего задания хранили прямо в самом таймере, используя его старшие разряды, которые обычно не используются. Но с тех пор и таймеры стали другими, и задачи стали сложнее, а потому нынче задачи обычно переключают по таблице, малость смахивающую на таблицу прерываний. Что-то более определенное сказать не могу, т.к. свою операционную системы вы не назвали. Хотя, судя по названию процедуры BaseType_t xTimerReset, у вас FreeRTOS.
|
|
|
|
|
Jul 13 2014, 11:16
|

Профессионал
    
Группа: Свой
Сообщений: 1 261
Регистрация: 14-05-09
Из: Челябинск
Пользователь №: 49 045

|
Цитата(Xenia @ Jul 12 2014, 19:32)  Судя по всему, под очередью понимается та задача/процедура, на которую таймер должен переключиться при выходе из своей процедуры прерывания. Т.е. по сути это чисто программная задача, а не аппаратная. Причем, место следующего возврата должно быть определено еще до запуска таймера, поскольку после того, как произойдет по нему прерывание, будет некогда искать того, кто стоит в очереди первым. В прерывании вообще нельзя долго находиться, а уж тем более выяснять там какие-то вопросы, которые обязаны были быть решены заранее. мимо не нужны ни какие места возврата. Цитата Не могу до конца понять как работают программные таймеры. Открываем журнал КиТ №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(). Если очередь таймера полна, то задача сброса таймера блокируется, а основная задача работает. Задача сброса должна быть приоритетом выше.
|
|
|
|
|
Jul 17 2014, 13:17
|

Гуру
     
Группа: Свой
Сообщений: 2 015
Регистрация: 23-01-07
Из: Москва
Пользователь №: 24 702

|
Цитата(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); если у задачи уже нет никакой памяти, т.е. в эту память может записаться что угодно ?
--------------------
Если у Вас нет практического опыта в данной теме- не вступайте в дискуссию и не пишите никаких теоретических рассуждений! Заранее спасибо !
|
|
|
|
|
Jul 17 2014, 16:46
|

Гуру
     
Группа: Свой
Сообщений: 2 015
Регистрация: 23-01-07
Из: Москва
Пользователь №: 24 702

|
Цитата(DASM @ Jul 17 2014, 20:10)  Читаю все это и волосы дыбом. Тем более что и работаю с этим. Почему программист должен думать об освобождении памяти? Почему многопоточность не поддерживается средствами языка? Почему до сих пор все сидят на древних языках вроде С и С++ (он недалеко ушел от С, пусть и поддерживает ООП, но все равно с ним обрушить любую систему на ура можно. Есть ли нормальные реализации Явы или С шарп для контроллеров? Иначе это хождение по граблям будет вечным. 15 лет в теме и все одно и тоже. И памяти то уже достаточно для Явы например, и все равно. От слов «указатель» и «приведение типов» тошнит уже в век, когда объемы флеш и озу - ничто, а время на выпуск - все, это анахронизм какой то Если бы озу было "ничто", то я бы вообще не делал динамическое создание/удаление задач. Если Вы знаете как надо, то скажите основные ключевые слова. Есть проц STM32L151 . Выбран как самый малопотребляющий, т.е. ни на что более мощное перейти нельзя.
--------------------
Если у Вас нет практического опыта в данной теме- не вступайте в дискуссию и не пишите никаких теоретических рассуждений! Заранее спасибо !
|
|
|
|
|
Jul 17 2014, 19:30
|

Профессионал
    
Группа: Свой
Сообщений: 1 261
Регистрация: 14-05-09
Из: Челябинск
Пользователь №: 49 045

|
Цитата(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 байт, а куча не используется.
|
|
|
|
|
Jul 17 2014, 19:47
|

Гуру
     
Группа: Свой
Сообщений: 2 015
Регистрация: 23-01-07
Из: Москва
Пользователь №: 24 702

|
Цитата(juvf @ Jul 17 2014, 23:30)  ps если у вас сценарий, как в последнем моём примере, то зачем вам вообще динамика? пишите в статике, будет вам автоматическая зачистка[code]void myTask(void *context) Видимо я плохо объяснил. Речь не о памяти, занятой при выполнении задачи. Речь о стеке самой задачи. После удаления задачи память освобождается не сразу, а только в задаче idle . Если я сразу после удаления создаю новую задачу , а программа между этими двумя действиями не попадает в Idle task , то памяти может не хватить. Вопрос : как освободить память менее криво, чем вызывать между удалением и созданием vTaskDeleay ? Ну неужели не предусмотрено простого способа ?
--------------------
Если у Вас нет практического опыта в данной теме- не вступайте в дискуссию и не пишите никаких теоретических рассуждений! Заранее спасибо !
|
|
|
|
|
Jul 17 2014, 20:36
|
Знающий
   
Группа: Свой
Сообщений: 875
Регистрация: 28-10-05
Пользователь №: 10 245

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