USB Host контроллер VinculumII. Запись на Flash.

Что такое USB Host контроллер?
Связь по USB происходит по принципу Главный-Подчинённый. В качестве подчиненных (USB Slave) обычно выступают периферийные устройства такие ка флешки, принтеры, клавиатуры, разрабатываемые электронщиками устройства и прочее. В качестве Главного (USB Host) обычно выступают компьютеры.

Если нам нужно передать информацию от нашего устройства на компьютер, то для реализации USB протокола подойдут как внешние микросхемы преобразователей, так и собственные средства самого контроллера. Но вот если данные нужно передать на флешку, то тут уже необходимо воспользоваться USB-Host контроллером. Можно воспользоваться контроллерами с внутренним USB-Host (например PIC24), ну или воспользоваться специальной микросхемой. Одну такую микросхему и рассмотрим — FTDI VinculumII.

FTDI VinculumII — это второе поколение USB-Host контроллеров в семействе Vinculum. Первая версия хоть и работала, но не слишком удалась. Поэтому FTDI выпустила вторую версию микросхемы, учтя все недостатки и прокачав в целом всю микросхему. В итоге мы имеем:

  • 16-разрядное процессорное ядро, выполненное по Гарвардской архитектуре;
  • два блока USB, которые могут выполнять функции периферийного устройства или хост-контроллера;
  • 256 кбайт флэш-памяти размером (128к х 16бит);
  • 16 кбайт ОЗУ (4к х 32бита);
  • набор интерфейсных модулей (UART, 2 SPI slave, SPI master, параллельный 8? разрядный FIFO, ШИМ, отладочный интерфейс);
  • внешний кварц на 12МГц (частота ядра 12, 24, 48 МГц);
  • мультиплексор, предназначенный для коммутации внутренних блоков контроллера и внешних выводов;
  • микросхемы доступны в корпусах LQFP и QFN с количеством выводов для каждого типа 32, 48 и 64.

 
Здесь хотелось бы поподробнее остановиться на мультиплексоре выводов микросхемы. Он позволяет подключать интерфейсные линии от различных протоколов к различным ногам контроллера (например одну и туже линию можно подключить с разных сторон контроллера). Это очень упрощает разводку платы. Да и к тому же если каждую интерфейсную линию выводить на отдельную ногу, то понадобилось бы слишком много ног, учитывая обилие интерфейсов в данном контроллере. Второй особенностью мультиплексора является работа с портами ввода-вывода, которые можно настроить не только как вход/выход, но и установить рабочий ток вывода, Pull-up или Pull-down, и даже Триггер Шмидта.

Что же имеем в сухом остатке. Отличная микросхема имеющая большОе количество различных интерфейсов, позволяющая построить различные комбинации преобразователей (мостов) интерфейсов. Главная особенность микросхемы наличие USB-Host, позволяющей работать с флешками.

И вот теперь, когда мы такие радостные, думаем сколько удивительных девайсов можно на ней сделать, пора вкусить правду-матку.

 

Первый сюрприз который нас ожидает — микросхема поставляется БЕЗ ПРОШИВКИ (NOTE: VNC2 devices are supplied unprogrammed). Для того что прошить микросхему необходим специальный VNC2 Debug Module. Здесь есть выбор либо купить фирменный (около 1100 руб), или же изготовить самостоятельно, ибо схема есть в даташите. Я решил взять готовый модуль (хорошо что деньги не мои ;)))
Выглядит вот так.

Тут нужно упомянуть еще один момент — модуль имеет выходной разъем PBS-2.0, а на своей плате я использовал более родной PLS-2.54. Поэтому пришлось изготовить небольшой переходник.

Изолентой заклеен один маленький, но ОЧЕНЬ мерзкий светодиодик.

 

Сюрприз номер два — микруха работает на собственной операционной системе реального времени (RTOS VOS), соответственно и все прошивки для нее необходимо писать с использованием этой RTOS.

 

Сюрпризик номер три — напрямую работать с ресурсам и контроллера не возможно. Чтобы обратиться к чему либо необходимо использовать API-функции и драйверы, поставляемые производителем в закрытом виде. Все что нам доступно — это файлы инклудов, в которых можно посмотреть какие есть функции и как к ним обратиться.

 

Ну и самый большой сюрприз (и самый большой минус) это среда разработки (IDE). Более убогой, тупой, и неудобной среды я не видел уже давно. Если бы компания FTDI располагалась в России, то «программистами» там бы работали внучатые племянники главного бухгалтера и начальника отдела кадров, этакие «супер-пупер-школоло-программеры». Это отличный пример того как хорошую аппаратную часть наглухо губит программное обеспечение. Сам от себя не ожидал сколько новых матерных оборотов могу я придумать пока не увидел ЭТО IDE.

За пару часов работы были замечены следующие фишки этого «ПО»:

  • полностью неудобный вкладочный интерфейс. Имея такое небольшое количество функций можно было их расположить на одной панели, чтобы не приходилось бегать по вкладкам;
  • минимальное количество настроек самой программы, и отсутствие необходимых настроек (например постоянный запрос на пере-сохранение файлов);
  • на редкость тормознутый интерфейс, например вызов меню по правой кнопки мыши (для COPY/PASTE) занимает от 1 до 2 секунд;
  • постоянные и многочисленные запросы на сохранение файлов и прочее. Причем не все из них срабатывают по кнопке Enter, хотя кнопка и подсвечена все равно придется клацать по ней мышкой;
  • при отладке не отображается место выполнения программы. Даже если поставить на паузу выскочит дизасемблинг программы, а не место останова программы в си-листинге;
  • просмотр значений переменных возможно только в месте ее обработки, что становится проблематичным, так как нет отображения места выполнения программы. Для того чтобы поймать переменную нужно постоянно нажимать Старт-Пауза и надеяться на то что переменная отобразится, а учитывая общую тормознулось интерфейса этот процесс мягко говоря ………………………!!!!!
  • просмотр переменных возможен только в HEX и DEC виде. Просмотр переменной в двоичном виде ОЧЕНЬ БЫ НЕ ПОМЕШАЛ!!!!
  • вероятность того что сработает установленный Breakpoint крайне мала!!! Например, в программе которая просто мигает светодиодом я наставил 3 бряка и так и не дождался их отработки хотя светодиодик исправно себе моргал!!! Опять же данная фишка сводит на нет все попытки посмотреть значение переменных. Единственную закономерность для срабатывания бряков которую удалось уловить — так это расстановка бряков с последующей компиляцией проекта (даже если ничего не менялось, а просто добавился новый бряк). Бряки поставленные во время отладки не срабатывают, да и просто иногда не ставятся и не отключаются;
  • ввиду всего вышесказанного невозможно определить состояние переменных во время зависания прошивки или при выполнении «вечного цикла» в конце программы;
  • ну и самое интересное — настройка вывод производится через wizard (IOMUX). Результат настройки записывается в специальный файл. Так вот если закрыть программу, запустить, снова зайти в wizard, то настраивать все выводы придется по новой. Поэтому либо настраивать все ноги изначально правильно и больше туда не лезть, либо при попытке, например, изменить направление одного пина, придется все настройки производить по новой!!!
  • имеющиеся примеры прошивок мало применимы в реальной жизни, так как неполноценны и однобоки. Но с этим еще можно мириться ведь это примеры. Но вот с тем, что примеры содержат ошибки мириться нельзя.

 
Плюсуем сюда еще кучу мелких и тупых недочетов на которые уже тупо забиваеш со временем.

Вот такая вот «среда разработки».

 

Просто эксперимент.
Перед началом хотелось рассказать еще об одной забавной фиче. Не буду рассказывать как я дошел до проведения данного опыта, но я решил проверить реальную частоту работы ядра микросхемы.

Для примера возьмём контроллер PIC16F876A, с внешним кварцем на 16 МГц. Как известно PIC16 делит внешнюю частоту на 4. Получаем частоту работы ядра — 4 МГц.

Закинем в контроллер программу-мигалку:

while(1) // вечный цикл
{
PORTB = 0b00000100; // зажечь светодиод
PORTB = 0b00000000; // погасить светодиод
}

Подключив осциллограф к RB2 получим вот такую картинку.

Частота переключений светика — 666653 Гц. Получается что на переключение требуется 6 тактов, Ну или 24 относительно кварца на 16 МГц.

Тот же самый опыт проведем с VinculumII.
Внешний кварц 12 МГц. Внутренняя частота 48 МГц.
Программка-мигалка:

while(1) // вечный цикл
{
vos_gpio_write_port(GPIO_PORT_A, 0b00000100); // зажечь светодиод
vos_gpio_write_port(GPIO_PORT_A, 0b00000000); // погасить светодиод
}

Получаем частоту переключений светика — 126142 Гц. Уж не знаю делит ли VinculumII частоту или нет, но получается что относительно внутренней частоты в 48 МГц на мигалку требуется 380 тактов О_о!!! Даже если рассчитывать относительно внешнего кварца в 12 МГц то потребуется 95 тактов!!! Это просто «ППЦ» какой-то!!!

После данного опыта отпал вопрос «Почему на такой большой скорости работы минимальная функция временной задержки 1 мС?».

Так что не только «средство разработки» тормозное, но и сам контроллер, по крайней мере в вопросе выполнения программы. Возможно аппаратные средства интерфейсов не такие тормознутые.

 

Пишем Firmware.
Первоначально я бы посоветовал пройти на сайт http://www.ftdichip.com/ и накачать оттуда даташитов, апнотов, примеров и прочего. Оттуда же тянем Vinculum II Toolchain 2.0 (SP1).

Также есть 3 статьи на русском, с более менее внятным объяснением основ.

  • Vinculum II — новый хост-контроллер USB от FTDI.
  • Vinculum II — с чего начать.
  • Vinculum II — с чего начать 2.

Статьи написаны видимо под раннюю версию IDE, но в принципе разобраться можно.

Для первоначального вкатывания в тему разберем процесс создания нового проекта и опробуем процесс записи на флешку на примере HelloWorld.

 

Для начала рассмотрим процесс создания нового проекта.

Запускаем Vinculum II IDE. Делаем New -> App Wizard Project.

Во вкладке New Project указываем Название проекта, Папку для сохранения, И название прибора (допустим).

На вкладке Target Module можно выбрать одну из отладочных плат, ну или как в нашем отдельную микросхему Discrete -> 32 Pin.

На вкладке Driver подключаем необходимые драйвера — USBHost2, GPIO Port A, FAT File System, BOMS (USBHost 2), stdio, string.

А вот и самая интересная вкладка IOMUX — управление мультиплексором портов. Выводы USB портов и питания помечены серым и не могут быть изменены. А вот линии портов или же каких-нибудь интерфейсов могут быть распределены по соответствующим ногам микросхемы.

Для примера закинем PORT_A.0 на 23 ногу, а PORT_A.2 на 31. Обе ноги настроим на выход (к ним подключены светодиоды) и подключим Pull-Up. Кроме направления здесь также можно задать его рабочий ток, скорость переключения, триггер Шмидта, подтяжки к питанию.

ВАЖНО!!! Лучше всего сразу все настроить правильно и не открывать больше данного Wizard’а. Так как если переоткрыть программу и зайти сюда опять, то все настройки портов сбрасываются и придется все настраивать заново. ХОТЯ ВСЕ ЭТИ НАСТРОЙКИ СОХРАНЯЮТСЯ В ОТДЕЛЬНЫЙ ФАЙЛ!!!

На вкладке Kernel ничего не трогаем. Объяснение здешних параметров есть в указанных ранее русскоязычных статьях.

Один момент — параметр CPU Speed устанавливает внутреннюю частоту микрухи. Основное назначение снижения внутренней частоты — это снижение тока потребления.

На вкладке Threads опять же ничего не трогаем.

Так как внутренняя RTOS многозадачная, то тут можно создать потоки и настроить из приоритет.

На вкладке Summary отображается результат всех наших действий.

Нажимаем кнопку Finish.

Если по какой то причине вы решите все же еще раз попасть в Wizard, то это можно сделать нажав кнопку Modify на панели File.

После того как отработает Wizard в окне Project Manager (слева) отобразиться куча файлов драйверов, автоматически подключенных к проекту. Здесь нас интересуют 3 последних файла.
В файле Project_2_iomux.c хранятся настройки портов.
В файлах Project_2.h и Project_2.c и будет содержаться наша программа.

Открыв файл Project_2.c мы увидим ОЧЕНЬ много автоматически сгенерированного кода, созданного на основе настроек Wizard’a. Если вкратце то автоматом создаются функции настройки RTOS, создания потоков, настройка периферии, работы с драйверами. Некоторое объяснение можно найти в упомянутых статьях.

ВАЖНО: Important: Sections between markers «FTDI:S*» and «FTDI:E*» will be overwritten by the Application Wizard.
Это означает, что нельзя ничего писать между тегами «/* FTDI:S* */» и «/* FTDI:E* */» ибо все что находится между ними может в любой момент переписано Wizard’ом. По личному опыту скажу что не только им — я так однажды большого куска кода недосчитался, хотя wizard я не запускал и код был расположен за пределами данных тегов.

Сейчас нас интересует место в конце файла.

/* Application Threads */

void firmware()
{
/* Thread code to be added here */

}

Именно в этой функции будет располагаться наш код. Название функции firmware() может быть и другим, оно указывается в wizard’е на вкладке Threads в столбце function.

Для начала переопределим переменную tx_buf, заменив на:

char *tx_buf = "01234567890123456789012345678901234567890123456789012345678901234";

Ну вот потому что надо мне записывать по 65 байт )))). Вы можете это и не делать.

На основе примера HelloWorld запишем следующее содержание функции. От оригинала она будет отличаться только работой со светодиодами и дополнительными комментариями.

void firmware()
{
FILE *file;

// подключить драйвера устройств
// USBhost, SPIslave, GPIO
open_drivers();

// Настроить выводы порта (0-вход, 1- выход)
vos_gpio_set_port_mode(GPIO_PORT_A, 0xFF); // все на выход
// хотя настройка портов производилась в IOMUX
// без данной строки все порты на ВХОД

do
{
// мигалка
vos_gpio_write_port(GPIO_PORT_A, 0b00000100); // зажечь светодиод
vos_delay_msecs(250);
vos_gpio_write_port(GPIO_PORT_A, 0b00000000); // погасить все
vos_delay_msecs(250);

// wait for enumeration to complete
// Ожидание подключения флешки
if (usbhost_connect_state(hUSBHOST_2) == PORT_STATE_ENUMERATED)
{
// Флешка подключена

// ОПРЕДЕЛЕНИЕ КЛАССА УСТРОЙСТВА
// ПОДКЮЧЕНИЕ BOMS ДРАЙВЕРА
hBOMS = boms_attach(hUSBHOST_2, VOS_DEV_BOMS);

if (hBOMS == NULL)
{
// Подключенное устройство НЕ соответствует
// классу USB MASS STORAGE
// BOMS НЕ подключен — ОБРАБОТКА ОШИБКИ
break;
}

// ПОДКЛЮЧЕНИЕ FAT ДРАЙВЕРА
hFAT_FILE_SYSTEM = fat_attach(hBOMS, VOS_DEV_FAT_FILE_SYSTEM);

if (hFAT_FILE_SYSTEM == NULL)
{
// FAT НЕ подлючен — ОБРАБОТКА ОШИБКИ
break;
}

// lastly attach the stdio file system to the FAT file system
// ПОДКЛЮЧИТЬ библиотеку stdio к файловой система FAT
fsAttach(hFAT_FILE_SYSTEM);

// now call the stdio runtime functions
file = fopen("TEST.TXT", "a+");

if (file == NULL)
{
// ОБРАБОТКА ОШИБКИ ОТКРЫТИЯ/СОЗДАНИЯ ФАЙЛА
break;
}

vos_gpio_write_port(GPIO_PORT_A, 0b00000001); // зажечь светодиод

if (fwrite(tx_buf, strlen(tx_buf), sizeof(char), file) == -1)
{
// ОБРАБОТКА ОШИБКИ ЗАПИСИ В ФАЙЛ
}

vos_gpio_write_port(GPIO_PORT_A, 0b00000000); // погасить все

if (fclose(file) == -1)
{
// ОБРАБОТКА ОШИБКИ ЗАКРЫТИЯ ФАЙЛА
}

fat_detach(hFAT_FILE_SYSTEM); // ОТКЛЮЧЕНИЕ FAT ДРАЙВЕРА
boms_detach(hBOMS); // ОТКЛЮЧЕНИЕ BOMS ДРАЙВЕРА

vos_gpio_write_port(GPIO_PORT_A, 0b00000001); // зажечь светодиод
vos_delay_msecs(100);
vos_gpio_write_port(GPIO_PORT_A, 0b00000000); // погасить все

vos_delay_msecs(3000); // задержка 3 секунд
}
} while (1);
}

Ах да! Тут нас ожидает первый прикол – хотя мы и настроили направление выводов без команды:
vos_gpio_set_port_mode(GPIO_PORT_A, 0xFF); // все на выходони останутся работать на вход. И ДА это не опечатка 0-вход, 1-выход.

Суть программы понятна из комментарием, но вкратце опишем ее так:

  • пока флешка не подключена, мигает светодиод на ноге PORT_A.2 (красный), с частотой 2 Гц;
  • когда подключается флешка происходит монтирование устройства, подключение раздела FAT, подключение библиотеки stdio, создание/открытие файла TEST.TXT (с установкой курсора в конец файла), производится запись тестовой строки в файл (для определения времени записи мигает белый светодиод на PORT_A.0), далее закрывается файл, размонтируется FAT и BOMS. В конце этого цикла белый светодиод зажигается на 100 мС. Потом следует пауза в три секунды и все повторяется по новой.
  • если флешку отключить, то опять включается мигалка красным светодиодом.

 
Компилируем, запускаем, проверяем, радуемся процессу, проверяем более углубленно, недоумеваем, тупим, разбираемся.

А разбираться приходится вот в чем — если подключить флешку и дождаться прохождения 1 цикла записи, и сразу отключить, то выясняется что файл создался только вот записей в нем нет!!! После десяти таких проверок файл был по-прежнему пуст!!!

Пробуем держать флешку дольше, процесс контролируем по светику или по осциллографу.
Как видно из рисунка — после компиляции (первый широкий импульс), было проделано ПЯТЬ записей в файл. НО открыв файл в нем обнаружилось только ЧЕТЫРЕ записи!!!

Можно конечно долго рассказывать как именно я извращался над программой, но не буду. Важно то, что удалось выяснить. А именно то не записывается именно первая строчка, а точнее она записывается только при следующем проходе цикла (это удалось выяснить только запись номера строки в файл). Опять же путем долгих и неистовых пыток программно-аппаратных средство получилось что хоть как то гарантировать только путем ПОВТОРНОГО ПЕРЕМОНТИРОВАНИЯ BOMS. Однако хоть это и редкостная тупость, но пришлось добавить в код вот такие вот две строки:

fat_detach(hFAT_FILE_SYSTEM); // ОТКЛЮЧЕНИЕ FAT ДРАЙВЕРА
boms_detach(hBOMS); // ОТКЛЮЧЕНИЕ BOMS ДРАЙВЕРА

// РЕДКОСТНАЯ ТУПОСТЬ
hBOMS = boms_attach(hUSBHOST_2, VOS_DEV_BOMS);
boms_detach(hBOMS);
// РЕДКОСТНАЯ ТУПОСТЬ

vos_gpio_write_port(GPIO_PORT_A, 0b00000001); // зажечь светодиод
vos_delay_msecs(100);
vos_gpio_write_port(GPIO_PORT_A, 0b00000000); // погасить все

 

Ок! С тупостью разобрались, переходим к маразму.

Для записи информации в файл существует несколько функций. Одна из них — fwrite() — была рассмотрена в примере. Но дабы познать все прелести форматированного вывода строк в библиотеке имеется такая замечательная функция как fprintf(), кстати именно с ее помощью удалось вывести нумерованные строки и определить «тупость». Эта функция так же была подвержена «тупости», но сейчас не об этом.

Индикация процесса записи была сделана тоже не просто так! Чисто эксперимента ради, было записано время записи функцией fwrite() и fprintf(), дабы определить самую быструю (потому что так надо)))).

Первый график показывает процесс записи с помощью функции fwrite().

Как видно все пики одинаковые и длительность записи (65 байт) составляет 4-6 мС. Для сравнения широкий импульс слева это тот самый импульс в 100 мС в конце цикла.

Вторая группа графиков показывает процесс записи с помощью функции fprintf() (те же 65 байт).

Вот тут то маразм крепчает!!! Из графиков видно, что импульсы записи не равномерны, каждый пятый импульс в 8.5 раз шире других. А именно обычный процесс записи длится 300 мС!!! А каждый пятый цикл записи длится ~2.5 СЕКУНДЫ!!! Повторюсь за один цикл записывается строка длинной 65 байт!!! Для сравнения импульс слева это тот самый импульс в 100 мС в конце цикла.

Что это за маразм такой и как он лечится я так и не понял, скажу только то что эти опыты повторялись неоднократно и с различным временем подключения флешки. Результаты были идентичные!!!

 

Вот так вот весело и неоднозначно происходит запись информации на флешку с помощью микросхемы VinculumII.

 

Еще небольшая ложка дегтя в бочку дегтя!

Для этой микросхемы на сайте производителя имеет большое количество примеров. Вот только вряд ли они пригодятся кому-то в первозданном виде, так что придется все равно лезть в потроха этого «кода». Качество этих примеров тоже не на высоте, например в одном из примеров не производилась проверка длинны входного массива данных, и послав на 1 байт больше удалось наглухо повесить микросхему до ребута.

В другом примере обработка подключения флешки производилась только в начале программы и больше туда не возвращалась — в итоге повторно вставив флешку ничего не происходило. Чтобы добиться от этого примера хоть какой то внятной работы пришлось в конец программы добавить варварский сброс программы при извлечении флешки (vos_reset_vnc2();).

Так же чего мне никак до сих пор не удалось добиться — так это передачи от SPI_Slave, хотя прием вроде работает. Опять же в примерах SPI_Slave описан только для приема, а для передачи по SPI есть пример только для SPI_Master. От Slave не удалось добиться хоть какого нибудь дерганья ножками. Пока буду обходиться без него, ибо задачи позволяют.

Так что приводимые производителем примеры можно рассматривать ТОЛЬКО КАК ОЗНАКОМИТЕЛЬНЫЕ!!!

 

Вот такой вот обзор!
Казалось по описанию — мощная микросхема с кучей всяких крутых фишек, а на деле оказывается не все так просто!!!
Источник

Оставить комментарий

Вы можете использовать следующие теги и атрибуты: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>