Статья полный бред несведущего человека. В ней проще указать что правда, потому что всё остальное вымысел и бред. Смешано в одну дурно пахнущую кучу всё, и компилятор, и и рантайм, и типы данных.
Задача компилятора для ПЛК состоит в выгрузке трёх блоков: блок исполняемого кода, блок инициализированных данных и блок информации об объёме требуемой ОЗУ и её разновидностях. Всё. Больше ничего от компилятора не требуется. Разместить в памяти код, выделить ОЗУ и инициализировать его есть задача рантайма. Ничего в этом сложного нет. Задача планирования немного усложняется, кода вы разные POU запускаете на выполнение на разных ядрах, но сути это не менят.
Для иллюстрации бредовых суждений из статьи приведу простой пример. Моя реализация ПЛК, совместимого с FX2N, работает под управлением FreeRTOS. В реализации рантайма возможно динамическое изменение программы пользователя без остановки и перезапуска ПЛК. Эта возможность изначально заложена в фирменные IDE и ПЛК. Скажу по секрету, что реализуется это весьма простыми средствами IDE и ПЛК.
Настоятельно рекомендую PetroBr направить фонтан своей энергии на изучение имеющихся решений в области ПЛКстроения, чтобы не нести в народ чушь, подобную этой статье.
Это пост для предпринимателей, которые периодически спрашивают о деталях моего проекта, буду скидывать его ссылку. И так же пост для всех кто интересуется разработкой. Сам люблю читать подобное. Начинаем.
Лично мое мнение. Компания разработчик ПЛК (или SCADA )без разработки своего компилятора это - разработчик "начального уровня". В таком случае , невозможно делать действительно передовые технологии, контролировать весь процесс, или иметь доступ к мельчайшему поведению программ.
Тут я расскажу, как я делал компилятор, и что выделял в первую очередь работе.
Среда исполнения и компилятор создавался для работы с MCU с 8 килобайт ОЗУ и до 4ГБ.
То есть, чтоб критически слабые системы, имели функциональность топовых ПЛК (горячая замена кода на лету, вытесняющая виртуальная многозадачность, и другое). Другими способами этого добиться, кроме как создавать свой компилятор - нет.
Я не использовал LLVM но использовал правила лексера/парсера библиотеки ANTLR. Сосредоточившись на архитектуре и алгоритмах компилятора касающиеся выполнения программы, а не обработки текстовых символов.
Сделать примитивный компилятор и машину - просто. Множество статей написано про это в интернете. Но что б я выделил в полноценном компиляторе, то есть, который может построить программу любого уровня сложности? В данном случае речь идет не о компиляции в нативный код как после СИ, а в байткод который выполняется рантаймом.
Настоящий компилятор и виртуальная машина.
Я бы выделил два ключевых момента которые нужно реализовать для полноценного компилятора:
1. Менеджер адресации данных.
2. Менеджер адресации инструкций, и управление контекстом.
Менеджер адресации данных.
Я б назвал это самым важным в работе. Любая программа работает с данными.
Если компилятор не игрушечный и не учебный - нужно реализовать поддержку сложных типов данных.
Возьмем простой пример:
INT varA=7;
INT varB=5;
LDR R0 VarA;
LDR R1 VarB;
ADD R0 R1 R0;
По сути это готовая LD математическая инструкция. Вполне можно сделать ПЛК на базе микроконтроллера с ОЗУ даже 2кб для небольшого количества LD инструкицй.
Но, что если пользователь захочет поддержку в ПЛК языка ST или LD и создавать собственные функциональные блоки, а не только стандартные?
Тут не обойтись без поддержки пользовательских данных и структур:
Пример сложных пользовательских типов.
У нас есть сложный тип структуры внутри которого - другие структуры, внутри которых и структуры и массивы и т.д
Теперь, при встрече строки
Equipment sandwikMB670;
Компилятор должен посчитать размер всех данных внутри переменной sandwikMB670 типа Equipment , и выделить под это память. А если в программе встретится строка:
LDW R0 sandwikMB670.states[245].Point.x;
Компилятор должен все просчитать и подставить вместо имени переменной, верный адрес после компиляции:
LDW R0 #200486;
Менеджер адресации и данных должен переварить любой тип данных из "бесконечных" вложений внутри:
кощей.дуб[4][8][2].гнездо[2][5].яйцо[3].игла
А самое главное, алгоритм просчета и управления адресами, должен быть надежным и лаконичным как X^2 , который предсказуемо выдаст те данные которые ожидаешь, и не промахнется ни на байт в сторону среди миллиарда других байт. Только для работы с типами, переменными и их адресами, я завел совершенно отдельный парсер ANTLR и создал библиотеку для этой конкретной задачи независимо от компилятора в целом.
Вторая составляющая компилятора:
Менеджер адресации инструкций, и управление контекстом
Тестовые задачи, для определения эффективности и скорости решения математических или LD инструкций виртуальной машиной.
На изображении - скрин, результат трансляции моей средой 3o|||sheet программ LD / ST в промежуточный виртуальный ассемблер для своей виртуальной машины. ВМ не знает что такое - потоки, функции и прочее, она просто поочередно выполняет все команды. Задача компилятора превратить метки (например BinaryOperaty \ MathOperaty etc...) в адреса переходов. Одни метки - играют роль отдельных потоков, другие метки играют роль - функций программы. Метки которые играют роль независимых задач/ потоков - обрабатывает виртуальная моя ОС 3o|||sheet которая , которая сохраняет адреса, в свой системный массив указателей задач, а при сообщении от физического таймера - прерывает задачу, и достает следующую.
В завершение компилятор переводит объекты инструкций, к бинарному виду типа:
В которых уже закодированы - тип инструкции, номера регистров , разные флаги и даже константы. Интерпретируются эти потоки байт - виртуальной машиной (а не физическим CPU/MCU ).
В итоге
Решив две эти задачи по управлению адресации данных, и менеджер инструкций, (ну и конечно рантайм который это воспроизводит на стороне железа) я создал собственный компилятор который может:
Создавать сложные типы данных
Утрамбовывать в памяти без пробелов
Надежно с ними работать.
Создавать сложные алгоритмы и поведения программы (рекурсии, многоуровневые переходы между функциями, передачи/возврата данных между ними
Реализовав управление контекстом, соответственно - создавать вытесняющую многозадачность , многопоточность, с полной масштабируемостью в многоядерных микроконтроллерах или CPU.
И при этом, легко и безопасно можно менять отдельные участки кода программы на лету.
И даже устанавливать (добавлять) в ПЛК - новые задачи, к уже работающим задачам/программ не останавливая ПЛК физически, как это в операционных системах Windows:
установил приложение, и оно сразу работает, или удалил его (но не злоупотреблять этим конечно, все таки это система для АСУ ТП с детерминированным, строгим по времени исполнением программ. Сборщиков мусора и фоновых задач по фрагментации памяти - нет).
А этого (менять код на лету, или устанавливать новые задачи без перепрошивки) не могут нативные ОС типа FreeRTOS. Так же можно обновлять ОС виртуального уровня - "по воздуху", и менять физические свойства ПЛК, например - включить дополнительный физический аналоговый IO - "по платной подписке" :D , это конечно шутка, но виртуальный уровень полностью может менять - физический если надо, управляя регистрами процессора и периферией.
Конечно, компилятор это еще и анализ самого кода и прочее (оптимизации) , но что касается ПЛК тут можно проще к этому относиться. Я реализовал только - удаление "мертвого кода"( да и то не по умолчанию), и предупреждения об неиспользуемых переменных и ошибках с типами. Чтоб не вышло как в старых версиях ПЛК от Siemense, когда компилятор дооптимизировался до такого что данные читал/записывал неинаисаои места( те самые "промахи" менеджера адресации данных).
Периодически буду рассказывать о других моментах проекта (например как организована виртуальная ОС и исполнение программ).
Не могу сказать на какую аудиторию больше ориентируюсь в данных постах, но скорее всего это будет интересно - разработчикам электронщикам, и предпринимателям в сфере АСУ ТП которые разрабатывают ПЛК и разное программно-аппаратное (они часто пишут). Как показывает практика - меньше всего это понятно АСУ-ТПшникам, что не удивительно так как посты больше о разработке ПЛК как прибора и предпринимательстве, а не о применении ПЛК.
Если коротко, то это аналог Codesys, в несколько скромном виде.
Среда разработки (LD FBD + текстовые типа ST), свой компилятор, и среда выполнения на CPU.
Потенциальному производителю ПЛК осталось разработать железо и скомпилировать среду выполнения под свой CPU/MCU. Один производитель уже разрабатывает железо под своим лейблом, и через полгода мы увидим что вышло.
Хотя со мной связывались так же из - станкостроительного предприятия, на предмет можно ли все это внедрять в станки. Можно.
Тестовое железо:
CPU: STM32F407VG
RAM: 192kb
FLASH: 1mb
168 MHz
Среда и компилятор - 3o|||sheet (Зошит, "Тетрадь") своей разработки
Методика тестирования:
Запускаем программу на LD из 184 блоков.
Замеряем осциллографом реакцию вывода , и считаем время отработки одной инструкции/блока.
Почему LD а не ST:
Очень часто спрашивают. LD - хорошо документирован. Производители ПЛК часто прямо в документации пишут время выполнения базовых LD инструкций, и я могу прямо сравнить “свой” ПЛК с брендом по скорости программ.
Результат тестирования в сравнении с брендами:
Allen Bradley Micro810 - какой в нем CPU неизвестно.
Хотя пост не о китайском МК, но интересен для сравнения результат моей машины на CH32V307 RISC V.
Еще несколько лет назад, когда я начал переносить на микроконтроллеры свой рантайм, я замерял тестовую скорость базовых LD операций, они так и были - 1 микросекунда. Потому у меня было некоторое удивление от STM32F407 (и вообще от всей линейки STM ARM) который был медленнее в два с половиной раза.
В данный момент, могу это объяснить так: у RISC V в два раза больше регистров ядра (16 в ARM против 32 RISC V), это значит что переходы между функциями RISC V может делать быстрее, так как меньше приходится использовать память, а промежуточные результаты хранить непосредственно в регистрах ядра CPU.
Хотя тут еще предстоит более тщательно разобраться, напишу отдельный пост о тестировании RISC V так как по одному такому МК я сотрудничаю с предприятием. Но скорее всего в данной задаче (по крайней мере моя виртуальная машина) и вправду на RISC V в два раза быстрее чем на ARM.
В прошлом посте где я тестировал свой комплекс на STM32F103 Своими разработками, соревнуюсь с Mitsubishi в АСУ ТП. STM32F103 как ПЛК lo , упоминал китайские дешевые ПЛК под среду Mitsubishi .Мне скинули китайскую документацию как сделать ПЛК под среду и компилятор от Mitsubishi. В общих чертах почитал, Оказывается, у меня такая же архитектура что и у Mitsubishi. Но я не делал оптимизацию под ARM и мой ПЛК оказался существенно медленнее. Хотя если брать не китайские и разные любительские ПЛК на Mitsubishi, а оригинальные, то тут Mitsubishi равных нет, они делают свои CPU и аппаратно реализовывают декодирование инструкций и выполнения программ. Мне такой скорости добиться можно наверное если только перенесу виртуальную машину на FPGA, где базовая операция длится - наносекунды.
Что можно выжать из STM32F407 в качестве CPU ПЛК:
ОЗУ больше сотни килобайт, и флэш под мегабайт, соответственно можно писать полноценные большие программы на LD и ST.
Если брать LD то за цикл 1 миллисекунды такой ПЛК отработает чуть больше 400 базовых LD инструкций. Из опыта знаю, ветка горного конвейера, обходилась примерно в 300 LD.
Пид регулятор такого ПЛК успеет отработать за 150 микросекунд вместе с фильтрацией .
Или за 2 миллисекунды еще + 200 LD математических.
(*/+-) на STM32f407 с моим рантаймом - 4.4 микросекунды, на математику. У Siemens S7 1200(CPU 1214C) этот показатель 2.3 микросекудны, а PID регулятор 150-300 микросекунд ( с временем на сетевой обмен). Таким образом, ПЛК на STM32F407 будет уступать S7 1200 не сильно много (я тестировал без учета сети).
Если брать особенность чисто моей архитектуры, то все МК которые имеют ОЗУ больше 16 Кб могут запускать в себе - множественные исполнители:
Код, с операционкой(моей виртуальной имею ввиду операционкой, которую писал), и все что потенциально может вызвать фатальную ошибку и вылет ПЛК - может запустить отдельно, а критический код (безопасность какая) - тоже отдельно. То от чего обычный ПЛК - вылетит, у нас просто заглохнет один исполнитель, в то время как другие продолжат работать.
Как это достигается. Каждый исполнитель, имеет свое виртуальное ОЗУ, что с точки зрения СИ есть - простым массивом байт:
В массиве хранятся плотно утрамбованные, как ОС, так и пользовательская программа, вместе с переменными и стеком. В общем все хранится в отдельном массиве который играет роль ОЗУ.
Виртуальная машина по очереди выполняет instruction каждой ОЗУ(в каждом массиве), и если где то произошла критическая ошибка (повреждение данных, или еще что) просто один исполнитель будет выключен. Как видите , хоть полностью удали данные массива который играет роль ОЗУ это не затронет другие исполнители, и тем более не затронет физический ПЛК.
Тут я ничего принципиально - нового не придумал. Точно так как в операционной системе Windows/Linux/Android - если вылетело какое то приложение, ни ПК ни смартфон от этого не перегружаются и не вылетают.
Но моя заслуга в том что я написал полноценный компилятор, поддерживающий вытесняющую многозадачность, сложную адресацию, и другие сложные , и все это может работать уже на МК с ОЗУ в 16 Кб. Система работает в режиме реального времени, с детерминированным исполнением инструкций, по системному таймеру. В отличии от операционных систем типа Linux/Windows где ОС может приостановить вашу программу, для каких то своих дел.
Следующие тесты буду проводить уже на RISC V микроконтроллерах, и больше буду уделять внимание как это выглядит и работает - физически.
Кому интересно - присоединяйтесь, или пишите на почту
Сделал ПЛК, совместимый с Мицубиси FX2N. С "железом" можно ознакомиться по ссылке в конце поста. Программируется из любой IDE от Мицубиси, поэтому доступны все языки из 61131-3. Реализована бОльшая часть команд из набора оригинального ПЛК. Часть команд реализованы в виде функциональных блоков, чтобы задействовать периферию STM32, часть в процессе реализации. Есть много отличий от оригинала, например, на борту есть Ethernet, EIA-485, CAN. Программирование ПЛК осуществляется через Ethernet. В рантайм встроена поддержка Modbus всех видов и лиц. Для настройки расширенного по сравнению с оригиналом функционала используются конфигурационные файлы, которые доступны через встроенный ftp-сервер. Средний темп исполнения 1000-1200 шагов за 1мс при включенной отладке, опросе слэйвов по Modbus/RTU и опросе самого ПЛК из СКАДА. Код рантайма написан на С++ изначально без привязки к конкретному МК, поэтому может быть перенесён на любой МК, для которого есть FreeRTOS. Была даже сборка по Windows, когда отлаживался протокол между IDE и ПЛК.
Продолжаю тестирование своей разработки (IDE, компилятор, runtime) на разном железе. Сравнивая с ПЛК от Mitsubishi на этом же камне.
В сети давно уже есть тесты с примером использования микроконтроллера STM32F103 в качестве ПЛК. Также продолжается выпуск китайскими компаниями современных ультра дешевых (около 100$) ПЛК на базе этого микроконтроллера с использованием среды разработки от Mitsubishi. Поэтому интересно было и мне попробовать этот чип и сравнить с брендом.
Схема виртуальной памяти машины в режиме вытесняющей многозадачности
Вытесняющее-многозадачный , значит если задача не успела отработать - ошибки не будет(в обычном режиме - будет). Контекст задачи сохранится и наша виртуальная 3o|||sheet OS переключиться на другую задачу. В данном тестовом случае задача не большая, отработать - успеет, и результаты будут корректны.
Алгоритм теста:
Тестовая программа содержит 184 LD, часть из которых истинная, часть ложная. Зная количество истинных , мы знаем количество отработанных команд.
Каждая вкладка в моей среде разработки - новая задача. Это будут вытесняющие задачи с ОС или последовательные задачи без ОС , режим работы сохраняется в настройках проекта.
Компилятор и выполняемая среда данные не кеширует, и работает программа в самом трудозатратном режиме. В конце тестовой задачи устанавливаем/ сбрасываем физический вывод.
Замеряем время осциллографом.
По тестам видно, что мой ПЛК работает в три раза медленнее чем на том же чипе но с средой о Mitsubishi. Почти 9 микросекунд за операцию в моем случае, против 3 микросекунды оппонентов. Да мой МК работал на 64 Мгц (не запустился внешний кварц, дефект платы, а внутренний HSI работал на 64 Мгц, до 72 не настраивался, оставил так) в отличии от 72 Мгц у Mitsubishi, но 10% роли не изменят, можем пренебречь.
Но если б я стремился к быстродействию, я б пошел коротким путем, которым идут как отечественные разработчики ПЛК, так и открытые проекты типа OpenPLC\Beremiz. А именно - простая трансляция LD/ST в текст СИ, и уже СИшным компилятором создавать прошивку.
Я выбрал сложный путь - создание полноценной виртуальной машины с компилятором. Что это дает? Дальше.
Что можно выжать с STM3F103 в качестве ПЛК с моей средой разработки.
1500 LD инструкций + 1500 дополнительно можно подгружать из флеш ( Mitsubishi предлагает 8000, Allen Bradley Micro810 - 2000 LD). Сколько влезет ST строк - трудно сказать, сложно измеряеммый, думаю около 500 -800 строк + стоько же с флэш (имеется ввиду версия МК с флэш 64 КБ. Так как моя версия оказалась - 128 Кб , по крайней мере так указывалось в утилите STLink. С этой версией (128кб) размер программы будет конечно не малым, LD как раз 8000, так и ST.
Критический код, можно отделить от кода с высоким риском фатальной ошибки. Связь, HMI и даже WEB сервер в ПЛК можно вынести - отдельно. А критический отлаженный код, отдельно. Что бы там не произошло в одном исполнителе - фатальная ошибка, никогда не остановит других исполнителей. У них полностью изолированы друг от друга области памяти и адресов. Там где обычный ПЛК бы слетел полностью, тут такого быть не может.
Кроме того, есть и обычные преимущества виртуализации памяти:
в машине с ОС 3o|||sheet - можно добавлять задачи не перезапуская ПЛК физически (как в Windows/Linux - установил, и сразу работает) . Изменение кода задачи ПЛК на лету я уже упоминал.
Все это я продемонстрирую уже на микроконтроллере, о котором много писали СМИ ( тот который на RISC V, 16 KB ОЗУ :) Объективно, среда 3o|||sheet (Зошит) это первый вменяемый и уже существующий инструмент который может превратить такой МК с ограниченными ресурсами в ПЛК причем с топовой функциональностью. На этот раз и вправду - аналоговнет).
Почему я полностью не пишу что имею ввиду - работаю в паре с одним небольшим предприятием по этому конкретному чипу. Если интересно что из этого получилось - присоединяйся, и напишите в комментах что за чип имеется ввиду :)
В Factory I/O построена линия сортировки и сборки с управлением от ПЛК. Изделия перемещаются по цепному конвейеру и проходят через видеодатчик, который выводит цифры от 0 до 9 для определения типа и цвета. Два привода распределяют детали: правый — для крышек, левый — для сырья. Сырье поступает в станок с ЧПУ, который изготавливает основание изделия и укладывает его на поворотный стол. На левых конвейерах крышки останавливаются, когда их определяет видеодатчик. Их цвет сохраняется. Сборочная станция соединяет каждую крышку с основанием только при совпадении цветов. Затем манипулятор поднимает и укладывает готовое изделие.