Pull to refresh

Comments 74

а почему с битовых операций?
я вижу два пути в микроконтроллеры — из схемотехника когда на обычных гейтах уже сложно и надоело лепить и нужны алгоритмы типа антидребезга, но в этом случае человек уже наверняка знает эту тему.
Либо же из программирования, но что за программист не умеющий в булевую логику? Может быть в вебе сейас таких немало но тогда зачем ему МК?
Честно не пойму зачем этот 1 класс нужен.
Ну и непонятно зачем тогда STM32 в заголовке.

Я бы советовал начать сразу с:
«Из чего состоит библиотека CMSIS? Как в ней ориентироваться? Что полезного можно из нее извлечь и как ей пользоваться?», это реально акутальная и мало раскрытая тема, особенно судя по мегатоннам тривиальных асмовских самописных функций — люди не знают что многое делается при помощи CMSIS в пару строк и на простом си.
Да и пункт №3 тоже полезен для тех кто на английском документацию не может читать.

т.к. «startup-файл» редко когда нужно править, да и наверняка будет разобран ассемблеровский вариант, т.е. bad practice — мамонт доставшийся от уважаемой пары старичков кейла с иаром. Всё для STM32 можно сделать на си. Асм в современных микроконтроллерах это очень не нормально и странно.
Согласен. Я бы тоже начал с CMSIS, стартап-файла и архитектуры самого контроллера. Там дофига тонких и малопонятных тем вроде начального конфигурирования контроллера. А уж с битовыми опрациями кто угодно разберется.
Но если уж говорить о битовых операциях — то я не уверен что в статье исчерпывающий перечень. Вроде бы еще в различных архитектурах бывают вращения, прямая работа с битами по номеру, поиски единичных битов, разворот битов в слове. В ARM точно некоторые из них есть (а может и все). Это более редкие (почему-то) инструцкции и для них нет привычных операций в си-подобных языках.
Если сделать оговорку, что это для самых маленьких — то рассмотрение вопросов касательно вращения, циклических сдвигов и прочего было бы немного излишним.
Почему? Что сложного в циклическом сдвиге по сравнению с обычным?
В виду прикладной невостребованности на начальном этапе изучения. ИМХО.
Смотря с какой стороны подходить к изучению. Я вот подхожу к изучению С и микроконтроллеров со стороны верилога…
Это фундаментальные знания… Я хоть это уже давно проходил, но для начинающих это хороший базис! Я например забрал к себе калькулятор из этой статьи.
А можно его где-то ещё выложить? А то почему-то «Access Denied» на весь сайт…
Вчера проверял ссылку — всё было ОК. Попробуйте открыть сайт через прокси, VPN или просто по названию программы поищите в гугле.
Я с утра нормально зашел и забрал. Да и сейчас открывается.
Что поделаешь, видимо ограничение по геолокации. Что довольно странно для интернета, надо попробовать ещё с другого провайдера.

Пробовал проследовать туда по https но походу там другой сайт висит, ругается на неверный сертификат(от другого сайта) и выдаёт ошибку 500.

Гугл кстати выдаёт ссылки только на этот же сайт, на других рассматривается уже другой калькулятор.
Начинать можно прекрасно без этого — не на асме же писать планируете?
Ну когда-то я втыкал в сайт EasySTM32 и проекты на CMSIS… Вот вроде понятно, но местами какая-то битовая операция автором не объясненная и сиди гадай, что это такое. Потом я с горем пополам написал на CMSIS гирлянду и ушел в SPL. Но в STM пока на уровне свистелок и мигалок с LCD 1602.
Тогда надо с архитектуры начинать. Что такое АЛУ, что такое счетчик адреса, что такое шина… Это тоже все фундоментальные знания.
Тут книгу тогда писать необходимо.
Без обзорного рассмотрения данных тем не обойдется 100%.
Вот как же надоело это «как пользоваться той или иной библиотекой»
Я бы хотел в любиттельском МК больше видеть людей, которые, когда пишут код, думают не о том, как это потом поддерживать/реюзать/портировать, а о том, в какой машинный код это собирётся, и как сделать так, чтобы вход-обработка прерываний-выход занимали как можно меньше тактов. Потом, когда они пойдут в профессиональное программирование, они научатся.
Такие люди должны очень хорошо разбираться в булевых операциях. Поэтому важно в начале тщательно их приподнести. Да, половина читателей знакомы с ними. Ещё треть знает половину их. А оставшаяся часть только думает, что знает.

А вот это всё «библиотека CMSIS», «HAL», «CAN для начинающих» — этого в интернете навалом. И писать о том, как можно портировать iconv на stm32 для того, чтобы на лету менять кодировку на символьном экране — хватит уже!
Воистину плюсую. Я считаю что библиотеками надо начинать пользоваться когда ты уже знаешь как это всё функционирует на низком уровне. Абстрагироваться от имеющихся знаний чтобы не держать в голове весь объем информации. Восходящая абстракция так скажем. А не наоборот.
1. Я в изложении в первую очередь опираюсь на то, как я начинал в свое время и в какой последовательности изучал темы. И долбёжку в регистры с булевыми операциями освоил только когда начал кодить под МК.
2. Заголовок в целом обозначивает принадлежность к циклу статей которые я буду периодически публиковать.
3. Я не знаю о том, с каким уровнем подготовки читающие попадут сюда и будут знакомиться с моим циклом статей. Поэтому я решил перестраховаться, для себя счёл логичным рассмотреть данную тему в совокупности с рассмотрением утилки для удобной работы с бинарными числами, уж лишним точно не будет. =)
4. Над 3им и 4ым пунктом еще нужно будет много подумать.
Как я и боялся, вы начали со слишком низкого уровня. Хорошо хоть не с «Что такое электричество».
Повторюсь) Я не знаю о том, с каким уровнем подготовки читающие попадут сюда и будут знакомиться с моим циклом статей. Поэтому я решил перестраховаться, для себя счёл логичным рассмотреть данную тему в совокупности с рассмотрением утилки для удобной работы с бинарными числами, уж лишним точно не будет. =)
Думаю, что еще успею и Вас порадовать чем-нибудь интересным!)
Кажется вы полноценный учебник решили сделать, что не может не радовать.
Неплохой материал (все знаю. но буду тыкать носом спрашивающих), но при чем тут STM32? Это же все платформонезависимые вещи — самая база, так сказать.
Тогда бы примеры кода не помешали.
О, это непременно будет предоставлено)
То есть, будет огромная куча микростатей?

P.S. мне-то не надо, но пока это выглядит как урезанный пересказ школьного курса.
Я подразумеваю написание цикла статей по данным МК.
От базовых основ до рассмотрения конкретных вопросов.
Логика будет в том, что мы подойдем к реализации целевого устройства, с создания которого всё и началось, через изучение тем которые касаются STM32 прямым или косвенным образом.
На текущий момент да, так и есть. Основа основ. Для самых зелёных.
Вот не совсем понятна целевая аудитория автора. Люди, которые не понимают основы языка и битовые операции, уж точно не пойдут на stm32. Для таких людей вполне подходит Ардуина. По моему разумению, stm32 не есть платформа для начинающих (особенно такого уровня, где человек не знаком с основами двоичной арифметики). STM32 — адское место даже для продвинутых профессионалов, особенно на уровне CMSIS. Периферия STM32 чрезвычайно сложна, регистры и их поля существенно различаются в разных семействах stm32. Например, при работе с модулем I2C нужно записывать в регистр некую константу, вычислить которую можно либо в Excel-утилите, которая есть на сайте STMicro, либо через STM32CUBEMX.

Если уж действительно обучать ИМЕННО stm32, наверное, нужно знакомить читателя не с битовыми операциями, а с общей архитектурой? Нужно показать, из чего она состоит, в какие группы объединяется периферия, какие шины её соединяют и какая схема тактирования этих шин. Также неплохо особенно подчеркнуть, что в Stm32 процессорное ядро является не монолитным, а входит в общий кластер периферии как модуль.

Говоря о тактировании, хорошо бы упомянуть про RCC, без понимания работы которого нет смысла вообще связываться с stm32. И почему бы, на этапах ознакомления с общей архитектурой, не использовать PeripheralLibrary, которая как раз позволяет сосредоточиться на функциональности периферии, общих принципах её работы, а не на деталях программирования регистров?

Опять же, самая главная книга при работе с stm32 это Reference manual. Почему бы не указать людям ссылку на источник?
Мне кажется Вы существенно преувеличили сложность STM32. Я начинал изучение и программирование МК именно с STM32. Все основы закладывал при работе с ним, в т.ч. и битовые операции.
В процессе написания статей я рассчитывал осветить целевые вопросы для людей самого широкого уровня подготовки, готовых учиться.
В целом, ведь никто не мешает пропустить материал по теме которого уже имеется достаточно знаний и опыта и перейти к рассмотрению более интересных вещей.
Насчёт I2С. Ничего страшного в этой константе нет совсем))) ну и я даже как новичок не соглашусь с определением «сложная периферия». Я бы тут употребил «всеобъемлющая» и «гибко настраиваемая».
Я безусловно ценю Ваше мнение но всё же, я буду строить логику изложения таким образом, как бы повторяя то, с чего я начинал и какие темы изучал сам на момент обучения. И ориентируюсь на создание такого обучающего материала, которого мне так не хватало в свое время.
Когда-то мы в универе учились на аврках и пиках. С удовольствием бы их выбросил, и учил бы СТМ, но тогда, в 2005…
сравнить два регистра и определить равны они или нет. В этом случае нам необходимо значения регистров подвергнуть операции XOR

Я не силен в ARM, но обычно сравнение делается через вычитание без сохранения результата но с модификацией флагов, одним простым действием можно сразу понять равно, меньше или больше.
А еще можно просто сравнить, и компилятор сам все распишет, как надо.
Как вы от сравнения регистров перешли к компилятору?
А в чем проблема? Регистр это один или несколько байт. Мне ничто не мешает написать что-то вида
if (PORTA==24) {do some code;}
При этом меня слабо волнует, какой там набор инструкций у камня, и как компилятор это раскроет. По крайней мере, до тех пор, пока я не захочу строгий реалтайм…

А первые программы можно вообще без знания даже о самом существовании битовых операций (а также — структуры АЛУ, его флагах и тд) писать. Потому я, хоть убейте, не понимаю, почему автор начал изучение архитектуры со школьной математики (~7 класс, емнип. у кого не было отдельно логики, должны были классе в 10-11 это на информатике пройти).
Плохо что не интересует, ну хотя бы для того, что бы в дискуссии про регистры, не писать PORTA
PORTA это тоже регистр, в чем проблема? Битовые операции чаще всего как раз с портами и делают (особенно — новички, которые пишут мигалку). Можно было любой другой (доступный на чтение) привести для примера — суть бы не изменилась.
Плохо что не интересует
Не понимаю, о чем вы.
PORTA это регистр устройства, для процессора это порт ввода/вывода, для обращения к которым есть свои отдельные команды (IN/OUT), напрямую делать с ними битовые операции, без загрузки в РОН, невозможно. Под словом регистр обычно и понимаются РОН — регистры общего назначения.
Спасибо, я знаю архитектуру микроконтроллеров. В тексте, на который я отвечал речь о просто абстрактных регистрах с точки зрения программиста. Не? Да, АЛУ в AVR работает только с регистрами общего назначения, но пойнт в том, что мой код выше все равно является валидным (спасибо компилятору). Кроме того, нет принципиальной проблемы сделать процесор, АЛУ которого будет напрямую работать еще и сс регистрами портов или другой переферии. То есть, это архитектурозависимо (даже если архитектур, где такое есть не существует).
Под словом регистр обычно и понимаются РОН
А это — культурозависимо. Везде принято разное. А то, вы так возмущаетесь, как будто бы назвать регистр порта регистром это что-то плохое. В окружающей меня культуре регистр это просто массив бит, реализованный в железе с известным способом доступа (ну там сдвиговые регистры и что угодно еще).

Если же мы говорим о сравнении чисел с помощью АЛУ, то вы правы насчет вычитания с последующей командой ветвления. На известных мне архитектурах это работает именно так. А вот только сейчас мне пришла мысль, что автор имел ввиду под сравнением регистра поиск отличающихся бит — собственно, ее XOR нам и даст (получим своего рода маску). Но слово регистр там опять же зря упомянуто — битовые операции с точки зрения математики работают с любыми массивами бит. Думаю, возникновение таких неточсностей нормально, когда неэлектронщик что-то узнал об электронике и хочет научить остальных.
«Это не этот регистр а тот регистр который регистр...» с точки зрения электроники, конечно, это массив синхронных триггеров, но… должно же быть какое-то однообразие в терминологии чтобы отличать РОН от регистров периферии и т.д.
Прямое подключение АЛУ с регистрами периферии создаёт больше проблем и трудностей чем решает.
Прямое подключение АЛУ с регистрами периферии создаёт больше проблем и трудностей чем решает.
Полнотью с этим согласен — потому и не применяется. По сути, оно ломает модульность архитектуры. Но я лишь хочу показать, что отсутствие таких реализаций не является каким-то фундоментальным правилом.
должно же быть какое-то однообразие в терминологии чтобы отличать РОН от регистров периферии и т.д.
Все правильно. Аббревиатура РОН для этого и существует. Я лишь хотел сказать, что текст автора полностью архитектуронезависим и не содержит ни строчки кода. Нет абсолютно ни какой возможности предполпгпть, о каких регистрах речь, и почему он вообще употребил там слово «регистр», когда «байт» было бы уместнее. Тк текст, по сути, про математику, а не про микроконтроллеры.
В далёком детстве где-то читал, что «xor ax, ax» выполняется быстрее, чем «mov ax, 0». Интересно, справедливо ли это сейчас, для современных МК и процессоров?
Зависит от архитектуры. В основном равнозначно — 1 такт.
На x86 во втором случае процессор кроме КОП должен считать ещё и константу, вероятно 32-битную если не 64-битную. Поэтому в любом случае это будет ДОЛЬШЕ.
Для AVR константа входит в фиксированного размера КОП, поэтому там будет равнозначно но играют другие ограничения — из-за нехватки битов в КОП из-за константы такая операция может быть выполнена только с ограниченным набором регистров.
STM32 не имеет фиксированного размера команды, поэтому отличия выполнения XOR и прямой загрузки константы всё-же будут.
Кстати интересный факт. В ассемблере AVR есть псевдокоманда CLR rx обнуляющая регистр, а на самом деле КОП у неё такой же как у XOR rx, rx.
Для микроконтроллеров это может быть и справедливо, но современные процессоры грузят команды не по одной, а большими блоками. Здесь может сыграть роль то, что в общем случае 'xor rax, rax' зависит по данным от предыдущего значения rax, а 'mov rax, 0' — не зависит. Поэтому код с mov может выполняться быстрее за счёт лучшего планирования. Однако, лучше здесь читать Intel software optimization guide.
А еще mov работает с любыми регистрами, а не только доступными напрямую для АЛУ. Что делает код, как минимум единообразнее.
Это на самом деле разные инструкции mov, кодировки у них совершенно разные. Просто в ассемблере пишутся одинаково, что вызывает недоумение у новичков в стиле: «а почему можно сделать mov eax, dword ptr [edx + 4*ecx +100500], но нельзя сделать mov cr0, dword ptr [edx + 4*ecx +100500]?»
Мы, вроде, ассемблер и обсуждаем. Но я честно признаюсь, что уже лет пять как пишу только на си, и обозначенный вопрос мне уже тоже не очевиден так сходу.
В том то и дело: mov с регистрами общего назначения и mov to/from control registers — это совершенно разные инструкции с разными кодировками. Кодировки, позволяющей закодировать 'mov cr0, dword ptr [edx + 4*ecx +100500]' в x86 просто не существует.
В AVR, вроде нет такой проблемы. Или я туплю?
Я знаю откуда это пошло… был когда-то нормальный ассемблер семейства Z80 где инструкции различались логично — отдельно LD для регистров и отдельно MOV для более сложных вариантов типа регистр-память. А кто-то решил что это слишком сложно для студентов и «сократил» количество сущностей. В итоге правильное и логичное описание системы команд я нашел только в одной из первых книг по этой теме, в более новых уже была новая методика с сокращенной системой и массой ньюансов в поведении казалось бы простых команд.
LD ни куда не исчезло же. В AVR с десяток его вариаций.
Кстати интересный факт. В ассемблере AVR есть псевдокоманда CLR rx обнуляющая регистр, а на самом деле КОП у неё такой же как у XOR rx, rx.

Таких команд там несколько, по сути это алиасы на другие на аналогичные команды, что видно по кодам.

Забыл за давностью лет какие ещё, а ведь раньше не переваривал Си и строчил только на асме… Если сейчас считается круто поглядеть ассемблерный листинг после компилятора, то раньше поглядывали на КОПы после ассемблера :)
А я всё ещё не перевариваю Си.
Вы просто не умеете его готовить :)
в x86 есть такие же вещи, например nop по опкоду равен xchg eax,eax
Сравнение вычитанием обычно делается, когда надо понять, какое из чисел больше. Когда хотят понять только, равны ли числа, используют именно XOR с игнорированием результата и сохранением флагов.
А в чем профит то? по скорости одинаково, зачем тогда делать две операции «для всего» и «только равно»?

Спасибо за публикацию, непременно пишите ещё!

Я так увлёкся написанием ответа на Вашу статью :))), что забыл упомянуть о том, что константа для инициализации I2C используется только в семействе stm32f0x. В других семействах, никакой необходимости в ней нет. Однако, не могу с Вами согласиться, что подобная константа является очень удобной. Ей нельзя просто так вот взять с «с потолка». Игнорировать её тоже нельзя. И обойтись без неё (как в семействах stm32f10x или stm32f20x) тоже.

Насчёт «гибко настраиваемой» периферии я полностью с Вами согласен, но сложность, на мой взгляд, всё же имеется. И она проистекает не только из обилия функция (хотя бы того же I2C), а из алгоритмов её использования (согласно Справочному руководству). В каждом семействе не только различаются регистры одной и той же периферии, а также различны и действия, которые нужно совершить для получения желаемого результата. Кроме того, чем ближе к регистрам, тем менее переносимой становится прошивка.

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

CubeMX был сделан не просто так — он был сделан, чтобы вынести работу с периферией в HAL и абстрагироваться от неё. Структура HAL во многом напоминает PerLib. Не готов утверждать, что это хорошоее решение, однако оно как нельзя лучше демонстрирует, что «не всё так гладко в Датском королевстве».

А насчёт сложностей, они обычно возникают не при мигании светодиодами, а где-то при написании, к примеру, многопоточного приложения, в котором на одной шине I2C1 висят LCD1602 экран (через расширитель порта PCF8574T), просто расширитель порта PCF8574T для клавиатуры, ds2482s-100, который опрашивает 5 термодатчиков ds18b20, а на шине I2C2 висят, например 3-4 других модуля с другими МК (к примеру 30й серии). При этом также используется USART1 для управления несколькими блоками по RS485 и протоколу MODBUS. И всё это в одном единственном stm32 (правда f103).

Я не в коем случае не посягаю на Ваше право строить логику изложения, коллега, прошу меня великодушно простить за (может быть) излишнюю настойчивость. :)))

Я по большей части хотел сказать, что мой уровень опыта работы и тип решаемых задач на текущий момент не располагает к таким выводам)))
Но и с Вашим мнением невозможно не согласиться!) Очень ценю Ваши объемные комментарии!
Основы языка C все же лучше изучать на десктопе и только после этого переходить к программированию микроконтроллеров.
сколько можно уже начинать? все это уже перелопачено по 10 раз, пора двигаться дальше с такими МК.
Возможно есть смысл после выхода всех статей цикла объединить их в руководство/пособие/соединить в одну pdf'ку
Я задумывался об этом, прикидывал. Если будет широкая заинтересованная аудитория — почему нет, думаю что было бы интересно. Посмотрим что выйдет из этого цикла статей.
UFO just landed and posted this here

Вы забыли главное — зачем это всё? Дополните, как пользоваться масками, выделять, маскировать биты. Бытовые операции в подавляющем большинстве случаев ведь используются для этого. Если нет — могу я натоптать.

Маски же я рассмотрел? Не? Уточните что добавить?
В Си-синтакисисе было бы полезно:
LED_PORT &= ~(1<<LED2);
LED_PORT |= 1<<LED2;
LED_PORT ^= 1<<LED2;

Возможно, я не совсем точно выразился. У вас упущен момент почему так происходит (или я его при беглом чтении мог пропустить).
Как выделить часть байта?
flags = byte & 0x30;
Почему так происходит?


x & 0 = 0
x & 1 = x

Таким образом


  xxxx xxxx
& 0011 0000
--------------
  00xx 0000

С пояснениями, и добавить для ИЛИ, почему на нём инвертируется маска.

UFO just landed and posted this here
Sign up to leave a comment.

Articles