
В любительском и не очень профессиональном сегменте авто-мото спорта многие используют приложение RaceChrono для записи телеметрии и хронометража. Если кратко, то RaceChrono позволяет решить 2 задачи:
Хронометраж. Отсечка времени по кругам или по линии старта и финиша. Приложение позволяет в "онлайне", прямо во время движения, видеть опережение или отставание от лучшего времени. Прямо как в компьютерной игре.
Запись телеметрии (траектории движения, параметров работы автомобиля) и последующий их просмотр для анализа. Так же можно наложить отображение нужных параметров на видео.
Как правило, для решения этих задач используют 2 отдельных устройства: внешний GPS приемник и CAN-адаптер. И то и другое выпускается промышленно и доступно для покупки.
Я сделал небольшое устройство, которое сочетает в себе сразу всё необходимое: GPS на 25 Гц и CAN интерфейс.
Железо
Выбор GPS приемника.
Внешний GPS приемник нужен для более высокой частоты обновления позиции. В мобильном телефоне уже есть GPS приемник, только его частота обновления 1 Гц, он выдает координаты 1 раз в секунду. Если автомобиль движется со скорость 100 км/ч, за 1 секунду он проходит 27 метров. Хотелось бы получать траекторию движения более точно.
Большинство доступных для покупки bluetooth GPS приемников имеют частоту обновления 10 Гц.
Я использовал модуль Ublox M9N, который, согласно его описанию, при использовании GPS+GLO+GAL выдает координаты 25 раз в секунду. Модуль относительно не дорогой и его можно приобрести. Документация у Ublox вполне хороша, есть и hardware integration manual и описание протокола. Кроме стандартного NMEA приемники Ublox работают по собственному бинарному протоколу, который значительно удобнее разбирать со стороны микроконтроллера.
Выбор микроконтроллера
Поддержка "самоделок" в RaceChrono была реализована достаточно давно. Используя классический Bluetooth можно было слать сообщения в формате RC2 и RC3. Набор параметров там ограничен, но это лучше, чем ничего.
Относительно недавно автор добавил новый способ подключения "самоделок", через BLE. Новый API рассчитан в первую очередь на подключение GPS приемников и CAN адаптеров. Есть так же возможность наоборот, получать данные из RaceChrono к себе в устройство, для создания каких-то мониторов.
Поскольку нужна была работа с BLE, выбор микроконтроллеров был не очень широким. Я предпочитаю STM32, но контроллеров с поддержкой BLE в количестве нескольких штук было не купить. Поэтому был выбран nRF52840.
Документация у Nordic похуже чем у ST, но в целом вполне достаточно. Чтобы немного облегчить себе жизнь, я решил использовать не голый МК, а в виде готового модуля Ebyte E73-2G4M08S1C. Больше всего мне не хотелось заниматься расчетом и разводкой радио части. Модуль не сильно больше по размерам чем голый МК + обвязка и купить его можно без проблем.
Выбор CAN интерфейса
К сожалению у nRF52840 нет CAN интерфейса. Поэтому пришлось использовать внешний. Выбрал самый популярный и легко доступный, mcp2515. Отдельно микросхем или в наличии не было или стоимость была неадекватной, поэтому проще оказалось купить на али готовые модули и снять с них микросхему и заодно кварц. На модуле используется 5 вольтовый трансивер, на нем сэкономить не получилось, использовал SN65HVD230.
Схема



Схема устройства и весь проект в KiCad, а также список комплектующих и файлы для производства лежат на GitHub.
Программная часть
Для своих МК Nordic предоставляет SDK. Я использовал сборку при помощи GCC через Makefile. В целом, вполне понятный HAL.
Для упрощения себе жизни, я использовал в проекте FreeRTOS. Сама RTOS уже есть в SDK, поэтому можно сказать всё было готово для использования "из коробки".
С BLE я раньше не сталкивался. Протокол оказался достаточно обширным. Кроме того, сам стек BLE у Nordic закрыт. Он прошивается во флеш отдельно и основная прошивка вызывает нужные функции по заранее определенным адресам. Это называется softdevice. Для "пользователя" это достаточно прозрачно, надо лишь помнить, что часть аппаратных ресурсов (таймеры, прерывания) используется внутри softdevice.
Работа с BLE сделана по примеру от Nordic - nRF52 Bluetooth Course.
Некоторые сложности возникли только, как ни странно, с UART. Вроде не сложный блок периферии, но завести удалось совсем не сразу. В SDK есть несколько драйверов для UART. Я сначала пробовал те, что попроще, но при скорости обмена выше 33600 начинались переполнения приемного буфера и мусор в принимаемых данных. В какой-то момент я решил вообще отказаться от использования HAL нордика и сделать свою реализацию. Тут оказалось, что ничего похожего на reference manual от ST, где описаны все регистры, все режимы работы и все последовательности инициализации у Nordic нет. Есть описание регистров, но без особых подробностей. Наиболее наглядным было изучение внутренностей HAL. В итоге, использовал драйвер libuarte из SDK и все заработало без ошибок на 115200.
С SPI и mcp2515 никаких проблем не возникло. В драйвере mcp2515 я реализовал только тот минимум, который был нужен мне. Прием работает по прерыванию с ноги INT.
API RaceChrono предполагает, что пересылаться будут напрямую CAN пакеты. Причем зарезервированы места даже для Extended ID, которых в живую я ни разу не видел. Предполагается следующая схема работы: устройство получает CAN пакет, пересылает его через BLE, а уже приложение RaceChrono на мобильном устройстве извлекает из данных пакета нужные параметры.
Чтобы увеличить частоту обмена, я сделал иначе. Я собираю все нужные параметры у себя на устройстве, складываю их максимально плотно в один пакет и уже его отправляю по BLE. Это позволяет пересылать меньше "пустых" данных и увеличить частоту обновления.
Я реализовал разбор 2 CAN протоколов. Во-первых это протокол adlm для блоков управления "Абит М11 Корвет". У производителя есть подробное описание протокола.
Во-вторых, это очень базовая реализация протокола ODBII. Дело в том, что заниматься отладкой на спортивном автомобиле и дорого и неудобно. Поэтому отлаживал я на повседневном автомобиле. Реализовано получение лишь нескольких базовых параметров (обороты, температура, дроссель).
Прошивка также доступна на GitHub.
Тестовый образец выглядит вот так:

Для тестов использовал самую дешевую gps антенну с али. Крепится на магните на крышу автомобиля. Корпус сделан на 3D принтере с расчетом под отладку (есть доступ к SWD разъему). Кабель для подключения к ODB разъему (используется 12В, GND, CAN-Hi, CAN-Low).
Ну и пример работы:
На видео в параметре "Частота обновления" два значения. Верхнее это обновление GPS данных (постоянно 25 Гц), нижнее это обновление данных из CAN. Частота CAN немного плавает около 18-20 Гц, но думаю это решаемо программно. Само приложение RaceChrono запущенно на телефоне, который на стекло прилеплен.
Что не реализовано.
Можно было бы реализовать поддержку K-Line. На мотоциклах (в частности у Honda) используется протокол аналогичный KWP2000. Можно собирать данные с K-линии, складывать в CAN пакет и отправлять в RaceChrono. Я не уверен, насколько это вообще кому-то нужно, поэтому поленился делать.