Comments 78
но как он сожрал полтора килобайта оперативы?! что там физически может занять такой объем!? В видимой части кода ведь вообще ни одной переменной нет.
А прога на 20-50 байт закончится, когда нужно будет делать тоже самое, только на немного другой модели контроллера. Вам снова придется изучать все его регистры (а они другие!) и весь код инициализации железа писать с нуля в ручную.
А я просто сгенерирую новый проект в CubeMX под другой процессор и вставлю тем самые пару строчек кода мигания, и все гарантированно заработает.
Когда я смотрел на Cube – у меня было ощущение, что мне его придётся изучать заново не то что при смене проца, а вообще на любой чих. Ибо постоянно натыкался на какие-то косяки, искал пути их обхода, и уверен, что то и другое постоянно меняется: http://forum.easyelectronics.ru/viewtopic.php?f=7&t=24337&hilit=Cube
Или он уже стабилизировался?
Для сравнения, на PSoC с кипрессовской средой всё было прозрачно: при создании схемы генерился API, который просто работал, а его использование давало читаемый код, а не клубок макарон с "вставьте кусочек кода сюда" от CubeMX.
Но, увы – экзотический контроллер...
Я смотрел исходники HAL, ничего криминального в них нету, то что бы сожрало столько памяти.
В bare-metal бинарниках обычно нет отладочной информации (или есть, но на девайс она не заливается); отладчик-то все равно на другом компе запускается.
С максимальной оптимизацией по размеру, без отладочной информации и еще поотключав много галочек удалось получить такой минимум, на readwrite data memory не обращайте внимания, в настройках указал размер стека 256 байт, так что дополнительно он съел 52 байта RAM:
3024 bytes of readonly code memory
36 bytes of readonly data memory
272 bytes of readwrite data memory
Module ro code ro data rw data
------ ------- ------- -------
C:\PROJECTS\My\BluePill\BlueHello\EWARM\BlueHello\Obj: [1]
main.o 336
startup_stm32f103xb.o 256
stm32f1xx_hal.o 168 12 12
stm32f1xx_hal_cortex.o 176
stm32f1xx_hal_gpio.o 484
stm32f1xx_hal_msp.o 68
stm32f1xx_hal_rcc.o 1202
stm32f1xx_it.o 20
system_stm32f1xx.o 92 4 4
-------------------------------------------------
Total: 2802 16 16
dl7M_tln.a: [3]
exit.o 4
low_level_init.o 4
-------------------------------------------------
Total: 8
rt7M_tl.a: [4]
ABImemclr4.o 6
ABImemset48.o 50
XXexit.o 12
cexit.o 10
cmain.o 30
copy_init3.o 44
cstartup_M.o 12
data_init.o 40
-------------------------------------------------
Total: 204
Gaps 10
Linker created 20 256
-----------------------------------------------------
Grand Total: 3024 36 272
Больше всего занимает stm32f1xx_hal_rcc.o — 1200 байт.
Не стоит забывать, что у STM довольно навороченная система тактирования. Я не пытался что-то там схитрить и сэкономить, включил внешний кварц, PLL — все как в обычном устройстве. Можно конечно все эти прескалеры и PLL инициализировать вручную, может быть и сэкономите несколько сотен байт кода, но это будет совершенно не поддерживаемый код. Следующий программист, которому посчастливится залезть в код, просто ничего не поймет.
Килобайт оперативы, скорее всего, почти целиком занят под стек, это норма.
А вот во флеше место, скорее всего, занимает код, который не используется. Прозревая компилятор gcc, предположу, что этот код можно выкинуть, сказав компилятору -fdata-sections -ffunction-sections
, а линкеру -Wl,--gc-sections
.
А если gcc там достаточно свежий, то можно и -flto
добавить.
Это оптимизация уровня линковки, поэтому к "глюкам", которых вы боитесь от -О1 и выше, она приводить не должна.
Правда, "глюки", скорее всего, вызваны неопределенным поведением у вас в коде :) Но это уже другой вопрос.
Ща, в процессе изучения stm32, пытаюсь перевести известный код 1wire на таймере с DMA из обращения к регистрам в (хотя бы) LL — третий день ищу, чем же оно пишет в TIM_CCMR2 :( То, что делается в 1 строку присвоения регистру, тут выливается в 10-30 байт структуру, плюс вызов нескольких функций :( А опции запуска таймера в режиме PWM в Cube32MX вообще не оказалось (в stm32fxx_ll_lim.h он есть)
Вот тут уже начинаешь подумывать, а не фиг ли с ней, переносимостью (тем более на другую линейку всё равно править — сравнивал stm32f103 и stm32f030)?.. Думаю, всё хорошо в меру…
arm-none-eabi-size build/hal_tim3_blink.elf
text data bss dec hex filename
4492 20 1636 6148 1804 build/hal_tim3_blink.elf
arm-none-eabi-size build/ll_tim3_blink.elf
text data bss dec hex filename
1900 12 1564 3476 d94 build/ll_tim3_blink.elf
бинарники, соответственно, 4512 и 1920 байт. Из кода — только дёрганье пином в обработчике прерывания…
Не, прозрение не катит :) там по-умолчанию эти опции включены (ну, для gcc — точно), а вот с lto всё гораздо грустнее — что HAL, что LL не собираются в таком режиме, потому как линкер выкидывает все обработчики прерываний и ещё кучу всего из потрохов HAL-a
Интересно. Могу предложить либо выключить lto для отдельных файлов (если, допустим, все обработчики прерываний в один сишник сложены, как STM любит) либо — как тут советуют, просто "вызвать" все обработчики из функций-заглушек, которые, в свою очередь, можно пометить атрибутом __attribute__((used));
Другие функции, по идее, выкидываться не должны, если их хоть откуда-нибудь вызывают.
третий день ищу, чем же оно пишет в TIM_CCMR2
Пробовали ставить access breakpoint на запись?
Из кода — только дёрганье пином в обработчике прерывания…
Можно еще попробовать ассерт выключить. Вообще, надо смотреть в ассемблер или в линкерный мап-файл, чтобы понять, че там столько места жрет :)
2. У меня обратная «задача» — по простому коду
TIM2_CCMR2 = TIM_CCMR2_OC4M_PWM1 | TIM_CCMR2_OC4PE | TIM_CCMR2_CC3S_IN_TI4;
(привет, EddyEm :) ) понять, а) как это указать в Кубе (никак — ибо нет опции для _PWM1) б) сообразить, как сделать то же самое, средствами LL или HAL, причём так, чтобы было легко поправить под F0 и F1 (ну и перенести на другой таймер до кучи, чтоб на F030 завелось). Пока всё в образовательных целях ))3. При сборке штатным Makefile с правками на DEBUG=0 и оптимизацией -Os оно, вроде, и так отключается (там везде (?) assert_param, что раскрывается в пустое место в Release)
ЗЫ: глянул пример «nolib» blink через SysTick — на «чистых регистрах» — там тоже 1144 байта бинарник — по сравнению моим тайменром на LL — примерно вдвое разница на только инициализацию фактически
А ничего, что у меня там не просто «блинк», а псевдоморзянка «SOS» на светодиоде + опрос кнопочек?
Ничего. Плохого :)
Я как раз о том, что даже «типа-низкий-железный-уровень» и то даёт вдвое оверхеда…
Попробовал собрать gcc 4.5 (лень было пути прописывать к 7):
text data bss dec hex filename
804 336 916 2056 808 mk/blink.elf
Вот. А с учётом порядка 280 байт «полезного» кода для кнопок и кода SOS, так и втрое!
- про атрибут советуют и где-то на ST-шном форуме, но это как-то грустно — там с пару десятков ошибок вываливается при линковке — все их править? И это не мой код, а потроха HAL-а…
Ну, а чего ж вы хотели. С точки зрения линкера обработчики прерывания — это функции, которые никогда не вызываются.
Конечно, разумнее было бы, если бы разработчики HAL'a сразу об этом подумали и все обработчики прерываний пометили бы этим атрибутом.
А так — ну хоть какое-то решение.
Наверное, можно еще переписать стартапный ассемблерный файл, в котором таблица векторов прерываний собирается.
- У меня обратная «задача» — по простому коду
Тут не подскажу, с HALом плотно дело не имел.
Уныло…
Никто не будет пилить проект неделю на регистрах, если его можно сделать за час на хале, но взять при этом контроллер пожирнее.
Так что правильно это только с вашей стороны.
Даже обычного BluePill за 100 руб с 60КБ свободной памяти, оставшейся после инициализации, хватит чтобы воплотить все самые смелые желания разработчика. А есть контроллеры и с 1МБ памяти. Просто некоторые застряли в начале 2000х, когда все делали ручками на довольно примитивных контроллерах. Сейчас за программирование регистров STM32 напрямую, я считаю, нужно сразу увольнять человека, потому что это вредительство обойдется значительно дороже в последствии.
Вот так и плодится невежество.
С чего вы вообще взяли, что ваш самописный не поддерживаемый код будет работать стабильнее, чем библиотека, которую каждый день используют миллионы разработчиков?
Правильно выше написал коллега, что есть разработчики застрявшие в 2000.
Нравится писать долго и самобытно — пожалуйста, но тогда будет правильным отказаться и от других благ человечества. Например от 4G, ведь GPRS надежнее…
А вы, похоже, в этот индусокод даже не заглядывали…
Нет, калокуб — это из разряда ардуины. Рассчитано на безмозглых бракоделов.
Покажите класс, напишите статью как надо делать, почему так надо делать и в чем ваш вариант выигрывает (относительно калокуба).
А еще желательно, чтобы это был пример боевого проекта, а не ваши домашние игрушки, на которые можно тратить годы жизни бесплатно.
Такое будет интересно почитать всем «Безмозглым бракоделам»
Боевой проект то вряд ли кто покажет, надёжный код обычно под NDA попадает. Например библиотека тестирования ALU от ST только с NDA поставляется, кто вам её покажет то? Поэтому только примеры на домашних игрушка могут быть, но те которые следуют принципам надёжности.
Подтверждаю в Cube баг на баге, даже у студентов отобрал греха подальше.
github.com/eddyem/stm32samples
Смотреть то, что «nolib», т.к. остальное на opencm3 — я перестал им пользоваться после того, как авторы сильно побили апи.
Кстати, на заметку лентяям. Opencm3 не в пример круче хала!!! По крайней мере, по оптимизации. И код писан программистами, а не «индусокодерами».
Еще у меня есть кое-какие проектики, оформленные отдельно. Они уже связаны с конкретными железяками, скажем, фотометр (уже больше года работает), система термомониторинга главного зеркала БТА (прошлая версия отработала год, в этом году обновил с учетом проблем с разъемами RJ-45 для CAN-шины — заменил их на DB9), а это — мое первое приличное детище (контроллер ИК-спектрометра/фотометра).
Если бы люди продолжали работать на языках низкого уровня (С, ассемблер), без абстракций, то у них ничего бы этого не получилось. Застряли бы в 80х-90х, оптимизируя байтики в АОНах.
Вы посмотрите, какая сейчас ситуация сложилась на рынке трудоустройства: нормальных программистов не найти почти. Сплошные «тяп-ляп» — всякие питонщики,.нетщики и прочая жабоскриптодрянь, совершенно не умеющая делать что-нибудь стоящее. Только копипастить.
И не надо С называть языком низкого уровня! Что за невежество?
Так что кто где застрял — это смотря с какой стороны поглядеть, с моей: да у вас другие камни, другой язык, другая производительность, более аляпистая IDE, ОЗУ вон полтора кб с свистом куда-то делось — но вы как мигали светодиодиком так им и мигаете! Решаете ту же самую скучную, никому не нужную и никого ничему не учащую задачу… В АОНе же по одному только коррелятору — 3 диплома написано и защищено было. А калькулятор с плавающей точкой там занимал 1.2к ROM 128 байт RAM (повторно используемого буфера обработчика — т.е по факту НОЛЬ RAM) — на процессоре где умножения и деления даже в помине не было.
Где эти дипломы, их обладатели или новые устройства которые они спроектировали?
Кому сейчас нужен калькулятор, который занимал 1.2к ROM 128 байт RAM?
ОЗУ вон полтора кб с свистом куда-то делось — но вы как мигали светодиодиком так им и мигаете! Решаете ту же самую скучную, никому не нужную и никого ничему не учащую задачу…
Напишите свою статью, пусть даже про тот злосчастный АОН
Распишите как делать правильно, где экономить на спичках
Или вы только языком в комментариях чесать умеете — а на деле ноль без палочки?
И не надо отмаз, ткнете носом в свою статью с тем как надо правильно — продолжим обсуждение, сольетесь — останетесь просто диванным троллем.
Только вот софт от АОН — произведение искусства!
Кладезь методов и алгоритмов.
Идеальное средство обучению программирования.
Ваш — обычный мусор сгенерированый компилятором из чужого однотипного кода, где вашего — 2 строки. В ваших программах через много много лет специалист так и будет видеть «мигание светодиодиком»… Пройдет 2-3 года — выйдет новое IDE, новый HAL, и новые процессоры по еще более мусорной цене — ваша статья к ним будет не применима, потому что единственная вечная тема тут — светодиодик который мигает.
Там был не просто процессор общего назначения, внутри еще был сопроцессор для ускорения 3D графики. Плюс дополнительные GPU, SPU. Просто космос по сравнению с АОНами.
Могли бы наверное спрайты на ассемблере продолжать рисовать, но рынок и копроэкономика требовала 3D графику.
В примере в статье ОЗУ никуда со свистом не делось. Точнее делись только 50 байт, остальное — это пожелания пользователя, который захотел себе сделать стек в 1.5 КБ.
Сплошная копи-паста! Для многих юзверей, переопределить пин для работы с 1-w, это уже «проблема».
ЗЫ
Многие и не знают, что есть форк ЯП Forth, для STM32 (MeacrispForth). Где всё возможности контроллера, можно подёргать в интерактивном режиме, а при желании «скомпилировать» и заставить исполнять код «нативно»!
А сейчас программисты без OpenCV не знают как жить.
Поколение ардуино…
ЗЫ если это конечно не секретно! ;)
ЗЗЫ Ардуино — это удачный проект, для привлечения неофитов (сам с него начинал), но если остановиться и продолжать «натягивать сову на глобус» (Атмегу), то это просто «не очень разумно»!
Index: stm32f4xx_hal_uart.c
===================================================================
--- stm32f4xx_hal_uart.c (revision 2632)
+++ stm32f4xx_hal_uart.c (revision 2633)
@@ -2487,7 +2487,7 @@
{
/*-------------------------- USART BRR Configuration ---------------------*/
#if defined(USART6)
- if((huart->Instance == USART1) || (huart->Instance == USART6))
+ if((huart->Instance == USART1) || (huart->Instance == USART6) || (huart->Instance == UART9))
{
huart->Instance->BRR = UART_BRR_SAMPLING8(HAL_RCC_GetPCLK2Freq(), huart->Init.BaudRate);
}
@@ -2506,7 +2506,7 @@
{
/*-------------------------- USART BRR Configuration ---------------------*/
#if defined(USART6)
- if((huart->Instance == USART1) || (huart->Instance == USART6))
+ if((huart->Instance == USART1) || (huart->Instance == USART6) || (huart->Instance == UART9))
{
huart->Instance->BRR = UART_BRR_SAMPLING16(HAL_RCC_GetPCLK2Freq(), huart->Init.BaudRate);
}
Да и благодаря сообществу — решение находится за 5 секунд github.com/ARMmbed/mbed-os/issues/12090
ST обещали исправить
Хал (как и регистры) — не панацея от всех бед.
Нельзя сказать: один раз написал и таскаю туда сюда бездумно
Нет. Это работает не так.
Пишу еще раз
Хал экономит ваше время, когда необходимо сделать довольно сложный проект за короткое время.
Хал помогает вам, когда надо проверить новую идею руководства сегодня-завтра.
Хал экономит вам время, когда у вас есть работающий код — который необходимо запустить на плате с отличающимся железом.
Он не защищает вас от ошибок (ваших или своих)
Нельзя бездумно делать копипаст, нужно понимать как это работает внутри.
Я сам много раз сталкивался с ошибками в хале, но эти ошибки нужно устранить один раз — а польза будет всем.
PS Кстати в вашем варианте устранение ошибки USART9 породило новую скрытую ошибку, надеюсь найдете сами.
Скажем, одновременно работающие: USB-устройство (да хоть CDC для начала), CAN, SPI через DMA на пару устройств, I2C через DMA, штук 5 таймеров (SysTick как обычно — для счета системного времени под многочисленные КА, пару таймеров на разные ШИМы, таймер на захват, таймер для DMA), эмуляция параллельного 8-битного интерфейса через DMA, штуки 4 канала АЦП через DMA, три UART'а… Еще можно добавить полуаппаратный 1-wire на таймере с DMA или UART+DMA.
И не надо рассказывать байки о том, что для построения подобного не придется корпеть над RM и даташитом!!!
Ну и вопрос: а коли все равно нужно очень хорошо изучить RM и даташит, то какой будет профит от хала (ведь дополнительно придется еще и его документацию изучать + внимательно читать исходники в поисках многочисленных багов).
Эх, ардуинщики… Славно у них светодиодом получается моргать, но лишь только они собираются что-то более-менее сложное сделать, как внезапно оказывается, что надо бы на уровень пониже спуститься…
STM32F4 + HAL + FreeRTOS + LWIP
Работало с родным ПО и драйверами
2) Так же делали контроллер для электропитающего узла.
STM32F4 + HAL + FreeRTOS + LWIP
На нем была веб морда для показа параметров с ява скриптами и динамическим отображением параметров
modbus tcp на 4 одновременных сессии
самописный modbus rtu slave на 2 uart (тоже полностью на HAL)
самописный modbus rtu master на 1 uart (тоже полностью на HAL)
крутилась внутренняя логика которая считала параметры установки в зависимости от полученных modbus master значений из сторонних приборов и состояний дискретных входов.
так же крутилась логика работы для резервного отключения нагрузки
был поднят самописный ftp для заливки файлов веб морды на spi флешку at...161 на плате
и вишенка на торте — эта штука могла обновить свое ПО по сети, параллельно с основной работой.
естественно еще была внешняя рамка на плате, чтобы было где разгуляться
Лично создал прошивку для платы управления имитатора стрелкового оружия тренажёра профи http://inter-sim.ru/profi.html.
Будучи абсолютным нулем в микроконтроллерах примерно за 2-3 месяца с использованием hal был создан промышленный образец прошивки, которая работает и по сей день(уже как 3 года).
В проекте использовалось 2 uart, несколько каналов АЦП для датчиков, несколько пинов для управления клапанами и лазером.
Если это игрушка, что что по вашему не игрушка?
Ваш комментарий из серии. Когда технологии поворачиваются лицом к разработчикам, разработчики поворачиваются к технологиям
консервативным задом.
Мне казалось уже прошло время, когда кто-то тратит уйму времени изобретая велосипед (явно со стальной рамой и шатунами на клиньях) для того, чтобы сэкономить лишние пару байт-мегабайт памяти(дорогого люминия, итана или арбона). Помню лет 15 назад в колледже мы с однокурсниками тоже удивлялись тому, что форма с кнопкой написанная на асм-е занимает 10кб, а на delphi / vcl все 300, но почему-то более чем формы с кнопкой никто ничего не писал на асм-е (ну так думаю надеюсь). Выводы, которые вы сделали в вашей статье примерно из этой же серии.
К счастью для разработчиков реальность сегодня такова, что никого не интересуют лишние 5кб памяти, когда на кону выпуск продукта на месяц раньше конкурентов. Будем благоразумны, мы же не для спутников и межпланетных кораблей софт пишем. Как минимум потому, что ни там ни там вряд-ли кто-то будет использовать абсолютно не защищённый от космической радиации stm32.
"плюсик" за STM8S
Мигалка по таймеру с ожиданием прерывания:
#include <stdint.h>
#include <stdio.h>
#define CLK_DIVR (*(volatile uint8_t *)0x50c6)
#define CLK_PCKENR1 (*(volatile uint8_t *)0x50c7)
#define __IO volatile
typedef struct GPIO_struct
{
__IO uint8_t ODR;
__IO uint8_t IDR;
__IO uint8_t DDR;
__IO uint8_t CR1;
__IO uint8_t CR2;
}
GPIO_TypeDef;
#define GPIOB_BaseAddress 0x5005
#define GPIOB ((GPIO_TypeDef *) GPIOB_BaseAddress)
#define TIM1_CR1 (*(volatile uint8_t *)0x5250)
#define TIM1_IER (*(volatile uint8_t *)0x5254)
#define TIM1_SR1 (*(volatile uint8_t *)0x5255)
#define TIM1_CNTRH (*(volatile uint8_t *)0x525E)
#define TIM1_CNTRL (*(volatile uint8_t *)0x525F)
#define TIM1_PSCRH (*(volatile uint8_t *)0x5260)
#define TIM1_PSCRL (*(volatile uint8_t *)0x5261)
volatile uint8_t led = 0;
void TIM1_overflow_Handler() __interrupt(11)
{
TIM1_SR1 &= ~1;
if (led == 1) {
GPIOB->ODR |= (1 << 5);
}
else
{
GPIOB->ODR &= ~(1 << 5);
}
led ^= 1;
}
void main(void)
{
CLK_DIVR = 0x00;
CLK_PCKENR1 = 0xFF;
GPIOB->DDR |= (1 << 5);
GPIOB->ODR |= (1 << 5);
TIM1_PSCRH = 0x00;
TIM1_PSCRL = 0xF4;
TIM1_CR1 = 0x01;
TIM1_IER = 0x01;
__asm__ ("rim");
while(1)
{
__asm__ ("WFI");
}
}
SW — SDCC + stm8flash
HW — STM8S103F3P6 + ST-LINK V2
240 байт флэша:
#define CLK_DIVR (*(volatile uint8_t *)0x50c6)
#define CLK_PCKENR1 (*(volatile uint8_t *)0x50c7)
TIM1_PSCRL = 0xF4;
TIM1_CR1 = 0x01;
TIM1_IER = 0x01;
Какой это процессор? Почему этим числам стоит доверять? Сколько вы времени потратили на создание таких define'ов?
Как минимум стоит использовать файлы с описанием регистров от производителя. Да, внутри они могут быть тем же самым, что у вас. Но у них нет описанных недостатков.
Процессор — STM8S103F3P6
Дефайны — из файла stm8s.h, вынимаем оттуда только то, что нужно для конкретного проекта (такой метод вполне сработал и для преобразователя PS/2-UART, хотя дефайнов там оказалось малость побольше)
Настройки таймера — из даташита
"Магия" — это, конечно, так, но для конкретного контроллера вполне оправдана.
Вместо магических чисел в регистры пишем комбинированные битовые маски, которые имеют те же названия, что и в даташите. Их опять же берем от производителя, а не сами руками создаем.
Опять же, какой функционал? Может быть в китайской печке on-off термостат, а в российской PID. Может в российской графический дисплей с кучей термопрофилей, а в китайской какой-нибудь примитив?
5КБ флеши много где? На AtTiny2313 — да, много. На копеечном BluePill F103 — около 10%.
habr.com/ru/post/481436/?reply_to=21045638#comment_21045602
Лично у меня мигалка светодиодом заняла под STM32L0:
Used FLASH: 720 bytes out of 128KB (0%)
Used SRAM: 28 bytes out of 20KB (0%)
#include <stm32l0xx_ll_bus.h>
#include <stm32l0xx_ll_gpio.h>
#include <stm32l0xx_ll_utils.h>
int main(void)
{
LL_InitTick(16000000, 1000);
LL_IOP_GRP1_EnableClock(LL_IOP_GRP1_PERIPH_ALL);
LL_GPIO_SetPinMode(GPIOB, LL_GPIO_PIN_5, LL_GPIO_MODE_OUTPUT);
LL_GPIO_SetPinOutputType(GPIOB, LL_GPIO_PIN_5, LL_GPIO_OUTPUT_PUSHPULL);
LL_GPIO_SetPinSpeed(GPIOB, LL_GPIO_PIN_5, LL_GPIO_SPEED_FREQ_LOW);
for (;;)
{
LL_GPIO_SetOutputPin(GPIOB, LL_GPIO_PIN_5);
LL_mDelay(500);
LL_GPIO_ResetOutputPin(GPIOB, LL_GPIO_PIN_5);
LL_mDelay(500);
}
}
Для си и ассемблеро-ретроградов, вот столько добавляет std::map и переменная с его использованием:
Used FLASH: 1932 bytes out of 128KB (1%)
Used SRAM: 160 bytes out of 20KB (0%)
STM32 fast start. Часть 2 Hello World на HAL, отладка в Atollic TrueSTUDIO