GPS трекер на ПЛИС. Подключить модуль GPS к ПЛИС, реализовать считывание получаемых координат о местоположении устройства и их накопление в памяти ПЛИС. Реализовать передачу хранимых координат на компьютер через UART соединение (USB) и индикацию текущих координат на внешнем дисплее или и 7-сегментном индикаторе.
GPS модуль neo-6 поддерживает три протокола:
- NMEA – самый популярный протокол, передает данные в текстовом виде (колировка 8- битный ASCII), I/O
- UBX – проприетарный протокол компании u-blox, передает данные в бинарном формате, I/O
- RTCM – открытый протокол, I
А также три интерфейса для передачи данных:
- UART
- USB
- DDC
В нашей работе использовалась связка протокола NMEA и интерфейса UART.
NMEA 0183 – стандарт определяющий текстовый протокол связи навигационного оборудования, особенно популярен в модулях GPS приемников, по нескольким причинам:
- Сообщения легко обрабатывать, за счет их простой структуры
- Каждое сообщение занимает мало памяти
- Сообщения передаются в текстовом, а не в бинарном виде, поэтому необработанное сообщение удобно читать человеку
- Протокол можно потенциально расширить новыми типами сообщений
- Каждое сообщение передает свою контрольную сумму, что позволяет проверять корректность принятого пакета
Формат сообщений NMEA 0183:
- "$" – маркер начала сообщения
- 5-буквенный идентификатор сообщения, определяет тип передаваемого сообщения:
- Первые две буквы – идентификатор источника сообщения, в случае GPS модуля это всегда "GP"
- Последние три буквы – тип сообщения
- Список данных сообщения. Количество и формат этих данных зависит от сообщения, однако для передаваемой информации обязательны следующие признаки:
- Все данные разделяются запятыми – ","
- В случае отсутствия каких-либо данных в сообщении запятые все равно ставятся (возможна ситуации по типу ",,,") – количество запятых в определенном типе сообщения постоянно и не зависит от данных, это сделано для упрощения процесса обработки сообщения
- "*" – маркер начала контрольной суммы
- 2 символа контрольной суммы – контрольная сумма считается как XOR-сумма всех символов между "$" и "*" не включительно. Полученная сумма представляется в шестнадцатеричном виде в двух ASCII символах (буквы передаются в верхнем регистре)
- "<CR><LF>" – 2 символа, маркирующих конец сообщения:
- <CR> – ASCII carriage return, шестнадцатеричное значение – 0D
- <LF> – ASCII line feed, шестнадцатеричное значение – 0A
Максимальная длина сообщения ограничена 82 символами.
В данной работе обрабатывалось одно NMEA сообщение – GPGLL (Geographic Position Latitude/Longitude)
Формат сообщения GPGLL:
$GPGLL,DDMM.MMMMM,S,DDDMM.MMMMM,S,HHMMSS.SS,S*CC
- $GPGLL – идентификатор сообщения
- Координата широты
- Буква N (север) или S (юг)
- Координата долготы
- Буква E (восток) или W (запад)
- Текущее UTC время в данной позиции
- Статус сообщения:
- A – валидные данные
- V – некорректные данные (такой статус выставляется например когда GPS модуль еще не подключился к спутникам)
- Контрольная сумма
- <CR><LF>
Пример сообщения:
$GPGLL,3723.2475,N,12158.3416,W,161229.487,A*2C
UART – универсальный асинхронный приемопередатчик. Преобразует передаваемые данные в последовательный вид так, чтобы было возможно передать их по одной физической цифровой линии другому аналогичному устройству.
Передача данных в UART осуществляется по одному биту в равные промежутки времени. Этот временной промежуток определяется заданной скоростью UART и для конкретного соединения указывается в бодах (что в данном случае соответствует битам в секунду). Существует общепринятый ряд стандартных скоростей: 300; 600; 1200; 2400; 4800; 9600; 19200; 38400; 57600; 115200; 230400; 460800; 921600 бод. Скорость (S) и длительность бита (T) связаны соотношением T=1/S.
Помимо информационных бит, UART автоматически вставляет в поток синхронизирующие метки, так называемые стартовый и стоповый биты. При приёме эти лишние биты удаляются из потока. Обычно стартовый и стоповый биты обрамляют один байт информации (8 бит), при этом младший информационный бит передаётся первым, сразу после стартового. Обрамленные стартом и стопом биты являются минимальной посылкой. Некоторые реализации UART используют два стоповых бита при передаче для уменьшения вероятности рассинхронизации приёмника и передатчика при плотном трафике.
Принято соглашение, что пассивным (в отсутствие потока данных) состоянием входа и выхода UART является логическая 1. Стартовый бит всегда логический 0, поэтому приёмник UART ждёт перепада из 1 в 0 и отсчитывает от него временной промежуток в половину длительности бита (середина передачи стартового бита). Если в этот момент на входе всё ещё 0, то запускается процесс приёма минимальной посылки. Для этого приёмник отсчитывает 9 битовых длительностей подряд (для 8-битных данных) и в каждый момент фиксирует состояние входа. Первые 8 значений являются принятыми данными, последнее значение проверочное (стоп-бит). Значение стоп-бита всегда равно 1. Если реально принятое значение иное, UART фиксирует ошибку.
- Плата Terasic DE10-Lite (использует Intel MAX 10)
- GPS модуль GY-GPS6MV2
- Керамическая антенна для GPS
- Breadboard и провода
- Плата Arduino и преобразователь напряжения (для проверки алгоритмов и их отладки)
- Компьютерс Intel Quartus Prime Lite 16.1
Для обработки сообщений с GPS модуля был разработан простой конечный автомат:
- Стартовое состояние (состояние покоя) – автомат ожидает сигнала от UART модуля, сообщающего что получены данные и по приходу этого сигнала проверяет данные, если пришло "$" – переходит в следующее состояние:
- Состояние сохраняет полученные с UART данные в массив NMEA[23:0] пока не встретит ",". Когда автомат встречает запятую он проверяет условие NMEA == "GLL", т.е. пришла ли необходимая команда и если условие выполняется – переходит в следующее состояние. Если с GPS модуля пришла другая команда – автомат возвращается в стартовое состояние
В массив NMEA сохраняются только последние три байта полученные с UART, т. к. именно они определяют тип сообщения, а остальная информация не требуется
- Данное состояние обрабатывает координату широты – оно записывает первые три ASCII байта с координатами в массив LAT[23:0]. Как только это состояние встречает символ запятой – оно переходит в следующее состояние
- В данном состоянии можно обрабатывать значение север/юг широты. Используемая плата имеет всего 6 семисегментных индикаторов, на 3 из которых выводилась координата широты, а на 3 других – координата долготы – поэтому значения север/юг широты и восток/запад долготы не обрабатывались, т.к. их некуда выводить, однако добавить их обработку не составит труда, т.к. состояние для этих случаев уже разработано и нужно просто записать полученные данные в желаемую переменную.
В нашем случае это состояние просто ждало "," и переходило в следующее состояние:
- Данное состояние обрабатывает координату долготы – принцип работы такой же, как и у обработчика координаты широты. Как только встречается символ переноса строки – происходит переход в стартовое состояние – данные которые идут далее нам не интересны
Данный конечный автомат удобен тем, что его можно легко масштабировать – можно улучшать обработку команды GPGLL и добавлять обработку новых команд – для добавления поддержки других команд необходимо просто добавить в состояние "ReadCMD" переход по другой полученной команде, вставить конечный автомат обрабатывающий параметры этой команды и конечное состояние этого обработчика связать с состоянием "Start" переходом по "<LF>".
В нашем случае обрабатывались только первые три байта координаты широты и долготы по техническим причинам, однако увеличить точность обработки достаточно просто – для этого необходимо увеличить переменную "precision" до необходимого значения точности.
Увеличить размерность массивов LAT и LON – необходимо по одному байту на каждую цифру точности. А также исправить заполнение этих массивов в состояниях "ReadLAT" и "ReadLON":
Для отображения шестнадцатеричных значений на семисегментом индикаторе использовался модуль "hex7seg":
Т. к. с GPS модуля мы получали каждую координату в 1 байте ASCII символа, а один семисегментный индикатор выводит только половину байта, мы использовали простой прием, основанный на особенности кодов цифр в ASCII таблице – все цифры от 0 до 9 выражены кодами от 0x30 до 0x39, причем ASCII код каждой цифры оканчивается именно на эту цифру:
Поэтому мы передавали на семисегментный индикатор только вторую половину каждого байта координаты, т. к. именно вторая половина содержала необходимую для вывода информацию, а первая половина байта всегда хранила 0x3 (в случае, когда байт представлял цифру):
Сборка устройства не составила особого труда – плата была подключена к компьютеру с установленным Quartus, GPS модуль был подключен к breadboard, землю и питание платы (3.3 В) отправили также на breadboard, а оттуда к соответствующим пинам GPS модуля. Пины RX и TXGPS модуля были отправлены на GPIO[34] и GPIO[35] соответственно. В коде программы все необходимые номера пинов были установлены в PinPlanner и далее использованы в логике программы.
Для проверки корректности работы UART модуля и модуля обработки GPS координат использовалась плата Arduino на которой была запущена простая программа, которая в зависимости от напряжения на одном из пинов переходила в состояние отправки или приема данных. В случае отправки данных плата просто писала полученные данные в лог, в случае, когда была установлена конфигурация отправки данных – плата отправляла тестовое NMEA сообщение GPGLL на плату:
Т. к. Arduino и DE10-Lite используют разное напряжение для передачи логической единицы – 5В и 3.3В соответственно, был использован преобразователь напряжения для связывания этих двух устройств.
Плата успешно подключилась к GPS модулю и стала получать оттуда сигналы, выданный нам GPS модуль требует достаточно много для подключения к спутникам (может быть больше 40 минут, точное время в нашем случае не замерялось, для уменьшения времени подключения можно поменять антенну).
Пока GPS модуль не был подключен к спутнику он отправлял пустые GPGLL команды, в которых не было координат, а флаг корректности результата был установлен в состояние V (invalid). Как только модуль связался со спутником (об этом сигнализирует мигание синего индикатора) плата начала выводить правильные координаты: