Версия для печати темы

Нажмите сюда для просмотра этой темы в обычном формате

Форум разработчиков электроники ELECTRONIX.ru _ FreeRTOS _ FreeRTOS - минимальное время тика?

Автор: maxntf May 22 2018, 09:36

Всем привет.
На FreeRTOS вертятся 3 задачи, больше ничего из инструментария ОС не пользую.
Так вот когда configTICK_RATE_HZ установлен 1000Hz, все работает без проблем. Меняю это значение на 10000Hz, после ресета все задачи какое то время работают, а потом работает только одна - 2-я задача (скорее работает просто функция). Шедуллер перестает работать вовсе - vApplicationTickHook перестает вызываться и задачи не переключаются.
МК STM32L152rc работает на 16MHz.
В чем может быть дело?
Как отследить где планировщик заткнулся и почему?

Автор: nanorobot May 22 2018, 09:57

Цитата(maxntf @ May 22 2018, 14:36) *
Всем привет.
На FreeRTOS вертятся 3 задачи, больше ничего из инструментария ОС не пользую.
Так вот когда configTICK_RATE_HZ установлен 1000Hz, все работает без проблем. Меняю это значение на 10000Hz, после ресета все задачи какое то время работают, а потом работает только одна - 2-я задача (скорее работает просто функция). Шедуллер перестает работать вовсе - vApplicationTickHook перестает вызываться и задачи не переключаются.
МК STM32L152rc работает на 16MHz.
В чем может быть дело?
Как отследить где планировщик заткнулся и почему?



Может стоит попробовать поочередно в каждой задаче не вызывать ничего иного кроме , например sleep(1000), или как там оно во ФриРтос. (я использую ChibiOs) Таким образом определиться, какая именно задача вешает шедулер, и уж потом исследовать ее под микроскопом.

Автор: haker_fox May 22 2018, 10:24

QUOTE (maxntf @ May 22 2018, 17:36) *
Как отследить где планировщик заткнулся и почему?

1. Воспользоваться JTAG или SWD.
2. Если код задач небольшой, то привести его тут.
3. А есть уверенность, что при тике 1 кГц всё работает правильно?

Автор: k155la3 May 22 2018, 10:31

Цитата(maxntf @ May 22 2018, 12:36) *
. . . .
МК STM32L152rc работает на 16MHz.
В чем может быть дело?
Как отследить где планировщик заткнулся и почему?

Работа самого планировщика не укладывается в период, который Вы задали. Одна задача осталась - в соотв-ии с приоритетом.
Поставьте в каждую задачу "ногодрыг" (а лучше - и в планировщик). Где собака порылась будет видно в реалтайм.

Да, и это. + поставьте равные приоритеты для задач.
Цитата(nanorobot @ May 22 2018, 12:57) *
Может стоит попробовать поочередно в каждой задаче не вызывать ничего иного кроме , например sleep(1000) . . .

Автор: haker_fox May 22 2018, 10:34

QUOTE (k155la3 @ May 22 2018, 18:31) *
Работа самого планировщика не укладывается в период, который Вы задали.

Кстати, ДА! Вспомнил, что когда-то читал о тиках планировщика. В голове отложилось, не делать менее 1 мс. Кстати, использовал эту цифру всегда, начиная с AVR и заканчивая Cortex-M4. Операционки: scmRTOS, FreeRTOS.

Автор: maxntf May 22 2018, 11:27

Цитата(haker_fox @ May 22 2018, 13:24) *
1. Воспользоваться JTAG или SWD.
2. Если код задач небольшой, то привести его тут.
3. А есть уверенность, что при тике 1 кГц всё работает правильно?

Да при тике 1кгц все работает.
2-я задача читает блоками аудио файл с флешь и DMA его пересылает в DAC. Она то и оставалась работать. Я ее отключил.

1-я задача обрабатывает сенсорные кнопки библиотекой touch-sensing library от ST. Собственно вызывает функцию, которая возвращает состояние кнопок. И если кнопка нажата, устанавливает глобальный флаг.
3-я задача проверяет этот флаг, когда он установился, запускает два таймера, один читает IR код с фотоприемника, а второй его передает.

Сразу оговорюсь, с ARM только начал разбираться, так что некоторые мои рассуждения могут быть глупые, не судите строго sm.gif.

Глючит именно пара задач 1 и 3.
Причем если я блокирую одну из них, глюк пропадает.
У меня пока один вариант:
- библиотека touch-sensing library как то конфликтует с FreeRTOS.

Сейчас просматриваю не использует ли она какие то аппаратные ресурсы что и ОС, например SysTickTimer.


Цитата(k155la3 @ May 22 2018, 13:31) *
Работа самого планировщика не укладывается в период, который Вы задали. Одна задача осталась - в соотв-ии с приоритетом.
Поставьте в каждую задачу "ногодрыг" (а лучше - и в планировщик). Где собака порылась будет видно в реалтайм.


В планировщик больше вообще не попадаем после глюка. Надо проверить что там с прерываниями SysTickTimer, которые где то в FreeRTOS

По ходу прерывания SysTick отключаются. Точнее я вижу что в структуре описания этого регистра меняется значение CTRL - при старте CTRL = 0х00000007 / 0х00010007, а после глюка 0х00010005, и больше в прерывание не попадаем. Сейчас поставил частоту 20000Нz и глюк начал проявляться практически сразу.

Автор: k155la3 May 22 2018, 11:43

Кроме всего, проверьте значения стеков задач (не помню, в FreeRTOS он общий или индивидуальные).
В настройках ОС задайте максимум, насколько позволит RAM. Если используются библиотеки - трудно сказать, как они потребляют стековую память.
Вместо "библиотечной" клавиатуры поставьте обычные кнопки или софт-эмулятор или эмулятор через USART.
Клавиатурная задача - самый низкий приоритет. Когда заработает "как надо" - прикрутите.

Цитата
Сразу оговорюсь, с ARM только начал разбираться, так что некоторые мои рассуждения могут быть глупые, не судите строго . . .
Аналогично sm.gif
Цитата
Сейчас просматриваю не использует ли она какие то аппаратные ресурсы что и ОС, например SysTickTimer.
Если есть осцилограф - ловится "на-раз" ногодрыгом.
Можно также под отладчиком поставить контрольную точку по состоянию (изменение) на требуемый регистр.

Автор: maxntf May 22 2018, 11:53

Цитата(k155la3 @ May 22 2018, 14:43) *
Можно также под отладчиком поставить контрольную точку по состоянию (изменение) на требуемый регистр.

В Кеил брекпоинт можно поставить только на весь регистр, вот если бы на изменение бита.sm.gif
Глючит из за библиотеки, там в прерывании таймера, у меня TIM3, вызывается некая функция обработчика этих кнопок. Вот тут то и происходит баг.

Автор: k155la3 May 22 2018, 12:02

Цитата(maxntf @ May 22 2018, 14:53) *
В Кеил брекпоинт можно поставить только на весь регистр, вот если бы на изменение бита.sm.gif
Глючит из за библиотеки, там в прерывании таймера, у меня TIM3, вызывается некая функция обработчика этих кнопок. Вот тут то и происходит баг.
Апп. прерывания надо переносить под FreeRTOS иначе . . .
Соотв-но "напрямую" использовать библиотеки с апп. прерываниями без адаптации - могут быть "варианты". IMHO (чтобы не подрались с прерыванием планировщика).



Автор: maxntf May 22 2018, 12:27

Цитата(k155la3 @ May 22 2018, 15:02) *
Апп. прерывания надо переносить под FreeRTOS иначе . . .
Соотв-но "напрямую" использовать библиотеки с апп. прерываниями без адаптации - могут быть "варианты". IMHO (чтобы не подрались с прерыванием планировщика).

Не понял что значит переносить под FreeRTOS?
Какие могут быть коллизии, если FreeRTOS использует прерывания с самыми высокими приоритетами? Я же обработчик делаю на низкоприоритетных TIM3 приоритет 36, а SysTick приоритет 6;

В общем из за малого опыта, тажело судить что происходит, но причина выявлена - 100% перестает работать SysTick, а соответственно и scheduler который крутится на этом таймере.
Вот только что происходит с SysTick, понять не могу.

Кто может, опишите регистры SysTick или ткните где посмотреть.

PS:
Судя по функции SysTick_Config там всего 3 бита, интуитивно по названиям дефайнов SysTick_CTRL_CLKSOURCE_Msk, SysTick_CTRL_TICKINT_Msk, SysTick_CTRL_ENABLE_Msk. один включает тактирование, второй инициализирует и третий запускает. Вот этот SysTick_CTRL_TICKINT_Msk и сбрасывается. Где не могу поймать. если бы в Кеил можно было установить брекпоинт на запись в бит. Кто знает можно такое?

Автор: esaulenka May 22 2018, 12:44

Цитата(maxntf @ May 22 2018, 15:27) *
В общем из за малого опыта, тажело судить что происходит, но причина выявлена - 100% перестает работать SysTick, а соответственно и scheduler который крутится на этом таймере.
Вот только что происходит с SysTick, понять не могу.



Файлик STMTouch_Driver_um.chm
Раздел STM32L1xx resources used

Цитата
Hardware acquisition mode
GPIOs Acquisition
SysTick Time base for ECS and DTO
Routing interface (RI) Acquisition
2 x 16-bit timers (TIM9, TIM11) Acquisition

Software acquisition mode
GPIOs Acquisition
SysTick Time base for ECS and DTO
Routing interface (RI) Acquisition


Из прерывания SysTick'а они вызывают TSL_tim_ProcessIT().
Должны, во всяком случае.
И, видимо, как-то некорректно работают с
Код
// SysTick enable/disable interrupt macros
#define enableInterrupts()  {SysTick->CTRL |= SysTick_CTRL_TICKINT_Msk;}
#define disableInterrupts() {SysTick->CTRL &= ~SysTick_CTRL_TICKINT_Msk;}

во всяком случае, каких-то других способов отключения таймера я сходу не нашёл.

А вообще - покажите регистры SYSTICK'а после ошибки.
Описание можно посмотреть на http://electronix.ru/redirect.php?http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0552a/Babieigh.html.

Автор: maxntf May 22 2018, 12:58


http://electronix.ru/redirect.php?https://postimages.org/

Я функцию TSL_tim_ProcessIT перенес в TIM3. Возможно у них где то в инициализации есть управление SysTick, буду искать. Спасибо за наводку.

Автор: haker_fox May 22 2018, 13:08

QUOTE (k155la3 @ May 22 2018, 19:43) *
Кроме всего, проверьте значения стеков задач (не помню, в FreeRTOS он общий или индивидуальные).
В настройках ОС задайте максимум, насколько позволит RAM. Если используются библиотеки - трудно сказать, как они потребляют стековую память.

У FreeRTOS свой стек для каждой задачи.

Кстати, автору топика рекомендую включить ловушки на нехватку памяти (настройки оси), использовать configASSERT'ы (настройки ОСИ), а также повесить обработчик на hardfault. Все эти вещи НЕ РАЗ выручали меня при отладке проекта.


QUOTE (maxntf @ May 22 2018, 20:27) *
Не понял что значит переносить под FreeRTOS?
Какие могут быть коллизии, если FreeRTOS использует прерывания с самыми высокими приоритетами? Я же обработчик делаю на низкоприоритетных TIM3 приоритет 36, а SysTick приоритет 6;

На всякий случай)))

Автор: k155la3 May 22 2018, 13:19

Цитата(maxntf @ May 22 2018, 15:27) *
Не понял что значит переносить под FreeRTOS? Какие могут быть коллизии, если FreeRTOS использует прерывания с самыми высокими приоритетами? Я же обработчик делаю на низкоприоритетных TIM3 приоритет 36, а SysTick приоритет 6; . . .
Очевидно, это процессор-зависимое требование. Возможно для ARM и не требуется.
В Demo FreeRTOS serial.c для STM32L152 в обработчике используется макрос portEND_SWITCHING_ISR( . . . ).
Код
void USART3_IRQHandler( void )
{
  . . . . . . . .
    /* If sending or receiving from a queue has caused a task to unblock, and
    the unblocked task has a priority equal to or higher than the currently
    running task (the task this ISR interrupted), then xHigherPriorityTaskWoken
    will have automatically been set to pdTRUE within the queue send or receive
    function.  portEND_SWITCHING_ISR() will then ensure that this ISR returns    <<<
    directly to the higher priority unblocked task. */                                             <<<
    portEND_SWITCHING_ISR( xHigherPriorityTaskWoken );
}

Код
#define portEND_SWITCHING_ISR( xSwitchRequired ) if( xSwitchRequired != pdFALSE ) portYIELD_WITHIN_API()
#define portYIELD_FROM_ISR( x ) portEND_SWITCHING_ISR( x )






Автор: esaulenka May 22 2018, 14:21

Цитата(maxntf @ May 22 2018, 15:58) *
Я функцию TSL_tim_ProcessIT перенес в TIM3. Возможно у них где то в инициализации есть управление SysTick, буду искать. Спасибо за наводку.


Ну вот и включение/выключение прерываний в коде этой тачлиб надо перенести на таймер 3. NVIC_Enable() / NVIC_Disable().

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

Автор: Forger May 22 2018, 17:56

Цитата(maxntf @ May 22 2018, 12:36) *
Меняю это значение на 10000Hz....
МК STM32L152rc работает на 16MHz
В чем может быть дело?

cranky.gif

Даже в толстых проектах никогда не ставлю больше 1000, а обычно вполне хватает 100.
Все остальные более точные времена и задержки следует реализовывать через аппаратные таймера и будить задачи из прерываний флагами или семафорами.

Цитата
Шедуллер перестает работать вовсе - vApplicationTickHook перестает вызываться и задачи не переключаются.

Вангую - в таком режиме либо не хватает основного стека (см. MSP) либо "кончается" стек одной из задач (PSP).
Ставьте контроль стека в настойках freeRTOS, и соотв. ловушки.

Зы. Как stress-test подобный "садизм" с таких космическим соотношением: 16МГц / 10кГц - имхо, вполне годное решение, возьму на вооружение smile3046.gif

Автор: uriy May 23 2018, 04:19

Тоже никогда не делал меньше 1 мс. Зачем вам это понадобилось?

Автор: k155la3 May 23 2018, 08:55

Цитата(uriy @ May 23 2018, 07:19) *
Тоже никогда не делал меньше 1 мс. Зачем вам это понадобилось?
Задачи обработки информации и событий "разложены" недостаточно неэффективно.
может так ?
приоритет High - "RealtimeTask" + IRQ
приоритет Middle - "DriverTask"
приоритет Low - "ApplicationTask"
приоритет LowLow - "GUI_keyb_console_Task"

Автор: Forger May 23 2018, 09:01

Цитата(k155la3 @ May 23 2018, 11:55) *
Задачи обработки информации и событий "разложены" недостаточно неэффективно.

Длительность системного такта не имеет отношения к этому.
Если загрузка СPU достигает 100% (ни разу не запускается IDLE задача), то нужно либо поднимать таковую частоту ядра, либо уменьшать частоту системного таймера ОС.
А правильнее - искать виновника: какая из задач "гадит в общую кастрюлю".
Слепая игра с приоритетами - это как молитвы о спасении умирающему: в самом лучшем случае лишь немного отсрочат неизбежную "кончину" laughing.gif

Автор: maxntf May 23 2018, 10:57

Цитата(haker_fox @ May 22 2018, 16:08) *
Кстати, автору топика рекомендую включить ловушки на нехватку памяти (настройки оси), использовать configASSERT'ы (настройки ОСИ), а также повесить обработчик на hardfault. Все эти вещи НЕ РАЗ выручали меня при отладке проекта.


С памятью все ок!
Ловушки хоть и примитивные - бесконечный цикл (для отладки сгодится) везде стоят: vApplicationStackOverflowHook, HardFault_Handler и т.д.

Цитата(uriy @ May 23 2018, 07:19) *
Тоже никогда не делал меньше 1 мс. Зачем вам это понадобилось?

Я не проект готовый делаю, а только разбираюсь. С STM и FreeRTOS, ранее не работал. Нужно было сделать захват сигнала с частотой 10мкс. Думал попробовать на таймере ОС, вот и поднял частоту. То оказалась глупая затея, а вот баг вылез. Вот и хочу разобраться, чтоб потом таких грабель не было.

Автор: maxntf May 23 2018, 12:16

Нашел костыль.
В функции обработка кнопок есть дефайн отключения а потом включения прерываний.
Там осталось от оригинала управление SysTick:

Код
#define enableInterrupts()  {SysTick->CTRL |= SysTick_CTRL_TICKINT_Msk;}
#define disableInterrupts() {SysTick->CTRL &= ~SysTick_CTRL_TICKINT_Msk;}

, а я кручу тайминг на TIM3.
Только пока не могу понять как это приводит к полному отключению прерываний. Проверил все места где disableInterrupts применяется, всегда есть обратный на включение enableInterrupts, а пока SysTick отключен, планировщик ведь не может передать управление. Дело в том что функция в которой SysTick включается/отключается вызывается из задачи 1, а когда происходит баг, программа весит в задаче 2.

Автор: Forger May 23 2018, 12:25

Цитата(maxntf @ May 23 2018, 15:16) *
Нашел костыль.

Это еще мягко сказано! Это настоящие грабли! smile3046.gif
Впервые вижу такую дичь cranky.gif

Берите готовые решения от FreeRTOS, там есть нужные макросы.

Автор: maxntf May 23 2018, 12:46

Цитата(Forger @ May 23 2018, 15:25) *
Это еще мягко сказано! Это настоящие грабли! smile3046.gif
Впервые вижу такую дичь cranky.gif

Берите готовые решения от FreeRTOS, там есть нужные макросы.


Нужные макросы чего?
Просто эта библиотека TouchSensorLib была заточена под SysTick. Ее нужно перебирать. Только хрена было ее делать под хардтимер не понятно.
Там и так хренова куча настроек, ну добавили бы еще одну по выбору и настройке таймера. Тем более что там нужно только мсек и сек считать и все!

Заделал такое:
Код
#define enableInterrupts()    {NVIC->ISER[TIM3_IRQn >> 0x05] = (uint32_t)0x01 << (TIM3_IRQn & (uint8_t)0x1F);}
#define disableInterrupts()     {NVIC->ICER[TIM3_IRQn >> 0x05] = (uint32_t)0x01 << (TIM3_IRQn & (uint8_t)0x1F);}

Все вроде работает.
Осталось проверить чтоб теперь TIM3 не вис. Если будет виснуть, тогда косяк где то в TouchSensorLib.

Автор: Forger May 23 2018, 12:49

Цитата(maxntf @ May 23 2018, 15:46) *
Нужные макросы чего?

Как чего? Критических секций: пара disableInterrupts/enableInterrupts именно для этого и тут и создана.

Цитата
Просто эта библиотека TouchSensorLib была заточена под SysTick. Ее нужно перебирать.

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

Автор: esaulenka May 23 2018, 19:46

Цитата(maxntf @ May 23 2018, 15:16) *
Нашел костыль.


Сообщения #11 и #15 в этом топике не читали? ладно, следующий раз постараюсь более внятно излагать свои мысли.


Цитата(maxntf @ May 23 2018, 15:16) *
Только пока не могу понять как это приводит к полному отключению прерываний. Проверил все места где disableInterrupts применяется, всегда есть обратный на включение enableInterrupts, а пока SysTick отключен, планировщик ведь не может передать управление. Дело в том что функция в которой SysTick включается/отключается вызывается из задачи 1, а когда происходит баг, программа весит в задаче 2.

Например, если задача 2 более высокоприоритетная, и устроена как-то следующим образом:
while (1) {
wait_mutex(); // queue/...
do_job();
sleep(N);
}
а это внешний мьютекс или элемент из очереди привязан не к SysTick'у, а к какому-то внешнему воздействию, она может проснуться в т.ч. и в тот момент, когда задача 1 находится внутри критической секции. И всё - из sleep'а мы никогда не выйдем...

Автор: jcxz May 23 2018, 22:31

Цитата(maxntf @ May 23 2018, 15:16) *
, а я кручу тайминг на TIM3.

А какой смысл в замене SysTick на TIM3? В Ваш МК SysTick впаять забыли? biggrin.gif

Цитата(esaulenka @ May 23 2018, 22:46) *
она может проснуться в т.ч. и в тот момент, когда задача 1 находится внутри критической секции. И всё - из sleep'а мы никогда не выйдем...

Почему?

Автор: volodya May 24 2018, 04:27

Цитата(jcxz @ May 24 2018, 01:31) *
А какой смысл в замене SysTick на TIM3? В Ваш МК SysTick впаять забыли? biggrin.gif


Почему?


Вот не копал глубоко - при использовании мастера CubeMX + FreeRtos
ПО советует использовать другой кроме SysTic таймер.
"Явление открыл - причин не измышляю"(Ломоносов).

Автор: jcxz May 24 2018, 06:17

Цитата(volodya @ May 24 2018, 07:27) *
Вот не копал глубоко - при использовании мастера CubeMX + FreeRtos

хммм.... Если это так, то это причина не заменить таймер, а выбросить нафиг куб вместе с фриртос-ом (или его кривым портом). laughing.gif

Автор: Forger May 24 2018, 06:27

Цитата(jcxz @ May 24 2018, 09:17) *
вместе с фриртос-ом (или его кривым портом). laughing.gif

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

Автор: Arlleex May 24 2018, 07:28

FreeRTOS работает хорошо и правильно, если с ней правильно работать...
А вот прикручивать таймеры общего назначения вместо специально интегрированного в ядро Cortex-Mx SysTick - ИМХО попахивает аттавизмом из 8-битных микроконтроллеров, где и другого выбора-то не было.

Автор: maxntf May 24 2018, 08:26

Цитата(esaulenka @ May 23 2018, 22:46) *
Сообщения #11 и #15 в этом топике не читали? ладно, следующий раз постараюсь более внятно излагать свои мысли.

Этот пост я проглядел. то есть не совсем проглядел, а проглядывал его с телефона дома, и не особо придал значение коду с дефайнами. После продолжение ветки перешло на второй лист, и туда забыл посмотреть. Но зато комент, где было сказано что тачлиб юзает SysTick натолкнула на мысль, что нужно из нее удалить все упоминания SysTick чтоб она вообще забыла о его существовании.
По этому автору esaulenka отдельное спасибо.

Это все хорошо.
Только мне не понятен один момент, откинув всю лирику о приоритетах задач, концепции FreeRTOS и т.д.
Планировщик, очень сокращенно - это функция которая управляет регистром PC, то есть выбирает куда перекинуть ход выполнения программы.
Он вызывается по прерыванию таймера на котором он работает - SysTick, или через API функции FreeRTOSа.
У меня 3 задачи, не в одной нет никаких API функций, даже делай.
1-я вызывает функцию, которая отключает SysTick и по какой то причине он не включается. Каким образом моя программа оказывается во второй задачи и там висит, потому как SysTick отключен и планировщик больше не вызывается, а API функций в задачах нет, чтоб вызвать планировщик.

P.S. Остается только один вариант - когда 1-я задача включает SysTick, срабатывает прерывание, мы попадаем в планировщик, он передает управление 2-й задаче, и тут по какой то причине SysTick отключается (уже в планировщике).

Автор: Baser May 24 2018, 08:34

Цитата(jcxz @ May 24 2018, 01:31) *
А какой смысл в замене SysTick на TIM3? В Ваш МК SysTick впаять забыли? biggrin.gif

Цитата(volodya @ May 24 2018, 07:27) *
Вот не копал глубоко - при использовании мастера CubeMX + FreeRtos
ПО советует использовать другой кроме SysTic таймер.

При использовании STMовского HAL (CubeMX) + FreeRTOS нужно назначать системный таймер HALа (который формирует сетку 1 мс) на любой другой свободный таймер кроме SysTick. Потому что SysTick монопольно занимает FreeRTOS.
И приоритеты на них назначаются соответственно.
Это подробно описано в доках на HAL, целая глава есть.

А по минимальному тику FreeRTOS тоже встречал рекомендации не делать частоту больше 1000 гц
Из доки на FreeRTOS v9.0 :
Цитата
configTICK_RATE_HZ
Sets the tick interrupt frequency. The value is specified in Hz.
The pdMS_TO_TICKS() macro can be used to convert a time specified in milliseconds to a time specified in ticks. Block times specified this way will remain constant even when the configTICK_RATE_HZ definition is changed. pdMS_TO_TICKS() can only be used when configTICK_RATE_HZ is less than or equal to 1000. The standard demo tasks make extensive use of pdMS_TO_TICKS(), so they too can only be used when configTICK_RATE_HZ is less than or equal to 1000.

То есть, если в ваших библиотеках применяется макрос pdMS_TO_TICKS(), то он будет неправильно считать время.

Автор: maxntf May 24 2018, 09:14

Что то кажется мне, что дело не в тачлиб, во второй задаче у меня используется FatFS, я ее прикрутил и просто читаю файл через SPI. Но сейчас вспоминаю, когда я с ней разбирался (поверхностно) особо на детали внимание не обращал, меня интересовало только чтение файла. Но там ведь где то должны быть часы, чтоб указывать время создания/редактирования файла (по идеи). То есть эта библиотека как то должна работать со временем, а где это делается и настраивается я даже не разбирался. Возможно это вторая задача SysTick останавливает.

P.S.
Хотя вроде нужно самому эти атрибуты заполнять, FatFS за датой не следит, по крайне мере настраивать ее я не находил как. Там есть структура FILINFO, вот пользователь ее сам и заполняет.

Автор: Forger May 24 2018, 09:59

Цитата(maxntf @ May 24 2018, 11:26) *
Только мне не понятен один момент ....

Судя по всему у вас нет не хватает знаний по RTOS, читайте матчасть, она есть на сайте freeRTOS.
В частности примеры применения.
Тогда не придется гадать на кофейной гуще ))


Автор: jcxz May 24 2018, 11:11

Цитата(Forger @ May 24 2018, 09:27) *
вся ось стала монстроподобной и потому не самой шустрой и удобной.

Мне тоже она показалась слишком монстроидальной. Поэтому пользую uCOS-II - она полегче.

Цитата(maxntf @ May 24 2018, 11:26) *
Он вызывается по прерыванию таймера на котором он работает - SysTick, или через API функции FreeRTOSа.

Обычно в РТОС он вызывается не только из ISR таймера и вызовов API OS, но и в других ISR (в которых это разрешено).

Цитата(Baser @ May 24 2018, 11:34) *
При использовании STMовского HAL (CubeMX) + FreeRTOS нужно назначать системный таймер HALа (который формирует сетку 1 мс) на любой другой свободный таймер кроме SysTick. Потому что SysTick монопольно занимает FreeRTOS.

Ну так можно вызвать нужную функцию этого куба из ISR FreeRTOS. Выставить для FreeRTOS 1КГЦ и вызывать.
Нафига козе баян Зачем кста кубу это прерывание? Там своя ОС внутри уже что-ль? wacko.gif

Цитата(maxntf @ May 24 2018, 11:26) *
Планировщик, очень сокращенно - это функция которая управляет регистром PC, то есть выбирает куда перекинуть ход выполнения программы.

Кста: не планировщик (шедулер) перекидывает ход выполнения программы, а переключатель контекста. Если уж на то пошло.
Шедулер только выбирает и назначает какая задача будет выполняться следующей, и возбуждает PendSV, в котором собственно контекст и переключается. Без PendSV ничего никуда не перекинется.

Автор: Forger May 24 2018, 12:03

Цитата(jcxz @ May 24 2018, 14:11) *
Мне тоже она показалась слишком монстроидальной. Поэтому пользую uCOS-II - она полегче.

Тоже смотрел в сторону uCOS, но уже uCOS-III.
Но "вдруг" попалась под руки RTX Keil (теперь она кстати принадлежит ARM), сделана по-уму: все сервисы на SVC, т.е. именно так, как это рекомендуется самой АRM при проектировании ядра.
Работает несколько быстрее FreeRTOS, размера занимает немного меньше. Сравнивал на одном и том же проекте.

Автор: Turnaev Sergey May 24 2018, 13:25

Цитата(Baser @ May 24 2018, 11:34) *
А по минимальному тику FreeRTOS тоже встречал рекомендации не делать частоту больше 1000 гц
Из доки на FreeRTOS v9.0 :

То есть, если в ваших библиотеках применяется макрос pdMS_TO_TICKS(), то он будет неправильно считать время.

На самом деле, сделать частоту тиков выше не проблема. Ну да, придётся переписать пару простых макросов и на этом всё.
Использую в сложном проекте где порядка 60 задач, частоту тиков почти 13кГц, при тактовой 96МГц, отлично работает.

Зачем это надо. Объясняю. Если используете энергосберегающие режимы и режим ticklessIdle, т.е. пропуск тиков, то в сон контроллер уходит не ранее чем через один тик, соответственно чем тик меньше, тем быстрее после выполнения задачи контроллер уснёт.

Цитата(maxntf @ May 24 2018, 11:26) *
Это все хорошо.
Только мне не понятен один момент, откинув всю лирику о приоритетах задач, концепции FreeRTOS и т.д.
Планировщик, очень сокращенно - это функция которая управляет регистром PC, то есть выбирает куда перекинуть ход выполнения программы.
Он вызывается по прерыванию таймера на котором он работает - SysTick, или через API функции FreeRTOSа.
У меня 3 задачи, не в одной нет никаких API функций, даже делай.
1-я вызывает функцию, которая отключает SysTick и по какой то причине он не включается. Каким образом моя программа оказывается во второй задачи и там висит, потому как SysTick отключен и планировщик больше не вызывается, а API функций в задачах нет, чтоб вызвать планировщик.

P.S. Остается только один вариант - когда 1-я задача включает SysTick, срабатывает прерывание, мы попадаем в планировщик, он передает управление 2-й задаче, и тут по какой то причине SysTick отключается (уже в планировщике).

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

Автор: jcxz May 24 2018, 13:59

Цитата(Forger @ May 24 2018, 15:03) *
Работает несколько быстрее FreeRTOS, размера занимает немного меньше. Сравнивал на одном и том же проекте.

Что значит "несколько быстрее"? Изменилась загрузка CPU? И на сколько (в %)?

Автор: Forger May 24 2018, 14:14

Цитата(jcxz @ May 24 2018, 16:59) *
Что значит "несколько быстрее"? Изменилась загрузка CPU? И на сколько (в %)?

Да, загрузка меньше, буквально проценты, но конкретное значение сильно зависит от проекта.
Т.е. если использутся очень много сервисов, то разница получается более заметная.
Полагаю, что все дело в более оптимальной работе шедулера и самих сервисов.
Точные замеры (профилирование) я не делал, ибо такой задачи себе не ставил.
Просто, было принято решение выбора: соскакивать с FreeRTOS или остаться. Выбор пал на первое ))


Ну и вторым доводом сыграло то, что мои проекты не привязаны к какой-то конкретной RTOS (раньше я об этом писал, использую "обертку"), но почти все проекты на ARM-Cortex.
Поэтому тащить чудовищную универсальность в плане портов FreeRTOS для меня просто нет смысла.

Но есть и минус (для меня): пока что нет у Segger порта для их SystemView под эту ось, но дойдут руки сам сделаю или на край дождусь пока на это созреет Segger.
Порты SystemView на FreeRTOS и uCOS есть в комплекте, вполне рабочие. Правда порт SystemView под FreeRTOS пришлось немного допиливать - сыроват он был на тот момент ((

Автор: uriy May 25 2018, 05:04

Цитата
Но есть и минус (для меня): пока что нет у Segger порта для их SystemView под эту ось
А про эту штуку знаете http://electronix.ru/redirect.php?https://electronix.ru/forum/index.php?showtopic=127646 ? Вроде и под ucos ее уже сделали

Автор: Forger May 25 2018, 05:14

Цитата(uriy @ May 25 2018, 08:04) *
А про эту штуку знаете?

Знаем такую, пробовали ))
Но лично мне она вообще не понравилась - вертикальная прокрутка (WTF???), информативность уступает systemview и нет нормальной FREE версии ((

Автор: uriy May 25 2018, 06:12

У меня было такое же мнение о вертикальной прокрутке.
Но сейчас у меня противоложное мнение.

Цитата
нет нормальной FREE версии
А J-link у вас настоящий? Тогда какая разница?
Как в горизонтальной прокрутке вывести столько инфы:

Автор: Forger May 25 2018, 06:17

Цитата(uriy @ May 25 2018, 09:12) *
А J-link у вас настоящий? Тогда какая разница?

Поясните, не пойму связи. J-link-ов в конторе много и нормальные и китай.
Придет время купят и SystemView, но пока 1млн событий (ограничение free версии) хватает в любом нынешнем проекте.

Цитата
Как в горизонтальной прокрутке вывести столько инфы:
В SystemView все события (текст) точно также выводятся c вертикальной прокруткой.
Если щелкнуть на любое событие в окне терминала или событий, то на графике автоматом будет указано место.
Удобно и главное - привычно: ось времени - X, слева направо. Никакой самодеятельности ))


Автор: esaulenka May 25 2018, 07:31

Цитата(Turnaev Sergey @ May 24 2018, 16:25) *
Я правильно понял, что в задачах нет вызовов vTaskDelay()?
В таком случае они всегда будут подвешивать планировщик.

Нет. Если задачи одного приоритета, они будут переключаться по кругу с периодом SYSTICK.
Не самая лучшая идея, но работает.

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

Цитата(jcxz @ May 24 2018, 14:11) *
Нафига козе баян Зачем кста кубу это прерывание? Там своя ОС внутри уже что-ль? wacko.gif


Классика. Пастернака не читал, но осуждаю. Извините.

Автор: jcxz May 25 2018, 19:29

Цитата(esaulenka @ May 25 2018, 10:31) *
Классика. Пастернака не читал, но осуждаю. Извините.

Я конечно извиняю за ваше незнание Пастернака. Но какое он имеет отношение к моему вопросу? wacko.gif

Автор: maxntf May 29 2018, 10:17

Потихоньку разбираюсь далее с FreeRTOS.
Возникла новая проблема, я ее решил но возможно не совсем правильно и не понимаю из за чего так получилось.
Сейчас системный тик 1мсек.
Может кто подскажет?

Есть таймер настроенный на 10мкс, на каждом прерывании он декрементирует глоб. переменную, значение которой задает Task2 (имеет самый высокий приоритет).
Когда переменная = 0, устанавливает семафор, чтоб разбудить задачу, которая установит новое значение переменной.

Код
//Task2
...
        IrState.ctim10ms = IrState.bRxTx[pValue->nComm][0];
        ctx_bit = 1;
        xSemaphoreTake(IrState.xSemNx, 0);
        T10_Init();
        while(ctx_bit <= IrState.cRxTx[pValue->nComm])
        {        
            [b]enableInterruptTIM10();[/b]
            if(xSemaphoreTake(IrState.xSemNx, 25) != pdTRUE) break;
            SwitchPWM;
            IrState.ctim10ms = IrState.bRxTx[pValue->nComm][ctx_bit];
            ctx_bit++;
        }
        T10_DeInit();
...

void TIM10_IRQHandler(void)
{
    static portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
    
    if(TIM_GetFlagStatus(TIM10, TIM_FLAG_Update) != RESET)
    {
        TIM_ClearFlag(TIM10, TIM_FLAG_Update);
        if(IrState.ctim10ms) IrState.ctim10ms--;
        else
        {
            [b]disableInterruptTIM10();[/b]
            xSemaphoreGiveFromISR(IrState.xSemNx, &xHigherPriorityTaskWoken);
            portEND_SWITCHING_ISR(xHigherPriorityTaskWoken);
        }
    }
}

В общем пока я не начал отключать прерывания таймера (в коде выделил), все висло в обработчике таймера и ни одна задача управление не получает.

Автор: jcxz May 29 2018, 10:26

Цитата(maxntf @ May 29 2018, 13:17) *
Есть таймер настроенный на 10мкс, на каждом прерывании он декрементирует глоб. переменную, значение которой задает Task2 (имеет самый высокий приоритет).
...
В общем пока я не начал отключать прерывания таймера (в коде выделил), все висло в обработчике таймера и ни одна задача управление не получает.

Чтобы на столь высоких частотах периодических прерываний работало и не висло, нужно вначале научиться обходиться без куба.
И потрудитесь хотя-бы посчитать каков период прерываний в тактах ядра.

Автор: maxntf May 29 2018, 10:33

Цитата(jcxz @ May 29 2018, 13:26) *
Чтобы на столь высоких частотах периодических прерываний работало и не висло, нужно вначале научиться обходиться без куба.
И потрудитесь хотя-бы посчитать каков период прерываний в тактах ядра.

Где тут куб увидели?
Ядра чего ОС? Если да то я писал 1мсек.

P.S. На всякий случай, частота тактирования МК - 16МГц.

Автор: jcxz May 29 2018, 10:44

Цитата(maxntf @ May 29 2018, 13:33) *
P.S. На всякий случай, частота тактирования МК - 16МГц.

Естественно тактах CPU.
Если не куб, то кубоподбный код: TIM_GetFlagStatus(), TIM_ClearFlag()
у Вас всего 160 тактов между прерываниями, за которые CPU должен успеть кучу всего (откройте листинг и вручную посчитайте такты или то же самое сделайте отладчиком).
Даже если писать нормально (с прямой работой с регистрами IO, без ненужных функций) при такой высокой частоте у Вас CPU только и будет заниматься входами/выходами в ISR - загрузка будет близка к 100%.
А при обнулении счётчика так вообще там у Вас таймер наверняка переполняется и что-то при этом происходит.
Вам надо кардинально пересматривать архитектуру проекта и или повышать частоту CPU или обходиться без таких ВЧ прерываний. И научиться работать с регистрами напрямую, без ненужных обёрток.

Автор: ViKo May 29 2018, 11:04

Цитата(jcxz @ May 29 2018, 13:44) *
у Вас всего 160 тактов между прерываниями, за которые CPU должен успеть кучу всего

1600

Автор: jcxz May 29 2018, 11:07

Цитата(ViKo @ May 29 2018, 14:04) *
1600

А если подумать? rolleyes.gif

Автор: Forger May 29 2018, 11:11

Любого ждет анафема, кто замечен за подобными злодеяниями - изменение глобальных объектов в фоне задачи и в прерываниях.
Допустимо, если будет только чтение таких объектов и оно атомарно (8...32-битное слово).
Как минимум непредсказуемые баги будут на самом ровном месте, а симптомы ни разу не однозначные. Поэтому найти такие баги крайне сложно!

Вот наглядный пример в Вашем коде:

процедура записи нового значения (между знаком "=") прервана прерыванием

Код
//Task2
...
        IrState.ctim10ms = IrState.bRxTx[pValue->nComm][0];
...


в котором будет выполнено это условие?

Код
void TIM10_IRQHandler(void)
{
....
        if(IrState.ctim10ms) IrState.ctim10ms--;
....
}


Зы. ту не поможет ни какая volatile.

Автор: ViKo May 29 2018, 11:11

Цитата(jcxz @ May 29 2018, 14:07) *
А если подумать? rolleyes.gif

10 кГц -> 100 мкс
100 мкс * 16 МГц = 1600 тактов

Автор: jcxz May 29 2018, 11:17

Цитата(ViKo @ May 29 2018, 14:11) *
10 кГц -> 100 мкс
100 мкс * 16 МГц = 1600 тактов

Цитата(maxntf @ May 29 2018, 13:17) *
Есть таймер настроенный на 10мкс,

Автор: ViKo May 29 2018, 11:24

Я думал, речь идет по-прежнему про частоту работы планировщика задач.

Автор: jcxz May 29 2018, 11:29

Цитата(Forger @ May 29 2018, 14:11) *
Любого ждет анафема, кто замечен за подобными злодеяниями - изменение глобальных объектов в фоне задачи и в прерываниях.

Ничего там криминального нет с IrState.ctim10ms, так как в задаче выполняется только запись в неё (хоть объявления IrState.ctim10ms не видно, но думаю что она - одного из встроенных типов), а запись встроенного типа 8/16/32/64 бита на Cortex-M - атомарна.
В ISR выполняется чтение-модификация-запись, приоритет ISR заведомо выше любого таска, так что таск не сможет прерывать ISR. А значит и операции внутри ISR для тасков - атомарны.

Цитата(Forger @ May 29 2018, 14:11) *
Допустимо, если будет только чтение таких объектов и оно атомарно (8...32-битное слово).

Для чтения/записи 64-битных переменных например IAR использует LDRD/STRD, а они тоже атомарны.

Цитата(Forger @ May 29 2018, 14:11) *
процедура записи нового значения (между знаком "=") прервана прерыванием
в котором будет выполнено это условие?
...

И что? Пускай прервана. Она не прервёт посередине операции записи (запись атомарна), а только перед или после.
К тому же как я понимаю: указанный участок внутри таска начнёт выполняться только когда IrState.ctim10ms == 0. А при этом в ISR никакого декремента не делается, только чтение.

Автор: Forger May 29 2018, 13:01

Я же все объяснил на конкретном примере.

Еще раз, но на пальцах:
Пусть IrState.ctim10ms равно, скажем 10, но прерывание еще не возникло и в этот момент выполняется в задаче это кусок:

IrState.ctim10ms = IrState.bRxTx[pValue->nComm][0];

скажем нас прервали как раз перед записью нового значения в IrState.ctim10ms, собирались записать туда 100, которые тока что вычитали из IrState.bRxTx[pValue->nComm][0]

и тут вдруг возникает прерывание, где мы вполняем эту строчку:
if(IrState.ctim10ms) IrState.ctim10ms--;

логично, что после выхода из прерывания будет IrState.ctim10ms = 9,
а тут мы выходим из прерывания и тут же загоняем в IrState.ctim10ms = 100

Не знаю, как это скажется на логике работы прерывания, но явно, что в следующем вызове прерывания вместо 9 вдруг получить 100 - очень странно.
Как себя поведет прога в таком случае остается только гадать.... smile3046.gif


Цитата
К тому же как я понимаю: указанный участок внутри таска начнёт выполняться только когда IrState.ctim10ms == 0.

Ну-ну. Но чуть-чуть поменяли логику и привет? Ловим баги на ровном месте, через час/сутки/год? Тут кому как повезет.

Существуют неписанные правила: доступ к глобальным объектам при чтении-модификации-записи (из задачи) должен быть защищен от любых прерываний, которые могут этот объект изменить посреди этой цепочки.
Для таких случае в простейшем варианте можно использовать критическую секцию.
А в идеале - вообще избегать "дергать" один и тот же глобальный объект из задачи и прерываний. Есть решения.
К тому же нужно постоянно держать в голове - "а что будет, если ... ". Кому нужна доп. головная боль на ровном месте?

В той же MISRA вообще рекомендуют избегать или на край очень осторожно использовать глобальные объекты.
Разумеется, если используются прерывания. Но где их нынче не используют? wink.gif

Автор: jcxz May 29 2018, 13:37

Цитата(Forger @ May 29 2018, 16:01) *
а тут мы выходим из прерывания и тут же загоняем в IrState.ctim10ms = 100

И что???

Цитата(Forger @ May 29 2018, 16:01) *
Не знаю, как это скажется на логике работы прерывания, но явно, что в следующем вызове прерывания вместо 9 вдруг получить 100 - очень странно.

А сколько там должно быть после записи 100? 200 что-ли? smile3046.gif
В чём проблема-то??
В программе написано "записать 100", код это делает? Делает. Никакие прерывания этому не мешают. Так в чём проблема, что Вас смущает?

Цитата(Forger @ May 29 2018, 16:01) *
Существуют неписанные правила: доступ к глобальным объектам при чтении-модификации-записи (из задачи) должен быть защищен от любых прерываний, которые могут этот объект изменить посреди этой цепочки.

Проблема тут только в том, что чтение-модификацию-запись (в задаче) переменной IrState.ctim10ms в указанном примере видите здесь похоже только Вы.... laughing.gif

Автор: Forger May 29 2018, 13:51

Цитата(jcxz @ May 29 2018, 16:37) *
В программе написано "записать 100", код это делает? Делает. Никакие прерывания этому не мешают. Так в чём проблема, что Вас смущает?

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

Короче, я указал на потенциально опасное место в коде.
И связано оно именно с обращениям к одним и тем же глобальным объектам из фона задачи и прерываний БЕЗ соотв. защиты.

Даже, если в самом коде это в данный момент работает, ну, какое-то определенное время работает. Хотя бы в текущей версии.
Если игнорировать эти вещи, то все может стать только хуже, особенно, когда проект практически готов, но сбоит на ровном месте и в самый неожиданный момент.
К тому же, судя по всему, ТС только-только осваивает RTOS и поэтому много может просто не знать. Особенно про такие очень скверные грабли с глобальными объектами.
Или Вы считаете, что это - не грабли, и так делать нормально и безопасно? wink.gif

Автор: jcxz May 29 2018, 14:00

Цитата(Forger @ May 29 2018, 16:51) *
Или Вы считаете, что это - не грабли, и так делать нормально и безопасно? wink.gif

Ещё раз: грабли там видите только Вы.
Никаких проблем (по крайней мере с работой этой переменной) в указанном фрагменте нет.
Сериализация доступа необходима только в случае неатомарных операций с переменной в прерываемом коде. Операции записи базовых типов данных в Cortex-M - все атомарные. Т.е. - в Task2 нет неатомарных операций с IrState.ctim10ms. Критические секции (или подобное) там как собаке пятая нога.

PS: Кто-нить ещё, кроме Forger, видит проблему с работой IrState.ctim10ms ? rolleyes.gif

PPS: ТСу можно разве что посоветовать объявить IrState.ctim10ms с модификатором volatile. Хотя возможно что он уже есть, так как объявления её не приведено.

Автор: Forger May 29 2018, 14:15

Цитата(jcxz @ May 29 2018, 17:00) *
Ещё раз: грабли там видите только Вы.

Опыт! wink.gif

Цитата
Операции записи базовых типов данных в Cortex-M - все атомарные.
Да это тут при чем? Речь совсем про другое!
Про атомарность записи таких маленьких переменных никто ни спорит.
Речь про ИЗМЕНЕНИЕ одного и того же объекта в фоне задач и прерываниях.
Причем в фоне задач еще и производится чтение-модификация-запись, которую можно безопасно прервать в прерывании в одном случае - в нем лишь ЧИТАЕТСЯ объект, но НЕ ИЗМЕНЯЕТСЯ.

Я понимаю, если в прерываниях мы только читаем некую volatile переменную, а меняем ее ТОЛЬКО в фоне задач. Это вполне безопасно.
Повторюсь, если в прерываниях мы НЕ меняем значения этой переменной, а ТОЛЬКО ЧИТАЕМ.

В приведенном примере ситуация другая: одна и та же переменная ИЗМЕНЯЕТСЯ и в фоне задач и в прерываниях.

Я уже не знаю как еще более доходчиво объяснить эти очевидные вещи (((

Автор: maxntf May 29 2018, 14:27

Цитата(jcxz @ May 29 2018, 17:00) *
PPS: ТСу можно разве что посоветовать объявить IrState.ctim10ms с модификатором volatile. Хотя возможно что он уже есть, так как объявления её не приведено.

Проблема не с переменной.
Я не пойму (от незнания) почему висит ОС вот здесь:
Цитата
xSemaphoreGiveFromISR(IrState.xSemNx, &xHigherPriorityTaskWoken);
portEND_SWITCHING_ISR(xHigherPriorityTaskWoken);

В том случае если Task2 еще не дошла до обработки семафора IrState.xSemNx.
То есть глючить начинает когда в прерывании первый раз семафор установили, в задаче его еще не забрали (не успели) и потом в прерывании срабатывают снова эти строки каждые 10мкс. (так как IrState.ctim10ms = 0 и его никто не устанавливает).

Автор: Forger May 29 2018, 14:39

Цитата(maxntf @ May 29 2018, 17:27) *
Проблема не с переменной.
Я не пойму (от незнания) почему висит ОС вот здесь:

В том случае если Task2 еще не дошла до обработки семафора IrState.xSemNx.
То есть глючить начинает когда в прерывании первый раз семафор установили, в задаче его еще не забрали (не успели) и потом в прерывании срабатывают снова эти строки каждые 10мкс. (так как IrState.ctim10ms = 0 и его никто не устанавливает).


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

Этот как готовить первый раз какое-нить новое блюдо - что-то положили, пробуем, анализируем. Но никогда не кладем все сразу скопом к одну кастрюлю )))

Автор: maxntf May 29 2018, 14:44

Цитата(Forger @ May 29 2018, 17:39) *
Для начала попробуйте упростить код до минимум...

Этим и планирую заняться. Попробую добиться глюков на простом коде (если получиться), а потом опишу непонятные мне моменты.

Автор: Arlleex May 29 2018, 14:50

Цитата(jcxz @ May 29 2018, 18:00) *
PS: Кто-нить ещё, кроме Forger, видит проблему с работой IrState.ctim10ms ? rolleyes.gif

Я вижу.

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

Теперь допустим, что переменная RingBuffer_DataCnt была равна 10, и сейчас код выполняется в потоке, вызывается функция чтения байта из кольцевой очереди, и следующая инструкция будет --RingBuffer_DataCnt.
Процессор выполняет чтение данных из памяти в регистр, считал 10, но... Возникло прерывание. Оно вызвало функцию помещения данных в очередь, и выполнила ++RingBuffer_DataCnt.
После выхода из прерывания RingBuffer_DataCnt == 11. Теперь продолжаем выполнять прерванный код - декрементируем число в регистра (получилось 9), и записываем обратно в переменную RingBuffer_DataCnt.

Что получилось? RingBuffer_DataCnt == 9, а по факту их было 10, один байт потеряли. Классическое нарушение атомарности. И никакие атомарные записи LDR/STR тут не при чем, это не 8-битные МК, где требовалось защищать даже саму запись многобайтного числа.
Логично? rolleyes.gif
P.S. Можно не запрещать прерываний (аля критические секции), а использовать для этого специальные конструкции LDREX/STREX, регламентирующие эксклюзивный доступ к памяти.

Автор: jcxz May 29 2018, 15:27

Цитата(Arlleex @ May 29 2018, 17:50) *
...
Что получилось? RingBuffer_DataCnt == 9, а по факту их было 10, один байт потеряли. Классическое нарушение атомарности. И никакие атомарные записи LDR/STR тут не при чем, это не 8-битные МК, где требовалось защищать даже саму запись многобайтного числа.
Логично? rolleyes.gif
P.S. Можно не запрещать прерываний (аля критические секции), а использовать для этого специальные конструкции LDREX/STREX, регламентирующие эксклюзивный доступ к памяти.

Всё что Вы написали, справедливо для случая если операции чтения-модификации-записи есть в прерываемом коде (т.е. - фоновой задаче).
Я уже это писал выше, прочитайте.
Здесь совсем не тот случай. Посмотрите внимательнее на исходный код: в задаче переменная только записывается!. Я на этот уже тоже несколько раз указал Forger.
И Вы что-ли узрели чтение-модификацию-запись в задаче ТС-а? Где??? Неужто только я вижу там только операции записи.
Приведите выдержку где там в фоновой задаче чтение-модификация-запись???

Цитата(Forger @ May 29 2018, 17:15) *
Причем в фоне задач еще и производится чтение-модификация-запись

Где там чтение-модификация-запись в фоновой задаче???
Приведите выдержку.

Цитата(maxntf @ May 29 2018, 17:27) *
Я не пойму (от незнания) почему висит ОС вот здесь:

Проблем может быть вагон. Например - переполнение стека. Или нехватка быстродействия о чём я писал выше.
Снижайте частоту таймера раз в 10 и запрещайте все остальные прерывания. И проверяйте.

Автор: Forger May 29 2018, 16:51

Цитата(jcxz @ May 29 2018, 18:27) *
Где там чтение-модификация-запись в фоновой задаче???

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

Автор: maxntf May 30 2018, 07:05

В общем выкинул все лишнее из программы.
ТО таймера ставил от 10мкс до 1мсек, вообще не влияет.
Если оставить как в коде ниже, не работает. Если раскомментировать вкл/выкл прерывания TIM10 - работает.
Если закомментированть обработку переменно ctim10ms в обработчике прерываний таймера, просто устанавливать семафор на каждом прерывании - то же работает.

Код
void TIM10_IRQHandler(void)
{
    static portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
    
    if(TIM_GetFlagStatus(TIM10, TIM_FLAG_Update) != RESET)
    {
        TIM_ClearFlag(TIM10, TIM_FLAG_Update);
        if(ctim10ms) ctim10ms--;
        else
        {
//disableInterruptTIM10();
            xSemaphoreGiveFromISR(xSemNx, &xHigherPriorityTaskWoken);
            portEND_SWITCHING_ISR(xHigherPriorityTaskWoken);
        }
    }
}

CODE
#define enableInterruptTIM10() NVIC->ISER[TIM10_IRQn >> 0x05] = (uint32_t)0x01 << (TIM10_IRQn & (uint8_t)0x1F)
#define disableInterruptTIM10() NVIC->ICER[TIM10_IRQn >> 0x05] = (uint32_t)0x01 << (TIM10_IRQn & (uint8_t)0x1F)

xSemaphoreHandle xSemNx; //управление задачей
volatile uint32_t ctim10ms; //счетчик отсчетов по 10 мксек

void Tx_Init(void);
void Tx_DeInit (void);

void Task_temp(void *pParams);

int main(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
NVIC_InitTypeDef NVIC_InitStruct;

RCC_HSICmd(ENABLE);
while (RCC_GetFlagStatus(RCC_FLAG_HSIRDY) == RESET);
RCC_SYSCLKConfig(RCC_SYSCLKSource_HSI);

RCC_HSEConfig(RCC_HSE_OFF);
while (RCC_GetFlagStatus(RCC_FLAG_HSERDY) != RESET);

SystemCoreClockUpdate();
SysTick_Config(SystemCoreClock/1000);//TO=1мс

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
NVIC_InitStruct.NVIC_IRQChannel = TIM10_IRQn;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
//NVIC_InitStruct.NVIC_IRQChannelCmd = DISABLE;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 11;
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;
NVIC_Init(&NVIC_InitStruct);

RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE);
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_5;
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_10MHz;
GPIO_Init(GPIOB, &GPIO_InitStruct);


xTaskCreate(Task_temp, "Temp-handler", configMINIMAL_STACK_SIZE, NULL, 2, NULL);

vTaskStartScheduler();

}

void Task_temp(void *pParams)
{
uint32_t c = 0;
vSemaphoreCreateBinary(xSemNx);

while(1){
xSemaphoreTake(xSemNx, 0);
ctim10ms = 100;
Tx_Init();

while(1)
{
//enableInterruptTIM10();
if(xSemaphoreTake(xSemNx, 10) != pdTRUE) break;
c++;
ctim10ms = 100;
GPIO_ToggleBits(GPIOB, GPIO_Pin_5);//пин контроля работы программы
if(c > 200) break;
}
//disableInterruptTIM10();
TIM_DeInit(TIM10);

}
}

void Tx_Init(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;

RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM10, ENABLE);

TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInitStruct.TIM_Period = 160-1;
TIM_TimeBaseInitStruct.TIM_Prescaler = 0;
TIM_TimeBaseInit(TIM10, &TIM_TimeBaseInitStruct);
TIM_ITConfig(TIM10, TIM_IT_Update, ENABLE);
TIM_Cmd(TIM10, ENABLE);
}

Автор: Forger May 30 2018, 07:13

Цитата(maxntf @ May 30 2018, 10:05) *
В общем выкинул все лишнее из программы.

Поменяйте в своем посте теги quote на code, иначе очень трудно читать этот сплошной текст ))
Не совсем понятна фраза "раскомментировать вкл/выкл прерывания TIM10", поясните о каких именно кусках кода идет речь.
Или покажите ДВА куска кода: работающий и неработающий.

Автор: maxntf May 30 2018, 07:17

Цитата(Forger @ May 30 2018, 10:13) *
Поменяйте в своем посте теги quote на code, иначе очень трудно читать этот сплошной текст ))
Не совсем понятна фраза "раскомментировать вкл/выкл прерывания TIM10", поясните о каких именно кусках кода идет речь.
Или покажите ДВА куска кода: работающий и неработающий.

ну в смысле включать и выключать прерывания enableInterruptTIM10() и disableInterruptTIM10() (они в примере закомментированы)

Автор: Forger May 30 2018, 07:23

Цитата(maxntf @ May 30 2018, 10:17) *
ну в смысле включать и выключать прерывания enableInterruptTIM10() и disableInterruptTIM10() (они в примере закомментированы)

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

Автор: maxntf May 30 2018, 07:25

Цитата(Forger @ May 30 2018, 10:23) *
Если закомментировать enableInterruptTIM10(), которые я увидел только в одном месте, то безусловно прерывания от этого таймера работать не будут ))

Не в одном месте.
в прерывании отключаем при установке семафора, в задаче включаем после того как забрали семафор и выполнили обработку.

Автор: Forger May 30 2018, 07:32

Цитата(maxntf @ May 30 2018, 10:25) *
Не в одном месте.

Я смотрю Ваш код, по поиску (CTRL-F) вижу enableInterruptTIM10 только в одном месте ((


Автор: maxntf May 30 2018, 07:35

Привожу проблемные участки кода (инициализация та что в пост №68):
1. Не работает.

CODE
void TIM10_IRQHandler(void)
{
static portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;

if(TIM_GetFlagStatus(TIM10, TIM_FLAG_Update) != RESET)
{
TIM_ClearFlag(TIM10, TIM_FLAG_Update);
if(ctim10ms) ctim10ms--;
else
{
xSemaphoreGiveFromISR(xSemNx, &xHigherPriorityTaskWoken);
portEND_SWITCHING_ISR(xHigherPriorityTaskWoken);
}
}
}

void Task_temp(void *pParams)
{
vSemaphoreCreateBinary(xSemNx);

xSemaphoreTake(xSemNx, 0);
ctim10ms = 10;
Tx_Init();

while(1)
{
xSemaphoreTake(xSemNx, 10);
ctim10ms = 10;
GPIO_ToggleBits(GPIOB, GPIO_Pin_5);//пин контроля работы программы
}

}

2. Работает
CODE
void TIM10_IRQHandler(void)
{
static portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;

if(TIM_GetFlagStatus(TIM10, TIM_FLAG_Update) != RESET)
{
TIM_ClearFlag(TIM10, TIM_FLAG_Update);
if(ctim10ms) ctim10ms--;
else
{
disableInterruptTIM10();
xSemaphoreGiveFromISR(xSemNx, &xHigherPriorityTaskWoken);
portEND_SWITCHING_ISR(xHigherPriorityTaskWoken);
}
}
}

void Task_temp(void *pParams)
{
vSemaphoreCreateBinary(xSemNx);

xSemaphoreTake(xSemNx, 0);
ctim10ms = 10;
Tx_Init();

while(1)
{
enableInterruptTIM10();
xSemaphoreTake(xSemNx, 10);
ctim10ms = 10;
GPIO_ToggleBits(GPIOB, GPIO_Pin_5);//пин контроля работы программы
}

}

3.Работает
CODE
void TIM10_IRQHandler(void)
{
static portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;

if(TIM_GetFlagStatus(TIM10, TIM_FLAG_Update) != RESET)
{
TIM_ClearFlag(TIM10, TIM_FLAG_Update);
xSemaphoreGiveFromISR(xSemNx, &xHigherPriorityTaskWoken);
portEND_SWITCHING_ISR(xHigherPriorityTaskWoken);

}
}

void Task_temp(void *pParams)
{
vSemaphoreCreateBinary(xSemNx);

xSemaphoreTake(xSemNx, 0);
Tx_Init();

while(1)
{
xSemaphoreTake(xSemNx, 10);
GPIO_ToggleBits(GPIOB, GPIO_Pin_5);//пин контроля работы программы
}

}

Автор: jcxz May 30 2018, 07:36

Цитата(maxntf @ May 30 2018, 10:05) *
Если оставить как в коде ниже, не работает. Если раскомментировать вкл/выкл прерывания TIM10 - работает.

Я не знаю что делает xSemaphoreGiveFromISR() во FreeRTOS, подозреваю что переводит семафор в сигнальное состояние.
Если так, то зачем Вы её вызываете всегда когда ctim10ms==0 ? ctim10ms обнулилась и после этого вы начинаете долбить семафор постоянно. Зачем???
Достаточно один раз вызвать xSemaphoreGiveFromISR().
При частоте таймера ==100кГц и частоте ядра==16МГц, у Вас как только обнуляется ctim10ms, то потом в каждом прерывании вызывается xSemaphoreGiveFromISR(), а так как она наверняка длительная (и следующая за ней функция - скорей всего ещё более длительная, так как скорей всего в ней делается решедулинг задач), то к моменту выхода из ISR успевает пройти >= 160 тактов ядра. А значит - ждёт уже новое прерывание таймера и сразу снова входит в ISR и всё повторяется. Естественно, что всё блокируется на постоянных входах в ISR и на выполнение фоновой задачи времени не остаётся
Я Вам на это намекал ещё в самом первом посте, когда советовал посчитать кол-во тактов, но Вы почему то не читаете советы (чукча не читатель? зачем тогда спрашивать?).
Вызывать xSemaphoreGiveFromISR() нужно только один раз. Например так:
CODE
static u8 volatile ctim10ms = 0;
void ISR()
{
...
int i = ctim10ms;
if (--i < 0) return;
ctim10ms = i;
if (i) return;
xSemaphoreGiveFromISR(...);
portEND_SWITCHING_ISR(...);
}

PS: Всё сказанное справедливо если я догадался правильно и xSemaphoreGiveFromISR() - перевод семафора в сигнальное состояние, а portEND_SWITCHING_ISR() - уведомление к ОС о выходе из ISR с требованием решедулинга задач.

PPS: И как Вам уже посоветовали тут - используйте тег codebox для длинных примеров кода (как в этом сообщении), а не code. Иначе ваши портянки трудно пролистывать. И меньше народу будут читать сообщения.

Автор: maxntf May 30 2018, 07:51

Цитата(Forger @ May 30 2018, 10:32) *
Я смотрю Ваш код, по поиску (CTRL-F) вижу enableInterruptTIM10 только в одном месте ((

Да так и есть. Включаем, когда готовы принимать семафор.

Цитата(jcxz @ May 30 2018, 10:36) *
При частоте таймера ==100кГц и частоте ядра==16МГц, у Вас как только обнуляется ctim10ms, то в каждом прерывании вызывается xSemaphoreGiveFromISR(), а так как она наверняка длительная (и следующая за ней функция - скорей всего ещё более длительная, так как скорей всего делается решедулинг задач), то к моменту выхода из ISR успевает пройти >= 160 тактов ядра. А значит - ждёт уже новое прерывание таймера и сразу снова входит в ISR и всё повторяется. Естественно, что всё блокируется на постоянных входах в ISR.


Ага. Но только если я долблю таймером xSemaphoreGiveFromISR без обработки переменной каждые 10мкс все работает. xSemaphoreGiveFromISR() не должна повторно устанавливать семафор пока задача его не заберет, соответственно возвращает FALSE и portEND_SWITCHING_ISR ничего не переключает.
Код
#define portEND_SWITCHING_ISR( xSwitchRequired ) if( xSwitchRequired != pdFALSE ) portYIELD()




Я как бы увидел что происходит.
В неработающем варианте
Код
xSemaphoreGiveFromISR(xSemNx, &xHigherPriorityTaskWoken);

всегда возвращается pdTREU - соответственно постоянно перевызывается планировщик - почему так?

Автор: Arlleex May 30 2018, 08:05

Цитата(maxntf @ May 30 2018, 11:51) *
Да так и есть. Включаем, когда готовы принимать семафор.
Я как бы увидел что происходит.
В неработающем варианте
Код
xSemaphoreGiveFromISR(xSemNx, &xHigherPriorityTaskWoken);

всегда возвращается pdTREU - соответственно постоянно перевызывается планировщик - почему так?

Потому что задача находится в состоянии READY и готова к выполнению.
Приведите пожалуйста файл настройки FreeRTOSConfig.h.

Цитата(maxntf @ May 30 2018, 11:51) *
xSemaphoreGiveFromISR() не должна повторно устанавливать семафор пока задача его не заберет, соответственно возвращает FALSE и portEND_SWITCHING_ISR ничего не переключает.

Нет. Это означает, что после выдачи семафора планировщик не видит задач, готовых к выполнению, находящихся в состоянии READY, поэтому решедулинга задач не производится.

Автор: maxntf May 30 2018, 08:06

Все разобрался, не верно обрабатывал семафор.
Нужно было так:

Код
void TIM10_IRQHandler(void)
{
    static portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
    
    if(TIM_GetFlagStatus(TIM10, TIM_FLAG_Update) != RESET)
    {
        TIM_ClearFlag(TIM10, TIM_FLAG_Update);
        if(ctim10ms) ctim10ms--;
        else
        {
            if(xSemaphoreGiveFromISR(xSemNx, &xHigherPriorityTaskWoken) != pdFAIL) portEND_SWITCHING_ISR(1);
        }
    }
}


Осталось понять нафиг xHigherPriorityTaskWoken.
И почему во всех примерах так
Код
            xSemaphoreGiveFromISR(xSemNx, &xHigherPriorityTaskWoken);
            portEND_SWITCHING_ISR(xHigherPriorityTaskWoken);

А у меня не работает?

P.S.
Все понял.
У меня задача всегда READY. Но в нее не успеваем попасть, и все время выполняем решедулинг!

Автор: Arlleex May 30 2018, 08:17

Код
if(xSemaphoreGiveFromISR(xSemNx, &xHigherPriorityTaskWoken) != pdFAIL) portEND_SWITCHING_ISR(1);

Да не правильно так делать!

Проверять на возвращаемое значение выдачи семафора - зачем? Да и portEND_SWITCHING_ISR(1) не с 1 должно быть, а с xHigherPriorityTaskWoken.
Семафор Вы можете выдавать всегда сколько раз угодно - другое дело, что пока задача его не заберет, выдать его Вы не сможете.
Повысьте тактовую частоту CPU и проверьте еще раз свой нерабочий вариант. У меня на F4 приблизительно похожая задача, и все прекрасно успевает и обрабатывается как нужно.

Автор: maxntf May 30 2018, 08:25

Цитата(Arlleex @ May 30 2018, 11:17) *
Код
if(xSemaphoreGiveFromISR(xSemNx, &xHigherPriorityTaskWoken) != pdFAIL) portEND_SWITCHING_ISR(1);

Да не правильно так делать!

Проверять на возвращаемое значение выдачи семафора - зачем? Да и portEND_SWITCHING_ISR(1) не с 1 должно быть, а с xHigherPriorityTaskWoken.
Семафор Вы можете выдавать всегда сколько раз угодно - другое дело, что пока задача его не заберет, выдать его Вы не сможете.
Повысьте тактовую частоту CPU и проверьте еще раз свой нерабочий вариант. У меня на F4 приблизительно похожая задача, и все прекрасно успевает и обрабатывается как нужно.

В моем случае не совсем так.
у меня запускается планировщик, где то по середине прерывается, и запускается снова и так бесконечно. Так как задача всегда READY, но семафор обработать не успевает.
Конкретно в моем варианте нужно так:
Код
void TIM10_IRQHandler(void)
{
    static portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE, fGiveResult = pdFALSE;
    
    if(TIM_GetFlagStatus(TIM10, TIM_FLAG_Update) != RESET)
    {
        TIM_ClearFlag(TIM10, TIM_FLAG_Update);
        if(ctim10ms) ctim10ms--;
        else
        {
            fGiveResult = xSemaphoreGiveFromISR(xSemNx, &xHigherPriorityTaskWoken);
            portEND_SWITCHING_ISR(xHigherPriorityTaskWoken & fGiveResult);
        }
    }
}


P.S.
На своей плате поднять частоту я не могу (на данный момент), а пропустить несколько отсчетов по 10мкс. в данном случае не критично и всегда можно подкорректировать.
Задача в первую очередь была понять почему так, а путей решения всегда бывает больше чем один!

Автор: jcxz May 30 2018, 08:32

Цитата(maxntf @ May 30 2018, 11:25) *
На своей плате поднять частоту я не могу (на данный момент), а пропустить несколько отсчетов по 10мкс. в данном случае не критично и всегда можно подкорректировать.
Задача в первую очередь была понять почему так, а путей решения всегда бывает больше чем один!

Я вам уже несколько раз объяснил и пример дал, но вы так и не поняли.... и опять всё то же самое накатали. Да ещё какой-то бред добавили с ПОБИТОВЫМ ИЛИ между логическими (видимо) типами...

Автор: maxntf May 30 2018, 13:03

На семафоре полностью развязать задачу я не смог, а вот с очередями получилось.
Реальная задача динамически запускается и удаляется примерно на сотню миллисекунд - передает команду через ИК диод.
В общем сделал так, все работает без проблем на любой частоте таймера.

Код
void TIM10_IRQHandler(void)
{
    static portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE, fGiveResult = pdFALSE;
    
    if(TIM_GetFlagStatus(TIM10, TIM_FLAG_Update) != RESET)
    {
        TIM_ClearFlag(TIM10, TIM_FLAG_Update);
        if(ctim10ms) ctim10ms--;
        else
        {
            fGiveResult = xQueueSendToBackFromISR(xQueue, (const void *)0, &xHigherPriorityTaskWoken);
            if(xHigherPriorityTaskWoken & fGiveResult)
            {
                portEND_SWITCHING_ISR(xHigherPriorityTaskWoken);
            }
                else cal_ctim10ms++;
        }
    }
}
void Task_temp(void *pParams)
{
    uint32_t newValue = 100;
    uint32_t q_buf;
    
    xQueue = xQueueCreate(1, sizeof(uint32_t));


    ctim10ms = newValue;
    Tx_Init();

    while(1)
    {
        xQueuePeek(xQueue, &q_buf, 10);
    taskENTER_CRITICAL();
        ctim10ms = newValue - cal_ctim10ms;
        cal_ctim10ms = 0;
    taskEXIT_CRITICAL();
        GPIO_ToggleBits(GPIOB, GPIO_Pin_5);//пин контроля работы программы
        xQueueReceive(xQueue, &q_buf, 0);
    }
}

Если кто объяснит почему так нельзя приведя реальный пример как нужно - респект!

Автор: Forger May 30 2018, 13:06

Цитата(maxntf @ May 30 2018, 16:03) *
Если кто объяснит почему так нельзя приведя реальный пример как нужно - респект!

Очередь (Queue) в данном случае - как из пушки по воробьям.


Чтобы избежать таких детских граблей:
Код
if(xHigherPriorityTaskWoken & fGiveResult)

это следует писать хотя бы так:
Код
if( (xHigherPriorityTaskWoken != 0) && (fGiveResult != 0))

Вы вообще понимаете разницу между операторами & и && ?

Самый главный косяк, разрешать себе делать так: if(some) { ... }.
Это допустимо только для одного случая some есть bool, но в таких случаях эту some лучше называть иначе, чтобы было проще читать, например: bool isRxDone = что_то_что_возвращает true/false;
Тогда всякие условия читаются в разы проще: if (isRxDone) { ... }

Если же речь идет про все остальные типы, которые анализируются в блоке if {} else, то их сравнение следует указывать явно (number != 0), и обязательно брать в скобки, если в одном блоке if проверяются более одного значения.

Автор: maxntf May 30 2018, 13:29

Цитата(Forger @ May 30 2018, 16:06) *
Очередь (Queue) в данном случае - как из пушки по воробьям.

Я спроси конкретный пример! А то все пишете плохо да плохо.

Цитата(Forger @ May 30 2018, 16:06) *
Вы вообще понимаете разницу между операторами & и && ?
Самый главный косяк, разрешать себе делать так: if(some) { ... }.

Отлично понимаю и вообще косяка не вижу. Поразрядное И с однотипными данными в условии, что тут такого!

Автор: Forger May 30 2018, 13:33

Цитата(maxntf @ May 30 2018, 16:29) *
Я спроси конкретный пример!

Конкретные примеры скачивайте с сайта freeRTOS.

Цитата
А то все пишете плохо да плохо.
Все просто - так оно и есть wink.gif

Цитата
Отлично понимаю и вообще косяка не вижу. Поразрядное И с однотипными данными в условии, что тут такого!
Вот с этого бреда и нужно было начинать тему. Дальше можно не продолжать, все ясно.

Напоследок. Вот так будет работать правильно:
Код
if ( (xHigherPriorityTaskWoken != pdFALSE) && (fGiveResult != pdFALSE) )

Автор: maxntf May 30 2018, 13:50

Цитата(Forger @ May 30 2018, 16:33) *
Напоследок. Вот так будет работать правильно:
Код
if ( (xHigherPriorityTaskWoken != pdFALSE) && (fGiveResult != pdFALSE) )


#define pdFALSE ( ( BaseType_t ) 0 )
#define pdTRUE ( ( BaseType_t ) 1 )
typedef long BaseType_t;

xHigherPriorityTaskWoken и fGiveResult могут быть только 0x00000000 или 0x00000001

(xHigherPriorityTaskWoken & fGiveResult) в результате даст либо 0 либо 1
if(0) нет
if(1) да

P.S.
Ваш вариант с точки зрения читабельности, верный.
Фактически в данном случае мой вариант рабочий и перед тем чтоб такое написать я проверил что там за типы данных и какие значения принимают. Так пишу потому что последнее время писал только под pic с очень малым flash и приходилось очень много вот так подтачивать чтоб все влезло. Ваш код займет больше места, особенно если таких сравнений будет много.

Автор: Forger May 30 2018, 14:14

Цитата(maxntf @ May 30 2018, 16:50) *
xHigherPriorityTaskWoken и fGiveResult могут быть только 0x00000000 или 0x00000001
Ну-ну ...
Мануалы читать - не Ваше.
Вот: http://electronix.ru/redirect.php?https://www.freertos.org/xQueueSendToBackFromISR.html
Цитирую строчку для особе упертых: "pdTRUE if the semaphore was successfully given, otherwise errQUEUE_FULL"

Цитата
Ваш код займет больше места, особенно если таких сравнений будет много.

Мля, что за идиотская привычка пошла у начинающих программеров экономить на спичках, плодя потенциальны места для будущих багов!!! cranky.gif
Забудьте про PIC и начинайте уже писать код так, как это делают остальные, без такой адской самодеятельности и оптимизаций!

Автор: maxntf May 30 2018, 14:30

Не тот пример был.

Автор: esaulenka May 30 2018, 15:30

Цитата(Forger @ May 30 2018, 16:06) *
Очередь (Queue) в данном случае - как из пушки по воробьям.

Расскажите пожалуйста, чем отличается очередь и семафор.
Напомню (и это важно!) мы по прежнему про FreeRTOS, а не о сферическом коне, как тут принято.

Автор: Forger May 30 2018, 15:34

Цитата(esaulenka @ May 30 2018, 18:30) *
Расскажите пожалуйста, чем отличается очередь и семафор.
Напомню (и это важно!) мы по прежнему про FreeRTOS, а не о сферическом коне, как тут принято.

http://electronix.ru/redirect.php?https://www.freertos.org/Inter-Task-Communication.html

Автор: esaulenka May 30 2018, 17:15

Никакой конкретики. Отлично.
Ещё раз. Пожалуйста, расскажите своё видение отличий очереди и семафора.
Что вижу я: макрос vSemaphoreCreateBinary вызывает xQueueGenericCreate, макрос xSemaphoreGive вызывает функцию xQueueGenericSend.
Т.е. внутри что семафор, что очередь из одного элемента отличаются минимально.

А теперь расскажите, почему эту очередь maxntf ни в коем случае использовать не должен.

Автор: Forger May 30 2018, 17:31

Цитата(esaulenka @ May 30 2018, 20:15) *
...

"Разжевать и положить в рот"? Нет, я пас. Извините, но мы не в ясельной группе!
Если вы сами до сих пор еще не разобрались, где какой сервис RTOS нужно использовать, а где какой будет избыточен, то я ни как Вам не смогу помочь.
В качестве "домашнего задания": подумайте, зачем в RTOS существует такое разноообразие сервисов?

Автор: maxntf May 30 2018, 17:58

Цитата(esaulenka @ May 30 2018, 20:15) *
Никакой конкретики. Отлично.
Ещё раз. Пожалуйста, расскажите своё видение отличий очереди и семафора...
А теперь расскажите, почему эту очередь maxntf ни в коем случае использовать не должен.

Опыта с freertos мало, точнее нет. Работал только с кооперативной ОС OSA, под pic_и, там все проще. По этому не смог сделать нужное мне на семафорах, в частности мне нужно было задачу разблокировать , а семафор забрать уже так, чтоб посреди этой функции снова не влететь в прерывание. А вот с очередями получилось, так как там можно прочитать сообщение не забирая его тем самым разблокировать задачу, а потом забрать когда задача будет к этому готова.

Цитата(Forger @ May 30 2018, 20:31) *
В качестве "домашнего задания": подумайте, зачем в RTOS существует такое разноообразие сервисов?

Чтоб народ с ума сводить sm.gif. Чем дальше углубляюсь, тем больше вижу, что там куча всего через дефайны дублируется.

Автор: Forger May 30 2018, 18:27

Цитата(maxntf @ May 30 2018, 20:58) *
Чтоб народ с ума сводить sm.gif. Чем дальше углубляюсь, тем больше вижу, что там куча всего через дефайны дублируется.

Это во FreeRTOS они все сделаны можно сказать "через одну щель", потому и не славится эта RTOS особой производительностью и малым размером. Но зато под нее существует порт практически под любой проц.
Увы, такова плата за универсальность и поддержку немереного числа платформ.

В самом начале пути можно делать как угодно: и через зад лечить зубы и через нос зашивать пятку.
Но потом все равно придется делать как надо ))

Автор: Arlleex May 30 2018, 19:41

Взял отладку на STM32F429, повторил код автора топика.

Код
int main(void)
{
    HW_MCUInit();
    
    SampleSemaphoreHandle = xSemaphoreCreateBinary();
    
    xTaskCreate(&SampleHandlingTask, "SampleHandlingTask", 512, NULL, SAMPLE_HANLING_TASK_PRIORITY, &SampleHandlingTaskHandle);
    
    vTaskStartScheduler();
    
    return 0;
}

Код
void SampleHandlingTask(void *Parameters)
{
    HW_TIMER_START();
    
    while(1)
    {
        xSemaphoreTake(SampleSemaphoreHandle, 10);
        
        unsigned int ReshedulingTime = DWT_CYCCNT - CYCCNT_ISR_Vale;

        ctim10ms = 10;
        
        GPIOG->ODR ^= GPIO_Pin_13;
    }
}

Код
volatile unsigned int ctim10ms = 10000;
volatile unsigned int CYCCNT_ISR_Vale = 0;

void TIM1_UP_TIM10_IRQHandler(void)
{
    static BaseType_t xHigherPriorityTaskWoken = pdFALSE;
    
    if(TIM1->SR & TIM_IT_Update)
    {
        if(ctim10ms)
            ctim10ms--;
        else
        {
            xSemaphoreGiveFromISR(SampleSemaphoreHandle, &xHigherPriorityTaskWoken);
            portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
            
            CYCCNT_ISR_Vale = DWT_CYCCNT;
        }
        TIM1->SR = (uint16_t)~TIM_IT_Update;
    }
}

Не работает (вернее работает через ж*пу - светодиод еле видно - но, видимо, переключается).
Ставлю таймер на 100мкс, все работает. Отлично - открываю отладчик, запускаю код в нем. Отключаю работу таймера при отладке, чтобы не поломалась система и результаты были честными.

В теле задачи ставлю точку останова на
Код
ctim10ms = 10;

и результат 256 тактов CPU тратит на работу переключателя контекста.

256/16000000Гц = 16мкс.

Далее точно также посчитаем, сколько выполняется тело цикла прерывания: 40 тактов в случае, если ctim10ms отличен от 0 и вызовов xSemaphoreGiveFromISR() не производится, и 356 тактов в случае, если ctim10ms достигло 0 и были вызваны сервисы RTOS выдачи семафора. Добавим ко всему этому по 12 тактов на вход/выход в прерывание (предполагаем, что tail-chaining и late-arriving не запускаются в связи с непериодичностью): итого 64 и 380 тактов соответственно. В микросекундах это 4 и 23.75 соответственно при синхронизации CPU от 16МГц. О какой нафиг тут периодичности прерываний 10мкс может идти речь - не пойму. У Вас за 23.75мкс сформируется еще 2 прерывания, которые Вы пропустите и обработаете как одно.

P.S. Поднял частоту работы системы - и теперь 10мкс прерывания работают отлично, что и требовалось доказать.
А Ваши старания с очередью... Ну не уверен я, что оно работает действительно так, как задумано.

Автор: jcxz May 30 2018, 20:05

Цитата(Arlleex @ May 30 2018, 22:41) *
Взял отладку на STM32F429, повторил код автора топика.
...
О какой нафиг тут периодичности прерываний 10мкс может идти речь - не пойму. У Вас за 23.75мкс сформируется еще 2 прерывания, которые Вы пропустите и обработаете как одно.

Пролистайте тему выше. Ещё в 47-м, 49-м и 75-м сообщениях тут я писал об этом. Тут даже отладка не нужна - и так всё очевидно. Но "чукча не читатель, чукча писатель"...... laughing.gif

Автор: Arlleex May 30 2018, 20:15

Цитата(jcxz @ May 30 2018, 23:05) *
Пролистайте тему выше. Ещё в 47-м, 49-м и 75-м сообщениях тут я писал об этом. Тут даже отладка не нужна - и так всё очевидно. Но "чукча не читатель, чукча писатель"...... laughing.gif

Мне просто было интересно поковырять, пока еда готовится biggrin.gif
Но где-то внутри тоже предполагал, что времени не хватает просто...

Автор: maxntf May 31 2018, 13:15

Всем участникам спасибо за помощь и в некоторых случаях за "мат". Кое как вроде разобрался, что то может не до понял, в дальнейшем процессе освоения дойдет.
Остался один не решенный момент, а именно макрос

Код
portEND_SWITCHING_ISR(xHigherPriorityTaskWoken);


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

Но судя по отладке это не так.
Кто может без нервов разжевать, как оно работает?

Автор: Arlleex May 31 2018, 13:44

Цитата(maxntf @ May 31 2018, 17:15) *
В начале я думал, что он работает следующим образом.

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

Автор: maxntf May 31 2018, 13:46

Цитата(Arlleex @ May 31 2018, 16:44) *
Еще раз прошу, скиньте файл FreeRTOSConfig.h

Вот пожалуйста.
Код
#define configTICK_RATE_HZ                        ( ( TickType_t ) 1000 )
#define configCPU_CLOCK_HZ                        ( SystemCoreClock )
#define configUSE_PREEMPTION                    1
#define configUSE_PORT_OPTIMISED_TASK_SELECTION    1
#define configUSE_IDLE_HOOK                        1
#define configUSE_TICK_HOOK                        1
#define configMAX_PRIORITIES                    ( 5 )
#define configMINIMAL_STACK_SIZE                ( ( unsigned short ) 170 )
#define configTOTAL_HEAP_SIZE                    ( ( size_t ) ( 14 * 1024 ) )
#define configMAX_TASK_NAME_LEN                    ( 16 )
#define configUSE_TRACE_FACILITY                1
#define configUSE_16_BIT_TICKS                    0
#define configIDLE_SHOULD_YIELD                    1
#define configUSE_MUTEXES                        1
#define configQUEUE_REGISTRY_SIZE                5
#define configCHECK_FOR_STACK_OVERFLOW            2
#define configUSE_RECURSIVE_MUTEXES                1
#define configUSE_MALLOC_FAILED_HOOK            1
#define configUSE_APPLICATION_TASK_TAG            0
#define configUSE_COUNTING_SEMAPHORES            1

/* Software timer related definitions. */
#define configUSE_TIMERS                        1
#define configTIMER_TASK_PRIORITY                ( configMAX_PRIORITIES - 1 )
#define configTIMER_QUEUE_LENGTH                10
#define configTIMER_TASK_STACK_DEPTH            configMINIMAL_STACK_SIZE

/* Co-routine definitions. */
#define configUSE_CO_ROUTINES             0
#define configMAX_CO_ROUTINE_PRIORITIES ( 2 )

/* Set the following definitions to 1 to include the API function, or zero
to exclude the API function. */

#define INCLUDE_vTaskPrioritySet        1
#define INCLUDE_uxTaskPriorityGet        1
#define INCLUDE_vTaskDelete                1
#define INCLUDE_vTaskCleanUpResources    0
#define INCLUDE_vTaskSuspend            1
#define INCLUDE_vTaskDelayUntil            1
#define INCLUDE_vTaskDelay                1

/* Standard assert semantics. */
//#define configASSERT( x ) if( ( x ) == 0 ) { taskDISABLE_INTERRUPTS(); for(;; ); }    

/* Use the system definition, if there is one */
#ifdef __NVIC_PRIO_BITS
    #define configPRIO_BITS       __NVIC_PRIO_BITS
#else
    #define configPRIO_BITS       4        /* 15 priority levels */
#endif

#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY            15
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY    5

/* The lowest priority. */
#define configKERNEL_INTERRUPT_PRIORITY     ( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
/* Priority 5, or 95 as only the top four bits are implemented. */
/* !!!! 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     ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )

/* Run time stats related macros. */
#define configGENERATE_RUN_TIME_STATS    0

/* Definitions that map the FreeRTOS port interrupt handlers to their CMSIS
standard names. */
#define vPortSVCHandler SVC_Handler
#define xPortPendSVHandler PendSV_Handler
#define xPortSysTickHandler SysTick_Handler

Автор: Arlleex May 31 2018, 14:05

Ну вроде в порядке все, только определены ли у Вас функции-ловушки всех установленных опций? Я про IdleHook, TickHook и т.д.
Как проверяете, что RTOS не переключается на задачу с самым высоким приоритетом?

Автор: maxntf May 31 2018, 14:13

Цитата(Arlleex @ May 31 2018, 17:05) *
Ну вроде в порядке все, только определены ли у Вас функции-ловушки всех установленных опций? Я про IdleHook, TickHook и т.д.

Код
void vApplicationIdleHook(void)
{
    //HOOK_PULSE;
}
void vApplicationStackOverflowHook(TaskHandle_t xTask, char *pcTaskName)
{
    for(;;);
}
void vApplicationTickHook(void)
{
    
}
void vApplicationMallocFailedHook(void)
{
    for(;;);
}

#define HOOK_PULSE GPIO_ToggleBits(GPIOB, GPIO_Pin_5) - это вывод пина на осциллограф, когда нужно что то проверить. А так они IdleHook, TickHook пока у меня пустые.
Цитата(Arlleex @ May 31 2018, 17:05) *
Как проверяете, что RTOS не переключается на задачу с самым высоким приоритетом?

Шагаю по прерыванию, а после выхода из обработчика прерывания вываливаюсь в Task2 (точнее в тело функции которую она периодически вызывает) с низким приоритетом (приоритет 1) а Task1 который ждет семафор (только у меня событие из очереди) приоритет 2.

Автор: Arlleex May 31 2018, 15:05

Код
xQueuePeek(xQueue, &q_buf, 10);
    taskENTER_CRITICAL();
        ctim10ms = newValue - cal_ctim10ms;
        cal_ctim10ms = 0;
    taskEXIT_CRITICAL();
        GPIO_ToggleBits(GPIOB, GPIO_Pin_5);//пин контроля работы программы
        xQueueReceive(xQueue, &q_buf, 0);

А зачем два раза подряд вызывать ожидающие функции xQueuePeek() и xQueueReceive() причем подряд?
Как-то не корректно Вы с очередью работаете...
xQueuePeek() считает значение из очереди, но не удалит его оттуда.
xQueueReceive() тоже считает, но удалит (FIFO).
Почему просто не вызывать xQueueReceive()?

Автор: maxntf Jun 1 2018, 09:18

Цитата(Arlleex @ May 31 2018, 18:05) *
А зачем два раза подряд вызывать ожидающие функции xQueuePeek() и xQueueReceive() причем подряд?
Как-то не корректно Вы с очередью работаете...
xQueuePeek() считает значение из очереди, но не удалит его оттуда.
xQueueReceive() тоже считает, но удалит (FIFO).
Почему просто не вызывать xQueueReceive()?

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

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

В частности сейчас у меня проблема, что не работает portEND_SWITCHING_ISR(xHigherPriorityTaskWoken);
Докопался portYIELD(), понял что он устанавливает флаг прерывания PendSV, в котором ОС выполняет переключение контекста.

А теперь о моих баранах. В Task2(с низким приоритетом) у меня вызывается функция F1() с той самой тачлиб что фигурировала в начале темы. Так вот после выхода из обработчика прерывания в котором вызывался portEND_SWITCHING_ISR(xHigherPriorityTaskWoken), программа попадает в место из картинки. Получается что флаг прерывания PendSV был установлен когда судя по записи __disable_irq() все прерывания били отключены.
http://electronix.ru/redirect.php?https://postimages.org/


Убрал нафиг эти __disable_irq() и __enable_irq(). Но все равно не работает.

Как бы в отладчике узнать включено ли прерывание для PendSV?

P.S.
Кстати у меня с калибровкой на 10мкс все работало четко, только потому, что не переключается контекст и время на это не тратится и все успевает. Вот так бывает sm.gif

Автор: Forger Jun 1 2018, 10:39

Цитата(maxntf @ Jun 1 2018, 12:18) *
По этому просьба больше не писать что я туплю и делаю не так.

Дык, тогда и не пишите тут то, что вызывает такую реакцию, кстати, вполне естественную реакцию laughing.gif

зы. "По этому" в данном случае пишется слитно biggrin.gif


Автор: maxntf Jun 1 2018, 10:53

Цитата(Forger @ Jun 1 2018, 13:39) *
Дык, тогда и не пишите тут то, что вызывает такую реакцию, кстати, вполне естественную реакцию


Так вот...
Упростил как мог, все выкинул никаких тачлибов и всего остального, только 2 задачи.
Код
xSemaphoreHandle xSem1ms;    
volatile uint32_t ctim100us;    
uint8_t FlagCreateTask;
void TIM10_IRQHandler(void)
{
    static portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
    
    if(TIM_GetFlagStatus(TIM10, TIM_FLAG_Update) != RESET)
    {
        TIM_ClearFlag(TIM10, TIM_FLAG_Update);
        if(ctim100us) ctim100us--;
        else
        {
            xSemaphoreGiveFromISR(xSem1ms, &xHigherPriorityTaskWoken);
            portEND_SWITCHING_ISR(xHigherPriorityTaskWoken);
        }
    }
}
int main(void)
{    
    xTaskCreate(Task2, "Task2-handler", configMINIMAL_STACK_SIZE, NULL, 1, NULL);    
    vTaskStartScheduler();
}
void Task2(void *pParams)
{

    FlagCreateTask = 0;
    vSemaphoreCreateBinary(xSem1ms);

    xTaskCreate(Task1, "Task1-handler", configMINIMAL_STACK_SIZE, NULL, 2, NULL);
    while(1)
    {
        if(FlagCreateTask != 0) continue;
        xTaskCreate(Task1, "Task1-handler", configMINIMAL_STACK_SIZE, NULL, 2, NULL);
    }
}
void Task1(void *pParams)
{
    uint16_t count = 3;

    xSemaphoreTake(xSem1ms, 0);
    FlagCreateTask = 1;

    ctim100us = count;
    Tx_Init();

    while(1)
    {
        if(xSemaphoreTake(xSem1ms, 10) != pdTRUE) continue;
        count++;
        if(count > 9) break;
    taskENTER_CRITICAL();
        ctim100us = count;
    taskEXIT_CRITICAL();
        GPIO_ToggleBits(GPIOB, GPIO_Pin_5);//пин контроля работы программы
    }
    TIM_DeInit(TIM10);
    FlagCreateTask = 0;
    vTaskDelete(NULL);
}


После выхода из обработчика прерывания TIM10 в случае выполнения portEND_SWITCHING_ISR(xHigherPriorityTaskWoken) программа попадает в Task2.
О Боже, за что?
Даже таймер настроен на 100мкс

Автор: Forger Jun 1 2018, 11:08

Цитата(maxntf @ Jun 1 2018, 13:53) *
Так вот...

Судя по всему, у обеих задач одинаковые приоритеты.
А Task2 вообще ВСЕГДА готова к выполнения.
Т.е. всегда что-то делает...
Более того, честно говоря, я чуть моск не сломал, пока попытался понять логику работы "флажка" FlagCreateTask wacko.gif
Так нифига и не понял, что вы задумали (((

А вообще, прочитайте, наконец, нормальный мануал, как писать проекты под RTOS, посмотрите видео на ютубе, примеры из мануала и т. п.
Посмотрите примеры применения, конкретные рабочие примеры. Желательно это делать перед тем, как плодить франкешнейнов самодеятельность, и уж тем более тут это публиковать wink.gif

FreeRTOS запускается с полпинка и работает как и любая друга RTOS, но необходимы хотя бы базовые знания. Решите сначала этот вопрос!
Уверяю, ничего сверхсложного тут нет, все через это прошли ))

Немного упрощу задачу. Вот яркий пример откровенной самодеятельности:
Код
    while(1)
    {
        if(FlagCreateTask != 0) continue;
        xTaskCreate(Task1, "Task1-handler", configMINIMAL_STACK_SIZE, NULL, 2, NULL);
    }


Автор: maxntf Jun 1 2018, 11:34

Цитата(Forger @ Jun 1 2018, 14:08) *
Судя по всему, у обеих задач одинаковые приоритеты.


Судя по чему конкретно?
Код
xTaskCreate(Task2, "Task2-handler", configMINIMAL_STACK_SIZE, NULL, 1, NULL);
xTaskCreate(Task1, "Task1-handler", configMINIMAL_STACK_SIZE, NULL, 2, NULL);


Цитата(Forger @ Jun 1 2018, 14:08) *
А вообще, прочитайте, наконец, нормальный мануал, как писать проекты под RTOS...


Какие проекты, я про конкретный случай спрашиваю.
Убрал то, что моск ломает.
Код
void Task2(void *pParams)
{
    vSemaphoreCreateBinary(xSem1ms);
    xTaskCreate(Task1, "Task1-handler", configMINIMAL_STACK_SIZE, NULL, 2, NULL);
    while(1);
}
void Task1(void *pParams)
{
    xSemaphoreTake(xSem1ms, 0);
    ctim100us = 10;
    Tx_Init();
    xSemaphoreTake(xSem1ms, 10);    
    TIM_DeInit(TIM10);
    vTaskDelete(NULL);
}


Если задачи с одинаковым приоритетом, почему? Может где то настройки FreeRTOS?
Если Task2 всегда готова к выполнению, то когда срабатывает portEND_SWITCHING_ISR(xHigherPriorityTaskWoken) разве после выхода из прерывания контекст не должен переключится с Task2 на Task1?

Автор: Forger Jun 1 2018, 11:46

Цитата(maxntf @ Jun 1 2018, 14:34) *
Код
xTaskCreate(Task2, "Task2-handler", configMINIMAL_STACK_SIZE, NULL, 1, NULL);
xTaskCreate(Task1, "Task1-handler", configMINIMAL_STACK_SIZE, NULL, 2, NULL);

Исходя из мануала
Task1 имеет приоритет выше, чем Task2. Признаю, тут я не доглядел (( .... Ненавижу функции с числом параметров больше одного-двух - невозможно разобраться без мануала sad.gif

Цитата
Убрал то, что моск ломает.
Уже проще wink.gif

Цитата
Может где то настройки FreeRTOS?
Еще раз на всякий случай приведите настройки (в теге CODEBOX).

Автор: maxntf Jun 1 2018, 11:53

Цитата(Forger @ Jun 1 2018, 14:46) *
Еще раз на всякий случай приведите настройки (в теге CODEBOX).

Для проверки работы приоритетов поменял приоритеты задач - программа в Task1 вообще не попадает, значит приоритеты работают.
CODE


#define configTICK_RATE_HZ ( ( TickType_t ) 1000 )
#define configCPU_CLOCK_HZ ( SystemCoreClock )
#define configUSE_PREEMPTION 1
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
#define configUSE_IDLE_HOOK 1
#define configUSE_TICK_HOOK 1
#define configMAX_PRIORITIES ( 5 )
#define configMINIMAL_STACK_SIZE ( ( unsigned short ) 120 )
#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 12 * 1024 ) )
#define configMAX_TASK_NAME_LEN ( 16 )
#define configUSE_TRACE_FACILITY 1
#define configUSE_16_BIT_TICKS 0
#define configIDLE_SHOULD_YIELD 1
#define configUSE_MUTEXES 1
#define configQUEUE_REGISTRY_SIZE 5
#define configCHECK_FOR_STACK_OVERFLOW 2
#define configUSE_RECURSIVE_MUTEXES 1
#define configUSE_MALLOC_FAILED_HOOK 1
#define configUSE_APPLICATION_TASK_TAG 0
#define configUSE_COUNTING_SEMAPHORES 1

/* Software timer related definitions. */
#define configUSE_TIMERS 1
#define configTIMER_TASK_PRIORITY ( configMAX_PRIORITIES - 1 )
#define configTIMER_QUEUE_LENGTH 10
#define configTIMER_TASK_STACK_DEPTH configMINIMAL_STACK_SIZE

/* Co-routine definitions. */
#define configUSE_CO_ROUTINES 0
#define configMAX_CO_ROUTINE_PRIORITIES ( 2 )

/* Set the following definitions to 1 to include the API function, or zero
to exclude the API function. */

#define INCLUDE_vTaskPrioritySet 1
#define INCLUDE_uxTaskPriorityGet 1
#define INCLUDE_vTaskDelete 1
#define INCLUDE_vTaskCleanUpResources 0
#define INCLUDE_vTaskSuspend 1
#define INCLUDE_vTaskDelayUntil 1
#define INCLUDE_vTaskDelay 1

/* Standard assert semantics. */
//#define configASSERT( x ) if( ( x ) == 0 ) { taskDISABLE_INTERRUPTS(); for( ;; ); }

/* Use the system definition, if there is one */
#ifdef __NVIC_PRIO_BITS
#define configPRIO_BITS __NVIC_PRIO_BITS
#else
#define configPRIO_BITS 4 /* 15 priority levels */
#endif

#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 15
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 5

/* The lowest priority. */
#define configKERNEL_INTERRUPT_PRIORITY ( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
/* Priority 5, or 95 as only the top four bits are implemented. */
/* !!!! configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to zero !!!!
See http://electronix.ru/redirect.php?http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html. */
#define configMAX_SYSCALL_INTERRUPT_PRIORITY ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )

/* Run time stats related macros. */
#define configGENERATE_RUN_TIME_STATS 0

/* Definitions that map the FreeRTOS port interrupt handlers to their CMSIS
standard names. */
#define vPortSVCHandler SVC_Handler
#define xPortPendSVHandler PendSV_Handler
#define xPortSysTickHandler SysTick_Handler

#endif /* FREERTOS_CONFIG_H */

Автор: Forger Jun 1 2018, 12:01

Создайте сразу две задачи (можно с разными приоритетами),
воткните в бесконечный цикл каждой задачи что-нибудь для постановки ее в очередь ожидания, например sleep(1) (или что там используется у freertos).

Поставьте по одному бряку внутри задач 1 и 2 и см. как идет процесс переключения задач.

Они должны переключаться по очереди.

Далее добавляйте свой код по чуть-чуть и смотрите, что сыпется от него.

Автор: maxntf Jun 1 2018, 15:21

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

Автор: Forger Jun 1 2018, 17:06

Цитата(maxntf @ Jun 1 2018, 18:21) *
Похоже отладчик всему беда.

Что же за отладчик такой, если не секрет?

Автор: maxntf Jun 2 2018, 12:04

Цитата(Forger @ Jun 1 2018, 20:06) *
Что же за отладчик такой, если не секрет?

Тот что в Keil.
Причем только в пошаговом режиме кнопками Step или Step Over при выходе из обработчика прерываний.
А если поставить брекпоинты в задачах, и выйти из прерывания Step Out или Run тогда попадаем куда нужно, то есть в Task2.

Автор: Forger Jun 2 2018, 12:17

Цитата(maxntf @ Jun 2 2018, 15:04) *
Тот что в Keil.
Причем только в пошаговом режиме кнопками Step или Step Over при выходе из обработчика прерываний.
А если поставить брекпоинты в задачах, и выйти из прерывания Step Out или Run тогда попадаем куда нужно, то есть в Task2.

Оптимизацию отключите, хотя бы для debug сборки. При пошаговой отладке она только вредит.
Или как вариант - ходить не по C/C++ исходникам, а в по командам в окне disasm.

И вообще, изучайте инструмент, а то вон 8 страниц наплодили по сути на пустом месте sm.gif

Автор: maxntf Jun 2 2018, 12:45

Цитата(Forger @ Jun 2 2018, 15:17) *
Оптимизацию отключите, хотя бы для debug сборки. При пошаговой отладке она только вредит.
Или как вариант - ходить не по C/C++ исходникам, а в по командам в окне disasm.

Оптимизация стоит Level 0, и сделал я это сразу после установки кейла. Никогда оптимизацию не использую.
Да хоть по Cи, хоть по disasm. Был бы disbasic sm.gif думаю так же работал.

Эта реплика к чему?
Цитата(Forger @ Jun 2 2018, 15:17) *
И вообще, изучайте инструмент, а то вон 8 страниц наплодили по сути на пустом месте sm.gif

Где про это сказано?

Автор: Forger Jun 2 2018, 12:50

Цитата(maxntf @ Jun 2 2018, 15:45) *
Оптимизация стоит Level 0, и сделал я это сразу после установки кейла. Никогда оптимизацию не использую.

Вангую, что переключение задачи на активную происходит лишь при отработке прерывания системного таймера.
Если это так, то это в корне неправильно, нужно разбираться, почему так в Вас работает.
Я с таким "багом" столкнулся в старой TNKernel, что, кстати, заставило ее поменять на другую ртос - как раз на freeRTOS
В ней такого "бага" нет. Это я сразу проверил, как только освоил. В ней все работает как надо. Но с настройками повозился, к слову, отключил нафик динамическую память (у freeRTOS есть свой типа диспетчер дин. памяти)

Если весь код состоит из макросов (define), то старый компилятор кейла (v5) не умеет ходить по макросам. Новый v6 умеет.
Возможно, тут есть проблемы.

К проекту подключены исходники freeRTOS или заранее собранная библиотека (lib)?

Автор: maxntf Jun 2 2018, 13:07

Цитата(Forger @ Jun 2 2018, 15:50) *
Вангую, что переключение задачи на активную происходит лишь при отработке прерывания системного таймера.

Нет.
Поставил 3 брекпоинта. Task1, Task2 и в xPortSysTickHandler.
Сразу попадаем в Task1.

P.S.
Возможно я ошибаюсь, но что то мне подсказывает, что по функции Step и Step Over отладчик не может попасть в прерывание, а собственно это и должно произойти после выход из обработчика прерывания TIM10, программа должна попасть в PendSV Handler.

Автор: Моисей Самуилович Jun 2 2018, 13:17

Цитата(maxntf @ Jun 2 2018, 16:07) *
Нет.
Поставил 3 брекпоинта. Task1, Task2 и в xPortSysTickHandler.
Сразу попадаем в Task2.

P.S.
Возможно я ошибаюсь, но что то мне подсказывает, что по функции Step и Step Over отладчик не может попасть в прерывание, а собственно это и должно произойти после выход из обработчика прерывания TIM10.

Ну значит задача просто закончила свою работу и сама вызвала диспетчер. Никакой мистики.
Так все операционки устроены

Автор: Forger Jun 2 2018, 13:21

Цитата(maxntf @ Jun 2 2018, 16:07) *
Нет.
Поставил 3 брекпоинта. Task1, Task2 и в xPortSysTickHandler.
Сразу попадаем в Task2.

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

И приведите код этого "проекта" (в теге CODEBOX)

Цитата(Моисей Самуилович @ Jun 2 2018, 16:17) *
Ну значит задача просто закончила свою работу и сама вызвала диспетчер. Никакой мистики. Так все операционки устроены

© "Слышу звон, да не знаю, где он" sm.gif

Автор: maxntf Jun 2 2018, 13:24

И наконец поставил четвертый брекпоинт в xPortPendSVHandler.
Нахожусь на строчке portEND_SWITCHING_ISR(xHigherPriorityTaskWoken).
2 раза нажимаю Step, попадаю в Task1.
А нажимаю Run, попадаю вначале в xPortPendSVHandler, снова Run и на Task2 на строку после xSemaphoreTake

Автор: Forger Jun 2 2018, 13:30

На всякий случай посмотрите, останавливается ли счет таймера (TIM10 вроде) в режиме отладки? Есть битик для этой цели.
Из-за этого возможно, пока идете по шагам, заново входите в прерывание таймер, не успев попасть PendSV.

Я тоже замечал, что отладка по шагам в Keil работает несколько "странно", что ли. Поэтому предпочитаю работать в лоб - бряки + Run.

Автор: maxntf Jun 2 2018, 13:58

Цитата(Forger @ Jun 2 2018, 16:30) *
На всякий случай посмотрите, останавливается ли счет таймера (TIM10 вроде) в режиме отладки? Есть битик для этой цели.
Из-за этого возможно, пока идете по шагам, заново входите в прерывание таймер, не успев попасть PendSV.


Я даже уже перед выполнением:
Код
xSemaphoreGiveFromISR(xSem1ms, &xHigherPriorityTaskWoken);
portEND_SWITCHING_ISR(xHigherPriorityTaskWoken);

Отключаю прерывания TIM10

Вот весь проект, убрал все лишнее и переименовал задачи, номер задачи соответствует приоритету, а то я и сам уже начал путаться.
CODE

xSemaphoreHandle xSem1ms;
void Task1(void *pParams);
void Task2(void *pParams);

void TIM10_IRQHandler(void)
{
portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
if(TIM_GetFlagStatus(TIM10, TIM_FLAG_Update) != RESET)
{
NVIC->ICER[TIM10_IRQn >> 0x05] = (uint32_t)0x01 << (TIM10_IRQn & (uint8_t)0x1F);
xSemaphoreGiveFromISR(xSem1ms, &xHigherPriorityTaskWoken);
portEND_SWITCHING_ISR(xHigherPriorityTaskWoken);
}
}
int main(void)
{
NVIC_InitTypeDef NVIC_InitStruct;

RCC_HSICmd(ENABLE);
while (RCC_GetFlagStatus(RCC_FLAG_HSIRDY) == RESET);
RCC_SYSCLKConfig(RCC_SYSCLKSource_HSI);
RCC_HSEConfig(RCC_HSE_OFF);
while (RCC_GetFlagStatus(RCC_FLAG_HSERDY) != RESET);

SystemCoreClockUpdate();

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
NVIC_InitStruct.NVIC_IRQChannel = TIM10_IRQn;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 14;
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;
NVIC_Init(&NVIC_InitStruct);

xTaskCreate(Task1, "Task1-handler", configMINIMAL_STACK_SIZE, NULL, 1, NULL);
vTaskStartScheduler();

}
void Task1(void *pParams)
{
xTaskCreate(Task2, "Task2-handler", configMINIMAL_STACK_SIZE, NULL, 2, NULL);
while(1);
}
void Task2(void *pParams)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;

vSemaphoreCreateBinary(xSem1ms);
xSemaphoreTake(xSem1ms, 0);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM10, ENABLE);
TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInitStruct.TIM_Period = 16000 - 1;
TIM_TimeBaseInitStruct.TIM_Prescaler = 0;
TIM_TimeBaseInit(TIM10, &TIM_TimeBaseInitStruct);
TIM_ClearFlag(TIM10, TIM_FLAG_Update);
TIM_ITConfig(TIM10, TIM_IT_Update, ENABLE);
TIM_Cmd(TIM10, ENABLE);

xSemaphoreTake(xSem1ms, 100);
vTaskDelete(NULL);
}


И на всякий случай заново опишу ситуацию.
Со строчки portEND_SWITCHING_ISR(xHigherPriorityTaskWoken) если шагами, попадаем в Task1 - цикл while(1);
А если через Run, то попадаем в Task2 на строку vTaskDelete(NULL);

P.S.
И напоследок. Проверил свое убеждение, что командами Step отладчик не попадает в прерывание, а Run попадает. Проверил на том же TIM10. Включил его, сразу установил флаг прерывания - если пройти его шагами, программа дальше пойдет не попадая в прерывания. А если через Run, то в прерывания попадает.

Возможно 9 листов "ереси" того стоило? sm.gif
Уверен что не каждый, тем более начинающий об этом знает. И шагая по программе нужно учитывать что в это время могло произойти прерывание и жизнь пошла бы по другому.

Автор: Forger Jun 2 2018, 14:15

Цитата(maxntf @ Jun 2 2018, 16:58) *
Возможно 9 листов "ереси" того стоило? sm.gif
Уверен что не каждый, тем более начинающий об этом знает. И шагая по программе нужно учитывать что в это время могло произойти прерывание и жизнь пошла бы по другому.

Ну, тогда можно с уверенностью сказать, что тема себя исчерпала sm.gif

Автор: Arlleex Jun 2 2018, 18:00

Пардон, читал уже между строк почти последние дни и не заметил, что ТС нажимает Single Step.
В режиме пошаговой отладки отладчик локально запрещает прерывания, поэтому даже если возникает любое прерывание (насчет системных исключений не уверен) - в обработчик прерывания Вы не попадете. И это правильно - иначе Вы не отладите нормально код. При Step Over и Run обработчики по-любому будут работать как надо (полагаю, у ТС так и есть). Я когда-то тоже http://electronix.ru/redirect.php?https://electronix.ru/forum/index.php?showtopic=138085 на такие чудеса, но со временем понял, что это более, чем правильное поведение отладчика...

Автор: maxntf Jun 2 2018, 19:44

Цитата(Arlleex @ Jun 2 2018, 21:00) *
...но со временем понял, что это более, чем правильное поведение отладчика...

Не имею ни капли сомнения, что оно и правильно, и даже уже понимаю зачем. Со всей уверенностью считаю, что ребята которые все это разрабатывали по умнее всех нас вместе взятых. Хотел написать, что о такой фиче, нужно упоминать через каждую страницу мануала. А потом призадумался, может это такой тактический ход, для тех кто не особо любитель почитать? (пишу о себеsm.gif). Пока это все разгребал, докапался до таких вещей, что неизвестно когда бы ещё специально лез в эти дебри.
Но... Было бы чудесно, если бы отладчик спросил, делать переход по вектору прерывания или нет. Это очень удобно для освоения, когда начинающий ещё не знает куда должна пойти программа, и хочет по шагать.

Автор: Arlleex Jun 2 2018, 19:50

Цитата(maxntf @ Jun 2 2018, 22:44) *
Не имею ни капли сомнения, что оно и правильно, и даже уже понимаю зачем. Со всей уверенностью считаю, что ребята которые все это разрабатывали по умнее всех нас вместе взятых. Хотел написать, что о такой фиче, нужно упоминать через каждую страницу мануала. А потом призадумался, может это такой тактический ход, для тех кто не особо любитель почитать? (пишу о себеsm.gif). Пока это все разгребал, докапался до таких вещей, что неизвестно когда бы ещё специально лез в эти дебри.
Но... Было бы чудесно, если бы отладчик спросил, делать переход по вектору прерывания или нет. Это очень удобно для освоения, когда начинающий ещё не знает куда должна пойти программа, и хочет по шагать.

IAR это позволяет. Именно при пошаговой отладке (у него есть для этого специальная галочка).

Автор: Forger Jun 2 2018, 19:50

Цитата(maxntf @ Jun 2 2018, 22:44) *
Это очень удобно для освоения, когда начинающий ещё не знает куда должна пойти программа, и хочет по шагать.

Начинающему нет особый нужды ходит по шагам под отладчиком, гуляя по прерываниям: поставил куб и вперед и с песней sm.gif

Русская версия Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)