Я вот думал как принудительно заставить GCC считать заранее, но увы нулевая оптимизация раскрывает макросы по умолчанию. К тому-же этот вариант записи только для быстрой настройки во время создания проекта. После полировки, вместо всего этого безобразия - остаётся массив 32b регистров, и простейший цикл. Работает быстрее, но не настолько наглядно.
VladislavS писал(а):
Но когда это на 20-100 ног умножится, то за гранью добра и зла получится.
Наоборот, получится всего 20-100 строк - с предельно понятной записью. А не 800-4000, как в стандартном варианте (по 40 линий на пин).
Достаточно популярный уровень оптимизации учитывая, что у нас мк с 2-х долларовым отладчиком и людям хочется пошагово отлаживать C/C++ код, а не только по ассму шагать Хотя я видел достаточно сложные либы портов на C++ которые с отключенной оптимизацией вообще не компилировались.
Да мне наоборот нужно, чтобы при любом уровне компиляции - часть кода всегда просчитывалась на компе. Потому как предварительная ловля багов уже закончилась.
Да мне наоборот нужно, чтобы при любом уровне компиляции - часть кода всегда просчитывалась на компе. Потому как предварительная ловля багов уже закончилась.
Компилируем простейший код без глобальной оптимизации(_inline_ - это always_inline + O2):
Код:
int _inline_ sum(int x, int y) { return x + y; } GPIOC->ODR = sum(10, 20);
Чтобы компилятор смог такой вызов заинлайнить и, соответственно, свернуть до константы, вызов должен происходить из оптимизированного контекста, обычно это функция которой тоже добавлен атрибут оптимизации. В противном случае инлайнинга не будет и получим передачу параметров в регистрах:
И ничего тут не сделаешь, однако на C++ простое превращение sum() в шаблонную функцию, даже без всяких consxtepr и т.д., проблему решает и вместо вызова функции компилятор подставит 30. То же самое будет если обычную функцию пометить как consteval, тогда и атрибуты оптимизации никакие не нужны:
AVI-crak, зацени вариацию твоего подхода LTDC, режим RGB444, передаем в функцию 14 пинов, она вызывает более общий инит для RGB666 куда передает принятые пины, а вместо 6-ти недостающих добавляются PinDummy<> которые везде игнорируются, но в списке пинов место все равно занимают, т.е. суммарно выходит 20 пинов. Все эти пины передаются в еще один класс который знает какие для конкретного мк допустимы LTDC пины и какие должны быть AF, он все проверяет и если ошибок нет, то возвращается такой-же список пинов, но теперь в нем правильные AF. Принимающая сторона берет у списка тип и запоминает, к этому моменту ничего кроме нового типа не существует и в рантайме компилятору генерить нечего, даже если очень захочется. Остается вызывать для типа списка mode(), она отсеивает все PinDummy<> и для оставшихся пинов формирует массив во флеше. Итого для -O0 получаем такую картину(естественно это все скрыто и в функцию инициализации передаются только пины):
6-ть байт на пару инструкций плюс 4 байта на константу во флеше плюс массив во флеше размером 39 байт Первый байт в каждой строке - это номер порта, затем идет байт режима и байт AF/Pin, эти два байта повторяются сколько потребуется, в конце описания каждого порта и в самом конце идет 0xFF. Класс который формирует массив по сути является усложненной версия класса сортировки массива, который я уже показывал: Спойлер
затем идет байт режима и байт AF/Pin, эти два байта повторяются сколько потребуется
Не всё так просто, для RGB интерфейса есть варианты AF. С таким направлением движения -весь кубик от st имеет реальный шанс переехать в программную реализацию. Вот только при работе с кубиком ломаться нечему, он только предлагает варианты и отображает ограничения. А программный вариант будет материться непонятной ошибкой, без наглядного и простого представления альтернативного варианта.
Кстати, подобный вариант можно написать на регионы памяти mpu. Эти регистры в разных мк - имеют отличие только в общем количестве, но структура и способ применения - совпадают. Там проблема в том что некоторые комбинации запрещены, есть комбинации которые не имеют смысла, и комбинации приводящие к критической ошибке. То-есть очень ограниченное состояние регистров программирующих поведение кеша ядра мк, буквально 64 варианта - которые работают, и приносят пользу.
Не всё так просто, для RGB интерфейса есть варианты AF. С таким направлением движения -весь кубик от st имеет реальный шанс переехать в программную реализацию. Вот только при работе с кубиком ломаться нечему, он только предлагает варианты и отображает ограничения. А программный вариант будет материться непонятной ошибкой, без наглядного и простого представления альтернативного варианта.
Все пины и AF известны, например, такой код компилируется на STM32H750VB:
// static assertion failed: G5 pin is Invalid! // static assertion failed: G6 pin is Invalid! // static assertion failed: PinList has Duplicates!
При таком раскладе даже не нужно подробно расписывать где какой пин, это и так даже во всплывающей подсказке видно, ошибку все равно совершить невозможно.
Reflector - Не, слишком сложно. Компактный ввод данных всегда граничит некоторой потерей информации. Одно дело когда оно раздуто непомерно на несколько десятков строк - с этим можно и нужно бороться. Но когда теряется часть важной информации - то уже поздно бороться, перестарались.
Я даже не буду просить повторить нижеследующий пример. Берём две группы пинов на разных портах. Читаем одну группу как байт, инвертируем и записываем во вторую группу.
Сколько вы это будете руками ковырять... Компилятор делает за долю секунды.
Какая жалость
Код:
error: 'PinList' does not name a type error: 'pins2' was not declared in this scope
видать чего-то не хватает, даже и не знаю сколько же буду ковырять это.
Ну да ладно, господа высокоинтеллектуальные программисты, вопрос не в этом, хотя тема называется
Цитата:
Ассемблер для STM32. Сложно ли, стоит ли пытаться?
но спрошу в этой.
stm32f030 я использую xprintf, с какого-то сайта уже не помню, не важно, но xprintf не работает без printf, из printf всего одна строка printf("\n");
Проблема в этом, если писать xprintf("HELL"); - то работает. А если xprintf("HELLO"); - не работает, сразу с ходу падает в hard fault.
Проблема в этом, HELL во флеш располагается так HELL FFFFFFFF а HELLO так HELL FFFFFFO, здесь еще ноль должен быть но это не важно. Если бинарничек вот с этим HELL FFFFFFO отредактировать так HELL 123O - то работает.
printf("\n") решает эту проблему, но дает лишние 2,5к коду, да на F100 работает без printf("\n").
Ну да ладно, господа высокоинтеллектуальные программисты, вопрос не в этом, хотя тема называется
Цитата:
Ассемблер для STM32. Сложно ли, стоит ли пытаться?
но спрошу в этой.
Наши примеры показывают, возможности инструмента отличного от асма и С. Что в большой степени является ответом на вопоос "а стоит ли". А вот ваш непоймикемнаписанный глючный xprintf тут явно злобный оффтопик.
Наши примеры показывают, возможности инструмента отличного от асма и С. Что в большой степени является ответом на вопоос "а стоит ли".
В первую очередь это возможности вашего класса, но не как не возможности С++. Это не входит в стандартный набор С++, cmsis, а такой ответ как "У меня есть класс который может ..." это не пойдет. Если хвастаетесь, то хвастайтесь более подробно, что бы другой человек мог ваш пример попробовать, оценить, и сказать - да, действительно это что-то значит, это проще, на С++ стоит переходить и т.п. Вот это и есть помощь, а так пока это только пиар.
a797945, ответ я нашел, мне просто интересно было что высокоинтеллектуальные специалисты скажут. А специалисты сказали - курите мануал.
Reflector - Не, слишком сложно. Компактный ввод данных всегда граничит некоторой потерей информации. Одно дело когда оно раздуто непомерно на несколько десятков строк - с этим можно и нужно бороться. Но когда теряется часть важной информации - то уже поздно бороться, перестарались.
Информация не потерялась в следствии стремления к компактности, я сам целенаправленно ее опускаю, потому что она излишня. Можно добавить 14 строк и расписать где какой пин, но зачем если функция и так защищена на 100%... Пины LTDC могут быть разными, сначала пришлось помучаться с их выбором, далее я беру пины со схемы, если там для HSYNC нужен PC6, то проще и вписать PC6 вместо целой строки:
И со speed1 скомпилируется или можно пропустить в конце lock_on, тоже компилируется и при этом размер вырастает на полторы сотни байт, что весьма вероятно указывает на ошибку... Опять же будет существенный проигрыш по размеру, 14*8 vs 49 байт(для -O0 разница в 500+ раз). Кстати, я потестил на разных проектах и далеко не везде даже с моим компактным кодом функция принимающая массив выигрывает у заинлайненых обращений к регистрам портов...
такой ответ как "У меня есть класс который может ..." это не пойдет. Если хвастаетесь, то хвастайтесь более подробно, что бы другой человек мог ваш пример попробовать, оценить, и сказать - да, действительно это что-то значит, это проще, на С++ стоит переходить и т.п. Вот это и есть помощь, а так пока это только пиар.
Мой пример с сортировкой можно скомпилировать без дополнительных библиотек и убедиться, что действительно на этапе компиляции можно получить во флеше массив практически любой сложности. И такой пример - это не то, что можно найти на каждом углу, потому для тех кому интересен C++ - это таки помощь. Для остальных - это пиар С++, ничего не могу поделать с тем, что большинство по-прежнему видит непонятные иероглифы там, где могло бы увидеть выдающие возможности языка и стимул к самосовершенствованию
Я бы где-нибудь в одном месте в заголовочном файле все ноги со схемы перерисовал
А потом после многократных переделок окажется что на одну физическую ногу подключены сразу несколько девайсов, и функция это проглотит. Потому как не различает символьное имя Hsync, Vsync, или spi_cl. Зато знает что такое A0, A2, A2, и умеет с ними обращаться.
Не в том месте бороться нужно, после запуска периферии - это уже не отдельные ноги, а вполне конкретный интерфейс. И вот не нужно тащить ноги в этот интерфейс, ни сверху ни снизу. Если работаете с ногами - работайте с ними, интерфейс уже потом.
И да, нога с символьными именем, или даже с несколькими вариантами символьных имён, но без указания физического номера контакта корпуса мк - это к большой головной боли во время отладки.
А потом после многократных переделок окажется что на одну физическую ногу подключены сразу несколько девайсов, и функция это проглотит. Потому как не различает символьное имя Hsync, Vsync, или spi_cl. Зато знает что такое A0, A2, A2, и умеет с ними обращаться.
Берем PC9, для H750 на него можно заремапить LTDC G3/B2 или DCMI D3, следовательно теоретически я могу использовать этот пин для обоих интерфейсов и ошибки не получу, однако не выйдет PC9 использовать одновременно для G3 и B2, т.к. список пинов проверяется на дубликаты. А если инитить каждый пин по отдельности, то без ошибки скомпилируется код где PC9 используется сразу для G3/B2/D3, причем вовсе не обязательно пины должны быть именно такими, использование любых других пинов вместо требуемых - это также не ошибка. Можно проинитить B1 для которого невозможно подставить неверный AF, но толку от этого, если сам пин другой От тотального контроля компилятором перешли к контролю, пусть и не тотальному, со стороны программиста... У VladislavS другой подход, там все пины инитятся в одном месте одним списком, в таком случае уже проверяются дубликаты во всем проекте.
ps. Если бы функция не различала Hsync и Vsync, то как бы она могла требовать передачи только подходящих пинов?
Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 20
Вы не можете начинать темы Вы не можете отвечать на сообщения Вы не можете редактировать свои сообщения Вы не можете удалять свои сообщения Вы не можете добавлять вложения