Simple verilog project with ability to connect to GPS module using UART and parse NMEA coordinates using finite state machine
GPS трекер на ПЛИС. Подключить модуль GPS к ПЛИС, реализовать считывание получаемых координат о местоположении устройства и их накопление в памяти ПЛИС. Реализовать передачу хранимых координат на компьютер через UART соединение (USB) и индикацию текущих координат на внешнем дисплее или и 7-сегментном индикаторе.
GPS модуль neo-6 поддерживает три протокола:
А также три интерфейса для передачи данных:
В нашей работе использовалась связка протокола NMEA и интерфейса UART.
NMEA 0183 – стандарт определяющий текстовый протокол связи навигационного оборудования, особенно популярен в модулях GPS приемников, по нескольким причинам:
Формат сообщений NMEA 0183:
Максимальная длина сообщения ограничена 82 символами.
В данной работе обрабатывалось одно NMEA сообщение – GPGLL (Geographic Position Latitude/Longitude)
Формат сообщения GPGLL:
$GPGLL,DDMM.MMMMM,S,DDDMM.MMMMM,S,HHMMSS.SS,S*CC
Пример сообщения:
$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 фиксирует ошибку.
Для обработки сообщений с GPS модуля был разработан простой конечный автомат:
Стартовое состояние (состояние покоя) – автомат ожидает сигнала от UART модуля, сообщающего что получены данные и по приходу этого сигнала проверяет данные, если пришло “$” – переходит в следующее состояние:
Состояние сохраняет полученные с UART данные в массив NMEA[23:0] пока не встретит “,”. Когда автомат встречает запятую он проверяет условие NMEA == “GLL”, т.е. пришла ли необходимая команда и если условие выполняется – переходит в следующее состояние. Если с GPS модуля пришла другая команда – автомат возвращается в стартовое состояние
В массив NMEA сохраняются только последние три байта полученные с UART, т. к. именно они определяют тип сообщения, а остальная информация не требуется
В нашем случае это состояние просто ждало “,” и переходило в следующее состояние:
Данный конечный автомат удобен тем, что его можно легко масштабировать – можно улучшать обработку команды GPGLL и добавлять обработку новых команд – для добавления поддержки других команд необходимо просто добавить в состояние “ReadCMD” переход по другой полученной команде, вставить конечный автомат обрабатывающий параметры этой команды и конечное состояние этого обработчика связать с состоянием “Start” переходом по “\
В нашем случае обрабатывались только первые три байта координаты широты и долготы по техническим причинам, однако увеличить точность обработки достаточно просто – для этого необходимо увеличить переменную “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). Как только модуль связался со спутником (об этом сигнализирует мигание синего индикатора) плата начала выводить правильные координаты: