Получаем лаг форсунок из прошивки произвольного ЭБУ методом обратного инжиниринга...

Лаг форсунок - довольно важная физическая характеристика. Его можно измерить на стенде для проливки форсунок, если на нем есть возможность менять напряжение на форсунках и длительность импульса, однако для того, чтоб сделать это точно нужны хорошие мерные цилиндры, и идеальные условия, обычные стенды не позволяют получить хорошую разрешающую способность для таких измерений ни по времени, ни по напряжению, ни по объему и массе топлива, поэтому лучше конечно посмотреть лаг в штатном ЭБУ машины, откуда взяты форсунки - если для него есть есть файлы определений (dam-a2l) и прошивка. Но что делать, когда файлов определений нет?! В этом случае нам поможет один хороший метод - метод обратного инжиниринга.

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

И так сегодня у нас стоит задача извлечь характеристику "Лаг форсунок" из блока управления М1.5.4 производства китайского отделения фирмы Bosch (Bosch Asia) для FAW Xiali. М1.5.4n - классика систем управления. Этот блок прожил активной жизнью почти 20 лет, выпускался с начала 90-х по конец 2000-х. В основе блока - микропроцессор Infineon 80c51x7. В качестве памяти программ применяется 27с256 или 27с512. Для данной работы нам понадобится:

1) Прошивка блока. В данном случае это TJ376QE_03_FD4606CA.rar EPK: 45/1/M154/741/3210//FD4606CA/FD4606CA/071205/ старенькая конечно - 10 лет как уже. Но задачи свои годно выполняет.

2) Описание архитектуры процессорной системы в целом. По Intel MCS51 лежащему в основе нашего микроконтроллера в интернете огромная куча информации. Начать можно отсюда http://www.gaw.ru/html.cgi/txt/doc/micros/mcs51/index.htm 

3) Описание конкретного процессора в частности - тут подойдет файл который лежит на сайте keil поскольку с сайта инфинеона он стерт за ненадобностью http://www.keil.com/dd/docs/datashts/infineon/80c5x7_um.pdf

4) Дизассемблер для MCS51. Дизассемблер - это серьезный религиозный вопрос. Новички обычно пользуются наиболее популярным ширпотребом (IDA pro) профессионалы конечно же дизассемблер пишут сами, это необходимо для того, чтоб быстро допиливать его под разные конкретные задачи.

Небольшое лирическое отступление. Кросс-дизассемблер для MCS-51, который я использую, был написан мной в начале 90-х годов, на языке ассемблера процессора Z80, для операционной системы CP/M 2.2. Все это было еще при СССР. Машины на которых это писалось давным давно умерли и этот дизассемблер сейчас запускается на PC в популярном эмуляторе CP/M 2.2 (известном как 22nice) который в свою очередь был написан для операционной системы MS-DOS 3.30 в 80-е годы (оно даже еще FCB использует...), но и эта MS-DOS 3.30  на самом деле не существует как OC машины - она тоже эмулируется виртуальной dos машиной в операционной системе Windows XP (ntvdm), ну то есть в конечном счете, все это работает из под  XP, на железе, на котором XP запущена пока еще нативно - но чувствую, скоро придется добавить в процесс еще одну ступень абстракции потому, что вряд ли ноутбуки, на который можно запускать XP, проживут лет 5-10 не устарев морально. К чему это я все... так вот, когда ваш iphone6 превратится в тыкву - эта 26 летняя программа запущенная в трех эмуляторах, так же хорошо и качественно будет решать все возложенные на нее задачи.

5) Плата блока. В данном случае платы именно того блока, от которого прошивка, у меня нет - но это и не важно, поскольку, почти все консервные м1.5.4 по сути одинаковы. Я взял горелую ВАЗовскую плату м1.5.4 -70 и спаял с него все крупные детали и разъем,  чтоб удобно было прозванивать любые соединения... Получилось вот такое вот непотребство:

 

И так для начала нам нужен листинг прошивки. Собственно изучаем архитектуру, берем дизассемблер - делаем листинг, нормальный такой - ну с всеми методами адресации. Мне очень сложно объяснять как делают листинг поскольку для меня этот процесс примерно соответствует "пожарить картошку" - т.е. берешь картошку, сковородку, масло и жаришь...

После того как листинг у нас есть - начинаем искать там наш лаг.

Обычно в таких простых архитектурах систем управления, лаг форсунок (TVUB) добавляется к времени впрыска (ti) самым последним сложением, перед программированием регистров модуля сравнения, для открытия форсунок. Чтоб проверить эту гипотезу, стоит обратится к исторической письменности с форума nefmoto датированной 1995-м годом в которых описаны старинные алгоритмы блоков управления Бош Мотроник.

Посмотрим определение функции %ESS (расчет времени впрыска при старте двигателя tist) - как мы видим снова наше TVUB добавляется в конце. 

Та же ситуация с функцией %ESTI

 Поэтому сейчас мы тупо ищем в листинге кусок управляющий форсунками. Нам известно, что во всех системах на базе 80с5x7 форсунки подключены на порт P4, так как именно к нему подключен модуль сравнения, наиболее удобный для управления форсунок. Если же мы не знаем куда к процессору подключены форсунки - это не проблема. Они легко вызваниваются тестером по плате сначала от разъема на выходы драйвера форсунок а потом по PDF на драйвер - от входов драйвера к процессору. Именно для этого у нас и есть распаянная плата. В данном случае так же мы знаем, что форсунок - 3 штуки, поэтому мы не будем прозванивать их по плате, а будем искать в коде - где портом P4 будут управлять на 3-х каналах обязательно с использованием модуля сравнения.

Первый же кусок удовлетворяющий условиям поиска выглядит так:

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

Что мы можем узнать из этого куска:

1) форсунок как мы и думали - три. Подключены они на линии процессора P4.0 P4.1 P4.2 

2) форсунки управляются модулем сравнения работающим от таймера T2.

3) Время впрыска для этой функции лежит в ОЗУ по адресам 5CH (TI_L) и 5BH (TI_H)

А значит следующее, что мы ищем - где и как заполняются TI_L TI_H

Вот тут мне кажется мы сразу нашли наш лаг. Берется нечто 8-ми разрядное. Умножается на 5.. и прибавляется к 16-ти разрядному значению - в результате получается наше время впрыска. Очень похоже, что это лаг - теперь надо найти как он получается. Ищем запись в ячейку RAM_6B:

Тут тоже никаких сложностей - подпрограмма по адресу 0400 возвращает нам результат выборки из 2D или 3D таблицы, индекс которой задан в регистре R2. Нам всего лишь нужно в начале функции найти загрузку регистров DPTR, чтоб узнать, на что они указывают, и выбрать в них 3-ю по порядку таблицу. Поэтому сначала идем по коду немножко вверх до последнего RET а затем заходим во все подряд вызовы функций.

Тому что мы ищем удовлетворяет подпрограмма по адресу 4С74H - она обычно самая первая вызываемая в функции.

Тут то и начинается самое мясо. Функции в прошивке инкапсулированны - т.е. каждая использует свой набор таблиц и свой набор констант. Каждая функция в своем начале загружает в три DPTR регистра (с разными селекторами) базу индексов и ссылку на адреса таблиц. Как мы видим наша функция может в зависимости от одного из битов использовать разные индексы таблиц (т.е подменять таблицы). Поэтому необходимо просмотреть оба варианта ее индексов таблиц по адресам 0d806h и 0d80dh.

Как мы видим интересующая нас 3-я таблица (значение по адресу +3 = 06H) в обоих вариантах одинакова, разные только две последние таблицы. Из этих цифр и анализа функции 0400H можно понять следующее:

1) Искомая таблица имеет 2D формат (бит 0 у индекса = 0) как впрочем и ВСЕ таблицы этой конкретно функции!

2) Индекс искомой таблицы расположен по адресу 0DA5EH+(06H&0FEH)=0DA64H, идем туда...

Наша таблица находится по адресу TE1C8 и выглядит так:

На первый взгляд - тут какая то билиберда. Но на самом деле это вполне осмысленные значения. Для начала, следует рассказать, как в таких старых системах формируется ось X. Если с указателем на ячейку ОЗУ, откуда берется значение для формирования оси X все ясно, то с самой осью все вроде бы не так очевидно. Но все проясняется, если рассмотреть внимательно функцию выборки 0400h.... Для начала давайте переведем нашу табличку из шестнадцатеричного в десятичный вид:

X 59 30 29 21
Y 185 92 69 52

Ось Y  выглядит нормально, монотонно спадает - а вот с осью X, что то явно не все в порядке. Значения, почему то, совсем близкие. Ответ, "почему",  кроется в функции 0400h -  на самом деле, по оси X во всех таблицах блока расположены вовсе не значения, а дистанции между ними, причем отсчитываемые "с конца". Для того, чтоб получить значения по оси X надо из 256 вычесть последнее значение 21, а затем из полученного вычесть следующее 29 и так далее.. 256-21=235 235-29=206 206-30=176....Перестроим нашу табличку исходя из этих знаний:

X(corr) 117 176 206 235
Y 185 92 69 52

Совсем другое дело. Пока все указывает на то, что мы на верном пути. Монотонный рост значения по оси X, монотонный спад по оси Y - именно так выглядит лаг. :Для проверки, что мы все делаем правильно, на всякий случай снова обратимся к отсканированной древней письменности, которая описывает ту же таблицу в другой системе управления но созданной теми же людьми в то же примерно время. 

Тут как мы видим используется точно такая же логика вычисления значений оси X - и следовательно она была нами восстановлена правильно однако в этом случае значений не 4 а 5.

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

Как видно, содержимое RAM_55 - это значение прочитанное из 1-го канала АЦП контроллера, который во всех блоках M1.5.4 отвечает за измерение напряжения бортовой сети. (Надеюсь вы уже поняли, что к этому моменту как настоящий реверс-инженер вы должны знать, за что отвечает КАЖДЫЙ КАНАЛ АЦП на целевой системе?!) Ну вот, теперь мы точно знаем, что RAM_55=UB а наша таблица и есть искомое TVUB, а значит настало время разбираться с ее размерностями.

Соответствие напряжения на входе АЦП с кодом его выхода, определяется коэффициентом, зависящим от опорного напряжения Vref АЦП и битности АЦП. Поскольку в данном случае Vref=5v а битность = 8, код АЦП можно перевести в его входное напряжение умножением на 5 и делением на 2 в 8-й степени (2^8=256). Однако поскольку в нашем случае канал предназначен для измерения бортового напряжения, значения которого могут превышать референсные для АЦП 5в - на входе канала установлен резисторный делитель из двух резисторов. Таким образом, в формулу преобразования надо ввести поправку, зависящую от сопротивления резисторов в этом делителе. Делитель этот несложно найти на плате. Для этого сначала смотрим связи между каналами АЦП и пинами микроконтроллера в pdf

А затем прозваниваем найденный нами пин тестером по плате. В данном случае - пин P7.1 связанный с 1-м каналом АЦП микроконтроллера. Находим делитель.

Резисторы идут на 37 ногу ЭБУ - т.е. непосредственно к выводу соединенному с плюсом питания форсунок (от главного реле). Верхний резистор делителя 67.8k Нижний 27.4k -  разница напряжений до после делителя считается как (67.8+27.4)/27.4=3,474453  Общая формула преобразования для X оси в физический вольтаж таким образом выглядит так UB(v) = X(corr)*(67.8+27.4)*5/(27.4*2^8), вновь пересчитаем ось X в нашей табличке TVUB используя эти новые знания:

X(corr) 117 176 206 235
UB(v) 7,93 11,94 13,97 15,94
Y 185 92 69 52

Округлим значения UB до ближайших целых чисел, чтоб исключить погрешности квантования при задании оси - получается совсем уж красота:

UB(v) 8 12 14 16
Y 185 92 69 52

Настало время разобраться с весами значений в оси Y. Для того, чтоб получить формулу преобразования, нам надо знать период счета таймера T2 и тактовую частоту процессора. Тактовая процессора во всех этих блоках так же одинаковая и давно известна - 16 МГц. 

Если кому то не известна - осциллограф в помощь! Чтоб узнать период тактирования T2 снова смотрим в pdf на процессор, там нас интересует вот такая мнемосхема: 

Смотрим, что там в прошивке у нас кладется в регистры CTCON и T2CON при инициализации ЭБУ.

Прескалер T2 = 2. Таким образом тактовая частота таймера T2 = 16000000 / 12 / 2 = 666666,7 Hz и соответственно период тика T2 = 1 / 666666,7 = 1,5mks 

Исходя из этой информации, формула пересчета значений в оси Y в физическое представление будет иметь вид: TVUB(ms) = Y * 1.5mks * 5 / 1000    (пятерка если вы помните участвует в алгоритме - на нее умножалось содержимое RAM_6B, а 1000 нужна для перевода микросекунд в миллисекунды, в которых привычно для нас выражен лаг). Пересчитаем еще раз нашу табличку с использованием этой новой информации::

UB(v) 8 12 14 16
TVUB(ms) 1,3875 0,69 0,5175 0,39

Мы получили абсолютно осмысленный результат - но это еще не все! Лаг просто так конечно никому  не нужен. Лаг нужен внутри "Января"! А у нас тут слишком мало точек, чтоб его туда внедрить. Решить эту проблему нам поможет один хороший инженерный софт - SciDAVis, его можно скачать естественно бесплатно, без СМС! Ссылку не даю - сами нагуглите. Для решения нашей задачи мы восстановим функцию TVUB используя полиномиальное приближение. Открываем SciDAVis  и запихиваем в исходные данные нашу табличку, затем выбираем в меню пункт "Анализ/Quick Fit/Полиномиальное приближение/полиномом 3й степени" :

Ну тут все ясно даже самым тупым. (Естественно в случае других систем вам надо конечно будет проиграться с степенями или методом приближения - но именно в этом случае все сразу получилось красиво). В итоге мы имеем следующую функцию:

y= a0+a1*x+a2*x^2+a3*x^3

 

a0 = 5,71500000000002 +/- inf

a1 = -0,894062500000005 +/- inf

a2 = 0,0532031250000005 +/- inf

a3 = -0,00113281250000001 +/- inf

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

Которая затем переносится в целевой ЭБУ и предстает перед нами уже в совсем привычном виде:

Вот и все - спасибо за внимание!

 

(c) Maxi(РПД) 2015 Копирование материалов ресурса без разрешения автора запрещено.