Ну говорю ж, блондинко со склерозом... -Os, не -О3... Вы правы. Давно не писала ничего уже, работа на работе полностью удовлетворяет...JackSmith писал(а):Чем "-Os" не угодил?
Stm32 с чего начать изучение...
- Just_Fluffy
- Вымогатель припоя
- Сообщения: 532
- Зарегистрирован: Ср июн 29, 2022 16:25:45
Re: Stm32 с чего начать изучение...
Белая и Пушистая
Re: Stm32 с чего начать изучение...
[uquote="Nranddek",url="/forum/viewtopic.php?p=4737789#p4737789"]Отладка возможна на всех уровнях оптимизации, другое дело, что можно, например, удивиться невозможности поставить breakpoint - это место может исчезнуть в результате оптимизации. Да и вообще, мне кажется странным отлаживание в одном уровне, а затем его изменить и получить иную версию кода.[/uquote]
breakpoint ставится, но в локальных переменных при трассировке пишет "optimized out"
breakpoint ставится, но в локальных переменных при трассировке пишет "optimized out"
Re: Stm32 с чего начать изучение...
Правильно. Эти переменные могут не сохраняться в ОЗУ и находиться в регистрах ядра. Исключаются лишние операции записи в ОЗУ и обратного их считывания оттудава.
Re: Stm32 с чего начать изучение...
отладчик без проблем из регистров читает, тут что-то другое

с флагом "-Og" все нормально.

с флагом "-Og" все нормально.
Re: Stm32 с чего начать изучение...
uint32_t interval = WAIT;
Причем, WAIT - это, судя по виду, константа. А константы - они оптимизируются и помещаются внутрь параметров инструкций.
А вон она - строчка 29 справа, с movw r6, #3000 - компилятор посчитал константные выражения и поместил их сразу в параметр инструкции.
Напишите перед объявлением переменной (обоих переменных) volatile и еще раз посмотрите.
самая частая проблема - "Памагите, я включил оптимизацию и на выходе получил 0 кБ кода, хотя там было написано 300 строк!"
Так что нечего на зеркало то пенять
А то крик то подняли, ай-ой, фуфло, константные выражения в функции оптимизатор выкинул, ой-ой, что такое Всё норм, посоны, не истерите. Всё нормальдос. Если продолжает работать, значит, всё норм. Хуже было бы, если бы из тыщщи строк он оставил 0 строк. Это говорило бы о том, что погромисътъ был пьян:)
Причем, WAIT - это, судя по виду, константа. А константы - они оптимизируются и помещаются внутрь параметров инструкций.
А вон она - строчка 29 справа, с movw r6, #3000 - компилятор посчитал константные выражения и поместил их сразу в параметр инструкции.
Напишите перед объявлением переменной (обоих переменных) volatile и еще раз посмотрите.
Так что нечего на зеркало то пенять
Re: Stm32 с чего начать изучение...
константа ни при чем.
до строки
до строки
отладчик показывает значение переменной interval, а после "optimized out".int remainder=smart_delay(interval);
Re: Stm32 с чего начать изучение...
Так я и говорю - перед объявлением обеих переменных напишите volatile.
С другой стороны, если после оптимизации всё работает как надо без сбоев, то значит, всё в порядке, не кричите. Переменная была оптимизирована и помещена в параметры инструкции movw.
Можете проийтись по отладке в режиме Instruction Step Mode (по ассемблерному листингу) и посмотреть, что происходит с переменной.
С другой стороны, если после оптимизации всё работает как надо без сбоев, то значит, всё в порядке, не кричите. Переменная была оптимизирована и помещена в параметры инструкции movw.
Можете проийтись по отладке в режиме Instruction Step Mode (по ассемблерному листингу) и посмотреть, что происходит с переменной.
Re: Stm32 с чего начать изучение...
[uquote="КотПротон",url="/forum/viewtopic.php?p=4737839#p4737839"]Так я и говорю - перед объявлением обеих переменных напишите volatile.[/uquote]
Зачем менять код, если можно поставить флаг компиляции "-Og" и все будет норм?
Зачем менять код, если можно поставить флаг компиляции "-Og" и все будет норм?
Re: Stm32 с чего начать изучение...
А вам шашечки или ехать? В смысле - смотреть на ваши любимые переменные, или чтобы код работал эффективно?
Re: Stm32 с чего начать изучение...
КотПротон, это "volatile" что ли делает код эффективным?
Re: Stm32 с чего начать изучение...
Нет, volatile показывает вашу любимую переменную, чтобы вы могли наслаждаться созерцанием её.
А еще, volatile - способ вернуть неожиданно исчезнувшие из бинарника 500 строк важного кода, которые вы так старательно писали, а негодяй-оптимизатор посчитал ваши труды никчемной тратой пространства на флеше
А еще, volatile - способ вернуть неожиданно исчезнувшие из бинарника 500 строк важного кода, которые вы так старательно писали, а негодяй-оптимизатор посчитал ваши труды никчемной тратой пространства на флеше
Re: Stm32 с чего начать изучение...
[uquote="КотПротон",url="/forum/viewtopic.php?p=4737846#p4737846"]А еще, volatile - способ вернуть неожиданно исчезнувшие из бинарника 500 строк важного кода, которые вы так старательно писали[/uquote]
нафига такой оптимизатор?
нафига такой оптимизатор?
Re: Stm32 с чего начать изучение...
А нафига такой погромист, который забыл (не знает) про volatile? 
Re: Stm32 с чего начать изучение...
[uquote="КотПротон",url="/forum/viewtopic.php?p=4737573#p4737573"]А у вас инит I2C зависит от дисплея. Нелогично. Либо писать один и тот же инит I2C и в дисплее, и во всех остальных устройствах, либо обращаться к иниту дисплея, чтобы настроить I2C, либо просто вынести инит I2C за пределы модуля дисплея..[/uquote]
на самом деле ничего страшного не будет, если инициализация дисплея будет включать инициализацию I2C модуля и связанные GPIO. даже если на шине более чем одно устройство.
на самом деле ничего страшного не будет, если инициализация дисплея будет включать инициализацию I2C модуля и связанные GPIO. даже если на шине более чем одно устройство.
- Just_Fluffy
- Вымогатель припоя
- Сообщения: 532
- Зарегистрирован: Ср июн 29, 2022 16:25:45
Re: Stm32 с чего начать изучение...
Значит далее в данном программном блоке данная переменная не используется, программный код обходится и без нее без потери функционалаJackSmith писал(а):отладчик показывает значение переменной interval, а после "optimized out".
Белая и Пушистая
Re: Stm32 с чего начать изучение...
Ничего страшного для тех, кто пишет как бох на душу положитичего страшного не будет, если инициализация дисплея будет включать инициализацию I2C модуля и связанные GPIO
Но для тех, кто думает разумом, это сигнал к исправлению неверной структуры программы.
Показываю на гипотетическом примере: на одной шине I2C висит дисплей и датчик температуры. Инит I2C и инит его пинов написан только в функции инита дисплея:
Код: Выделить всё
void InitDisplay()
{
InitI2CPins();
InitI2C();
WriteI2C(0xAA);
}
void InitSensor()
{
WriteI2C(0xBB);
}
Код: Выделить всё
int main(void)
{
InitSensor();
InitDisplay();
Ога. Обычный кодописатель впихнет InitI2CPins(); InitI2C(); и в функцию InitSensor(). На всякий случай.
Думающий программист прикинет возможные последствия - дублирование кода, лишние логические связи, и просто вынесет фукнции инита за пределы функций инита дисплея и сенсора. Всё просто, если мыслить думать!
Re: Stm32 с чего начать изучение...
[uquote="КотПротон",url="/forum/viewtopic.php?p=4737857#p4737857"]Обычный кодописатель впихнет InitI2CPins(); InitI2C(); и в функцию InitSensor(). На всякий случай.[/uquote]
грязные инсинуации.
[uquote="КотПротон",url="/forum/viewtopic.php?p=4737857#p4737857"]Думающий программист прикинет возможные последствия - дублирование кода, лишние логические связи, и просто вынесет фукнции инита за пределы функций инита дисплея и сенсора.[/uquote]
поздравляю, вы открыли распределительный закон из второго класса
КотПротон, девчонка шарит лучше тебя. надеюсь тебе стыдно?
грязные инсинуации.
[uquote="КотПротон",url="/forum/viewtopic.php?p=4737857#p4737857"]Думающий программист прикинет возможные последствия - дублирование кода, лишние логические связи, и просто вынесет фукнции инита за пределы функций инита дисплея и сенсора.[/uquote]
поздравляю, вы открыли распределительный закон из второго класса
Just_Fluffy писал(а):JackSmith писал(а):Значит далее в данном программном блоке данная переменная не используется, программный код обходится и без нее без потери функционала
КотПротон, девчонка шарит лучше тебя. надеюсь тебе стыдно?
Re: Stm32 с чего начать изучение...
я написал, что переменная была оптимизирована и перенесена в параметр инструкции movw r6, #3000, и даже показал, где она находится. Если вы не шарите в ассемблерном тексте и слабо понимаете написанное, то это исключительно ваша личная беда.
Re: Stm32 с чего начать изучение...
Пролистывая на досуге форум, наткнулся еще на один опус. В целом, товарищ погрузился в глубины, но навалял таких дров, как и в предыдущем разобранном примере. Код изобилует оверинженирингом и не очень хорошим пониманием того, что и для чего автор пишет. Такое впечатление, что он пишет наугад и возникшие проблемы решает наваливанием, а не разгребанием каши, пытаясь применить весь инструментарий языка, который он узнал.
Всё-таки, от написания лапшеобразного кода программиста должно удерживать знание принципов построения взаимосвязей и логики. То есть, когда ты понимаешь, что ты хочешь получить на выходе, ты выбираешь путь и инструменты именно те, которые минимально нужны для достижения цели. А не так, как там - наугад, не видя, что в конце.
Вот что представляет тот товарищ в виде схемы:
Похвала ему в том, что он составляет хоть какие-то схемы, это несомненно ценно.
Правда, есть там функциональная ошибка - unlock() в GPIO не будет работать, поскольку механизм блокировки настроек пинов не подразумевает разблокировки вообще. Блокируются они до следующего перезапуска после сброса.
А вот дальше портянка кода - довольно жуткое зрелище именно по причине неверного построения логики. Автор использует инструменты языка без понимания того, зачем он их использует в конкретной задаче.
Суть опуса - банальнейшая работа с портом и пинами на плюсах. И в целом, если по уму, это реализуется значительно проще. Значительно. Единственная не слишком красивая штука - это виртуальный параллельный порт с вариативным шаблоном списка пинов. Но виртуальный порт - это не аппаратная часть, он немножко на другом уровне. А в остальном, всё делается сильно проще.
Во-первых, прежде чем наворачивать списки параметров шаблона класса, надо включить голову и подумать.
Автор предлагает:
Но если подумать - а что вообще может быть общего у всего порта GPIO с его 16-ю пинами? Что общее вообще у всех этих пинов? А общее и неизменное у них только одно - буква в имени порта, или иначе говоря, базовы адрес регистров. Так вот этот параметр и следует выносить в шаблон для всего класса Gpio. Ну и во-вторых, имена классов надо задавать попроще, без несущественных уточнений: template<char Name> class Gpio; Всё, больше там ничего не надо, просто, понятно легко запоминается и кратко пишется. Маска пинов в классе аппаратного порта не нужна, она ставится в методах, а не в общем классе. Наследования так же не нужны, ибо описывается класс для работы с хардварным портом GPIOx как он есть, не придумывая того, чего в нем нет.
Для описания виртуального параллельного порта с произвольным набором пинов должен быть отдельный класс, работающий через класс аппаратного Gpio, и виртуальный порт может быть не ограничен максимум 16-ю пинами и не ограничен одним хардварным портом. И это - правильная логика взаимосвязей. Вообще, виртуальный параллельный порт довольно редко используется, можно по пальцам пересчитать случаи его применения. Но ладно.
Да не "вроде", а точно там uint16_t надо. Сами ж написали в static_assert, что ширина порта максимум 16 пинов.
Дальше идут мелкие ошибки, такие как
и нелогичности
зачем копировать данные со входов одного Gpio в выход другого Gpio? На практике это вообще вряд ли когда будет использовано. Я не припомню ни единого случая, когда прочитанное со входов одного порта тут же без изменений передавалось на выход другого порта. А писать "мёртвый код" - лишь замусоривать класс. Этот мусор лишь ради дешевых понтов, или когда платят за кол-во строк, как у индусов. Индусский код - вот правильное слово для характеристики написанного автором. Индусский код. Участники форума подозревали это, но, к сожалению, не смогли аргументированно объяснить автору.
Так же есть каша в задании конфигурации пинов.
Конфигурация пинов описывается сильно проще. Опять же, надо посмотреть на конечную цель - какие есть режимы пина. А их 4 штуки - аналоговый, цифровой вход, цифровой выход и альтернативная функция. В аналоговом режиме нет настраиваемых параметров. В режиме цифрового входа - enum class InType {HiZ, PP, PD}, в режиме цифрового выхода - enum class OutType {PP, OD} и enum class Speed {LOW, MED, HIGH, VHIGH}. В режиме альт.функ. добавляется номер ф-ции, который при желании можно оформить аналогично в виде списка имен.
Если хочется конфигурировать за один раз разные пины в разные режимы, то тогда класс Gpio должен предоставлять открытый интерфейс для прямой записи регистров MODER, OTYPER и тд. как они есть. А вот сборку значений для этих регистров из отдельных пинов проводить следует вне класса Gpio. И тогда уж тем более в шаблоне класса Gpio не должно быть упоминания о режиме пинов, поскольку это будет нелогично, что режимы пинов - разные.
Хотя на практике чаще требуется конфигурировать в один режим несколько пинов. Например, SDRAM с её более чем 50-пинами в максималке требует одинаковой конфигурации используемых пинов. При этом, на одном аппаратном GPIO может находиться более половины пинов для нее.
Ну и в завершении, вместо
напишите просто и коротко: using GpioA = Gpio<'A'>; Не нужно "создавать" порт и "создавать" его пины, всё уже создано производителем МК. Нужно только реализовать методы работы с ним.
Пример с "созданием" порта я видел когда-то много-много лет назад. Не знаю, чья это была идея, но автор разбираемого здесь опуса, как видно, пошел тем же путем. Чья-то ошибка распространилась в головы и других начинающих.
И если автор пишет, что
Вот уж и правда - "Горе от ума"
Автор пытается применить сразу все инструменты, которые он только что узнал.
Есть расхожая фраза: "Keep it simple, stupid". Что в переводе означает: "Пиши проще, чувак!"
Всё-таки, от написания лапшеобразного кода программиста должно удерживать знание принципов построения взаимосвязей и логики. То есть, когда ты понимаешь, что ты хочешь получить на выходе, ты выбираешь путь и инструменты именно те, которые минимально нужны для достижения цели. А не так, как там - наугад, не видя, что в конце.
Вот что представляет тот товарищ в виде схемы:
Спойлер
Правда, есть там функциональная ошибка - unlock() в GPIO не будет работать, поскольку механизм блокировки настроек пинов не подразумевает разблокировки вообще. Блокируются они до следующего перезапуска после сброса.
А вот дальше портянка кода - довольно жуткое зрелище именно по причине неверного построения логики. Автор использует инструменты языка без понимания того, зачем он их использует в конкретной задаче.
Суть опуса - банальнейшая работа с портом и пинами на плюсах. И в целом, если по уму, это реализуется значительно проще. Значительно. Единственная не слишком красивая штука - это виртуальный параллельный порт с вариативным шаблоном списка пинов. Но виртуальный порт - это не аппаратная часть, он немножко на другом уровне. А в остальном, всё делается сильно проще.
Во-первых, прежде чем наворачивать списки параметров шаблона класса, надо включить голову и подумать.
Автор предлагает:
Код: Выделить всё
template<uint32_t GpioID, uint32_t PinsMask, typename TPM = STM32Fx_MODE::NotDefined,
uint32_t pwr_moder=0, uint32_t pwr_ospeedr=0, uint32_t pwr_pupdr=0>
class TSTM32Fx_GPIO : public GpioTemplate<GpioID, 16, PinsMask, TPM>
Для описания виртуального параллельного порта с произвольным набором пинов должен быть отдельный класс, работающий через класс аппаратного Gpio, и виртуальный порт может быть не ограничен максимум 16-ю пинами и не ограничен одним хардварным портом. И это - правильная логика взаимосвязей. Вообще, виртуальный параллельный порт довольно редко используется, можно по пальцам пересчитать случаи его применения. Но ладно.
Код: Выделить всё
_static_always_inline_ void write(uint32_t data) // Тут вроде uint16_t надо
Дальше идут мелкие ошибки, такие как
Код: Выделить всё
_static_always_inline_ void toggle()
{
base()->ODR = ~base()->ODR;
Код: Выделить всё
_always_inline_ TSTM32Fx_GPIO& operator=(const TSTM32Fx_GPIO& gpio)
{
write(gpio.read());Так же есть каша в задании конфигурации пинов.
Конфигурация пинов описывается сильно проще. Опять же, надо посмотреть на конечную цель - какие есть режимы пина. А их 4 штуки - аналоговый, цифровой вход, цифровой выход и альтернативная функция. В аналоговом режиме нет настраиваемых параметров. В режиме цифрового входа - enum class InType {HiZ, PP, PD}, в режиме цифрового выхода - enum class OutType {PP, OD} и enum class Speed {LOW, MED, HIGH, VHIGH}. В режиме альт.функ. добавляется номер ф-ции, который при желании можно оформить аналогично в виде списка имен.
Если хочется конфигурировать за один раз разные пины в разные режимы, то тогда класс Gpio должен предоставлять открытый интерфейс для прямой записи регистров MODER, OTYPER и тд. как они есть. А вот сборку значений для этих регистров из отдельных пинов проводить следует вне класса Gpio. И тогда уж тем более в шаблоне класса Gpio не должно быть упоминания о режиме пинов, поскольку это будет нелогично, что режимы пинов - разные.
Хотя на практике чаще требуется конфигурировать в один режим несколько пинов. Например, SDRAM с её более чем 50-пинами в максималке требует одинаковой конфигурации используемых пинов. При этом, на одном аппаратном GPIO может находиться более половины пинов для нее.
Ну и в завершении, вместо
Код: Выделить всё
#ifdef GPIOA
MAKE_PORT(A,PWR_CFG_A)
MAKE_16PINS(GpioA,A)
#endif
Пример с "созданием" порта я видел когда-то много-много лет назад. Не знаю, чья это была идея, но автор разбираемого здесь опуса, как видно, пошел тем же путем. Чья-то ошибка распространилась в головы и других начинающих.
И если автор пишет, что
то я даже не представляю, что у него творилось в голове, когда он всё это писалПри том что самая жесть на самом деле слева от черты.
Есть расхожая фраза: "Keep it simple, stupid". Что в переводе означает: "Пиши проще, чувак!"
Re: Stm32 с чего начать изучение...
BusMaster, ну сколько можно? )