
UDS (ISO 14229) (Unified Diagnostic Services) это бинарный протокол. Обычно этот протокол гоняют поверх протокола ISO-TP в CAN шине между ECU. Подробно протокол описан в стандарте ISO 14229. Это диалоговый протокол, то есть работает по принципу запрос-ответ. Получается что тут есть master и slave узлы. Ещё говорят клиент сервер. Где клиент - это тестировочное оборудование, а сервер - ECU.
В этой заметке я расскажу про наиболее полезные пакеты UDS протокола.
Что надо из спецификаций?
Полная спецификация UDS составляет 400+ страниц. Документ называется International Standard ISO 14229-1, Road vehicles — Unified diagnostic services (UDS) — Part 1: Specification and requirements
№ |
Код спеки |
Пояснение |
1 |
ISO 14229-1 |
Спецификация прикладного уровня UDS |
2 |
ISO 11899-2 |
Controller area network |
3 |
ISO-15765 |
Transport Layer |
Стек протоколов выстраивается в пирамиду.

На самом деле формально ничто не запрещает гонять этот UDS и по другим интерфейсам. Как в случае с протоколом XCP. Например по тому же UART. UDS это же про то как на входной массив байт выдать ответный выходной массив байт. Только и всего... Режим UDS over UART весьма полезен для модульных тестов UDS. Чтобы разграничить возможные ошибки в реализации ISO-TP от ошибок в реализации UDS. В связи с этим я бы порекомендовал Вам не приколачивать гвоздями свой код UDS к CAN коду, а добавить возможность переключаться между интерфейсами в зависимости от конфига в экземпляре UDS драйвера. Условно, вы можете объявить три экземпляра UDS. Первый прикрепить к CAN, второй UDS вывести на UART2, а третий просто оставить без интерфейсов чисто как SW экземпляр специально для модульных тестов.
Что позволяет протокол UDS?
UDS работает на уровне приложения и на сеансовом уровне модели OSI-7. UDS протоколом можно перезагрузить микроконтроллер, обновлять прошивку, управлять агрегатами автомобиля, считывать диагностические параметры агрегатов и прочее.
№ |
Действие |
1 |
считать\стереть коды ошибок – DTC |
2 |
запросить текущие параметры датчиков и блоков управления (ECU) |
3 |
Обновить прошивку |
4 |
давать команды исполнительным механизмам. Запускать подпрограммы |
5 |
Прописывать калибровочные данные |
6 |
Прописывать и читать конфигурационные данные |
7 |
Перезагрузить устройство |
Переменные в этом протоколе (такие как DID) передаются в формате Big-Endian. Контрольная сумма в UDS отсутствует, так как она и так проверяется на канальном уровне, где работает CRC15 от CAN пакетов.
Подпрограммы встроены в саму прошивку ECU и могут быть начаты по UDS команде от клиента. Например UDS подпрограммой можно открыть и закрыть дверной замок.
Что надо из доков?
Полный стандарт UDS это четыре сотни страниц!
# |
Документ |
Пояснение |
pages |
1 |
ISO 14229 |
Стандарт описывает уровень приложения для UDS |
464 |
UDS это надстройка над протоколом ISO-TP(ISO-15765). Про ISO-TP у меня есть отдельный текст: Обзор Протокола ISO-TP [ISO 15765-2] https://habr.com/ru/articles/798489/.

Есть два типа ответов от ECU: положительный и отрицательный.
Аппаратная часть.
UDS не определяет внешний вид разъёма. Однако скорее всего UDS будет на 6 и 14 пинах разъёма OBD2. К слову, в легковых автомобилях разъём OBD2 реализован в виде гнезда. Поэтому для подключения Вам потребуется ответная часть в виде вилки. Перед установкой вилки обязательно проверьте, что между разъёмами не очутилась всяческая грязь в виде фольги от папиросок или прочих проводников.

Структура UDS совместимых сетей передачи данных
Архитектура UDS протокола подразумевает наличие клиента и сервера.

С сервером USD всё понятно. Это ECU. В качестве клиента в конечном счете будет выступать LapTop.

При этом тестированную утилиту можно написать тоже на Си пере используя значительную часть Си кода прошивки в виде консольного Win приложения.
Структура UDS пакета для запроса.
Рассмотрим структуру бинарного пакета для запроса.
Поле #1: SID Service ID [1-Byte]

Поле #2: UDS Sub Function [1-Byte]
Некоторые UDS запросы имеют под функцию а некоторые нет.

USD пакет может полностью поместиться в 8 байт, как запрос так и ответ.
Поле №3: Data Identifier DID [2 байта]
DID - это переменные ECU, которые можно читать или писать. Физически DID хранятся либо в RAM либо в Flash памяти микроконтроллера (NVRAM). Каждый DID адресуется 16-битным адресом. То есть в ECU может храниться до 65536 переменных. Сами же эти DID переменные могут быть совершенно любого размера, как по 1 байту, так и целые массивы. Чисто теоретически через DID можно прочитать скорость автомобиля, обороты двигателя и прочие переменные ECU. Чтобы прочитать DID надо использовать сервис 0x22-Read Data by Idenvifier (RDBI). Чтобы прочитать DID надо использовать сервис 0x2E-Write Data By Identifier (WDBI)

В самом простом случае использования по UDS можно читать данные по их ID. Для этого есть сервис SID=0x22.
ECUReset (0x11)
UDS позволяет перезагрузить микроконтроллер. Для этого достаточно буквально отправить два байта.

ReadDataByIdentifier (SID=0x22) service
Этот сервис позволяет клиенту запрашивать значения данных по одному или более идентификатору данных DID.
Запрос клиент содержит одно или более двухбайтовых DID значений, которые соответствуют данным. Формат и определение записей данных должны быть определены производителем ECU. Там могут быть показания аналоговых входов, цифровых входов или выходов, внутренние данные, статус системы и прочее.
Сервер может ограничить количество DIDов которые запрашивают одновременно за раз.
Получив пакет SID=0x22 ECU должен извлечь запрашиваемые данные с заданным DID и передать их значение в одном положительном ответе, который содержит соответствующее значение данных. Запрос может содержать тот же самый DID несколько раз. ECU должен рассматривать каждый DID как отдельный параметр и отвечать данными для каждого DID, как запрошено.
UDS предусматривает положительный и отрицательный ответ. В случае положительного ответа в ответном пакете к оригинальному SID прибавляется константа 0x40. Вот пример запроса скорости транспортного средства (DID=0xF40D) по UDS. В пакете DID передается в big-endian формате, то есть старшим байтом вперёд.

Это же в составе с ISO-TP

Однако есть и отрицательные ответы. Это может произойти если Вы запросили значение DID про который ECU ничего не знает. В случае негативного ответа это может быть, когда сервис не поддерживается.

Вот все коды ошибок для ответа на пакет ReadDataByIdentifier
NRC |
Description |
Mnemonic |
0x13 |
incorrectMessageLengthOrInvalidFormat |
IMLOIF |
0x14 |
responseTooLong |
RTL |
0x22 |
conditionsNotCorrect |
CNC |
0x31 |
requestOutOfRange |
ROOR |
0x33 |
securityAccessDenied |
SAD |
Вот так выглядит попытка прочитать не валидный DID=0xAAAA, который не поддерживает ECU.

Прибор просто посылает значение 0x31 (requestOutOfRange), что запрошенное 16-битное значение DID не поддерживается этим конкретным CAN-устройством.
Кодов отрицательный ответов много. Вот некоторые из них

ReadScalingDataByIdentifier (SID=0x24)
Этот сервис показывает как интерпретировать данные из ECU. Это необходимо для визуализации данных полученных от ECU. Благодаря пакету ReadScalingDataByIdentifier LapTop запрашивает у ECU информацию про его внутренние переменные. Для каждой доступной переменной можно узнать её тип данных(uint8 int32 float string и т п), физическую величину (скорость, массу, ток), размер (1, 2, 5 байта), единицы измерения (градусы или радианы, паскали, бары, атмосферы или сила на кв метр) и размерный множитель (милли, пико, нано и т. п.). Всё это называется словом scaling information. У каждого DID должна быть известная информация про тип, размер, величину, единицы измерения, множитель. Запрос от LapTop содержит одно ID переменной. Формат поля dataRecord должны быть определены по желанию производителя транспортного средства и могут включать сигналы аналоговых входов или выходов, цифровые входы, внутренние данные, информацию про статус системы. В случае получения пакета запроса ReadScalingDataByIdentifier микроконтроллер должен получить доступ к информации про переменную и передать значения в положительном ответе.

Переменная scalingByteExtension содержит единицы измерения, формат и множитель. Это нужно для представления переменной в дружественном для человека виде. Для каждой размерности в UDS предусмотрен числовой код в виде натурального числа. Поле scalingByteExtension определяет множитель для более компактного представления числа в памяти. Поле scalingByteExtension применимо только для формул, чисел и битовых масок. Для переменных типа unit первым байтом определяется единицы измерения переменной. Коды множителей перечислены в таблице Table C.8 — Unit/format scalingByteExtension encoding.
Запись NVRAM по ID. WriteDataByIdentifier (SID=0x2E)
Сервис WriteDataByIdentifier позволяет LapTop-у прописывать информацию во внутренности ECU по идентификатору данных. Можно прописывать так называемые dataRecord. Данные идентифицируются по идентификатору данных. Идентификатор данных имеет разрядность 16 бит. Благодаря этому сервису можно прописывать конфигурационные данные в ECU. Например VIN номер. Прописывать NVRAM память. При этом надо ограничивать доступ на изменение определенных ID.

Чтение сырой памяти по физическим адресам микроконтроллера
UDS протокол позволяет читать физическую память. Для этого заложены пакеты типа ReadMemoryByAddress (SID: 0x23). UDS клиент должен запоминать, что и сколько он хотел прочитать, так как в ответном пакете от ECU отсутствует повторение значения адреса и размера пакета. В ответе только данные.

Запись сырой физической памяти WriteMemoryByAddress (SID=0x3D)
Протокол UDS позволяет прописывать произвольную физическую память. В случае 32бит МК получается вот такой пакет.

Чтение информации по Diagnostic Trouble Codes Service(0x19)
Этот сервис позволяет клиенту читать состояние диагностических кодов ошибок на ECU от любого сервера или группы серверов. Если иное не требуется конкретной подфункцией то сервер должен возвращать всю информацию о DTC (например связанную или несвязанную с выбросами). Этот сервис позволяет сделать следующее:
--Получите количество кодов DTC, соответствующих маске состояния DTC, определенной клиентом.
--Получить список всех кодов неисправности, соответствующих маске состояния кодов неисправности, определенной клиентом.
--Получить список кодов DTC в конкретной функциональной группе, соответствующих маске состояния DTC, определенной клиентом.
--Получите все коды DTC со статусом «постоянный код неисправности».
Пакеты класса RoutineControl (Управление Подпрограммами) (SID=0x31)
Служба RoutineControl используется клиентом для выполнения определенной последовательности шагов и получения любых уместных результатов. Этот сервис обладает большой гибкостью, но типичное использование может включать в себя такие функции, как
стирание памяти, сброс, запуск самотестирования и контроль изменения значения сервера с течением времени, включая предопределенные последовательности (например, закрытие
складной крыши), и это лишь некоторые из них.
Сервис RoutineControl используется клиентом для следующего
Описание |
sub-function |
Mnemonic |
Количество аргументов |
Начать подпрограмму |
0x01 |
STR |
1-2 |
остановить подпрограммы |
0x02 |
STPR |
1 |
запросить результат подпрограммы |
0x03 |
RRR |
1 |
Каждой подпрограмме поставлен в соответствие 2-байтовый идентификатор подпрограммы routineIdentifier.
Начать процедуру по ID
Процедура должна быть запущена в памяти сервера через некоторое время между завершением сообщение запроса StartRoutine и завершение первого ответного сообщения, если ответное сообщение положительное или отрицательный, указывающий, что запрос уже выполнен или находится в процессе выполнения.

Подпрограммы могут быть либо тестами, которые выполняются вместо обычного рабочего кода, либо подпрограммами, которые активируются и выполняется при нормальном рабочем коде. В частности, в случае теста это может быть необходимо переключить сервер в конкретный диагностический сеанс с помощью службы DiagnosticSessionControl или разблокировать сервер с помощью службы SecurityAccess перед использованием службы StartRoutine.

Остановить подпрограмму по ID
Серверная процедура должна быть остановлена в памяти сервера ECU через некоторое время после завершения сообщение запроса StopRoutine и завершение первого ответного сообщения, если ответное сообщение положительное или отрицательный, указывающий, что запрос на остановку процедуры уже выполнен или находится в процессе выполнения.
Запросить результат подпрограммы по ID
Эта подфункция используется клиентом для запроса результатов (например, информации о статусе выхода), на которые ссылается подпрограмму, генерируемую подпрограммой, которая выполнялась в памяти сервера.
На основании результатов подпрограммы, которые могли быть получены в положительном ответном сообщении Параметр подфункции stopRoutine (например, нормальный/ненормальный выход с результатами) requestRoutineResults должна использоваться подфункция.
Примером routineResults могут быть данные, собранные сервером, которые не могут быть переданы во время выполнения подпрограммы из-за ограничений производительности сервера (ECU).
Вот так выглядит бинарная структура пакета запроса для RoutineControl в общем виде

Итоги
Появилось некоторое представление о UDS протоколе. Научились читать параметры по сервису SID=0x22 и запускать подпрограммы по UDS ( SID=0x31 ).
UDS больше похож не на протокол, а на набор протоколов. Для каждого сервиса предусмотрена своя уникальная бинарная структура пакета, как для запроса, так и для ответа.
UDS настолько велик, что как правило мало, кто делает полную поддержку всех UDS сервисов. Обычно ограничиваются реализацией запуска подпрограмм, чтением / записью DIDов, чтением / запись физической памяти и пакета для Reset.
Словарь
акроним |
расшифровка |
UDS |
Unified Diagnostic Services |
ECU |
Electronic Control Units |
OSI |
open systems interconnection |
ISO |
International Organization for Standardization |
OEM |
Original Equipment Manufacturers |
OBD |
On-Board Diagnostics |
OBD2 |
On-Board Diagnostics 2 |
DTC |
Diagnostic Trouble Codes |
SA |
Source Address |
RA |
Remote Address |
NRC |
Negative Response Code |
NVRAM |
Non-Volatile Random-Access Memory |
TA |
Target Address |
LEV |
Level |
PCI |
Protocol Control Information |
SID |
Service ID |
SF |
Single Frame |
FC |
Flow Control |
DID |
Data IDentifier |
CAN |
Controller area network |
VIN |
Vehicle Identification Number |
URLs
Ссылка |
URL |
UDS Explained - A Simple Intro (Unified Diagnostic Services) |
https://www.csselectronics.com/pages/uds-protocol-tutorial-unified-diagnostic-services |
Протокол UDS |
|
Обзор Протокола ISO-TP [ISO 15765-2] |
|
Обзор USB-CAN переходника USB2CANFD_V1 |
|
Как собрать Си программу в OS Windows |
Вопросы
--Какой может быть максимальный размер UDS DID? Можно ли одним UDS DIDом прочитать или прописать всю прошивку? Размер DID ограничен сверху размером одной ISO-TP транзакции. А это 4kByte. Также могут быть ограничения по оставшейся RAM памяти в микроконтроллере на котором собран данный ECU.
--Как можно протестировать реализацию UDS протокола?
--Какие UDS DID значения общие для всех автопроизводителей?
--Существует ли какая-нибудь готовая клиентская Windows утилита (c GUI или консольный вариант), которая опрашивает ECU по CAN через UDS протокол? Чтобы прочитать стандартные в UDS DID параметры. Такие как VIN номер, серийный номер ECU, дату производства ECU, дату программирования ECU, название производителя ECU и прочее. Vector CANape, TOSUN TSMaster
--Можно ли по UDS читать/писать произвольные адреса физической памяти? Если да то какой cерсис позволяет это делать? Какой пакет UDS предназначен для чтения физической памяти микроконтроллера?
--Зачем в 2006 понадобился автомобильный протокол UDS, если тремя годами ранее уже в 2003 был автомобильный протокол XCP? И UDS и XCP могут читать и писать произвольную память, оба могут обновлять прошивку. Они ориентированы на разные задачи: UDS-диагностику и XCP-калибровку. XCP нужен разработчикам. UDS - техникам.
--Какими UDS пакетами следует обновлять прошивку?
--Какие еще прикладные протоколы могут быть в автомобиле кроме UDS? J1939, On-Board Diagnostics (OBD2), World-Wide Harmonized OBD (WWH-OBD), CCP, XCP.
VBKesha
KWP2000(TP20) ещё, и наверно его предшественник TP16.