Для одного проекта мне понадобилось сделать сниффер шины LIN. Для тех кто не знает, сниффер (от англ. sniff — нюхать) это устройство для перехвата данных.
Про LIN шину я как-нибудь расскажу в отдельной статье. А если кратко, то LIN-шина это почти тот же UART, только с напряжением высокого уровня 12В. Чаще всего применяется в современных автомобилях, в тех местах, где использование CAN шины слишком избыточно. Например, LIN шина часто используется в дверях автомобилей для управления локальными блоками: стеклоподъемником, поворотниками на боковом зеркале, мотором складывания боковых зеркал, положением зеркала и прочей локальной электроникой.
LIN-шина является полудуплексной шиной, то есть по этой шине нельзя одновременно передавать и принимать данные. В единицу времени можно
или передавать или принимать данные.
LIN-шина так же является однопроводной. То есть, состоящей из одного сигнального провода. В этом отношении она напоминает шину 1-wire. И так же как и в шине 1-wire, в LIN шине есть одно ведуще устройство (master) и одно или несколько ведомых (slave)
Для работы с LIN шиной я решил использовать микроконтроллер из семейства STM8. Конкретно я выбрал STM8S105K4T6. Почему именно этот микроконтроллер? Во-первых, в нем уже есть встроенный модуль для работы с этой шиной. А во-вторых, именно на этом микроконтроллере уже был разработан контроллер, которому и предстояло взять на себя функцию сниффера шины.
Для того что бы познакомится с LIN шиной я решил сначала написать тестовый код передатчика, который бы имитировал работу master-блока на шине. Код создавался в среде IAR
Итак, для тестирования кода для работы с LIN шиной использовался вот такой код:
int main( void ) { CLK_CKDIVR_bit.HSIDIV = 0; // частота 16 МГц UART2_BRR1 = 0x68; // скорость 9600 at 16 MHz UART2_BRR2 = 0x03; UART2_CR3_LINEN = 1; // Разрешение работы LIN UART2_CR2_TEN = 1; // Разрешение передатчика UART2_CR2_REN = 1; // Разрешение приемника while(1){ _delay_ms(500); UART2_CR2_SBK = 1; // Отправка start импульса outUart(0x55); // Отправка поля синхронизации outUart(0x2E); // И еще нескольких байт outUart(0x09); outUart(0x03); outUart(0x00); outUart(0x00); outUart(0xF6); } } void outUart(uint8_t data){ // Передача байта через UART while(UART2_SR_TC == 0) {}; // Ожидание завершения передачи UART2_DR = data; // Отправка байта }
В заголовочном файле iostm8s105k4.h есть вот такие структуры
typedef struct { unsigned char SBK : 1; unsigned char RWU : 1; unsigned char REN : 1; unsigned char TEN : 1; unsigned char ILIEN : 1; unsigned char RIEN : 1; unsigned char TCIEN : 1; unsigned char TIEN : 1; } __BITS_UART2_CR2;
При помощи этих структур и вот таких объявлений:
#define UART2_CR2_SBK UART2_CR2_bit.SBK #define UART2_CR2_RWU UART2_CR2_bit.RWU #define UART2_CR2_REN UART2_CR2_bit.REN #define UART2_CR2_TEN UART2_CR2_bit.TEN #define UART2_CR2_ILIEN UART2_CR2_bit.ILIEN #define UART2_CR2_RIEN UART2_CR2_bit.RIEN #define UART2_CR2_TCIEN UART2_CR2_bit.TCIEN #define UART2_CR2_TIEN UART2_CR2_bit.TIEN
очень удобно обращаться к отдельным разрядам регистров.
Сделать это можно вот так:
UART2_CR2_TEN = 1; // Установить бит TEN в регистре UART2_CR2 UART2_CR2_TEN = 0; // Сбросить бит TEN в регистре UART2_CR2
Запускаю код на тест, подключаюсь логическим анализатором и вижу вот такую картину:
Да что за дичь такая?!
И почему пакет не распознается логическим анализатором?
Понятно, что с пакетом что-то не то, но хотя бы стартовый импульс шины должен же был распознаться?
В общем, дальше было тщательное изучение документации, errata sheet (документа с описание ошибок работы микроконтроллера) и около одного часа разных экспериментов.
При очередном этапе отладки я обратил внимание на ассемблерную команду в окне отладки, которая соответствует строке
UART2_CR3_LINEN = 1;
Обратите внимание, что в строке при помощи команды BSET происходит установка 7 разряда регистра UART2_CR3:
Но, так быть не должно!
Судя по документации в регистре UART2_CR3 бит LINEN это 6-ой бит.
Решаю закомментировать строку UART2_CR3_LINEN = 1; и вместо неё прописываю явное указание на установку 6 разряда UART2_CR3 |= 1<<6;
И, наконец, все заработало!
А причина оказалась там, где я и не ожидал.
В файле описаний iostm8s105k4.h была ошибка в указании
номера бита LINEN.
Правильно структура должна выглядеть вот так:
После исправления файла описания, программа со строкой UART2_CR3_LINEN = 1; наконец, заработала!
Самое интересное, что согласно документации бит 7 зарезервирован. Но, при этом есть пометка: Reserved, must be kept cleared. То есть, бит 7 обязан быть сброшенным!
Вот так незначительная ошибка в файле описаний может надолго заставить задуматься.
Одно радует, подобные ошибки в файлах описаний встречаются достаточно редко.