Pull to refresh

Comments 25

Студент привел, по-моему около 20 или 30 способов
приписывают физику по имени Нильс Бор

Эм. "Экзотерично" это как? Экзотично? Эзотерично? Шестнадцатирично? :-)
А вообще конечно странно, что до сих пор не написали каноничный код для работы с регистрами мк. На хабре статей 5 уже видел...

Ну т. е. простая, очевидная — не составляющий никакой магии и особых знаний.
Там ARM сделал SVD файлы для каждого производителя, впринципе решенин есть, я в конец статьи добавил…

Типичный случай забивания гвоздей микроскопом.
Нафига вам работать с регистрами из C++ напрямую?
Вы пишите BSP так что потом вас долго вспоминали тихим добрым словом, те кому придётся всё переделывать?
Что мешает работать с готовой HAL отделанной от регистров, и реализованной на обычном C или даже ассемблере где не надо бороться с проблемами вызванными улучшениями, призванными бороться с этими самыми проблемами но в общем виде?
По HAL, ну кроме того, что там оверхед — мама не горюй, хотя для меня это странно, если ты выпускаешь, например, 1 000 000 розеток умных в год и из-за использования HAL с оверхедом пришлось контроллер взять с большим ОЗУ и ПЗУ и дороже на 30 центов — это же 300 000 долларов и можно держать 3 программиста в США дополнительно и делать на один проект больше.

Так вот кроме этого, я считаю, что его можно использовать только в устройствах, которые поработал быстро и выключил, типа CAN сканера для считывания ошибок в автомобиле, или управление геликоптером, или блутуз чайник (хотя спорный вопрос, но знаю, что Редмонд его и использует), где риск отказа вообще не высокий. Ведь не беда, что устройство работает час, а потом перестает отвечать через USB(баг в USB там жесткий был)… или вытыкаешь на живую, а windows с синим экраном падает, ну ничего пользователь просто переткнул устройство, перегрузил компьютер и все…

А если вы делаете медицинское оборудования, где от такого зависания зависит жизнь человека? А если на атомной станции стоит?
Я бы даже в умной розетке его бы не использовал, потому, что опасно это.
Ответ на стековрелфлоу, мне кажется очень разумным:
It gives pseudo developers false feeling that they do not have to know how their hardware works.
Time spent learning HAL may be longer (and usually is) than needed to understand how the hardware works.
Horrible overhead
Many errors.

А переделывать все равно придется рано или поздно, ведь Общедоступные библиотеки же появляются уже тот Kvasir, modm. А закрытых еще больше… и все уже написано и ethernet и usb и стеки все и оно не жрет столько ресурсов, как HAL и код даже компактнее, чем на ассемблере.
Я вот помню, как примерно в таком же стиле переходили в 90х с ассемблера на Си. Ну тоже самое все было… и библиотеки и программисты только на ассемблере писали для 6800, 51 и PIC, но ведь перешли, ничего, сейчас кто ассемблер вспоминает?

Даже ARM это понял что люди переходят на С++ и выпустил вот это для генерации нормальных регистров на С++.
Если не нравится готовые BSP вы можете сами написать модули работы с периферией и использовать их из C++. Будет проще и короче. Нафига тащить в выскоуровневый код особенности целевой платформы. Если вы хотите управлять светодиодом это должно выглядеть так:
digitalWrite(led1Pin, HIGH);
или так
analogWrite(led2Pin, level);
А чем это лучше, такого
Led1::Set();
А теперь представьте, что вам надо переключить сразу несколько ножек на разных портах… на Си это во сколько на ассемблере выльется?
А на С++ в 5-7 команд. Смотрите Reflector показал, как это реализовано easyelectronics.ru/rabota-s-portami-vvoda-vyvoda-mikrokontrollerov-na-si.html
А код будет выглядеть, примерно так
LedList<<Led1, Led2, Led4, Led3>::Toggle();
И всего то, и выродится это может в что-то типа
GpioA->Odr ^= (1 <<1) | (1<<2);
GpioC->Odr ^= (1 <<4) | (1<<3);

У него даже еще лучше через BSRR регистры

В статье довольно простой поиск групп пинов, там ищутся только идущие подряд, только в одном направлении и не должно быть других пинов относящихся к тому-же порту, т.е. список из PA8, PA7, PA6, PA3 — это 4 отдельных пина, из-за последнего. У меня ищутся цепочки в обоих направлениях и порядок не имеет значения, для списка PA8, PA7, PA3, PA5 будет найдена цепочка PA8, PA7, PA5, потому что если биты 3, 2 и 0 входных данных сдвинуть на 5 влево, то они станут как раз битами 8, 7 и 5. И в статье старенькая Loki используется, я брал за основу списки типов от Олега Фатхиева, на вариадиках, есть видео на youtube .

Представите что вам вообще не нужно переключать ножки на C++ а просто выставляете код ошибки. А он отобразиться на 9-ти сегментном индикаторе, в виде моргания сетодиодов или последовательности звуковых сигналов в зависимости от платы под которую собран проект. Я говорю про то что часть которая зависит от платы должна быть не большой, простой, легко меняемой и независимой от вашей программы написанной на C++ которая реализует конкретный функционал. И тянуть в неё всякие излишества не имеет практического смысла.

Есть у меня класс для работы с дисплеями, дисплеи могут быть с разными контролерами и работает это все через SPI, FMC или ногодрыг. В последнем случае я передают в шаблон отдельные управляющие пины(RS, WR...) и список пинов для данных, там они могут идти в любом порядке. Можно взять плату на которой дисплей с 16-ти битной шиной подключен к FMC и заставить ее работать через ногодрыг задав для данных такой список пинов:


PinList<PD10, PD9, PD8, PE15, PE14, PE13, PE12, PE11, PE10, PE9, PE8, PE7, PD1, PD0, PD15, PD14> LcdData;

Все, теперь внутри либы будет вызваться LcdData::write(...) и все разлирутся самом собой, пины автоматически разобьются на 4 группы и данные будут записаны в 2 порта, причем так же работает чтение, установка режима, быстрая смена направления и т.д… С точки зрения пользователя все предельно просто, эффективность на самом высоком уровне… С семисегментником будет то же самое, не важно к каким ногам он подключен, достаточно в списке расставить пины в правильном порядке.

Как раз все наоброт, на Си придется переписывать этот кусок, в зависимости от конфигурации порта, номера ножек и так деле, а на С++ берите и переиспользуйте его в другом проекте. И даже проще чем на Си.
А то что там на задворках для компилятора написано, в это вникать не надо… Это не для микроконтроллера, это для компилятора.
Кстати насчет ошибки… вы же вот тут написали Унифицированная обработка ошибок (C++ вариант для микроконтроллеров)
пример на Си — но это же столько ненужной работы надо сделать, и как его вообще переиспользовать, если у меня новые коды ошибок появляются? А на С++ ничего делать не надо… только список определи и все…
using CategoryErrorsList = EnumTypeRegister<Cpu_Error, Measure_Error, My_Error>;
И самое главное, в итоге по ресурсам процессора меньше. Зачем эти ненужные траты времени на написание скрипта? считайте что, аналог этого скрипта на С++ это как раз реализация класса метапрограммированием. Еще раз повторяюсь, все что там на шаблонах написано, это и есть скрипт-код не для микроконтроллера, а для того, чтобы компилятор этот код (скрипт) выполнил во время компиляции.
Вы как-то предвзято относитесь к C на нём так же можно параметризовать к каким ногам привязано внешнее оборудование. Я про другое вы добавляете множество ненужных сущностей, якобы для упрощения. Если что-то не заработает то придётся разбираться с вашими задворками которые только для компилятора.
По поводу скриптов, вот у вас есть десяток вариантов плат. Где вы их конфигурации храните, даташиты и схемы по разводке? В шаблонах. Нет вы их храните в системе контроля версий в субмодуле платы. А на шаблонах там сделано или на дефайнах это дело десятое. Просто скриптом вытягиваете нужную ревизию и собираете. Причем заставляете это делать какой-нибудь jenkins.

«И самое главное, в итоге по ресурсам процессора меньше» — это не главное.
Напоминаю главное чтобы работало здесь и сечас. Поэтому переписывать так чтобы было офигенно со всех сторон как правило экономически не выгодно.
Да я не имею ничего против Си, я согласен, что новый С18, вроде бы тоже штука мощная. Я Си не так хорошо знаю, собственно и С++ тоже не освоил до конца, там еще учить и учить. Но то, что применяю, кажется очень эффективным.
В общем я не хотел сказать, что Си плохой и на нем не надо писать, я к нему отношусь нейтрально, как к любому другому языку, который не очень знаю. Я больше хочу сказать, что С++ хороший и на нем можно писать эффективно на микроконтроллерах, но не обязательно нужно.
Думаю, что если надо быстро выпустить продукт на рынок широкого потребления, то да, взял Cube, HAL, быстро накидал логику — выпустил и собираешь прибыль, то альтернативе Си сейчас нет.
Но вот если продукт для атомной станции, который делается годами, то можно и потратить время на изучение более безопасного подхода, в том числе и на С++
переход с ассма на си дал очень много,
но разница в сложности между си и асмом не такой большой была,
а учитывая сколько видов не совместимых с собой асмов на одну и ту же архитектуру было я бы за засомневался была ли сложность асма ниже чем у си, особенно у асмов с макросами и метапрограммингом, особенно у дсп от AD и техасов в конце 90ых — вот там творился вообще адский ад, пример попроще — турбоассемблер и макроассемблер под ДОС.
Пюсы дают проблемы компиляции на ровном месте из за более строгой типизации, зато огромный плюс плюсов в том что не перепутаешь xxxAPHxxxx и xxxAPBxxxx константные энумы инициализации и прочие плюшки строгой типизации и более развитый язык за который нужно платить в разы возрастающим временем проектирования, например генерики функций на шаблонах — такое порой проще препроцессором си написать (самое главное чтоб этот АД не пришлось потом через год поправить — никакая даже самая подробная дока не спасёт от траты минимум дня на разбор что это за ужас) — я про то что случае си читать потом неудобно, а в случае плюсов проектировать такое гораздо дольше — существенного преимущества нет.

Именно поэтому, я сомневаюсь, что плюсы полностью си вытеснят.
Скорее кончатся программисты которые на голом си умеют писать.
Полностью согласен. Ни C ни asm никуда не денутся. А C++ надо применять не везде, а там где это оправдано не говоря уже о зоопарке новых стандартов.
Почти согласен, что проектировать новое всегда дольше, но как только спроектировал, перезаимствовать уже намного проще. Но поддерживать код приложения на С++ гораздо проще, потому что он просто понятнее…

И да, так и будет — программисты кончатся, как кончились программисты на чистом ассемблере. По-крайней мере, так как я преподаю в университете, а там только С++ дают, в том числе и мой курс для микроконтроллеров. Про указатели многие студенты, приходя ко мне на курс даже и не знают, про ссылки знают, про ссылки на rvalue знают. А указатель это новость для них. Может это и правильно, не будут не безопасный код писать.
Про указатели многие студенты, приходя ко мне на курс, даже и не знают, про ссылки знают.

Юные, жизнерадостные идиоты...)))
UFO just landed and posted this here
UFO just landed and posted this here
Только про простое ногодрыжество? А как же SFR, реализовать их типобезопасно интереснее, нет?
Я рассматривал только периферийные регистры, потому что они часто используются в разных модулях и следовательно надо их передавать как-то. А регистры специального назначения, по моему мнению, нужны только при начальной настройке и при реализации РТОС. Так то их трогать не рекомендуется. Но вообще АРМ делает такие вот файлики и можно от производителя его получить и генерить регистры по адресам. Считайте способ 8 или 7 будет…
Заинтересовался данной статьей, так как сейчас занимаюсь написанием библиотек для stm32mp15x. Статью прочитал несколько раз, вдумчиво, заметил следующий минус:
Тип доступа RO/WO/RW должен отностится не к регистру, а строго к каждому биту в отдельности
Дело в том, что во многих регистрах соседствуют биты rw и ro, некоторые биты сбрасываются записью 1, а не 0. Отсюда минус «можно сделать глупость» никуда не уходит.
В заголовочниках от производителя нет описания типов доступа для отдельных бит, а значит автоматически пересобрать заголовок с регистрами через python не получится. Теоретически это может делать производитель путем обработки исходных hdl-кодов (собственно, стандартные cmsis-заголовочники так и делаются), но вряд ли они будут делать это в сколь-нибудь обозримом будущем.
Вот тут я немного поигрался… www.onlinegdb.com/edit/BJ7BiHDqE
Там идея в том, в том, что генерация описания классов и регистров будет из SVD файлов, а код обращения к регистрам уже не сложный.
И да, некоторые производители делают описание для перечислений, т.е. допустимых значений битов с их именами. Например, Техас, но ST почему то игнорирует это. Хотя с ST можно договориться :) если надо. Но самому для каждого бита добавлять тип только для чтения или только на запись по 1, например, это конечно еще та работенка. В любом случае, можно по возможности ограничить запись неверных значений, или вообще ограничить запись сразу всего регистра, а предоставить доступ только для конкретных битов.
Если время будет, я попытаюсь это описать и выложить на хабр.
Куда хуже когда производители вообще не дают описание периферии.
Sign up to leave a comment.

Articles