Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Несколько вопросов начинающего
Форум разработчиков электроники ELECTRONIX.ru > Cистемный уровень проектирования > Операционные системы > FreeRTOS
Страницы: 1, 2, 3
MiklPolikov
Помогите пожалуйста побыстрее разобраться что к чему.

Вопрос 1:
Есть задача, управляющая миганием светодиода. Мигать он может с разными частотами и разным цветом. Что бы он мигал задача всё время "крутится",
а частота мигания регулируется при помощи vTaskDelay.
Мигание светодиода должно зависеть от результатов выполнения других задач. Как правильнее всего реализовать передачу данных из нескольких разных задач в эту одну ?
Пришло в голову : сделать очередь, в которую все задачи управляющие миганием будут записывать данные по мере их появления. В задаче мигания проверять наличие в очереди непрочитанного элемента. И только если он есть читать, иначе задача заблокируется и светодиод перестанет мигать совсем.
AlexMad
А нельзя просто, по результату полученного сообщения менять частоту мигания?
То есть, пришло сообщение от одной задачи, мигаем пять раз в секунду, от другой - десять.
Не говоря о том, что в теле самого сообщения Вы можете указать частоту мигания, или другой аргумент, по которому задача мигалки будет что-то решать для себя.
И отсюда можно начинать говорить об алгоритмизации взаимодействия потоков и пользователя.
Lagman
Цитата(MiklPolikov @ Nov 16 2013, 17:09) *
В задаче мигания проверять наличие в очереди непрочитанного элемента. И только если он есть читать, иначе задача заблокируется и светодиод перестанет мигать совсем.

Можно при получении из очереди выставить xTicksToWait и ждать он будет не больше этого количества тиков.
MiklPolikov
Цитата(Lagman @ Nov 16 2013, 23:06) *
Можно при получении из очереди выставить xTicksToWait и ждать он будет не больше этого количества тиков.

Большое спасибо !

MiklPolikov
Вопрос 2 :

Есть USB библиотека. К ней я обращаюсь при помощи всего трёх функций USB_INIT(), USB_RECEIVE(char *p_data), USB_TRANSMIT(char *p_data);
Переписывать всю библиотеку под операционку разумеется желания нет.
Как правильнее всего применить эту библиотеку в проекте, где я решил использовать freeRTOS ? Будет ли правильно просто вставить эти функции в какие-то задачи, чтоб они там вызывались ?
Мой вопрос не "будет ли работать ?" а "как вообще это надо сделать по всем правилам ?"
MiklPolikov
Вопрос 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();

}
MiklPolikov
Вопрос 4:

Почему в файле FreeRtosConfig.h нету параметров configUSE_STATS_FORMATTING_FUNCTIONS и configCHECK_FOR_STACK_OVERFLOW ?
configUSE_STATS_FORMATTING_FUNCTIONS вписал туда руками что бы начать использовать отладочную функцию vTaskList
Lagman
Цитата(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/ по умолчанию никому не надо.
MiklPolikov
Цитата(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 ?
Lagman
Цитата(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 содержит информацию о том, как запросить размер стека, используемого задачей.
MiklPolikov
6 ) Вопрос по структуре программы :

Допустим есть задача v_Start_File_Write_Task, которая начинает запись файла на SD карту. Эта задача запускает какие-то ещё задачи, а те в свою очередь возможно запускают ещё задачи.
Как остановить запись файла и удалить все связанные с этим задачи ? Сделать задачу v_Stop_File_Write_Task в которой все связанные с файловой системой задачи будут удалятся ?
Более изящного пути нет ?
kolobok0
Цитата(MiklPolikov @ Nov 21 2013, 15:47) *
...Более изящного пути нет ?


не знаю как на счёт изяществ, но... в серверном мире(как пример) просматриваются следующие модели:
1) когда логика отрабатывает по запросам пользователя. Этот вариант смахивает на Ваш. У Вас пользователь = это обращение к карточке.
2) когда есть поток(и) обрабатывающие запросы от любых пользователей к определённым ресурсам.
3) смешенная.

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

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

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

ЗЫ
Пример:
на одной из серверных осей(НЕ форточки), разграничение доступа к БД было на уровне потоков. Доступ к БД, по условию задачи, возможен
был только со стороны сервера. Обращение к БД было инкапсулировано в один поток. Код обращения к БД резко сократился - механизмы
транзакций(сервер считался защищён с точки зрения отказов железа) и блокировки не использовались. Быстродействие повысилось. Т.к. читала
и писала одна и та-же "правая рука", то целостность базы была обеспечена априори. Т.е. на лету можно было делать бэкапы в фоновом режиме,
заливку данных, сжатие данных, печать любых отчётов за 0 минут 0 секунд.
MiklPolikov
Ещё вопрос, №7

Правильно ли я понимаю, что любой переход задачи в блокированное состояние, будь то вызов vTaskDelay() , попытка взять симофор, взять элемент из пустой очереди и т.п. эквивалентен форсированному переключению контекста ?
Иными словами, Если у меня во всех задачах либо форсированное переключение контекста, либо какие угодно переводы задачи в блокированное состояние, то я могу быть уверен в том что моя программа "крутится" с максимально возможной скоростью при данной частоте процессора, и системный квант времени фактически ни на что не влияет ?
kolobok0
Цитата(MiklPolikov @ Dec 9 2013, 07:15) *
...что любой переход задачи...Если у меня во всех задачах либо форсированное
переключение ..либо ..переводы задачи в блокированное состояние..уверен в том что .."крутится" с максимально возможной скоростью при данной
частоте процессора, и системный квант времени .. ни на что не влияет ?


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

я так понимаешь, что не было попытки заглянуть внутрь оси и разобраться sm.gif самое лучшее именно та ки поступить...
по поводу максимально возможного - тут всё верно, но немножко оговорочка: теоретически можно поставить колом и даннй механизм,
который будет конечно же дышать, но будет бОльшее выполнение кол-во кода при одном и том же конечном функционале. Но думаю
1) накладные расходы (по сравнению с полезным выполнением, будут минимальны)
2) вопрос спускается к устройству оси. И если Вы ей "доверяете" - то оставте это дело ей. Если нет - переписывайте, либо изучайте вопрос
уже более глубже(сравнивая оси, выбирая и корректируя на более оптимальный олгаритм шедуллер и иже).
3) ИМХО - достаточно при написании кода относится к оси почти как к НЕ вытесняющей. Т.е. помнить о шедуллере и писать код
менее "жадным" к выполнению. Т.е. там где нет необходимости постоянно поллить - перейти на прерывания (идеально чтоб всё было
на прерываниях. от аппаратуры и при передачи самих данных.)

По поводу таймера:
Рекомендую посчитать в тактах МК время кванта тиканья системного таймера. если у Вас всё по умолчанию, тиканье с частотой 1ms
и частота ядра 168Мгц, то на один квант приходится около 168000 тактов МК. Что более чем достаточно для многих задач, с
"бесконечными циклами выполняющихся за 10 секунд" sm.gif т.е. вероятность того, что Вы получите прерывание потока именно таким
способом сводится к минимуму, по большому счёту... хотя зависит от задач sm.gif
juvf
Цитата(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 там все азы и буки по фриртос да и вообще по ртос, всё разжованно и по полочкам.
MiklPolikov
Объясните, как подружить FREERTOS и STM32F030 ?

Взял FreeRTOSConfig.h , который компилировался с STM32L151 .
Не компилируется. ругается на ассемблерные вставки в port.c " error: A1874E: Specified register list cannot be loaded or stored in target instruction set" и другие подобные ошибки.
Взял FreeRTOSConfig.h из демо проекта STM32F05 IAR. У меня keil . Не компилируется. Да и этот файл сильно отличается от моего , наверно потому что он для Iar.

Направьте меня пожалуйста в нужную сторону.
kolobok0
Цитата(MiklPolikov @ Dec 21 2013, 21:32) *
...ругается на ассемблерные вставки в port.c...


а разве для кейла нет уже адаптированой фриртос? я барахтаюсь на иаре, но вроде как под кейло был порт? На худой случай - переписать азм файл.
Там ничего страшного нет. Оригинальный пример + немного инфы по командам вашего камня и будет вам победа...

За одно и поучитесь и ошики подправите во фриртос - они там немного существуют...
juvf
Цитата(MiklPolikov @ Dec 21 2013, 22:32) *
Взял FreeRTOSConfig.h из демо проекта STM32F05 IAR. У меня keil . Не компилируется. Да и этот файл сильно отличается от моего , наверно потому что он для Iar.

Направьте меня пожалуйста в нужную сторону.

а от куда взял port.c? Для кортексаМ0 с кейлом порт нужно брать от сюда FreeRTOS\Source\portable\RVDS\ARM_CM0
а FreeRTOSConfig.h ... может этот подойдёт FreeRTOS\Demo\CORTEX_M0_Infineon_XMC1000_IAR_Keil_GCC\FreeRTOSConfig.h
MiklPolikov
juvf , спасибо, получилось. Моя проблема была в том что в версии 7.4.0 скаченной несколько месяцев назад вообще не было папки ARM_CM0
MiklPolikov
Вопрос про удаление задач.
Как это организовать правильно, или правильно ли я вообще подхожу к созданию алгоритма ?

Есть 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

Задачи хочу именно удалять для экономии стека. да и запускать их надо каждый раз с начала.

Вопрос: как это сделать по-человечески ?
juvf
Цитата(MiklPolikov @ Dec 23 2013, 16:38) *
Но вот беда : если переключение контекста произойдёт после проверки условия v_Task2_Handle ! = NULL , задача v_Task2 где-то удалится, а потом программа вернётся в Task1 и снова попытается удалить уже удалённую задачу, то Task1 удалит сама себя, т.к. v_Task2_Handle уже == NUL

Дак а критические секции? Остановка планировщика?

см taskCRITICAL_ENTER(), taskCRITICAL_EXIT(), vTaskSuspendAll(), xTaskResumeAll();
MiklPolikov
juvf, спасибо !

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

juvf
не путай 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 ); //удаляется динамически выделенная память.
MiklPolikov
juvf, огромное спасибо !!!

Наблюдения :
Разбирался с переполнением стека. vApplicationStackOverflowHook иногда работает, иногда нет.
А если вставить вот такую функцию-заглушку перед каждым созданием новой задачи, она даст 100% верный результат.
vTaskDelay(1); нужен для того что бы запустить Idle Task которая память освободит если этого ещё не случилось после удаления задач.
В худшем случае программа просто зацыклится внутри этой функции, и я буду точно знать в какой момент память кончилась.


Код
//функция- костыль
//////////////////////////////////////
void CHECK_FREE_MEMORY(void)
{
    xxx=xPortGetFreeHeapSize();
    while(xxx<256)
    {
        xxx=xPortGetFreeHeapSize();
        vTaskDelay(1);
    }    
}
juvf
Цитата(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
MiklPolikov
Стало любопытно, каким образом память становится фрагментирована на куски по 10 байт ? После того как была удалена задача со стеком 60 байт, и создана новая задача со стеком 50 , стек которой заполнил освободившуюся "дырку"?
А она потом сама автоматически дефрагментируется ? Возможно для этого необходимо уходить в задачу idle , так же как и для освобождение памяти после удаления задачи ?


Цитата(juvf @ Dec 24 2013, 07:20) *
Т.е. у тебя может быть в общей куче 500 байт свободно, 50 блоков по 10 байт. ни одну новую задачу создать не возможно. Память фрагментирована. Твой костыль тут не поможет.

juvf
Цитата(MiklPolikov @ Jan 6 2014, 05:32) *
Стало любопытно, каким образом память становится фрагментирована на куски по 10 байт ? После того как была удалена задача со стеком 60 байт, и создана новая задача со стеком 50 , стек которой заполнил освободившуюся "дырку"?
Да

Цитата
А она потом сама автоматически дефрагментируется ?
Нет

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

Конечно же я их прочитал. И не только их. Ну всего же не запомнишь...
MiklPolikov
У меня новый вопрос.
Правильно ли я отдаю симафор из прерывания и переключаю в нём контекст ?
Такая проблема : работает, но через 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(); //переключаем контекст
}
kolobok0
Цитата(MiklPolikov @ Jan 6 2014, 18:44) *
...Правильно ли я отдаю симафор из прерывания и переключаю в нём контекст ?...


в коде подвоха не видно.
привидите пример создания этого семафора, ну и обратите на это внимание собственно sm.gif
MiklPolikov
Цитата(kolobok0 @ Jan 6 2014, 21:55) *
в коде подвоха не видно.
привидите пример создания этого семафора, ну и обратите на это внимание собственно sm.gif


Код
xSemaphoreHandle x_RTC_Second_Change;    //глобальная переменная
/*
.......
*/
vSemaphoreCreateBinary( x_RTC_Second_Change );  //в самом начале программы, до инициализации прерываний и создания задач
kolobok0
Цитата(MiklPolikov @ Jan 7 2014, 01:06) *
Код
..vSemaphoreCreateBinary( x_RTC_Second_Change );...


вот тут есть инфа о различиях и правильном применении семафоров.
семафоры
обратите внимание на другие способы создания семафоров(и способы работы с ними - рисунки 30 и 31), например xSemaphoreCreateCounting

если интенсив у Вас большой - то возможно это Ваш случай.
MiklPolikov
Цитата(kolobok0 @ Jan 7 2014, 03:04) *
вот тут есть инфа о различиях и правильном применении семафоров.
семафоры
обратите внимание на другие способы создания семафоров(и способы работы с ними - рисунки 30 и 31), например xSemaphoreCreateCounting

если интенсив у Вас большой - то возможно это Ваш случай.

Знаю про другие способы создания симафора. Но это не даёт ответа на вопрос, из-за чего именно происходит глюк. И увеличение частоты выдающего симафор прерывания в 1000 раз не учащает появление глюка.

Изучил глюк получше :
Во время глюка иногда попадаю в HardFault_Handler, иногда просто операционка начинает работать не так.
В HardFault_Handler под отладкой вижу, что одна задача как будто вызвала саму себя, хотя код в задачах самый простой и линейный, никакой рекурсии.
Глюк происходит, только если в задаче есть строчка xSemaphoreTake( x_RTC_Second_Change, portMAX_DELAY );
Т.е. будто бы проблема связана с тем что контекст захотел переключится после выдачи симафора в прерывании.
При этом переключаю я контекст taskYIELD() в конце прерывания или не переключаю ни на что не влияет.
juvf
Цитата(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, может косяк выскочит из-за конфига ртос
MiklPolikov
Цитата(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 ?
В разных примерах есть "вроде бы подходящие" файлы, и с ними до сих пор работало.
Ну а какой точно нужен ? Может в этом дело ?
juvf
Цитата(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 ?
Ну так а чего там может быть правильно и неправильно. разберись с каждой строчкой и сделай свой. Не сложно вроде.
MiklPolikov
juvf, огромное спасибо, сделал приоритет прерывания от RTC 12 и проблема исчезла !!!

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


Понимаю что 11 это не количество прерываний а приоритет. Но ведь выходит, что операционка резервирует для своих нужд все приоритеты выше 11, т.е. 11 разных приоритетов ,
и возникает вопрос почему так много, если реально используется меньше прерываний.

Lagman
Цитата(MiklPolikov @ Jan 11 2014, 16:15) *
Понимаю что 11 это не количество прерываний а приоритет. Но ведь выходит, что операционка резервирует для своих нужд все приоритеты выше 11, т.е. 11 разных приоритетов ,
и возникает вопрос почему так много, если реально используется меньше прерываний.

никто ничего не резервирует, просто приоритеты от 11 до 15 могут использовать функционал freertos, а которые выше приоритетом от 0 до 10 уже не могут и не могут быть прерваны тиком freertos.

ну и наверно в cortex m3 может быть много прерываний с одинаковым приоритетом, ведь векторов прерываний не 15.
juvf
На сколько я понял.... ос использует приоритеты ниже 11, т.е. 15-11. Да же не ос, а в обработчика прерываний есть апи ос.
Например сработал твой rtc, в обработчике вызвал функционал ртос. Сработал какой нить уарт с прерыванием 11.
Прервал функционал ртос и вызвал другую апи. Обе апи из обоих оработчиков могут использовать одни и реже ресурсы. Поэтому ртос должна как-то это разрулить. Потом обработчик уарта был прерван прерыванием таймера с приоритетом 7. Ртос знает, что там нет вызова апи, и что не одна переменная ртосины не изменится, поэтому ртосу не надо защищаться от совместного использования ресурсов ос.
MiklPolikov
Ещё один вопрос :
Почему в задачу vApplicationStackOverflowHook вместо указателя на название задачи стек которой переполнился передаётся 0 ?
Раньше работало, и я мог увидеть название задачи. Вопрос : что могло изменится ?
Заранее спасибо !
juvf
Цитата(MiklPolikov @ Jan 13 2014, 14:52) *
Ещё один вопрос :
Почему в задачу vApplicationStackOverflowHook вместо указателя на название задачи стек которой переполнился передаётся 0 ?
Раньше работало, и я мог увидеть название задачи. Вопрос : что могло изменится ?
Заранее спасибо !

Не знаю. Смотри указатель xTaskHandle xTask в vApplicationStackOverflowHook на какую задачу указывает. Как создавал задачу? прописал ли имена задач, задал ли xTaskHandle?
MiklPolikov
Цитата(juvf @ Jan 13 2014, 14:56) *
Не знаю. Смотри указатель xTaskHandle xTask в vApplicationStackOverflowHook на какую задачу указывает. Как создавал задачу? прописал ли имена задач, задал ли xTaskHandle?

Разобрался. Это Keil не хочет показывать значение локальной переменной, если она определена но не используется. Раньше этой проблемы с pcTaskName почему-то не было.
Сделал глобальную переменную, которой присваиваю pcTaskName.
MiklPolikov
Вопрос по организации алгоритма :

Допустим начала работать задача А(была создана, была разблокирована), и пока она работает должны заблокироваться задачи Б, С, Д. Когда задача А завершила работу, Б С Д должны разблокироваться. Как это принято делать так, что бы было наименее путано ? Сделать очередь из одного элемента, из которой задачи Б С Д читают этот элемент без удаления, а задача А его либо удаляет либо возвращает ?
Нет ли способа проверять внутри задачи Д чему равен хэндлер задачи А, так что бы когда он не NULL задача Д блокировалась бы, а когда снова стал NULL разблокировалась бы?


Спасибо.
juvf
для этого существуют эвэнты. в v8.0 наконецто их добавили. задачи Б, С, Д блокируй в ожидании установки флага (эвента). Задачи Б, С, Д могут ждать одного флага, а можно для каждой задачи сделать отдельный флаг в группе флагов.

А с проверкой хэндлера..... дак это прийдется в задачах Б, С, Д с какимто периодом проверять хендлер. С таким же успехом можно завести глобальную переменную и проверять её в Б, С, Д и не заморачиваться с хендлером.
Timma
Цитата(MiklPolikov @ Feb 5 2014, 00:46) *
Вопрос по организации алгоритма :

Допустим начала работать задача А(была создана, была разблокирована), и пока она работает должны заблокироваться задачи Б, С, Д. Когда задача А завершила работу, Б С Д должны разблокироваться. Как это принято делать так, что бы было наименее путано ? Сделать очередь из одного элемента, из которой задачи Б С Д читают этот элемент без удаления, а задача А его либо удаляет либо возвращает ?
Нет ли способа проверять внутри задачи Д чему равен хэндлер задачи А, так что бы когда он не NULL задача Д блокировалась бы, а когда снова стал NULL разблокировалась бы?


Спасибо.

Может просто сделать приоритет А выше других?
MiklPolikov
Ещё вопрос:

Как я понял , для того что бы использовать флаги событий нужно добавить в 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
juvf
Я работал с флагами (эвентами) в др ртос. В ФрииРТОС пока не доводилось, не разбирался. С чем их есть во фри - не знаю. laughing.gif
MiklPolikov
Настроил как написал выше, и вроде бы всё хорошо.

Ещё один вопрос, мучает уже давно :
Почему в примерах в объявлениях семафоров , мьютиксов и т.п. нет директивы volatile, и почему без неё работает когда семафор выдаётся в прерывании ?
Заранее спасибо за объяснение !

Код
/*volatile*/  xSemaphoreHandle    x_RTC_Second_Change;  //разве тут не нужен volatile ?

//.....

xSemaphoreGiveFromISR(x_RTC_Second_Change,&xHigherPriorityTaskWoken);
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2024 Invision Power Services, Inc.