Форум программистов, компьютерный форум, киберфорум
Наши страницы
Микроконтроллеры
Войти
Регистрация
Восстановить пароль
 
Рейтинг 4.68/41: Рейтинг темы: голосов - 41, средняя оценка - 4.68
HotD
0 / 0 / 0
Регистрация: 05.10.2017
Сообщений: 2,048
1

вопрос по IdleHook, xTaskCreate

03.10.2015, 14:47. Просмотров 7375. Ответов 14
Метки нет (Все метки)

Вопрос пока без кода, дома ничего нет, завтра скину. Ситуация следующая: Есть 3 задачи, которые работают с FROM памятью через SPI по DMA+ISR. В начале каждой задачи стоит проверка семафора, условно MEMORY_BUSY, который отдается по завершению задачи - в конце цикла стоит xTaskDelete. Т.е, если одна из задач захватила семафор, то остальные задачи висят блокированными, ждут пока этот семафор отдадут. Приоритет у всех задач одинаковые(idle+1). Структура программы условно следующая:
-создали задачу1
-создали задачу2
-создали задачу3
-стартанули диспетчер.
Поидее они все должны выполниться, порядок особо не важен. В итоге выполняется только 1 задача, иногда - 2 задачи(если поменять размер стека, или еще что-либо). Поодиночке выполняются корректно.
Если создать задачу-пустышку, которая будет постоянно выполняться c пустым циклом, условно taskNop, то задачи все задачи выполняются корректно! т.е. при таком порядке:
-создали taskNop (приоритет 1)
-создали задачу1(приоритет 2)
-создали задачу2(приоритет 2)
-создали задачу3(приоритет 2)
-стартанули диспетчер.
Всё работает. Стоит перенести создание задач после старта диспетчера - выполняется только 1 задача:
-создали taskNop (приоритет 1)
-стартанули диспетчер.
-создали задачу1(приоритет 2)
-создали задачу2(приоритет 2)
-создали задачу3(приоритет 2)
Дебиггером смотрю, что как только в задаче1 я взял семафор программа заходит в другие 2 задачи, натыкается на проверку семафора, и больше в эти задачи не заходит. После выполнения задачи1 я отдаю семафор, но задачи2 и 3 не стартуют (хотя поидее должны, т.к. семафор я отдал)всё сваливается в Defaulthomdler. Вопрос - может я что-то упустил в настройке? Стека для корректного выполнения задач хватает, куча явно больше чем нужно. Крутится все на STM32F103CB. В документации сказано, что задачи можно создавать как до, так и после старта диспетчера. Организация памяти - heap_2.c. Может вместо этой задачи пустышки надо сделать перехват IdleHook? Если в конфиге перехват выключен, то что ядро будет делать, если нет ни одной готовой задачи?
0
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
03.10.2015, 14:47
Ответы с готовыми решениями:

Вопрос по SetParent (поэтому, наверное, это вопрос к NickStaves)
Есть набор форм, назовём их 'интерфейсными'. Есть отдельная форма, назовём её 'хранилищем'. Сама...

[ВОПРОС]: Меню и вопрос при регистрации
Помогите пожалуйста. У меня vbulletin 4.0.7 и после установки в верхнем меню есть лишняя навигация....

Вопрос о картинках, вопрос о формулах
Всем доброго времени суток! Как обычно глупые вопросы... Вопрос первый, с сайта копируется...

Вопрос по массивав, "институтский" вопрос.
Готовлюсь к летней сессии по программированию. С++ Есть такая вот задачка (привожу как есть) ...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
14
itysiy
0 / 0 / 0
Регистрация: 18.01.2012
Сообщений: 1,418
03.10.2015, 21:56 2
Семафор точно создается раньше, чем используется?
0
HotD
0 / 0 / 0
Регистрация: 05.10.2017
Сообщений: 2,048
04.10.2015, 07:04 3
Прикладываю код. Да, семафор создается точно раньше, чем используется. Сейчас еще пошагал в дебаггере, возник такой вопрос, есть функция:
Код
void SaveCardRTOS( void *pvParameters )
{
while(1)
{
uint16_t FriiSposi = 0xFFFF;
uint8_t i,j,bytePos,bitPos;
xSemaphoreTake(Memory_Complete, portMAX_DELAY);
//полный код смотри в проекте

WriteMemory(BASE_TABLE_ADDR   ,&MemoryData   , SIZE_TABLE_DATA);      //пишем таблицу
xSemaphoreTake(FROM_Complete, portMAX_DELAY);

ReadMemory(BASE_TABLE_ADDR   ,&MemoryData   , SIZE_TABLE_DATA);      //проверяем что записалось корректно
xSemaphoreTake(FROM_Complete, portMAX_DELAY);
if (CRC16(&MemoryData, SIZE_TABLE_DATA))
{   //todo обработать ошибку crc
vTaskDelete( NULL );
}
WriteMemory(BASE_DATA_ADDR + (SIZE_CARD_DATA * FriiSposi)   ,&CardData   , SIZE_CARD_DATA);   //пишем данные
xSemaphoreTake(FROM_Complete, portMAX_DELAY);   //ждем когда значения запишутся

ReadMemory(BASE_DATA_ADDR + (SIZE_CARD_DATA * FriiSposi)   ,&ReadCardData   , SIZE_CARD_DATA);      //проверяем что записалось корректно
xSemaphoreTake(FROM_Complete, portMAX_DELAY);

if (CRC16(&ReadCardData, sizeof(ReadCardData)))
{   //todo обработать ошибку crc
vTaskDelete( NULL );
}
sprymtf((char *)UsartBuffer, "Save OK Pos=%u Plate=%u Sector=%u\r\n",FriiSposi,i-1,j);
UART2SendString((const uint8_t*)UsartBuffer);
xSemaphoreGive(Memory_Complete);
vTaskDelete( NULL );
}
}
когда я отдаю семафор xSemaphoreGive(Memory_Complete), то на строчку vTaskDelete( NULL ) я уже не попадаю. Отчего такое может быть? После того, как отдал семафор сваливаюсь в DefaultHanlder

Проект лежит тут http://disk.tom.ru/bg7whaj . CoIDE 1.7.8 , завязки на железо особо нет, можно запустить подебажить, разве что UART на другой перекинуть.
0
HotD
0 / 0 / 0
Регистрация: 05.10.2017
Сообщений: 2,048
04.10.2015, 07:23 4
Блин! Вопрос похоже снят, я балбес. В функции ReadMemory(), я читаю прямо в память SIZE_CARD_DATA-байт по адресу с инкрементом адреса. А физически, структура куда читаю меньше адреса SIZE_CARD_DATA. Естественно, оперативка частично затирается, даже не берусь предсказывать что там могло перетираться.
0
HotD
0 / 0 / 0
Регистрация: 05.10.2017
Сообщений: 2,048
04.10.2015, 07:33 5
Однако, раз уж тему создал, задам еще несколько интересующих вопросов:
1. В чем координальная разница между семафором и мьютексом? Так и не понял где какой стоит применять, использую обычные семафоры.
2. Что делает диспетчер, если нет ни одной выполняющейся или готовой задачи? Висит в своем Idle? У Курница сказано "Поэтому хотя бы одна задача должна постоянно находиться в состоянии готовности к выполнению". Или надо явно делать перехват Idle, и там вешать пустой цикл?
3. Начиная с версии 8.2.0 появилась API функция xTaskNotify() и еще несколько, связанных с ней. Беглое чтение документации на англ так и не дало явного понимания, когда это нужно/можно использовать. Если я правильно понял, то это нечто вроде счетного семафора, для запуска задач, когда не требуется быстрого/частого выполнения этой задачи.
0
itysiy
0 / 0 / 0
Регистрация: 18.01.2012
Сообщений: 1,418
04.10.2015, 08:53 6
Цитата Сообщение от Hotd
Однако, раз уж тему создал, задам еще несколько интересующих вопросов:
1. В чем координальная разница между семафором и мьютексом? Так и не понял где какой стоит применять, использую обычные семафоры.
2. Что делает диспетчер, если нет ни одной выполняющейся или готовой задачи? Висит в своем Idle? У Курница сказано "Поэтому хотя бы одна задача должна постоянно находиться в состоянии готовности к выполнению". Или надо явно делать перехват Idle, и там вешать пустой цикл?
3. Начиная с версии 8.2.0 появилась API функция xTaskNotify() и еще несколько, связанных с ней. Беглое чтение документации на англ так и не дало явного понимания, когда это нужно/можно использовать. Если я правильно понял, то это нечто вроде счетного семафора, для запуска задач, когда не требуется быстрого/частого выполнения этой задачи.
1. Очень похожие две сущности. Но
Семафор используется для сигнализирования о событии. Аналог флага. В одном потоке взвели семафор (выдали), другой поток разблокировался, схватив этот семафор. Семафор в нормальном состоянии всегда занят/не выдан. Последовательность работы с ним: отдать -> взять. Часто используется для сигнализировании из прерываний в рабочий таск.
Мьютекс - разделение доступа к общему ресурсу. Тоже аналог флага, но с другой стороны. Потоку нужно доступ к внушней памяти - поток захватывает мьютекс, работает с памятью и отдает мьютекс. Остальные потоки в случае необходимости дождутся освобождения мьютекса. Последовательность работы с мьютексом обратная: взять -> отдать. И в нормальном состоянии мьютекс свободен. У мьютекса есть фишка - наследование приоритетов (У курница об этом написано). Если высокоприоритетная задача пытается захватить мьютекс, занятый низкоприоритетной задачей, то высокоприоритетная задача заблокируется пока низкоприоритетная задача не выполнится и не отдаст мьютекс. Технически приоритет у такой задачи опускается. При использовании мьютекса ядро это видит и повышает низкоприоритетной задаче приоритет до значения, равного той задачи, которая пытается захватить мьютекс, пока этот мьютекс не будет отдан.

Вообще хитросплетения мьютексов и семафоров очень опасно. Можно нарваться на взаимные блокировки, которые не так очевидны.

2. При отсутствии готовых задач ядро себя нормально ведет в ожидании задач, готовых для выполнения. Крутится в своих внутренних лупах. По крайней мере я на это внимания не обращал, ибо все работает без определения хука для idle.
3. Сам до сих пор сижу на V8.0.1. Ленюсь обновиться. Из того, что читал, xTaskNotify() дает весьма оптимальный аналог семафорам
0
HotD
0 / 0 / 0
Регистрация: 05.10.2017
Сообщений: 2,048
04.10.2015, 17:18 7
В процессе возник еще такой вопрос. Есть прерывание UART по приему байта. Необходимо после каждого принятого байта взводить таймаут (условно 50мс), и если таймаут дотикал, значит новых байтов нет, можно обрабатывать входной буфер. Вопрос - как это лучше реализовать средствами FriiRTOS? Логично было бы завести однократный таймер, каждый раз в прерывании ресетить его xTimerRisetFromISR(), и если он всё таки сработал - отдать в обработчике таймера семафор, что данные готовы, для основного таска. Только вот нельзя в обработчике таймера использовать функции связанную с семафорами, очередями и прочим. Как выйти из данной ситуации? Думал может как-то использовать очереди, но кидать данные из UART в очереди на скорости 115200 мне видится не совсем корректной идей.
0
itysiy
0 / 0 / 0
Регистрация: 18.01.2012
Сообщений: 1,418
04.10.2015, 18:07 8
Цитата Сообщение от Hotd
В процессе возник еще такой вопрос. Есть прерывание UART по приему байта. Необходимо после каждого принятого байта взводить таймаут (условно 50мс), и если таймаут дотикал, значит новых байтов нет, можно обрабатывать входной буфер. Вопрос - как это лучше реализовать средствами FriiRTOS? Логично было бы завести однократный таймер, каждый раз в прерывании ресетить его xTimerRisetFromISR(), и если он всё таки сработал - отдать в обработчике таймера семафор, что данные готовы, для основного таска. Только вот нельзя в обработчике таймера использовать функции связанную с семафорами, очередями и прочим. Как выйти из данной ситуации? Думал может как-то использовать очереди, но кидать данные из UART в очереди на скорости 115200 мне видится не совсем корректной идей.
А если использовать хардварный таймер? На каждый принятый байт дергать таймер из прерывания (а это запрет прерываний, системная функция), не очень эффективно и красиво.
И почему именно 50 мс? Какая изначальная задача? Если нужно ловить паузу между пакетами, то может посмотреть на прерывание IDLE? Оно срабатывает после паузы, которая после приема данных. Величина паузы - время отправки одного байта.
0
HotD
0 / 0 / 0
Регистрация: 05.10.2017
Сообщений: 2,048
04.10.2015, 18:18 9
Есть девайс, который просто шлет данные, без спецсимвола конца данных. Логично предположить, что явный признак конца пакета данных - отсутствие новых поступаемых данных в течении таймаута. 50 мс - просто с потолка, реально может пару мс. Сейчас решил следующим образом:
1. Создаю однократный таймер, изначально неактивен
2. В прерывании по принятому байту делаю xTimerRisetFromISR() - название функции в принципе намекает, на использование из прерываний
3. В обработчике таймера просто создаю задачу xTaskCreate(RxComplete,,,,,)
4. В таске RxComplete уже выдаю семафор готовности данных

xTimerRisetFromISR не дергает таймер из прерывания, а лишь обновляет его период. Сейчас такая система работает, пока косяков нет. Не уверен что это правильно, но вроде ничего криминального не делаю.
0
itysiy
0 / 0 / 0
Регистрация: 18.01.2012
Сообщений: 1,418
04.10.2015, 18:35 10
Цитата Сообщение от Hotd
xTimerRisetFromISR не дергает таймер из прерывания, а лишь обновляет его период. Сейчас такая система работает, пока косяков нет. Не уверен что это правильно, но вроде ничего криминального не делаю.
Криминального ничего нет. Двухэтажно получается. Под словом дергает я имел ввиду доступ к данным таймера из прерывания. Это через запрет прерываний. Если не требуется быстрота отклика и контроллер не нагружен, то работать будет нормально.

Только вот нельзя в обработчике таймера использовать функции связанную с семафорами, очередями и прочим.
Можно. Нельзя использовать блокирующие функции и функции до*ступа к очередям, семафорам и мьютексам с ненулевым временем тайм-аута.
Тоесть с нулевым временем таймаута можно. А значит можно выдать семафор. Вся проблема с обработчиками таймеров: они должны быть быстрыми в пределах разумного. Ничего не ждать, не зацикливаться в бесконечные лупы и т.д.
0
HotD
0 / 0 / 0
Регистрация: 05.10.2017
Сообщений: 2,048
05.10.2015, 18:22 11
Да, был неправ, семафор вполне себе можно отдавать в обработчике таймера, переделал код. Хотел еще задать вопрос по heapN.c. Сколько ни читал разных форумов, документации, так и не сложилось явного понимания, где какой стоит применять. Понимаю, что это от недостатка опыта, но все же - какой стоит использовать и почему? Из того что я понял - heap1.c - самый простой, стоит применять, если задачи только создаются, но не удаляются, т.к. память не очищается. Видимо для самых простых задач. С другой стороны - если задача настолько простая, но нужно ли там RTOS? Heap2.c - выделяет и освобождается память, но появляются фрагментированные участки. Если я правильно понимаю, то из этого следует, что стек под задачи (как самая жрущая часть ОС), стоит всегда выделять равного размера, чтобы новые задачи помещались на место старых. Heap3.c работает почти как Heap2.c, но используется родные malloc free, которые оптимальнее всего работают с памятью, но скорость выполнения может сильно плавать. Сейчас сижу на heap2.c, не знаю как оценить подходит мне это или нет, может что-то другое нужно.
0
Sovo
0 / 0 / 0
Регистрация: 05.10.2007
Сообщений: 498
05.10.2015, 19:44 12
А зачем вам создавать задачу в прерывании, чтобы потом убить? Может быть лучше один раз её создать, а потом пусть обрабатывает ваши семафоры. Это быстрее.
0
HotD
0 / 0 / 0
Регистрация: 05.10.2017
Сообщений: 2,048
05.10.2015, 20:30 13
Задача не создается в прерывании, в прерывании лишь ресетится таймер, а уже в его обработчике я отдаю семафор для основного таска, мол данные готовы, можешь работать дальше.
0
itysiy
0 / 0 / 0
Регистрация: 18.01.2012
Сообщений: 1,418
05.10.2015, 21:32 14
2Hotd, я почти всегда использую первую реализацию кучи. Один раз выделяю память и не освобождаю ее. Очень редко сталкиваюсь с необходимостью освобождать ее в процессе работы программы. И даже в эти разы стараюсь обходиться без этого. На ум только приходят связные списки и динамические массивы. Оперативы слишком мало в контроллере, и много надо принимать во внимание, чтобы она во время работы вдруг не кончилась из-за того, что все таски ее одновременно сожрали. Ну и фрагментация, да.
0
HotD
0 / 0 / 0
Регистрация: 05.10.2017
Сообщений: 2,048
12.02.2016, 18:52 15
Возник еще такой вопрос, ответа сходу не нашел. Можно ли два раза удалять одну и ту же задачу? Если у меня задача, условно раз в секунду посылает данные куда-то. Есть еще несколько задач, которые крутятся своим чередом, и при возникновении некоторых условий надо прекратить эту регулярную передачу данных. Если попытаться удалить задачу, которая уже удалена то попадаю в HordFault Homdler. Пытался проверять статус задачи:
Код
if( eTaskGetState(TaskHomdle) != eDeleted)   vTaskDelete(TaskHomdle);
Все равно в HordFault улетаю. Выкрутиться конечно можно, при удалении устанавливать какой-нибудь флаг, что задача удалена, но это как-то кривовато. Стека хватает, создавал голый проект, где пытался два раза удалить одну и ту же задачу.
0
12.02.2016, 18:52
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2018, vBulletin Solutions, Inc.
Рейтинг@Mail.ru