jcxz 166 10 октября, 2018 Опубликовано 10 октября, 2018 · Жалоба 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: Нет уж - лучше внимательнее просматривать код. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Forger 17 10 октября, 2018 Опубликовано 10 октября, 2018 · Жалоба 41 minutes ago, jcxz said: printf не reentrant может бить только в плане целевого устройства вывода. Но для многозадачной версии stdlib для этого устройства должна быть сделана reentrant-обёртка в самой stdlib. А от самого пользователя нужно только правильно указать компилятору на необходимость этого. Но судя по всему, далеко не все об этом знают ;) Quote Имхо - очень неудачный вариант. Во-первых: сохранять состояние (в общем случае) - нужно обязательно. Иначе - придётся просматривать все функции, вызываемые внутри такой секции, на всю глубину вызова на предмет наличия там аналогичный секций. А это - просто вселенские грабли: если вдруг понадобится в одной из таких функций вставить аналогичную к.секцию, то придётся просматривать весь код который её использует. И причём - на всю иерархию вызовов до самого верха, до main (данной задачи). Да и вообще - а как тогда вообще вызывать функции, которые внутри имеют такие же к.секции? Я указал, что использую критические секции крайне редко и всегда оооочень аккуратно, а вложенные никогда не использую. Ибо мне нафик не нужны грабли на ровном месте. По мне, любая критическая секция - костыль и явно говорит о том, что в моем проекте есть проблемы с проектированием. В RTOS для защиты важных кусков кода существуют более безопасные механизмы вместо критических секций. Например, все, что связано с обращению к некому порту (в частности та же PRINTF), я использую отдельную задачу/модуль. А все остальные задачи/модули обращаются к этому порту не напрямую, а через эту задачу/модуль через соотв. механизмы синхронизации (мьютекс). Ранее использовал критические секции более сложные - запоминалось состояние флагов прерываний и на выходе восстанавливалось, но в процессе набора опыта нужда в таких вещах напрочь пропала, причины я указал выше. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 166 10 октября, 2018 Опубликовано 10 октября, 2018 · Жалоба 8 минут назад, Forger сказал: Например, все, что связано с обращению к некому порту (в частности та же PRINTF), я использую отдельную задачу/модуль. А все остальные задачи/модули обращаются к этому порту не напрямую, а через эту задачу/модуль через соотв. механизмы синхронизации (мьютекс). Кто-то и до сих пор на бейсике пишет. Или на всяких абдуринах. ;) Когда речь идёт о быстром оптимальном коде, от использовать тяжёлый мьютекс в десятки-сотни(?) команд CPU, там где можно обойтись критической секцией в одну-две команды CPU - это как ваять на абдурине. ;) К тому же попробуйте как-нить заглянуть в эти самые мьютексы, в их реализацию в разных ОС - вполне возможно, что увидите там внутрях банальные критические секции. И не одну. :-D Ранее использовал критические секции более сложные - запоминалось состояние флагов прерываний и на выходе восстанавливалось, но в процессе набора опыта нужда в таких вещах напрочь пропала, причины я указал выше. Запрет прерываний с запоминанием на Cortex-M - это 2 команды, восстановление - 1 команда. Как бы разница очень существенна с мьютексами. Опять же - а как же быть с критическими секциями внутри ISR? В них тоже нужда отпала? ;) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Forger 17 10 октября, 2018 Опубликовано 10 октября, 2018 · Жалоба 39 minutes ago, jcxz said: Когда речь идёт о быстром оптимальном коде, от использовать тяжёлый мьютекс в десятки-сотни(?) команд CPU, там где можно обойтись критической секцией в одну-две команды CPU - это как ваять на абдурине. ;) К тому же попробуйте как-нить заглянуть в эти самые мьютексы, в их реализацию в разных ОС - вполне возможно, что увидите там внутрях банальные критические секции. И не одну. :-D Тут нужно полноценное перепроектирование кода, тогда не будет таких проблем, как вы описали. Да, конечно, бывает так, что схемотехник нарисовал так схему, что программист вынужден изголяться: заниматься ногодрыгом где это ни к чему, ставить костыли в виде критических секций. Но если все сделано правильно (грамотно спроектирована схема и соотв. код), то можно вообще обойтись без критических секций. Хотя ставить борьбу с костылями первостепенной целью - так же глупо, как и везде совать критические секции :) Мой подход прост: минимум костылей в коде, благодаря достаточному запасу по объему коду и производительности проца, ибо его стоимость и цена его памяти у меня всегда в разы меньше стоимости остальных комплектующих. На спичках не экономлю ;) Quote Опять же - а как же быть с критическими секциями внутри ISR? Не использую. Нет нужды. зы В который раз прихожу к выводу, что мы в очередной раз беседуем о разных вещах. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 166 10 октября, 2018 Опубликовано 10 октября, 2018 · Жалоба 43 минуты назад, Forger сказал: Мой подход прост: минимум костылей в коде, благодаря достаточному запасу по объему коду и производительности проца, ибо его стоимость и цена его памяти у меня всегда в разы меньше стоимости остальных комплектующих. Почему это к.секции - это костыль? Очень полезная вещь. И в большинстве случаев можно обойтись к.секциями вместо тяжёловесных мьютексов и пр. И тем более - как Вам мьютексы помогут при взаимодействии ISR-ISR или ISR-задача_ОС? Объясните? "полноценное перепроектирование кода" - это демагогия. Покажите как организовать совместный сериализированный доступ к некоей структуре данных из одного ISR и из другого (находящихся на разных уровнях приоритета)? Или из задачи ОС и из ISR? Цитата На спичках не экономлю ;) ну-ну... Когда начнёте что-то делать для серийного производства, то не только на спичках начнёте экономить. А и на количестве серы в их головках ;) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Forger 17 10 октября, 2018 Опубликовано 10 октября, 2018 · Жалоба 1 hour ago, jcxz said: Почему это к.секции - это костыль? Все очень просто: пока запрещены прерывания, все другие прерывания ждут своей очереди. Также в этим моменты напрочь теряется вся прелесть вытесняемых прерываний. Вот поэтому и костыль :) Правда все в той же Freertos можно указать границу (для кортекс М3 и выше), выше которой в критических секциях прерывания не запрещаются, но и в тех прерываниях нельзя использовать сервисы rtos. Конечно же, когда уже никак нельзя без этого или где подобные ограничения не имеют значения, то этот костыль - вполне рабочее решение. И отказывать от него полностью также неразумно, как и его сувать в каждую дырку )) Quote И в большинстве случаев можно обойтись к.секциями вместо тяжёловесных мьютексов и пр. Никаких вместо, выше я об этом написал. Мьютекс в прерывании не использую, он нужен только в фоне задач. В прерываниях использую счетные или простые бинарные семафоры, ну и флаги по нужде. Тут кто как привык )) Во freertos есть даже непосредственные уведомления конкретной задачи task notify - вроде даже как самое легкое решение из всех межзадачных синхронизаций. Вроде бы в ucos-3 тоже появилась такая штука. Quote "полноценное перепроектирование кода" - это демагогия. Покажите как организовать совместный сериализированный доступ к некоей структуре данных из одного ISR и из другого (находящихся на разных уровнях приоритета)? Или из задачи ОС и из ISR? Просто - не обращаться в прерывании к тем данным, которые используются напрямую в фоне задач. Кольцевой буфер (без проверок на исчерпание/переполнение) тут будет в самый раз в купе с одним счетным семафором. Если не годится, то существуют сообщения, очереди сообщений, Также существуют механизмы непосредственного уведомления задач - notify. Короче, все решаемо и очень даже просто )) Оверхед? Незначительный. Если, конечно, он есть. Quote ну-ну... Когда начнёте что-то делать для серийного производства, то не только на спичках начнёте экономить. А и на количестве серы в их головках ;) Как раз про серию и говорю ;) Конечно, бывают проекты, где приходится писать на самом-самом голом С с ASM вставками, но там RTOS, плюсы с их "наворотами" и т. п - вообще как собаке пятая нога. Там уже совсем другая история, где главное - результат, а костыли - по боку )) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 166 10 октября, 2018 Опубликовано 10 октября, 2018 · Жалоба 38 минут назад, Forger сказал: Просто - пока запрещены прерывания, они ждут своей очереди. Также в этим моменты напрочь вся прелесть вытесняемых прерываний. Вот поэтому - это костыль :) И что? Пускай ждут. Что тут страшного? Прерывания они всегда ждут. Даже если нет запретов прерываний нигде. Потому что могут быть другие прерывания с приоритетом >= данному. И точно так же будут ждать. Так что выигрыша от неиспользования к.секций нет никакого. А минусов много. 38 минут назад, Forger сказал: Также существуют механизмы непосредственного уведомления задач - notify. Короче, все решаемо и очень даже просто )) Я просил Вас привести пример сериализированного (монопольного) доступа к объекту данных (структуре) из задачи ОС и ISR. А не нотификации о событии в задачу. И очереди - это тоже нечто другое. Речь о единственной структуре. В которой (в простейшем случае) допустим находится переменная машины состояний + счётчик таймаута. И менять/читать её нужно в задаче и в ISR. Так как? Или если есть система с такой структурой и несколькими ISR и одной задачей ОС. Как часть драйвера устройства. Как без к.секций? 38 минут назад, Forger сказал: Как раз про серию и говорю ;) В серии к вашему сведению важна себестоимость изделия. И каждый кБ и МГц - на счету, и каждая нога корпуса. И даже - занимаемая корпусом площадь. Так как их экономия позволяет поставить более дешёвый МК, сделать более дешёвую плату, обыграть конкурентов. 2 часа назад, Forger сказал: достаточному запасу по объему коду и производительности проца, ибо его стоимость и цена его памяти у меня всегда в разы меньше стоимости остальных комплектующих Или все Ваши проекты - на самых дешёвых STM8 или что значит "в разы"? В десятки-сотни раз? Или в два раза? Если в 2 раза - это значит стоимость МК примерно == 33% от цены всей комплектации. Для серии это не просто значительная часть цены, это - огромная часть цены. А в серии экономят даже на комплектации, составляющей в цене 1% и меньше. А если стоимость МК составляет 33% стоимости всей комплектации, то это одна из основных статей, на которой стоит экономить. И будут экономить. Или Вы в реальности никогда не имели дела с серией, а только разводите демагогию.... ;) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Forger 17 10 октября, 2018 Опубликовано 10 октября, 2018 · Жалоба 47 minutes ago, jcxz said: Я просил Вас привести пример сериализированного (монопольного) доступа к объекту данных (структуре) из задачи ОС и ISR. А не нотификации о событии в задачу. И очереди - это тоже нечто другое. Речь о единственной структуре. А я вам в который раз пытаюсь донести, что нельзя тупо заменить критическую секцию на сервис ОС. Нужна перестройка кода, чтобы обойтись БЕЗ конкуррентного доступа к одним и тем же данным. Quote В серии к вашему сведению важна себестоимость изделия. И каждый кБ и МГц - на счету, и каждая нога корпуса. И даже - занимаемая корпусом площадь. Так как их экономия позволяет поставить более дешёвый МК, сделать более дешёвую плату, обыграть конкурентов. В моих проектах себестоимость копеешного МК в рамках всего изделия составлять крохи. Однако, я уже упоминал, что в критичных случаях годны любые средства - и костыли критические секции, и голый С и даже ... ASM С таким проектами работал (чистый ширпотреб). Там совсем другой мир. Экономить приходится практически на всем. Но это - совсем другой мир. Quote Или все Ваши проекты - на самых дешёвых STM8 или что значит "в разы"? В десятки-сотни раз? Или в два раза? Если в 2 раза - это значит стоимость МК примерно == 33% от цены всей комплектации. Для серии это не просто значительная часть цены, это - огромная часть цены. А в серии экономят даже на комплектации, составляющей в цене 1% и меньше. А если стоимость МК составляет 33% стоимости всей комплектации, то это одна из основных статей, на которой стоит экономить. И будут экономить. Или Вы в реальности никогда не имели дела с серией, а только разводите демагогию.... ;) Смотрю, моя персона не дает вам покоя )) Я ничего не могу поделать с тем, что вам все-таки приходится использовать критические секции и даже вложенные (!). Однако, мне, к счастью или увы (тут вам виднее), прекрасно удается избежать этого. Хотя такой цели я не ставлю, просто, это получается как-то само собой ;) Проекты серийные (не более тысячи в год), изделия не для ширпотреба, но и не оборонка, где цена комплектующих вообще не имеет значения (там с комплектовкой вообще свой цирк, вдаваться не в детали не буду). Стоимость МК от всего изделия в моих проектах составляет 1..2%. Поэтому экономия на ОЗУ и памяти всегда оборачивается весьма недешевым геморроем. Пройденный этап. Конкуренция - почти нет, по крайней мере, в настоящее время. Если припрет, "отрезать" есть что, но уж точно не МК. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 166 10 октября, 2018 Опубликовано 10 октября, 2018 · Жалоба 21 минуту назад, Forger сказал: Нужна перестройка кода, чтобы обойтись БЕЗ конкуррентного доступа к одним и тем же данным. Какой смысл в перестройке, которая делается только ради себя самой? Какой смысл обходиться без чего-то если с этим "чем-то" получается оптимальнее? К.секции (в том числе реализуемые и запретом прерываний) - это точно такой же инструмент как и прочие методы сериализации данных. У каждого есть плюсы и минусы. И каждый годен для своего. И применять их нужно все. Глупо называть что-то "костылями", только из-за своих фобий. 21 минуту назад, Forger сказал: Однако, мне, к счастью или увы (тут вам виднее), прекрасно удается избежать этого. Хотя такой цели я не ставлю, просто, это получается как-то само собой ;) Как следует из Ваших постов, избежать к.секций - это как раз и есть Ваша самоцель. :-D Пускай код будет тормознее и монструознее, главное чтобы без критических секций и запретов прерывания! А это уже напоминает фобию. 21 минуту назад, Forger сказал: Проекты серийные (не более тысячи в год), ... Стоимость МК от всего изделия в моих проектах составляет 1..2%. Поэтому экономия на ОЗУ и памяти всегда оборачивается весьма недешевым геморроем. Пройденный этап. Конкуренция - почти нет, по крайней мере, в настоящее время. Ну вот я как раз об этом и говорил - с настоящим серийным производством, и именно в конкурентной среде, Вы дела не имели. 1..2% при цене МК == 1...1.5 тыр - это значит == 50...150 тыр себестоимость изделия, а цена ещё выше, и при такой малой серийности выше значительно, может в 2 раза. И нет конкуренции, значит заказчик - бюджет или типа того. Раз нет конкуренции, значит и нет стимула экономить на комплектации. Теперь ясно почему Вы так легко считаете МГц и МБ. PS: И 1000шт./год при цене ~300тыр - это 300 лямов в год! Да ещё без конкуренции! Это что за ниша такая хлебная? :-D Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Forger 17 10 октября, 2018 Опубликовано 10 октября, 2018 · Жалоба 35 minutes ago, jcxz said: Какой смысл в перестройке, которая делается только ради себя самой? У меня как раз никакой "перестройки" нет, проект сразу проектируется как надо, а потом уже кодится. А не наоборот, как принято у многих "программеров" ;) Поэтому переделка и развитие такого кода (если приходится это делать) по крайне мере у меня происходит очень гуманно, т. к. "перестройка" уже не требуется. Я не призываю переделывать проект, который уже набит критическими секциями. Это - бессмысленно. Quote Пускай код будет тормознее и монструознее, главное чтобы без критических секций и запретов прерывания! А это уже напоминает фобию. Код как раз проще и понятнее. По крайней мере для меня. Я уже в который раз повторюсь, что тупо заменить критические секции сервисами RTOS нельзя, иначе как раз и получим монстроподобный код. Короче, я не настаиваю, тут уж ваше дело - использовать совать критические секции или нет. Но для меня они - в чистом виде костыль, пройденный этап. Однако, бывает, что использую их, но лишь в очень редких случаях, когда нужно например что-то по-быстрому отладить, не вдаваясь в подробности. Особенно, если работа с чужим кодом. В настоящее время стараюсь вместо них использовать ldrex/strex, как на мой взгляд более "гуманную" версию критических секций. В принципе, вполне рабочее решение, особенно, если нужно просто защитить всего один указатель или переменную. Но тоже - по особой нужде. Quote Ну вот я как раз об этом и говорил - с настоящим серийным производством, и именно в конкурентной среде, Вы дела не имели. 1..2% при цене МК == 1...1.5 тыр - Ну, это вы уж очень жирные МК называете, их использую редко. В такие можно напихать "черта дикого" и еще останется огромный запас места и производительности. Quote Это что за ниша такая хлебная? :-D Секрет! Но проекты коммерческие, к распилу госбюджета отношения не имеют, по крайней мере прямого. Но больше ничего не могу сказать. Типа NDA ;) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Svalkash 0 11 октября, 2018 Опубликовано 11 октября, 2018 · Жалоба Handler вызывается исправно, но без использования vTaskDelay задачи система самостоятельно не меняет. Delay/YIELD решает эту проблему (отключает одну задачу - запускается другая), но вручную отключать задачи не всегда удобно. Причём вторая задача всегда в состоянии Ready, но не запускается. В 09.10.2018 в 23:53, Forger сказал: Убедитесь, что происходит вызов прерывания SysTick и соотв. вход в SysTick_Handler, реализованный freertos, а не какую-то постороннюю функцию. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 166 11 октября, 2018 Опубликовано 11 октября, 2018 · Жалоба 59 минут назад, Svalkash сказал: Handler вызывается исправно, но без использования vTaskDelay задачи система самостоятельно не меняет. Delay/YIELD решает эту проблему (отключает одну задачу - запускается другая), но вручную отключать задачи не всегда удобно. Причём вторая задача всегда в состоянии Ready, но не запускается. Прерывание PendSV разрешено? В вектор прописан адрес ISR? Входит туда? Именно оно обычно на Cortex-M переключает контекст на готовую задачу. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
haker_fox 55 12 октября, 2018 Опубликовано 12 октября, 2018 · Жалоба Для 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 будет вызывана автоматически Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Forger 17 12 октября, 2018 Опубликовано 12 октября, 2018 · Жалоба 5 hours ago, haker_fox said: по мотивам scmRTOS В этом плане вы не одиноки ;) См. последний пост на первой странице этой темы. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 166 12 октября, 2018 Опубликовано 12 октября, 2018 · Жалоба 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. Таких атомарно меняемых переменных может быть больше. Т.е. - один вход и к.секцию и множество выходов из неё. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться