Страница 8 из 15
Re: Ассемблер для STM32. Сложно ли, стоит ли пытаться?
Добавлено: Пн дек 07, 2020 16:40:35
AVI-crak
[uquote="Reflector",url="/forum/viewtopic.php?p=3937925#p3937925"]меня 23КБ отожрала[/uquote]
Я вот думал как принудительно заставить GCC считать заранее, но увы нулевая оптимизация раскрывает макросы по умолчанию.
К тому-же этот вариант записи только для быстрой настройки во время создания проекта. После полировки, вместо всего этого безобразия - остаётся массив 32b регистров, и простейший цикл. Работает быстрее, но не настолько наглядно.
VladislavS писал(а):Но когда это на 20-100 ног умножится, то за гранью добра и зла получится.
Наоборот, получится всего 20-100 строк - с предельно понятной записью. А не 800-4000, как в стандартном варианте (по 40 линий на пин).
Re: Ассемблер для STM32. Сложно ли, стоит ли пытаться?
Добавлено: Пн дек 07, 2020 16:41:47
Reflector
[uquote="VladislavS",url="/forum/viewtopic.php?p=3937929#p3937929"]Что такое -O0 ???

[/uquote]
Достаточно популярный уровень оптимизации учитывая, что у нас мк с 2-х долларовым отладчиком и людям хочется пошагово отлаживать C/C++ код, а не только по ассму шагать

Хотя я видел достаточно сложные либы портов на C++ которые с отключенной оптимизацией вообще не компилировались.
Re: Ассемблер для STM32. Сложно ли, стоит ли пытаться?
Добавлено: Пн дек 07, 2020 16:54:28
VladislavS
[uquote="AVI-crak",url="/forum/viewtopic.php?p=3937933#p3937933"]Я вот думал как принудительно заставить GCC считать заранее[/uquote]Вы уже одной ногой на тёмной стороне силы. Не мучайтесь, сделайте этот шаг.
Добавлено after 8 minutes 47 seconds:
[uquote="Reflector",url="/forum/viewtopic.php?p=3937935#p3937935"]Хотя я видел достаточно сложные либы портов на C++ которые с отключенной оптимизацией вообще не компилировались.[/uquote]Я видел целую IDE c компилятором, который на -O0 делал нерабочий код

Re: Ассемблер для STM32. Сложно ли, стоит ли пытаться?
Добавлено: Пн дек 07, 2020 16:54:51
Reflector
[uquote="AVI-crak",url="/forum/viewtopic.php?p=3937933#p3937933"]Я вот думал как принудительно заставить GCC считать заранее, но увы нулевая оптимизация раскрывает макросы по умолчанию[/uquote]
Как минимум можно для дебага инлайнинг отключать добавив перед функцией zap_gpio_nomer():
Код: Выделить всё
#ifndef DEBUG
__attribute__((always_inline))
#endif
Re: Ассемблер для STM32. Сложно ли, стоит ли пытаться?
Добавлено: Пн дек 07, 2020 17:13:51
AVI-crak
Да мне наоборот нужно, чтобы при любом уровне компиляции - часть кода всегда просчитывалась на компе.
Потому как предварительная ловля багов уже закончилась.
Re: Ассемблер для STM32. Сложно ли, стоит ли пытаться?
Добавлено: Пн дек 07, 2020 17:20:11
VladislavS
[uquote="AVI-crak",url="/forum/viewtopic.php?p=3937962#p3937962"]Да мне наоборот нужно, чтобы при любом уровне компиляции - часть кода всегда просчитывалась на компе.[/uquote]расширение файла .cpp, ключ компилятора -std=C++2a и constexpr, consteval, constinit в вашем распоряжении

Re: Ассемблер для STM32. Сложно ли, стоит ли пытаться?
Добавлено: Пн дек 07, 2020 18:03:21
Reflector
[uquote="AVI-crak",url="/forum/viewtopic.php?p=3937962#p3937962"]Да мне наоборот нужно, чтобы при любом уровне компиляции - часть кода всегда просчитывалась на компе.
Потому как предварительная ловля багов уже закончилась.[/uquote]
Компилируем простейший код без глобальной оптимизации(_inline_ - это always_inline + O2):
Код: Выделить всё
int _inline_ sum(int x, int y) { return x + y; }
GPIOC->ODR = sum(10, 20);
Чтобы компилятор смог такой вызов заинлайнить и, соответственно, свернуть до константы, вызов должен происходить из оптимизированного контекста, обычно это функция которой тоже добавлен атрибут оптимизации. В противном случае инлайнинга не будет и получим передачу параметров в регистрах:
Код: Выделить всё
movs r3, #10
str.w r3, [r7, #144]
movs r3, #20
str.w r3, [r7, #140]
ldr.w r2, [r7, #144]
ldr.w r3, [r7, #140]
add r2, r3
ldr r3, [pc, #364]
str r2, [r3, #20]
И ничего тут не сделаешь, однако на C++ простое превращение sum() в шаблонную функцию, даже без всяких consxtepr и т.д., проблему решает и вместо вызова функции компилятор подставит 30. То же самое будет если обычную функцию пометить как consteval, тогда и атрибуты оптимизации никакие не нужны:
Код: Выделить всё
consteval int sum(int x, int y) { return x + y; }
Re: Ассемблер для STM32. Сложно ли, стоит ли пытаться?
Добавлено: Вт дек 08, 2020 22:53:13
Reflector
AVI-crak, зацени вариацию твоего подхода

LTDC, режим RGB444, передаем в функцию 14 пинов, она вызывает более общий инит для RGB666 куда передает принятые пины, а вместо 6-ти недостающих добавляются PinDummy<> которые везде игнорируются, но в списке пинов место все равно занимают, т.е. суммарно выходит 20 пинов. Все эти пины передаются в еще один класс который знает какие для конкретного мк допустимы LTDC пины и какие должны быть AF, он все проверяет и если ошибок нет, то возвращается такой-же список пинов, но теперь в нем правильные AF. Принимающая сторона берет у списка тип и запоминает, к этому моменту ничего кроме нового типа не существует и в рантайме компилятору генерить нечего, даже если очень захочется. Остается вызывать для типа списка mode(), она отсеивает все PinDummy<> и для оставшихся пинов формирует массив во флеше. Итого для -O0 получаем такую картину(естественно это все скрыто и в функцию инициализации передаются только пины):
Код: Выделить всё
using pins = decltype(AltFuncMap<>::ltdc<Hsync, Vsync, R7, R6, R5, R4, R3, R2, G7, G6, G5, G4, G3, G2, B7, B6, B5, B4, B3, B2>());
pins::template mode<PinMode::AF_PushPull>();
// ldr r0, [pc, #256]
// bl 0x24000900
// 00 0e e4 0e ca 0e e3 0e eb ff
// 01 0e eb 0e e8 0e e9 0e ea 0e 91 ff
// 02 0e e7 0e e6 0e e0 ff
// 03 0e e3 ff
// 04 0e ef ff ff
6-ть байт на пару инструкций плюс 4 байта на константу во флеше плюс массив во флеше размером 39 байт

Первый байт в каждой строке - это номер порта, затем идет байт режима и байт AF/Pin, эти два байта повторяются сколько потребуется, в конце описания каждого порта и в самом конце идет 0xFF. Класс который формирует массив по сути является усложненной версия класса сортировки массива, который я уже показывал:
Спойлер
Код: Выделить всё
template<uint32_t N>
class PinModePack
{
struct Pack
{
uint32_t gpio;
uint32_t portNum;
uint32_t pin;
AltFunc af;
PinMode mode;
};
public:
template<typename... Ps>
consteval PinModePack(TypeList<Ps...> ps)
{
Pack pins[] = { { Ps::gpio, Ps::portNumber, Ps::pin, Ps::af, Ps::mode_ }... };
std::ranges::sort(pins, [](auto& p1, auto& p2) { return p1.portNum < p2.portNum; });
auto p = arr;
auto prevPortNum = 0xFF;
for(auto& pin : pins)
{
if (!pin.gpio) continue;
if (prevPortNum != pin.portNum)
{
if(prevPortNum != 0xFF) *p++ = 0xFF;
*p++ = prevPortNum = pin.portNum;
}
*p++ = uint8_t(pin.mode);
*p++ = (uint8_t(pin.af) << 4) | pin.pin;
}
*p++ = 0xFF;
*p++ = 0xFF;
size = p - arr;
}
uint8_t arr[N * 4 + 1]{};
uint32_t size;
};
template<uint32_t N>
struct PinModePackResize
{
consteval PinModePackResize(const uint8_t* ptr) { std::copy(ptr, ptr + N, arr); }
uint8_t arr[N]{};
};
template<PinMode Mode>
static void _inline_ mode()
{
static constexpr auto pinModePack = PinModePack<size(realPins_)>(combinePinsWithModes(pins_, PinModeList<Mode, Size>::modes));
static constexpr auto resize = PinModePackResize<pinModePack.size>(pinModePack.arr);
gpioMode(resize.arr);
}
Re: Ассемблер для STM32. Сложно ли, стоит ли пытаться?
Добавлено: Ср дек 09, 2020 00:52:20
AVI-crak
[uquote="Reflector",url="/forum/viewtopic.php?p=3938798#p3938798"]затем идет байт режима и байт AF/Pin, эти два байта повторяются сколько потребуется[/uquote]
Не всё так просто, для RGB интерфейса есть варианты AF. С таким направлением движения -весь кубик от st имеет реальный шанс переехать в программную реализацию. Вот только при работе с кубиком ломаться нечему, он только предлагает варианты и отображает ограничения. А программный вариант будет материться непонятной ошибкой, без наглядного и простого представления альтернативного варианта.
Кстати, подобный вариант можно написать на регионы памяти mpu. Эти регистры в разных мк - имеют отличие только в общем количестве, но структура и способ применения - совпадают. Там проблема в том что некоторые комбинации запрещены, есть комбинации которые не имеют смысла, и комбинации приводящие к критической ошибке. То-есть очень ограниченное состояние регистров программирующих поведение кеша ядра мк, буквально 64 варианта - которые работают, и приносят пользу.
Re: Ассемблер для STM32. Сложно ли, стоит ли пытаться?
Добавлено: Ср дек 09, 2020 01:12:17
Reflector
[uquote="AVI-crak",url="/forum/viewtopic.php?p=3938838#p3938838"]Не всё так просто, для RGB интерфейса есть варианты AF. С таким направлением движения -весь кубик от st имеет реальный шанс переехать в программную реализацию. Вот только при работе с кубиком ломаться нечему, он только предлагает варианты и отображает ограничения. А программный вариант будет материться непонятной ошибкой, без наглядного и простого представления альтернативного варианта.[/uquote]
Все пины и AF известны, например, такой код компилируется на STM32H750VB:
Код: Выделить всё
ltdc.initRgb444<PC6, PA4, PE15, PB1, PC0, PA11, PD3, PC7, PB11, PB10, PB9, PB8, PA3, PA10>(...);
Тут я поменял пины для R6 и R5, он тоже компилируется(у R6 был AF9, стал AF14):
Код: Выделить всё
ltdc.initRgb444<PC6, PA4, PE15, PA8, PA12, PA11, PD3, PC7, PB11, PB10, PB9, PB8, PA3, PA10>(...);
А здесь я наугад поменял пару пинов из середины списка и получил 3 ошибки:
Код: Выделить всё
ltdc.initRgb444<PC6, PA4, PE15, PA8, PA12, PA11, PD3, PC4, PB10, PB10, PB9, PB8, PA3, PA10>(...);
// static assertion failed: G5 pin is Invalid!
// static assertion failed: G6 pin is Invalid!
// static assertion failed: PinList has Duplicates!
При таком раскладе даже не нужно подробно расписывать где какой пин, это и так даже во всплывающей подсказке видно, ошибку все равно совершить невозможно.
Re: Ассемблер для STM32. Сложно ли, стоит ли пытаться?
Добавлено: Ср дек 09, 2020 16:46:37
AVI-crak
Reflector - Не, слишком сложно. Компактный ввод данных всегда граничит некоторой потерей информации. Одно дело когда оно раздуто непомерно на несколько десятков строк - с этим можно и нужно бороться. Но когда теряется часть важной информации - то уже поздно бороться, перестарались.
Re: Ассемблер для STM32. Сложно ли, стоит ли пытаться?
Добавлено: Ср дек 09, 2020 21:51:17
Dimon456
[uquote="VladislavS",url="/forum/viewtopic.php?p=3937811#p3937811"]Я даже не буду просить повторить нижеследующий пример. Берём две группы пинов на разных портах. Читаем одну группу как байт, инвертируем и записываем во вторую группу.
Код: Выделить всё
PinList<PC7, PC6, PC5, PC4, PC3, PA0, PA1, PA5> pins1;
PinList<PB1, PB2, PB3, PB4, PB5, PD5, PD1, PD0> pins2;
pins2 = ~pins1;
Сколько вы это будете руками ковырять... Компилятор делает за долю секунды.[/uquote]Какая жалость
Код: Выделить всё
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").
Кто что подскажет?
Re: Ассемблер для STM32. Сложно ли, стоит ли пытаться?
Добавлено: Ср дек 09, 2020 22:25:05
VladislavS
[uquote="Dimon456",url="/forum/viewtopic.php?p=3939294#p3939294"]Ну да ладно, господа высокоинтеллектуальные программисты, вопрос не в этом, хотя тема называется
Ассемблер для STM32. Сложно ли, стоит ли пытаться?
но спрошу в этой.[/uquote]Наши примеры показывают, возможности инструмента отличного от асма и С. Что в большой степени является ответом на вопоос "а стоит ли". А вот ваш непоймикемнаписанный глючный xprintf тут явно злобный оффтопик.
Добавлено after 5 minutes 57 seconds:
[uquote="Dimon456",url="/forum/viewtopic.php?p=3939294#p3939294"]Кто что подскажет?[/uquote]Ах, да, про главное то забыл. Курите невыровненый доступ к памяти.
Re: Ассемблер для STM32. Сложно ли, стоит ли пытаться?
Добавлено: Ср дек 09, 2020 22:51:16
a797945
Re: Ассемблер для STM32. Сложно ли, стоит ли пытаться?
Добавлено: Чт дек 10, 2020 06:28:46
Dimon456
VladislavS писал(а):Наши примеры показывают, возможности инструмента отличного от асма и С. Что в большой степени является ответом на вопоос "а стоит ли".
В первую очередь это возможности вашего класса, но не как не возможности С++.
Это не входит в стандартный набор С++, cmsis, а такой ответ как "У меня есть класс который может ..." это не пойдет.
Если хвастаетесь, то хвастайтесь более подробно, что бы другой человек мог ваш пример попробовать, оценить, и сказать - да, действительно это что-то значит, это проще, на С++ стоит переходить и т.п. Вот это и есть помощь, а так пока это только пиар.
a797945, ответ я нашел, мне просто интересно было что высокоинтеллектуальные специалисты скажут. А специалисты сказали - курите мануал.
Re: Ассемблер для STM32. Сложно ли, стоит ли пытаться?
Добавлено: Чт дек 10, 2020 08:31:29
VladislavS
[uquote="Dimon456",url="/forum/viewtopic.php?p=3939425#p3939425"]А специалисты сказали - курите мануал.[/uquote]Не мануал, а невыровненый доступ!
Не припомню, чтобы задолжал вам ни в выкладывании кода, ни в обучении, ни в поиске ошибок.
Re: Ассемблер для STM32. Сложно ли, стоит ли пытаться?
Добавлено: Чт дек 10, 2020 11:54:36
Reflector
[uquote="AVI-crak",url="/forum/viewtopic.php?p=3939081#p3939081"]Reflector - Не, слишком сложно. Компактный ввод данных всегда граничит некоторой потерей информации. Одно дело когда оно раздуто непомерно на несколько десятков строк - с этим можно и нужно бороться. Но когда теряется часть важной информации - то уже поздно бороться, перестарались.[/uquote]
Информация не потерялась в следствии стремления к компактности, я сам целенаправленно ее опускаю, потому что она излишня. Можно добавить 14 строк и расписать где какой пин, но зачем если функция и так защищена на 100%... Пины LTDC могут быть разными, сначала пришлось помучаться с их выбором, далее я беру пины со схемы, если там для HSYNC нужен PC6, то проще и вписать PC6 вместо целой строки:
Код: Выделить всё
gpio_one_pin(zap_gpio.H.pin05.v_af14_ltdc_hsync.speed4.pull_up.lock_on);
Набирая 14 таких строк, где все сливается, можно запросто случайно выбрать HSYNC от DCMI и все скомпилируется:
Код: Выделить всё
gpio_one_pin(zap_gpio.A.pin04.v_af13_dcmi_hsync.speed4.pull_up.lock_on);
И со speed1 скомпилируется или можно пропустить в конце lock_on, тоже компилируется и при этом размер вырастает на полторы сотни байт, что весьма вероятно указывает на ошибку... Опять же будет существенный проигрыш по размеру, 14*8 vs 49 байт(для -O0 разница в 500+ раз). Кстати, я потестил на разных проектах и далеко не везде даже с моим компактным кодом функция принимающая массив выигрывает у заинлайненых обращений к регистрам портов...
[uquote="Dimon456",url="/forum/viewtopic.php?p=3939425#p3939425"]такой ответ как "У меня есть класс который может ..." это не пойдет.
Если хвастаетесь, то хвастайтесь более подробно, что бы другой человек мог ваш пример попробовать, оценить, и сказать - да, действительно это что-то значит, это проще, на С++ стоит переходить и т.п. Вот это и есть помощь, а так пока это только пиар.[/uquote]
Мой пример с сортировкой можно скомпилировать без дополнительных библиотек и убедиться, что действительно на этапе компиляции можно получить во флеше массив практически любой сложности. И такой пример - это не то, что можно найти на каждом углу, потому для тех кому интересен C++ - это таки помощь. Для остальных - это пиар С++, ничего не могу поделать с тем, что большинство по-прежнему видит непонятные иероглифы там, где могло бы увидеть выдающие возможности языка и стимул к самосовершенствованию

Re: Ассемблер для STM32. Сложно ли, стоит ли пытаться?
Добавлено: Чт дек 10, 2020 13:03:35
VladislavS
[uquote="Reflector",url="/forum/viewtopic.php?p=3939526#p3939526"]Пины LTDC могут быть разными, сначала пришлось помучаться с их выбором, далее я беру пины со схемы[/uquote]Я бы где-нибудь в одном месте в заголовочном файле все ноги со схемы перерисовал
Код: Выделить всё
using Hsync = PC6;
using Vsync = PA4;
...
using B2 = PA10;
и уже по коду вызывал вполне понятное
Код: Выделить всё
ltdc.initRgb444<Hsync, Vsync, R7, R6, R5, R4, R3, R2, G7, G6, G5, G4, G3, G2, B7, B6, B5, B4, B3, B2>(...);
[uquote="Reflector",url="/forum/viewtopic.php?p=3939526#p3939526"]И такой пример - это не то, что можно найти на каждом углу, потому для тех кому интересен C++ - это таки помощь.[/uquote]100% - хоть конспектируй!
Re: Ассемблер для STM32. Сложно ли, стоит ли пытаться?
Добавлено: Чт дек 10, 2020 13:56:20
AVI-crak
[uquote="VladislavS",url="/forum/viewtopic.php?p=3939559#p3939559"]Я бы где-нибудь в одном месте в заголовочном файле все ноги со схемы перерисовал[/uquote]
А потом после многократных переделок окажется что на одну физическую ногу подключены сразу несколько девайсов, и функция это проглотит. Потому как не различает символьное имя Hsync, Vsync, или spi_cl. Зато знает что такое A0, A2, A2, и умеет с ними обращаться.
Не в том месте бороться нужно, после запуска периферии - это уже не отдельные ноги, а вполне конкретный интерфейс. И вот не нужно тащить ноги в этот интерфейс, ни сверху ни снизу. Если работаете с ногами - работайте с ними, интерфейс уже потом.
И да, нога с символьными именем, или даже с несколькими вариантами символьных имён, но без указания физического номера контакта корпуса мк - это к большой головной боли во время отладки.
Re: Ассемблер для STM32. Сложно ли, стоит ли пытаться?
Добавлено: Чт дек 10, 2020 14:26:19
Reflector
[uquote="AVI-crak",url="/forum/viewtopic.php?p=3939580#p3939580"]А потом после многократных переделок окажется что на одну физическую ногу подключены сразу несколько девайсов, и функция это проглотит. Потому как не различает символьное имя Hsync, Vsync, или spi_cl. Зато знает что такое A0, A2, A2, и умеет с ними обращаться.[/uquote]
Берем PC9, для H750 на него можно заремапить LTDC G3/B2 или DCMI D3, следовательно теоретически я могу использовать этот пин для обоих интерфейсов и ошибки не получу, однако не выйдет PC9 использовать одновременно для G3 и B2, т.к. список пинов проверяется на дубликаты. А если инитить каждый пин по отдельности, то без ошибки скомпилируется код где PC9 используется сразу для G3/B2/D3, причем вовсе не обязательно пины должны быть именно такими, использование любых других пинов вместо требуемых - это также не ошибка. Можно проинитить B1 для которого невозможно подставить неверный AF, но толку от этого, если сам пин другой

От тотального контроля компилятором перешли к контролю, пусть и не тотальному, со стороны программиста... У
VladislavS другой подход, там все пины инитятся в одном месте одним списком, в таком случае уже проверяются дубликаты во всем проекте.
ps. Если бы функция не различала Hsync и Vsync, то как бы она могла требовать передачи только подходящих пинов?