Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: STM32F7XX аналог bit-banding
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
amiller
В последние годы пришлось достаточно много писать для STM32F1XX и STM32F4XX.
Везде активно пользовался механизмом bit-banding для доступа к битовым переменным.
Сейчас заказал отладку с STM32F746ZG.
Читаю документацию и вижу, что там никаких упоминаний про bit-banding при работе с оперативной памятью...
Ткните носом, что на замену? Может появились неделимые операции "чтение-модификация-запись"?
jcxz
Цитата(amiller @ Dec 26 2016, 13:11) *
Читаю документацию и вижу, что там никаких упоминаний про bit-banding при работе с оперативной памятью...
Ткните носом, что на замену? Может появились неделимые операции "чтение-модификация-запись"?

Механизм LDREX/STREX есть уже в M3.
amiller
Цитата(jcxz @ Dec 27 2016, 01:34) *
Механизм LDREX/STREX есть уже в M3.

Это немного не то.
Команды предназначены для организации эксклюзивного доступа к ячейке памяти.
Причём они не гарантируют эксклюзивности, а позволяют проверить успешность операции по изменению данных.
В какой то мере это танцы с бубном, которые в некоторых случаях ещё сложнее простого запрета прерываний.
Хотелось бы обойтись без всего этого.
Чтобы код на С выглядел как то так:
X &= mask; или X |= mask;
И при этом, разместив переменную в определенной секции памяти или объявив эту переменную особым образом, мы бы получили результат, когда компилятор генерирует непрерываемый код (в идеале из одной команды), который модифицирует переменную прямо в памяти.
Например IAR (всегда?) генерирует код из трёх отдельных этапов - чтение - модификация - запись.
Механизм bit-banding в Cortex-M3 и Cortex-M4 позволял достаточно красиво обойти эту проблему.
А в Cortex-M7 решили отказаться от этого без каких либо альтернатив?
SSerge
Идея bit-banding в том, что он делается не процессором, а контроллером памяти.
С одной стороны это хорошо, поскольку все операции выполняются "на месте", не загружая шину лишними пересылками.
С другой это приводит к усложнению логики коммутатора шин.
Наиболее вероятная, на мой взгляд, причина - скорострельности ОЗУ стало недостаточно чтобы провести цикл чтение-модификация-запись за один такт, а за два делать - неоправданное усложнение контроллера и всего шинного хозяйства, которое в семёрке и так не маленькое.

Ну и со стороны компиляторов поддержки так и не дождались.
jcxz
Цитата(amiller @ Dec 27 2016, 06:05) *
Это немного не то.
Команды предназначены для организации эксклюзивного доступа к ячейке памяти.
Причём они не гарантируют эксклюзивности, а позволяют проверить успешность операции по изменению данных.

... которая будет успешной только при эксклюзивном доступе.
И в чём разница?
Вы думаете классический битбандинг какие-то специальные операции делал по шине памяти предназначенные только для битов? wink.gif
Нет, процессор так же выполнял чтение-модификацию бита-запись для всей ячейки содержащей данный бит, но скрыто от программиста и в непрерывном режиме.

Вот моя реализация аналога команды CMPXCHG для x86:
CODE
PUBLIC _Z13AtomicCmpSwapPVjjj
;АтомарнаЯ операциЯ "сравнение и обмен" длЯ типа u32.
;u32 AtomicCmpSwap(u32 volatile *ptr, u32 newVal, u32 cmpVal);
_Z13AtomicCmpSwapPVjjj:
aCmpSwap32_01: LDREX R12, [R0]
CMP R12, R2
ITT EQ
STREXEQ R3, R1, [R0]
CMPEQ R3, #1
BEQ aCmpSwap32_01
MOV R0, R12
BX LR

На основе этой процедуры можно сделать и другие операции атомарной модификации памяти (хоть |=, хоть &=, ...).

Цитата(amiller @ Dec 27 2016, 06:05) *
Чтобы код на С выглядел как то так:
X &= mask; или X |= mask;
И при этом, разместив переменную в определенной секции памяти или объявив эту переменную особым образом, мы бы получили результат, когда компилятор генерирует непрерываемый код (в идеале из одной команды), который модифицирует переменную прямо в памяти.
Например IAR (всегда?) генерирует код из трёх отдельных этапов - чтение - модификация - запись.
Механизм bit-banding в Cortex-M3 и Cortex-M4 позволял достаточно красиво обойти эту проблему.

Святая наивность.... biggrin.gif biggrin.gif biggrin.gif biggrin.gif biggrin.gif
Похоже Вы никогда не заглядывали, что генерит IAR при работе с bit-banding-ом. Там команд подчас ещё больше, чем в той процедуре, что я привёл выше.
И это не "IAR генерирует", это архитектура Cortex-M такова - у него нет команд непосредственно модифицирующих данные в памяти. Чтобы получить то, что Вы хотите, Вам нужно поменять процессор.
SasaVitebsk
Цитата(SSerge @ Dec 27 2016, 10:19) *
Ну и со стороны компиляторов поддержки так и не дождались.

Да и со стороны пользователей тоже. Я, к примеру, не стал заморачиваться. Смысл какой? Если бы это было общее решение для всех процов, ну тогда да. Или подход.
Да и вообще, надо от головы плясать. Если бы язык С поддерживал бы какую то директиву, которая бы обеспечивала атомарные операции с данными, либо механизм, то тогда производители компиляторов вынуждены были бы реализовывать эти директивы средствами имеющимися в наличии у конкретного CPU. Вот тогда бы всё закрутилось. А так ... Пустое.
_Pasha
Цитата(SasaVitebsk @ Dec 27 2016, 14:56) *
Если бы язык С поддерживал бы какую то директиву, которая бы обеспечивала атомарные операции с данными, либо механизм, то тогда производители компиляторов вынуждены были бы реализовывать эти директивы средствами имеющимися в наличии у конкретного CPU. Вот тогда бы всё закрутилось. А так ... Пустое.

С как язык и не должен более развиваться, потому что для решения этих проблем есть плюсы
zltigo
Цитата(amiller @ Dec 27 2016, 05:05) *
А в Cortex-M7 решили отказаться от этого без каких либо альтернатив?

Альтернатива, причем более, чем разумная, Вам была названа. А вот работу с псевдобитами разумной назвать сложно, ввиду затрат на вычисление адреса бита.
amiller
Цитата(jcxz @ Dec 27 2016, 13:45) *
Вы думаете классический битбандинг какие-то специальные операции делал по шине памяти предназначенные только для битов? wink.gif

Нет, не думаю.

Цитата(jcxz @ Dec 27 2016, 13:45) *
Похоже Вы никогда не заглядывали, что генерит IAR при работе с bit-banding-ом. Там команд подчас ещё больше, чем в той процедуре, что я привёл выше.

Нет, заглядывал.

Я прекрасно знаю, как работать с разделяемыми переменными программными средствами.
И эти механизмы можно реализовать в любой архитектуре.
Чаще всего существует поддержка на уровне системы команд, т.е. есть специальные команды для упрощения реализации, в Cortex M это LDREX/STREX.
Если речь идёт о реализации семафоров, то bit-banding ничем не поможет,так как он не обеспечивает атомарный доступ (теперь уже к биту).

Позвольте уточню, для чего я использовал этот механизм:
Есть переменная, содержащая набор флагов. С помощью bit-banding я мог спокойно установить или сбросить любой бит в этой переменой, не заботясь о том, что одновременно другие процессы с разными приоритетами могут работать с другими битами этой переменной.
И похоже для Cortex M7 можно работать с битовыми структурами только через критические секции.



Цитата(zltigo @ Dec 27 2016, 16:45) *
Альтернатива, причем более, чем разумная, Вам была названа. А вот работу с псевдобитами разумной назвать сложно, ввиду затрат на вычисление адреса бита.

Спорить не буду, но я не занимался вычислением адресов.
Я создавал две секции памяти, одна в bit области, другая в band области памяти.
В этих секциях синхронно создавались две переменные, одна - битовая переменная нужного размера, вторая - структура из переменных int32 для доступа к отдельным битам.
Может быть и коряво, но задачу решало, причём с минимумом накладных расходов.


zltigo
Цитата(amiller @ Dec 27 2016, 14:57) *
Есть переменная, содержащая набор флагов. С помощью bit-banding я мог спокойно установить или сбросить любой бит в этой переменой, не заботясь о том, что одновременно другие процессы с разными приоритетами могут работать с другими битами этой переменной.

При этом если работать с несколькими битами, то все становится сразу неудобным. При этом количество тактов на этот bit-banding это не один такт.
Цитата
И похоже для Cortex M7 можно работать с битовыми структурами только через критические секции.

Разумнее с проверкой доступа к памяти.
Цитата
Спорить не буду, но я не занимался вычислением адресов.
Я создавал две секции памяти, одна в bit области, другая в band области памяти.
В этих секциях синхронно создавались две переменные, одна - битовая переменная нужного размера

битовая НЕ может быть "нужного размера" sad.gif. Она только битовая.
Цитата
вторая - структура из переменных int32 для доступа к отдельным битам.

В свою очередь 32bit обеспечивает доступ сразу ко всем 32 битам, а не отдельным.
Цитата
Может быть и коряво, но задачу решало, причём с минимумом накладных расходов.

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

amiller
Цитата(zltigo @ Dec 27 2016, 17:25) *
При этом если работать с несколькими битами, то все становится сразу неудобным. При этом количество тактов на этот bit-banding это не один такт.

Ну так я с этим и не спорю.

Цитата(zltigo @ Dec 27 2016, 17:25) *
битовая НЕ может быть "нужного размера" sad.gif. Она только битовая.

В данном случае имелась в виду переменная, состоящая из нескольких битов (8, 16, 32, 64).

Цитата(zltigo @ Dec 27 2016, 17:25) *
В свою очередь 32bit обеспечивает доступ сразу ко всем 32 битам, а не отдельным.

А разве смысл bit-banding не в том, что доступ к отдельному биту производится через полноразмерную 32-битную переменную из band области? Нет?
А у меня вроде работает именно так, и в документации так написано. Или опять вопрос в терминологии?

Цитата(zltigo @ Dec 27 2016, 17:25) *
Минимума накладных расходов по производительности, увы, не было. Как то то, что решаемую задачу Вы тоже описали шиворот на выворот.

Да я вроде просто в Cortex M7 не обнаружил bit banding. Была мысль, что придумали что-то новое, более продвинутое, что я не увидел в документации.
Именно в это я попросил ткнуть меня носом.
А меня стали наперебой тыкать носом в известные вещи.
jcxz
Цитата(amiller @ Dec 27 2016, 15:57) *
Позвольте уточню, для чего я использовал этот механизм:
Есть переменная, содержащая набор флагов. С помощью bit-banding я мог спокойно установить или сбросить любой бит в этой переменой, не заботясь о том, что одновременно другие процессы с разными приоритетами могут работать с другими битами этой переменной.
И похоже для Cortex M7 можно работать с битовыми структурами только через критические секции.

Блин... Похоже Вы ничего не поняли... wacko.gif
Я же написал в первом сообщении: "На основе приведённой мной процедуры можно реализовать многие операции атомарного чтения-модификации-записи".
Пример - хотим "a |= b" атомарно:
Код
u32 volatile a;
u32 i0, i1;
do i1 = (i0 = a) | b;
while (AtomicCmpSwap(&a, i1, i0) != i0);

Всё! Здесь получили то, что Вы хотели - атомарная работа с битовыми структурами. Только функционал ещё по-больше - можно сразу неск. битов установить.
Подобные процедуры у меня есть и для других типов данных: u8, u16.
Так можно реализовать и все прочие логические и арифметические операции атомарные.
А можно, при желании, написать отдельные функции, подобные этой, для каждой такой операции (чтобы уменьшить кол-во команд).

Цитата(amiller @ Dec 27 2016, 17:06) *
Да я вроде просто в Cortex M7 не обнаружил bit banding. Была мысль, что придумали что-то новое, более продвинутое, что я не увидел в документации.

Даже в M3/M4 bit-banding был опционален и в некоторых камнях его могло и не быть.
Так что может и для M7 то же самое? Может в том МК, который Вы смотрите, его решили не реализовывать? Не большая потеря....
SasaVitebsk
На AVR это делал. А теперь вообще так не делаю. Как правило этих флагов ну пусть 30 ... Если каждый поместить в 4-ёх байтное слово будет потрачено 120 байт. Это что критично для M7?
Вообще подходы к написанию поменял. Стараюсь флаги выставлять в одной задаче - забирать в другой... Короче стараюсь писать так, чтобы не возникало проблем. И задачи делаю строго асинхронные.
Выделяю задачу одну, следящего типа... Она диагностирует...
Несколько сложнее работать с общими ресурсами. Например флэш память. Записываются сообщения об ошибках с любой задачи. Можно делать конечно её обслуживание лишь в одной задаче, а туда слать лишь сообщения...
Короче лучше всего поменять подходы к самому программированию. Когда нужно выбрать или производительность или стабильность работы, то думаю, стабильность важнее. А производительность всегда можно повысить выбрав другой камень. Сейчас с этим нет вопросов.
Ну это мой взгляд на вещи.
jcxz
Цитата(SasaVitebsk @ Dec 27 2016, 22:39) *
На AVR это делал. А теперь вообще так не делаю. Как правило этих флагов ну пусть 30 ... Если каждый поместить в 4-ёх байтное слово будет потрачено 120 байт. Это что критично для M7?

Я думаю цель - не экономия памяти, а реализация механизма, когда доступ к объекту возможен как по частям (по битам) так и целиком (словом) из разных задач/ISR. В нескольких разных местах флаги ставятся (клиентами), а в одном месте - считываются-обнуляются другой задачей целиком всё слово.

Цитата(SasaVitebsk @ Dec 27 2016, 22:39) *
Вообще подходы к написанию поменял. Стараюсь флаги выставлять в одной задаче - забирать в другой... Короче стараюсь писать так, чтобы не возникало проблем. И задачи делаю строго асинхронные.

Ну да, если бы всегда так можно было бы, то семафоров разных не придумывали бы.
Представьте случай:
Есть задача (сервер), выполняющая запросы нескольких других задач-клиентов. Соответственно она может быть занята. Клиенты когда хотят пнуть задачу, ставят её флажок, который она обработает или сразу или как только освободится.
Я вот так часто реализую блокирующий или неблокирующий доступ к ресурсам, когда есть одна задача, обслуживающая общий ресурс и осуществляющая приоритетный арбитраж доступа клиентов к ресурсу и много клиентов.
Клиенты ставят флажки-биты в переменной запросов (опционально переходя в ожидание обслуживания) и пингуют задачу-сервер, пробуждая её. Задача, как только получает управление или освобождается от обработки предыдущего запроса, считывает сразу всю переменную флагов-запросов, в соответствии со своими правилами выбирает наиболее приоритетный запрос из имеющихся, сбрасывает этот флаг запроса, обрабатывает запрос.
Вот здесь нужен доступ к флагам-запросам как по отдельности и атомарно, так и сразу ко всем.
AVI-crak
Цитата(amiller @ Dec 26 2016, 16:11) *
Читаю документацию и вижу, что там никаких упоминаний про bit-banding при работе с оперативной памятью...
Может появились неделимые операции "чтение-модификация-запись"?

Атомарные операции не терялись. Вот только выглядят они как громадный костыль.

Применимы к флагам которых безумно много, или как вариант - обязаны занимать минимальное место (не всегда правило).
В общем у меня получатся так: глобальная структура с флагами ( ingl ) - цель, собрать в кучу мелкие имена флагов, строго 32б, ну и модификация с помощью стандартных команд __LDREXW и __STREXW.
Поместил функции f_ask_с и f_ask_d в разные задачи, они там в цикле просто меняют свой флаг. Смысла в функции нет, потому как я не придумал способ передать указатель члена структуры (оно ниже физического адреса). Возможно можно перечислениями сделать, но как потом не запутаться - не знаю.

Словом, если кто предложит решение - буду рад.

CODE
typedef union
{
struct
{
uint32_t stop:5;
uint32_t start:1;
uint32_t a:1;
uint32_t b:1;
uint32_t c:1;
uint32_t d:2;
uint32_t e:1;
uint32_t f:1;
uint32_t g:1;
uint32_t h:1;
uint32_t i:1;
uint32_t j:1;
uint32_t k:1;
uint32_t l:1;
uint32_t m:1;
uint32_t n:1;
uint32_t o:1;
uint32_t p:1;
uint32_t q:1;
uint32_t r:1;
uint32_t s:1;
uint32_t t:1;
uint32_t u:1;
uint32_t v:1;
uint32_t w:1;
uint32_t x:1;
uint32_t y:1;
uint32_t z:1;
} Flags;
uint32_t Flagi;
} Flag_Type;

Flag_Type ingl;


static void f_ask_c (void);
void f_ask_c (void)
{
Flag_Type tmp;
do
{
tmp.Flagi = __LDREXW(&ingl.Flagi);
tmp.Flags.c ^= 1;
}while ( __STREXW(tmp.Flagi, &ingl.Flagi));
__CLREX();
}

static void f_ask_d (void);
void f_ask_d (void)
{
Flag_Type tmp;
do
{
tmp.Flagi = __LDREXW(&ingl.Flagi);
tmp.Flags.d ^= 1;
}while ( __STREXW(tmp.Flagi, &ingl.Flagi));
__CLREX();
}
amiller
Цитата(jcxz @ Dec 27 2016, 18:58) *
Блин... Похоже Вы ничего не поняли... wacko.gif

Да понял я всё.
Просто не считаю, что предложенный Вами механизм, - это полная альтернатива бит-бандинга.
Поэтому жаль, что битбандинг не входит в состав архитектуры Cortex М в обязательном порядке.
Тем не менее, спасибо, при отсутствии аппаратных альтернатив этот способ наиболее хорошо подходит для решения моей задачи.
Придётся действительно переходить на программную реализацию атомарных операций по работе с битами.
Кстати в ИАР есть встроенные обертки на С для этих команд (core_cmInstr.h). Например:
CODE
/** \brief STR Exclusive (16 bit)

This function executes a exclusive STR instruction for 16 bit values.

\param [in] value Value to store
\param [in] ptr Pointer to location
\return 0 Function succeeded
\return 1 Function failed
*/
__attribute__((always_inline)) __STATIC_INLINE uint32_t __STREXH(uint16_t value, volatile uint16_t *addr)
{
uint32_t result;

__ASM volatile ("strexh %0, %2, %1" : "=&r" (result), "=Q" (*addr) : "r" ((uint32_t)value) );
return(result);
}
jcxz
Цитата(AVI-crak @ Dec 28 2016, 05:11) *
Словом, если кто предложит решение - буду рад.

А зачем Вы у себя использовали CLREX?

Цитата(amiller @ Dec 28 2016, 06:15) *
Просто не считаю, что предложенный Вами механизм, - это полная альтернатива бит-бандинга.
Поэтому жаль, что битбандинг не входит в состав архитектуры Cortex М в обязательном порядке.

Как предположение: возможно бит-бандинг убрали из-за того, что он не работает в многопроцессорных системах?
По крайней мере про механизм LDREX/STREX в мануале заявлено, что он нормально работает и в многопроцессорных системах.
А я думаю, что цель развития МК в дальнейшем - по несколько ядер в одном чипе. Некоторые вендоры это уже осознали.
Так что может и не зря сейчас переходите. Потом когда выйдет новый МК с несколькими ядрами, окажется что Ваш код с бит-бандингом весь надо переписывать, а если напишете на LDREX/STREX - он и там окажется рабочим wink.gif
Сергей Борщ
Лично я использовал bit-band для доступа к отдельным ногам. При вызове функции дерганья ногой мне было достаточно передать один указатель, без bit-band на M0 приходится передавать указатель на регистр, маску и обеспечивать атомарность.
jcxz
Цитата(Сергей Борщ @ Dec 28 2016, 14:25) *
Лично я использовал bit-band для доступа к отдельным ногам. При вызове функции дерганья ногой мне было достаточно передать один указатель, без bit-band на M0 приходится передавать указатель на регистр, маску и обеспечивать атомарность.

Во многих МК доступ к функциям установки 0 и 1 на GPIO-ногах сделан атомарным посредством периферийных регистров. В некоторых и атомарный toggle есть.
А передавать можно в старших битах - номер порта, в мл. - номер ноги. А в функции это нетрудно развернуть.
AVI-crak
Цитата(jcxz @ Dec 28 2016, 16:48) *
А зачем Вы у себя использовали CLREX?

Там написано что это снятие блокировки, но мне кажется это корявый перевод гугла.
В реальности это очистка регистра адреса, который используется для мониторинга атомарного адреса. Прикол в том что когда __LDREXW и __STREXW применяется в прерывании, и перебивается другим прерыванием ровно между командами - при возврате получается глюк.
Поймал пару раз, теперь просто ставлю CLREX.
В майне любое прерывание работает как CLREX, команда короткая и простая, к тому-же с явным указанием перезагрузки операторов "memory". Этот барьер запрещает GCC размазывать функцию по всему коду, как он это любит делать.

----------------
Есть мысли? как в функцию передать адрес члена битовой структуры???
Гугол молчит на эту тему, наверное это особо_извращённая методика программирования, возможная исключительно под грибами (запрещёнными Законодательством Российской Федерации). Грибы есть, мыслей нет.
jcxz
Цитата(AVI-crak @ Dec 28 2016, 19:02) *
Прикол в том что когда __LDREXW и __STREXW применяется в прерывании, и перебивается другим прерыванием ровно между командами - при возврате получается глюк.
Поймал пару раз, теперь просто ставлю CLREX.

Странно.... Надо будет проверить на своём МК как нить.
Думал, что любого вложенного прерывания достаточно для очистки признака эксклюзивности.......
zltigo
Цитата(jcxz @ Dec 29 2016, 14:23) *
Странно.... Надо будет проверить на своём МК как нить.
Думал, что любого вложенного прерывания достаточно для очистки признака эксклюзивности.......

Мне не очень интересно, поскольку вложенных прерываний для сколь-нибудь серьезных контроллеров, в том числе уже и мелких корексов, не использую принципиально. И для обработчиков прерываний использую макросы установки флагов без атомарных оберток.
jcxz
Цитата(zltigo @ Dec 29 2016, 15:30) *
Мне не очень интересно, поскольку вложенных прерываний для сколь-нибудь серьезных контроллеров, в том числе уже и мелких корексов, не использую принципиально. И для обработчиков прерываний использую макросы установки флагов без атомарных оберток.

При модификации битовых флагов в ISR даже вложенных редко требуется дополнительное обеспечение атомарности, так как как правило только один ISR работает с данной конкретной флаговой переменной.
А если нужно более одного ISR для одной флаговой переменной, я просто располагаю эти ISR на одном уровне приоритета.
А Вы просто используете частный случай этого - все прерывания на одном приоритете.
Так что можете не бояться вложенности wink.gif
zltigo
Цитата(jcxz @ Dec 29 2016, 15:10) *
Так что можете не бояться вложенности wink.gif

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


Цитата(jcxz @ Dec 29 2016, 15:10) *
А Вы просто используете частный случай этого - все прерывания на одном приоритете.

Приоритеты прерываний и их вложенность есть две разных сущности. Приоритеты, естественно, используются.
AVI-crak
Цитата(zltigo @ Dec 29 2016, 18:30) *
Мне не очень интересно, поскольку вложенных прерываний для сколь-нибудь серьезных контроллеров, в том числе уже и мелких корексов, не использую принципиально.

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

И не стоит забывать про call функции, которые в последнее время пихают куда попало, даже в обработчики прерываний. Посему, если есть возможность выстрелить себе в ногу - такой человек найдётся. Потом придётся искать глюк, который срабатывает синхронно с магнитными бурями на Марсе.
Обработка глобальных флагов в прерывании должна завершаться CLREX, всё по той-же причине.
zltigo
Цитата(AVI-crak @ Dec 29 2016, 20:17) *
Вы серьёзно?

Да.
Цитата
Просто это как купить билет на самолёт, и отправится в путь пешком.

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

Большая, но ненужная мне радость. На самом деле контроллер прерываний МЛАДШИХ кортексов это именно костыль. У старших, как и у "старых" армов, контролеры прерываний без этих костылей. Причина проста - явно предполагалось перетаскивать под крыло младших кортексов программистов с восьмибитовиков с их де-факто стилем писательства с стиле "суперцикл". Для такого подхода к делу наличие наворотов контролера в сторону навороченных вложенных прерываний, есть несомненное благо.
Цитата
Посему, если есть возможность выстрелить себе в ногу - такой человек найдётся.

Посему для начала не надо плодить без надобности решения для стрельбы в ногу.
jcxz
Цитата(zltigo @ Dec 29 2016, 23:52) *
Нет, это как имея костыли ими НЕ пользоваться. Костыли в виде вложенности не нужны по причине использования функциональной операционной системы. Я же писал об этом.

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

Цитата(zltigo @ Dec 29 2016, 23:52) *
Большая, но ненужная мне радость. На самом деле контроллер прерываний МЛАДШИХ кортексов это именно костыль. У старших, как и у "старых" армов, контролеры прерываний без этих костылей. Причина проста - явно предполагалось перетаскивать под крыло младших кортексов программистов с восьмибитовиков с их де-факто стилем писательства с стиле "суперцикл".

Да ладно!! Это FIQ/IRQ в ARM7/9 - лучше??? laughing.gif
Ну да, он удобнее когда нет вытесняющей ОС. Когда не надо переключать контексты задач и когда мало ISR, могущих конкурировать друг с другом по времени. И можно одно-два самых быстрых прерывания вынести в отдельный контекст FIQ.
Но как только возникают задачи вытесняющей ОС, как только оказывается необходимым копировать стеки между разными состояниями CPU (нормальное/IRQ/FIQ/...) сразу всё это удобство превращается в огромный костыль.
И не надо тут сказки рассказывать - мне приходилось писать порты ОС и под ARM7/9 и под Cortex-M. И это небо и земля по сложности/размеру. И любой желающий может самостоятельно сделать такой вывод взглянув на готовые переключатели задач для классических ARM и для Cortex-M.
Архитектура NVIC в Cortex-M как раз и была создана с целью оптимизации для использования под ОС. В то время как IRQ/FIQ классических ARM - для ускорения обработки ISR без механизма вытеснения задач в ISR.
zltigo
Цитата(jcxz @ Dec 30 2016, 10:23) *
Костыли - это когда начинают по каким-то идеологическим/религиозным причинам игнорировать существующие механизмы и пытаться создать свой лисапет с квадратными колёсами.

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

Количество таких случаев зависит от сложности решаемых контроллером задач и наличия головы на полечах у решающего эти задачи.
Цитата
Да ладно!! Это FIQ/IRQ в ARM7/9 - лучше??? laughing.gif

Да, лучше. В этом случае FIQ это действительно и быстрое и приоритетное. Как раз для таких случаев когда действительно надо. На форуме уже было пара веток разговоров чем контроллер препываний ARM7/9 и старших кортексов лучше, чем удобный "кирпич" младших кортексов. Например: https://electronix.ru/forum/index.php?showt...t&p=1348629
Цитата
Ну да, он удобнее когда нет вытесняющей ОС.

Глупость. Удобство состоит в возможности реализации замыслов, а не в том, что что то там "само" сохраняется не требуя умственных усилий и кода.
Цитата
Архитектура NVIC в Cortex-M как раз и была создана с целью оптимизации для использования под ОС. В то время как IRQ/FIQ классических ARM - для ускорения обработки ISR бс в ISR.

По Вашей "теории" Cortex-A так же рождены для безосевых решений sm.gif

P.S.
То, что касается "сделать такой вывод взглянув на готовые переключатели задач для классических ARM", то глядя на некоторые реализации портов, например, uCOS для ARM7, можно сказать, что для его писателя, действительно "M" есть благо, поскольку железо он абсолютно не понимает и то, что он сотворил с обработкой прерываний вообще и преключателе задач в частности, ни в какие ворота не лезет.
jcxz
Цитата(zltigo @ Dec 30 2016, 11:51) *
То, что касается "сделать такой вывод взглянув на готовые переключатели задач для классических ARM", то глядя на некоторые реализации портов, например, uCOS для ARM7, можно сказать, что для его писателя, действительно "M" есть благо, поскольку железо он абсолютно не понимает и то, что он сотворил с обработкой прерываний вообще и преключателе задач в частности, ни в какие ворота не лезет.

Может приведёте здесь Ваш переключатель задач для classic ARM? Чтобы не быть голословным.
zltigo
Цитата(jcxz @ Dec 30 2016, 15:03) *
Может приведёте здесь Ваш переключатель задач для classic ARM? Чтобы не быть голословным.

В первом приближении берете, например, FreeRTOSовские порты ARM7 и M3 и сравниваете на предмет наличия ужасных сложностей порта ARM7.
У меня отличия от штатного ARM7 порта под IAR не разительные. Могу, конечно, и свой выложить. Это не секрет. Просто под руками сейчас нет.
Потом можете сравнить с тем, что для ARM7 начиная со startup c бодуна понаписано в uCOS. Там действительно страшненько, но это не следствие ARM7, а следствие уровня писавшего порт.
klen
интересненько почитал... а то как то вяло на электрониксе последние пол года
по существу думаю Вы оба правы! но каждый про свое.
механизмы прерываний реализованные в железе и ОСность вещи перпендикулярные.
на armv4 считаю что создть невозможно вложенные прерывания абсалютно надежно, вот их там и не любят. в armv7 это решили пофиксить но тоже не без придури, поэтому получилось полено папы Карло.
я традиционно из stm32 "ПЛИСину" выжимаю поэтому мне ближе механизмы заложенные в armv7 так как более детерминированая сисием получается.
ну и с наступающим всех!!!
желаю всем в НГ менее глючного кода и более быстрого железа.
zltigo
Цитата(klen @ Dec 30 2016, 17:24) *
по существу думаю Вы оба правы! но каждый про свое.
механизмы прерываний реализованные в железе и ОСность вещи перпендикулярные.

Не совсем понимаю про перпендикулярность. Говорил только, что навороты воложенных прерываний с их приортиетами не надо смешивать с тем, что предоставляет операционная система. То есть при наличии операционной системы нужны более, чем веские основания для использования вложенных прерываний.
Цитата
на armv4 считаю что создть невозможно вложенные прерывания абсалютно надежно, вот их там и не любят.

Слово "абсолютно" не понимаю. Но вложенные сам для маленькой маленькой штучки на LPC2101 в свое время делал руками. Без проблем. Как и еще на доброй полудюжине контроллеров и PC.
Какие вообще могут быть проблемы со вложенными прерываниями на той же v4, если они делаются софтово БЕЗ какой либо аппаратной поддержки.
Другое дело, то де-факто у самого контролера есть какие то глюки sad.gif. Вот здесь спустя много лет наступил https://electronix.ru/forum/index.php?showt...t&p=1374580. Залатал. Но причину так и не понял.
Цитата
в armv7 это решили пофиксить но тоже не без придури, поэтому получилось полено папы Карло.

Получился некий законченный универсальный вариант. Вполне тщательно продуманный. Но как любой универсальный не без недостатоков и избыточности.
AVI-crak
Цитата(zltigo @ Dec 30 2016, 21:58) *
Вот здесь спустя много лет наступил https://electronix.ru/forum/index.php?showt...t&p=1374580. Залатал. Но причину так и не понял.

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

Далее, неважно насколько крута ось - важно что физические устройства должны иметь разный приоритет. Например банальный spi: при равных приоритетах на Rx и Tx - получим стабильный глюк. Причём приоритеты на тот-же spi имеются и в каналах dma и на само конечное прерывание.
Разные приоритеты обработки для включённой периферии. Например sd карта может и подождать звуковой кодек.

Цитата(jcxz @ Dec 30 2016, 19:03) *
Может приведёте здесь Ваш переключатель задач для classic ARM? Чтобы не быть голословным.


Для cortex m7 переключатель получается жирным, необходимо сохранять много регистров. А точнее на 16 штук больше чем cortex m4.
Ничего сложного: сохранить в стек r4-r11, и математику s16-s31, сохранить адрес стека в структуру задачи, остальное автоматически сохраняется в текущем стеке задачи. Восстанавливать так-же.
Стеки под задачи разные, стек под прерывания один единственный.
https://bitbucket.org/AVI-crak/rtos-cortex-m3-gcc/src
zltigo
Цитата(AVI-crak @ Dec 30 2016, 20:51) *
Это и есть проблема атомарности в чистом виде. Вам необходимо настроить регионы mpu, включить сквозную запись в адресном пространстве регистров управления мк.
....

Вы бредите sad.gif. Советую для начала ознакомится с контроллером. Для начала нет у него кэшей. Совсем.
Цитата
Например банальный spi: при равных приоритетах на Rx и Tx - получим стабильный глюк.

Ни банальный ни какой другой SPI не имеет никаких отдельных прерываний Rx/Tx по определению.
Цитата
неважно насколько крута ось - важно что физические устройства должны иметь разный приоритет

Или не иметь. Как надо, так и делается. Это Вы с кем спорите? Кто-то утверждал, что все прерывания должны быть одного приоритета?
jcxz
Цитата(AVI-crak @ Dec 30 2016, 21:51) *
Для cortex m7 переключатель получается жирным, необходимо сохранять много регистров. А точнее на 16 штук больше чем cortex m4.

Что за дополнительные регистры? В FPU? Ну так их сохранение опционально - я в своём порту под uCOS при переключении задач сохраняю S0-S31,FPSCR только для задач, использующих FPU. Большинство задач FPU не использует и для них размер сохраняемого контекст можно уменьшить.
И регистры S0-S31 были и в M4.
Вы ничего не напутали? rolleyes.gif
Obam
"The code designed for other Cortex®-M processors is compatible with Cortex®-M7 as long as it does not rely on bit-banding." - STM32F7 Series Cortex®-M7 processor programming manual. DocID028474 Rev 2.

Аминь… wink.gif
amiller
В процессе переезда с bit-banding сделал несколько макросов, может кому будет интересно:
CODE
#define setw_amask(x,y) {while(__STREXW(__LDREXW(&x) | (y), &x));__CLREX();}
#define clrw_amask(x,y) {while(__STREXW(__LDREXW(&x) & ((int32u)~((int32u)y)), &x));__CLREX();}
#define seth_amask(x,y) {while(__STREXH(__LDREXH(&x) | (y), &x));__CLREX();}
#define clrh_amask(x,y) {while(__STREXH(__LDREXH(&x) & ((int32u)~((int32u)y)), &x));__CLREX();}
#define setb_amask(x,y) {while(__STREXB(__LDREXB(&x) | (y), &x));__CLREX();}
#define clrb_amask(x,y) {while(__STREXB(__LDREXB(&x) & ((int32u)~((int32u)y)), &x));__CLREX();}

Примеры применения:
CODE
seth_amask(flag, 0x10);
clrh_amask(flag, 0x20);

Вроде бы под IAR компилируется достаточно лаконично.
scifi
Цитата(amiller @ Jan 9 2017, 13:52) *
В процессе переезда с bit-banding сделал несколько макросов, может кому будет интересно:

Пишут же, что CLREX тут не нужен.
zltigo
Цитата(amiller @ Jan 9 2017, 12:52) *
В процессе переезда с bit-banding сделал несколько макросов...

CLREX тут лишние, поскольку STREX сбрасывает флаг доступа.
KnightIgor
Цитата(AVI-crak @ Dec 28 2016, 18:02) *
В реальности это очистка регистра адреса, который используется для мониторинга атомарного адреса. Прикол в том что когда __LDREXW и __STREXW применяется в прерывании, и перебивается другим прерыванием ровно между командами - при возврате получается глюк.

Я тоже много думал и пытался найти подробнее, как работает LDREX/STREX пара, предполагая, что там какие-то адреса мониторятся. Все гораздо... тупее. Никаких адресов. Если между LDREX и STREX произошло хоть какое прерывание, считается, что оно МОГЛО что-то изменить в атомарной переменной, даже если обработчики ни сном, ни духом и нигде пальчиками не лазили, и операция экслюзивности отвергается. Так, на всякий случай. Я не подпишусь, как там с DMA, который может влезть на атомарную переменную. Не нашел упоминания по поводу (может, плохо искал), но по логике предполагаю, что если между LDREX и STREX хоть какое-то телодвижение со стороны DMA было, эффект будет аналогичный прерыванию. В этой связи есть у меня подозрение, что LDREX/STREX внутри прерывания может действительно приводить к странным эффектам.

P.S. Касаемо bit-banding, а точнее - его нужности, то дискуссия в ее нынешнем состоянии есть просто излишня. Здесь нужно принимать явление феноменологически: коль ARM такое замутил, то в этом был и есть глубинный смысл и польза. Не нравится - не ешь.
zltigo
Цитата(KnightIgor @ Jan 9 2017, 15:23) *
В этой связи есть у меня подозрение, что LDREX/STREX внутри прерывания может действительно приводить к странным эффектам.

И каким образом лишний сброс флага эксклюзивности развеивает Ваши подозрения?
scifi
Цитата(KnightIgor @ Jan 9 2017, 16:23) *
Я тоже много думал и пытался найти подробнее, как работает LDREX/STREX пара, предполагая, что там какие-то адреса мониторятся.

А что там думать? Всё же написано:
Цитата
The Cortex-M3 includes an exclusive access monitor, that tags the fact that the processor has executed a Load-Exclusive instruction. If the processor is part of a multiprocessor system, the system also globally tags the memory locations addressed by exclusive accesses by each processor.
The processor removes its exclusive access tag if:
- It executes a CLREX instruction.
- It executes a Store-Exclusive instruction, regardless of whether the write succeeds.
- An exception occurs. This means the processor can resolve semaphore conflicts between different threads.
KnightIgor
Цитата(zltigo @ Jan 9 2017, 15:34) *
И каким образом лишний сброс флага эксклюзивности развеивает Ваши подозрения?

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

Цитата(scifi @ Jan 9 2017, 15:47) *
А что там думать? Всё же написано:

Очень хорошо написано. Кратко. А кто спорит? Но мне в свое время недоставало в документации некой преамбулы, фразы о концепции, идее LDREX|STREX с точки зрения всей системы в процессоре. Вроде "если ход исполнения между LDREX и STREX будет прерыван, будем рассматривать такое ответвление как риск потерять целостность операции, потому, независимо от того, действительно ли изменилась атомарная переменная в результате прерывания или осталась нетронутой, атомарная операция отклоняется". Вроде того.

Кстати, ни слова про DMA, как я на сей момент и предполагал. То есть, надо чисто организационными методами предотвратить какие-либо доступы со стороны DMA в память семафоров. Иначе - защиты от дурака нет.
scifi
Цитата(KnightIgor @ Jan 9 2017, 17:46) *
Но мне в свое время недоставало в документации некой преамбулы, фразы о концепции, идее LDREX|STREX с точки зрения всей системы в процессоре.

Мне тоже. Но тут ничего нового. У них там всё так написано - сухо и кратко. Видимо, не хотят отбирать хлеб у всяких писателей талмудов "кортекс-м3 за 10 простых уроков"...

Цитата(KnightIgor @ Jan 9 2017, 17:46) *
Кстати, ни слова про DMA, как я на сей момент и предполагал. То есть, надо чисто организационными методами предотвратить какие-либо доступы со стороны DMA в память семафоров. Иначе - защиты от дурака нет.

Мне это кажется естественным. Дан простой инструмент, позволяющий реализовать исключительный доступ. А если у вас переполнение стека или кто-то подсунул DMA левые адреса - пеняйте на себя. Тот же MPU не везде присутствует.
jcxz
Цитата(KnightIgor @ Jan 9 2017, 17:46) *
Кстати, ни слова про DMA, как я на сей момент и предполагал. То есть, надо чисто организационными методами предотвратить какие-либо доступы со стороны DMA в память семафоров. Иначе - защиты от дурака нет.

А нафиг оно нужно??? Кому взбредёт в голову работать с переменными эксклюзивного доступа через DMA (либо другим bus master нежели CPU)???
Единственный момент: исходя из выдержки, приведённой scifi, не очень понятно как оно работает в много процессорных системах.
Предполагаю, что возможно так: когда в каком-то из CPU возникает условие "removes its exclusive access tag", то он на внешний вывод выдаёт некий сигнал, по-которому этот флаг сбрасывается во всех остальных CPU.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.