Программный USB на микроконтроллерах STM8

20 Февраля 2014 К комментариям

В один прекрасный момент в меня засела мысль “а можно ли реализовать программный 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 и вставкой пустых бит, но позже у меня получилось делать это на лету, без предварительной подготовки данных.

Алгоритм формирования сигналов:

2014-02-21-Блок-схема-алгоритма-передачи

Давно не рисовал алгоритмы, возможно некоторые элементы неправильно нарисовал.

Кратно по алгоритму:

  1. Регистр А используется только для отсчета переданных подряд единиц
  2. Выходной сигнал формируется только путем инверсии выходных состояний сразу всех линий порта С
  3. После передачи всех данных, длительность формирования сигнала конец пакета складывается из времени выхода из подпрограммы передачи и выполнения дополнительных операций, возможно лучше переключать линии на выход и формировать длительность сигнала “конец пакета” с последующим переводом линий на вход в данной подпрограмме.

В коде передатчика очень много пустых команд “nop”, часть из них используется для выравнивания кода во флеш-памяти, остальная для формирования задержек (уж очень быстро работает микроконтроллер Улыбка) суммарно почти 50% от общего числа команд.

После написания кода приемника появилось больше знаний и практики в ассемблере STM8 и некоторые моменты можно было сделать проще и красивее, но на данном этапе не вижу смысла что-то править.

Для постоянства формирования интервалов код должен быть расположен в фиксированном месте флеш-памяти, я думаю можно перемещать, но только с выравниванием по словам (сам не пробовал).

На текущий момент код передатчика занимает порядка 300 байт.

На сегодня все, дальше будет самое интересное - код приемника.



comments powered by Disqus