Программный USB на микроконтроллерах STM8
В один прекрасный момент в меня засела мысль “а можно ли реализовать программный USB на микроконтроллерах STM8, по аналогии с V-USB для AVR микроконтроллеров”.
И не знаю почему, но я занялся данной реализацией (правда, запала хватило не до конца , но об этом далее).
На сколько мне известно первым реализовал данный протокол на АВР-ах Инженер Игорь Чешко (Igor Cesko)), в последствии Atmel опубликовала документ AVR309: Software Universal Serial Bus (USB) (читать перевод на русский).
Игорем был реализован прием данных в кодированном виде с последующим анализом, а в V-USB уже декодирование NRZI и выборка незначащих бит происходит “на лету”.
(Если я где-то ошибся прошу сильно не пинать, я не очень сильно углубился в данную тему).
К сожалению прямой перенос кода с AVR на ATM8 не возможен ввиду отличий архитектуры и набора команд.
Основные проблемы STM8 с которыми я столкнулся:
- малое число регистров (основная часть операций доступна только для регистра А)
- трехуровневый конвейер
- неопределенное время вхождения в обработчик прерывания (9 циклов на сохранения контекста и от 1 до 6 на завершение команд)
Конвейер доставляет больше всего проблем, однозначно сказать сколько тактов будет выполнятся тот или иной код не возможно.
Время выполнения зависит от состояния конвейера на начало выполнения кода и расположения команд в памяти.
Микроконтроллер
В качестве подопытного я выбрал микроконтроллер STM8S103F3 (нацелился использовать STM8S003 ).
Хотя можно использовать любой из серии STM8L, STM8S.
Тактирование от “внешнего кварца” на 12 МГц, частота делится кратно с тактовой USB (8 тактов на один бит).
Линии USB подключены напрямую к PC7 и PC6.
Передача данных
Разумнее было начать с формирования сигналов (передачи), чтобы было легче отлаживать код приемника, передавая свои данные, а не захватывать данные с работающей USB шины.
Для формирования дифференциальных сигналов я задействовал две линии порта С, но занят весь порт целиком, т.е. другие его линии нельзя использовать во время приема и передачи данных.
Первоначально я реализовал передачу без кодирования в NRZI и вставкой пустых бит, но позже у меня получилось делать это на лету, без предварительной подготовки данных.
Алгоритм формирования сигналов:
Давно не рисовал алгоритмы, возможно некоторые элементы неправильно нарисовал.
Кратно по алгоритму:
- Регистр А используется только для отсчета переданных подряд единиц
- Выходной сигнал формируется только путем инверсии выходных состояний сразу всех линий порта С
- После передачи всех данных, длительность формирования сигнала конец пакета складывается из времени выхода из подпрограммы передачи и выполнения дополнительных операций, возможно лучше переключать линии на выход и формировать длительность сигнала “конец пакета” с последующим переводом линий на вход в данной подпрограмме.
В коде передатчика очень много пустых команд “nop”, часть из них используется для выравнивания кода во флеш-памяти, остальная для формирования задержек (уж очень быстро работает микроконтроллер ) суммарно почти 50% от общего числа команд.
После написания кода приемника появилось больше знаний и практики в ассемблере STM8 и некоторые моменты можно было сделать проще и красивее, но на данном этапе не вижу смысла что-то править.
Для постоянства формирования интервалов код должен быть расположен в фиксированном месте флеш-памяти, я думаю можно перемещать, но только с выравниванием по словам (сам не пробовал).
На текущий момент код передатчика занимает порядка 300 байт.
На сегодня все, дальше будет самое интересное - код приемника.
comments powered by Disqus