Флейм в чистом виде - все что угодно...
Но - в рамках закона :)
Ответить

Re: ARV: мысли вслух

Сб июн 12, 2021 08:34:47

Во-первых, взять мегу для столь простой задачи, это не спортивно.
Во-вторых, у меня два десятка тинек скопилось, что с ними делать, если всякий раз меги покупать?!

Re: ARV: мысли вслух

Пн июн 14, 2021 10:50:35

снова подумываю о карьере управдома... в соседней теме про С/С++ задал вопрос, свидетельствующий о новом тупике...
возможно, конечно, что для меня настала пора чудес... у большинства она в раннем детстве, а у меня вот сейчас...
наверное, этому можно радоваться... :dont_know:

Re: ARV: мысли вслух

Чт июн 17, 2021 08:25:00

вчера столкнулся с интересным эффектом: при включении LTO-оптимизации размер результирующей прошивки не уменьшается, как ожидается, а возрастает, и заметно возрастает... с базовой оптимизацией -O3 без LTO примерно 6,5К прошивка, с LTO почти 8К. это я все про проект своих ГРИ-часов.

всё-таки, я не зря ковыряюсь с ним: столько занятных моментов обнаружил...

Re: ARV: мысли вслух

Чт июн 17, 2021 08:39:28

Использую следующие ключи оптимизации обычно:
Код:
-Os -std=gnu11 -flto -ffunction-sections -fdata-sections -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -Wall -Wl,--warn-common -Wl,--gc-sections -Wl,-lm

Для использования с -flto желательно компилятору указать -ffunction-sections -fdata-sections, чтобы функции и данные в отдельные секции были положены, а линкеру соб-но указать --gc-sections, чтобы он неиспользуемые секции почистил (gc - garbage collection). Попробуйте.

Re: ARV: мысли вслух

Чт июн 17, 2021 08:48:35

NStorm писал(а):желательно компилятору указать -ffunction-sections -fdata-sections,
именно так и делаю, эту фишку еще лет 10 назад разузнал и с тех пор всем начинающим советую сам. и раньше LTO всегда уменьшало прошивку, а вот тут... облом. но это просто результат эксперимента, не трагедия же...

Добавлено after 1 minute 27 seconds:
а вот с -Os мой проект не работает - слишком долго прерывания исполняются, динамическая индикация и стабилизация высокого напряжения ломаются. поэтому -O3

Re: ARV: мысли вслух

Чт июн 17, 2021 08:53:00

Так а --gc-sections линкера тоже используете? Не забыли?

Re: ARV: мысли вслух

Чт июн 17, 2021 09:03:31

NStorm писал(а): Не забыли?
абыжаиш, начальник!

Добавлено after 9 minutes 20 seconds:
вот прямо сейчас повторил эксперимент, чтобы не быть голословным.
без LTO:
AVR Memory Usage
----------
Device: atmega328p

Program: 7506 bytes (22.9% Full)
(.text + .data + .bootloader)

Data: 102 bytes (5.0% Full)
(.data + .bss + .noinit)


с LTO:
AVR Memory Usage
----------
Device: atmega328p

Program: 8626 bytes (26.3% Full)
(.text + .data + .bootloader)

Data: 103 bytes (5.0% Full)
(.data + .bss + .noinit)

Re: ARV: мысли вслух

Чт июн 17, 2021 09:16:20

А версия компилятора какая? Я заметил, что версии новее 5.4.0 от микрочипа генерят больший код.

Re: ARV: мысли вслух

Чт июн 17, 2021 09:21:07

версия avr-gcc в текущий момент у меня 6.3.0, беру не с сайта микрочипа, а с какого-то репозитория вроде как всё еще поддерживаемого какими-то энузиастами

из имеющихся у меня версий от 3.3.2 (WinAVR) до 10.1.0 версия 6.3.0 по моим опытам порождает наиболее оптимальный размер кода.

Re: ARV: мысли вслух

Чт июн 17, 2021 09:23:49

Вот у меня реальный проект завершенный. 7 юнитов. На 5.4.0 (avr-gcc (AVR_8_bit_GNU_Toolchain_3.6.2_1759) 5.4.0) с -flto (опции, которые я выше показал):
Код:
AVR Memory Usage
----------
Device: atmega8

Program:    7184 bytes (87.7% Full)
(.text + .data + .bootloader)

Data:        218 bytes (21.3% Full)
(.data + .bss + .noinit)


Без него:
Код:
AVR Memory Usage
----------
Device: atmega8

Program:    7482 bytes (91.3% Full)
(.text + .data + .bootloader)

Data:        224 bytes (21.9% Full)
(.data + .bss + .noinit)


Сейчас попробую 11.1 собрать.

Репозитарий от энтузиазистов куда более свежих сборок avr-gcc: https://blog.zakkemble.net/avr-gcc-builds/
Попробуйте отсюда. А вообще я на 5.4.0 от микрочипов остановился. По мне он самый стабильный и оптимальный код дает, несмотря на "старость". Тоже советую попробовать. Может в вашей версии кривой LTO.

Re: ARV: мысли вслух

Чт июн 17, 2021 09:27:56

вот откуда беру - сам забыл, пришлось вспоминать: https://blog.zakkemble.net/avr-gcc-builds/
там уже и 11.1.0 есть...

Re: ARV: мысли вслух

Чт июн 17, 2021 09:29:10

Забавно. Попробовать 9.2.0 собрать и получаю ошибку:
Код:
<artificial>:(.text.startup.main+0xe): undefined reference to `WDT_off'

При этом WDT_off объявлено в main.c и оттуда же вызывается только:
Код:
void inline WDT_off(void) {

Убрал inline и собралось... странно. 9.2.0 с LTO:
Код:
AVR Memory Usage
----------
Device: atmega8

Program:    7128 bytes (87.0% Full)
(.text + .data + .bootloader)

Data:        218 bytes (21.3% Full)
(.data + .bss + .noinit)


Без LTO:
Код:
AVR Memory Usage
----------
Device: atmega8

Program:    7490 bytes (91.4% Full)
(.text + .data + .bootloader)

Data:        224 bytes (21.9% Full)
(.data + .bss + .noinit)

Re: ARV: мысли вслух

Чт июн 17, 2021 09:31:01

:))) :))) :))) опередили :beer:

Добавлено after 1 minute 7 seconds:
ну, вы меня сподвигли на эксперименты.
ща стану проверять разные версии из имеющихся

Re: ARV: мысли вслух

Чт июн 17, 2021 09:32:47

11.1 у меня линкер не запускается, Зак собрал его на каком-то новом дистре Linux, требуется более новый GLIBC, чем у меня. Не буду заморачиваться.

EDIT: А хотя фиг с ним, самому интересно уже. Поставил собраться 11.1 скриптом Зака из исходников, посмотрим как соберется под мою систему.
Последний раз редактировалось NStorm Чт июн 17, 2021 09:37:42, всего редактировалось 1 раз.

Re: ARV: мысли вслух

Чт июн 17, 2021 09:40:35

9.2.0 без LTO:
AVR Memory Usage
----------
Device: atmega328p

Program: 7414 bytes (22.6% Full)
(.text + .data + .bootloader)

Data: 102 bytes (5.0% Full)
(.data + .bss + .noinit)


с LTO:
AVR Memory Usage
----------
Device: atmega328p

Program: 8812 bytes (26.9% Full)
(.text + .data + .bootloader)

Data: 103 bytes (5.0% Full)
(.data + .bss + .noinit)


Добавлено after 59 seconds:
9-ка еще хуже собрала :)))

Добавлено after 4 minutes 28 seconds:
10.1.0 с LTO:
AVR Memory Usage
----------
Device: atmega328p

Program: 8846 bytes (27.0% Full)
(.text + .data + .bootloader)

Data: 103 bytes (5.0% Full)
(.data + .bss + .noinit)


без LTO смысла не вижу проверять

4.9.2 - не собралось

5.2.1:
AVR Memory Usage
----------
Device: atmega328p

Program: 8456 bytes (25.8% Full)
(.text + .data + .bootloader)

Data: 103 bytes (5.0% Full)
(.data + .bss + .noinit)


короче, больше не буду, эффект налицо: мой проект с LTO получается больше, чем без :)))

учитесь, пока я жив! :))) :))) :)))

Добавлено after 1 minute 36 seconds:
NStorm, вы попробуйте ваши проекты с -O3 собрать с LTO и без. так будет корректнее сравнивать эффекты.

Re: ARV: мысли вслух

Чт июн 17, 2021 10:35:04

С -O3 оно у меня просто не собирается, из-за того, что не влезает в мегу8 :)))
Дефайнами у меня часть функционала отключается. Значительная. Просто с -Os с отключенным функционалом у меня около 3500 байт занимает... а с -O3 (и LTO):
Код:
AVR Memory Usage
----------
Device: atmega8

Program:    8152 bytes (99.5% Full)
(.text + .data + .bootloader)

Data:        186 bytes (18.2% Full)
(.data + .bss + .noinit)


А без LTO и правда сильно меньше:
Код:
AVR Memory Usage
----------
Device: atmega8

Program:    5918 bytes (72.2% Full)
(.text + .data + .bootloader)

Data:        202 bytes (19.7% Full)
(.data + .bss + .noinit)


Вот значит в чем собака зарыта. Видимо LTO всё-таки не только место старается оптимизировать. Раз задан -O3 оптимизация идет в другую сторону, явно не в сторону места.

Тоже самое, без части функционала, с LTO и -Os просто вот так весит:
Код:
AVR Memory Usage
----------
Device: atmega8

Program:    3720 bytes (45.4% Full)
(.text + .data + .bootloader)

Data:        198 bytes (19.3% Full)
(.data + .bss + .noinit)

Re: ARV: мысли вслух

Чт июн 17, 2021 13:56:59

судя по тому, что с LTO прибавляется и расход ОЗУ, хотя все неиспользуемые переменные выброшены чисткой секций, и в самом деле LTO работает для размера так, а для скорости - этак...

интересное наблюдение, однако.

Добавлено after 2 hours 4 minutes 28 seconds:
начну-ка я помаленечку рассказывать о своем многотрудном проекте часов на ГРИ... в тему про ГРИ не буду, т.к. ничего нового я не внесу туда, а вот тут блуждания моих мыслей вполне уместны.

итак, вот такой код главной функции у меня вышел:
Код:
int main(void){
   show_mode_t show_mode = SHOW_SIMPLE;
   mode_t tm, mode = MODE_TIME;
   uint8_t sec = 255;

   mode_clock_init(mode);

   indication(false); // индикация отключается
   refresh = true;

   sei();

   while(1){
      // TODO проверка питания
      while(main_power_miss()){
         // пока питания нет
         indication(false); // индикация отключается
         sec = time.s;
         // уходим в сон
         do {
            set_sleep_mode(SLEEP_MODE_PWR_SAVE);
            sleep_mode();
            // пробуждение по прерыванию от таймера
            refresh = time.s != sec;
         } while (!refresh);
         continue;
      }
      // при наличии питания
      indication(mode != MODE_NIGHT); // индикация включена, если не ночной режим

      if(time.s != sec){
         refresh = true;
         sec = time.s;
      }

      // выводим режим
      if(modes[mode].show != NULL)
         modes[mode].show(show_mode);

      refresh = false;

      // проверки условий разных событий
      if(!played() && alarm.s && (time.h == alarm.h) && (time.m == alarm.m) && (time.s == 0))
         // принудительно включаем режим будильника, если наступило время
         tm = MODE_WAKE;
      else if(night_time() && (abs(time.s - night_sec) >= 3) && (mode != MODE_NIGHT))
         // принудительно включаем ночной режим, если условие соблюдено
         tm = MODE_NIGHT;
      else
         // иначе получаем и обрабатываем событие
         tm = modes[mode].exec(get_key_event());

      if(tm != mode){
         // если возможно - делаем инициализацию нового режима
         if(modes[tm].init != NULL)
            modes[tm].init(mode);
         mode = tm;
         refresh = true;
      }
   }
}
МК засыпает (POWER_SAVE), если функция main_power_miss вернет true. просыпается он по прерываниям переполнения второго таймера, работающего в асинхронном режиме от часового кварца. таймер настроен так, что переполняется он 16 раз в секунду, но проверка питания осуществляется только 1 раз в секунду, чтобы предельно снизить потребление. делается это вторым циклом внутри того, что с функцией проверки питания - надеюсь, по коду и комментам все понятно.

ну, а затем все более-менее просто:
- функция indication включает-выключает высоковольтный преобразователь и другие энергоёмкие периферийные компоненты МК;
- структура time (поля традиционные - час, минута и секунда) изменяется в обработчике прерывания второго таймера и хранит текущее время;
- переменная mode хранит текущий режим работы часов, а массив modes заполнен функциями, реализующими поведение того или иного режима.

таким образом, логика работы часов реализована в виде конечного автомата: состояние автомата задается переменной mode, а переходы между состояниями определены значением, возвращаемым функцией exec каждого состояния. если осуществляется переход в новое состояние, то, если существует, вызывается функция предварительной инициализации нового состояния. чем-то все это напоминает ООП с конструкторами.

вот, как-то так.

Добавлено after 37 minutes 43 seconds:
наверное, предыдущий текст я напрасно не сопроводил описанием типа и структуры массива modes:
Код:
/// структура методов режима часов
typedef struct {
   void (*init)(mode_t prev);      //!< инициализация
   mode_t (*exec)(event_t ev);      //!< обработчик событий
   void (*show)(show_mode_t sm);   //!< индикация
} mode_methods_t;

static const __flash mode_methods_t modes[MODE_CNT] = {
   //MODE_TIME
      {mode_clock_init, mode_clock_exec, mode_clock_show},
   //MODE_SEC
      {NULL, mode_sec_exec, mode_sec_show},
   //MODE_ALARM
      {mode_alarm_init, mode_alarm_exec, mode_alarm_show},
   //MODE_SETUP
      {mode_edit_init, mode_edit_exec, mode_edit_show},
   //MODE_WAKE
      {mode_wake_init, mode_wake_exec, mode_clock_show},
   //MODE_NIGHT_VIEW
      {mode_nview_init, mode_nview_exec, mode_nview_show},
   //MODE_NIGHT
      {mode_night_init, mode_night_exec, NULL},
   //MODE_NIGHT_EDIT
      {mode_edit_night_init, mode_edit_night_exec, mode_edit_night_show},
};
ну и заодно немного подробностей о состояниях конечного автомата часов:
Код:
/// возможные режимы работы
typedef enum{
   MODE_TIME,         //!< индикация времени
   MODE_SEC,         //!< индикация секунд
   MODE_ALARM,         //!< индикация будильника
   MODE_SETUP,         //!< настройка времени
   MODE_WAKE,         //!< срабатывание будильника
   MODE_NIGHT_VIEW,   //!< индикация настройки ночного режима
   MODE_NIGHT,         //!< ночной режим
   MODE_NIGHT_EDIT,   //!< изменение настроек ночного режима
   //
   MODE_CNT         //!< общее количество режимов
} mode_t;
ночной режим - это когда все ГРИ погашены большую часть времени, и только 1 раз в секунду минуту конечно же (или после нажатия любой кнопки) активируются на 3 секунды. лично меня на этапе засыпания выбешивает свечение во мраке чего-то электронного, даже индикатор зарядки телефона. вот и решил сделать такой режим, сведя к минимуму освещение от часов по ночам, но сохранив возможность, если мучает бессонница, все-таки контролировать время.

Re: ARV: мысли вслух

Пт июн 18, 2021 11:07:56

не могу не процитировать сегодняшний Хабр:
Изображение
:)))

Добавлено after 3 hours 23 minutes 42 seconds:
продолжаю про ГРИ-часы

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

поскольку есть подсветка ламп, можно выделять показания изменяя цвет подсветки. но следует учитывать, что подсветка может быть отключена.

поскольку у меня 2 независимые (в смысле, независимо управляемые) разделительные точки, я решил сделать выделение режимов с их помощью:

1. если точки мигают - видим текущее время, независимо от подсветки
2. если обе точки светятся, не мигая - видим минуты и секунды, независимо от подсветки
3. если светится только одна точка - видим заданное время будильника
4. если точки не светятся - видим настройку ночного режима

в первом случае точки мигают поочередно, т.е. верхняя-нижняя-верхняя-нижняя. не обратить внимание на это нельзя.

во-втором случае обе светятся, но и непрерывно меняющиеся показания правой пары ламп так же выделяют индикацию особо.

в-третьем - если светится верхняя точка, то будильник активирован, если нижняя - заблокирован, а на лампах - установленное время будильника.

наконец, в последнем случае пара левых ламп отображает час начала ночного режима, а правая - час окончания. благодаря отсутствию свечения точек режим так же хорошо различим.

теперь установка/коррекция времени/параметров.
для выделения этих режимов я принял решение использовать подсветку: то, что в текущий момент можно изменить, подсвечивается полной яркостью, остальное не подсвечивается.
настройку реализовал поразрядно, т.к. изменение, например, минут путем нажатия кнопки коррекции до 60 раз, меня не устраивает. когда активируется режим коррекции (длительным нажатием кнопки MODE), подсветка, если была включена, гаснет на всех лампах, кроме самой левой (это десятки часов). цвет подсветки в режиме коррекции всегда один и тот же (пока не определился, какой, пока красный). нажатие MODE переключает подсветку последовательно на единицы часов, десятки минут, единицы минут и снова на десятки часов и т.д. ну а кнопками +/- можно изменять подсвеченную цифру. реализовал и блокировку ввода недопустимого значения: если были показания часов 19 и нажимаем + в разряде десятков часов, то показания меняются на 23, а не на 29. это немного противоречит логике "меняется то, что подсвечено", зато соответствует логике показаний времени.
когда показания введены, надо нажать и удерживать MODE пару секунд для принятия изменений. если этого не сделать, то спустя 30 секунд отсутствия нажатий кнопок часы сбросят введенные показания и вернутся к тем, которые являются текущими.

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

например: короткое нажатие MODE в режиме текущего времени активирует показания минут и секунд, а долгое нажатие этой же кнопки - режим коррекции времени. фактически режим секунд срабатывает по отпусканию MODE, но благодаря тому, что до этого момента осуществляется контроль времени нажатия, пользователь не замечает этого. логика такая же, как в большинстве "настоящих" электронных часов.

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

вот, как-то так, пока что...
Вложения
хабр.PNG
(3.08 KiB) Скачиваний: 640

Re: ARV: мысли вслух

Пт июн 18, 2021 14:51:23

не могу не процитировать сегодняшний Хабр:
Изображение
:)))
Не знаю, это наверное отдельная порода самодельщиков.
У меня наоборот никогда часы и погодные станции не получаются, вместо них всегда что-то совершенно другое получается. :)))

Re: ARV: мысли вслух

Пт июн 18, 2021 15:42:44

как бы ни старался Upgrader сделать часы или погодную станцию, все равно выходит что-то другое :)))
так?
Ответить