PROFIBUS DP-V0 & STM32
Краткий тезис повествования
В этой статье я расскажу опыт разработки ведомого устройства для промышленных контроллеров 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
Циклический обмен данными происходит без фанатизма. Инициализация ведомого представляет из себя минимально 4 посылки в следующем порядке: диагностика, параметризация, конфигурация, диагностика. При этом накладывается маска на адреса 0×80.
Для начала поговорим о типах посылок
Как говорилось ранее, основная информация была взята с сайта Макса Фелсера. В целом, там вы найдете достаточное описание посылок, байтиков, сиквенсов и т.д. Поэтому подробно на каждом останавливаться я не буду. Пройдусь тезисно, с вниманием к некоторым деталям.
типы телеграмм
Все телеграммы отличаются начальным лимитером — ключевой признак конкретной телеграммы, что устанавливает определенные правила в обработке такого пакета. Например, поиск контрольной суммы (FCS) в телеграмме, которая может включать те или иные поля в зависимости от типа телеграммы. Основных телеграмм 3: SD1, SD2, SC.
SD1 используется для запроса input данных от слейва в случае, если он только отдает данные. Используется в качестве ответа в случае, если слейв только получает данные. Также используется для запроса к слейву на вход в токен ринг.
SD2 используется для передачи данных, конфигурации, параметризации и диагностики. Часто используемый тип посылки. Используется для запроса к слейву с данными типа out. Используется для ответа в случае, если слейв отдает данные. Соответственно, используется для inout data.
SC — ответ размером в 1 байт на запросы параметрирования и конфигурирования.
Практически все байты телеграммы понятны из названия, я бы хотел остановиться на FC (код функции):
функции запроса
Для функционирования необходимо отвечать только на некоторые функции: SRD_HIGH (0×0D), Request FDL Status (0×09), а также учитывать биты FCV и FCB. К слову, можно запустить слейв и без контроля этих битов. Да и на запрос входа в кольцо можно тоже не отвечать, на самом деле, для реализации простого устройства этим можно пренебречь. Остается только SRD_HIGH.
функции ответа
В функциях ответа нам достаточно только 1 — DL (0×08). В некоторых случаях может пригодиться и DH (0×0A) ≈ ответ мастеру, после которого тот будет диагностировать ведомого (пошлет диагностическую телеграмму со всеми вытекающими). Кодом функции OK (0×00) нужно отвечать на запросы FDL статуса (0×09), но отвечать я на них не планирую)
Вернемся к инициализации, на очереди диагностика:
формат диагностической телеграммы
Для простого устройства достаточно и 6 байтов диагностики. При этом Status3 — 0×00.
Status1
Все биты описаны, немного деталей:
Station_Not_Ready — ответ на самую первую (req. FC = 0×6D) диагностическую телеграмму. В процессе этот бит можно устанавливать в ответах на диагностику после его запроса (res. FC |= 0×0A).
Cfg_Fault — в случае, если конфигурация модуля неверная.
Not_Supported — в случае, если какие-то функции не поддерживаются ведомым. Например, Freeze или Sync.
Prm_Fault — в случае, если аргументы для сторожевого таймера (WDOG factors) или минимальной задержки перед ответом (minTSDR) неверные. Также в случае, если идентификатор неверный.
Status2
Немного деталей:
Prm_Req — запрос параметров. В случае, если слейв готов продолжать инициализацию.
WD_On, Freeze_Mode, Sync_Mode — статусы активности соответствующих фич.
Adr
Теперь попробуем завести девайс со следующими параметрами:
Адрес слейва: 0×03
Адрес мастера: 0×02
Скорость шины: 1.5 Мбит/с
Конфигурация слейва: 8 byte out (0xA7)
Пример начала инициализации — первой диагностики:
Диагностика стучится в SAPs:
REQ: 0×3C > 0×3E (DSAP > SSAP)
RES: 0×3E > 0×3C (DSAP > SSAP)
На очереди параметрирование. Здесь нам необходимы только 7 байт, при этом Group = 0×00:
телеграмма параметрирования
Здесь все байты описаны достаточно, не буду останавливаться.
Пример параметрирования:
Параметрирование стучится в SAPs:
REQ: 0×3D > 0×3E (DSAP > SSAP)
RES: 0×3E > 0×3D (DSAP > SSAP)
На очереди конфигурирование. Конфигурация может быть описана компактным и специальным форматами. В моем случае это компактный формат:
Бит 7 всегда 1. Это конфигурация для шинных модулей. Таким образом максимальный размер полезной нагрузки составит 32 байта для компактной конфигурации.
Пример конфигурации:
Конфигурирование стучится в SAPs:
REQ: 0×3E > 0×3E (DSAP > SSAP)
RES: 0×3E > 0×3E (DSAP > SSAP)
После удачного ответа на конфигурацию мастер шлет диагностическую телеграмму:
Если устройство готово к циклическому обмену данными, то необходимо ответить Status1 = 0×00. В моем случае я использую сторожевой таймер, поэтому Status2 = 0×0C (WD_On |= 0×04 const). Если слейв не готов, (проводит селф-тест, ждет ответа из космоса и т.д.) он должен ответить Status1 = 0×02 (nrdy). В этом случае мастер будет посылать диагностические сообщения, пока слейв не будет готов.
В результате успешной инициализации мастер начнет циклически опрашивать слейва:
Также по шине летает токен:
Если мастер в шине только один, он будет слать токен самому себе.
На шине в тестах присутствовал Lenze i550 c адресом 0×04:
Как и говорилось ранее, я не отвечаю на запросы 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 и будет отправлять мастер в телеграмме конфигурирования. Соответственно, идентификатор (0×1133) — в телеграмме параметрирования.
Реализация протокола
В качестве среды я использовал 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. Для реализации модуля аналогового/цифрового входа/выхода этого достаточно.
Спасибо, что дошли до конца!