Комментарии 87
Самое интересное в STL — контейнеры, а вот их я бы неопытному разработчику крайне не советовал применять на микроконтроллерах. Да, их можно "правильно приготовить", но многие ли новички знают, как именно?
Вообще, имхо, при программировании под микроконтроллеры весьма разумно перенять подходы, принятые в линуксовом ядре. Списки, таскание контекста в предвыделенных структурах и жонглирование членством их в списках, структуры данных с использованием container_of для доступа к содержимому, и все такое прочее.
Многие алгоритмы работают через итераторы. Пользоваться ими над какими-то сущностями, уже реализующими итераторы — удобно, но кроме контейнеров таких сущностей как-то и не вспоминается. А вот дополнять итераторами все свои внутренние мелкие сущности — уже морока, и непонятно, окупается ли она. Понятно, что сортировку, например, лучше делать стандартным библиотечным алгоритмом, и тогда снабдить свою структуру данных итераторами оправданно. А вот просто просуммировать элементы — имхо, проще вручную, дедовским методом.
Ну так-то да. Но потом джуны начинают морщить лоб, рвать волосы и терять самооценку, попытавшись создать std::begin от массива, переданного в параметрах функции — "ну как же, ну ведь с глобальным массивом же работало!", и все это потому, что массив, переданный через параметры, имеет sizeof () равный sizeof-у указателя, а не всего массива, и итератор не создается :)
Не подумайте, что я против итераторов или алгоритмов. Просто лично у меня как-то с ними не складывается. Не особо нужны, поэтому в голове не задерживаются, приходится лазать в книжку, поэтому стараюсь не использовать, поэтому в голове не задерживаются, и так далее, самоподдерживающийся процесс. Да и на плюсах я уже очень давно не пишу… А когда писал, плюсы были совсем не такие, как сейчас.
Ну так-то да. Но потом джуны начинают морщить лоб, рвать волосы и терять самооценку, попытавшись создать std::begin от массива, переданного в параметрах функции — "ну как же, ну ведь с глобальным массивом же работало!", и все это потому, что массив, переданный через параметры, имеет sizeof () равный sizeof-у указателя, а не всего массива, и итератор не создается :)
Щас бы использовать встроенные массивы вместо std::array
Мне не совсем понятно, что значит, научился "программировать микроконтроллеры". С моей точки зрения все 7 пунктов это тот минимум, который нужно знать для того, чтобы научиться "программировать микроконтроллеры". А чтобы понять тонкости и научится оптимально использовать ресурсы микроконтроллера, думаю, времени надо поболе. Так то, чтиво брошюрки на ядро ARM v7 reference manual на 2700 страниц займет достаточно времени. Если перейти на другое ядро, например, RISC V, там таких брошюрок несколько, а еще прибавить к этому брошюрки по С++, там и жизнь пройдет, а не только 3 года.
ru.wikipedia.org/wiki/MISRA_C
Увы, имхо, misra c требует вещей, которые после некоторого порога сложности проекта (очень небольшого) приводят не к упрощению и большей контролируемости проекта, а наоборот.
Что делать, если ты уже научился программировать микроконтроллеры?
Создать на них, наконец, что-то стоящее.
Людей, которые могут генерировать стоящие идеи, гораздо меньше чем людей, которые умеют программировать. В итоге мы видим очередную погодную станцию или очередного бота для телеграмма.
Кстати, на ПЛИС можно собрать свой собственный процессор, со своим набором команд, придумать к нему ассемблеры, компиляторы и тд. Ну или воспользоваться чем-то уже готовым, но сделанным на логике, например, RISC-V, MIPS, Cortex M3/M0, NIOS, MicroBlaze, PicoBlaze.
Да нет там никакого особенного порога входа. Отладочная плата для "пионерских поделок" стоит $40, софт бесплатный, хороший учебник — бесплатный, чип со вполне приличной для многих задач емкостью — от $6 до $12.
Была бы нормальная задача, а реализовать — несложно.
а реализовать — несложно.
Если всё так просто, то где (буквально миллионы, как в случае с Ардуино) пионеров с платами FPGA в руках?
Приличнаая емкость, это 32 макроячейки? На которой элементарный счетчик едва соберёшь…
Приличнаая емкость, это 32 макроячейки?
Сейчас играю: ZYNQ 7010, 2 core 666MHz ,22 KLUT — 256 MB DDR3 128 Mb flash — вполне серьезная игрушка за $13.5 c бесплатной доставкой aliexpress.com/item/1005001500766274.html
Впрочем согласен, что у FPGA не совсем та же область применения как у контроллеров.И порог вхождения немного другой, не скажу, что выше, просто другой. Товарищ вверху habr.com/ru/post/532744/#comment_22416460 немного сам себе противоречит с реализацией микроконтроллеров на FPGA. Их поэтому и делают, что микроконтроллеры иногда удобней чем RTL.
"вполне серьезная игрушка за $13.5 c бесплатной доставкой aliexpress.com/item/1005001500766274"
Забавно, они продают плату от кондиционера как девборду. Цинк за копейки. Хорошая основа для разработок.
Тот чип, что имею ввиду — это младший альтеровский Cyclone-IV, стоит меньше $10 в розницу, паябельный вручную корпус, 6 с лишним тысяч триггеров, 30 штук блоков памяти по 9 килобит. Я на нем расширение ввода-вывода для своего нынешнего устройства делал: пачка UART-ов (больше дюжины) через быстрый SPI с удобным для основного процессора протоколом, развязка клоковых доменов, пачка GPIO-шек (у основного процессора со свободными пинами напряженка), софтверно-переключаемые внешние интерфейсы, конфигурируемые пины плат расширения. Все это удовольствие на верилоге написалось с нуля за пару недель без предыдущего опыта работы на verilog, и спасло меня от громадной возни с кучей противоестественных ограничений, которых было бы уйма, если бы я попытался все сделать на основном процессоре.
Кстати, бесплатность софта сохраняется вплоть до очень немаленьких чипов. Вроде бы 4-е циклоны все поддерживаются на бесплатном квартусе. Ну а когда один чип стоит за тысячу баксов — тут уж и софт можно купить.
raw.githubusercontent.com/howerj/howerj.github.io/master/h2/107.mp4
И эту фигню можно написать и на PC, раз в десять быстрее(хотя бы за счет более короткого цикла изменение/компиляция/запуск).
Первый процессор Novix появился в июне 1985 года и получил обозначение NC4016. Он работал с тактовой частотой до 7,5 МГц и показывал скорость до 10 миллионов операций в секунду — впечатляющий результат для того времени. Все операции NC4016 исполнялись за один такт.
Чужие: странная архитектура инопланетных компьютеров
P.S. Ардуино шилд c GPU, FPGA, HDMI, и Python поддержкой для игр и аудиовидео Gameduino 3X Dazzler by Excamera Labs. J1 процессор запущен в FPGA.
Дело за малым, цена, борьба с багами даже в топовых сериях, недетерминированость синтеза сложных дизайнов в плане таймингов.
Естественно, что это и другие вещи — не новости для опытных ребят.
2. FPGA подходит для выполнения очень быстрого IO на множестве каналов, но таких задач практически не бывает в «обычных» устройствах.
То есть собрать цифровой 64 канальный осциллограф с частотой сэмплирования в сотни мегагерц — тут FPGA подойдет. Написать GUI для этого осциллографа — нужен микроконтроллер.
3.
на ПЛИС можно собрать свой собственный процессор, со своим набором команд, придумать к нему ассемблеры, компиляторы
ЗАЧЕМ?!!! Зачем делать тот пласт работ, что проделал Atmel или ST, если можно просто взять их готовый микроконтроллер, который будет дешевле в 100 раз, в 10 раз экономичнее и в несколько раз быстрее.
Мое мнение — FPGA нужна для очень узкого класса задач, где нужно очень быстро обрабатывать по несложным алгоритмам параллельные данные — головки самонаведения ракет, PCI-Express переходник, осциллографы, сетевое оборудование и т.п.
Сфера применения микроконтроллеров гораздо шире.
Автору. Не давайте таких советов, сначала разберитесь сами, микроконтроллеры бывают разные.
Очень легко сбиться и использовать STL с аллокациями, особенно когда пишешь сразу на обе стороны (и PC и контроллер ) Я люблю с++, но в контроллерах ему не место (ИМХО), и Вы меня не переубедите, я раньше выйду на пенсию :)
Наверноге дураки пишут на чистом С ядро линукса?
Технически это не "чистый C", а его GNU-тый диалект. Но да, дураки.
Я люблю с++, но в контроллерах ему не место (ИМХО), и Вы меня не переубедите, я раньше выйду на пенсию :)
А, то есть на микроконтроллерах не нужны ни нормальные массивы, ни пространства имён, ни сокрытие данных, ни constexpr, ни более строгая типизация, ни шаблоны, ни целая пачка алгоритмов из std. Деды терпели — и ты потерпи.
" Да дураки "- нет слов… Все отнять и поделить?
Псс. Да я не против, можете мигать светодиодом и дальше хоть на расте.
Все будет опасным если если не разбираться и не понимать что проиходит, и не только в контексте программирования МК.
А по теме — С++ однозначно удобней и безопасней С в любых контекстах.
Во первых STL это не только контейнеры но и алгоритмы.
Во вторых уже давно есть std::array — контейнер без аллокации. И недавно добавили std::span, который на понядок удобней всяких (void*, size_t size).
Ну и как вишенка — все контейнеры, которые аллоцируют память, делают это через аллокатор. И вы вполне можете написать себе такой какой надо.
В 2020 году, компиляторы для МК вышли на такой уровень компиляции исходного кода, что выхлоп с Си и С++ не будет отличаться.
Боюсь вас удивить, но в выборе C vs C++ наиболее важным критерием является не «выхлоп» компилятора, а то, сколько у вас памяти, и как она распределяется.
Если у вас есть безразмерный heap — можете хоть на питоне писать (модное, кстати, направление для микроконтроллеров).
А вот если памяти лишней нет, да еще и распределять ее некому (кроме себя самого), то на плюсах писать конечно можно… но это уже искусство ради искусства.
Приведу достаточно продвинутый пример использования современного C++. Допустим есть класс для работы с LTDC и в функцию инициализации одной строкой передаются требуемые пины, пусть это будут 14 пинов для RGB444. Эта функция пробрасывает пины в более общую initRgb666(), а в качестве недостающих передаются PinDummy<>. Далее все пины передаются в функцию которая добавляет им правильные AF одновременно проверяя допустимость использования конкретных ног и если что выдается сообщение об ошибке с именами ошибочных пинов. И пины одним списком возвращаются обратно, уже с AF, затем этот список вместе с режимом, а можно использовать и список разных режимов, передается функции инициализации пинов из класса портов. Там к пинам подмешиваются режимы, удаляются PinDummy<> и вызывается конструктор очередного класса который сначала распаковывает все пины в обычный массив структур, затем сортирует его по трем параметрам при помощи std::ranges::sort() и далее идет код примерно на страницу который в цикле берет отсортированные данные и этого массива и после некоторых преобразований сохраняет их в другом массиве. Наконец есть еще небольшой класс который забирает массив у предыдущего и копирует, в такой-же массив, но меньшего размера. В самом конце вызывается функция, которая получает на вход массив с информацией о пинах/AF/режимах и выполняет их инициализацию. Итак, что же получится на выходе, если на входе было:
ltdc.initRgb444<PC6, PA4, PE15, PB1, PC0, PA11, PD3, PC7, PB11, PB10, PB9, PB8, PA3, PA10>();
Думаю даже многие из тех кто давно пишет на C++ удивились бы узнав, что получим мы следующее, даже при отключенной оптимизации:
ldr r0, [pc, #668]
bl 0x24000454
В R0 грузится адрес массива и этот массив расположен во флеше(!), а размер его 29 байт. Насколько это мало должно быть понятно из того, что 14 переданных пинов были с 5-ти портов с тремя разными AF. Фактически, поскольку в С++20 можно на этапе компиляции динамически выделять память, использовать виртуальные функции или std::vector, это все тоже могло там быть с нулевым оверхедом в рантайме. Использую С или ассм и близко ничего похожего не получишь, пора уже смириться с тем, что при правильном подходе С++ — это самый эффективный язык для эмбедда :)
Для меня такой подход подход совершенно не допустим именно поэтому:
Думаю даже многие из тех кто давно пишет на C++ удивились бы узнав, что получим мы следующее
Я должен точно знать, где, когда, и как будет выделяться память, а не лезть каждый раз в дизассемблер, для изучения особенностей поведения конкретной версии компилятора.
В дизассемблер лезть не придется, получим или массив во флеше или программа не скомпилируется(для чего она должна быть написана с ошибками), а все потому, что от C++ можно явно это потребовать. Не случайно же настолько впечатляющий результат получается даже при отключенной оптимизации, когда один sort() занял бы в рантайме 3КБ флеша.
Добавили для простого массива const и он пойдет по флеш, добавили для класса constexpr/consteval и компилятор будет обязан его разместить там же, но константным класс стал только после создания, за которое отвечает конструктор, а в нем можно делать практически что угодно и совершенно бесплатно. Многие пишущие на C++ удивятся просто потому, что не знают о таких возможностях языка, на ПК они, например, не особо востребованы. Что уж говорить про тех, кто на С++ не пишет...
«Ядро Cortex-M3 компании ARM. Полное руководство Джозеф Ю».Спасибо!
Вчера встретил упоминание про специальные регистры отладки и таймер, а в pdf stm32 только скупая сноска, что мол читайте об этом у ARM
Ну, например, невозможно впихнуть ARM везде, где только можно.
1. Во-первых, когда есть требования по потреблению — например, 80uA в спящем режиме, почти постоянным сном, просыпаешься только по внешним прерываниям или прерыванию от таймера, в остальное время ядро спит.
2. Планируется крупный тираж, и надо, чтобы было дёшево. Экономишь на железе на каждой копейке. Сравнивается твоё время на работу, «впихнуть в невпихуемое», и выбор компонентов на тираже.
3. В этом случае C++ — чисто для удобства, C — норма, ASM — круто, но долго. Пишешь код на C так, что в голове понимаешь, как оно будет компилиться. Ограничения по RAM и ROM.
Но это крайний случай, конечно. Но для дешёвых и энергоэффективных устройств распространён, в случае крупной партии.
(Начинал с PIC 16C622 N-дцать лет назад. Было очень критично. Архитектуру контроллера, ASM надо было знать на 200%, про схемотехнику не говорю. Запихнуть всё сложное в 2kW RAM, 128 bytes SRAM, 2kB EEPROM, эх… По 100_000 строк не было, каюсь)
проект, в котором более 100000 строк (что не является большим количеством), становится практически не поддерживаемым на Си
Проект в более чем 100000 строк говорит о неумении писать код для контроллеров)
Ну или берите Raspberry, а не контроллер, там вас ничто не ограничивает)
Я о том, что опытный алгоритмист в большинстве случаев сведет эти 100к строк к 10к.
Начальник отдела программистов. И сам писал код, и другим указывал, как.
Вот сидит Embed программист на горе со своим знанием IDE, микроконтроллера, С++,
а что запрограммировать ( «сделать что-то стоящее»(с) ) не знает :) Этому вопросу тоже стоит уделять внимание — куда приложить ваши знания и умения. Не моргать же всю жизнь светодиодами :)
Они просто отказались от писания кода на С руками!
Важно что С++ нет и не будет — ибо не нужен. Потому, что это не развивало индустрию а притягивало в нее лишний велосипед, раздувающий штат программистов. Развитие же наоборот сократило штат, увеличив объемы код на порядок.
Если ваш истребитель через 0-ю высоту перелетит — то ЧТО!?
5G это уже что то серьезное из вашего примера. — но все равно — откажет и ЧТО!?
В любом проекте ГДЕ-ТО всегда используется С++ — какая нибудь унылая прикладуха всегда на нем написана. Только вот, когда от кода начинают зависеть жизни миллионов людей — то C++ резко там не наблюдается, потому, что все его преимущества вдруг резко превращаются в недостатки.
То с чем ваш преподаватель игрался — стандарт индустрии. embedded софт давно уже пишется в связке Matlab-Simulink-Ascet а не в VS и тп… И программирование руками осталось лишь как трюково-кроильное (когда надо сэкономить ресурсы)…
Space-X кстати LabView как минимум использует. (9 слайд) А он тоже сам генерит код на С.
А Я вам пишу о проектах с 10млн юнитов и в 2 млн строк кода в каждом. Да чтоб их руками написать — вас таких 2 непрокормимых армии нужны…
Вождение авто, в большинстве случаев, есть ни что иное как однообразная механическая работа,
Бу го га. Вождение авто — это не однообразная механическая работа. Это решение задачи распознавания на дороге ребенка, включая случай, когда он едет на велосипеде задом наперед, сидя задницей на руле и вращая педали руками и размахивая ногами в воздухе — естественно с вероятностью в 100%. И эта задача решения не имеет ни в настоящий момент, ни через 10 лет иметь не будет.
Про с++ там где этот скачок произошел — он уже давно произошел. А там где нет — уже вряд ли не произойдет. Просто большинство embedded систем обладают конечной сложностью которая не растет исходя из самой задачи которую они выполняют и в лучшем случае там за 20лет раздуют С код на 10-20% — да и черт с ним.
Что делать, если ты уже научился программировать микроконтроллеры?