Краткий тезис повествования

В этой статье я расскажу опыт разработки ведомого устройства для промышленных контроллеров Siemens с протоколом PROFIBUS DP-V0. Реализованный функционал достаточный для разработки простых устройств, но не полон. Статья нацелена на людей, которые знакомы с промэлектроникой и микроэлектроникой. Основная информация была взята с сайта. Если интересно, крути колесо!

PROFIBUS это кто(who)?

PROFIBUS, она же Process Field Bus, она же полевая шина, она же так называемый RS485. Именно так, ничего сверхъестественного. Вообще, RS485 до сих пор является самым популярным физическим интерфейсом передачи данных в промышленности, хоть его и вытесняет стек TCP/IP... В целом, можно выделить несколько фич этого протокола:

  • Циклический обмен данными

  • Отслеживание потери мастера/слейва

  • Скорость до 12 Мбит/с

  • Бродкаст

  • Гибкая конфигурация слейва

На уровне повыше, как и у любого другого RS485, UART с конкретными 8E1 и скоростью от 9600 до 12M. Скорость действительно большая, однако в действительности на такой скорости не часто проектируют технологические линии. Да и немногие микроконтроллеры, на базе которого проектировался слейв, смогут раскачать свой приемопередатчик до такой скорости. Cименс разработал специализированные контроллеры для реализации всего стека PROFIBUS DP, взрослые дядьки делают слейвы на них. А я еще маленький, поэтому пошел более подсанкционным путем.

В деталях

Чтобы заставить устройство работать в сети PROFIBUS, его нужно правильно спараметризировать и сконфигурировать, после чего устройство будет готово к циклическому обмену. В качестве мастера выступает ПЛК, в моем случае это S3xx. Мастеров в шине может быть несколько, право на арбитраж шины передается посредством токена. Ведомых устройств в шине может быть до 127, при этом под мастеров и программатор выделяются первые несколько адресов. Мастер может циклически обмениваться с ведомым устройством, диагностировать его, а также параметризировать и конфигурировать. Помимо этого есть несколько команд так называемого глобального контроля, когда посредством бродкаст-сообщения мастер переводит все устройства в так называемую заморозку или синхронизирует тики слейвов. Именно бродкаст я и не реализовывал) Данная фича в рамках моей задачи не была нужна...

В качестве железки я взял STM32F407:

Изолированный физический интерфейс:

С железками пока все, пойдем ковырять протокол...

Детали в деталях

Итак, главное сейчас уяснить: диагностика, параметризация и конфигурирование происходит в так называемых сервисных точках доступа — SAP, это логическое пространство для сервиса над ведомым. Доступ к конкретным SAP осуществляется дополнительными 2 байтами в PDU: адресами SAP источника (SSAP) и цели (DSAP):

SD2 телеграмма с доступом к SAP
SD2 телеграмма с доступом к SAP

Циклический обмен данными происходит без фанатизма. Инициализация ведомого представляет из себя минимально 4 посылки в следующем порядке: диагностика, параметризация, конфигурация, диагностика. При этом накладывается маска на адреса 0x80.

Для начала поговорим о типах посылок

Как говорилось ранее, основная информация была взята с сайта Макса Фелсера. В целом, там вы найдете достаточное описание посылок, байтиков, сиквенсов и т.д. Поэтому подробно на каждом останавливаться я не буду. Пройдусь тезисно, с вниманием к некоторым деталям.

типы телеграмм
типы телеграмм

Все телеграммы отличаются начальным лимитером — ключевой признак конкретной телеграммы, что устанавливает определенные правила в обработке такого пакета. Например, поиск контрольной суммы (FCS) в телеграмме, которая может включать те или иные поля в зависимости от типа телеграммы. Основных телеграмм 3: SD1, SD2, SC.

  • SD1 используется для запроса input данных от слейва в случае, если он только отдает данные. Используется в качестве ответа в случае, если слейв только получает данные. Также используется для запроса к слейву на вход в токен ринг.

  • SD2 используется для передачи данных, конфигурации, параметризации и диагностики. Часто используемый тип посылки. Используется для запроса к слейву с данными типа out. Используется для ответа в случае, если слейв отдает данные. Соответственно, используется для inout data.

  • SC — ответ размером в 1 байт на запросы параметрирования и конфигурирования.

Практически все байты телеграммы понятны из названия, я бы хотел остановиться на FC (код функции):

функции запроса
функции запроса

Для функционирования необходимо отвечать только на некоторые функции: SRD_HIGH (0x0D), Request FDL Status (0x09), а также учитывать биты FCV и FCB. К слову, можно запустить слейв и без контроля этих битов. Да и на запрос входа в кольцо можно тоже не отвечать, на самом деле, для реализации простого устройства этим можно пренебречь. Остается только SRD_HIGH.

функции ответа
функции ответа

В функциях ответа нам достаточно только 1 — DL (0x08). В некоторых случаях может пригодиться и DH (0x0A) ≈ ответ мастеру, после которого тот будет диагностировать ведомого (пошлет диагностическую телеграмму со всеми вытекающими). Кодом функции OK (0x00) нужно отвечать на запросы FDL статуса (0x09), но отвечать я на них не планирую)

Вернемся к инициализации, на очереди диагностика:

формат диагностической телеграммы
формат диагностической телеграммы

Для простого устройства достаточно и 6 байтов диагностики. При этом Status3 — 0x00.

Status1
Status1

Все биты описаны, немного деталей:

  • Station_Not_Ready — ответ на самую первую (req. FC = 0x6D) диагностическую телеграмму. В процессе этот бит можно устанавливать в ответах на диагностику после его запроса (res. FC |= 0x0A).

  • Cfg_Fault — в случае, если конфигурация модуля неверная.

  • Not_Supported — в случае, если какие-то функции не поддерживаются ведомым. Например, Freeze или Sync.

  • Prm_Fault — в случае, если аргументы для сторожевого таймера (WDOG factors) или минимальной задержки перед ответом (minTSDR) неверные. Также в случае, если идентификатор неверный.

Status2
Status2

Немного деталей:

  • Prm_Req — запрос параметров. В случае, если слейв готов продолжать инициализацию.

  • WD_On, Freeze_Mode, Sync_Mode — статусы активности соответствующих фич.

Adr
Adr

Теперь попробуем завести девайс со следующими параметрами:
Адрес слейва: 0x03
Адрес мастера: 0x02
Скорость шины: 1.5 Мбит/с
Конфигурация слейва: 8 byte out (0xA7)

Пример начала инициализации — первой диагностики:

Диагностика стучится в SAPs:
REQ: 0x3C > 0x3E (DSAP > SSAP)
RES: 0x3E > 0x3C (DSAP > SSAP)

На очереди параметрирование. Здесь нам необходимы только 7 байт, при этом Group = 0x00:

телеграмма параметрирования
телеграмма параметрирования

Здесь все байты описаны достаточно, не буду останавливаться.

Пример параметрирования:

Параметрирование стучится в SAPs:
REQ: 0x3D > 0x3E (DSAP > SSAP)
RES: 0x3E > 0x3D (DSAP > SSAP)

На очереди конфигурирование. Конфигурация может быть описана компактным и специальным форматами. В моем случае это компактный формат:

Бит 7 всегда 1. Это конфигурация для шинных модулей. Таким образом максимальный размер полезной нагрузки составит 32 байта для компактной конфигурации.

Пример конфигурации:

Конфигурирование стучится в SAPs:
REQ: 0x3E > 0x3E (DSAP > SSAP)
RES: 0x3E > 0x3E (DSAP > SSAP)

После удачного ответа на конфигурацию мастер шлет диагностическую телеграмму:

Если устройство готово к циклическому обмену данными, то необходимо ответить Status1 = 0x00. В моем случае я использую сторожевой таймер, поэтому Status2 = 0x0C (WD_On |= 0x04 const). Если слейв не готов, (проводит селф-тест, ждет ответа из космоса и т.д.) он должен ответить Status1 = 0x02 (nrdy). В этом случае мастер будет посылать диагностические сообщения, пока слейв не будет готов.

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

Также по шине летает токен:

Если мастер в шине только один, он будет слать токен самому себе.

На шине в тестах присутствовал Lenze i550 c адресом 0x04:

Как и говорилось ранее, я не отвечаю на запросы FDL:

Теперь о некоторых параметрах для телеграмм параметрирования и конфигурирования. Все устройства описываются в так называемых GSx файлах, например GSD. Структура файла немного описана у Фелсера, но следует остановиться поподробнее:

#Profibus_DP
GSD_Revision = 1
Vendor_Name = "STM V GmbH"
Model_Name = "STM4V slave"
Revision = "Version 1.0"
Protocol_Ident = 0 (0 - DP-V0)			
Station_Type = 0 (0 - слейв, 1 - мастер)
FMS_supp = 0	(этим можно пренебречь)
Hardware_Release = "Hardware 1.0"
Software_Release = "Software 1.0"
9.6_supp=1				(1 - поддерживает, 0 - не поддерживает)	
19.2_supp=1
93.75_supp=1
187.5_supp=1
500_supp=1
1.5M_supp=1
3M_supp=1
6M_supp=1
12M_supp=1

MaxTsdr_9.6 = 60			(максимальное время ответа на запрос в Tbit)	
MaxTsdr_19.2 = 60
MaxTsdr_93.75 = 60
MaxTsdr_187.5 = 60
MaxTsdr_500 = 100
MaxTsdr_1.5M = 150
MaxTsdr_3M = 250
MaxTsdr_6M = 450
MaxTsdr_12M = 850

Ident_Number = 0x1133 (идентификатор)

Redundancy = 0				    (этим можно пренебречь)	
Repeater_Ctrl_Sig = 2		    (этим можно пренебречь)		
24V_Pins = 0				    (этим можно пренебречь)	
Implementation_Type = "STMF4"	(этим можно пренебречь)		

Freeze_Mode_supp = 0		(1 - поддерживает, 0 - не поддерживает)		
Sync_Mode_supp = 0
Auto_Baud_supp = 0
Set_Slave_Add_supp = 0

User_Prm_Data_Len = 0	(кол-во дополнительных байтов информации в параметрировании)						

Min_Slave_Intervall = 1		(этим можно пренебречь)		
Modular_Station = 1			(1 - поддержка нескольких конфигураций одновременно в 1 девайсе)	
Max_Module = 1				(макисальное кол-во этих конфигураций)	
Max_Input_Len  = 8			(максимальное кол-во байт отдаваемых слейвом)	
Max_Output_len = 8			(максимальное кол-во байт получаемым слейвом)	
Max_Data_Len  = 16          

Max_Diag_Data_Len = 6       (максимальное кол-во байт в диагностике)
				
Module = "1 Byte OUT" 0xA0	(N-ая конфигурация модуля и ее значение)		
EndModule                   (конец описания конфигурации N-го модуля)

Module = "2 Byte OUT" 0xA1			
EndModule

Module = "4 Byte OUT" 0xA3			
EndModule

Module = "8 Byte OUT" 0xA7			
EndModule

Module = "1 Byte IN" 0x90			
EndModule

Module = "2 Byte IN" 0x91			
EndModule

Module = "4 Byte IN" 0x93			
EndModule

Module = "8 Byte IN" 0x97			
EndModule

Module = "1 Byte IN, 1 Byte OUT" 0xB0			
EndModule

Module = "2 Byte IN, 2 Byte OUT" 0xB1			
EndModule

Module = "4 Byte IN, 4 Byte OUT" 0xB3			
EndModule

Module = "8 Byte IN, 8 Byte OUT" 0xB7			
EndModule

Конфигурация в STEP7:

Max_Module отвечает за максимально возможное кол-во конфигураций, в данном случае 1 — "8 Byte OUT".

Все описанные конфигурации в GSD будут видны в дереве:

Конфигурации составлены по стандарту компактного формата. Добавляем нужную конфигурацию, заливаем хардвару, радуемся...

Именно Module = "4 Byte IN, 4 Byte OUT" 0xB3 и будет отправлять мастер в телеграмме конфигурирования. Соответственно, идентификатор (0x1133) — в телеграмме параметрирования.

Реализация протокола

В качестве среды я использовал STM32CubeIDE v1.5. Библиотеку HAL использую для начальной инициализации и каких-то простых вещей, в остальном CMSIS. Ссылка на проект.

Жизненно важные пояснения в проекте присутствуют. Для возможности портирования на другой контроллер указания тоже оставлены...

Шина реализована на UART c прерыванием простоя (IDLE) и контролем флагов ошибок. При срабатывании прерывания IDLE полученный фрейм проверяет алгоритм. Если алгоритм знает, что с ним делать, он будет его парсить со всеми вытекающими. Алгоритм предусматривает несколько функций обратного вызова для информирования пользовательского кода о соответствующих событиях. Их можно не использовать. Для работы необходимо проинициализировать пару структур и 2 буфера, с которыми алгоритм будет взаимодействовать. Передать их в функцию инициализации алгоритма, а также вызвать сам алгоритм:

uint8_t my_input_buf[256] = {0,};
uint8_t my_output_buf[256] = {0,};

int main(void) {

  ***

  dev_config.dir = OUT;
  dev_config.size = BYTE;
  dev_config.len = 8;

  slave_cfg.addr = 0x03;
  slave_cfg.speed = speed_1500K;
  slave_cfg.ident = 0x1133;
  slave_cfg.dev_cfg = dev_config;

  pb_dp0_pcb_init(&slave_cfg, my_input_buf, my_output_buf);

  ***

  while(1) {

    pb_dp0_pcb();

  }

}

ВАЖНО: При работе на больших скоростях процессорного времени остается мало, так как контроллер практически все время занимается обработкой и ответом на запросы. Поэтому пользовательский код должен это учитывать. Например, максимально использовать аппаратные ресурсы контроллера, не использовать блокирующие функции, быструю обработку прерываний, желательно на CMSIS. Для реализации модуля аналогового/цифрового входа/выхода этого достаточно.

Спасибо, что дошли до конца!

Комментарии (17)


  1. sami777
    18.07.2023 17:40

    По-уму, туда давно уже пора прикрутить CAN. Отпадет очень много вопросов по организации протокола обмена.


    1. N1X
      18.07.2023 17:40
      +2

      CAN вполне себе используется давно, в частности CANOpen если об автоматизации говлрить. Но профибас гораздо шире распространен, так уж сложилось. И если подстраиваться под готовые системы - с этим придется считаться...


      1. Indemsys
        18.07.2023 17:40
        +2

        У автора в статье применялся Lenze i550. А мы с ним работали через MODBUS например.
        Они и с CAN также продаются. Там интерфейс отдельным накладным модулем определяется.

        Но потом отказались от Lenze. Они у нас постоянно зависали и их программирование особенно замороченное на фоне других производителей.

        Поэтому говорить о некоей распространённости PROFIBUS я бы не стал. Тем более что это морально устаревший протокол. На сегодня требуются более быстрые и риалтаймовые протоколы типа EtherCAT.


        1. NutsUnderline
          18.07.2023 17:40
          +1

          Ну как бы Lenze != Profibus я полагаю И Если он зависал под modbus то это даже не означает что он обязательно будет виснуть под profibus, равно как и любой другой девайс. Если очень грубо то Profibus это навороченный Modbus и все эти усложнения надо хорошо отлаживать и тестировать А если требуется что то более быстрое то это повод задуматься не разместить ли управляющую программу более локально


          1. Indemsys
            18.07.2023 17:40
            +3

            Мы с проблемой долго боролись. Lenze свою вину не признал. Но небольшой реверс показал, что гальвано-изолированный их интерфейс на полевую шину сделан непрофессионально. Центральный микроконтроллер на интерфейсе у них XMC4400, он имеет и CAN и SCI/UART. Поэтому не думаю что схемотехника у них сильно отличается между CAN и RS485 (об этом говорят и лишние посадочные места на плате). Виснет и причём железно их интерфейсный микроконтроллер. Оживает только после полного выключения питания. Типичный Latch-up.


            1. RisingEdge Автор
              18.07.2023 17:40

              Проблемы с полевой шиной, по-моему опыту, в основном связаны с именно с полевой шиной) За 2 года я заменил около 3х десятков приемопередатчиков RS485 в различных девайсах. И понял, что к выбору микросхемы тоже нужно подойти с "подветренной". Могу посоветовать ADM485 исключительно от Analog Devices (частенько встречаю их в девайсах B&R), а также SN75ALS176x. Я бы не грешил на какие-то недочеты парней из Lenze, по крайней о софтверной стороне...


              1. Indemsys
                18.07.2023 17:40
                +1

                Два года в индустрии довольно мало. Мы в индустрии около 20 лет.
                У нас лежат горы просто сгоревших инвертеров от разных известных производителей.

                Про софт я бы даже не начинал.

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

                Зависания тоже никто не заметит, если мотор кратковременного действия и каждый раз после использования выключают питание.

                Поэтому у нас императивная установка такая - сбивается всё. А если не сбивается значит недостаточно наблюдали.

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

                Драйверы шин и мы меняли. Это приходилось делать из-за длинных полевых шин, где разность потенциалов земель между дивайсами превышала допустимый уровень смещения для драйвера. Беда в том, что выбросы на переходных процессах, индуктивность заземления и просачивание в землю от ЧП рассчитать невозможно, можно только эмпирически прийти к необходимости усиливать драйвер.


        1. RisingEdge Автор
          18.07.2023 17:40
          +1

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


        1. Ailuropoda_M
          18.07.2023 17:40
          +1

          Во-первых, по оценкам того же ARC Advisory - PROFIBUS существенно более распространен.

          Во-вторых, есть миллионы устройств, которым этот ваш реалтайм более чем не нужен.


  1. DerSpiwak
    18.07.2023 17:40

    Довольно печально звучит когда мощного STMа хватает по сути только на сам обмен


    1. RisingEdge Автор
      18.07.2023 17:40

      Есть такое. Но, такие проблемы сегодня неизбежны. Поэтому в обиходе и появилось такое понятие как контроллер интерфейса. Даже специфичные архитектуры разрабатывают для этих целей, либо реализовывают на FPGA. А по поводу стмки, по сути, любой контроллер возьми - такие же проблемы будут. Очень быстрый период запроса посылки, процессору просто некогда делать что-то другое. Либо делать это по частям/аппаратно/дополнительное ядро для программного когда, а аппаратные возможности у конкретного контроллера неплохие. Конечно, я бы добавил всяких интересных фич, но для этого лучше взять FPGA... Как и говорилось, для реализации входа/выхода этого достаточно. Вообще, в планах портануть на f103c8, но это когда будет скучно)


  1. NutsUnderline
    18.07.2023 17:40
    +3

    Материал для тех кто не просто очень очень в теме не промэлектроники, а конкретно в профибасах-сименсах, более того - уже знает как работает этот протокол и как пользователь (это еще ладно) но и изнутри. Начало вроде расжеванное, а потом бац - SAP, PDU. Расшифровки понятия PDU не приведено нигде. Некая табличка и это это сразу надо уяснить. С постоянной отсылкой на другой сайт, даже без указания пунктов... понятия о работе протокола это не дает, а для описания работы конкретной реализации многовато всего "азбучного" - зачем это все?


    1. RisingEdge Автор
      18.07.2023 17:40

      Можно согласиться с тем, что статья была написана не совсем корректно - мой первый опыт. Но тема здесь специфичная, ищущая человека, который достаточно скиловый в теме микроэлектроники. Это не для "подпивасного" скрола... Зачем? Когда мне поставили этот вопрос, я был бы рад найти какую-то интересную информацию, тем более пример кода. Может кому-то это поможет...


      1. NutsUnderline
        18.07.2023 17:40

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


    1. Ailuropoda_M
      18.07.2023 17:40
      +3

      Те кто в теме- вот на этом:

      PROFIBUS, она же Process Field Bus, она же полевая шина, она же так называемый RS485

      в удивлении поднимут бровь и спросят, а знаком ли автор с моделью OSI? Потому что совершенно не всякий PROFIBUS - это RS-485 и уж тем более наоборот.


      1. RisingEdge Автор
        18.07.2023 17:40

        Не переживайте, знаком...


        1. Ailuropoda_M
          18.07.2023 17:40

          Ну а зачем тогда автор такое пишет? Потому что RS-485 может быть и PROFIBUS, и Modbus, и CAN и BACnet. Никто в здравом уме не ставит равенство между PROFIBUS и RS-485.