ComradeBulkin

ComradeBulkin

На Пикабу
поставил 829 плюсов и 759 минусов
Награды:
5 лет на Пикабу
911 рейтинг 318 подписчиков 5 подписок 8 постов 4 в горячем

STM32 от Булкина. Урок 2: Пишем библиотеку сами для STM32

Предисловие


Меня частенько упрекают, что я даю материал в слишком трудной манере и не по порядку. Спешу вас расстроить, я и дальше буду следовать этой логике.


Стерильно-приторных уроков “для чайников” по программированию МК, в том числе и по STM32, на просторах инета полно. Учат они чему-то? Не уверен. Они лишь дают возможность разобраться в какой-то функции, когда возникает потребность.


У меня цели другие: научить думать и пользоваться документацией. Это можно сделать только на живых и настоящих примерах. Только в бою, так сказать. Я стараюсь показывать не столько возможности, сколько путь от задумки до реализации. Стараюсь выстраивать логику процесса так, чтоб не дочитав до конца вы уже могли бы предположить, что получится или какие могут возникать проблемы.


Я практикующий радионженер. Я не занимаюсь DIY. Я стараюсь показывать вещи так, как их делать ПРАВИЛЬНО. Делать на совесть, а не тяп-ляп и так сойдёт. Одно дело, когда вы берёте чужую реализацию и не разбираясь суёте в свой проект. Другое дело, когда сами пишете библиотеку с настроением, мол, разбираться некогда. Как то работает и х** с ним. Это ужас ужасный!


Предыдущие статьи:


Настройка Sublime Text 3, SW4 и STM32CubeMX для разработки STM32 под Windows 10

Настройка Sublime Text 3, SW4 и STM32CubeMX для разработки STM32 под Linux

STM32 от Булкина. Урок 1: Вводный, где мы немножко похулиганим

STM32 от Булкина. Atmega и Arduino vs STM32 и HAL


Ладно, сегодня у нас интересная тема!


Пишем библиотеку сами для STM32


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


Написание библиотеки - это приятный и увлекательный процесс! Бывает нудноватым, когда приходится тупо копипастить какие-то значения из документации, но в целом, весь процесс даёт какой-то адреналин даже. Ну а когда ты с чувством удовлетворения взглянешь на свой труд - оргазм!


Я долго не мог придумать, что же такое взять в качестве примера из того, что у меня самого не реализовано. И с удивлением обнаружил, что у меня нет библиотеки для классического текстового LCD на Hitachi HD44780. Это 1-но, 2-х или 4-х строчные дисплеи до 20 символов на строку. Те самые, которые все так любят втыкать во все свои DIY.


Полазил по просторам и с ещё большим удивлением обнаружил, что все реализации для шины I2C основаны на дурацкой классической библиотеке Arduino LiquidCrystal_I2C. Ну, думаю, сам Бог велел!


Начнём с главного: чтения документации.


Как работает дисплей


Дисплей основан на старинном чипе от HITACHI HD44780. У него нет последовательного интерфейса, как, например, у ST7920. Тем не менее, он прост до безобразия.


Открываем даташит раздел “Interfacing to the MPU” и видим примерную диаграмму, как устроен обмен данными. Смотрим, смотрим и видим фигу. Но всё-таки что-то почерпнуть можно.

STM32 от Булкина. Урок 2: Пишем библиотеку сами для STM32 Stm32, Урок, Длиннопост

Базовый его режим 8-ми битный. Т.е. мы можем передавать ему 1 байт за раз. Для чего у него есть восемь ног DB0-DB7. Ещё у него используются 3 ноги:


E: выдаём строб (импульс), который сообщает дисплею, что на ногах DB0-DB7 выставлены нужные данные, мол, давай, считывай

RS: Сообщаем дисплею, что мы хотим передать или считать, команду или конфигурацию

R/W: Сообщаем дисплею, пишем мы данные или считываем


На схеме показывается 4-битный режим. Это когда мы используем 4 ноги DB4-DB7 вместо восьми и передаём два раза по 4 бита. Режим полезен там, где жалко отдавать лишние ноги у МК. Или для нашего расширителя портов на PCF8574.


Пытливый ум заметит, что сначала мы передаём старшие 4 бита, потом младшие. Также обратит внимание, что для передачи данных на ноге R/W должен быть 0, а для чтения 1.


Итак, как же выглядит передача данных в 8-битном режиме:


Для передачи команды дисплею, на ноге RS мы выставляем 0. Если надо передать символ, выставляем 1;

Если мы передаем команду или данные, то выставляем 0 на ноге R/W;

На ногах DB0-DB7, мы выставляем значения побитово того, что хотим передать;

Выдаём строб (импульс) на ноге E;

Документация рекомендует после строба считывать готовность дисплея к приёму следующей команды.


Как же выглядит передача данных в 4-битном режиме:


Для передачи команды дисплею, на ноге RS мы выставляем 0. Если надо передать символ, выставляем 1;

Если мы передаем команду или данные, то выставляем 0 на ноге R/W;

На ногах D4-D7 дисплея, мы выставляем значения старших 4-х бит, что хотим передать;

Выдаём строб (импульс) на ноге E;

На ногах D4-D7 дисплея, мы выставляем значения младших 4-х бит, что хотим передать;

Выдаём строб (импульс) на ноге E;

Документация рекомендует после двух стробов считывать готовность дисплея к приёму следующей команды.


Я тут накидал диаграмку, как передаются данные в 4-х битном режиме. Передаём два байта 0xA6 и 0xE9.

STM32 от Булкина. Урок 2: Пишем библиотеку сами для STM32 Stm32, Урок, Длиннопост

Обратите внимание, нельзя вот просто так взять и щёлкнуть стробом. Нужно помнить, что ширина строба и пауза между ними должны соответствовать паспортным данным. Идём в даташит и ищем что-то похожее на delay, timeout, execution time и т.д. Обязательно даются такие данные. Находим табличку “Table 6: Instructions” и видим, что на исполнение команды требуется от 37мкс до 41мкс. На возврат курсора в начало экрана требуется 1.52мс. Также при хаотичном листании документа в поисках информации, какая же должна быть пауза, находим в диаграмме “Figure 24: 4-Bit Interface” это:


When BF is not checked, the waiting time between instructions is longer than the execution instuction time. (See Table 6.)

Т.е. если мы не проверяем флаг занятости дисплея (почему объясню позже), то пауза должна быть больше, чем время исполнения инструкции. Т.о. я указал на диаграмме ширину строба 50мкс, интервал между парными стробами тоже в 50мкс, а интервал между данными 60мкс, для гарантии (китайские микрухи такие китайские).


Сами символы хранятся в таблицах, которые бывают Японскими или Кириллическими. На Али кириллицу хрен купишь, поэтому мы можем только загрузить в дисплей 8 собственных символов. Полностью это алфавит не покроет, но хоть что-то.


Как с ними работать, будем смотреть позже. Сейчас нас волнует подключение и протокол.

Подключение дисплея к шине I2C


Но нам вот жалко отдавать 7 ног МК (в 4-битном режиме) на дисплей. И кто-то взял и придумал копеешный модуль, который цепляет дисплей к I2C и сохраняет старый протокол.


Основан он на расширителе портов PCF8574. Вещь простая до безобразия. У него есть 8 ног, на которых мы можем выставлять 0 или 1. По I2C мы тупо шлём один байт на него, где каждый бит соответствует ноге. Либо тупо считываем такой же байт с текущим состоянием этих самых ножек.


Так вот модуль подключен по аналогичной схеме (я реализовывал это у себя на плате года два назад):

STM32 от Булкина. Урок 2: Пишем библиотеку сами для STM32 Stm32, Урок, Длиннопост

Пытливый ум, глядя на эту схему, задастся вопросом: А как же строб выдавать? Да ещё тайминги соблюдать. Да и вообще, как дрыгать ножками RS да R/W, чтоб не мешать данным и не сводить с ума дисплей? А вот тут и начинается самое интересное.


Ход мыслей такой. Давайте сначала заглянем в документацию PCF8574 и поищем там диаграмму по обмену данными. Находим прекрасную картинку:

STM32 от Булкина. Урок 2: Пишем библиотеку сами для STM32 Stm32, Урок, Длиннопост

Внимательно смотрим и видим, что состояние на ногах меняется сразу по окончании приёма байта от МК. Т.е. нам нужно передать данные и выставить ногу P2 в высокий уровень чтобы включить строб. Потом передать данные и выставить P2 уже в ноль, т.е. строб мы выключаем. А для этого нам надо разобраться, что такое шина I2C и с чем её едят.


Шина I2C


Откровенно говоря, не люблю я её. Использую только там, где нет альтернативы. Скорость небольшая, ёмкость линии ограничена 400пФ, в результате длина линии очень маленькая. К тому же сама суть протокола имеет существенный недостаток, об этом позже. Для каждого готового устройства приходится вручную подбирать номиналы подтягивающих резисторов. В этом плане SPI гораздо удобнее и круче, хоть и требует минимум 3-х ног. Ладно, к сути.


I2C - это асимметричная последовательная шина, использует две двунаправленные линии. Т.е. данные передаются последовательно в одном направлении. Обе линии подтянуты к питанию. Шина типа “Ведущий-Ведомый”. Теоретически возможно ситуация, когда хоть все устройства могут быть как ведущим, так и ведомым. На практике реализовать это почти невозможно.


Для понимания работы, надо сначала запомнить правила:


- Данные на линии SDA могут меняться только при низком уровне на линии SCL

- Пока на линии SCL высокий уровень, на линии SDA данные не меняются

- Утрируя, есть три состояния: СТАРТ, СТОП и передача данных.

- Формировать сигналы СТАРТ и СТОП может только ведущий, даже в случае приёма им данных от ведомого

- Адрес ведомого устройства состоит из 7-ми бит.


Сигнал СТАРТ - это перевод линии SDA в низкий уровень при высоком уровне линии SCL.


Сигнал СТОП - перевод линии SDA в высокий уровень также при высоком уровне SCL.


Т.о. для начала передачи данных ведомогу, ведущий формирует сигнал СТАРТ. Все ведомые устройства на линии начинают слушать. Затем ведущий выстреливает адрес ведомого, с которым он хочет поговорить и сажает SDA на ноль. Адрес этот, как видно по картинке выше, занимает старшие 7 бит, а последний бит задаёт читаем мы данные или пересылаем. Если устройство на линии есть, оно удержит линию SDA в низком уровне, это значит, что оно готово общаться. Тоже самое и по окончании приёма данных. По окончании передачи ведущий формирует сигнал СТОП.


Вот тут и кроется главная проблема шины I2C. После передачи данных, если ведомый занят, он может продолжать удерживать линию SDA. Ведомый также может удерживать и SCL, если он не успевает обрабатывать данные, т.е. ведомый может снижать скорость передачи данных. По стандарту, устройства должны управлять линиями по схеме Open Drain. И даже если какое-то устройство монопольно займёт линию, другое сможет её сбросить. Теоретически. На практике же, если, например, ведомый подвис и держит линию, а мы поднимаем её на ведущем, оживить ведомого порой можно только reset’ом. Там вообще такие бывают дичайшие комбинации, что однажды даже пришлось прокидывать отдельную линию RESET для ведомых устройств и периодически их дергать.


Итак. Более менее и в общих чертах мы разобрались с I2C. На wiki есть неплохая статья, да и вообще погуглите, шина непростая, я дал лишь общую информацию для понимания вопроса.

Приступаем к написанию библиотеки


Вот и настал момент, когда мы почти готовы написать первые строки кода. Давайте сначала посмотрим, как устроены другие библиотеки. Мы же ленивые и надеемся обойтись малой кровью.


Откроем классическую Arduino LiquidCrystal_I2C. Просто бегло пройдём по ней глазками. Не знаю, как у вас, у меня сразу глаз цепляется за несколько вещей:


- Используются аппаратные задержки

- Куча однотипных функций

- Нет никаких оптимизаций по экономии потребления памяти

- Нет контроля ошибок

- Нет вменяемых комментариев


Если мы просто пороемся на GitHub в поисках библиотек для STM32, почти все они будут на основе этой же LiquidCrystal_I2C. С теми же недостатками. Я не буду глубоко туда влезать, я просто сделаю всё по-своему.


Итак, составим требования к нашей библиотеке:


- Никаких аппаратных задержек

- Использовать DMA для передачи данных

- Минимум функций, максимально выносить всё в #define

- Максимально экономим память

- Каждое обращение к дисплею должно контролироваться


Создаём проект


Для начала надо создать проект. Я уже написал инструкцию, как правильно настроить STM32CubeMX у себя в блоге, не буду повторяться тут. Полностью проект с уроком доступен в моем репо на GitHUB.


Отмечу только, что урок написан для отладочной платы на STM32F303VC. У меня сейчас нет под рукой STM32F103C8, так что всё проверял на STM32F3DISCOVERY. Но адаптировать под любую другую плату можно без особых проблем.


Дальше, конечно, мы можете взять готовую библиотеку, я её выложил на GitHub. Я вкратце напишу, что я делал.


Создадим два файла:

Inc/lcd_hd44780_i2c.h
Src/lcd_hd44780_i2c.c

Для начала написания кода, нам бы вообще понять, что делать в реальности. Для этого нам надо сделать две вещи: включить дисплей и послать на него пару символов. Открываем даташит дисплея, ищем описание процедуры инициализации.

STM32 от Булкина. Урок 2: Пишем библиотеку сами для STM32 Stm32, Урок, Длиннопост

Отлично! Всё написано по шагам, с таймингами и даже биты указаны! Но мы любопытные и хотим сразу знать, что же битики значат, чтобы сразу заполнить заголовочный файл #define'ами. Вспоминаем про "Table 6: Instructions". Там прям идеально, с комментариями, расписаны все биты команд.


Открываем наш заголовочный файл и предварительно накидываем:

STM32 от Булкина. Урок 2: Пишем библиотеку сами для STM32 Stm32, Урок, Длиннопост

Это та самая нудная часть работы, о которой я говорил. Внимательно смотрим в табличку, двоичный код переводим в HEX. Поясню на примере:


Инструкция Display on/off control требует всегда выставленного бита DB3. Открываем калькулятор, вводим двоичное 1000 и получаем 0x08 HEX.


В самой инструкции есть три команды:


- Display on/off

- Cursor on/off

- Blinking of cursor position character


Калькулятором высчитываем их HEX и будем их потом суммировать с LCD_BIT_DISPLAY_CONTROL.


Биты RS, RW, E и Backlight относятся к PCF8574, так что не забываем прописать и их.


Позже аналогичным способом напишем и остальные #define.


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


Но теперь мы задумались и пришли к выводу, что нам нужно где-то хранить те параметры, что мы уже отправляли на дисплей. Также надо хранить данные шины, параметры дисплея и прочее. Для этого мы создадим структуру:

STM32 от Булкина. Урок 2: Пишем библиотеку сами для STM32 Stm32, Урок, Длиннопост

Обратите внимание. В этом struct мы храним не саму структуру для I2C, а лишь указатель. Т.о. мы не дублируем данные и всегда под рукой их состояние.


Судя по алгоритму инициализации, первые этапы уникальны и можно реализовать их тупо отправляя данные через базовые функции HAL. Их мы реализуем в функции lcdInit().


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


Посмотрите реализацию в уже готовой библиотеке. В чём фишка. Для того, чтобы выдавать строб, мы дважды шлём первую партию 4-х бит. Третьим байтом шлём младшие 4-бит и закрываем строб.


И вот, что получается на деле:

STM32 от Булкина. Урок 2: Пишем библиотеку сами для STM32 Stm32, Урок, Длиннопост

При таком раскладе и скорости шины I2C в 100кбит, ширина строба ~180мкс, пауза между стробами ~90мкс, и пауза между парными стробами ~530мкс. По идее, и я так думал предварительно, можно не удлинять строб на два байта, обойтись одним. Но на деле оказалось, что 90мкс мало для ширины строба, но достаточно для паузы между стробами. Похоже, что кварц в дисплее работает на более низкой частоте, чем положено по даташиту. Как говорил - Китай такой Китай =( А может мой дисплей дурит.


Также можно сократить длинную паузу раза в два, для этого есть два способа:


- Использовать прерывания и циклом фигачить побайтово прямо в регистр. Но это постоянные прерывания с обработчиками, на больших данных будут блокировки. А я этого ой как не люблю. Я предпочитаю отправить данные через DMA и забыть о них. И начать заниматься другими делами, пусть МК сам разруливает.


- Либо создать большущий буфер на отправку, для 20 символьного дисплея это будет порядка 120 байт. Надо будет просто подготовить данные в буфере и отправить одним выстрелом в DMA. Но я решил экономить память.


Но нас интересует вопрос, я так ругал Ардуиновскую библиотеку, а есть ли выигрыш? А вот смотрите, что показывает LiquidCrystal_I2C:

STM32 от Булкина. Урок 2: Пишем библиотеку сами для STM32 Stm32, Урок, Длиннопост

Комментарии излишни. Но ведь я учу вас критическому мышлению, не так ли? Что если оптимизировать код библиотеки Ардуино? Да! И я уверен, получится значительно улучшить параметры передачи. Делайте, думаю стотыщпятьсот людей вам скажут спасибо. Ведь я к чему это всё говорю. К тому, что в этом и есть беда Ардуино - такой вот код, где никто не думает об оптимизациях. Причём ведь делает вид, что всё согласно даташиту. Например, зачем нужны задержки между передачами в 50мкс, если в реальности между стробами 500мкс??


У пытливого ума опять же возникает вопрос, а есть выигрыш на большой передаче? А вот смотрите, сверху STM32, а снизу LiquidCrystal_I2C, данные одинаковые, процедура инициализации тоже:

STM32 от Булкина. Урок 2: Пишем библиотеку сами для STM32 Stm32, Урок, Длиннопост
STM32 от Булкина. Урок 2: Пишем библиотеку сами для STM32 Stm32, Урок, Длиннопост

Итог: STM32 83мс, LiquidCrystal_I2C 122мс. Повторю, если использовать прерывания или готовый буфер вместо чистого DMA, можно получить ещё больший выигрыш, думаю вполне реально сократить это время до 60мс. Но надо ли? С таким дисплеем и его откликом это уже за гранью добра и зла =)


Что ещё интересного в библиотеке


Я написал одну единственную функцию, которая занимается командами. Это функция lcdCommand().


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


Обратите внимание, никаких if/else. Всё сделано на Switch/Case. Несмотря на то, что их аж три штуки и приходится как минимум дважды проверять команду, работает это невероятно быстро. И причина тому - Бинарное дерево, в которое компилятор транслирует наш код. По сути, там всего два узла, так что поиск происходит за несколько тактов.


Конечно, вы можете использовать и запись типа if (command == LCD_DISPLAY), это также будет откомпилировано в бинарное дерево, но такой код читается хуже.


В результате мы получили возможность через #define определить прототипы функций, с коротким написанием и удобным чтением:

STM32 от Булкина. Урок 2: Пишем библиотеку сами для STM32 Stm32, Урок, Длиннопост

А вообще, совет. Там, где у вас чётко обозначенные варианты, использовать switch/case, там, где необходимо сравнивать величины, использовать if/else. И не стесняйтесь нумерованных списков enum - они занимают очень мало памяти. Компилятор сам подбирает тип, но всё также, как с обычными целочисленными переменными, чем больше список, тем больше разрядность.


Почему не проверяем готовность дисплея, как в даташите


А потому, мои дорогие, что в случае с I2C это лишено смысла. Посмотрите на реальную передачу. На один только запрос уходит минимум 1 байт плюс ещё байт на адрес. Итого 180мкс. Для проверки готовности мы сначала должны выставить R/W в 1, потом еще щелкать стробами и внутри 1-го строба проверять бит BF на ноге DB7. Посчитали? Это при том, что по документации занят дисплей от 37мкс до 1,52мс. Проще просто использовать трюк с I2C.


Что можно придумать с русскими символами


У нас есть только возможность загрузить своих 8 символов. Я с этим сталкивался и, скажу, это нелегкий выбор =) Для этого в дисплее есть доступный EPROM на 8 ячеек. Каждая в каждую ячейку можно записать символ из 8 строк по 5 точек в каждой. Соответственно, это массив из 8 байт, где младшие 5 бит и есть наши точки. На самом деле, последняя строка - это курсор, так что, если уж соответсвовать стандартам, на символ можно использовать 5х7 точек. Вот схема из даташита (Example of Correspondence between EPROM Address Data and Character Pattern (5 × 8 Dots)):

STM32 от Булкина. Урок 2: Пишем библиотеку сами для STM32 Stm32, Урок, Длиннопост

Например, символ Д в HEX будет такой:

uint8_t symD[8] = { 0x07, 0x09, 0x09, 0x09, 0x09, 0x1F, 0x11 }; // Д

Соответственно загружаем его в CGRAM функцией:

lcdLoadCustomChar(0, &symD);

и выводим функцией:

lcdPrintChar(0);



Ну а как просто вывести текст?


Это элементарно. Нужно просто выставить курсор и отправить код символа в дисплей. Он сдвинет курсор на следующую позицию автоматически, а мы следом шлём следующий символ. И т.д.


Код символа в C/С++ определяется, если взять его в одиночные кавычки, например, 'B'. Либо просто перебором берём из строки &data[i]. Реализацию можете посмотреть в исходнике.


В готовом виде это:

STM32 от Булкина. Урок 2: Пишем библиотеку сами для STM32 Stm32, Урок, Длиннопост

Обратите внимание. Мы отправляем в функцию не строку, а указатель на массив uint8_t. Т.е. мы, во-первых, создаём строку в памяти, во-вторых, преобразуем строку в unsigned int, в-третьих, отправляем указатель на неё. Это, конечно, вариант для примера. В боевых устройствах использовать такую запись плохой тон. Т.к. во-первых, мы используем динамическое выделение памяти, что само по себе в условиях крайне её ограниченности не айс. Лучше стараться заранее выделить память под некоторые переменные. А во-вторых, приходится вручную пересчитывать размер строки. Так что хорошим тоном будет примерно так:

STM32 от Булкина. Урок 2: Пишем библиотеку сами для STM32 Stm32, Урок, Длиннопост

Немного о комментариях в коде


Призываю не слушать тех, кто заявляет, что очевидный код не нуждается в комментировании. В этом есть здравое зерно, правда есть несколько суровых НО.


Конечно, глупо комментировать каждую строчку. Но хорошим тоном, по моему опыту, являются:


Перед каждой функцией писать стандартный заголовок с тегами brief и note. В них стоит описать что это за функция и как она работает. Там же дать описания переменных и что она возвращает. Во многих современных редакторах есть плагин типа Docblockr. Просто перед функцией пишете /** и плагин сам создаёт отформатированный заголовок, вам нужно только дописать ручками несколько строк.

Давать отсылки на переменные из других файлов и документацию

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

Добавляйте комменты для выделения этапов и всяких неочевидных вещей

Я сейчас дописываю документацию к библиотеке, читать её можно будет тут.


Напоследок


Невозможно описать и зацепить все моменты по такой теме. Честно говоря, когда я замахнулся, думал будет проще. Но вот писал статью полторы недели и всё ещё не чувствую её законченной.


Я постарался заострить внимание на ключевых моментах. Параллельно показать какие-то банальные фишки, которые многие боятся использовать. Например, указатели.


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

Показать полностью 15

STM32 от Булкина. Atmega и Arduino vs STM32 и HAL

Долго думал над содержанием, но всё-таки решил написать статью-сравнение Atmega vs STM32 и немного пройтись по Arduino vs HAL.


Предыдущие статьи:


Настройка Sublime Text 3, SW4 и STM32CubeMX для разработки STM32 под Windows 10

Настройка Sublime Text 3, SW4 и STM32CubeMX для разработки STM32 под Linux

STM32 от Булкина. Урок 1: Вводный, где мы немножко похулиганим


Вступление


Давайте немного определимся с понятиями и что же мы будем сравнивать.


Для начала зададимся вопросом, а корректно ли сравнивать 8-битную архитектуру МК Atmega/ATtiny и 32-битную ARM STM32?


Собственно, в этой статье я обсуждаю преимущества, которая даёт 32-битная архитектура в целом, а также преимущества МК STM32 относительно МК Atmega/ATtiny в частности. Вопрос из той же оперы, как стоит ли переходить с процессоров i486 на i7.


Я сам занимаюсь автоматикой. Так что и вижу я картину с точки зрения автоматики, в основном промышленной.


Немного теории о 8 битах


Часто сталкивался с заблуждением, что программа на 8-ми битных МК оперирует только 8-ми битными данными, потому смысла в переходе на 32-битные МК нет. На самом деле, например, простые целочисленные данные и указатели в 8-ми битных МК являются 16-ти битными. Поэтому, утрируя, при работе с такими данными, МК тратит дополнительные такты там, где 32-битное ядро тратит всего один. Плюс для доступа к таким данным 8-ми битный МК производит дополнительные операции чтения/записи и операции со стеком. На деле это дополнительно приводит и к увеличению объема прошивки, и к увеличению потребления памяти.


32-битные же МК могут легко оперировать 8-, 16- и 32-битными данными за такт. Плюс наличие готовых команд для доступа к ним и преобразования, т.н. набор команд Thumb.


А что с производительностью?


Тут можно обратиться к сухим синтетическим тестам, например CoreMark. Он хорош ещё и тем, что даёт показатель CoreMark/MHz. Просто навскидку из таблицы:


- ATmega2560 (на частоте 8МГц): 0.53 CoreMark/MHz

- ATmega644 (на частоте 20МГц): 0.54 CoreMark/MHz

- STM32F103RB (на частоте 72МГц): 1.50 CoreMark/MHz

- STM32F051C8 (на частоте 48МГц): 2.20 CoreMark/MHz


Ещё раз подчеркиваю, это показатель производительности на МГц частоты. Общая производительность вообще разгромная:


- ATmega2560 (на частоте 8МГц): 4.25 CoreMark

- ATmega644 (на частоте 20МГц): 10.21 CoreMark

- STM32F103RB (на частоте 72МГц): 108.26 CoreMark

- STM32F051C8 (на частоте 48МГц): 105.61 CoreMark


Я привёл примеры наиболее используемых МК из готовой таблицы.


Если ещё коснуться ARM, то они имеют набор команд Thumb, которые позволяют делать, например, множественные пересылки данных одной командой.


Давайте сюда ещё прибавим модуль FPU, который есть на всех STM32 начиная с серий F3xx. Значительно ускоряет вычисления с плавающей точкой. Конечно, можно изгаляться с псевдо-плавающей точкой, типа умножать такие числа на 1000 и считать их целыми. Но на деле это далеко не всегда возможно и удобно.


И ещё потом добавим DMA, который на порядок ускоряет работу с периферией и не только.


Выходит очень вкусно, я считаю.

А что с потреблением?


Тут всё по канонам. В сравнении с 32-бит, 8-битные МК производят в 4 раза больше циклов обращения к памяти и большее количество команд для копирования того же объема данных. Также, например, ARM позволяют выполнять по 2 команды Thumb за такт. У 32-бит меньше работы, меньше потребление.


Если говорить про переход в спящий режим, то у ARM есть фишка - проснулись по прерыванию, отработали его и сразу заснули. С учётом того, что отработает он быстрее, чем AVR 8-бит, потребление будет значительно меньше.


Также это всё значит, что и работаем на пониженном напряжении. Это 3.3В у STM32 против 5В у Atmega. Конечно, у Atmega можно снизить напряжение, но придётся снижать и частоту в разы. Если брать те же 3.3В, то придётся снизить частоту до 10МГц.


Это кстати, ещё преимущество для STM32. Далеко не вся периферия работает на 5В, поэтому приходится ставить дополнительный регулятор напряжения для неё при использовании ATmega/ATtiny.


Хотя, чего греха таить, я сам предпочитаю использовать импульсный регулятор на входе на 4.5-5В и потом опускаю линейником до 3.3В. Это особенно важно там, где используются ADC/DAC.

Ну и не забудем про такую серию у STM32, как Lxxx. Это МК с ультра-низким потреблением. Хотя они дороговаты. Но у них, зато, есть ещё и EEPROM на борту, как у Atmega/ATtiny.

А что с ценой?


Тут вообще момент прекрасный. Если брать прям вот аналогичный в плане ног и периферии STM32, выигрыш значительный. Плюс можно сэкономить на RTC и USB.


Если брать современную серию STM32 на Cortex M4 и Cortex M7, это F3xx и выше, там цена выше, конечно, но и плюшек море.


Замучил уже, сравнивай в таблице!

Я решил разбить сравнение на 4 части:


Микро: ATtiny861A-SU vs STM32F030F4P6

Мини: ATmega328P-AU vs STM32F103C8T6

Средне: ATmega644PA-AU vs STM32F303CBT6

Макси: ATmega2560-16AU vs STM32F405VGT6


Линейка чипов огромная о обоих производителей. Я выбирал такие чипы, которые схожи по ногам, более менее по памяти и периферии. В каждом пункте ниже дам немного описаний, почему и как.
Я намеренно не сравниваю отладочные платы, особенно с Ali. Их вообще надо использовать только для отладки софта и разработки готового устройства. Мы же серьёзные люди, да?
Я не буду брать цены с Ali, только Российские поставщики. Я не буду давать тут рекламу, могу в комментах ответить, где я покупаю. Всегда есть, где подороже, а где подешевле. Нам важны относительные цены. К тому же, через неделю они могут поменяться, все зависит от курса $.

И ещё. Указать корректное количество каналов PWM может быть не везде просто. Поэтому пишу везде приставку “до”. Я считаю количество тех, которые можно вывести всей кучей на разные ноги.


Я везде в STM32 отмечаю наличие CRC32. Это очень важная и нужная фишка. Позволяет считать контрольные суммы налету. Очень нужно, если пишете свой протокол обмена данными, например. Для того же Modbus можно приспособить.


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

Микро: ATtiny861A-SU vs STM32F030F4P6


Собственно решение для минимальных задач. Выбирал МК по доступности, количеству ног ну и более-менее нормальной периферии.

STM32 от Булкина. Atmega и Arduino vs STM32 и HAL Stm32, Atmega, Attiny, Arduino, Длиннопост

Слева ATtiny, справа STM32. Разница в размерах впечатляет, особенно как узнаешь возможности этой финтифлюшки.

STM32 от Булкина. Atmega и Arduino vs STM32 и HAL Stm32, Atmega, Attiny, Arduino, Длиннопост

Мини: ATmega328P-AU vs STM32F103C8T6

STM32 от Булкина. Atmega и Arduino vs STM32 и HAL Stm32, Atmega, Attiny, Arduino, Длиннопост

Слева ATmega, справа STM32. При схожих размерах, ног у STM32 больше.

STM32 от Булкина. Atmega и Arduino vs STM32 и HAL Stm32, Atmega, Attiny, Arduino, Длиннопост

Средне: ATmega644PA-AU vs STM32F303CBT6


По опыту прошлой разработки знаю, что первым делом, когда 328-й уже не хватает, но 2560 ещё как-то слишком, ATmega644 лучший вариант. 44 ноги, периферия побогаче, памяти побольше и стоит по-божески. Думал включить сюда ATmega1284, но стоит у нас непотребных денег, решил всё-таки учесть цену.


Относительно STM32F303CB стоит заметить, что это очень сбалансированный чип по всем параметрам. Богатая периферия, много памяти, нормальная цена. Есть FPU, аппаратная поддержка RS485 (умеет аппаратно дёргать ногой направления передачи данных) и куча других плюшек.

STM32 от Булкина. Atmega и Arduino vs STM32 и HAL Stm32, Atmega, Attiny, Arduino, Длиннопост

Слева ATmega, справа STM32. При сравнимом количестве ног, размер у STM32 меньше.

STM32 от Булкина. Atmega и Arduino vs STM32 и HAL Stm32, Atmega, Attiny, Arduino, Длиннопост

Макси: ATmega2560-16AU vs STM32F405VGT6


Ну выбор МК от AVR в этой категории очевиден. STM32F405 выбрал также из-за его сбалансированности. А ещё вкусной цене при таких-то характеристиках.

STM32 от Булкина. Atmega и Arduino vs STM32 и HAL Stm32, Atmega, Attiny, Arduino, Длиннопост

Выводы


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


Где-то года полтора назад я сам наткнулся на подобное сравнение и был ошарашен. К тому моменту уже больше года у меня было несколько отладочных плат на STM32 и я всё никак не мог к ним подступиться. Но тогда твёрдо решил добить. Отложил дела и потратил месяц на изучение. Через вопли, бури возмущения, сопли и ярость. А теперь не понимаю, как я раньше жил на Atmega’х и Arduino.


Ладно. Хочу отметить некоторые вещи, которые здорово влияют на выбор с обеих сторон.


Плюсы Arduino и вообще.


Конечно же сама экосистема. Огромная база знаний, огромное коммьюнити.

Библиотеки есть подо всё, прям вообще.

Доступность шилдов подо всё и вся.

Чрезвычайно низкий порог вхождения, вот для любого.

На борту есть EEPROM, это очень удобно и круто.

Отдельно стоит отметить, что даже без Arduino программировать под Atmel довольно легко. Библиотеки, Atmel Studio и прочее.


Но есть и глобальные недостатки.


Из-за того же простого порога вхождения, качество библиотек в подавляющей своей массе просто ужасное. Я б даже сказал, отвратительное.

На Arduino нет нормальной отладки. Serial.print() - это нефига не отладка.

С Atmega никогда не получишь нормальной производительности. Нормального планировщика не воткнёшь. Они есть, конечно, даже FreeRTOS можно воткнуть, но памяти и так мало, а планировщики очень голодные. Потому не сделаешь нормальный интерфейс с хорошим откликом, не сделаешь контроллер с сотней прерываний и несколькими десятками устройств на периферии.

Куча народу (не все, конечно) возомнили себя крутыми спецами и штампуют дерьмо на отладочных платах и шилдах. Частенько промышленное дерьмо. Это, у меня лично, вызывает дикое негодование.

Сама по себе платформа, не смотря даже на то, что и STM32 тоже может работать с Arduino, подразумевает усреднение. Отсюда даже на нормальных чипах ты получаешь кастрата. И по-любому приходится лезть в дебри. Ну и в чём смысл тогда?

Если касаться Atmel Studio - это тяжелейший монстр, который даже на моем i5 с 24Gb и SSD тормозит так, как Quake на 486-м.


А что сказать хорошего про STM32?


Платформа изначально очень производительная. Как я писал выше, нет кучи недостатков 8-битных МК.

У тебя всегда изначально куча периферии. И ты выбираешь, на какие ноги её вешать и плату разводишь, как тебе удобно. А МК уже конфигурируешь исходя из этого.

Из неочевидного, например, на любую ногу можно сделать как PullUP, так и PullDown. А это очень облегчает проектировку плат, поверьте.

HAL, на самом деле, очень мощный инструмент. Хотя некоторые его хают за громоздкость, но на деле это в основном набор готовых #define, которые сильно облегчают написание и чтение кода. И переносимость!

Отладка практически на любом инструменте, почти в любой среде работает на ура из коробки. А это в любой момент все переменные, как на ладони. И точки, и даже графики. Я вообще не пользуюсь ничем, что выводило бы данные в консоль. Зачем? Тратить время на написание этих шаблонов, которые потом вычищать из продакшена?

STM32CubeMX вообще панацея. За пару минут переносится код на почти любой другой STM32. Что-то поменял? Нет проблем, галочки расставил, пересобрал проект и всё!

Тот же SPI на F405 можно запустить на 41Мбит! Я просто EEPROM на SPI пользую на 21Мбит. А ещё прибавьте к нему DMA и вообще красота! Летает!

А наличие USB и RTC почти во всех STM32?


Ладно, плюсами можно до бесконечности. Что из минусов есть:


Довольно трудный вход. Разобраться сходу не получится, нужно иметь базис.

Библиотек в свободном доступе не то чтобы нет. Есть и много. Но они либо под устаревший StdPerif, либо заточены под конкретного человека и его собственный набор библиотек. Либо и то, и другое сразу. Так, чтобы почти без доработки большая редкость. К сожалению, сложно абстрагировать библиотеку в STM32, они часто повязаны друг с другом и заточены подо что-то конкретное

Так что да, вам придётся писать свои библиотеки довольно часто. Даже под элементарные вещи вроде LCD1602

Вас будет бесить написание HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, GPIO_PIN_SET) в сравнении с digitaWrite(LED1, HIGH). Вас будет бесить, что вы должны ВСЕГДА указывать размер буфера приёма. Ведь какая красота в Arduino Serial.available()! Нет, в STM32 мы тоже можете сделать подобное, но придётся взрыть тонны документации, чтоб понять некоторые неочевидные, но элементарные вещи.

Вас будет бесить переход к C99 после C++, но потом даже будете этому рады.

Вас будет бесить объем и количество документации по STM32. Но потом вы проникнетесь и увидите лаконичность и очень грамотную подачу относительно документации Atmel.

На борту нет EEPROM, кроме серии STM32Lxxxx, которая дорогая, как изумруд.


Стоит ещё отметить такую штуку, как Mbed. Довольно крутая вещь для IoT. Большое коммьюнити, мощная поддержка. Куча библиотек для всего. Хотя для моих задач не очень подходит. Посмотрите, если в чистом виде STM32 пугает. STM выпускает платы Nucleo под эту платформу. Так что есть готовые решения, есть =)


Ладно. Всего не отметишь. Обо всём не расскажешь. Каждый должен сам решить, стоит ли. Я вот прошел этот рубеж и безумно этому рад. Я не пошёл по простому пути Arduino -> RPi и в результате имею сейчас гораздо более мощные инструменты. Конечно, одноплатки нужны и они крутые. Туда и Linux можно накатить, и сервачок поднять с БД. Но это другая опера.


На сегодня всё, удачи!

Показать полностью 7

STM32 от Булкина. Урок 1: Вводный, где мы немножко похулиганим.

Как и обещал, начинаю тему про STM32. Данный пост вводный, я расскажу о настройке рабочей среды, немножко поморгаем светодиодами, всковырнём (чуть-чуть) FreeRTOS. Ну а в следующей статье я сравню STM32 и Atmega, посмотрим, зачем вообще нам нужны ARM.


Статья рассчитана на тех, кто давно ходит вокруг да около STM32, но не знает, с какого бока подступиться. Некоторые моменты могут показаться сложными на первый взгляд, но надо поработать мозгами, уж простите =) Стоит только понять некоторые основополагающие вещи, как наступит просветление, уверяю вас!


Внимание! Много текста и картинок!


1. Макетная плата


Для Пикабу я буду адаптировать статьи под обычную и дешёвую плату на STM32F103C8T6, например такую:

STM32 от Булкина. Урок 1: Вводный, где мы немножко похулиганим. Stm32, Stm32f103, Freertos, Урок, Длиннопост

Их полно на Али, стоят около 120 рублей, можно заказывать пачками. Я заказал себе штук пять вариаций. По их приезду буду адаптировать больше своих статей сюда. У неё на борту 64-Кбайт Flash и 20-КБайт RAM. Вообще, чип довольно попсовый. Таймеров всего 4 штуки, периферия хиленькая. Но он стоит копейки, частота 72МГц, много оперативы, а значит можно неплохо развернуть FreeRTOS.


Также на Хабре и у себя в блоге я публикую статьи для оригинальной макетки STM32F3DISCOVERY, она основана на МК STM32F303VCT6 c 256-Кбайт Flash и 48-КБайт RAM в корпусе LQFP100. С ней гораздо интереснее работать.


Также вам понадобится программатор ST-Link, их также полно на Али, стоят от 150 руб с доставкой.


2. Среда разработки


Корпел несколько дней и родил аж две огромные статьи по настройке среды разработки под Linux Ubuntu 16.04 и MS Windows 10. Ниже я покажу, как настроить проект под нашу макетную плату и как подключить к ней светодиоды и кнопку.


Настройка Sublime Text 3, SW4 и STM32CubeMX для разработки STM32 под Windows 10

Настройка Sublime Text 3, SW4 и STM32CubeMX для разработки STM32 под Linux


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


Также я буду приводить все примеры для SW4. Если вы хотите работать под Keil uVision - нет проблем. Я в другой статье напишу, как он устроен и какой у него крутой дебаггер, если доступные статьи вам не нравятся (пишите в комментах).



Ну ладно. приступим!


Подключать будем по такой схеме (RESET и BOOT0/BOOT1 нарисовал до кучи)

STM32 от Булкина. Урок 1: Вводный, где мы немножко похулиганим. Stm32, Stm32f103, Freertos, Урок, Длиннопост

Я считаю с этого места, что вы настроили среду разработки.


Для начала надо подключить ST-Link к нашему контроллеру. Делаем по схеме (слева программатор, справа контроллер):


SWDIO -> IO (или пин PA13)

SWCLK -> CLK (или пин PA14)

3.3V -> V3

GND -> G


Открываем STM32CubeMX и устанавливаем библиотеки для STM32F1 Help->Install New Libriaries, ставим галку Firmware Package for Family STM32F1, жмём Install Now:

STM32 от Булкина. Урок 1: Вводный, где мы немножко похулиганим. Stm32, Stm32f103, Freertos, Урок, Длиннопост

Жмем New Project, в поле Part Number Search пишем STM32F103C8:

STM32 от Булкина. Урок 1: Вводный, где мы немножко похулиганим. Stm32, Stm32f103, Freertos, Урок, Длиннопост

Щёлкаем два раза на чипе в нижней части экрана и попадаем в окно настройки.

Сначала настроим основные параметры.

- Включим FreeRTOS

- Включим резонатор на плате

- Затактируем системный таймер от TIM4

- Включим дебаг

- Включим RTC

STM32 от Булкина. Урок 1: Вводный, где мы немножко похулиганим. Stm32, Stm32f103, Freertos, Урок, Длиннопост

Теперь подключим кнопку и два светодиода:

- Щелчок на PA0 -> GPIO_EXTI0. Правый щелчок на PA0 -> Enter User Label -> BUTTON. Обратите внимание, мы подключаем кнопку на прерывание EXT0.

STM32 от Булкина. Урок 1: Вводный, где мы немножко похулиганим. Stm32, Stm32f103, Freertos, Урок, Длиннопост
STM32 от Булкина. Урок 1: Вводный, где мы немножко похулиганим. Stm32, Stm32f103, Freertos, Урок, Длиннопост

- Аналогично щелкаем на PB0 и PB1, только выбираем GPIO_Output и называем LED1 и LED2:

STM32 от Булкина. Урок 1: Вводный, где мы немножко похулиганим. Stm32, Stm32f103, Freertos, Урок, Длиннопост

В результате получим такую распиновку:

STM32 от Булкина. Урок 1: Вводный, где мы немножко похулиганим. Stm32, Stm32f103, Freertos, Урок, Длиннопост

Откроем вкладку Clock Configuration.

- Отмечаем, что тактируемся от HSE и ставим частоту системной шины 72МГц:

STM32 от Булкина. Урок 1: Вводный, где мы немножко похулиганим. Stm32, Stm32f103, Freertos, Урок, Длиннопост

Переходим во вкладку Configuration.


1. Настроим Кнопку. Жмём GPIO, выбираем кнопку и ставим сработку прерывания по обоим фронтам импульса, а также подтянем линию к питанию.

STM32 от Булкина. Урок 1: Вводный, где мы немножко похулиганим. Stm32, Stm32f103, Freertos, Урок, Длиннопост

2. Включим прерывание на кнопку. Жмём NVIC и в строке EXTI line0 interrupt ставим обе галки

STM32 от Булкина. Урок 1: Вводный, где мы немножко похулиганим. Stm32, Stm32f103, Freertos, Урок, Длиннопост

3. Настроим FreeRTOS

Жмём на FreeRTOS, во вкладке Config parameters выставляем TOTAL_HEAP_SIZE 4096 (это сколько памяти мы резервируем для всего FreeRTOS в целом)

STM32 от Булкина. Урок 1: Вводный, где мы немножко похулиганим. Stm32, Stm32f103, Freertos, Урок, Длиннопост

Во вкладке Task and Queues добавляем три задачи:

- Task Name: buttonPress, Priority: osPriorityNormal, Entry Function: StartButtonTask

- Task Name: Led1, Priority: osPriorityNormal, Entry Function: StartLed1Task

- Task Name: Led2, Priority: osPriorityNormal, Entry Function: StartLed2Task

STM32 от Булкина. Урок 1: Вводный, где мы немножко похулиганим. Stm32, Stm32f103, Freertos, Урок, Длиннопост

Во вкладке Timers and Semaphores добавим семафор, за который будут драться светодиоды:

STM32 от Булкина. Урок 1: Вводный, где мы немножко похулиганим. Stm32, Stm32f103, Freertos, Урок, Длиннопост

Включим функцию vTaskDelayUntill во вкладке Include parameters:

STM32 от Булкина. Урок 1: Вводный, где мы немножко похулиганим. Stm32, Stm32f103, Freertos, Урок, Длиннопост

Теперь укажем параметры проекта в Project->Settings из верхнего меню.


Указываем имя проекта в поле Project Name: PikabuLes1

Указываем путь в поле Project Location: ВАШ ПУТЬ, ГДЕ ХРАНИТЕ ПРОЕКТЫ

Выбираем Toolchain: SW4STM32

Не забываем во вкладке Code Generator включить “Add necessary libriary files as reference in the toolchain project configuration file”


Генерируем проект:

STM32 от Булкина. Урок 1: Вводный, где мы немножко похулиганим. Stm32, Stm32f103, Freertos, Урок, Длиннопост

Дальше, чтоб не выкладывать тут простыни кода, вы можете заменить три файла на аналогичные с моего репозитория на GitHub:


Inc/main.h -> меняем на этот

Src/main.c -> меняем на этот

Src/stm32f1xx_it.c -> меняем на этот


И для корректного автодополнения кода в ST3 в корень проекта закинуть CMakeLists.txt (если у вас Linux) либо сформировать правильный .clang_complete (если Windows), как я писал в статье.


Загружаем и запускаем так, как написано в той же статье.


Можете и тупо клонировать репо, инструкцию выше я давал для понимания, как это делается.


Теперь расскажу, как это всё работает.


Суть всего процесса - это планировщик задач FreeRTOS. У нас есть три задачи:

- ButtonTask: Занимается обработкой нажатий нашей кнопки

- Led1Task и Led2Task: занимаются светодиодами LED1 и LED2.


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


Итак. При старте семафор свободен, состояние кнопки неизвестно. Кому повезёт, тот и хватает семафор функцией xSemaphoreTake. Соответственно задачи Led1Task или Led2Task ждут, когда семафор освободится.


Если нажимается кнопка, то задача ButtonTask ждёт, когда ей отдадут семафор. Когда она его получает, зажигает оба светодиода и держит семафор, пока не отпустить кнопку.


Дальше. Нажатия кнопки отбиваются прерыванием в Src/stm32f1xx_it.c в колбэке EXTI0_IRQHandler(). Самое главное вот в чём:

- Срабатывает прерывание.

- Мы проверяем, что сработка была более 50мсек от предыдущего срабатывания (простая защита от дребезга)

- Проверяем состояние линии: нажата или отпущена кнопка

- Уведомляем задачу ButtonTask об изменившемся состоянии кнопки

- Задача ButtonTask в зависимости от состояния кнопки пытается перехватить семафор или наоборот отдаёт его.


Вообще, с бинарными семафорами надо быть ОЧЕНЬ аккуратными. Это опасная штука и надо стараться обходиться без них. Хотя в некоторых задачах они необходимы. Например, если несколько задач используют одну шину для передачи данных. Но надо всегда держать в голове, что категорически нельзя глушить задачи, которые имеют доступ к семафору, иначе можно повесить всё наглухо.

Так, на этом всё на сегодня. Это вводная статья и тут куча моментов, на которых стоит остановиться подробнее. Об этом другой раз. Ну или пишите в комментах.


P.S. Баянометр ругается, но совпадений точно нет, контент на 100% уникальный.

Показать полностью 17

Сделать подсветку синтаксиса языков программирования

Я ужаснулся, когда оказалось, что на Пикабу нет подсветки синтаксиса. Посмотрел на то, как другие выкладывают статьи по программированию и волосы дыбом. Ну нельзя так!


Посмотрите, как выглядит это сейчас, например, в "Лиге программистов C/C++":

Сделать подсветку синтаксиса языков программирования Языки программирования, Синтаксис, Хотелки

А вот как он бы выглядел с нормальной подсветкой:

Сделать подсветку синтаксиса языков программирования Языки программирования, Синтаксис, Хотелки

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


Сейчас люди либо выкладывают код в "цитату", либо дают ссылки на ресурсы типа GitHubGist, либо, что чаще всего, выкладывают скриншоты. Что людям делать со скриншотами? Перепечатывать? От этого читаемость поста резко снижается.


В результате, банально не хочется писать такой материал. Хотя на Пикабу очень много заинтересованной публики.


Я понимаю, задача непростая, но пора бы задуматься. Спасибо за внимание!

Показать полностью 1

Темы будущих уроков по STM32

На волне вчерашнего поста https://pikabu.ru/story/18_podrobneyshikh_urokov_po_programm...


Есть идеи по написанию уроков по различным темам в разрезе STM32. Приглашаю @DmitryAR, @witiliar, @XanderEVG, @Arimf, @Alexey9, @slonofil, и @AlexGyver к обсуждению. Сам я занимаюсь разработкой и проектированием автоматики для отопительных систем на биотопливе, готов говорить в этом разрезе.


Собственно не вижу смысла говорить об основах языка, вроде типов данных. @AlexGyver это уже осветил. Но может стоит это преподнести в разрезе C99, а не C++?


Вот темы, которые я бы мог осветить, по разделам:


Основы программирования в разрезе C99 и STM32:

- #define: хитрости и приёмы

- SWITCH/CASE или IF/ELSE: когда и где применять

- Битовые операции: хитрости и приёмы


Фишки в разрезе STM32:

- FreeRTOS: планировщик, семафоры, стэки

- CubeMX и HAL: как сохранить переносимость кода, как искать нужные функции, где искать примеры и прочее

- Настройка таймеров, их различия, где искать информацию в документации по их параметрам

- RTC

- ADC и DAC

- Обработчик ошибок с задержками с использованием FreeRTOS (собственная библиотека)

- Простая Round Robin База данных (собственная библиотека)



Среда программирования и аппаратная отладка:

- Настройка собственной среды под Linux и Windows

- Настройка Sublime Text, System Workbench for STM32, KEIL

- Отдельно по KEIL: стилизация под Monokai, дебагинг, трэйсинг, настройка компилятора

- Логический анализатор (могу рассказать про Saleae Logic)


Модули:

- Принципы работы шин I2C, SPI. Их достоинства и недостатки. Различные режимы: Polling, Interrupt, DMA

- Watchdog: IWDG и WWDG - назначение, настройка

- Использование 7-сегментных дисплеев: подключение напрямую к МК и с помощью драйвера MAXIM MAX6950/MAX6951 (собственная библиотека)

- SPI EEPROM STM M95xxx (собственная библиотека)

- I2C расширители портов NXP PCA9671 и PCF8574  (собственная библиотека)


Проектирование схем и хитрости:

- Как правильно разводить резонаторы

- Дребезг кнопок: триггеры Шмитта и RS-триггер

- Защита портов (в разрезе дискретных и аналоговых для токовых петель)

- Импульсные и линейные регуляторы напряжения:  подбор элементной базы, разводка

- Реле: электромагнитные и твердотельные. Схемы подключения и различия использования

- В разрезе твердотельных реле особенно хочу остановиться на снабберных цепях

- Энкодеры

- Токовая петля

- Onewrire

- RS485 и Modbus (может имеет смысл рассмотреть их отдельно). По Modbus могу преподнести материал по адаптации FreeModbus Slave и собственную реализацию Modbus Master с использованием DMA и FreeRTOS

- Подключение датчика температуры PT100 напрямую (без звезды) с использованием ОУ в схеме стабилизации тока

- Фазовое регулирование напряжения: датчик нуля, табличные расчёты, таймеры


Проектирование готовых изделий:

- Проектирование плат в KiCAD: принципы работы, создание деталей, 3D-моделей и прочее

- Проектирование готового изделия в FreeCAD: сборочный чертёж, 3D-модель и т.д.


Отдельно могу поговорить об учёте и хранении радиодеталей, тем более, что использую самописную программу для этого.


Ну и на закуску, вот несколько готовых изделий:

Темы будущих уроков по STM32 Arduino, Программирование, Микроконтроллеры, Stm32, Длиннопост, Ремонт техники
Темы будущих уроков по STM32 Arduino, Программирование, Микроконтроллеры, Stm32, Длиннопост, Ремонт техники
Темы будущих уроков по STM32 Arduino, Программирование, Микроконтроллеры, Stm32, Длиннопост, Ремонт техники
Темы будущих уроков по STM32 Arduino, Программирование, Микроконтроллеры, Stm32, Длиннопост, Ремонт техники
Темы будущих уроков по STM32 Arduino, Программирование, Микроконтроллеры, Stm32, Длиннопост, Ремонт техники
Показать полностью 5

Я бы побоялся пойти к этому врачу

Я бы побоялся пойти к этому врачу Веб-дизайн, Silent Hill, Бред, Идиотизм
Я бы побоялся пойти к этому врачу Веб-дизайн, Silent Hill, Бред, Идиотизм

У меня у одного такие ассоциации? Не понимаю, что за мода такая делать обезличенные аватары.

Показать полностью 1

Как решаются проблемы

Как решаются проблемы Решение проблемы, Комиксы

Честно стырено у жены

О зубочистке и добродетели

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


У многих есть швейцарские ножи Викторинокс. И эти люди знают, какие хорошие в этих ножах пинцет и зубочистка. Ну как хорошие - удобные скорее. Всегда под рукой, да и пинцет хваткий. Потеря пинцета заставила многих взгрустнуть, а некоторых и покупать другой нож, взамен "ущербного". Я являюсь владельцем такого ножа уже больше 20 лет и за все время не потерял ни пинцета, ни зубочистки. Последний нож лежит в кармане с 1998 года. Его мне подарили немцы после выставки Comtek'98, на которой я работал на стенде AMD. Таким образом и пинцет, и зубочистка прослужили мне на момент этой истории 10 лет. Сам нож и пинцет в идеальном состоянии. Зубочистку же за эти годы я сточил аж на 4мм!!


И вот  произошла трагедия - зубочистка сломалась пополам прямо у меня в руках! У меня возникло чувство, будто лишился части тела, честное слово! Но горевал я не долго. Инет рядом, сразу загуглил зубочистку и в первой же строке инет-магазин, который, как показали дальнейшие поиски, единственный торговал зубочистками для ножей Victorinox всего по 5 рублей за штуку.


Конечно, заказывать такую мелочь несколько смешно, но делать нечего. Они также высылали наложным платежом, правда аж рублей за 200, но это мелочь. Потому отправляю им заказ на 5 зубочисток наложным платежом. А в комментарии написал, как долго живу с этим ножом, как стойко моя зубочистка перенесла все трения и как умоляю их сжалиться надо мной :) Заказ оформил на рабочий адрес.


И что вы думаете? Через 10 минут мне звонит менеджер магазина и еле сдерживая смех и утирая слезы говорит, что не будут они высылать такой заказ, им совесть не позволяет :) И говорит, что они все, да и курьер, решили, прочитав мои мольбы, привезти мне эти зубочистки БЕСПЛАТНО :) Т.е. 25 р. за сами зубочистки, но с бесплатной доставкой :) Тем более, что как раз курьер выезжает в мой район :)


Да, через час я нёсся навстречу своему счастью :) Оставил работу, причем меня все поняли и благословили в дорогу. И все по-честному. Курьер меня уже ждал, выдал мне мое богатство. Я, конечно, заплатил "немного" больше 25 рублей и довез его поближе к метро.


Вот так вот. Есть еще добрые люди на свете! И теперь у меня 4 запасных зубочистки. При моем подходе мне их хватит аж на 50 лет :)


Кстати с тех пор, эти 4 зубочистки так и лежат в заветном пакетике.

Показать полностью
Отличная работа, все прочитано!