USB для AVR. Часть 2. HID Class на V-USB


Обновление от 20.03.2011
Здравствуйте, в данной статье попытаюсь доступным языком описать USB HID Class устройство на микроконтроллере AVR, а также как общаться с таким девайсом программе написанной на Borland C++ Builder 6 под Windows. Рассмотрим основные настройки V-USB, откомпилируем прошивку для микроконтроллера, напишем простенькую программу пример для ПК, весь код хорошо комментирован. В качестве подопытного микроконтроллера — ATmega8 (можно смело брать любой другой, завалялась просто у меня старая ;) макетка Trashduino, эх ностальджи...) Также для ознакомления можно почитать: USB для AVR. Часть 1. Вводная

Сразу возникает вопрос: а почему именно HID? Ответ простой — прикинемся шлангом не нужно никакого драйвера для Windows (под *nix системами для работы с HID устройствами можно использовать библиотеку libusb, также libusb-win32 пригодится для custom-class USB под Windows, но это я уже далеко забежал). При подключении HID-совместимого устройства операционка сама включит необходимый драйвер. Нашей программе для компьютера не прийдется ничего устанавливать, конфигурировать, будем просто использовать готовые механизмы для работы с HID устройствами :)

Необходимый софт для работы:
  • AVR Studio 4 — среда разработки от Atmel, для написания прошивки МК. Если у кого-нибудь ещё нет такого чуда :)? Тогда качаем (там придется заполнить скучные поля регистрации) по данной ссылке AVR Studio 4.18 (build 684) и обновление AVR Studio 4.18 SP3 (b716). Также AVR Studio ликбез от DI HALT
  • WinAVR — open source набор разработчика для AVR, тут нас интересует GNU GCC компилятор, автоматом интегрируется в студию. Всё что касается языка Си на EasyElectronics.ru
  • V-USB — программная реализация low-speed USB 1.1 для микроконтроллеров AVR. Последняя версия vusb-20100715.tar.gz
  • Borland C++Builder 6 Enterprise Edition + UPDATE 4 — среда быстрой разработки приложений на C++ под ОС Windows. Полезный сайт по C++ Builder
Железо

ATmega8 подключена классически с 5-ти вольтовым питанием (примеры других схем можно посмотреть в каталоге circuits архива V-USB). В USB уровень сигнала на линиях D+ и D- составляет 3.3V, а схему подключили к 5V, поэтому для согласования установлены стабилитроны D1 и D2, которые уменьшают сигнал с микроконтроллера на гасящих резисторах R3, R4 до уровня необходимого по стандарту. Для определения версии протокола в схеме задействован делитель напряжения на резисторах R1 и R2 который обеспечивает 3.4V для D- на холостом ходу. Если вместо резистора R1 2,2K поставить R1 номиналом 1,5K (или, что ещё хуже, не установить R2 вовсе — как в оригинальном circuit от V-USB), то вместо 3,4V мы получим 3.7V, что в свою очередь откроет стабилитрон D1 который уменьшит его до напряжения его открывания (3.4 — 3.5V). И в результате мы получим перекос по току в режиме холостого хода (D2 не нагружен совсем, а по D1 уже течет ток) что будет сказываться на длинных проводах USB. Сопротивления R3 и R4 рассчитываются по току и для данной схемы равны 68 Ом. (P.S. инфу по поводу нюансов с делителем на резисторах откопал здесь)

Тактовая частота для микроконтроллера
Ассемблерные части V-USB написаны с поддержкой только таких частот: 12 MHz, 12.8 MHz, 15 MHz, 16 MHz, 16.5 MHz, 18 MHz и 20 MHz. Другие не поддерживаются. Частоту вручную нигде прописывать не нужно! Её необходимо определить в настройках проекта AVR Studio: Project -> Configuration Options -> вкладка General -> поле Frequency (в Герцах, для 12MHz добавляем приставку мега = 12000000) иначе получите кучу варнингов и не сможете правильно скомпилировать программу (студия создает define F_CPU для компилятора, который доступный всему проекту, V-USB как раз использует его). Потом при прошивке не забудьте правильно выставить FUSE биты, для работы от кварца.


  • 12 MHz: традиционная частота для V-USB, потому что это минимальная частота при которой возможно эмулировать все необходимые тайминги спецификации USB.
  • 15 MHz: похожа к 12 MHz, но местами вставлены NOP-ы. С другой стороны большая частота позволяет чаще использовать циклы, которые делают конечный код прошивки немного меньшим в сравнении с 12 MHz.
  • 16 MHz: поддержка этой частоты была специально добавлена для пользователей Arduino и других готовых плат которые имеет штатный кварц на 16 MHz. Также полезно если необходимо повысить частоту в целях производительности. Поскольку 16 MHz не делится нацело на USB low speed bit clock 1.5 MHz, то ассемблерная реализация для данной частоты написана с некоторыми хитростями, применяются циклы для замедления.
  • 12.8 MHz и 16.5 MHz: эти частоты расчитаны для тактирования от встроенного RC генератора с точностью 1%. Генератор прийдется калибровать на ходу при помощи USB frame clock. Кому интересно работать без кварца можна раскуривать такой пример — EasyLogger на ATTiny45.
  • 18 MHz: такой вариант более близок к стандартам USB, потому что позволяет на лету проводить CRC проверку входящих пакетов. Пакеты с неверной контрольной сумой отклоняются. Также есть возможность проверять целостность данных на уровне самой программы. Код занимает больше места в сравнении с другими опциями.
  • 20 MHz: для людей которые любят всё по максимуму. Поскольку 20 MHz не делится нацело на USB low speed bit clock 1.5 MHz, то ассемблерная реализация похожа на 16 MHz, применяются циклы для замедления.

Создаем проект в AVR Studio
Начнем писать прошивку. В студии создаем AVR GCC проект, назовем например Hid_example_firmware.

Далее в каталог проекта копируем все файлы с директории usbdrv скачанного архива vusb-20100715.tar.gz. Затем добавляем к проекту такие файлы (Add Existing Source File(s)… — это пункт контекстного меню в дереве проэкта):
  • usbdrv.c
  • usbdrvasm.S
  • oddebug.c

Теперь правильно настроим usbconfig.h и также поместим в каталог с проектом (ссылка рабочего проекта-примера в конце статьи). Inline документацию usbconfig.h я перевел на русский (использовал перевод от microsin.ru + дополнял сам). Там очень много опций, в статье опишу самые необходимые для быстрого старта (подробности смотрим внутри файла):

#define USB_CFG_IOPORTNAME      D
/* Указан порт, к которому подключена шина USB. Если Вы сконфигурируете "B",
 * будут использоваться регистры PORTB, PINB и DDRB.
 */
#define USB_CFG_DMINUS_BIT      4
/* Это номер бита в USB_CFG_IOPORT, куда подключен сигнал D-, может 
 * использоваться любой бит в порте.
 */
#define USB_CFG_DPLUS_BIT       2
/* Это номер бита в USB_CFG_IOPORTNAME, куда подключен сигнал D+, может
 * использоваться любой бит в порте. Пожалуйста, примите во внимание, что D+
 * должен быть также подсоединен к ножке прерывания INT0! [Вы можете также
 * использовать другие прерывания, см. секцию "Optional MCU Description" далее,
 * или Вы можете подсоединить D- к прерыванию, как это необходимо если Вы
 * используете опцию USB_COUNT_SOF. Если Вы используете D- для прерывания,
 * оно будет срабатывать также от маркеров Start-Of-Frame каждую
 * милисекунду.]
 */
#define USB_CFG_VENDOR_NAME     'w', 'e', '.', 'e', 'a', 's', 'y', 'e', 'l', 'e', 'c', 't', 'r', 'o', 'n', 'i', 'c', 's', '.', 'r', 'u'
#define USB_CFG_VENDOR_NAME_LEN 21
/* Здесь указывают имя вендора (vendor name), возвращаемое устройством.
 * Имя должно предоставляться как список символов в одиночных
 * кавычках, а USB_CFG_VENDOR_NAME_LEN задает их количество. Символы
 * интерпретируются как Unicode (UTF-16). Если Вам не нужно имя вендора,
 * закомментируйте этот макрос. ВСЕГДА указывайте имя вендора, содержащее Ваше
 * доменное имя Internet, если Вы используете свободно распространяемую пару
 * obdev VID/PID. За деталями обращайтесь к файлу USB-IDs-for-free.txt.
 */
#define USB_CFG_DEVICE_NAME     'H', 'i', 'd', ' ', 'e', 'x', 'a', 'm', 'p', 'l', 'e'
#define USB_CFG_DEVICE_NAME_LEN 11
/* Здесь указывается имя устройства (device name) таким же способом, как и в
 * предыдущем параметре указывается имя вендора. Если Вам не нужно имя
 * устройства, закомментируйте этот макрос. См. файл USB-IDs-for-free.txt
 * перед назначением имени, если Вы используете свободно распространяемую
 * пару obdev VID/PID.
 */
#define USB_CFG_INTERFACE_CLASS     3
/* Установленное значение 3 означает что наше устройство будет
 * принадлежать класу HID.
 */

Принцип работы
Перед тем как начнем писать прошивку МК, разберемся с основными принципами работы. Устройство класса HID может обмениваться с хостом блоками данных фиксированного размера — репортами, их структура описывается в HID дескрипторе который устройство предоставляет хосту при подключении. Первым делом обратим внимание на тот факт, что прием/передачу данных инициализирует хост программа на ПК!!!. Когда хост хочет отправить данные устройству он дает команду HID_SET_REPORT, при этом V-USB внутри микроконтроллера вызывает функцию usbFunctionWrite(). Аналогично когда хост хочет прочитать данные с устройства, он дает команду HID_GET_REPORT, при этом V-USB вызовет функцию usbFunctionRead(). USB линия данных D+ подключена к прерыванию INT0 (оно с наивысшим приоритетом). Короче когда будет происходить обмен данными по USB, микроконтроллер постоянно будет уходить на обработку INT0, на котором висит V-USB. И только потом управление отдадут основной программе. Если нужно использовать свои прерывания (желательно быстрые и компактные), то сразу же ставим глобальный флаг прерываний I командой sei(), чтобы при запросах от хоста могло сработать INT0 для правильной работы V-USB.

Функция usbPoll(), которую необходимо вызывать не реже чем 50 ms — сообщает хосту, что наше устройство на шине USB ещё живое и ждет своего часа готово к работе. Если это не соблюдать, то винда напишет «Подключено неизвестное устройство бла бла бла...». 50 ms — это USB timeout for accepting a Setup message (это специальные команды хоста, у нашем случае — HID_SET_REPORT и HID_GET_REPORT). Setup сообщениями занимается функция usbFunctionSetup(), собственно тут обрабатываются управляющие команды USB и дальше уже запускается usbFunctionRead() либо usbFunctionWrite() в данном Hid примере. Вот здесь хорошо описано пакеты при передачи данных по USB.

Что такое USB HID report descriptor?
Простыми словами это массив констант зашитый у Flash память устройства для описания структуры пакетов данных (Hid репортов). В нем содержится такая информация: сколько пакетов поддерживает устройство, какая их длина, назначение каждого байта и бита в пакете. Таким образом при подключении к компьютеру устройство с помощью такого дескриптора сообщает свои параметры, а ОС компьютера уже будет знать как правильно общаться с этим устройством (например какие биты отвечают за нажатие определенных кнопок джойстика). У нас будет «HID совместимое устройство» для передачи произвольных данных фиксированного размера (не мышь, не джойстик). Поэтому пускай дескриптор в примере будет в некотором смысле набором магических чисел с комментариями (я планирую позже написать отдельную статью по HID дескриптору, а пока полезная информация: USnooBie's USB HID Report Descriptor Tutorial и HID Related Specifications. Менять дескриптор прийдется только для того, чтобы представиться конкретным HID устройством, например клавиатурой (отличные примеры для взрыва мозгов: Маленькая USB пакость и The Haunted USB Cable!). Также дюжина примеров разных HID устройств находится на сайте V-USB.

Как будем передавать данные
Для передачи данных создадим структуру, так намного удобней/гибче для собственных переделок чем просто массив (при чем никто не запрещает внутри структуры описать кучу массивов). Наш дескриптор имеет только один вид репорта, размер которого 8 бит (REPORT_SIZE), количество равняется размеру передаваемой структуры (REPORT_COUNT). Таким образом будем передавать данные порциями по 8 бит. Надо только помнить что по дефолту V-USB поддерживает прием/передачу до 254 байт данных. Если хотим больше, тогда в usbconfig.h ставим define USB_CFG_LONG_TRANSFERS в 1, при этом возрастет размер самого драйвера.

Как было сказано выше, весь экшн по поводу приема/передачи данных (наша структура) внутри МК берут на себя функции usbFunctionRead(uchar *data, uchar len) и usbFunctionWrite(uchar *data, uchar len). Заполнять саму структуру данными не обязательно внутри этих же функций (я так сделал для простоты), этим могут заниматься другие участки кода (например прерывания, но тогда структуру обьявляем как volatile). Параметр *data — это указатель на буфер V-USB, где мы обязаны прочитать/записать данные размером len. Максимальный размер этого буфера — 1 байт (uchar) и это значение = размеру нашего репорта. Структура для передачи данных естественно занимает больше чем 1 байт, именно поэтому ее нужно передавать частями. Переменные currentAddress и bytesRemaining хранят информацию про текущую передачу.

Страшная запись uchar *buffer = (uchar*)&pdata; означает следующее: pdata — наша структура, &pdata — адрес начала нашей структуры в памяти, (uchar*)&pdata — явное приведение типа (uchar* — указатель на данные типа uchar). Таким способом мы просто обьявляем указатель uchar *buffer на место в памяти где хранится наша структура (и плевать что в ней хранится, передавать будем кусками uchar). Как писал в комментах Vga — «объявить структурку и привести указатель к ней — вполне типичный метод, когда надо работать с блоком данных в памяти, который может представлять собой ту или иную структуру». Иллюстрация объяснений приема/передачи структуры по частям:


Разобравшись со всем вышесказанным, приступим к написанию программы для микроконтроллера (main.c):

#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <avr/pgmspace.h>   /* нужно для usbdrv.h */
#include "usbdrv.h"


struct dataexchange_t       // Описание структуры для передачи данных
{
   uchar b1;        // Я решил для примера написать структуру на 3 байта.
   uchar b2;        // На каждый байт подцепим ногу из PORTB. Конечно это
   uchar b3;        // не рационально (всего то 3 бита нужно).
};                  // Но в целях демонстрации в самый раз.
                    // Для наглядности прикрутить по светодиоду и созерцать :)


struct dataexchange_t pdata = {0, 0, 0};


PROGMEM char usbHidReportDescriptor[22] = { // USB report descriptor         // Дескриптор описывает структуру пакета данных для обмена
    0x06, 0x00, 0xff,                       // USAGE_PAGE (Generic Desktop)
    0x09, 0x01,                             // USAGE (Vendor Usage 1)
    0xa1, 0x01,                             // COLLECTION (Application)
    0x15, 0x00,                             //    LOGICAL_MINIMUM (0)        // min. значение для данных
    0x26, 0xff, 0x00,                       //    LOGICAL_MAXIMUM (255)      // max. значение для данных, 255 тут не случайно, а чтобы уложиться в 1 байт
    0x75, 0x08,                             //    REPORT_SIZE (8)            // информация передается порциями, это размер одного "репорта" 8 бит
    0x95, sizeof(struct dataexchange_t),    //    REPORT_COUNT               // количество порций (у нашем примере = 3, описанная выше структура передастся за три репорта)
    0x09, 0x00,                             //    USAGE (Undefined)
    0xb2, 0x02, 0x01,                       //    FEATURE (Data,Var,Abs,Buf)
    0xc0                                    // END_COLLECTION
};
/* Здесь мы описали только один report, из-за чего не нужно использовать report-ID (он должен быть первым байтом).
 * С его помощью передадим 3 байта данных (размер одного REPORT_SIZE = 8 бит = 1 байт, их количество REPORT_COUNT = 3).
 */


/* Эти переменные хранят статус текущей передачи */
static uchar    currentAddress;
static uchar    bytesRemaining;


/* usbFunctionRead() вызывается когда хост запрашивает порцию данных от устройства
 * Для дополнительной информации см. документацию в usbdrv.h
 */
uchar   usbFunctionRead(uchar *data, uchar len)
{
    if(len > bytesRemaining)
        len = bytesRemaining;

    uchar *buffer = (uchar*)&pdata;

    if(!currentAddress)        // Ни один кусок данных еще не прочитан.
    {                          // Заполним структуру для передачи
        if ( PINB & _BV(1) )
            pdata.b1 = 1;
        else
            pdata.b1 = 0;


        if ( PINB & _BV(2) )
            pdata.b2 = 1;
        else
            pdata.b2 = 0;


        if ( PINB & _BV(3) )
            pdata.b3 = 1;
        else
            pdata.b3 = 0;
    }

    uchar j;
    for(j=0; j<len; j++)
        data[j] = buffer[j+currentAddress];

    currentAddress += len;
    bytesRemaining -= len;
    return len;
}


/* usbFunctionWrite() вызывается когда хост отправляет порцию данных к устройству
 * Для дополнительной информации см. документацию в usbdrv.h
 */
uchar   usbFunctionWrite(uchar *data, uchar len)
{
    if(bytesRemaining == 0)
        return 1;               /* конец передачи */

    if(len > bytesRemaining)
        len = bytesRemaining;

    uchar *buffer = (uchar*)&pdata;
    
    uchar j;
    for(j=0; j<len; j++)
        buffer[j+currentAddress] = data[j];

    currentAddress += len;
    bytesRemaining -= len;

    if(bytesRemaining == 0)     // Все данные получены
    {                           // Выставим значения на PORTB
        if ( pdata.b1 )
            PORTB |= _BV(1);
        else
            PORTB &= ~_BV(1);


        if ( pdata.b2 )
            PORTB |= _BV(2);
        else
            PORTB &= ~_BV(2);


        if ( pdata.b3 )
            PORTB |= _BV(3);
        else
            PORTB &= ~_BV(3);
    }

    return bytesRemaining == 0; /* 0 означает, что есть еще данные */
}

/* ------------------------------------------------------------------------- */

usbMsgLen_t usbFunctionSetup(uchar data[8])
{
usbRequest_t    *rq = (void *)data;

    if((rq->bmRequestType & USBRQ_TYPE_MASK) == USBRQ_TYPE_CLASS){    /* HID устройство */
        if(rq->bRequest == USBRQ_HID_GET_REPORT){  /* wValue: ReportType (highbyte), ReportID (lowbyte) */
            // у нас только одна разновидность репорта, можем игнорировать report-ID
            bytesRemaining = sizeof(struct dataexchange_t);
            currentAddress = 0;
            return USB_NO_MSG;  // используем usbFunctionRead() для отправки данных хосту
        }else if(rq->bRequest == USBRQ_HID_SET_REPORT){
            // у нас только одна разновидность репорта, можем игнорировать report-ID
            bytesRemaining = sizeof(struct dataexchange_t);
            currentAddress = 0;
            return USB_NO_MSG;  // используем usbFunctionWrite() для получения данных от хоста
        }
    }else{
        /* остальные запросы мы просто игнорируем */
    }
    return 0;
}
/* ------------------------------------------------------------------------- */

int main(void)
{
    DDRB = 0b00001110;      // PB1,PB2,PB3 - выход

    usbInit();
    usbDeviceDisconnect();  // принудительно отключаемся от хоста, так делать можно только при выключенных прерываниях!
    
    uchar i = 0;
    while(--i){             // пауза > 250 ms
        _delay_ms(1);
    }
    
    usbDeviceConnect();     // подключаемся

    sei();                  // разрешаем прерывания

    for(;;){                // главный цикл программы
        usbPoll();          // эту функцию надо регулярно вызывать с главного цикла, максимальная задержка между вызовами - 50 ms
    }
    return 0;
}
/* ------------------------------------------------------------------------- */ 

Компилируем, заливаем прошивку в микроконтроллер, подключаем к USB порту компьютера и вуаля:





Пишем программу для компьютера
Запускаем Borland C++ Builder 6, добавляем на форму три CheckBox-а и две обычных кнопки:

Сохраняем проект и копируем в его каталог полезную библиотеку hidlibrary.h, она специально написана для работы с Hid устройствами из Borland C++ Builder. Сделана как класс, также применяются шаблоны. Библиотека с помощью WINAPI функции LoadLibrary подгружает hid.dll, затем GetProcAddress — вычисляет адреса функций внутри hid.dll. Предоставляет удобный и простый интерфейс для работы с HID. Нашел тут — «Общение с контроллером по USB». Немного модернизировал. Я очень долго мучился с передачей данных Hid устройствам на Borland C++ Builder, пока не нашел эту библиотеку. Никак не получалось. Теперь всё стало на свои места :) Думаю многим будет полезна, огромное спасибо авторам.

Так выглядит простенькая программа:

//---------------------------------------------------------------------------
#define  uchar  unsigned char

#include <vcl.h>
#pragma hdrstop
#include "main.h"

#include "hidlibrary.h" // Библиотека для работы с Hid устройствами


#include "../Hid_example_firmware/usbconfig.h"  // Здесь пишем путь к usbconfig.h
char  vendorName[]  = {USB_CFG_VENDOR_NAME, 0}; // для того что бы знать как
char  productName[] = {USB_CFG_DEVICE_NAME, 0}; // называется наше устройство


struct dataexchange_t		// Описание структуры для передачи данных
{
   uchar b1;        // Я решил для примера написать структуру на 3 байта.
   uchar b2;        // На каждый байт подцепим ногу из PORTB. Конечно это
   uchar b3;        // не рационально (всего то 3 бита нужно).
};                  // Но в целях демонстрации в самый раз.
                    // Для наглядности прикрутить по светодиоду и созерцать :)

struct dataexchange_t pdata = {0, 0, 0};

HIDLibrary <dataexchange_t> hid; // создаем экземпляр класса с типом нашей структуры

//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
   : TForm(Owner)
{
}
//---------------------------------------------------------------------------

int connect()  // этой функцией будем подключаться к устройству
{
   int i, n, res=0;
   string exampleDeviceName = "";

   exampleDeviceName += vendorName;
   exampleDeviceName += " ";
   exampleDeviceName += productName;

   n = hid.EnumerateHIDDevices(); // узнаем все Hid устройства vid_16c0&pid_05df
                                  // vid и pid указаны в hidlibrary.h константой idstring

   for (i=0; i<n; i++)            // ищем среди них наше
   {
      hid.Connect(i);

      // GetConnectedDeviceName() возвращает string,
      // где через пробел указаны vendor и product Name.
      // Сравниваем, если совпало - значить устройство наше
      if ( hid.GetConnectedDeviceName() == exampleDeviceName )
      {
         res = 1;
         break;
      }
   }
   return res;
}
//---------------------------------------------------------------------------

// Кнопка "Принять данные"
void __fastcall TForm1::Button1Click(TObject *Sender)
{
   if ( 1 == connect() )
   {
      hid.ReceiveData(&pdata);           // Читаем данные с устройства

      if (pdata.b1)
         CheckBox1->Checked = true;
      else
         CheckBox1->Checked = false;

      if (pdata.b2)
         CheckBox2->Checked = true;
      else
         CheckBox2->Checked = false;

      if (pdata.b3)
         CheckBox3->Checked = true;
      else
         CheckBox3->Checked = false;
   }
   else
   {
      AnsiString s = "";
      s += vendorName;
      s += " ";
      s += productName;
      s += " не подключено.";
      ShowMessage(s);
   }
}
//---------------------------------------------------------------------------

// Кнопка "Отправить данные"
void __fastcall TForm1::Button2Click(TObject *Sender)
{
   if ( 1 == connect() )
   {
      if (CheckBox1->Checked)
         pdata.b1 = 1;
      else
         pdata.b1 = 0;

      if (CheckBox2->Checked)
         pdata.b2 = 1;
      else
         pdata.b2 = 0;

      if (CheckBox3->Checked)
         pdata.b3 = 1;
      else
         pdata.b3 = 0;

      hid.SendData(&pdata);           // Отправляем данные устройству
   }
   else
   {
      AnsiString s = "";
      s += vendorName;
      s += " ";
      s += productName;
      s += " не подключено.";
      ShowMessage(s);
   }
}
//---------------------------------------------------------------------------

Тут действительно ничего сложного: описана одна функция connect() для подключения нашего устройства, и два обработчика событий при нажатии на кнопки «Принять данные» и «Отправить данные». Всё теперь можно мигать светодиодами :) Для передачи данных специально использовалась структура dataexchange_t, точно такая описана для МК. Чтобы откомпилированная программа потом работала на компьютерах где не установлен Borland C++ Builder необходимо в настройках проекта отключить использование динамических библиотек. Для этого идем в Project -> Options -> вкладка Linker и Packages -> снимаем галочки напротив «Use dynamic RTL» и «Build with runtime packages»:



Ссылки:
Удачных экспериментов с USB!

  • +12
  • 13 марта 2011, 19:13
  • XANDER

Комментарии (351)

RSS свернуть / развернуть
видео надо бы перезалить
0
Исправлю. Подозрительно, раньше работало…
0
Хорошая статья.
Но немного завуалированным остается работа с конечными точками и с дескриптором. (отчасти потому что движок уменьшает окно и неудобно читать длинные комменты).

Закомментируйте дескриптор лучше. Если сделаете статью по правилам написания HID-дескриптора — будет совсем классно. Ну и я беглым взглядом не нашел работы с остальными дескрипторами USB, а если менять HID-дескриптор, то надо будет как минимум еще его размер в других дескрипторах USB указывать. Хотябы затроньте эту тему.
Литература га эту тему конечно есть, но там курить и курить, особенно новичкам…
Удачи.
0
Из статьи нихрена не понятно как же собственно идет обмен данными через усб в самом контроллере.

Куда их совать и откуда их забирать? Когда их забирать и как инициировать обмен? Есть только какие то
usbFunctionWrite и usbFunctionRead

кто их вызывает, зачем они нужны? Прочитал я ее и нихрена не понял, с таким же успехом я мог бы прочитать Doxygen описание усб библиотеки.

Плюс только за пример с билдером на PC
0
Спешил сильно :) Добавлю ещё пояснений…
Принцип таков: прием/передачу начинает хост, а V-USB в микроконтроллере при запросе HID_GET_REPORT вызывает функцию usbFunctionRead (комп читает данные с устройства), соответственно при запросе HID_SET_REPORT срабатывает функция usbFunctionWrite (комп передает данные в устройство). Информация передается кусками размером REPORT_SIZE бит, их количество = REPORT_COUNT.
0
Да. Надо в статье описать структуру работы библиотеки, а не просто дать пример.

Т.е. я бы описал это так:

В работе усб библиотека чем то похоже на работу аппаратного блока. Т.е. мы тупо вызваем usbpoll и ни о чем не думаем больше, как если бы мы загрузили на генерацию сигнала какой-нибудь ШИМ таймер. И эта usbpoll функция, будучи запускаемой раз в 50мс сама стуканется в комп и спросит что ей делать. А в зависимости от ответа компа вызывается либо usbFunctionRead либо usbFunctionWrite. Подобное прерываниям на разные события. И уже в этих функциях мы можем делать разные непотребства в зависимости от того что нам пришло. Выставлять флажки, запускать задачи диспетчера, что то там с портами мутить. Данные которые нам приходят из компа забирать в переменной/массиве/структуре ХХХХ, а то что мы хотим послать в комп мы закладываем в переменую/Массив/струкутуру УУУУ которую определяем там то. И которая должна отвечать таким то требованиям.

Вот как то так. И сразу в голове ясность и все понятно что к чему.
0
Коллбеки это называется. В принципе, по их виду это сразу это понятно. Но описание было бы полезней кода, да.
0
Такие вещи понятны когда сам такое сделал не один раз. А вот кто только неделю назад диодиком помигать научился нивжисть не вкурит с первого раза что там и куда по таким обьяснениям.
0
Ну в приципе да) Хотя под МК я впервые что-то закодил тока получив от тебя пинборд (т.е. пару неделек назад), на ПК я программист довольно опытный)
Правда, лезть к USB без опыта программирования все равно смысла не так уж много. В большинстве случаев придется или реализовывать чей-то (не факт что простой) протокол, либо вообще писать свой драйвер.
0
на microsin.ru все это уже сто раз описано. К тому же много функционально завершенных устройств.
0
Пусть будет сто раз + 1. Людям приятно, и самому интересно.
0
В том то и дело, что статья получилась один в один как на микросине, но ни там ни тут нет главного — «Как же это, блядь, работает то?»
0
Добавил несколько абзацов «Принцип работы».
Более детально смогу написать позже, надо собираться… Завтра мне на учебу.
0
Оки, я тебе пока еще в комменты наброшу слабые места которые надо бы разьяснить.
0
Спосибо за статью, надо будет как нибуть попробовать. По этому у меня два маленьких вопроса:

1. Почемуб структуру dataexchange_t не заменить просто масивом char[], тогда не нужна и эта операция

uchar *buffer = (uchar*)&pdata;
да и адресация упращается, вместо

buffer[j+currentAddress] = data[j];
чтото по проще.
2. В функции usbFunctionRead в строчке

if ( PORTB & _BV(1) )

не должно быть

if ( PINB & _BV(1) )
0
Спасибо, действительно PINB правильней :)

Структура чисто из удобства для апгрейда/переписывания программы. Если нужно массив — пожалуйста. Но когда придется передавать кучу параметров (сдесь был маленький пример), представьте что-действительно серьезное, вот тогда преимущества очевидны.

Адресация проще не станет, все равно данные идут кусками.
uchar *buffer = (uchar*)&pdata;
— это лишь указатель на структуру, ему плевать какие данные внутри структуры. Мы просто байт за байтом передаем всю структуру. А потом делайте с ею что хотите.

В случае из обычным массивом все равно пришлось бы так писать:
masiv[j+currentAddress] = data[j];

И при этом помнить что где в этом массиве хранится.
0
Да, объявить структурку и привести указатель к ней — вполне типичный метод, когда надо работать с блоком данных в памяти, который может представлять собой ту или иную структуру. В принципе, в большом проекте вместо цикла с buffer[j+currentAddress] = data[j] будет вызов функции типа copymem, принимающий непосредственно указатели на структурку с данными и буфер V-USB.
0
не улавливаю, откуда это if ( PINB & _BV(1) ), вроде нигде не объявлялось это
0
DIHALT не могли бы вы удалить мой первый комент, да и эту просьбу тоже :)
0

uchar i = 0;
    while(--i){             // пауза > 250 ms
        _delay_ms(1);
    }

В этом куске кода i разве не должна быть равна 250?
0
Тут переменная i типа unsigned char.
В записи while(--i) от ноля минусуем 1, в результате i = 255
потом цикл крутится столько же, пока i опять не достигнет 0.
0
Вот оно что, прикольно.
0
Фотографии матрицы — монструозны. Автор — гигант паяльника:)
0
Скорей джедай сверловки. Столько дырок сверлить я бы заебался.
0
Нет, сверлить было намного проще и быстрее чем паять… Эту матрицу собирал два дня (каждый подход примерно 4 часа)
0
И монстр многоуровневого монтажа:)
0

#define USB_CFG_VENDOR_NAME     'w', 'e', '.', 'e', 'a', 's', 'y', 'e', 'l', 'e', 'c', 't', 'r', 'o', 'n', 'i', 'c', 's', '.', 'r', 'u'
#define USB_CFG_VENDOR_NAME_LEN 21
/* Эти две величины задают имя вендора (vendor name), возвращаемое устройством.

Нифига :) Одна величина задает имя вендора, а вторая длинну этого имени. Оно конечно понятно, но лучше разьяснить, чтобы доходило даже до дебилов.
0
Дебилы не будут программировать микроконтроллеры :) Да и не только микроконтроллеры ;)
Исправлю, просто очень много информации, за всем не уследить…
Причем со многими вещами стыкаюсь впервые, очень сложно раскуривать такую тему, не зря официальное руководство на usb.org такое огромное. Сложно всё на пальцах показать.
0
ООо ты заблуждаешься :))) Еще как пытаются :))))
0
Думаю, лучше так:
#define USB_CFG_VENDOR_NAME L"we.easyelectronics.ru"
Макрос USB_CFG_VENDOR_NAME_LEN убрать, вместо него использовать:
STR_LENGTH( USB_CFG_VENDOR_NAME )
Где макрос STR_LENGTH определяется так:
#define ARR_SIZE(arr)   ( sizeof(arr) / sizeof(arr[0]) )
#define STR_LENGTH(str) ( ARR_SIZE(str) - 1 )
0
Этот define авторы V-USB так описали специально, затем внутри usbdrv.c вот так используется:
#if USB_CFG_DESCR_PROPS_STRING_VENDOR == 0 && USB_CFG_VENDOR_NAME_LEN
#undef USB_CFG_DESCR_PROPS_STRING_VENDOR
#define USB_CFG_DESCR_PROPS_STRING_VENDOR   sizeof(usbDescriptorStringVendor)
PROGMEM int  usbDescriptorStringVendor[] = {
    USB_STRING_DESCRIPTOR_HEADER(USB_CFG_VENDOR_NAME_LEN),
    USB_CFG_VENDOR_NAME
};
#endif
0
Да, это скорее к авторам V-USB, намекнуть бы им :) Приведенный Вами кусок можно переписать так:
#if USB_CFG_DESCR_PROPS_STRING_VENDOR == 0 && STR_LENGTH(USB_CFG_VENDOR_NAME)
#undef USB_CFG_DESCR_PROPS_STRING_VENDOR
#define USB_CFG_DESCR_PROPS_STRING_VENDOR   sizeof(usbDescriptorStringVendor)
PROGMEM int  usbDescriptorStringVendor[] = {
    USB_STRING_DESCRIPTOR_HEADER(STR_LENGTH(USB_CFG_VENDOR_NAME)),
    USB_CFG_VENDOR_NAME
};
#endif
Зато не надо будет самому считать длину строки и разбивать строку на символы. Правда, это же определение строки используется и для С++ Builder, вроде бы он должен правильно понимать L"...".
0
Будет ошибка. Здесь определяется содержимое usbDescriptorStringVendor[] = {… } и там за правилами Си нужно указывать значения через запятую, а не передавать string!!! Вот простый аналог int masiv[] = {1,2,3,4,5}. Для использования string придется радикально переписать этот участок кода, бесполезно для микроконтроллера, где наоборот стремятся к простоте, быстродействию и минимальному размеру кода.
+1
Да, Вы правы, плохо протестировал, вместо строки gcc поместил туда указатель. И еще STR_LENGTH в #if работать не будет. Ладно, тогда так:
#if USB_CFG_DESCR_PROPS_STRING_VENDOR == 0 && USE_USB_CFG_VENDOR_NAME
#undef USB_CFG_DESCR_PROPS_STRING_VENDOR
#define USB_CFG_DESCR_PROPS_STRING_VENDOR   sizeof(usbDescriptorStringVendor)
MAKE_USB_STRING_DESCRIPTOR(usbDescriptorStringVendor, USB_CFG_VENDOR_NAME);
#endif
#define MAKE_USB_STRING_DESCRIPTOR(descriptor, str)                \\
PROGMEM struct                                                     \\
{                                                                  \\
    int len;                                                       \\
    int s[STR_LENGTH(str)];                                        \\
}                                                                  \\
descriptor = {USB_STRING_DESCRIPTOR_HEADER(STR_LENGTH(str)), str};
0
Слишком много приключений для таково простого параметра. Один раз прописал константу и всё.
0
ОС компьютера уже будет знать как правильно общаться с этим устройством. Полезная информация по USB HID report descriptor тут и тут.


Никуда не годится. Сегодня это «тут, тут», а завтра 404 not found хотя бы один пример обьявления дескриптора надо дать. С подробным разьяснением чего и зачем. Иначе даже «тут тут» не поможет, ибо там дохрена какой то инфы и непонятно что с ней делать, не говоря уже про то, что все не по русски и поди это пойми.
0
Согласен, не всё сразу. Думаю написать примеров ещё. Просто этот дескриптор что в примере идеально подходит для передачи custom данных. Другой дескриптор нужен будет если мы захочем прикинуться джойстиком например, а не просто Vendor-specific устройством

Всё же человек я, а не…
0
Вот потому я и указыаю слабые места, чтобы потом получилась статья-конфетка, а не очередной перевод оригинальной документации. Время на доделку есть. ДО завершения еще статей 80 осталось :)
0
Обнадеживает :) Буду стараться, а я так спешил… Хотел успеть сегодня к вечеру опубликовать. У меня свободное время в основном по выходным, рабочие дни как белка в колесе (учеба + работа)
0
Я еще же по всем пройдусь и дам волшебного пендаля, на исправление ошибок. А потом только буду оценивать результат.
+1
Кстати, второму линку особо ничего не грозит — это доки от создателей USB.
0
PROGMEM char usbHidReportDescriptor[22] = { // USB report descriptor         // Дескриптор описывает структуру пакета данных для обмена
    0x06, 0x00, 0xff,                                   // USAGE_PAGE (Generic Desktop)
    0x09, 0x01,                                         // USAGE (Vendor Usage 1)
    0xa1, 0x01,                                         // COLLECTION (Application)
    0x15, 0x00,                                         //    LOGICAL_MINIMUM (0)        // min. значение для данных
    0x26, 0xff, 0x00,                                   //    LOGICAL_MAXIMUM (255)      // max. значение для данных, 255 тут не случайно, а чтобы уложиться в 1 байт
    0x75, 0x08,                                         //    REPORT_SIZE (8)            // информация передается порциями, это размер одного "репорта" 8 бит
    0x95, sizeof(struct dataexchange_t),                //    REPORT_COUNT               // количество порций (у нашем примере = 3, описанная выше структура передастся за три репорта)
    0x09, 0x00,                                         //    USAGE (Undefined)
    0xb2, 0x02, 0x01,                                   //    FEATURE (Data,Var,Abs,Buf)
    0xc0                                                // END_COLLECTION
};


Не помешает расписать что зачем поподробней. Что за числа стоят впереди? Например:
0x75, 0x08,     //    REPORT_SIZE (8) 

08 это REPORT_SIZE, а что такое 75? Какие то метки?

/* Эти переменные хранят статус текущей передачи */
static uchar    currentAddress;
static uchar    bytesRemaining;

Эти переменные часть VUSB или сам добавил?

uchar *buffer = (uchar*)&pdata;

Вот тут неплохо бы дать подробное пояснение, что передать Мы можем что угодно, любую конструкцию. Массив, структуру, или один байт. Главное, чтобы был указан его размер, а дальше vusb схватит отсюда и до сего размера и побайтно все запинает в хост. Причем это можно добавить лучше даже не в исходник в виде комментов, а в абзац про обьяснение принципов работы. Мол для отправки данных мы даем библиотеке указатель на то, где они лежат и сколько надо копать, а дальше она сама разберется. Главное указателю buffer присвоить нужный адрес таргет данных.

Там же, в абзаце про устройство надо добавить, что весь экшн по поводу подготовки/обработки пришедших/отсылаемых данных тупо дописываеваем ручками в functionWrite/functionRead
0
Ок, допишу.
0
Не помешает расписать что зачем поподробней. Что за числа стоят впереди? Например:
Лучше отдельную статью про формат дескриптора.
Эти переменные часть VUSB или сам добавил?
Ну вообще-то, если оно в программе, а не в V-USB — то, видимо, сам. Ну и по логике коллбэков это становится понятно.
Главное, чтобы был указан его размер, а дальше vusb схватит отсюда и до сего размера и побайтно все запинает в хост.
Не совсем, хватаем и читаем мы сами, причем кусками того размера, который просит V-USB (это, опять же, видно из кода — сам я V-USB еще не ковырял), и копируем в выданный драйвером буфер.
Ну а приведение произвольного указателя на память к указателю на структуру, соответствующую формату этого куска памяти — вполне типичный прием при программировании. Например, пришедший по сети пакет с данными (пример из програмирования игр) читается в память и затем в зависимости от типа приводится к указателю на структуру, описывающую этот тип пакета. Вообще говоря, его надо знать, к V-USB он не сильно относится, да и V-USB без этого приема вполне обойдется.
0
Не совсем, хватаем и читаем мы сами
Ну как это сами. functionWrite же вызывается через VUSB так что это уже его юристдикция.
причем кусками того размера, который просит V-USB
Опять же нас это уже не касается. Оно само сделает. Но вот про передаваемую от VUSB величину порции (len, как понимаю) тоже не помешает указать. Что это и зачем.

Ну а приведение произвольного указателя на память к указателю на структуру, соответствующую формату этого куска памяти — вполне типичный прием при программировании.
Прикол в том, что к контроллерам большая часть людей приходят не от программирования, а от железа. И каких то стандартных и очевидных фишек они просто не знают. Поэтому то надо подробнейшим образом описывать все что делается на нашем уровне. Что, куда зачем и почему. Иначе сразу не дойдет.
0
Скажем так, хватаем по запросу от V-USB, а не так, что отдали ему буфер данных на отправку и забыли. По сути, нужно в usbRead как раз таки реализовать логику функции чтения, аналогичной скажем ReadFile в винде, а V-USB, когда ему нужны данные для передачи хоста — читает их из программы вызовом этой функции.
0
Тоже верно. Т.е. первична у нас все же usbfunctionRead/Write т.е. топик стартеру нужно досконально описать что это функция получает от VUSB в параметрах ( шо за uchar *data, и нах нужен uchar len), что должна сделать и что должна вернуть.

Да и про usbFunctionSetup тоже надо подробней описать, что мы в нее получаем, что там должны сделать, что она должна вернуть. А то глядишь на пример и гадаешь то ли это копипаста и просто так надо, то ли тут что то надо свое вписать.
+1
А вообще, в целом довольно понятно по сорцам. Ясно теперь по крайней мере, откуда к нему подступиться) А такие вещи как формат дескриптора — для своего проекта все равно в справочных данных курить.
Правда, опять же, я не начинающий погромист и с USB чуть-чуть знаком)
+1
Привет! Пасиб за статью, я давно с HID хотел разобраться.
Я обычно делаю девайсы, кторые определяются как клас Libusb-win32(дескиптор тут вообще не надо) и когда делаю запрос с компа, то указываю буфер, размер пакета, ну и ее несколько опций. А тут вижу что при запросе с компа нужно просто указывать буфер. Но у меня такая проблема: с МК на комп нужно передавать 80 байт, а с ПК на МК только 9. Вопрос: если я с компа буду передавать буфер размером 9 байт, то передадутся только 9 или сколько бдет указано в репорт_сайз? Спрашиваю так нужно секономить время передачи по юсб.
+1
В данном примере всего один репорт, соответственно размер на прием/передачу будет одинаковый. Думаю можно реализовать, но прийдется написать другой дескриптор на два разных репорта: один использовать для приема, другой для передачи (хотя и тем и другим можно будеть принимать/отправлять). В программе добавить проверку Report-ID, и для нужного репорта запускать правильное действие.

Позже планирую добавить в статью информацию про Hid дескрипторы (если будет очень много, то вынесу в отдельную статью)

USnooBie's USB HID Report Descriptor Tutorial — хорошие примеры дескрипторов, English
0
Доброй ночи! Имеется немалый опыт работы с V-USB. Если кто-нибудь объяснит как можно поделиться своими проектами, буду только рад стараться! Раньше все на forums[.]obdev[.]at сидел, но там все заглохло. Мой проект на V-USB и реализация на нем Mass storage class, я думаю, был бы интересен!
+1
Для начала почитайте we.easyelectronics.ru/page/about/
Ну а дальше, если будут вопросы — пишите
0
очень интересен.
0
Отлично! Можете написать статью и поделиться опытом, покажете свои проекты. Mass storage class на AVR очень интересно…
0
Вам может показаться смешным, но я так и не понял как разместить статью =) Ну не очень я во всяких там форумах. Ткните носом! Могу написать статью и дать ответственному человеку свой логин и пас для помощи мне неумеке=(
0
Во первых, ссылку от Ultrin прочитайте (оно же «справочная» в заголовке). В принципе, все необходимое там есть. А кнопочка «написать» вверху слева, прямо под заголовком, там же где «Все Коллективные Персональные ТОР». Как написать в коллективный блог — сказано в справочной, если не дает из-за рейтинга — можно написать в персональный и попросить модеров перенести (либо подождать пока поднимется рейтинг и перекинуть самому).
0
Можешь дать свой логин и пасс мне. Выслав его на dihalt@dihalt.ru помогу разместить статью. Раз уж все так плохо. Заодно по почте ликбез проведу.
0
Уважаемый DIHALT, если Вам не мложно, окинте хотябы одним глазом часть моей статьи и дайте пару советов(замечаний, указания и т.п.) если можно!
0
Прочитал статью, а вопросы остались:
1. Какие (и когда) возникают прерывания, при работы V-USB?
2. Повлияют ли на работу V-USB обработчики прерываний, внедренные мной? И как минимизировать их влияние на работу USB??
Заранее спасибо.
0
INT0 при передаче по шине, часто (1.5 мегагерца). При использовании D- на прерывание — еще и ежемиллисекундно. По крайнйе мере это теоретически. Может еще что-то юзает, но врядли.
Обработчики не сильно повлияют, INT0 приоритетней. Но можно проморгать свое прерывание, т.к. проц запросто может тратить 95% времени только на обработку USB.
0
А хотя, при передаче оно скорее всего из INT0_ISR и не выходит. Так что INT0, частота зависит от частоты передач.
0
Получается, прерывание INT0 возникает, только при обращении компа к контроллеру? А остальное время могу делать, что хочу? Я что-то не интересовался глубиной стека, к примеру, смогу ли я обрабатывать прерывание INT1 2000 раз в секунду?
0
А причем тут глубина стека?
Насчет прерываний не уверен, врядли оно даст себя прерывать во время активности на шине (а если и даст — то шина отвалится).
0
Хм, ясненько… Значит V-USB подходит разве что для опроса датчиков, наподобие датчиков температуры и отправки данных с компа на исполнительный механизм. Но тем не менее интересно!
0
На подобном стеке (на знаю каком) делали ИК-приемнички для ПДУ, а там необходимо мерять интервалы. Так что не так все плохо видимо.
0
Наверно, без напряга использовать как мост
0
Универсальный ИК приемник для ПК IgorPlug2 делался на основе проекта от Igor Češko.
0
Это просто не единственный проект, который я видел. Я например видел еще какой-то коммерческий, на tiny2313, не знаю, какой там стек.
0
На основе V-USB можно очень многое сделать, не только датчики… Из всех ресурсов микроконтроллера используется только прерывание INT0 (можно настроить и на другое, но это не столь важно). Для того чтобы не отваливалось устройство USB при обработке любых других прерываний всего то нужно разрешать прерывания внутри прерываний и максимум каждых 50 мс запускать функцию usbPoll().

Короче говоря если мы будем использовать любые другие прерывания в своих целях, то сразу же нужно установить флаг I коммандой sei()

Если нужно добиться большей производительности, тогда просто повышаем тактовую частоту.
0
Про глубину стека можно не беспокоится если собственных прерываний будет не очень много. В собственном прерывании мы будем разрешать другие (в основном для V-USB, но может и другое сработать) а внутри INT0 ничего другого разрешаться не будет. Главное чтобы обработчики прерываний были компактными и быстрыми.
0
Появилась проблема:
Когда подключаю к компу, девайс работает нормально, запускаю прогу, она запрашивает данные с девайса и отображает, но через некоторое время (от 4 сек до 8 минут) устройство ставновится невидимым для программы, тоесть ф-ция connect() возвращает 0. Программа снова находит девайс только когда передернуть юсб шнур (при этом, питание устройства не прерывается). К тому же, все это время остальная часть устройства работает нормально (опрос десяти устройств по rs485 и отображение строк на ЖК дисплее).
При этом usbPoll() вызывается не реже чем раз в 30 мс, и во всех обработчиках прерывания (юарт, таймеры) стоит в начале sei.

Кто нить сталкивался с этой проблемой?
0
Забыл добавить: в диспетчере устройств после глюка оно всеравно отображется.
0
если в диспетчере устройство есть и при этом на нем не стоит никаких ошибок, то скорее всего проблема в ПО на компе.
Или мб у вас оно отвалилось и подключилось быстро, а вы не обратили внимание на звуковое оповищение из-за музыки ))
0
Только что посмотрел через еверест. Оказывается, что при нормальной работе в эвересте отображаются производитель, продукт, VID/PID, клас, а когда программа не может найти устройство, то только VID/PID. Соответственно, программа не может найти устройство.
Как можно исправить этот глюк?
0
и еще: я передаю по 76 байт, может из-за этого ошибка:
0
Нет, 76 байт ни при чем. Нарушена работа V-USB внутри МК. Внимательно проверьте свои прерывания, можете поотключать все для эксперимента (только INT0 оставить) и проверять устойчивость работы — пересылайте/принимайте свои 76 байт. Если будет и дальше отваливаться, значить проблема в железе (МК, резисторы, стабилитроны, плохой кабель...)

У меня таких проблем не было, все устойчиво работает. Тот LED экран 8x32 целыми днями мучил когда отлаживал, при чем данные отсылаются постоянно с интервалом 0.5… 0.01 с (регулирую софтом скорость).
0
Ага, это походу не из-за 76 байт. Я даже когда просто вызываю ф-цию connect, после нескольки сот запросов опять дисконект.
Резисторы и стабилитроны проверил — рабочие.
Мож у кого то есть хать примерный догадки, из-за чего такие глюки?
0
90% — проблема в коде для МК, экспериментируйте, ищите, на словах тут сложно что-либо посоветовать, нужно действовать
0
Пробовали просто пересылать данные при отключенных своих прерываниях, что-нибудь ради теста?
0
У меня та же самая проблема! Удалось ли Вам решить ее?
0
Вообще никак не получилось решить проблему. Точней получилось, но нехорошим способом: если функция сетап не вызывается 10 секунд, то МК делает реконект
0
Самое интересное, что программа на компе, как будто подвисает, а потом продолжает работать как не бывало, без всякого дисконекта-коннекта устройства от/к usb.
Даже если внутри МК крутится базовая программа — я только закомментарил вывод в порты.
Кстати происходит подвичание совершенно случайно — может через пару секунд, а может, действительно несколько десятков минут работать.
Может все-таки в драйвере проблема?
0
Порты это мелочи, с драйвером проблем нет — отлично работает в множестве проектов. Еще раз внимательно проверьте все СВОИ ПРЕРЫВАНИЯ! Большинство подводных камней именно у конфликтах с прерываниями а также с атомарными операциями, такие баги действительно совершенно случайны, могут всплывать у самый неожиданный момент.

Почему то сразу вспомнился абзац «Лирическое отступление» из статьи "AVR. Учебный Курс. Программирование на Си. Атомарные операции" :)
0
РАЗОБРАЛСЯ!
После глюка с тем девайсом, делал еще несколько, но использовал LibUSB, проблем небыло, но вот на этой неделе делал еще один тоже с LibUSB, и начались точно такие же дисконекты, почти 2 дня пытался понять в чем проблема. Оказывается, что проблема была в разводке платы. В 2 устройствах, который глючили, дорожки были зигзагами и достаточно длинными, это и была проблема.
Вот кусок платы:

Одна дорожка выделена красным, я заменил ее на кусок провода и глюк пропал
0
Хорошо все что хорошо заканчивается :) Все таки у вас проблема была аппаратная… Но все же странно, сам по себе USB достаточно помехоустойчивый, так как данные передаются по проводам D- и D+ дифференциально.
0
ну, как видно, недостаточно. Я думаю, что это баг софтового ЮСБ.
0
Вот поэтому, по идее, USB следует тянуть по плате специальной дифлинией. Хотя на LS обычно на это можно забить, так что я тоже удивлен, что возникли проблемы.
0
  • avatar
  • Vga
  • 30 сентября 2011, 21:54
Слишком короткие дороги для проблем. Может быть, проблемы с чистотой зазоров вокруг той трассы, которую заменили проводом? Кстати, а что за хитрость, выводы 5 и 6 МК через резисторы, наверно, свести в одну точку?
0
неа, плата промыта ультразвуком, а вокруг той дорожки я процарапал иголкой.
второй резистор 1,5к, его можно вешать или на + питания, или на ногу мк, которую надо выбрать в usbconfig.h
0
Вот ссылка, посмотрите на 3 странице как выполнена схемотехника USB ввода и обратите внимание на текст из трех пунктов над ней.
0
Это для FS/HS. На LS на все это по идее можно забить. Там даже от кабеля не требуют свивки и экранирования, тогда как HS уже на 5-10см такого кабеля мрет.

Via'шки кстати на USB линиях ставят, еще как. ЕМНИП даже на SS парах (а там 5ГГц сигнал).
0
А как бы сделать так, чтобы МК не запитывалось от USB, имея собственное питание?
0
Не подключать VCC от шины, нэ?
Для обнаружения подключения можно завести VCC через резистор (во избежание паразитной запитки) на вход детекта подключения.
0
Думаю, если не использовать задержку резета фузами, то можно брать прямо с супрессора сброса на гейт Р-мосфета в цепь +V_USB и через инвертор на гейт N-мосфета в цепи GND_USB, после которых и ставить резистивный делитель. Если используется задержка, например, для инициализации знакосинтезирующего индикатора, то придется пожертвовать ногой МК, которой и открыть ключи после необходимой задержки.
0
Выложи пожалуйста конфигурацию FUSE. Блин замучался. Залочил уже 2 микросхемы (Ранее «паял» только с внутренним RC). Буду очень благодарен. Шью через вот это
0
Для ATmega8 так:

Здесь fuse bit's по аннотации Atmel(как в даташитах):
без галочки — значит не запрограммирован (1),
стоит галочка — запрограммирован (0).

Отличный калькулятор: Engbedded Atmel AVR® Fuse Calculator
Статья от DIHALT-а: AVR. Учебный Курс. Конфигурация FUSE бит
0
По вашему комментарию я так и не смог догадаться чем шьете :)

Главное поставить тактирование от кварца, CKSEL3..0 = 1111 по даташиту!!!

Ни в коем случае не перепутать с CKSEL3..0 = 0000 — это внешний источник тактовых импульсов, иначе придется собирать простенький генератор.
0
Урааа заработало на 12 Mhz. В 2 часа ночи :). Залил прошивку. сегодня буду припаивать сам USB разьем. Зашивал через Khazama AVR Programmer сообщение обрезалось наверное потому, что вставлял как ссылку. Спасибо.
0
Сегодня наткнулся на интересный проект: Atmega fusebit doctor. Будет очень полезным при желании восстановить ваши залоченые микросхемы :) Конечно лучше собрать HVSP программатор, например AVR-Doper, хотя в целях поправить FUSE биты такой «доктор» проще.
0
все конечно хорошо, и даже прошитый контроллер определился как устройство HID после некоторых мучений :) но увы не видно VID/PID данного устройства -> соответственно программка не может подключиться к этому устройству и выдает ошибку "… не подключено". Я так понимаю, что проблема с USBCONFIG файлом в проекте для МК. Вопрос в следующем: куда в проекте для МК подключается этот usbconfig.h? В проект я его кинул как и было написано…
0
Файл usbconfig.h в проекте для МК на AVR Studio явно нигде подключать НЕ нужно, он должен просто лежать в каталоге проекта. VID/PID устройства указывается дефайнами USB_CFG_VENDOR_ID и USB_CFG_DEVICE_ID соответственно (желательно использовать свободную пару 16c0/05df от obdev, подробности внутри USB-IDs-for-free.txt).

Библиотека для билдера «hidlibrary.h» по дефолту ищет Hid устройства с VID=16c0 и PID=05df (прописано константой внутри библиотеки: const char idstring[] = «vid_16c0&pid_05df»;).

Если изменяли VID/PID, тогда внимательно всё проверьте, может где-то ошиблись :)
Примеры к статье проверены, работают отлично…
0
спасибо, буду смотреть, может и правда где профонарил ;)
0
Если появится желание прикрутить гальваническую развязку посредством, например, ADUM3160, то политика с R1, R2, D1, D2 остается в силе?
0
  • avatar
  • DVF
  • 06 апреля 2011, 14:20
Почитал я даташит, вот что пишут:
•  Peripheral devices have a fixed data rate that is set at de
time. The ADuM3160 has configuration pins, SPU and
SPD, that are set by the user to match this speed on the 
upstream and downstream sides of the coupler. 
•  USB enumeration begins when either the D+ or D−line
pulled high at the peripheral end of the USB cable. Con
of the timing of this event is provided by the PIN input 
the downstream side of the coupler. 
•  Pull-up and pull-down resistors are implemented inside
the coupler. Only external series resistors and bypass 
capacitors are required for operation. 

Значит подтягивающие резисторы уже внутри, SPU и SPD — специальные пины конфигурации. Стабилитроны наверно уже не нужны будут (гальваническая развязка). Думаю проблем не должно быть, пробуйте на реальном железе (у меня нет возможности поэкспериментировать с ADUM3160)
0
Добрый день. Спасибо за статью.
Будучи новичком в программировании (и микроконтроллеров в частности) вроде бы всё понял, что модифицировать, чтоб плоучить что-то своё, но тем не менее возник вопрос:
Возможно ли проверить работу soft реализации usb, без микроконтроллера, скажем в Proteus'е?
Я запихнул Ваш .hex файл в Proteus, при запуске — никакой реакции, хотя вшитые примеры выплёвывают что девайс обнаружен.
Собственно весь мой опыт работы с контроллерами — 3 дня, так что вероятно где-то что-то сделал не так.
0
Здравствуйте, лично не проверял, но подозреваю что в протеусе V-USB работать правильно не будет… Симулятор протеуса делекий от идеала, иногда даже простые примеры ведут себя совсем не так как реальное железо. Потому рекомендую экспериментировать именно на настоящем микроконтроллере :)
0
Эх, в том то и дело, что програму надо написать по учёбе, и я надеялся обойтись без покупки микроконтроллера. Увы, сколько я не копал — ничего подходящего, кроме протеуса, на чём можно было бы проверить подключение по USB, не нашёл =(.
0
AVR-ки достаточно дешевы и доступны :)
0
Запустил сегодня сей пример на Atmega32. Отладка через JTAG. Долго танцевал с бубном, не понимая почему контроллер постоянно пересбрасывается, пока не поменял в файле Makefile «MCU = atmega8» на «MCU = atmega32». Хотя в настройках проекта AVR Studio изначально выставил тип контроллера atmega32. Линию подключил как советуют «OBJECTIVE DEVELOPMENT»-цы: D- 1k5 на VCC, D+ 1M на GND. Подключение 1к5 — через отдельную ногу. Работает. Портировал все это хозяйство в IAR 5.5. Тоже не без плясок. Работает.
Большое спасибо за статью.
0
Всегда пожалуйста, очень рад что заинтересовала и хоть чем-то помогла статья. Танцы с бубном хороший метод в любом деле :) Честно говоря USB достаточно сложный, ещё предстоит много чего раскурить… Спасибо людям, которые внесли свою лепту в это дело :)
0
Хорошие примеры :) Мне понравилось воспроизведение звука на RC цепочке (кратко упоминается у us5.djvu как вариант для говорящего термометра)
AN #165 — RC2 sound / Voice playback, и даже исходники (на Bascom)
RC Sound encoder
0
Здравствуйте! Собрал устройство по примеру. Всё отлично работает. После перекомпиляции компьютерной программы, она пишет, что устройство не подключено. Хотя исходная версия работает. Компилирую в BORLAND C++ 6. Ошибок при компиляции не выдаёт.

Не знаете в чём неисправность?
0
Здравствуйте, довольно подозрительная ситуация… Если имеется ввиду перекомпиляция без изменений в коде, тогда однозначно нужно разбираться с билдером (можете попробовать установить такой: Borland C++Builder 6 Enterprise Edition + UPDATE 4) и виндой (рекомендую Simplix). Всё тестировалось на нескольких компьютерах под ОС Win XP — отлично работает :)
0
Спасибо!!! Установил предложенный Вами билдер и всё заработало!!!
0
Народ кто нибудь пробовал сие железо на виндовс7? у мну чет не хочет vendor name показывать. В чем может быть проблема?
0
Где именно не отображается Vendor name? Лично на 7 не проверял, теоретически должно работать (попробовать совместимость + права админа). Everest-ом удобно смотреть все железяки на ПК, пример на скриншоте в статье.
0
Заработала! Проблема была в моем компиле. Апдейт 4 помог
0
скажите кто нибудь, можно ли реализовать примерно такой же обмен по usb только с PIC16F84, или для этого надо контролеры с какими-тот специфическими функциями?
0
«примерно такой же обмен по usb только с PIC16F84» реализовать не получится (во первых программного USB для данного контролера нет; во вторых даже если сильно захочется написать самому с нуля, что маловероятно, недостаточно ОЗУ — 68 bytes of Data RAM по даташиту).
Варианты решения:
1. Использовать универсальный конвертор USB в «другой» интерфейс (например FT232RL)
2. Перейти на более жирный PIC-камень с апаратной поддержкою этого чуда — USB PIC микроконтроллеры (полезные ссылки: Какой лучше PIC взять для USB, Практическое использование интерфейса USB в PIC контроллерах)
0
Ну, ОЗУ-то возможно и хватит (тот же obdev V-USB просит 45 байт), но он же работает на частоте до 20МГц, а машинный цикл — 4 такта. Это три команды (причем одноцикловые) на бит USB. Это АВР-ки однотактовые, им 12 МГц кое-как хватает.
0
Соглашусь, ОЗУ возможно и хватит на очень урезанную реализация стека. Чего точно не хватит на данном этапе — знаний для написания аналога V-USB под PIC.
0
спасибо за ответы, довольно быстро среагировали)
0
если мне память не изменяет то только некоторые команды 2-ух тактные, тип btfss и еще несколько, а остальные выполняются за один такт, или я ошибаюсь?
0
Я с пиками не знаком, но соседняя статья их упоминала, и там сказано, что у пиков, по крайней мере старых (а PIC16F84 к ним относится) машинный цикл — 4 такта, а команды исполняются за один (некоторые за два) машинный цикл. Примерно как C51, только у тех при тактовой 12 МГц производительность вообще ~1MIPS (у стандартного ядра, которое скажем в распространенных AT89 — у него 12 тактов на машинный цикл).
0
А возможно ли передать строку? Ну т.е. текст загнать в пам контролера?
0
Естественно можно любые данные в двоичном виде :)
0
меня интересует как закодировать. И какой тип юзать на мк.
0
Спасибо за отличный материал, но возникла проблема. Я по этой схеме собрал все как указано и на моем компе все работает на 100%. Однако после проверки на компе в офисе я получил сообщение что «Устройство не опознано» и т.п. Проверка на других компах (всего их было 8) показала что подобная ситуация возникла еще на одном. Т.е. 2 из 8 отказались определять устройство. Другие HID USB устройства на них работают без проблем. 3 дня ломаю голову — компы разные (Aces, Asus и т.д.), а Windows XP одинаковый и установлен с одного диска. Настроек в BIOS на счет USB 1.1 и 2.0 на них вообще. Короче чудеса еще те.
0
Все нормально. Софтовый USB не везде работает. Можешь попробовать подключить через хаб (или наоборот, не через хаб, если подключено через него). А можешь использовать МК с аппаратным USB.
0
Да чуть не забыл! Настроек в BIOS на счет USB 1.1 и 2.0 на них нет вообще. А неизвестное устройство пишет в диспетчере устройств USB\VID_0000&PID_0000\и тут разную ерунду). Подскажите в чем косяк, может кто-то уже правил подобное.
0
Софтовый USB не везде работает? Интересно почему? Конечно можно взять кристалл с готовым USB, но хочется разобратся в чем здесь дело. Все равно спасибо!
0
Потому, что он не полностью соответствует стандарту.
0
Извините за назойливость, но в чем конкретно несоответствует и можн ли это исправить?
0
Всем подряд. Как на физическом уровне, так и на программных. Исправлению, AFAIK, не подлежит, иначе бы авторы давно исправили, но увы, мешают физические ограничения AVR'ки.
0
Очень интересно.Спасибо за статью!
0
Понял почему у меня не работал прибор на 2 компах. В представленной здесь схеме нет диодов D2 и D3 на V+ как в стандартной схеме. Подключил полностью по ней и все заработало. Если кто знает скажите их назначение? Почему в одних схемах они есть, в других нет.
0
Здесь вместо них стабилитроны на D+ и D-. Суть в том, что уровни на линиях Data — 0В и 3.3В, поэтому нужно либо питать контроллер от 3.3В (дешевле всего — через два диода, но можно поставить LDO на 3.3В), либо ограничивать напряжения на линиях стабилитронами на те же 3.3В. Если с диодами у тебя работает лучше — стабилитроны можешь выкинуть.
Но вариант с диодами тоже не везде работает, к тому же, ЕМНИП, атмел не гарантирует, что при 3.3В мега8 заведется на 12МГц.
0
Спасибо за пояснения, попробую собрать еще один со стабилитронами и поэксперементировать с разными марками, может заработает.
0
dcoder еще грозился сей чудный код под stm8 портировать, но может уже конечно забыл. Ждем с нетерпением)
0
Собрал я эту штуковину — работает без проблем. Но есть у меня вопрос. Кто знает, возможно ли в принципе чтобы контроллер одновременно выполнял функции
HID-клавиатуры, HID-мыши, HID-custom, ну в общем на все руки мастер. Вероятно нужно создать в проекте несколько дескрипторов репорта??? Или я заблуждаюсь?
0
Нужно создать один большой дескриптор репорта с несколькими ReportID для каждого вида. Автор давал ссылку, там есть пример.
0
Спасибо, посмотрю.
0
Касаемо реализации — устройство высылает последовательность байт, первый из которых — ReportID соотвествующей части дескриптора нужного «подустройства», а остальные — структура с передаваемыми данными. Только вот для мыши и клавиатуры данные передаются через Interrupt-конечные точки соответствующими функциями библиотеки.
0
Собрал два устройства — подключаю по очереди. То, что последнее (в любом порядке), не определяется виндами — пишет неизвестное устройство. Хотя USB_CFG_DEVICE_NAME у устройств разные, и в соответствии с первой статьей все должно работать… Что не так?
0
  • avatar
  • sasa
  • 10 августа 2011, 11:16
У устройств с одинаковыми VID/PID должны быть определены и не совпадать USB_CFG_SERIAL_NUMBER (серийный номер).
0
Спасибо за совет! Прописал разные серийные номера — эффект изменился: иногда удается подключить все устройства, но после их отключеня становится невозможным заново их подключить (пишет «неизвестное устройство» сколько не вытыкай/втыкай, хотя пару секунд назад подключалось все отлично) — приходится ждать много времени…
0
Попробуйте сделать одинаковыми в обеих устройствах USB_CFG_VENDOR_NAME и USB_CFG_DEVICE_NAME — вдруг поможет ;)
0
чудеса! работает. огромное спасибо!
Напрашивается три вопроса: 1) почему последним способом работает (одинаковые вендор и девайс нейм, но разные сериал намберы), а первым (одинаковый вендор, разные девайс нейм и намберы) — нет?
2) нет ли противоречия, в том, что устаройства-то на самом деле разные, а у них девайс неймы одинаковые?
3) как с помощью описанной в статье бибилиотеки hidlibrary вытянуть сериал намбер?
0
1) При одинаковых PID/VID и отсутствии серийного номера в устройстве ОС не сможет их различить, поэтому про второе устройство после считывания дескриптора система забывает. Если у устройств есть S/N, одинковые VID/PID, но разные DevName, ОС слетает с катушек, т.к. по VID/PID устройства одинаковые и драйвер нужен один и тот же, а по DevName — устройства разные, и дла каждого нужен свой драйвер.
2) Представьте, например, принтер — в DevName записана модель этого принтера, различаются только серийники, и при этом можно без проблем воткнуть несколько принтеров в один комп.
3) Нужно добавить в hidlibrary.h экспорт функции HidD_GetSerialNumberString, ну и использовать ее для получения S/N.
+1
Большое спасибо Resp за помощь! Но, не поверите, опять проблема ))) 1) добавил в хид библиотеку функцию чтения серийного номера (строки) по аналогии с 2) написал для каждого из устройств int connect_dev1() и int connect_dev2(), где теперь сверяются три параметра (вендор, девайс и сериал)

Если не запускать программу — все устройства определяются просто замечательно. Как только запускаю программу, винды опять пишут про неизвестные устройства ((( что не так?
0
может что-то еще нужно задать для устройств?
0
Библиотека изначально заточена под одно устройство, переменная m_ConnectedDevice как раз содержит его адрес после удачного подключения, поиск ведется среди всех (сохраняются у векторе m_HIDPaths функцией EnumerateHIDDevices).

Программа вообще не должна никак влиять на подключенные устройства, значит ваша модификация библиотеки содержит ошибки :)

Согласен с Resp, необходимо добавить проверку серийника устройства, также придется добавить путь для второго устройства (например m_ConnectedDevice2), две ваши функции int connect_dev1() и int connect_dev2() (или одну, с параметром), а также добавить параметр для функций Transmit/ReciveData (при желании и остальные функции модифицировать для поддержки нескольких железячек) — чтобы общаться с нужным устройством.

А также как вариант решения, чтобы не переписывать всю библиотеку — можно сделать две копии библиотеки с разными именами (добавить лишь проверку серийника), каждая будет работать из своим устройством.
0
Небольшая поправка: функция Connect(unsigned int device) уже содержит параметр — номер устройства к которому хочем подключится среди m_HIDPaths, реально нужно добавить только проверку серийника. Но при таком подходе общение с устройствами только по очереди. Варианты решения выше позволят параллельное общение с устройствами.
0
а можно ли сделать так:
HIDLibrary <data_struct> hid_dev1;
HIDLibrary <data_struct> hid_dev2;

чтобы не плодить библиотеки?
0
Попробовал — получается, только повторяется ситуация из моего предыдущего поста:
Если не запускать программу — все устройства определяются просто замечательно. Как только запускаю программу, винды опять пишут про неизвестные устройства ((( что не так?
библиотека, за исключением доработок по проверке сирийника — идентична исходной
0
Естественно что должно получатся, это обычное объявление двух экземпляров класса.

Странно, очень странно. Похоже на то, что проблема все таки в доработке по проверке серийника. Сложно из одних только комментариев сделать выводы, необходимо проверять в железе именно с вашими модификациями.
0
мою библиотеку смог разместить только тут www.super-bit.ru/sojonbxcxmdb.html
0
Тут вы добавили серийник к информации про устройства, храниться в map<string,string> m_HIDDeviceIdents:
if(strlen(s1)>4)
{
   strcat(s1," "); // s1 = s1 + " "
   HidD_GetSerialNumberString(h,buffer,500);
   wcstombs(s1+strlen(s1),buffer, 1000);
}

. . .

m_HIDDeviceIdents[path]=s1;
m_HIDPaths.push_back(path);
Проверьте отличается путь для разных устройств (теоретически должен быть разным, но у меня нет двух устройств V-USB, чтобы поэкспериментировать) или нет (string path, ключ для map), возможно в этом ошибка.

Функция Connect использует именно путь:
m_ConnectedDevice = m_HIDPaths[device];

Получается что серийник просто себе лежит без дела в map, как значение, а путь — это ключ для того же map. И посмотреть серийник можно только после Connect:
string GetConnectedDeviceName(){return m_HIDDeviceIdents[m_ConnectedDevice];};

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

Интересно сколько устройств возвращает вам функция:
string GetDeviceCount() { return m_HIDPaths.size(); };

Также желательно выложить код, который юзает библиотеку.
0
Хотел использовать INT1 вместо INT0, контроллер ATMega 16, в файле usbconfig.h изменил следущие дефайны:
#define USB_INTR_CFG            MCUCR 
 #define USB_INTR_CFG_SET        ((1 << ISC10) | (1 << ISC11)) 
 #define USB_INTR_CFG_CLR        0 
 #define USB_INTR_ENABLE         GICR
 #define USB_INTR_ENABLE_BIT     INT1
 #define USB_INTR_PENDING        GIFR 
 #define USB_INTR_PENDING_BIT    INTF1	 
 #define USB_INTR_VECTOR         INT1_vect

При подключении система говорит: «Неизвестное USB устройство», c INT0 всё отлично работает. Может что-то ещё надо поменять?
0
Наверное забыл еще подправить линию, на которую заведен INT1:
#define USB_CFG_DPLUS_BIT       2
/* Это номер бита в USB_CFG_IOPORTNAME, куда подключен сигнал D+, может
 * использоваться любой бит в порте. Пожалуйста, примите во внимание, что D+
 * должен быть также подсоединен к ножке прерывания INT0! [Вы можете также
 * использовать другие прерывания, см. секцию "Optional MCU Description" далее,
 * или Вы можете подсоединить D- к прерыванию, как это необходимо если Вы
 * используете опцию USB_COUNT_SOF. Если Вы используете D- для прерывания,
 * оно будет срабатывать также от маркеров Start-Of-Frame каждую
 * милисекунду.]
 */
0
Нет, всё поправил.
0
А какой компилятор? IAR? Потому что для avr-gcc наведенные вами дефайны вообще ненужны.
0
Поспешил я с выводами: именно здесь нужны изменения чтобы перейти на INT1, верно писали у комментарии выше + настройка линий порта, на этом пожалуй все, больше ничего править не нужно.
0
Проверьте ещё раз усе в даташите по поводу INT1, может какой бит или регистр неверно прописали.
0
Компилятор avr-gcc, в файле usbdrv.h заменил всё, что касается INT0 на соответствующее INT1:

#ifndef USB_INTR_CFG_SET    /* allow user to override our default */
#   if defined(USB_COUNT_SOF) || defined(USB_SOF_HOOK)
#       define USB_INTR_CFG_SET (1 << ISC11)                    /* cfg for falling edge */
        /* If any SOF logic is used, the interrupt must be wired to D- where
         * we better trigger on falling edge
         */
#   else
#       define USB_INTR_CFG_SET ((1 << ISC10) | (1 << ISC11))   /* cfg for rising edge */
#   endif
#endif
#ifndef USB_INTR_CFG_CLR    /* allow user to override our default */
#   define USB_INTR_CFG_CLR 0    /* no bits to clear */
#endif

#ifndef USB_INTR_ENABLE     /* allow user to override our default */
#   if defined GIMSK
#       define USB_INTR_ENABLE  GIMSK
#   elif defined EIMSK
#       define USB_INTR_ENABLE  EIMSK
#   else
#       define USB_INTR_ENABLE  GICR
#   endif
#endif
#ifndef USB_INTR_ENABLE_BIT /* allow user to override our default */
#   define USB_INTR_ENABLE_BIT  INT1
#endif

#ifndef USB_INTR_PENDING    /* allow user to override our default */
#   if defined  EIFR
#       define USB_INTR_PENDING EIFR
#   else
#       define USB_INTR_PENDING GIFR
#   endif
#endif
#ifndef USB_INTR_PENDING_BIT    /* allow user to override our default */
#   define USB_INTR_PENDING_BIT INTF1
#endif
0
Банальный вопрос: сигнал D+ шины USB подключен к тому самому INT1 микроконтроллера (PD3 для ATmega16), или же он остался на INT0 (PD2)?
0
D+ подключил к PD3.
0
Читал я полезный топик на форуме obdev — problems with using external interrupt different from INT0, есть примеры.

Очень важно, чтобы желанное прерывание для V-USB имело самый высокий приоритет, иначе тоже не будет работать. Если выделить INT1 для V-USB, то INT0 уже нельзя использовать как прерывание, только как GPIO.
0
А где в AVR Studio 5 установить частоту кварца подобно скрину в статье?
0
  • avatar
  • DVF
  • 05 октября 2011, 13:14
На одной из вкладок опций компилятора есть список Defines. В нем, в виде «F_CPU=12000000L». Аналога полю Frequency не нашел.
0
«Define symbols (-D)»?
0
Да
0
Уважаемые, будьте добры, подскажите (объясните), пожалуйста!
Необходимо от устройства на основе микроконтроллера получать данные типа int (long) и float. Что в usbHidReportDescriptor[] (и, наверно, не только тут) нужно менять?
0
Дескриптор можешь оставить без изменений, просто сделай свою структуру, при помощи которой передавай что душе угодно :)
Пример:
struct dataexchange_t
{
   int i;
   long l;
   float f;
};
0
Ну размер-то репорта в нем придется поправить. Алсо вроде какие-то ограничения на его размер есть.
0
Размер репорта мы не сможем вылезти он у нас статический:
0x75, 0x08,                             //    REPORT_SIZE (8)
А вот количество репортов увеличится автоматически:
0x95, sizeof(struct dataexchange_t),    //    REPORT_COUNT
0
Ограничение действительно есть:
5.6 Reports
Using USB terminology, a device may send or receive a transaction every USB
frame (1 millisecond). A transaction may be made up of multiple packets (token,
data, handshake) but is limited in size to 8 bytes for low-speed devices and 64
bytes for high-speed devices.
Но для нас это все равно.
0
Спасибо за ответы.
Но… Я сначала так и пробовал.

Создал структуры типа
struct dataexchange_t
{
int a;
float b;
int c;
};
Передаю на чип:
a = 1, b = 2.3, c = 4
Считываю:
a = 1, b = 2.3, c = 0

Создал структуры типа
struct dataexchange_t
{
int a;
float b;
int c;
int d;
};
Передаю на чип:
a = 1, b = 2.3, c = 4, d = 5
Считываю:
a = 1, b = 2.3, c = 4, d = 0

В чем может быть ошибка?
0
С данных участков кода понять в чем проблема нереально :) Можно лишь догадываться, что ошибка возникает при заполнении структуры или передаче/приеме данных…
0
Уважаемый, XANDER. Вот код:
files.mail.ru/LFGF5V

Посмотри, пожалуйста, буду признателен.
0
Задание на дом: «Будьте добры, соберите кто-нибудь данный проект под AVR Studio 5». Никак не получается.
0
  • avatar
  • DVF
  • 10 октября 2011, 15:40
А в чём проблема?
0
Не собирается. error «USB_CFG_CLOCK_KHZ is not one of the supported non-crc-rates!»
0
Какие-то странности с этим. Проект собирается, если задефайнить ещё раз F_CPU, на этот раз в файле usbconfig.h. Хм.
0
Пример в студию (извините за каламбур). У меня ругается на redefined.
0
0
Ну вот и определи в usbconfig.h, а из остальных мест выпили. Только потом посмотри на предмет отсутствия варнингов от библиотеки задержек. Ну и в своем сорце располагай иклюд usb-библиотеки первым. Если варнинги будут — придется еще в опции компилятора добавлять, как я выше писал.
0
Собрал схемку с некоторыми незначительными отличиями (кварц на 16 мгц, два стабилитрона). Сделал все по мануалу, прошил, подключаю… Ось определяет устройство как USBAsp почему-то. Скачал приложенный архив, скомпилировал, зашил, ось определяет девайс как hid устройство. В чем может быть проблема? Совершенно запутался, это чистая мистика. Специально сравнил usbconfig.h, main.c, все идентично.
0
Добрый день.
Подскажите, пожалуйста, как решить данную проблему:

Nov  9 15:40:02 dimak-Joybook-S31V kernel: [62881.448107] usb 5-2: new low speed USB device using uhci_hcd and address 44
Nov  9 15:40:02 dimak-Joybook-S31V kernel: [62881.860155] usb 5-2: device not accepting address 44, error -71
Nov  9 15:40:02 dimak-Joybook-S31V kernel: [62881.860195] hub 5-0:1.0: unable to enumerate USB device on port 2

перепробовал 2 варианта сбора схемы… оба дают такой результат.
В windows — «неизвестное устройство», при просмотре inf-wizard.exe'ом(из пакета libusb-win32) у данного устройства vid и pid = 0, а install-filter.exe его не видит.
В каком направлении копать?
0
Вопрос автору:
В функции — uchar usbFunctionWrite(uchar *data, uchar len)
возвращается значение — return bytesRemaining == 0; /* 0 означает, что есть еще данные */
Что вы этим хотели сказать?
Если вы хотите принудительно вернуть значение нуля в переменной bytesRemaining, то операция 'bytesRemaining == 0;' работать не будет! Надо это делать честно: 'bytesRemaining = 0;'.
Если вы подразумевали ЧТО-ТО ДРУГОЕ!?, то return bytesRemaining == 0; не имеет никакого смысла. Не лучше ли, что бы не морочить другим голову писать классический вариант:
return bytesRemaining;
0
  • avatar
  • VBU
  • 01 декабря 2011, 11:44
Я не автор, но попробую Вам помочь.

то return bytesRemaining == 0; не имеет никакого смысла

Выражение return bytesRemaining == 0; имеет смысл. Функция вернет 0 (FALSE) если bytesRemaining не равно 0, и вернет отличное от 0 число (TRUE) если bytesRemaining равно 0.
0
Я конечно очень извиняюсь, может быть я что-то в жизни упустил, но подобный синтаксис: return bytesRemaining == 0, это нововведение для языка C/C++? По моемому это бред какой-то… Функция usbFunctionWrite объявлена, как uchar и возвращает она значение типа uchar содержащееся в переменной bytesRemaining, которое само посебе не измениться, если вы сами его не измените. А '==' используется в условных операциях и значения переменных не меняют!
0
  • avatar
  • VBU
  • 02 декабря 2011, 12:05
Нет, это не нововведение. Оператор сравнения ( '==' ) в С такой же оператор как и другие, его можно использовать где угодно, не обязательно в конструкциях типа if(…).

Вот смотрите, выражение «return a + b» вернет результат сложения a и b.
Выражение «return a == b» вернет результат сравнения a и b.
0
Вернее, '==' — это оператор равенства (equal to operator)
0
e_mc2,
Операторы сравнения не влияют (не изменяют) результат возвращаемой переменной (не путайте с арифметическими и логическими операторами).
0
  • avatar
  • VBU
  • 03 декабря 2011, 15:02
Конечно не изменяют! bytesRemaining в данном примере никак не изменится. Просто функция возвращает не bytesRemaining а результат сравнения bytesRemaining с 0.
0
Возможно, Вас сбивает с толку сам синтаксис.
Давайте распишем.


uchar res = (bytesRemaining == 0);
return res;


Переменой res будет присвоен результат сравнения bytesRemaining с 0.
Если bytesRemaining отличен от 0 то res будет присвоен 0 (FALSE), в противном случае, res будет присвоено отличное от 0 число (TRUE).

Такой синтаксис используется нечасто, но вполне допустим.
0
Конечно не изменяют! bytesRemaining в данном примере никак не изменится.

Я имею ввиду, что оператор равенства не изменит значения аргументов (bytesRemaining ). А вот результат (согласно стандарту, ЕМНИП, оператор == возвращает int) будет зависть от того, истинно равенство или нет.
0
Там все правильно. Просто ты плохо понимаешь С. e_mc2 правильно говорит.
Такой синтаксис используется нечасто, но вполне допустим.
Я бы не сказал, что нечасто. Напротив, довольно распространенная практика.
0
Щас делаю дешифратор UART для USB. Ну типа присла символ, а нажалась клавиша клавиатуры соотведствующая этому символу. Ну вроде HID клавиатури только опрос идет по UART. Никто не знает что по этому поводу почитать можна? Заранее спасибо.
0
0
Спасибо, очень интересно.
Собрал, работает, только на ХР-шке.
Что нужно сделать, чтобы в 98-ой Винде заработало.
Там устройство отмечено как «не известное».
Я пропустил, или этот вопрос не поднимался.
Подскажите.
0
Скорее всего вам надо поискать HID-драйвера для Win 98. Когда то давно для работы с флешками на Win 98 я ставил Maximus Decim Native USB ver.3.3 (сильно сомневаюсь что там присутствуют HID дрова, но можно поэкспериментировать). Но всё же эта ОС уже морально устарела :) Правда до сих пор вспоминается J3QQ4… А фееричный BSOD прямо на презентации ;)
0
Скорее всего именно этот универсальный драйвер у меня и установлен.
По крайней мере при установке «новой» флэшки всегда указываю один и тот-же каталог для поиска драйвера.
А вот для этого устройства не помогает :(
Оно остаётся «не известным»… :(
0
Hello
I would like to ask how I modify sample software to the PC it will be function?

I assigned a the way the library usbconfig, but the software not operated.

Thank you for your help
0
Hi
First of all you must to have some programming skills to edit this example :) Otherwise, it will be difficult to understand. You need to use Borland C++Builder 6 for recompiling the PC software.

There is line in file «main.cpp»:
#include "../Hid_example_firmware/usbconfig.h"
It is required for «USB_CFG_VENDOR_NAME» and «USB_CFG_DEVICE_NAME» definitions. These definitions are used by PC software for determining the device.

What does it mean «the software not operated»? Please, describe your problem in more detail.
0
My problem was in the old version Borland C++. The program working now. :)

I still have the problem as simply send the text(32 characters). :(
I can not just c + + only c for mikrotrolery.

Thanks for english answer
0
Как можно переслать текст через USB? У меня есть строковая переменная, но я незнаю как её передать на хост, так чтобы я с ним мог дальше работать в МК. Мне будет достаточно например его показать на LCD. Если у кого есть уже готовый код или подробное описание как это сделать.
Зарание спасибо за ваши ответы :)
0
Предлагаю посмотреть:
«Дмитрий Петров | Полиглот. Выучим английский за 16 часов! (16 из 16) [2012] SATRip»

Вообще работа со строками на Си — камень преткновения многих начинающих.
IMHO самый простой вариант и одновременно «легкий» для МК — это массив char:
struct dataexchange_t
{
char stroka1[128];
char stroka2[16];
};

struct dataexchange_t pdata;
...
sprintf(pdata.stroka1, "Hello world!");
sprintf(pdata.stroka2, "кирилица");
...
hid.SendData(&pdata);
0
Да, как-то непривычно общаться на русско-язычном форуме на чужом языке(+ на хромающем). Мот лучше попробовать на социально верном языке =)
0
А как быть если мне надо, например, по нажатию кнопки в устройстве выполнить какое то действие на компьютере? Ведь устройство, как я понял, не может инициализировать передачу?
0
  • avatar
  • Bonio
  • 28 февраля 2012, 23:29
Не может. Но комп его регулярно опрашивает (LS HID — с частотой 125Гц). Именно так и работают USB клавиатуры и мыши.
0
Опрашивать из программы по таймеру?
0
Хост опрашивает автоматически, и автоматически же забирает данные с конечных точек типа «interrupt» (если они готовы к передаче, а это уже определяется устройством). Вот как оно выглядит со стороны виндового API — не знаю.
0
Ну это всякие мыши и клавиатуры он опрашивает автоматически.
А если как в примере, надо забрать данные с устройства из самописной программы. Думаю, опроса по таймеру с частотой герц 30 хватит?
Если с большей частотой опрашивать программа не будет подвешивать компьютер?
0
Можно смело протестировать разное время опроса и проследить за нагрузкой на процессор. Теоретически не должно «подвешивать компьютер». Разве что бесконечные циклы по кругу гонять :) Правда слишком частые опросы могут круто загрузить AVR-ку, которая в отличие от PC более скромна у своих вычислительных ресурсах.
0
Не смогут они ее загрузить. В HID запросы легко фильтровать. Слишком часто PC микроконтроллер не спамит. Да и не така уж гиганская частота опроса меток в микроконтроллере чтоб это его загрузило.
0
Согласен с тем, что не всегда нужна гигантская частота опроса. Категорически не согласен с тем, что AVR-ку не смогут загрузить частые опросы (тут также важен размер передаваемых данных). V-USB для работы использует прерывание с наибольшим приоритетом, соответственно при пересылке пакетов все остальные задачи нервно курят в ожидании.
0
Пользовательская программа НЕ ОПРАШИВАЕТ контроллер!!! Она смотрит буфер, который создан хостом в памяти компьютера при инициализации USB-устройства. Частота просмотра буфера должна быть чаще, чем частота с которой контроллер посылает данные в буфер, в противном случае буфер будет переполняться и данные будут теряться. Частота просмотра буфера устанавливается в пользовательской программе.
Контроллер посылает данные в буфер, когда хост(комп) их запрашиает. Частота посылок из контроллера (точнее частота опроса контроллера хостом) устанавливается(прописывается) в прошивке контроллера в дескрипторе конечной точкb (это в последнем пункте дескриптора) и не может быть меньше чем 10мс для low speed.
0
Частота просмотра буфера должна быть чаще, чем частота с которой контроллер посылает данные в буфер, в противном случае буфер будет переполняться и данные будут теряться.
Точнее, скорость. МК может раз в кадр слать пару байт данных, а программа раз в 10-20 кадров читать все, что там накопилось — с полсотни байт. Главное, чтобы буфер не переполнялся между чтениями.
и не может быть меньше чем 10мс для low speed.
Вообще-то, HID-устройства, вроде мышей и клав, по дефолту опрашиваются в каждом восьмом кадре, а это 8мс или 125Гц. А нынешние «геймерские» мышки позволяют выставлять частоты вплоть до 1-2мс. Хотя я и не вижу в том смысла.
0
Точнее, скорость. МК может раз в кадр слать пару байт данных, а программа раз в 10-20 кадров читать все, что там накопилось — с полсотни байт. Главное, чтобы буфер не переполнялся между чтениями.
«Без сомнения.
нынешние «геймерские» мышки позволяют выставлять частоты вплоть до 1-2м
HID с full speed.
0
Ну, вообще говоря, до их появления LS мышки разгоняли правкой соответствующего драйвера в недрах винды, где частота опроса и задана. Хотя и не все мыши с такой нагрузкой справлялись.
0
Ну, вообще говоря, до их появления LS мышки разгоняли правкой соответствующего драйвера в недрах винды
Интересный факт, я и подумать о таком не мог.
0
Посмотрел в usbconfig.h
В этой реализации usb-устройства установлен интервал опроса контроллера хостом — 100мс
#define USB_CFG_INTR_POLL_INTERVAL 100
Т.е. буфер в компе получает данные из устройства каждые 100мс. Значение можно поменять при желании. Народ, дерзай!
0
здравствуйте. у меня есть плата с загрузчиком usbasp, будет ли она совместима с этим проектом?
0
Будет. Нет ничего невозможного :)
0
здравствуйте. у меня есть вопросик этот проект в С++??? если да скиньте папку со всем на мыло viorel_1990@mail.ru буду очень благодарен, надо очень да и не шарю в программирование ПЛЗЗ
0
даите плз прашивку всё сабрал ток прашивки нету плз
0
что, диплом горит? :)
0
да
0
Спасибо автору за статью. Реализовал девайс на AtMega16 (c соответствующим изменением usbconfig.h и выходных портов). Everest прекрасно видит HID устройство, но тестовая програмка на BC упорно его не находит (при нажатии Принять данные пишет — устройство не найдено). Подскажите, куда копать?
0
  • avatar
  • DPA
  • 21 мая 2012, 16:30
дебаг кода показал, что в функции connect() не отрабатывает кусок
if ( hid.GetConnectedDeviceName() == exampleDeviceName )
hid.GetConnectedDeviceName() возващает пустые строки. хотя, когда устройство отключено, в цикле 6 иттераций, а когда подключено, то уже 7 итераций.
0
у меня тоже самое чё делоть???
0
Билдер обновляли?
0
нет там галачьки были сняты, через гатовыи ехе работает а как поменял там каптионы так нифега не видет апарат
0
я нашел исходники под дельфи. ссылка
в оригинале tiny2313 я запустил с mega16. скомпилил — запустил, заработало с первого раза. только пумучился с установкой компонента для дельфей
0
я непоиму как кампилирывать???
0
Здравствуйте! Экспериментирую с юсб. Ваша прога работает, светодиоды загораются, гаснут, статус читается верно. Пересобираю прогу — ничего не работает. HidEnumerate показывает 2 устройства — мою мышь и собственно демо плату, если плату отключаю — показывает 1 ус-во — тут все норм. А дальше ничего не работает: в функции connect ф-я hid.Connect возвращает для обоих устройств 0(false), строка с именем и производителем пустая для обоих устройств. Билдер установил тот, на который вы давали ссылку. Винда 7. Билдер запускал и в совместимости и от админа — одно и тоже. В чем может быть проблема?
0
Должно вылечиться установкой UPDATE 4.
+1
Поставил, вроде заработало)Спасибо.
0
Великолепная статья, спасибо!
Вопрос — никто не переписывал программу на дельфях? Как пример? ну не видал я ранее борланд…
0
В этой программе ничего сложного. Скуриваешь книжку вида «С за 40 минут», после чего переносишь как есть — благо структура VCL-программ в билдере абсолютно идентична таковой в Delphi. Просто рисуешь такую же форму (строго говоря можно использовать форму из билдера, но в данном случае проще нарисовать), создаешь такие же обработчики, переносишь в них код из билдера и переводишь на дельфи.
0
Спасибо!
0
Во времена дипломов самая основная «халтурка» — это переписывание программ с дельфи на борланд и с борланда на дельфи.
0
А как можно переписать программу с фирмы на язык? Более того, как ее вообще можно на фирме написать?
0
захотите подработать перепишите. а будите придираться к заказчикам, халтурка билдовская вам не светит :)
0
Я придираюсь к тебе, а ты не заказчик ;).
0
Кто знает, кто знает…
0
вопрос начинающего в юсб- если сигнал идет на инт0, то как успевает другое работать- ведь там же не только мои сигналы, а вся шина!
0
Не вся видимо, не зря же в USB хабы активные.
0
на прерывании только мой обмен?! Я конечно почитаю, но что-то юсб не идет у меня- как посмотрю на библиотеку…
0
Что именно другое?
0
другое- я имел ввиду работу, для которой предназначен микроконтроллер- например, работа с чем-то по RS485, шина 1-wire и др. Кстати, АВТОРУ СПАСИБО ЗА ПРОЕКТ, спаял-работает.
0
Реально ли скомпилировать hidlibrary.h в Visual C++ 2008 express? У кого-нибудь получилось?
Дело в том, что библиотека из этого поста оказалось единственная, которая у меня работает.
Пробовал hidapi: без проблем скомпилировал библиотеку и пример к ней, устройство находит, но не шлет репорты. Атмеловская AtUsbHib.dll вылетает когда подключаешься к устройству с реальным VID,PID. Примеры на libusb win32 не находят HID устройство.
0
Нет ничего нереального :) Теоретически должно работать на любом уважающем себя компиляторе под винду. Там всё просто. Можно даже на асме Win API функции дергать, лишь бы желание.
0
А чего с HIDAPI не так? Там надо не забывать нулевой ReportID засылать, даже если оно не используется.
0
HIDAPI заработала, оказывается надо минимум 4 байта слать:
unsigned char buf[4] = {0,10,70,255}; // First byte is report number
hid_send_feature_report(handle, buf, 4);
0
Здравствуйте, Xander..
Пытаясь использовать исходники Вашего проэкта для своего, используя макетку AVR-USB-Mega16, мне было нужно увеличить количество портов, которыми можно управлять с ПК. Для этого я увеличил struct dataexchange_t pdata = {0, 0, 0}; c 3 нулей до 4… и прописал еще один байт uchar b4. Но при попытке отправить информацию на МК с уже запущенной програмки, мне все время выводится сообщение, что «we.easyelectronics.ru не подключено». Но в Everest'е устройство есть и все как на скриншоте с Вашей статьи. (Когда я зашил в МК Вашу прошивку, то все работало тип-топ, но как только к ней добавил еще один порт, получил эту проблему...) Уже все перепробовал, но так и не получается… На Ваше мнение, в чем может быть проблема?

P.S. Может быть проблемка сдесь?

PROGMEM char usbHidReportDescriptor[22] = { // USB report descriptor // Дескриптор описывает структуру пакета данных для обмена
0x06, 0x00, 0xff, // USAGE_PAGE (Generic Desktop)
0x09, 0x01, // USAGE (Vendor Usage 1)
0xa1, 0x01, // COLLECTION (Application)
0x15, 0x00, // LOGICAL_MINIMUM (0) // min. значение для данных
0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255) // max. значение для данных, 255 тут не случайно, а чтобы уложиться в 1 байт
0x75, 0x08, // REPORT_SIZE (8) // информация передается порциями, это размер одного «репорта» 8 бит
0x95, sizeof(struct dataexchange_t), // REPORT_COUNT // количество порций (у нашем примере = 3, описанная выше структура передастся за три репорта)
0x09, 0x00, // USAGE (Undefined)
0xb2, 0x02, 0x01, // FEATURE (Data,Var,Abs,Buf)
0xc0 // END_COLLECTION
};

Заранее спасибо, жду Вашего ответа, Степан
0
При помощи этих «3 нулей» можно спокойно управлять 24 пинами (1 байт = 8 бит, 8x3=24). Даже если и добавить четвертый, всё равно должно отлично работать. Перечитывая предыдущие комментарии, можно сделать вывод, что бывают проблемы если не установить UPDATE 4 на билдер: comment10214, comment67141. Дескриптор в данном случае менять не нужно (comment28321), так что «P.S. Может быть проблемка сдесь» отпадает сразу. Как показывает практика, в основном проблемы с пониманием Си. Сложно что-либо посоветовать конкретное в таком случае :) Самое необходимое — это желание, большая мотивация, и тогда всё получится.
0
а возможно ли в С++ Билдере изменить стиль формы чтобы она выглядела не как у Виндовс 2000, а как в Семерке? На мой взгляд, такой стиль кнопок выглядит довольно грубо(
0
если в самой семрке, то добавьте manifest к приложению.
0
боюсь показаться глупым, но что такое manifest?
0
Тогда лучше «выглядит довольно грубо»=) А вообще есть спец компонента… Удачи=)
0
нашел только XP Manifest.а для Севена не могу… Вы не можете подсказать где найти подобный файл?
0
Вроде семерка и с XP манифестом применит стили.
А вообще, манифест — это не компонент, а xml-файлик, закладываемый в ресурсы приложения. Вот инфу о его синтаксисе и ищи, она вполне доступна.
Кстати, для экспериментов с манифестом удобно использовать внешний манифест — просто положить манифест рядом с прогой и назвать так же, как exe, только .manifest (myprog.exe.manifest или myprog.manifest, не помню точно). Когда результат устроит — манифест можно засунуть в ресурсы.
+2
спасибо) получилось) действительно, как в Семерке)
0
Спасибо, дельная статья.
С помощью надфиля запустил проект на Atmel Studio 6 :)

Изначально планировал использовать CDC/ACM, но под Win7 x64 вечная проблема с подписью драйверов :D
0
  • avatar
  • hexus
  • 30 сентября 2012, 23:13
есть же атмега8 и 32 с железным усб на борту…
0
И что?
0
Здравствуйте. Нужна помощь.Собрал это девайс, прошил, при подключении винда определяет, через эверест тож-все норм. Проблема с программой хостом, при нажатии кнопки «принять/отправить данные» — пишет "… не подключено" т.е. не выполняется условие
if ( hid.GetConnectedDeviceName() == exampleDeviceName )
{
res = 1;
break;
}
Не могу понять в чем дело. В Си не силён, особенно в классах.Заранее спасибо.
0
Собрал это устройство, работает нормально с откомпилированного хоста. Когда пытаюсь сам компилировать — хост не видит МК. «Use dynamic RTL» и «Build with runtime packages» — галки сняты. В изначальном исходнике он немог найти файл usbconfig.h. Я его скопировал с папки где прога под МК(может быть в этом дело? хотя я пробовал вставлять тот конфиг что по ссылке выше). Компилируется нормально но устройство не видит. Почему уже откомпилированная прога с проэкта работает а эта нет? Хотя я еще не успел ничего там поменять кроме пути к usbconfig.h. Подскажите пожалуйста, очень нужно собрать устройство для обмена данными через юсб
0
  • avatar
  • zoox
  • 20 ноября 2012, 08:26
Комменты выше читайте.)
0
Да я уже давно разобрался. Все работает после того как апдейт поставил
0
уменя прога не компелируется не видит
#include "../Hid_example_firmware/usbconfig.h"
я его в каталоге тоже не нашол
0
«usbconfig.h» находится в папке с прогой под AVR. Нужно оттуда скопировать и соответсвенно изменить путь
0
Скажите пожалуйста можно ли както осуществить передачу отдельных участков структуры или както подругому? Столкнулся с такой проблемой что нехватает скорости. Структура немалая по размеру (переменные, массивы). Устройство передает данные хосту только при загрузке, далее только принимает. Сейчас после доработок возникла потребность передавать и получать данные одновременно но с хоста нужно передавать всю структуру а с устройства на хост только первые 3 байта. Когда пытаюсь передать всю структуру назад в хост то мне нехватает скорости… Можно ли както сделать чтоб хост передавал устройству всю структуру но читал только первые две переменные?
0
  • avatar
  • zoox
  • 03 января 2013, 14:03
Доброго времени суток, уважаемые специалисты! Помогите пожалуйста разобраться.

Скачал с сайта последнюю версию v-usb, тупо подключил библиотеки к avr studio 5, скопировал код из статьи. Компилирую и ругается вот на что:

s018.radikal.ru/i503/1301/15/c8ca02f5d277.jpg

Скачал четвертую версию студии, сделал то же самое, ошибка аналогичная, что в 5й, что в 4й. Скачал отсюда готовый проект с библиотеками v-usb, скомпилировал, все работает. То есть что то изменилось в библиотеках?? Как быть, объясните пожалуйста, пока я хочу тупо скопировать готовый проект. Опыта пока мало, писал только прошивки для часов с будильником и градусника на 18б20.

Поможите люди добрые!!! Сил нет уже и мозгов не хватает, что не так то??? Три ночи и три дня уже сижу
0
Ты сам-то на скрине хоть что-то разобрать можешь?) Не говоря уже о том, что скрины в JPEG — моветон. И вообще, скрин не нужен. Просто выдели ошибки в окне сообщений и скопируй их.
0
я сильно извиняюсь, сам не посмотрел что залил, только сейчас заметил блин.

../main.c:20:14: error: conflicting types for 'usbDescriptorHidReport'

вот ошибка. И далее идет варнинг ../usbdrv.h:477:6: note: previous declaration of 'usbDescriptorHidReport' was here
0
Скорее всего ты забыл настроить стек в usbconfig.h.
0
так я usbconfig.h скопировал прямо из текста статьи и еще раз подставил его из скачанного проекта в свой
0
А под что этот проект? Я пробовал открыть IAR — не видит файла проекта. В WinAVR последнем видит ошибку в makefile.

Под Codevision нет кода?
И еще вопрос — каков размер HEX получается? в TINY какой-нибудь можно запихнуть?
0
  • avatar
  • zheka
  • 13 февраля 2013, 21:24
Проект для AVR Studio 4, немного подпилив можно юзать и в новых студиях.

Под Codevision кода нет. Размер зависит от настроек V-USB и собственных требований. При желании можно и в Tiny, примеры: 1, 2, 3, 4, 5. Да осилит дорогу идущий :) Удачи
0
Там довольно жирные тиньки. Есть и примеры с 2-килобайтными ATTINY2313, в том числе и здесь. Ну и по идее на ATTINY25 тоже должно работать, только я их ни разу не видел :)
+1
И как его пилить надо? ПОд 5-ю студию?
0
  • avatar
  • zheka
  • 13 февраля 2013, 23:09
Точнее, српоуш по другому, если в 5-й студии слепить свой проект из прилагаемых файлов — будет компилитсья?
0
  • avatar
  • zheka
  • 13 февраля 2013, 23:10
Конечно. Почему бы нет.)
0
Там есть небольшая грабля. В AVR Studio 5 так и не нашел, как объявить дефайн F_CPU для ассемблера (по видимому, задавать его надо в строчке дополнительных опций командной строки для ассемблера, но у меня так и не получилось), поэтому пришлось объявлять F_CPU прямо в usbconfig.h.
0
Здравствуйте. ваш устройство прекрасно работает.Нужна помощь. я добавил usbconfig.h ку
#define ELECTRONIC_SINGATURE 'A','S','D','F','Q','W','E','T','G','F','T','H','G','H','G','H','G','H','2','1','2','1','J','G','H','5','6','H','G','H','5','6','5','G','H','G','H','6','5','H','5','6','G','H','G','H','6','5','G','H','5','6','G','H','G','6','H','5','6','G','H','2','G','3','F','D','3','F','D','F','F','D','F','H','G','H','H','H','F','G','H','F','G','D','G','D','G','J','H','G','H','J','H','J','F','H','G','D','F','H','G','H','J','H','F','D','G','H','F','D','J','G','H','J','H','G','J','F','G','H','J','H','F','H','G','F','8','7','7'

как эту константу присвоить dataexchange_t как char массив.

struct dataexchange_t
{
char *array[]; // здесь
};

я сделать в фуксии
uchar usbFunctionRead(uchar *data, uchar len)
{
pdata.array=ELECTRONIC_SINGATURE; //здесь ошибка выдает
}

как присвоить pdata.array массив ELECTRONIC_SINGATURE;
мне надо получит pdata.array в программе C++Builder 6
0
Приветствую. Важно понять каким образом передаются данные, в нашем случае структура dataexchange_t — это некая порция информации, которую хост может прочитать\записать.

char *array[]; — это указатель на массив, а не сам массив :) Получается за один раз можно прочитать\записать один указатель (грубо говоря одно число или один символ массива, потому что сам указатель не будет уже иметь смысла для программы на хосте). Если надо, то массив можно передавать например так:
struct dataexchange_t
{
 char array[3];
};

uchar usbFunctionRead(uchar *data, uchar len)
{
 ...
 pdata.array[0]='A';
 pdata.array[1]='S';
 pdata.array[2]='D';
 ...
}
#define ELECTRONIC_SINGATURE — это не массив, это макрос. Его содержимое будет подставляться вместо идентификатора ELECTRONIC_SINGATURE каждый раз, когда он встретится в исходном файле.
#define ELECTRONIC_SINGATURE 'A','S','D'
char  array[] = {ELECTRONIC_SINGATURE};
это тоже самое что: 
char  array[] = {'A','S','D'}
Желательно подтянуть уровень Си, тогда будет меньше таких вопросов :) Удачи
0
Спасибо. ещё один вопрос у меня программатор ChipBlaster clone
Atmega8 память 8kb а у меня 6кб hex file. он не прошивает. говорит file размер большой. что делать?
0
Собрал схему, сделал программу, все работает, обмен данными идет. Но никак не могу заставить параллельно работать USB и часы DS1307 (шина I2C)

У меня устройство, которое имеет собственное питание. Но когда обмен идет по USB, то и питание тоже только по USB. То есть, устройство работает, потом отсоединяется от питания, несется в другое помещение и втыкается в компьютер как флешка.

Суть проблемы такова — как только я добавляю или инициализацию часов или чтение информации из DS1307 — при подключении появляется неопознанное устройство.
Как я только ни менял порядок инициализации, то USB ставил на первое место, то часы — работает либо одно, либо другое, но не вместе.

Если я подключаю основное питание, а уже потом USB — то все нормально, сначала инициализируются часы, и проблем при подключении USB нет. Но по спецификации, для енумерации дается 100 мсек, а инициализация часов занимает 3 мсек.

Можно ли как-то решить проблему, не добавляя транзистор, который подтягивает к плюсу D- тогда, когда надо?

Вот код:
int main(void)
{

 DDRC |= _BV(0);
 DDRC |= _BV(1);
 DDRC |= _BV(2);
 DDRC |= _BV(3);

PORTC |= _BV(0);

    I2CInit();
	//Clear CH bit of RTC
	#define CH 7

	uint8_t temp;
	DS1307Read(0x00,&temp);

	//Clear CH Bit
	temp&=(~(1<<CH));

	DS1307Write(0x00,temp);

	//Set 12 Hour Mode
	DS1307Read(0x02,&temp);

	//Set 12Hour BIT
	temp|=(0b01000000);

	//Write Back to DS1307
	DS1307Write(0x02,temp);
PORTC &= ~_BV(0);




    usbInit();
    usbDeviceDisconnect();  // принудительно отключаемся от хоста, так делать можно только при выключенных прерываниях!
    uchar i = 0;
    while(--i){             // пауза > 250 ms
        _delay_ms(1);
    }

    usbDeviceConnect();     // подключаемся

    sei();                  // разрешаем прерывания


//Read the Second Register
	

 if (sec ==13) PORTC |= _BV(0);
 if (min==15) PORTC |= _BV(1);
 if (hr==9) PORTC |= _BV(2);
 

    for(;;){                // главный цикл программы

PORTC |= _BV(0);

DS1307Read(0x00,&temp);
	sec=(((temp & 0b01110000)>>4)*10)+(temp & 0b00001111);

	//Read the Minute Register
	DS1307Read(0x01,&temp);
	min=(((temp & 0b01110000)>>4)*10)+(temp & 0b00001111);

	//Read the Hour Register
	DS1307Read(0x02,&temp);
	hr=(((temp & 0b00010000)>>4)*10)+(temp & 0b00001111);
	PORTC &= ~_BV(0);
        usbPoll();          // эту функцию надо регулярно вызывать с главного цикла, максимальная задержка между вызовами - 50 ms
    }
    return 0;
}
0
Если проблема действительно в таймингах и V-USB голодает :) тогда надо оптимизировать обращение к часам, чтобы это занимало минимум процессорного времени.
добавляю или инициализацию часов или чтение информации из DS1307 — при подключении появляется неопознанное устройство
Попробуй другие библиотеки для часиков или напиши свою (сверхкомпактную и быструю). Как я понял из описания, транзистор не поможет, потому что «чтение информации из DS1307» тоже делает неопознанное устройство.
0
А библиотека для работы с часами прерывания случаем не выключает? К тому же, при работе с прерываниями и V-USB одновременно нужно разрешать вложенные прерывания.
0
вброшу ложку дёгтя — на новых чипсетах ноутов и пека AVRки с программным USB работают через жопу.
есть смысл задуматься — а не прикупить ли какой-нибудь lpc1343 хотя бы?
0
Сейчас лпц-шку достать тяжко. Лучше стм32 брать.
0
опрос DS1307 занимает всего 3 мсек.
ПРобовал в цикле принудительно включать прерывания — не помогло.
А как в AVRStudio разрешить вложенные прерывания?
0
Залезть в сорцы библиотеки и изменить там объявления прерываний. Как именно — не помню, нужно чтобы компилятор добавлял sei в начало прерывания и сохранял контекст. Если библиотечка на асме — можно и ручками добавить sei и сохранение контекста.
0
Уточню — это инициализация датчика занимала 3 мсек. А опрос — 250 мксек.
ВОт код:
PORTC |= _BV(0);
    DS1307Read(0x00,&temp);
PORTC &= ~_BV(0);
//	_delay_ms(30);

Дергаю нулевой ножкой порта C.
Если я включаю функцию чтения датчика — USB устройство не опознается. Если выключаюто устройство работает нормально, даже если включить задержку в 30 мсек, а это до хрена. Так что дело не в задержке…
0
Библиотека часов вот здесь zalil.ru/34372847
0
Гм, а прерываний-то библиотека и не использует… Тогда единственный вариант — в каких-то условиях опрос часов занимает более 50мс и прошивка не успевает вовремя вызвать usbPoll. Такое может быть, если часики тупят при обработке запроса. Тогда нужно переделывать I2C — выносить циклы ожидания в тот цикл, где вызывается usbPoll либо делать I2C на прерываниях (не забывая сразу же разрешать вложенные прерывания в них).
0
Да нет… это какие-то глюки…
Потому что бессмысленное, на первый взгляд действие — добавление PORTC |= _BV(0); в начале цикла и PORTC &= ~_BV(0); в конце — так, для индикации, приводит USB в норму… И выясняется что весь опрос DS1307 (3 запроса) при любых условиях занимает 750 мксек. Правда с DS1307 в это время начинает читаться какая-то хрень.

Более — того — у меня питание через диодную развязку — от адаптера и от USB. Так вот, если воткнуть сначала адаптер, а потом подключить USB — все работает безупречно. Тока от USB не хватает — тоже вряд ли у меня кроме часиков и контроллера ничего нет.
Есть предпололжение — у меня диодная развязка на диодах, которые просаживают напряжение до 4 вольт. Но они просаживают напряжение и от адаптера и от USB…

Буду копать…
0
Показал бы ты лучше полную схему и возможно — полный код.
0
Часы при напряжении питания ниже 4,5 вольт начинают глючить, ставьте диоды Шотки.
0
Так они не глючат, когда на них подается питание и с адаптера и с USB…
Схема вот electronix.ru/forum/index.php?act=attach&type=post&id=74852
0
Подозрительная схема. Где согласование уровней USB? Должны быть или стабилитроны с резисторами (не особо надежно), либо МК нужно питать от 3.3В.
Кроме того, если часы действительно начинают глючить при 4.5В — то они вполне могут заблокировать шину и прошивка заклинится в цикле ожидания готовности I2C.
На питание от USB здесь рассчитывать не стоит — компы как правило изначально выдают не более 4.8В, из этого вычитается падение на проводах (а на китайских USB-шнурках оно может быть охрененно большим, до вольта) и на диодах. Попробуй перевести МК на питание 3.3В и поставить часики с питанием 3.3В либо питать их от USB через степ-ап на 5В, а к МК подключать через согласователь (для него нужно всего пару 2N7002 или других дешевых N-MOSFET).
0
Объясняю, что и как глючит.
Точнее, как работает нормально.
Если подключить адаптер — то вся инициализация проходит, часы начинают тикать. ПОтом в любое время подрубаешь USB, запускаешь программу, все работает безукоризненно. На часах и на контроллере 4.1 вольт.
Если же втыкаешь сразу USB — видимо начинается енумерация и контроллер занимается своими делами. Рождается глюк.
Код главного цикла прилагаю

eeprom_read_block(&pdata,&eeprom_data,sizeof(eeprom_data)); 


 DDRC |= _BV(0);
 DDRC |= _BV(1);
 DDRC |= _BV(2);
 DDRC |= _BV(3);
 DDRD &= ~_BV(3);


    I2CInit();

	//Clear CH bit of RTC
	#define CH 7

	uint8_t temp;
	DS1307Read(0x00,&temp);

	//Clear CH Bit
	temp&=(~(1<<CH));

	DS1307Write(0x00,temp);

	//Set 12 Hour Mode
	DS1307Read(0x02,&temp);

	//Set 12Hour BIT
	temp|=(0b00000000);

	//Write Back to DS1307
	DS1307Write(0x02,temp);


//	rtc_init(0,1,0);
 
 PORTC |= _BV(1);
 _delay_ms(2000);
 PORTC &= ~_BV(1);  


usbInit();
    usbDeviceDisconnect();  // принудительно отключаемся от хоста, так делать можно только при выключенных прерываниях!
    uchar i = 0;
    while(--i){             // пауза > 250 ms
        _delay_ms(1);
    }

  usbDeviceConnect();     // подключаемся
sei();                  // разрешаем прерывания
            
	for(;;){                // главный цикл программы

   if (PIND & _BV(3))    
    {
	 
     //if (flag1==0) 
	 //{
		 
//	   flag1=1; 
  
    PORTC |= _BV(0);
 
    DS1307Read(0x00,&temp);
	sec=(((temp & 0b01110000)>>4)*10)+(temp & 0b00001111);

	DS1307Read(0x01,&temp);
	min=(((temp & 0b01110000)>>4)*10)+(temp & 0b00001111);

	DS1307Read(0x02,&temp);
	hr=(((temp & 0b01110000)>>4)*10)+(temp & 0b00001111);
	
	if ( ((hr*60+min)>=(pdata.CH1_begin_hour*60+pdata.CH1_begin_minute)) && ((hr*60+min)<(pdata.CH1_end_hour*60+pdata.CH1_end_minute)))
	{
	    if ((pdata.CH1_ONTime_minute*60+pdata.CH1_ONTime_second) > ( ((hr*3600+min*60+sec) -  (pdata.CH1_begin_hour*3600+pdata.CH1_begin_minute*60)) % (pdata.CH1_period_minute*60+pdata.CH1_period_second) )  ) PORTC |= _BV(0);else PORTC &= ~_BV(0);
	}
	

	if ( ((hr*60+min)>=(pdata.CH2_begin_hour*60+pdata.CH2_begin_minute)) && ((hr*60+min)<(pdata.CH2_end_hour*60+pdata.CH2_end_minute)))
	{
	    if ((pdata.CH2_ONTime_minute*60+pdata.CH2_ONTime_second) > ( ((hr*3600+min*60+sec) -  (pdata.CH2_begin_hour*3600+pdata.CH2_begin_minute*60)) % (pdata.CH2_period_minute*60+pdata.CH2_period_second) )  ) PORTC |= _BV(1);else PORTC &= ~_BV(1);
	}

	if ( ((hr*60+min)>=(pdata.CH3_begin_hour*60+pdata.CH3_begin_minute)) && ((hr*60+min)<(pdata.CH3_end_hour*60+pdata.CH3_end_minute)))
	{
	    if ((pdata.CH3_ONTime_minute*60+pdata.CH3_ONTime_second) > ( ((hr*3600+min*60+sec) -  (pdata.CH3_begin_hour*3600+pdata.CH3_begin_minute*60)) % (pdata.CH3_period_minute*60+pdata.CH3_period_second) )  ) PORTC |= _BV(2);else PORTC &= ~_BV(2);
	}

	if ( ((hr*60+min)>=(pdata.CH4_begin_hour*60+pdata.CH4_begin_minute)) && ((hr*60+min)<(pdata.CH4_end_hour*60+pdata.CH4_end_minute)))
	{
	    if ((pdata.CH4_ONTime_minute*60+pdata.CH4_ONTime_second) > ( ((hr*3600+min*60+sec) -  (pdata.CH4_begin_hour*3600+pdata.CH4_begin_minute*60)) % (pdata.CH4_period_minute*60+pdata.CH4_period_second) )  ) PORTC |= _BV(3);else PORTC &= ~_BV(3);
	}
     
	 PORTC &= ~_BV(0);
  //  }
   }  
   else flag1=0;
	usbPoll();          // эту функцию надо регулярно вызывать с главного цикла, максимальная задержка между вызовами - 50 ms
	
	


    }
    return 0;
0
Что самое интересное — убираю диод, ставлю перемычку, напряжение 5 вольт -у стройство не опознается…
0
Все правильно, уровни USB не согласованы.
0
У меня стоит жук — STF202-22 что в нем стоит диоды, или стабилитроны — не знаю, но работает отлично. Убираю, ставлю перемычки — не работает.
0
Все правильно, уровни USB не согласованы.
Аа… вы имеете в виду, что если у меня 4.1 вольт на выходах AVR, то USB кое-как с ними работает. А когда я дповышаю напряжение до 5 вольт — USB отключается. Так?
0
Да. И жук не для согласования, а для защиты от статики. Видимо в нем есть резисторы, иначе бы сгорел или он, или пин МК… В доках на V-USB не зря приведены схемы аппаратной части. И лично я рекомендую вариант с 3.3В — он правильней с т.з. перфекционизма и он стабильней работает.
0
Mega8 не будет работать на 12 МГц и 3.3 вольт.
Да и откуда такие советы — ведь в статье схема с питанием 5 вольт?
Если я в свою схему добавлю стабилитроны и уберу жука, а также буду управлять пуллапом с помощью транзистора — будет работать?
0
Mega8 не будет работать на 12 МГц и 3.3 вольт.
Будет. Даже ATMEGA8, а для ATMEGA8A, которые продаются нынче максимальная тактовая частота официально поддерживается во всем диапазоне питающих напряжений.
Да и откуда такие советы — ведь в статье схема с питанием 5 вольт?
Из собственного опыта и документации на V-USB.
Если я в свою схему добавлю стабилитроны и уберу жука, а также буду управлять пуллапом с помощью транзистора — будет работать?
Понятия не имею. По видимому, проблемы у тебя из-за того, что часики сбоят от недостатка питания. Но V-USB и так имеет не лучшую совместимость, а при отсутствии согласования уровней она совсем аховая и есть риск спалить порт.
+1
  • avatar
  • Vga
  • 23 марта 2013, 19:29
Наверное возьму я DS1340 — она на 3.3 вольт
0
Не нашел в магазине DS1340.
Зато купил стабилитроны. Убрал нафиг STF202-22, убрал диод, поставил стабилитроны, просаживающий напряжение, питаю от 5-ти вольт.

Все работает!

Все равно конечно непонятки остались. Я ставил BAT54С он просаживает напряжение до 4.5 вольт — для USB такое напряжение некритично — на линиях 3.3. вольт, а для DS1307 — это минимум. USB не опознается.
Кто кому не дает работать — часы USB, или USB часам — непонятно.

Вопрос — не опасно ли подключать напрямую друг к другу 5 вольт от USB и 5 вольт от линейного стабилизатора?
0
Часы виснут и перестают отвечать. Функции работы с I2C ждут ответа часов, но он не приходит и виснут тоже. usbPoll не вызывается вовремя и USB отваливается.
Учти еще, что некоторые материнки и хабы не работают с V-USB на стабилитронах. То ли емкость стабилитронов для них слишком высока, то ли что — хз.
0
Все выяснил. Дело было и в часах и в USB, а точнее в пуллапе.

Ставил резисторный делитель на D- — напряжение было не 3.3 вольт а значительно меньше. Работать стало, когда напряжение поднялось до 3 вольт, а это при 3к и 22 к резисторах.
После того, как разобрался с напряжением на D-, стало через раз определяться. Но тем не менее определялось и работало. Заменил диод на BAT54C — заработало без сбоев.
0
С делителями тоже лучше не связываться. Правильная (т.е. по стандарту) подтяжка — это резистор 1.5к к +3.3В. Нижний если и ставится, то 1М для защиты от наводок при отключенных USB и подтяжке.
Алсо, не понимаю, зачем народ ставит транзистор для подтяжки. Можно просто прицепить резистор к пину МК, при выдаче единицы там внутри именно такой транзистор на плюс питания и откроется.
0
ну а если нету у меня 3.3 вольт — куда подтягивать? городить преобразователь? Зачем, если у меняч на делителе работает?
0
Лично я решаю эту проблему, а также проблему согласования уровней USB и избыточной емкости стабилитронов одним махом — запитывая МК от 3.3В.
Зачем? Да затем, что так требует стандарт. Отступление от стандарта иногда работает, но не всегда.
0
Ого переписка у вас тут :) Полностью согласен с Vga, запитать всё от 3.3В надежней будет чем грабли с резисторами и стабилитронами. Но стандарт интересный, почему было делать питание 5В а сигналы 3.3В? Хотя это создает приключения только «ридиогубителям» :) Остальным не помеха…
0
Питание логики на тот момент уже везде было 3.3В, на внутренних портах USB даже часто 5В нет, сразу 3.3В (скажем, на minicard слотах в ноутах). 5В выбраны потому, что они есть на плате, они дают запас на понижение до 3.3В линейным стабилизатором даже с учетом потери почти вольта на проводах и защитах (стандарт допускает падение напряжения питания до 4.1В на терминалах устройства), они позволяют передавать большую мощность при том же токе. Новый стандарт вообще предусматривает выдачу питания до 30В по запросу устройства.
0
Есть проблема как у MrMisha выше: Девайс работает некоторое время затем пропадает. Он решил проблему доп. проводником для одной петляющей дорожки. Мне спрямлять таким образом нечего (прямее некуда). А вот когда замерил напряжение на D-, оно оказалось не 3.6В, а 2.5В (без подключения к USB хосту).
Когда начал проверять работу стабилитронов, то оказалось, что через резистор он открывается уже на 2В и далее при увеличении напряжения источника питания, напряжение на стабилитроне растет, но медленно, т.е. источник 5В равен 2.5В (стабилитрон 1N5227B). На др. стабилитроне BZX55C3V6 модель поведения такая же, но при источнике 5В, на стабилитроне уже 3В. (детальнее описал тут http://forum.easyelectronics.ru/viewtopic.php?f=4&t=14540)
Поменял стабилитроны на BZX55C3V6, вот уже 2.5 часа полет нормальный.
Но объясните мне почему такая непонятная логика работы стабилитрона? Он открываться должен только при превышении номинального напряжения и стабилизировать напряжение, а на деле он линейно понижает напряжение (тестировал на новых стабилитронах).
0
На 3-ем часу работы все-таки дал сбой. Ну хоть не раз в 10 минут, как стало в последнее время на 1N5227B. Хотя и было 1 раз, что устройство 5 дней проработало без сбоев, но уже давно.
0
У стабилитронов есть минимальный рабочий ток, обычно в районе 3мА. При меньших токах — напряжение тоже меньше. Лично я рекомендую выкинуть стабилитроны и запитать AVR от 3.3В. Проблем с работой на 12МГц при таком напряжении питания обычно не возникает даже со старыми МК, новые (серия А) изначально рассчитаны на работу на максимальной частоте во всем диапазоне питания.
0
Ну, в серию данный вариант я запускать не собираюсь и хотелось бы уже просто стабилизировать работу данного решения. Само устройство уже научил определять, когда его хост потерял и переподключаться и отдельно определять, когда просто софт на компе перестал посылать данные, т.о. достиг полностью автономной работы, но как-то это все криво…
В даташите на Atmega8A действительно нет ограничения по питанию для высоких частот. На будущее приму к сведению…
0
Дополнение по питанию самого МК (из обсуждения на форуме):
>>Возьмите микроконтроллер с префиксом PA, они работают на максимальной частоте во всем диапазоне напряжений.

ничего подобного — тема уже обсуждалась однажды. В даташите есть диаграмма зависимости максимальной частоты от напряжения питания. Атмел просто с первых страниц даташита убрали эту информацию — и вводят в заблуждение.
0
Кстати да, действительно. Впрочем, 12MHz@3.6V они на практике обеспечивают и девайс работает в целом куда стабильней, чем со стабилитронами. Сам я только этот вариант и применяю.
0
Vga, Вы оказались правы! У меня схемка завелась через L78L33, который вместо 3.3В выдал мне всего 3В, но ATMega8A успешно завелся на 16MHz. Вот уже неделю работает :)
Правда светодиоды пришлось замкнуть напрямую, а то через резисторы 220Ом совсем тускло стали моргать…
0
Вы взамен синих/белых поставьте красные/желтые/зелёные тогда норм будет. А если сверхяркие брать, то ещё и килоомные резисторы можно использовать.
0
У меня только зеленые и красные, но красные сами по себе очень тусклые.
0
а вот у меня проблема возникла.
подключаю контроллер, а хост программа говорит что он не подключен. vid, pid, vendor/device name все правильно.
может это Windows 7 не дает доступ к портам или типа того?
хост программа и прошивка не менялась.
0
Возможно проблема в «железе». В девайсах винды устройство определяется правильно (vid/pid)?
Сам все делаю под Win7, проблем не возникало…
0
да, все правильно определяется. вот скрин img14.imageshost.ru/img/2013/04/04/image_515d80b4bdaed.jpg
может того что винда х64 или того что прогу не перекомпилил?
0
Лично я похожее наблюдаю только при наличии device lock, когда вставляю флешку, то она определяется, но при попытке доступа облом. HID-устройства — это устройства ввода и обычно всегда разрешены.
Еще бывает глюк в винде, если ставили разные версии устройств с одним и тем же vid/pid, то винда помнит настройки предыдущего устройства и не обновляет их от нового (например, изменился размер или формат пакетов). Мне помогало удалить устройство и запустить поиск новых, после реинициализации все работало прекрасно.
Хорошо бы еще Вашу ошибку на Русский перевести :)
Да, и устройство может отваливаться по ошибкам как у меня (см. пост выше), т.е. оно успевает установиться в систему, затем сбой и данные уже не идут и выдается ошибка вроде «Устройство не подключено» или «Ошибка в данных (CRC)», хотя в девайсах оно присутствует. При худших раскладах у меня сбой происходил раз в несколько секунд, но мой девайс теперь умный и сам быстро переподключался (или ребутился в первой редакции). И самые частые ошибки у меня были именно при схеме устройства описанной в данной статье (делитель напряжения в подтяжке к D-. Сделал подтяжку как в оригинале v-usb и частота ошибки уменьшилась до раза в сутки). Многие жалуются в подобных случаях и на конкретные модели стабилитронов.
0
А к др. компу подключить?
0
К другому компу подключал. Тоже самое. Крякозябрами написано «не подключен» но чего-то русский шрифт так вываливает.
Попробую удалить устройство, а то тот же vid/pid у меня на бутлоадере стоит.
0
Проблема решилась перекомпиляцией хост программы только с Update 4. Без апдейта я что только не перепробовал ни в какую не работало. Зато после стольких часов тщательного изучения кода стал лучше разбираться что и как работает=)
Всем спасибо за советы)
0
А можно в процессе работы, на подключенном устройстве тоесть, изменить количество репортов?
Для того, чтобы при первом подключении принять с устройства большую пачку данных (сотню байт), а потом принимать всего пару байт.
0
  • avatar
  • Bonio
  • 21 августа 2013, 00:35
я тут недавно сделал зарядку для аккумов. питание на зарядник подается через usb кабель.
Че то я стал побаиваться как бы кто не воткнул зарядку в комп, ток то по больше 500мА.
может стоить прикрутить схемку детектирования подключенности к компу на микроконтроллере? или если получится без контроллера.
собстна хотел уточнить как происходит инициализация. я понял так:
1) девайс посылает сигнал коннект(для лоу спид D- на питание, D+ на землю).
2) после этого комп посылает какой то сигнал(какой? посылает ли вообще?) мы видим или не видим этот сигнал и понимаем куда нас воткнули(в комп или в бп с усбвыходом)
0
Извращаюсь описанным в статье способом. На PBII не получилось, бо там подтяжка D+ сделана для Full Speed, зато на PBI взлетело с полтычка, бо там D- подтянуто. Вот, кстати, уважаемому Ди на заметку идея для модернизации пинбарды — возможность выбирать тип подтяжки перемычкой, а то не слишком гибко получается.
Поскольку билдер очень даже платный, хост-программу корячу на C# в VisualStudio Express, обнаруженные в тырнете компоненты для работы с HID под .Net не пошли по-человечески, поэтому приходится постигать libusb.
0
Всем привет, залил прошивку в atmega16 кварц 16 МГц операционная система Windows XP видит, но Win 7 пишет 'unknown device'. Как исправить?
0
Никак=) Просто забить. у семерки и v-usb не срослось на уровне host стека usb =(
0
V-USB на семерке работает нормально. Проблемы возникают с теми классами, которые запрещены на LS — скажем, CDC, но и они нормально опознаются (но система пишет «запуск невозможен, код 10»).
Скорее капризы железа. Компы-то наверняка разные, и некоторые USB-контроллеры не принимают девайсы на V-USB из-за того, что физический интерфейс реализован не совсем по стандарту. romanF, ты по какой схеме собирал? Со стабилитронами?
0
Так компьютеры разные, ХР работает на ноуте, а 7 на стационарном. Схему собирал точно как здесь указано, за исключением того, что резистора на 2,2 кОм не было взял 2 кОм. Сегодня ночью на 100 раз включения 7 увидела, в чем дело было так и не понял. В знакомого на ноуте 7 сразу сегодня увидела. Чудеса и только. 2 недели мучился, еще бы знать в чем дело. Спасибо что откликнулись.
0
Тыщщу раз сказано — V-USB реализует USB PHY с большими допущениями и из-за этого на части USB-хостов не работает. Забарывается это подбором совместимого железа (от втыкания через хаб (который может потребоваться подобрать) до замены USB-контроллера/мамки/компа).
Ну и я бы посоветовал использовать схему, где МК питается от 3.3В и нет стабилитронов. У нее совместимость лучше. Алсо играет роль разводка линий USB на плате, некоторые огребали проблем из-за игнорирования требований к ним (хотя, казалось бы, на LS это влиять не должно).
0
Очень благодарен, у меня возникали сомнения в самой прошивки, которую я менял на другую, однако результата это не давало. Я не профессионал в этой области, поэтому на данном этапе у меня это все реализовано на макетной плате) А за ваши рекомедации благодарен и буду учитывать как начну делать другой вариант реализую без стабилитронов.
0
Добрый день, гуру МК ) Столкнулся с интересной задачей — реализую USB-HID устройство с возможностью выбора дискриптора по замыканию перемычкой (вывода МК на землю). т.е. задача чтоб при включении устройства без перемычки подтягивался один дескриптор (его длина, например 130), а при замкнутой перемычке — другой (длина 124). В main.c я написал:
0
// если дискриптор = 130 (абсолютка)
#if USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH == 130

PROGMEM char usbHidReportDescriptor[130] = {

};
#else
PROGMEM char usbHidReportDescriptor[124] = {

};
#endif

, вот как сделать возможность изменения параметра #define USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH 124
в usbconfig.h, в зависимости от джампера MK, ума не приложу, т.к. в заголовочном файле .h нет возможности опрашивать состояние портов МК… (как впрочем и до основного цикла программы main).

Буду благодарен за любые советы. Спасибо!
0
Надо закапываться в потроха V-USB, смотреть где оно работает с дескриптором и заменять в этих местах дефайны переменными. Тогда в main() можно будет назначить этим переменным требуемые значения до инициализации USB.
Еще, правда, можно попытаться скомпилировать две отдельные прошивки и выбирать нужную бутлоадером, но это несколько извратно :D
0
С бутлоадером не вариант, у меня уже там спец ПО назначено, занято в общем…
А вот с заменой дефайна переменной — попробую поковыряться, по поиску этот дефайн USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH фигурирует всего лишь в 2 файлах драйвера — usbdrv/usbdrv.c и usbdrv/usbdrv.h
0
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.