LIN шина, теория и практика

lin

Некоторые тонкости разработки программного обеспечения для реализации lin интерфейса. 

Лин шина - одна из наиболее развивающихся технологий передачи данных. Ее можно рассматривать в качестве недорогой и упрощенной замены rs-485, да и вообще всех uart-подобных интерфейсов. По сути lin - это новая надстройка над uart'ом, только скорее аппаратная. Про тонкости реализации физической части интерфейса можно найти полно информации даже на русском языке. Отмечу, что лин интерфейс можно реализовать даже на отечественных элементах 40-летней давности и работать будет превосходно: резистивный делитель на считывание данных и транзисторный ключ на кт315 с парой сопротивлений - весь интерфейс :) Это конечно даже больше чем приятно.

И все же довольно мало информации по программной реализации ЛИН интерфейса, только общие слова. В данной статье постараюсь выкладывать по мере сил и возможностей некоторые решения. Все необходимое по интерфейсу можно найти в официальной документации на сайте лин интерфейса, но там и воды много.

И так, первая тонкость (а точнее первые грабли, на которые можно наступить). Стартовый бит. Многие могут по ошибке подумать, что лин можно реализовать на обычном УАРТ. Так вот они окажутся неправы ровно наполовину. Шина лин в покоящемся состоянии держит +12 вольт постоянно, а стартовый бит должен быть не менее 11 бит низкого уровня. Если смотреть сниффером, то первый байт - 0x00, т.е. стартовый байт. На самом деле, если бы мы передавали 0x00 байт, то уарт подал бы один стартовый бит (низкое состояние), затем 8 нулей (низкое состояние), а затем стоповый бит (ВЫСОКОЕ состояние). И вот тут и заключается основная проблема.Стандартным уартом мы не можем передать 11 бит низкого состояния, даже перенастроив его (на что тоже нужно время). Поэтому передачу данных приходится делать программно в случае мастера.

А вот с приемом намного все веселее. На примем можно использовать и стандартный уарт. только надо учитывать, что все что мы передаем сами и мы и ловим (как внутренний интерфейс сетевой карты), потому что в ЛИН используется один провод на передачу и на прием данных

 

Теперь вторая неочевидная тонкость: crc. То как оно считается нигде не нашел. Передается как всегда в конце сообщения. Откуда считать тоже не сразу понял. Сумма считается с первого байта после байта адреса, а вот как она считается меняется от ревизии к ревизии. Насколько я понял, лин сумма ревизии 1.3 и 2.0 отличаются, также бывают другие алгоритмы подсчета суммы (enhanced check sum). Как правило используется циклическая избыточная сумма. Вот пример исходного кода для подсчета crc

#include <string.h>
#include <conio.h>
#include <stdio.h>
unsigned char lin_crc (unsigned char *message, int len)
{
    volatile unsigned int res = 0;
    for (int i = 0; i < len; i++)
    {
        res += (volatile unsigned int) message[i];
        if (res & 0x100)
        {
            res++;
            res &= 0xFF;
        }
    }
    res ^= 0xFF;    // inverting result
    return (unsigned char) res;
}

int main(int argc, char *argv[])
{
    volatile unsigned char str[4]  = {0x02, 0x63, 0x00, 0x00};
    volatile unsigned char str2[4] = {0x02, 0x63, 0xEC, 0x00};
    unsigned char crc = lin_crc((unsigned char*)str, 4);
    unsigned char crc2 = lin_crc((unsigned char*)str2, 4);
    // Печать результата
    printf("\nmes:  ");
    for (int i = 0; i < 4; i++)
        printf("%02X ", str[i]);
    printf("\n lin_crc = %02X \n", crc);
    // Печать результата 2
    printf("\nmes2:  ");
    for (int i = 0; i < 4; i++)
        printf("%02X ", str2[i]);
    printf("\n lin_crc = %02X \n", crc2);
    getch();
    return 1;
}