Перейти к содержанию
    

FreeRTOS не переключает задачи после одного цикла, FRDM-KL27Z

28 минут назад, Forger сказал:

Код действительной примитивный, за исключением скрытых граблей в ввиде PRINTF, который тут врядли полностью reentrant. Да и стек жрет он весьма непредсказуемо. И не исключено, что тут он даже обращается к куче ...

printf не reentrant может бить только в плане целевого устройства вывода. Но для многозадачной версии stdlib для этого устройства должна быть сделана reentrant-обёртка в самой stdlib. А от самого пользователя нужно только правильно указать компилятору на необходимость этого.

Хотя сам я нигде не использую printf конечно.....

28 минут назад, Forger сказал:

 


class CriticalSection
{
public:
	inline CriticalSection() __attribute__((always_inline)) { __asm volatile ("CPSID i"); }
	inline ~CriticalSection() __attribute__((always_inline)) { __asm volatile ("CPSIE i"); }
};

Это - простейшая реализация, без запоминания предыдущего состояния флажков разрешения прерываний. Но если используется RTOS, то она как раз самое то.

Имхо - очень неудачный вариант.

Во-первых: сохранять состояние (в общем случае) - нужно обязательно. Иначе - придётся просматривать все функции, вызываемые внутри такой секции, на всю глубину вызова на предмет наличия там аналогичный секций. А это - просто вселенские грабли: если вдруг понадобится в одной из таких функций вставить аналогичную к.секцию, то придётся просматривать весь код который её использует. И причём - на всю иерархию вызовов до самого верха, до main (данной задачи). Да и вообще - а как тогда вообще вызывать функции, которые внутри имеют такие же к.секции?

Во-вторых: неужто у Вас весь код настолько простейший, что количество входов в к.секцию равно количеству выходов из неё??? У меня в большинстве случаев использования к.секций это нет так - чаще всего бывает один вход и несколько выходов из к.секции. И что в этом случае прикажете делать с конструкторами/деструкторами? Но даже если кол-во входов равно кол-ву выходов, то как быть если нужно внутри одной функции несколько раз входить и выходить из к.секции? На каждый такой случай делать отдельный блок {} и внутри него определять собственный объект класса? Это будет форменное захламление исходника и снижение читаемости.

И как быть в случае:

CriticalSectionEnter();

if (...) {

  ...

  CriticalSectionExit();

  ...

  CriticalSectionEnter();

  ...

}

...

CriticalSectionExit();

 

PS: Нет уж - лучше внимательнее просматривать код.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

41 minutes ago, jcxz said:

printf не reentrant может бить только в плане целевого устройства вывода. Но для многозадачной версии stdlib для этого устройства должна быть сделана reentrant-обёртка в самой stdlib. А от самого пользователя нужно только правильно указать компилятору на необходимость этого.

Но судя по всему, далеко не все об этом знают ;)

 

Quote

Имхо - очень неудачный вариант.

Во-первых: сохранять состояние (в общем случае) - нужно обязательно. Иначе - придётся просматривать все функции, вызываемые внутри такой секции, на всю глубину вызова на предмет наличия там аналогичный секций. А это - просто вселенские грабли: если вдруг понадобится в одной из таких функций вставить аналогичную к.секцию, то придётся просматривать весь код который её использует. И причём - на всю иерархию вызовов до самого верха, до main (данной задачи). Да и вообще - а как тогда вообще вызывать функции, которые внутри имеют такие же к.секции?

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

По мне, любая критическая секция - костыль и явно говорит о том, что в моем проекте есть проблемы с проектированием.

В RTOS для защиты важных кусков кода существуют более безопасные механизмы вместо критических секций.

Например, все, что связано с обращению к некому порту (в частности та же PRINTF), я использую отдельную задачу/модуль. А все остальные задачи/модули обращаются к этому порту не напрямую, а через эту задачу/модуль через соотв. механизмы синхронизации (мьютекс).

 

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

 

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

8 минут назад, Forger сказал:

Например, все, что связано с обращению к некому порту (в частности та же PRINTF), я использую отдельную задачу/модуль. А все остальные задачи/модули обращаются к этому порту не напрямую, а через эту задачу/модуль через соотв. механизмы синхронизации (мьютекс).

Кто-то и до сих пор на бейсике пишет. Или на всяких абдуринах.  ;)

Когда речь идёт о быстром оптимальном коде, от использовать тяжёлый мьютекс в десятки-сотни(?) команд CPU, там где можно обойтись критической секцией в одну-две команды CPU - это как ваять на абдурине.  ;)

К тому же попробуйте как-нить заглянуть в эти самые мьютексы, в их реализацию в разных ОС - вполне возможно, что увидите там внутрях банальные критические секции. И не одну.  :-D

 

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

Запрет прерываний с запоминанием на Cortex-M - это 2 команды, восстановление - 1 команда. Как бы разница очень существенна с мьютексами.

Опять же - а как же быть с критическими секциями внутри ISR? В них тоже нужда отпала?  ;)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

39 minutes ago, jcxz said:

Когда речь идёт о быстром оптимальном коде, от использовать тяжёлый мьютекс в десятки-сотни(?) команд CPU, там где можно обойтись критической секцией в одну-две команды CPU - это как ваять на абдурине.  ;)

К тому же попробуйте как-нить заглянуть в эти самые мьютексы, в их реализацию в разных ОС - вполне возможно, что увидите там внутрях банальные критические секции. И не одну.  :-D

 

risovach.ru.jpg

 

Тут нужно полноценное перепроектирование кода, тогда не будет таких проблем, как вы описали.

 

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

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

 

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

На спичках не экономлю ;)

 

Quote

Опять же - а как же быть с критическими секциями внутри ISR? 

Не использую. Нет нужды.

 

 

зы В который раз прихожу к выводу, что мы в очередной раз беседуем о разных вещах.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

43 минуты назад, Forger сказал:

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

Почему это к.секции - это костыль? Очень полезная вещь. И в большинстве случаев можно обойтись к.секциями вместо тяжёловесных мьютексов и пр. И тем более - как Вам мьютексы помогут при взаимодействии ISR-ISR или ISR-задача_ОС? Объясните?

"полноценное перепроектирование кода" - это демагогия. Покажите как организовать совместный сериализированный доступ к некоей структуре данных из одного ISR и из другого (находящихся на разных уровнях приоритета)? Или из задачи ОС и из ISR?

Цитата

На спичках не экономлю ;)

ну-ну... Когда начнёте что-то делать для серийного производства, то не только на спичках начнёте экономить. А и на количестве серы в их головках  ;)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 hour ago, jcxz said:

Почему это к.секции - это костыль? 

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

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

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

 

Quote

И в большинстве случаев можно обойтись к.секциями вместо тяжёловесных мьютексов и пр.

Никаких вместо, выше я об этом написал.

Мьютекс в прерывании не использую, он нужен только в фоне задач.

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

Во freertos есть даже непосредственные уведомления конкретной задачи task notify - вроде даже как самое легкое решение из всех межзадачных синхронизаций.

Вроде бы в ucos-3 тоже появилась такая штука.

 

Quote

"полноценное перепроектирование кода" - это демагогия. Покажите как организовать совместный сериализированный доступ к некоей структуре данных из одного ISR и из другого (находящихся на разных уровнях приоритета)? Или из задачи ОС и из ISR?

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

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

Если не годится, то существуют сообщения, очереди сообщений, 

Также существуют механизмы непосредственного уведомления задач - notify.

Короче, все решаемо и очень даже просто ))

Оверхед? Незначительный. Если, конечно, он есть.

 

Quote

ну-ну... Когда начнёте что-то делать для серийного производства, то не только на спичках начнёте экономить. А и на количестве серы в их головках  ;)

Как раз про серию и говорю ;)

Конечно, бывают проекты, где приходится писать на самом-самом голом С с ASM вставками, но там RTOS, плюсы с их "наворотами" и т. п - вообще как собаке пятая нога.

Там уже совсем другая история, где главное - результат, а костыли - по боку ))

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

38 минут назад, Forger сказал:

Просто - пока запрещены прерывания, они ждут своей очереди. Также в этим моменты напрочь вся прелесть вытесняемых прерываний. Вот поэтому - это костыль :)

И что? Пускай ждут. Что тут страшного? Прерывания они всегда ждут. Даже если нет запретов прерываний нигде. Потому что могут быть другие прерывания с приоритетом >= данному. И точно так же будут ждать. Так что выигрыша от неиспользования к.секций нет никакого. А минусов много.

38 минут назад, Forger сказал:

Также существуют механизмы непосредственного уведомления задач - notify.

Короче, все решаемо и очень даже просто ))

Я просил Вас привести пример сериализированного (монопольного) доступа к объекту данных (структуре) из задачи ОС и ISR. А не нотификации о событии в задачу. И очереди - это тоже нечто другое. Речь о единственной структуре.

В которой (в простейшем случае) допустим находится переменная машины состояний + счётчик таймаута. И менять/читать её нужно в задаче и в ISR.

Так как?

Или если есть система с такой структурой и несколькими ISR и одной задачей ОС. Как часть драйвера устройства. Как без к.секций?

38 минут назад, Forger сказал:

Как раз про серию и говорю ;)

В серии к вашему сведению важна себестоимость изделия. И каждый кБ и МГц - на счету, и каждая нога корпуса. И даже - занимаемая корпусом площадь. Так как их экономия позволяет поставить более дешёвый МК, сделать более дешёвую плату, обыграть конкурентов.

2 часа назад, Forger сказал:

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

Или все Ваши проекты - на самых дешёвых STM8 или что значит "в разы"? В десятки-сотни раз? Или в два раза? Если в 2 раза - это значит стоимость МК примерно == 33% от цены всей комплектации. Для серии это не просто значительная часть цены, это - огромная часть цены. А в серии экономят даже на комплектации, составляющей в цене 1% и меньше. А если стоимость МК составляет 33% стоимости всей комплектации, то это одна из основных статей, на которой стоит экономить. И будут экономить.

Или Вы в реальности никогда не имели дела с серией, а только разводите демагогию....  ;)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

47 minutes ago, jcxz said:

Я просил Вас привести пример сериализированного (монопольного) доступа к объекту данных (структуре) из задачи ОС и ISR. А не нотификации о событии в задачу. И очереди - это тоже нечто другое. Речь о единственной структуре.

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

Нужна перестройка кода, чтобы обойтись БЕЗ конкуррентного доступа к одним и тем же данным.

 

Quote

В серии к вашему сведению важна себестоимость изделия. И каждый кБ и МГц - на счету, и каждая нога корпуса. И даже - занимаемая корпусом площадь. Так как их экономия позволяет поставить более дешёвый МК, сделать более дешёвую плату, обыграть конкурентов.

В моих проектах себестоимость копеешного МК в рамках всего изделия составлять крохи.

Однако, я уже упоминал, что в критичных случаях годны любые средства - и костыли критические секции, и голый С и даже ... ASM

С таким проектами работал (чистый ширпотреб). Там совсем другой мир. Экономить приходится практически на всем. Но это - совсем другой мир.

 

Quote

Или все Ваши проекты - на самых дешёвых STM8 или что значит "в разы"? В десятки-сотни раз? Или в два раза? Если в 2 раза - это значит стоимость МК примерно == 33% от цены всей комплектации. Для серии это не просто значительная часть цены, это - огромная часть цены. А в серии экономят даже на комплектации, составляющей в цене 1% и меньше. А если стоимость МК составляет 33% стоимости всей комплектации, то это одна из основных статей, на которой стоит экономить. И будут экономить.

Или Вы в реальности никогда не имели дела с серией, а только разводите демагогию....  ;)

Смотрю, моя персона не дает вам покоя )) 

Я ничего не могу поделать с тем, что вам все-таки приходится использовать критические секции и даже вложенные (!).

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

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

Стоимость МК от всего изделия в моих проектах составляет 1..2%. Поэтому экономия на ОЗУ и памяти всегда оборачивается весьма недешевым геморроем. Пройденный этап.

Конкуренция - почти нет, по крайней мере, в настоящее время. Если припрет, "отрезать" есть что, но уж точно не МК.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

21 минуту назад, Forger сказал:

Нужна перестройка кода, чтобы обойтись БЕЗ конкуррентного доступа к одним и тем же данным.

Какой смысл в перестройке, которая делается только ради себя самой? Какой смысл обходиться без чего-то если с этим "чем-то" получается оптимальнее?

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

 

21 минуту назад, Forger сказал:

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

Как следует из Ваших постов, избежать к.секций - это как раз и есть Ваша самоцель.  :-D

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

21 минуту назад, Forger сказал:

Проекты серийные (не более тысячи в год),

...

Стоимость МК от всего изделия в моих проектах составляет 1..2%. Поэтому экономия на ОЗУ и памяти всегда оборачивается весьма недешевым геморроем. Пройденный этап.

Конкуренция - почти нет, по крайней мере, в настоящее время.

Ну вот я как раз об этом и говорил - с настоящим серийным производством, и именно в конкурентной среде, Вы дела не имели. 1..2% при цене МК == 1...1.5 тыр - это значит == 50...150 тыр себестоимость изделия, а цена ещё выше, и при такой малой серийности выше значительно, может в 2 раза. И нет конкуренции, значит заказчик - бюджет или типа того. Раз нет конкуренции, значит и нет стимула экономить на комплектации. Теперь ясно почему Вы так легко считаете МГц и МБ.

PS: И 1000шт./год при цене ~300тыр - это 300 лямов в год! Да ещё без конкуренции! Это что за ниша такая хлебная?  :-D

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

35 minutes ago, jcxz said:

Какой смысл в перестройке, которая делается только ради себя самой? 

У меня как раз никакой "перестройки" нет, проект сразу проектируется как надо, а потом уже кодится.

А не наоборот, как принято у многих "программеров" ;)

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

 

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

 

 

Quote

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

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

 

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

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

В настоящее время стараюсь вместо них использовать ldrex/strex, как на мой взгляд более "гуманную" версию критических секций.

В принципе, вполне рабочее решение, особенно, если нужно просто защитить всего один указатель или переменную. Но тоже - по особой нужде.

 

Quote

Ну вот я как раз об этом и говорил - с настоящим серийным производством, и именно в конкурентной среде, Вы дела не имели. 1..2% при цене МК == 1...1.5 тыр -

Ну, это вы уж очень жирные МК называете, их использую редко. В такие можно напихать "черта дикого" и еще останется огромный запас места и производительности.

 

Quote

Это что за ниша такая хлебная?  :-D

Секрет! Но проекты коммерческие, к распилу госбюджета отношения не имеют, по крайней мере прямого. Но больше ничего не могу сказать. Типа NDA ;)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Handler вызывается исправно, но без использования vTaskDelay задачи система самостоятельно не меняет.
Delay/YIELD решает эту проблему (отключает одну задачу - запускается другая), но вручную отключать задачи не всегда удобно.
Причём вторая задача всегда в состоянии Ready, но не запускается.

В 09.10.2018 в 23:53, Forger сказал:

Убедитесь, что происходит вызов прерывания SysTick и соотв. вход в SysTick_Handler, реализованный freertos, а не какую-то постороннюю функцию.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

59 минут назад, Svalkash сказал:

Handler вызывается исправно, но без использования vTaskDelay задачи система самостоятельно не меняет.
Delay/YIELD решает эту проблему (отключает одну задачу - запускается другая), но вручную отключать задачи не всегда удобно.
Причём вторая задача всегда в состоянии Ready, но не запускается.

Прерывание PendSV разрешено? В вектор прописан адрес ISR? Входит туда? Именно оно обычно на Cortex-M переключает контекст на готовую задачу.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Для FreeRTOS сделал так (по мотивам scmRTOS). При выходе из блока кода ({}) делать выход из критической секции не требуется.

namespace OsApi {
    class CritSecSmart {
    public:
        CritSecSmart() {
            taskENTER_CRITICAL();
        }
        ~CritSecSmart() {
            taskEXIT_CRITICAL();
        }
    };

    inline void critSecBegin() {
        taskENTER_CRITICAL();
    }
    inline void critSecEnd() {
        taskEXIT_CRITICAL();
    }
}

/// Пример использования
{
OsApi::CritSecSmart cs;
/// Что-то делаем
} /// По выходу из блока taskEXIT_CRITICAL будет вызывана автоматически

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

5 hours ago, haker_fox said:

по мотивам scmRTOS

В этом плане вы не одиноки ;)

См. последний пост на первой странице этой темы.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

6 часов назад, haker_fox сказал:

Для FreeRTOS сделал так (по мотивам scmRTOS). При выходе из блока кода ({}) делать выход из критической секции не требуется.

Зачем??? Какой от этого прок? И как "по мотивам scmRTOS" оформить код ниже, может объясните?:

CPU_SR_ALLOCATE();
  u32 t = sysTimer;
  while (1) {
    ENTR_CRT_SECTION();
    switch (faza) {
      case FAZA_INIT:
        newCfg = 0;
        EXIT_CRT_SECTION();
        ReadConfig();
        fazaTime = t + ms2tkt(TOU?T_SILENCE);
        faza = FAZA_IDLE;
        break;
      case FAZA_IDLE:
        if (IS_CONSOLE_INPUT()) {
          #if LOG_SERVICE && LOG_DTE
          console.faza = console.F_EXEC;
          #endif
        } else if (newCfg) {
          faza = FAZA_INIT;
          EXIT_CRT_SECTION();
          continue;
        } else if ((s32)(t - fazaTime) < 0) {
          EXIT_CRT_SECTION();
          return;
        }
        fazaTime = t + ms2tkt(TOUT_CONNECT);
        faza = FAZA_CONNECT;
        EXIT_CRT_SECTION();
        SocketOpen(SOCK_TIME);?
        return;
      case FAZA_CONNECT:
        ...
        
      case FAZA_RX_END:
        fazaTime = t + ms2tkt(TOUT_CLOSE);
        faza = FAZA_CLOSE;
        EXIT_CRT_SECTION();
        SocketClose(SOCK_TIME);
        return;
      default: EXIT_CRT_SECTION();
    }
    break;
  }

где: ENTR_CRT_SECTION() и EXIT_CRT_SECTION() - вход и выход в/из критической секции.

И нужно изменять faza (машина состояний некоего процесса) и fazaTime (счётчик таймаута для некоторых состояний faza) атомарно в нескольких задачах и ISR. Таких атомарно меняемых переменных может быть больше.

Т.е. - один вход и к.секцию и множество выходов из неё.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

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

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...