Код STM раздут?

Доктек
Ср. 25 июля 2018 г., 4:25
Я пытаюсь создать очень маленькие ардуиносы. Я использовал avrtiny84, но у него всего 8 тысяч вспышки. Некоторые из чипов ST не намного больше (в пакетах ufqfn), но имеют 32 тыс. Флэш, все еще в очень низкой мощности, недорогой пакет. Я делаю прорывную доску, но чтобы программное обеспечение работало, я работаю с L053 Nucleo и L031 Nucleo. Мои первые проекты (после Blink) были простым интерфейсом I2C с несколькими чтениями и записями. Очень просто.

Программное обеспечение все сработало! Я очень счастлив, кроме одной проблемы. Размер кода огромный! Его более 22 тыс. Сладкой и более 20 тыс. С наименьшей оптимизацией. Это почти 70% кодового пространства, разжевываемого, чтобы выполнить простую задачу! Поскольку я могу сделать это легко в Tiny84, я вижу это как стоп -шоу шоу!

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

Спасибо за любые предложения.

Доктек
Ср. 25 июля 2018 г. 5:13
Хм. После моего смелого обвинения в вздутии кода, я подумал, что должен собрать некоторые данные.
Программа -Teensy2- Teensy3.2- L031
Мигание 2410 11 592 10 248
I2c 5.016 21 212 20 780
Похоже, проблема в использовании руки, а не реализации STM. Так что я думаю, что мой вопрос просто должен быть перефразирован: почему у процессоров Arm столько накладных расходов? Есть ли способ уменьшить его, или я сталкиваюсь с необходимостью использовать устройство с большей вспышкой (Ala Teensy 3.2)? Я не вижу, как использование L031 было бы усилием, просто используя Tiny84.

fpistm
Ср. 25 июля 2018 г. 6:08
Привет, на трубе есть некоторые оптимизации:
https: // github.com/stm32duino/arduino_c ... Проблемы/228
https: // github.com/stm32duino/arduino_c ... Проблемы/274

Еще одна оптимизация, которая сохраняет пространство, - использовать LL для конфигурации часов, это сохранит некоторое пространство, пример здесь:
https: // github.com/stm32duino/arduino_c ... -373646769

Стивестронг
Ср. 25 июля 2018 г., 6:59
Короткий поиск на форуме (вы знаете, небольшое неважное поле в верхней правой части страницы, которое мало используется ;) ) показал бы много дискуссий об этом...

Дэнниф
Ср. 25 июля 2018 г. 10:26
Почему у процессоров рук столько накладных расходов? 1. Подход программирования: для более крупных / более сложных чипов подход программирования имеет тенденцию быть более модульным. Это означает больше слоев и больше кода для той же функциональности на 8-битном чипе;
2. Плотность кода, как правило, ниже на 32-разрядном чипе против. 8-битный чип.
3. Ваша конкретная реализация.
...

AG123
Ср. 25 июля 2018 г. 15:46
Libmaple STM32Duino Core имеет USB-сериал-сборку в эскизе, он является частью Core STM32Duino Sake Sake Leaflabs Maple. Это больше, чем просто UART, и он уходит с отдельным USB-сериалом на борту, и теперь мы выходим за рамки просто USB-сериал для других USB-функций, но это другая тема

Если вы готовы обойтись без USB-сериала, вы можете редактировать доски.txt и undefine -deserial_usb Flag
Я не слишком уверен, что если вы просто включите файл заголовка и поместите #undef serial_usb, это было бы таким же, как здание без USB-сериала
Без USB-сериала вы не сможете делать такие вещи, как сериал.написать ("любое сообщение"); Чтобы отправить что -нибудь обратно в свою серийную консоли

Другие вещи - компилятор и различные флаги оптимизации E.глин.
-Fno-Exceptions Нет исключений
-fno-rtti нет информации о типе времени
-fno_use_cxa_atexit без использования cxa atexit
-Fno-threadsafe-statics-без безопасной нити статики
-nostdlib - без запуска или по умолчанию
-Xlinker-gc-sections Удалить неиспользованные секции (это может сэкономить много места)
-Spects = nano.Спецификации - используйте Newlib -Nano

Некоторые из них, вероятно, на платформе.TXT или доски.TXT, так что имейте резервные копии, если вы их редактируете.
Использование всех вышеупомянутых флагов на самом деле все еще позволяет моим эскизам работать ОК, но ваш пробег может варьироваться

Доктек
Ср. 25 июля 2018 г., 21:45
Спасибо за быстрые, полезные ответы!
fpistm - я посмотрю на эти предметы сегодня вечером.
Stevestrong - Поиск L053 или L031 поднял только мои собственные самые последние посты. Вот почему я опубликовал.
AG123 - Хммм. Я внимательно посмотрю на USB-сериал. Я также проверю другие предметы, которые вы упоминаете.

Спасибо, все!

Стивестронг
Чт 26 июля 2018 г., 7:36 утра
Я только что понял, что это связано с ST Core, поэтому я перемещаю эту тему там.

Доктек
Пт 27 июля 2018 12:24
Спасибо, что поместили это на надлежащий форум, Stevestrong.

Следуя тому, что кажется самым прямым путем к уменьшению размера кода, я пытаюсь избавиться от UART и, надеюсь, USB. Но я не делаю очень хорошего успеха. Вот что я сделал.

В вариантах/ucleo_l031k6, я модифицированный вариант.H и STM32L0XX_HAL_CONF.H, чтобы прокомментировать UART и Serial Port определяет. Однако, когда я пытаюсь скомпилировать (из среды Arduino), UART_Handletypedef не определен. Проблема в том, что термин определяется в STM32L0XX_HAL_CONF.H, но этот файл не включен из -за описанных модов, которые я описал. Так что когда uart.H включен из досок.H, я получаю ошибку.

Вы, вероятно, думаете, почему бы не изменить доски.h не называть uart.час? Ну, это приводит к дальнейшим проблемам. Я пошел по этому пути, даже комментируя большие разделы кода в различных файлах. Где это заканчивается, что Mass_storageUploadMethod вызывает syscalls_stm32.c, который называет uart_debug_write, который не найден (потому что я вытащил UART, помните?). Источник для них не включен, поэтому я ничего не могу с этим поделать. Переключение на загрузку Stlink имеет такую ​​же проблему. Я не вижу, как указать «без загрузки» в среде Arduino, поэтому я также застрял в этом маршруте.

Любые предложения о том, как продолжить, будут наиболее оценены. Избавление от UART кажется важным шагом.

Доктек
Пт 27 июля 2018 г., 4:13
Больше экспериментов. После другого предложения AG123 я модифицировал доски.txt, чтобы удалить {build.enable_usb} {build.xserial} из сборки.Extra_flags. Я удалил все остальные изменения. Код создан без проблем, но точно такой же размер.

Возможно, я не делаю модификации в нужном месте. У меня действительно нет хорошей идеи и ценю все предложения.

Рик Кимбалл
Пт 27 июля 2018 г., 4:22 утра
Используйте ARM-None-Eabi-NM на .Файл ELF, сортируйте по размеру, начните с самых больших пользователей памяти и выясните, как они включаются и если вам действительно нужно то, что они предоставляют

fpistm
Пт 27 июля 2018 г., 6:17
По умолчанию USB не определено.
Для USART просто выберите «Отключить» в меню серийного интерфейса.

Стивестронг
Пт 27 июля 2018 г., 7:49
Я использую Амап Чтобы проанализировать сгенерированный файл карты, вы можете выяснить, какой сегмент является самым большим.

Доктек
Сб 28 июля 2018 г. 20:37
Спасибо всем за публикации! Я использовал NM в прошлом, поэтому я пробовал amap. Работал отлично и очень полезен.

Первое, что я обнаружил, это то, что выбирать без сериала не имел значения в размере кода. Также не удалось удалить меню метода загрузки и действия в досках.текст. Все еще 22 680 в режиме отладки.

Поскольку я хотел избавиться от вещей Uart, я просто переместил UART.C библиотека из пути сборки. Затем я обнаружил, что uart_debug_write вызывается из syscalls_stm32.в. Я удалил этот звонок и построенные вещи. Размер кода теперь 17 208 в режиме отладки. Падает до 15 048, если оптимизация установлена ​​на наименьшую. Проверка приложения, оно все еще работает!

Еще больше работы, но это настоящий прогресс!

Еще раз большое спасибо за помощь!

fpistm
Сб 28 июля 2018 г. 22:15
Звучит странно, как uart.c находится под: #if defined(HAL_UART_MODULE_ENABLED)

Доктек
Sun 29 июля 2018 г., 17:20
FPISTM: я использую версию 1.2.
AG123: Все флаги оптимизации, кроме-FNO-USE-CXA-ATEXIT уже находятся на платформе.текст. Я добавил CXA One, но не получил отдельное измерение того, насколько он имеет разницу.

Дальнейшие эксперименты: я заметил, что syscalls_stm32.C есть такие вещи, как _SBRK, _Signal и т. Д. Я не думаю, что мне это нужно, но удаление Syscalls вызвало много проблем, поэтому я не мог этого сделать.

Я удалил iPaddress.cpp и print.CPP, а также -dprintf+iprintf на платформе.текст. Теперь размер кода 15.500 (отладка) и 13 636 (наименьшее)

Для сравнения, я скомпилировал с Teensy3.2, без USB и наименьшей оптимизации. Кодовая сторона 11 372. Я также изменил платформу Teensy.TXT для создания карты, чтобы я мог использовать AMAP, чтобы сделать еще немного сравнения.

Похоже, Teensy включает в себя около 5452 байт серийных и твердых вещей, поэтому фактический размер кода ближе к 5467 только для I2C Stuff. Попытка выяснить, насколько много кода L031, вероятно, не нужна сложнее, но вот некоторые наблюдения.
Вещи, которые я мог бы удалить или уменьшить:
lib_a: 2608 (имеет материал _sbrk и т. Д.)
HAL_RCC: 3256 (кажется огромным количеством для настройки снятия?)
Вещи для i2c:
HAL_I2C: 3256
Проволока.CPP: 1184
Тви.C: 928

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

Рик Кимбалл
Sun 29 июля 2018 г., 18:20
Может быть, вам следует просто взять STM32Cubemx и Truestudio, генерировать для LL и двигаться дальше?

Доктек
Солнце 29 июля 2018 г. 18:54
Это хорошая идея и разумный подход. Мое единственное беспокойство заключается в том, будет ли LL поддерживать в будущем. Похоже, я видел уведомления о том, что это не было. Должен ли я заботиться об этом?

Спасибо!

Рик Кимбалл
Sun 29 июля 2018 г., 19:04
Они написали LL, потому что все были враждебны по отношению к Хэлу и его вздутии.

LL в основном выглядит как старый SPL (стандартная периферийная библиотека). Я не работаю на ST, но я бы предположил, что это будет поддержано в будущем как способ подавить восстание в сторону HAL.

Есть SPL -> LL Code Converter Application. Я думаю, что многие разработчики придерживались SPL из -за HAL. (Снова анекдотические наблюдения с моей стороны)

fpistm
Sun 29 июля 2018 г., 21:20
LL поддерживается.
Перейти к 1.3.0, чтобы удалить код, связанный с USART.
И использовать LL для конфигурации SystemClock.

Рик Кимбалл
Ср. 01 августа 2018 12:51
У меня есть личный проект, который использует мое собственное ядро. Я сосредоточен на том, чтобы сделать код маленьким, используя шаблоны C ++ и зарегистрировать доступ, используя определения, предоставленные STM32F103XB.H Заголовок устройства от STM32Cubemx. Я не использую ни одного из кода куба, только этот заголовок и их процедура инициализации часов.

На днях кто -то ( @human890209) опубликовал какой -то код, используя новый/malloc (), и он не работал со Sloeber. Я перенес этот код в свое ядро ​​и собрал его с новейшим ARM-None-Eabi-GCC (7.3.1) Использование стандарта GNU ++ 17. Это удивило меня тем, что он полностью исключил новые вызовы Malloc и заменил их постоянной. Конечно, код был очень простым, чтобы компилятор мог видеть, что происходит. Что мне очень приятно, так это то, что, пока я с радостью сплю, мечтаю, кто -то другой делает улучшения, которые просто появляются на моем пороге.

Вот код: /* fabooh code highlighting the efficiency of gnu++17 and gcc 7.3.1 */ class MYCLASS { public: uint8_t content; MYCLASS() : content(99) { } ~MYCLASS() { } }; LED_BUILTIN LED_BUILTIN_; serial_default_t<115200, CPU::frequency, TX_PIN, NO_PIN> Serial; void setup() { Serial.begin(); pinMode(LED_BUILTIN_, OUTPUT); } void loop() { static unsigned x = 0; unsigned ts; digitalWrite(LED_BUILTIN_, HIGH); do { ts = millis(); } while ( (ts + 1000) < x); x += 1000; Serial << "curr millis()=" << ts << "\r\n"; digitalWrite(LED_BUILTIN_, LOW); delay(50); { MYCLASS mc; MYCLASS * const mcp = &mc; Serial << (mcp->content + 1) << "\r\n"; } { MYCLASS * const mcp = new MYCLASS; Serial << (mcp->content + 1) << "\r\n"; delete(mcp); } { void * p = malloc(sizeof(MYCLASS)); MYCLASS * const mcp = new(p) MYCLASS; Serial << ( mcp->content + 1) << "\r\n"; free(mcp); } }

Доктек
Пт, 03 августа 2018 г., 4:34
Очень вдохновляет! Прямо сейчас я смотрю на использование LL из Cubemx, чтобы создать свой собственный код I2C для моей доски, который будет работать с Arduino. Это может быть слишком много для меня, но это хорошие упражнения, просто выясните, как это сделать. Спасибо за поддержку!

Доктек
Пт 10 августа 2018 г., 4:30 утра
Когда я исследую дальше, я сделал пару открытий, которые могут быть полезными.

Во -первых, я заметил, что весь код интерфейса LL находится в коде интерфейса HAL, поэтому я надеюсь, что все, что мне нужно сделать, это использовать его. Это означает, как разделы, такие как TWI.C должны быть переписаны, но части LL должны быть доступны. Я собираюсь начать с попытки использовать LL -версию System_clock_config.

Во -вторых, я посмотрел на старый фаворит: классика Geoffery Brown's Classic Обнаружение микроконтроллера STM32. Один раздел, который действительно привлек мой взгляд на Newlib (LIBC). Этот LIBC добавляет около 2600 байтов в мой код и совершенно не нужен для моей простой программы I2C. Вопрос в том, как мне избавиться от этого?? Я не нашел, где его втягивают в связанный код. У кого -нибудь есть идеи по этому поводу?

Тиа!

тв
Пт 10 августа 2018 г. 5:26 утра
Я не авторитет, но, насколько я могу сказать, Newlib втягивается с конфигурацией инструментов GCC, и он обеспечивает кучу довольно важных функций, которые производят C & C ++ Работа. Есть меньшие библиотеки, которые обеспечивают такую ​​же функциональность, вы можете пойти по этому пути... Дело в том, что ваш код может оказаться не называть ничего в этой библиотеке, но какой -то код в ядре STM, вероятно, делает. В этом смысле у меня есть хорошие новости и плохие новости для вас ;-). Хорошая новость заключается в том, что GCC очень хорош в связи только с функциями, на которые на самом деле ссылаются. Таким образом, в то время как Newlib может быть большой, порция, которая заканчивается в вашем бинарном. Плохая новость заключается в том, что самая большая свинья, которую вы перетаскиваете из Newlib, - это (скорее всего) printf (и все, от чего это зависит), и если вы Grep для printf в ядре STM, вы обнаружите, что он используется для печати очень простых Сообщения об ошибках, которые на самом деле являются простыми строками и могут быть напечатаны с использованием пута. Я колебался, отправлять ли пиар, но затем решил, что я готов компромисс с удобством printf в своих собственных эскизах для этого размера, поэтому я сдался. :ржу не могу: :ржу не могу: :ржу не могу:

fpistm
Пт 10 августа 2018 г., 6:46
Правильно, printf - хороший трек. Вот почему я уже удалял его из error_handler.
Это друг друга в моем огромном списке Todo. :рулон:

тв
Пт 10 августа 2018 г., 19:46
В контексте избегания раздувания..., Сделав некоторую реализацию АЦП, используя библиотеки LL, мне интересно, какие плюсы и минусы по сравнению с использованием только заголовков CMSIS, и я подумал, что спрошу тех из вас, у кого больше опыта с различными библиотеками ST и сериалом UC...

Вот тривиальный пример, который должен начать преобразование в АЦП. Используя библиотеку LL, я бы написал: LL_ADC_REG_StartConversion(ADC1);

Доктек
Пт 10 августа 2018 г. 22:36
Небольшая программа тестирования, с которой я работаю (только несколько транзакций I2C - результаты, только что сохраненные в массиве), была составлена ​​для STM32L031 и для Teensy 3.2 (использует кинетизисную руку). Я думаю, очень стоит отметить, что Teensy3.2 карта не показывает никакого признака того, что LIBC используется! Также следует отметить, что прямая реализация с использованием кода из STMCUBEMX не вызывает LIBC. Поскольку это явно не нужно, я хочу от него избавиться!

Как мне вытащить крючки, которые вызывают это??

Спасибо!

Кстати, в отношении функций LL, это еще одна вещь, над которой я работаю. Прямо сейчас я пытаюсь использовать LL SYSTEM_CLOCK_CONFIG, но он не будет построить. Я должен включить файлы заголовка LL. Тогда я могу знать, насколько это имеет значение.

Доктек
Пт 10 августа 2018 г., 22:41
Еще один момент в отношении LIBC. Похоже, что LIBC вносит несколько функций «поддержки», даже если они не называются в другом месте в коде. И используемый код предназначен для более крупных систем (чтение: память бесплатная), и поэтому раздувается по проектированию для использования в небольших системах. Я ссылаюсь на книгу Брауна, упомянутая выше.

Доктек
Сб 11 августа 2018 г. 12:48
Вот результаты использования LL -версии System_clock_config. Я нахожу это почти удивительным!

С версией HAL размер кода составил 13 784 (наименьшая оптимизация). Глядя на карту, я смог приписать 2112 к вызовам HAL_RCC.
Использование версии LL (больше ничего не изменилось!), размер сейчас 11 556! Разница - это почти точно размер кода HAL_RCC. Теперь я не вижу вызовов для материала hal_rcc на карте. На самом деле, я даже не вижу вызовов для функций LL_RCC. И, да, код все еще работает правильно.

Доктек
Сб 11 августа 2018 г. 20:26
Результаты другого эксперимента:

Прежде чем заняться реализацией I2C с помощью LL, я подумал, что начну с простых миганных программы. Используя те же моды, которые я сделал для программы I2C, Blink Somplys до 6420 байтов. Глядя на карту, показывает, что LIB_A (LIBC) исчез (2608), WIRE.CPP (1184) исчез, и все, кроме 150 или около того, TWI.C (~ 930-150 = 780) исчез. Итак, по сравнению с моей программой I2C, которая составляет 11556 - 4072 = 7484. Фактическое - 6420; Итак, около 1000 сокращений, кроме больших. Но LIBC явно не требуется для основного эскиза Arduino. Я буду продолжать пытаться выяснить, как от него избавиться.

Еще одно наблюдение состоит в том, что HAL_I2C продолжает втягивать, даже если он вообще не используется. Это 2408 байтов раздувания. Так что я пытаюсь выяснить, почему это мигание, когда это явно не используется.

И я даже не думал, как использовать LL для проведения мигания!

Много веселья!

Хейсан
Солнце 12 августа 2018 г. 11:56 утра
Статический линкер GCC на самом деле очень хороший. Он не включает код из LIBC.А в последнем бинарном, если только он не используется.

Просмотр .Файл ELF Для одного из моих проектов, я вижу, что самой большой кусок LIBC является Malloc_R, который используется кодом CXA_ATEXIT (который требуется для строгого соответствия стандартов C ++). Я должен быть возможно выключить это с помощью флага -фно-использования Cxa-atexit компилятора.

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

Глядя на дампы, самой большой победой было бы добавить более простые Malloc/бесплатные реализации.

Удаление LIBC полностью не является вариантом (например, инициализаторы статического массива реализованы внутри функций LIBC). Любое использование нестатического объекта C ++ использует много функций LIBC. Вы можете попытаться изменить свой код, чтобы избежать всего такого внутреннего использования, но тогда вы получите тривиальный код. Гораздо лучше рассмотреть замену функций LIBC по умолчанию более простыми/меньшими вариантами.

Squonk42
Солнце 12 августа 2018 12:37
Проверять https: // keithp.com/blogs/umedded-arm-libc/ и соответствующий репо https: // keithp.com/cgit/newlib.git/.

Доктек
Пн 13 августа 2018 г., 4:38
Хейсан: Ваши наблюдения за окружающей средой Arduino? Я спрашиваю, потому что я вижу, как втягивается большой кусок LIBC, но мой код не должен его использовать.

Squonk42: Спасибо за этот указатель! Кит р. блестящий парень и отлично справляется. Теперь, если я могу просто выяснить, как включить его библиотеку в среду Arduino, моя проблема может быть на пути к решению!

Хейсан
Пн 13 августа 2018 г., 7:51
[Доктек - Пн 13 августа 2018 г., 4:38] - Хейсан: Ваши наблюдения за окружающей средой Arduino? Я спрашиваю, потому что я вижу, как втягивается большой кусок LIBC, но мой код не должен его использовать.
Символы, которые я дал, были от Spiscanner в ядре Роджера, составленные в Arduino 1.8.5. Я следовал всем вызовам, используя 'objdump -d xxxx.ELF 'и все включенные функции LIBC были вызваны из приложения.

Хейсан
Пн 13 августа 2018 г., 19:54
Была просто двойная проверка. Если вы посмотрите на файл карты, есть несколько разделов. Сначала все символы перечислены - но позже есть раздел для «отброшенных символов»... Так что довольно сложно увидеть, что связано, глядя на файл карты.

Файл ELF не перечисляет исходный файл, но в нем перечислены только символы, которые фактически были включены.

Squonk42
Пн 13 августа 2018 г., 20:59
[Хейсан - Пн 13 августа 2018 г., 19:54] - Была просто двойная проверка. Если вы посмотрите на файл карты, есть несколько разделов. Сначала все символы перечислены - но позже есть раздел для «отброшенных символов»... Так что довольно сложно увидеть, что связано, глядя на файл карты.
Файл ELF не перечисляет исходный файл, но в нем перечислены только символы, которые фактически были включены.
В файлах карты сначала перечислены включенные члены архива, затем выделенные общие символы, затем выброшенные разделы, общая конфигурация памяти, скрипт линкера и в конечном итоге карта памяти, так что она на самом деле содержит 6 разных форматов строки в одном файле (!!!).

Пример: Archive member included to satisfy reference by file (symbol) /tmp/arduino_cache_163115/core/core_STM32_stm32_GenF103_pnum_BLUEPILL_F103C8,flash_C8,upload_method_serialMethod,xserial_generic,opt_osstd_37797f055aaae0f124e551a637c4a2ed.a(startup_stm32yyxx.S.o) (--whole-archive) /tmp/arduino_cache_163115/core/core_STM32_stm32_GenF103_pnum_BLUEPILL_F103C8,flash_C8,upload_method_serialMethod,xserial_generic,opt_osstd_37797f055aaae0f124e551a637c4a2ed.a(board.c.o) (--whole-archive) ... Allocating common symbols Common symbol size file errno 0x4 /home/mstempin/.arduino15/packages/STM32/tools/arm-none-eabi-gcc/6-2017-q2-update/bin/../lib/gcc/arm-none-eabi/6.3.1/../../../../arm-none-eabi/lib/thumb/v7-m/libc_nano.a(lib_a-reent.o) uwTick 0x4 /tmp/arduino_cache_163115/core/core_STM32_stm32_GenF103_pnum_BLUEPILL_F103C8,flash_C8,upload_method_serialMethod,xserial_generic,opt_osstd_37797f055aaae0f124e551a637c4a2ed.a(stm32yyxx_hal.c.o) pFlash 0x20 /tmp/arduino_cache_163115/core/core_STM32_stm32_GenF103_pnum_BLUEPILL_F103C8,flash_C8,upload_method_serialMethod,xserial_generic,opt_osstd_37797f055aaae0f124e551a637c4a2ed.a(stm32yyxx_hal_flash.c.o) Discarded input sections .text 0x0000000000000000 0x0 /home/mstempin/.arduino15/packages/STM32/tools/arm-none-eabi-gcc/6-2017-q2-update/bin/../lib/gcc/arm-none-eabi/6.3.1/thumb/v7-m/crti.o .data 0x0000000000000000 0x0 /home/mstempin/.arduino15/packages/STM32/tools/arm-none-eabi-gcc/6-2017-q2-update/bin/../lib/gcc/arm-none-eabi/6.3.1/thumb/v7-m/crti.o .bss 0x0000000000000000 0x0 /home/mstempin/.arduino15/packages/STM32/tools/arm-none-eabi-gcc/6-2017-q2-update/bin/../lib/gcc/arm-none-eabi/6.3.1/thumb/v7-m/crti.o ... Memory Configuration Name Origin Length Attributes RAM 0x0000000020000000 0x0000000000005000 xrw FLASH 0x0000000008000000 0x0000000000010000 xr *default* 0x0000000000000000 0xffffffffffffffff Linker script and memory map LOAD /home/mstempin/.arduino15/packages/STM32/tools/arm-none-eabi-gcc/6-2017-q2-update/bin/../lib/gcc/arm-none-eabi/6.3.1/thumb/v7-m/crti.o LOAD /home/mstempin/.arduino15/packages/STM32/tools/arm-none-eabi-gcc/6-2017-q2-update/bin/../lib/gcc/arm-none-eabi/6.3.1/thumb/v7-m/crtbegin.o LOAD /home/mstempin/.arduino15/packages/STM32/tools/arm-none-eabi-gcc/6-2017-q2-update/bin/../lib/gcc/arm-none-eabi/6.3.1/../../../../arm-none-eabi/lib/thumb/v7-m/crt0.o LOAD /home/mstempin/.arduino15/packages/STM32/tools/CMSIS/5.3.0/CMSIS/Lib/GCC//libarm_cortexM3l_math.a START GROUP LOAD /tmp/arduino_build_254597/sketch/slave_sender_receiver.ino.cpp.o ... 0x0000000020005000 _estack = 0x20005000 0x0000000000000200 _Min_Heap_Size = 0x200 0x0000000000000400 _Min_Stack_Size = 0x400 .isr_vector 0x0000000008000000 0x10c 0x0000000008000000 . = ALIGN (0x4) *(.isr_vector) .isr_vector 0x0000000008000000 0x10c /tmp/arduino_cache_163115/core/core_STM32_stm32_GenF103_pnum_BLUEPILL_F103C8,flash_C8,upload_method_serialMethod,xserial_generic,opt_osstd_37797f055aaae0f124e551a637c4a2ed.a(startup_stm32yyxx.S.o) 0x0000000008000000 g_pfnVectors 0x000000000800010c . = ALIGN (0x4) .text 0x000000000800010c 0x44f4 0x000000000800010c . = ALIGN (0x4) *(.text) .text 0x000000000800010c 0x6c /home/mstempin/.arduino15/packages/STM32/tools/arm-none-eabi-gcc/6-2017-q2-update/bin/../lib/gcc/arm-none-eabi/6.3.1/thumb/v7-m/crtbegin.o .text 0x0000000008000178 0x10 /home/mstempin/.arduino15/packages/STM32/tools/arm-none-eabi-gcc/6-2017-q2-update/bin/../lib/gcc/arm-none-eabi/6.3.1/../../../../arm-none-eabi/lib/thumb/v7-m/libc_nano.a(lib_a-strlen.o) 0x0000000008000178 strlen *(.text*) .text.loop 0x0000000008000188 0x2 /tmp/arduino_build_254597/sketch/slave_sender_receiver.ino.cpp.o ...

Хейсан
Пн 13 августа 2018 г., 21:23
Спасибо, забыл о нм...

`nm -c -size -sort i2c_scanner_wire.Ино.эльф | меньше

дает очень хорошее представление о том, с чего начать оптимизировать...
...
000002bc b tft
000002d0 t setup0_process
000003f0 t adafruit_ili9341_stm :: begin (spiclass&, без подписи долго)
00000408 d __malloc_av_
00000428 D Impure_Data
00000500 R шрифт
00000538 t _malloc_r
Сам Malloc является самой большой функцией, и его инициализируется структура __malloc_av_ является единственным самым большим куском оперативной памяти...

РЕДАКТИРОВАТЬ: BAH - только что попытался заменить его в качестве теста, но Malloc () и Free () являются сильными символами в LIBC по умолчанию, поэтому не могут быть перегружены во время компиляции...

Хейсан
Пн 13 августа 2018 г., 22:03
Edit2: быстрый и грязный взлом:

objcopy -Waeaken libc.а

А затем скопируйте/вставьте k&R Ссылка Malloc/Free в .INO -файл сохраняет ~ 3K вспышки и 1K ОЗУ...

Доктек
Вторник 14 августа 2018 г. 1:07
Stevestrong предложил использовать AMAP (на странице 2 есть ссылка), чтобы посмотреть на карту. Я нахожу это очень полезным.

Squonk42 - Что касается версии Newlib от Keithp, я клонировал репозиторий, но я не вижу каталога Debian, который показывает, когда я смотрю на его веб -сайт. Мне также совсем не ясно, как построить библиотеку, чтобы я мог ее использовать. Приглашаются любой совет! Это выглядит очень многообещающе, если я могу просто понять это.

Гесян - Ваше использование objcopy очень интересно. Я не вижу этого трюка. Спасибо, что поделились этим.

Хейсан
Вторник 14 августа 2018 г., 7:40
Спасибо. AMAP выглядит интересно... Я всегда использовал бинутилы, но, похоже, у этого есть много хороших особенностей.

Что касается objcopy, используйте с экстремальной осторожностью (или, что еще лучше, только ослабьте конкретные символы, которые вы хотите заменить). Если вы делаете то, что я сделал, то все символы в LIBC слабы. Использование символа того же имени в вашем приложении (или любой библиотеке, используемой вашим приложением), заменит символ LIBC без предупреждения. Если вы случайно замените важный (например, Brk ()), ваше приложение сломается чрезвычайно интересными способами.

Также необходимо иметь в виду, что некоторые функции работают на одних и тех же внутренних структурах данных, поэтому должны быть заменены в качестве набора (например, Malloc+Free+Calloc+Realloc+Memalign+Friends). Я только заменил Malloc и Free - но только после того, как ни одна из других функций не было упомянуто.

Хейсан
Ср 15 августа 2018 г. 18:14
Я играю немного больше, и я понимаю, что на самом деле есть немного кода для управления «выходом» из программы. Но это невозможно в среде Arduino, и все это можно удалить.

На оригинальном ядре Arduino выход (0) компилируется в 'cli (); В то время как (1); ' - Так отключить прерывания и вращаться навсегда. Нет ОС более низкого уровня, поэтому мы не можем выйти!

Первый шаг в очистке-добавить '-fno_use_cxa_atexit' в флаги CPP. Это удаляет код, чтобы вызвать неопределенное количество деструкторов статических объектов, когда приложение выходит (что никогда не может произойти, так же бесполезно).

Даже с этим флагом компилятор будет называть atexit (), что почти неэффективно.

С слабыми символами LIBC вы можете добавить: int atexit(void (*function)(void)) {return 0;} void exit(int status) {while(1);}

Доктек
Пн 20 августа 2018 11:18
Последние несколько дней я расследовал библиотеки, которые связаны с моей программой Arduino Blink. Основные инструменты, которые я использовал, - это AMAP (упоминается ранее), чтобы посмотреть на карту символов и флаг словеса для линкера. Параметр «Перебороз» передается путем добавления -wl, -вербозу в рецепт линкера на платформе.текст.

Хейсан - Как вы поняли, какую версию LIBC ослабить? Похоже, есть так много версий, и я не могу понять, как система сборки Arduino решает, какие из них использовать. Я не вижу, чтобы пути четко определены. Все, что я могу пройти, это словесный выход из линкера.

Доступ к известным выводам линкера показывает, что доступно несколько библиотек. К ним относятся libc_nano.А, Либм.A, Libgcc.a, libstdc ++ _ nano.а и libc.а. Однако карта показывает, что только libc_nano.A и Libgcc.фактически внести код для мигания. Какую часть играют другие библиотеки и почему они получают доступ к? Я хотел бы понять это. Все библиотеки, кроме LIBGCC.А расположены по адресу stm32/инструменты/arm-none-eabi-gcc/6-2017-q2-update/arm-none-eabi/lib/thumb/v6-m/. Libgcc.A расположен в STM32/Tools/Arm-None-Eabi-GCC/6-2017-Q2-Update/Lib/GCC/ARM-None-EABI/6.3.1/большой палец/V6-m/. Обратите внимание, что сигнал словесного положения не показывает, какие символы из доступных библиотек будут отображаться на карте, и, по -видимому, исполняемое изображение.

Я бы очень хотел выяснить, как построить версию Newlib Кита Паккарда. Я смотрел на попытку использовать афилы Make, которые поставляются с архивом GIT от Keithp, но материал Automake/AutoConfig - это слишком сложный для меня, чтобы расшифровать. Я думаю, что просто копирование файлов и выполнение соответствующей компиляции GCC и построение библиотеки - правильный подход. Но потом я доберусь до вопроса: какие флаги я должен указать? А потом, как мне заставить линкера использовать новую библиотеку, чтобы я мог ее проверить? Наконец, какой файл заголовка должен быть указан для использования программ и какие флаги линкера должны использовать для них? Я уверен, что мне придется ответить для себя, но если кто -то еще сможет помочь, я был бы вечно благодарен! И я ожидаю, что сообщество STM32Duino!!

Хейсан
Вторник 21 августа 2018 г. 8:03
[Доктек - Пн 20 августа 2018 г., 23:18] - Хейсан - Как вы поняли, какая версия Libc ослабить? Похоже, есть так много версий, и я не могу понять, как система сборки Arduino решает, какие из них использовать. Я не вижу, чтобы пути четко определены. Все, что я могу пройти, это словесный выход из линкера.
Посмотрите в .Файл карты - он обеспечивает полный путь включенных библиотек. Я думаю, что это была версия «V7-M», но у меня нет своих материалов Arduino на работе...

Редактировать: для флагов линкеров, посмотрите в .Файлы спецификации в основном дереве - они содержат примеры того, как переключиться на Nano LIB, должны быть возможны, чтобы изменить их, чтобы переключиться на другие либера. Хотя вы также должны обменять файлы заголовков, это обычно не требуется, так как прототипы C стандартизированы.

Доктек
Пн 27 августа 2018 г., 4:51
После нескольких ложных заводов мне удалось построить раздел Tinystdio в Newlib. Затем я изменил рецепт ссылки на платформе.TXT, чтобы использовать мою библиотеку. Wile Библиотека была найдена и открыта процессом ссылки, ни один из файлов не использовался. Быстрое расследование показало очевидную причину: имена функций в библиотеке (Thumb/V6-M/Libc-Nano.а) Все начинаются с lib_a-. Например, функция GETC с именем GETC в библиотеке TinyStdio, но LIB_A-GETC в версии libc-nano. Поэтому мои попытки предоставить альтернативную библиотеку провалится.

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

Как всегда, любая помощь или руководство очень ценится!

Хейсан
Пн 27 августа 2018 г., 7:41
Я думаю, вам нужно проверить рецепт ссылки.

Я дважды проверил, и символы в libc_s.А есть 'getc'. Символ происходит из файла 'lib_a-getc.o ' - но исходное имя файла не имеет значения во время ссылки, только имя символа.

Если вы не ослабите libc.(или libc_s.А вы используете Nano.спецификации), вы не можете просто заменить stdio - вам нужно заменить весь LIBC...

Squonk42
Пн 27 августа 2018 г., 7:53
IIRC, инструмент (компилятор, ассемблер, линкер и другие бинарные инструменты) связаны с данным LIBC.

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

Фактически, когда вы создаете набор инструментов, создается первый LIBC, основанный на NewLib, который используется для компиляции компилятора, который используется для компиляции конечного LIBC (стандартный LIBC или Newlib), прежде чем компилировать конечный компилятор. При создании Cross Compiler или еще хуже он становится все более сложным != сборка != цель):
Изображение

Я предполагаю, что вы должны перекомпилировать весь кросс-тройник, чтобы работать с финальным Newlib.

Я предлагаю использовать автоматический инструмент, как Crosstool-ng.

Хейсан
Пн 27 августа 2018 г., 7:59
[Squonk42 - Пн 27 августа 2018 г., 7:53] - IIRC, инструмент (компилятор, ассемблер, линкер и другие бинарные инструменты) связаны с данным LIBC.

Это происходит из -за проблемы с курицей и яйцом: компилятору нужен LIBC, но вам нужен компилятор, чтобы компилировать LIBC...
Хотя это правда, что вам нужно LIBC, чтобы построить и запустить компилятор, конечный LIBC на цели не обязательно должен быть одинаковой. Пока он обеспечивает все символы, требуемые стандартом C, создан компилятор, вы должны быть в порядке.

Весь код библиотеки, конкретный компилятор, размещен в LIBGCC - и это не должно меняться.

Squonk42
Пн 27 августа 2018 г. 8:59 утра
Это не так просто, компилятор может использовать встроенные функции, а функции могут вызывать другие функции.

Поэтому, как вы сказали, если вы не ослабите весь LIBC, вы должны заменить все это Newlib, не только часть Stdio.

Как насчет использования меньшего Newlib-Nano, если многопоточно?

Хейсан
Пн 27 августа 2018 г., 10:02
[Squonk42 - Пн 27 августа 2018 г. 8:59] - Это не так просто, компилятор может использовать встроенные функции, а функции могут вызывать другие функции.

Поэтому, как вы сказали, если вы не ослабите весь LIBC, вы должны заменить все это Newlib, не только часть Stdio.

Как насчет использования меньшего Newlib-Nano, если многопоточно?
Если вы придерживаетесь публичных API, вы можете смешивать и сочетать практически так, как хотите. Документы API будут перечислены, если есть связанные символы, которые необходимо заменить в качестве семьи.

У меня есть продукт ARMV6 в полевых условиях с заменой функций STDIO и Malloc, замененными на акции LIBC. Более миллиона рабочих часов (совокупно) без каких -либо проблем с программным обеспечением.

Squonk42
Пн 27 августа 2018 г., 11:46
API не описывают внутренние состояния (вызывая проблемы повторного входа), побочные эффекты или проблемы, связанные с временем, и тот факт, что чего-то не произошло, не является доказательством того, что этого не произойдет :)

Меня укусили при изменении реализации Malloc/Free на устройстве с ограниченной памятью из-за фрагментации памяти. Я могу привести еще несколько примеров, связанных с различным использованием стека, выравниванием структуры, которое вызвало проблемы только в очень специфических условиях (худшее, согласно закону Мерфи).

Изменение только части LIBC-более или менее воображается, более общим подходом будет иметь выбор между несколькими реализациями LIBC, такими как обычный GNU Libc, UCLIBC, Newlib, Newlib-Nano...

Хейсан
Пн 27 августа 2018 12:04
[Squonk42 - Пн 27 августа 2018 г. 11:46] - API не описывают внутренние состояния (вызывая проблемы повторного входа), побочные эффекты или проблемы, связанные с временем, и тот факт, что чего-то не произошло, не является доказательством того, что этого не произойдет :)

Меня укусили при изменении реализации Malloc/Free на устройстве с ограниченной памятью из-за фрагментации памяти. Я могу привести еще несколько примеров, связанных с различным использованием стека, выравниванием структуры, которое вызвало проблемы только в очень специфических условиях (худшее, согласно закону Мерфи).

Изменение только части LIBC-более или менее воображается, более общим подходом будет иметь выбор между несколькими реализациями LIBC, такими как обычный GNU Libc, UCLIBC, Newlib, Newlib-Nano...
Вы никогда не найдете ни одного LIBC, который соответствует всем вашим операционным требованиям. Просто прочитайте документацию библиотеки, и вы можете безопасно заменить биты, которые не работают для вас. Семейство инструкций Malloc разделяет внутреннее состояние и должно быть заменено как группа. Stdio не состоит из состояния и может быть заменен кусочным - но это обычно побеждает объект, так что скорее замените всю семью.

Смотрите здесь для деталей GLIBC:
https: // www.гну.org/software/libc/manua ... Ing-Malloc

Squonk42
Пн 27 августа 2018 12:44
[Хейсан - Пн 27 августа 2018 12:04] - Вы никогда не найдете ни одного LIBC, который соответствует всем вашим операционным требованиям. Просто прочитайте документацию библиотеки, и вы можете безопасно заменить биты, которые не работают для вас. Семейство инструкций Malloc разделяет внутреннее состояние и должно быть заменено как группа. Stdio не состоит из состояния и может быть заменен кусочным - но это обычно побеждает объект, так что скорее замените всю семью.
... И затем вы обнаружите, что STDIO зависит от семейства функций Malloc с использованием внутренней/внешней дефрагментации с использованием рекомбинации приятеля и объединения того же размера, чтобы само по себе избегать объединения структур, но не относится к другому более простому Malloc/Free, которые вы выбрали и выбрали Тогда вы выходите из памяти раньше... Был там, сделал это. :рулон:

Хейсан
Пн 27 августа 2018 г., 13:05
Если вы подключите распределитель памяти, который недостаточно для рабочей нагрузки, то вы, очевидно, можете ожидать проблем.

И это главная причина, по которой я обычно заменяю функции Stdio почти сразу. Полная спецификация C для строки формата не может быть реализована без Malloc/Free. Интенсивно используя форматированные строки разорвут вашу кучу, независимо от того, насколько хорош ваш распределитель. Так что скорее замените функции stdio на детерминированные. Придется сделать короткие сокращения в некоторых вариантах форматирования, но скорее, чем что -то впадает в сбою случайным образом.

Squonk42
Пн 27 августа 2018 г., 16:16
[Хейсан - Пн 27 августа 2018 г. 13:05] - Если вы подключите распределитель памяти, который недостаточно для рабочей нагрузки, то вы, очевидно, можете ожидать проблем.
...
Интенсивно используя форматированные строки разорвут вашу кучу, независимо от того, насколько хорош ваш распределитель.
Так что, похоже, ни один распределитель памяти не является «достаточным» для обработки форматированных строк :) Что, конечно, не так, поскольку без проблем работают серверы Linux, хотя они обрабатывают форматированную строку.
[Хейсан - Пн 27 августа 2018 г., 13:05] - и это главная причина, по которой я обычно заменяю функции stdio почти сразу. Полная спецификация C для строки формата не может быть реализована без Malloc/Free.
Обратите внимание, что строгая среда Arduino не включает в себя процедуры stdio и xxprintf ():
https: // Playground.Ардуино.cc/main/printf

Однако, если он вам нужен, вот крошечный Printf, который может быть полезен:
http: // www.SpareTimeLabs.com/printfrevi ... ISITED.PHP

Хейсан
Пн 27 августа 2018 г., 17:39
[Squonk42 - Пн 27 августа 2018 г. 16:16] -
[Хейсан - Пн 27 августа 2018 г. 13:05] - Если вы подключите распределитель памяти, который недостаточно для рабочей нагрузки, то вы, очевидно, можете ожидать проблем.
...
Интенсивно используя форматированные строки разорвут вашу кучу, независимо от того, насколько хорош ваш распределитель.
Так что, похоже, ни один распределитель памяти не является «достаточным» для обработки форматированных строк :) Что, конечно, не так, поскольку без проблем работают серверы Linux, хотя они обрабатывают форматированную строку.
Я явно говорил о среде MCU с ограниченным пространством кучи.
[Squonk42 - Пн 27 августа 2018 г. 16:16] -
[Хейсан - Пн 27 августа 2018 г., 13:05] - и это главная причина, по которой я обычно заменяю функции stdio почти сразу. Полная спецификация C для строки формата не может быть реализована без Malloc/Free.
Обратите внимание, что строгая среда Arduino не включает в себя процедуры stdio и xxprintf ():
https: // Playground.Ардуино.cc/main/printf

Однако, если он вам нужен, вот крошечный Printf, который может быть полезен:
http: // www.SpareTimeLabs.com/printfrevi ... ISITED.PHP
Спасибо. У меня уже есть очень маленькая и полная реализация Printf, которую я использую в других своих проектах. Для приложений, которые требуют большого форматирования текста, добавление PrintF сохраняет много места на ручной кодировании или создание пользовательских форматеров.

Хейсан
Пт 31 августа 2018 г. 11:15 утра
Для любого, кто хочет играть с плагинными библиотеками для уменьшения размера, я приложил свои первые усилия на GitHub:

ViewTopic.PHP?f = 9&t = 4066

Хейсан
Ср. 05 сентября 2018 г., 19:03
Только что добавил поддержку Printf в мою замену LIBC. Были проблемы с лицензированием с моей оригинальной версией, поэтому я написал новый с нуля. Я вполне доволен результатами, почти символом для персонажа идеально подходит с версией Glibc, но на 19 КБ меньше.

Удивительно, но это даже на 400 байт меньше, используя печатную.println ((float)), и у вас есть богатое форматирование (точность, заполнение, оправдание и т. Д.). Только реальный недостаток заключается в том, что преобразование поплавки точнее примерно до 7 значимых цифр.

Доктек
Чт, 06 сентября 2018 г. 3:36 утра
Спасибо за LIBC! Хотя он не сделал мой код меньше (я не использую Malloc или другие функции), он дал мне ключ к замене функций LIBC. Функция Abort, казалось, добавляла код без полезных целей. Итак, я скопировал его из GitHub's Github's Github's Keith Packard. Я переписывался, и я! Мой код был почти на 400 байтов меньше. Я думаю, что это действительный подход, который я планирую использовать чаще.

Затем я атаковал ненужные процедуры прерывания. Например, PIN PIN -IRQ GPIO в прерывании.CPP. Я переместил этот файл, чтобы он не был составлен (он не нужен в мигании!), достал #include прерывание.h с доски.H, и переехал WinterAupts.CPP. Сократил исполняемый файл почти 1100 байтов!

Делая это последнее немного, помогло мне понять, откуда берется много раздувания: если файл скомпилируется, в котором есть определение функции, которая объявляется «слабой» в другом месте, используется более сильная версия. Наиболее очевидный случай этого - в ISRS! Код ISR/IRQ втягивается. Так как это не используется: мгновенное раздувание. ISR часто притягивают другие функции, добавляющие больше раздувания. Прерывания PIN GPIO - хороший пример. Я смотрю на аналог.С и таймер.C также код. Это втягивается необходимостью в PWM-стопе с помощью цифровой цифры.в. Я буду атаковать это дальше.

Еще раз спасибо за LIBC!

Хейсан
Чт, 06 сентября 2018 г., 6:52
Спасибо. Если у вас есть какие -либо проверенные изменения, которые, по вашему мнению, будут полезны для других, отправьте их через GitHub. Даже одноразовые вещи, так как это можно упаковать в автономном .H файлы для включения в каждом конкретном случае.

fpistm
Пн 17 сентября 2018 г., 18:23
Просто к вашему сведению, я удаляю использование printf для по умолчанию.
https: // github.com/stm32duino/arduino_c ... C367C8C6A5

Размер эскиза теперь меньше. ;)

Доктек
Пт 5 октября 2018 г., 3:57
Резюме моей работы до сих пор. Далее следует функциональность I2C. После прохождения GPIO и Systick Stuff, я думаю, что готов к этому решить.

STM32L031 История сокращения размера 21.10.18 (начало 24.07.18)

Началось с простой программы I2C. Он просто сделал простую настройку и прочитал в массив.
Использовал доску IMU для I2C Slave.
С отладкой 22 680; с наименьшим, около 20 тысяч.
Удалили любые направления загрузки и прокомментировали uart_debug_write в syscalls_stm32.в
Отладка: 17 208 маленьких: 15 048.
Удален -dprintf = iprintf и did -fno-use-cxa-atexit
Отладка: 15 500 наименьших: 13 636
Вставьте в LL версию конфигурации часов.
Отладка: 13 128 наименьших: 11 556
Переключился на мигание на этом этапе.
Самая маленькая: 6420
Перенял HAL I2C Stuff и TWI.C так нет ничего I2C (может быть, ISRS?)
Наименьший: 3692 - но не мигает!
Фиксированный конфликт между HAL и LL Systick (используется HAL) - мигает!
Отладка: 4880
С использованием <Либ> от Гесяна я переехал и потрошил прерван.в.
Отладка: 4500
После обнаружения, сколько ISRS может добавить, я удалил их. Избавился от прерывания.CPP и Winterrupts.CPP.
Отладка: 3420
Пытался удалить таймер.С и аналоговый.c, но pwm_stop () в whing_digitalwanted потянуть их в. Поэтому я прокомментировал звонок в pwm_stop (). Пока это нормально, я исправлю это позже, когда захочу использовать ШИМ.
Отладка: 2376.
Получил LL версию Systick Working.
Отладка: 2180.
Добавлена ​​LL версия GPIO.
Отладка: 1856. Самая маленькая: 1780. ОЗУ: 72 байта.