Ручная настройка USB
-
misyachniy
- Прорезались зубы
- Сообщения: 219
- Зарегистрирован: Вт июл 02, 2013 09:17:49
Re: Ручная настройка USB
Ручной настройкой USB я разбирался давно, еще на ассемблере.
http://njnmnp.narod.ru/proj/flashbom/flashbom.html
В принципе нет ничего сложного.
Получил запрос от компьютера - отдал ответ.
Захотел передать данные - "положил в нужное место" и ждешь пока данные заберет компьютер.
Единственная заморочка - после приема сигнала "USB Reset" нужно прекратить передачу и перейти в исходное состояние.
Сейчас я перешел на более высокий уровень "некомпетентности".
Если мне нужен проект на USB для любого контроллера, я беру пример от производителя Mass Storage Device.
Меняю VID/PID и тип устройства.
Теперь у меня есть проект с двумя endpoint на прием передачу.
Со стороны компьютера беру libusb0 и генерирую inf файл.
В микроконтроллере нахожу точки входа по приему/передаче собственно данных и цепляюсь к ним.
Все лишнее по MSD удаляю и пишу свое.
http://njnmnp.narod.ru/proj/flashbom/flashbom.html
В принципе нет ничего сложного.
Получил запрос от компьютера - отдал ответ.
Захотел передать данные - "положил в нужное место" и ждешь пока данные заберет компьютер.
Единственная заморочка - после приема сигнала "USB Reset" нужно прекратить передачу и перейти в исходное состояние.
Сейчас я перешел на более высокий уровень "некомпетентности".
Если мне нужен проект на USB для любого контроллера, я беру пример от производителя Mass Storage Device.
Меняю VID/PID и тип устройства.
Теперь у меня есть проект с двумя endpoint на прием передачу.
Со стороны компьютера беру libusb0 и генерирую inf файл.
В микроконтроллере нахожу точки входа по приему/передаче собственно данных и цепляюсь к ним.
Все лишнее по MSD удаляю и пишу свое.
- Реклама
- IfoR
- Поставщик валерьянки для Кота
- Сообщения: 2029
- Зарегистрирован: Сб ноя 15, 2008 10:09:56
- Откуда: г. Тула
- Контактная информация:
Re: Ручная настройка USB
Так дело в том, что я не могу узнать, что хост от меня хочет, потому что в буффер не пишется абсолютно ничего.
-
misyachniy
- Прорезались зубы
- Сообщения: 219
- Зарегистрирован: Вт июл 02, 2013 09:17:49
Re: Ручная настройка USB
Обычно нужно посмотреть куда подсоединен резистор 1,5К в схеме.IfoR писал(а):Так дело в том, что я не могу узнать, что хост от меня хочет, потому что в буффер не пишется абсолютно ничего.
Один конец к D+ второй к 3,3В. Напрямую, через транзистор с вывода МК.
Если резистор встроенный, то пример должен заработать не зависимо от схемы.
Если резистор есть, нужно найти в примере работу с ним. Обычно функция типа USB_connect();
Бывает что пока отладчик загрузит ПО в МК, windows пытается проинициализировать устройство.
Если внешний резистор есть, то переписать пример в части манипуляции данным резистором.
Если windows пишет, что устройство USB не определено, значит резистор подключен.
Первое обращение по шине USB не посылка данных а специальная манипуляция проводами D+/D-, которое устройство должно декодировать как сброс шины.
- IfoR
- Поставщик валерьянки для Кота
- Сообщения: 2029
- Зарегистрирован: Сб ноя 15, 2008 10:09:56
- Откуда: г. Тула
- Контактная информация:
Re: Ручная настройка USB
Резистор просто подключён напрямую к Vcc. Мне ни к чему разрывать шину программно (а хост, после подключения, ждёт что-то около 100 мс для самоинициализации устройства, прежде чем начнёт обмен). Прошивается у меня микроконтроллер но SWD. USB который нужно настроить расположен отдельно и подключаю я кабель USB уже после запуска откладки. При работе без отладчика (с выводом результатов на дисплей) результат тот же самый.
Низкоуровневая манипуляция с шиной, грубо говоря, - это забота контроллера, а не моя. Мне приходит лишь событие сброса и оно (в if-е с USB->ISTR & USB_ISTR_RESET) отрабатывается нормально. Опять повторюсь - аппаратная часть работает вроде как нормально. Всё проходит вроде как штатно как со стороны контроллера, так и со стороны компа. Проблема в том, что контроллер хоть и правильно принимает пакеты, но почему то не пишет принятые данные в буффер для разбора программой. Хост мне отправляет первый запрос дескриптора устройства (контроллер чётко понимает что пришёл SETUP пакет с запросом данных от хоста, что явно указывается в регистрах), что длиной 64, однако я не могу этого понять, т.к. пакета то нет в памяти. А в чём дело понять не могу. Вроде бы адреса и размеры
Пишутся правильно в нужное место при BTABLE = 0. Это видно по дампу памяти, что на скрине выше. Но больше ничего не происходит. 
Я не в винде смотрю, но лог соединения на стороне хоста говорит, что подсоединение происходит успешно, но в процессе энумерации всё стопорится: хост отправляет запрос GET_DESCRIPTOR и примерно через 2 мс приходит в ответ (от контроллера) пакет 0-й длины. Хост повторяет запрос ещё 2 раза с тем же исходом, после чего сбрасывает шину и пробует повторить запрос ещё раз. Я же на контроллера каждый раз не могу прочитать присланный пакет.
Низкоуровневая манипуляция с шиной, грубо говоря, - это забота контроллера, а не моя. Мне приходит лишь событие сброса и оно (в if-е с USB->ISTR & USB_ISTR_RESET) отрабатывается нормально. Опять повторюсь - аппаратная часть работает вроде как нормально. Всё проходит вроде как штатно как со стороны контроллера, так и со стороны компа. Проблема в том, что контроллер хоть и правильно принимает пакеты, но почему то не пишет принятые данные в буффер для разбора программой. Хост мне отправляет первый запрос дескриптора устройства (контроллер чётко понимает что пришёл SETUP пакет с запросом данных от хоста, что явно указывается в регистрах), что длиной 64, однако я не могу этого понять, т.к. пакета то нет в памяти. А в чём дело понять не могу. Вроде бы адреса и размеры
Код: Выделить всё
bufferDescriptor->ADDR0_RX = EP0_ADDR_RX;
bufferDescriptor->ADDR0_TX = EP0_ADDR_TX;
bufferDescriptor->COUNT0_RX = maxPacketSize;
bufferDescriptor->COUNT0_TX = maxPacketSize;
Я не в винде смотрю, но лог соединения на стороне хоста говорит, что подсоединение происходит успешно, но в процессе энумерации всё стопорится: хост отправляет запрос GET_DESCRIPTOR и примерно через 2 мс приходит в ответ (от контроллера) пакет 0-й длины. Хост повторяет запрос ещё 2 раза с тем же исходом, после чего сбрасывает шину и пробует повторить запрос ещё раз. Я же на контроллера каждый раз не могу прочитать присланный пакет.
Re: Ручная настройка USB
Ребята, объясните пожалуйста не понятный момент с BTABLE.
Чувствую тут можно накосячить, как то запутанно.
Например BTABLE по адресу 0x40006000, пусть будет описан один ендпоинт, одна запись в таблице, длина таблицы 8 байт, далее следует 2 байта count0_tx, далее буффер addr0_tx.
COUNT0_TX = 0x0008, ADDR0_TX = 0x000A
Соответственно буффер начинается с 0x000A, записывать данные в него можно с этого оффсет адреса, верно?
Зачем умножать адрес на два?Due to the common APB bridge limitation on word addressability, all packet memory
locations are accessed by the APB using 32-bit aligned addresses, instead of the actual
memory location addresses utilized by the USB peripheral for the USB_BTABLE register
and buffer description table locations.
To obtain the correct STM32F10xxx memory address value to be used in
the application software while accessing the packet memory, the actual memory location
address must be multiplied by two.
Чувствую тут можно накосячить, как то запутанно.
Например BTABLE по адресу 0x40006000, пусть будет описан один ендпоинт, одна запись в таблице, длина таблицы 8 байт, далее следует 2 байта count0_tx, далее буффер addr0_tx.
COUNT0_TX = 0x0008, ADDR0_TX = 0x000A
Соответственно буффер начинается с 0x000A, записывать данные в него можно с этого оффсет адреса, верно?
Последний раз редактировалось include Пн сен 21, 2015 14:39:40, всего редактировалось 1 раз.
- Реклама
Re: Ручная настройка USB
Там же написано - Due to the common APB bridge limitation on word addressability.Зачем умножать адрес на два?
Взаимодействие с памятью USB реализовано достаточно хитро. Если я верно помню, к этой памяти параллельно подключен собственно блок USB и шина APB, причем по разным каналам. За счет этого получается, что для блока USB адресация последовательная, а вот в адресном пространстве APB идет выравнивание по ближайшему слову.
Умножать на два надо.
Если найду свои упражнения годовой давности, выложу свой код доступа к этим областям. Он у меня работал.
Разница между теорией и практикой на практике гораздо больше, чем в теории.
Re: Ручная настройка USB
YS писал(а):Там же написано - Due to the common APB bridge limitation on word addressability.Зачем умножать адрес на два?
Похоже я начинаю понимать. Это настоящее шаманство :). Выходит для приложения память PMA выглядит как 32*word , а для USB как 32*half-word;Due to the common limitation of APB1
bridges on word addressability, all register addresses are aligned to 32-bit word boundaries
although they are 16-bit wide. The same address alignment is used to access packet buffer
memory locations, which are located starting from 0x4000 6000.
В таком случае да, умножение на два требуется.
Re: Ручная настройка USB
Это вы еще не видели (или видели?Это настоящее шаманство
Разница между теорией и практикой на практике гораздо больше, чем в теории.
Re: Ручная настройка USB
Не видел :( Лежат две штучки, всё никак не доберусь. Интересно конечно, поковырять, займусь позже. Меня очень расстроило то, что ST не предоставили для STM8 компилятора под разные ОС. Типа пользуйтесь своим Кейлом, нас это не заботит. Правда положение дел сейчас исправляет SDCC. Главное дебагер раздобыть, ну или самому сделать.YS писал(а):Это вы еще не видели (или видели? :) ) как в STM8 устроена пара регистров, устанавливающая скорость UART'а... :)))Это настоящее шаманство :)
Зато видел кривые реализации прерываний для spi и usart в stm32, такие костыли приходится городить, что порой хочется вообще без прерываний. Сюда можно и i2c отнести с его необходимостью заранее NUCK-ать.(В старших моделях вроде пофиксили).
Скучать в общем не приходится :D
Re: Ручная настройка USB
Я с некоторых пор для STM8 использую Cosmic + ST Visual Develop. Cosmic, правда, тоже, гм, не без особенностей (например, в нем из коробки нет stdint.h, ну или я не нашел), но вообще эта связка очень напоминает милую моему сердцу AVR Studio 4.Меня очень расстроило то, что ST не предоставили для STM8 компилятора под разные ОС.
Жалко что пока не сделали соответствующий backend для GCC. Даже странно, контроллеры-то очень приятные.
А что там?Зато видел кривые реализации прерываний для spi и usart в stm32, такие костыли приходится городить, что порой хочется вообще без прерываний.
Разница между теорией и практикой на практике гораздо больше, чем в теории.
Re: Ручная настройка USB
Наверное сказывается не популярность сих архитектур. Но как я и говорил, есть SDCC, правда код генерирует он слегка "пухлый" :)YS писал(а):Жалко что пока не сделали соответствующий backend для GCC. Даже странно, контроллеры-то очень приятные.
Подробности с USART не опишу, давно работал с ним, но как мне помнится, у меня нормально не вышло включить прерывания одновременно на TX и RX.А что там?
У SPI болеет TX прерывание. Оно работает совсем не так, как того ожидаешь. При включении прерывания, при отсутствии данных обработчик будет "долбиться" пока прерывание не вырубишь. Ожидается, что после снятия tx флага прерывания, прерывание не вызовется до тех пор, пока я снова не положу данные в буфер и он освободится.
Официальный костыль от ST - выключение прерывания в обработчике. Такое tx прерывание подходит разве что, для больших объёмов данных, а не, скажем, когда нужно отправить пару байт.
Хотя, можно конечно не париться и включить DMA. Но так и DMA каналов не хватит, если на каждую кривую периферию врубать DMA.
- oleg110592
- Друг Кота
- Сообщения: 3832
- Зарегистрирован: Сб сен 10, 2011 17:46:25
Re: Ручная настройка USB
несколько не так, в линейке STM8 имеет смысл использовать STM8S003F3P6 из-за крайней дешевизны оного - там 8 Kbytes Flash, поэтому можно использовать любой коммерческий компилятор даже с ограничениями. Cosmic (неплохой компилятор) сейчас раздают в одном флаконе STM8 32K + STM32 32K на шару (FREE, лично получал): http://www.cosmic-software.com/download.phpinclude писал(а):Наверное сказывается не популярность сих архитектур
Для всего остального, как замену всем устаревшим восьмибитникам PIC AVR, имеет смысл использовать серию STM32F0 - там с GCC все в ажуре, но для этой серии отличный компилятор, от самого производителя ядра (ARM), вместе с ИДЕ Keil раздается бесплатно (free-to-use professional tool suite) http://www2.keil.com/stmicroelectronics-stm32/mdk
Re: Ручная настройка USB
Может кому понадобится, написал на коленках работу с USB через регистры, используются только header'ы для числовых define'ов. Дескрипторы устройства и репорты HID брались отсюда STM32 и USB-HID — это просто или на geektimes.ru. Можно использовать Windows программу из статей для проверки, отправка report'ов на устройство не обрабатывается.
Особенности:
1) Код очень корявый, куча мест не проверятся, куча debug переменных, но он работает и очень помог бы мне вначале сократить время на разработку (а теперь нет желания писать дальше). Для примера с чего начать самое то.
2) Писался для STM32F103C8T8
3) Надо очень правильно инициировать USB, соблюдать последовательность, я уже забыл все нюансы.
4) Память под внутренние буферы находится в адресном пространстве регистров периферии, внутренняя адресация по 16бит, мы же пишем выровнено по 32 и рассматриваем 16бит данных как 32бита. Не пишите туда по-байтно, только разом по 16бит, иначе будет дублирование старших/младших байт.
5) У одного USB регистра USB_EPnR куча toggle битов, нужно извращаться с XOR'ами и AND'ами.
6) Вообще реализацию USB на этих микроконтроллерах делал садист и получал удовольствие от каждого разработчика кто пытался разобраться в потрохах (ну она очень мудрено-извращенная), лучше используйте готовые библиотеки, RAW MODE только если нехватка памяти.
Особенности:
1) Код очень корявый, куча мест не проверятся, куча debug переменных, но он работает и очень помог бы мне вначале сократить время на разработку (а теперь нет желания писать дальше). Для примера с чего начать самое то.
2) Писался для STM32F103C8T8
3) Надо очень правильно инициировать USB, соблюдать последовательность, я уже забыл все нюансы.
4) Память под внутренние буферы находится в адресном пространстве регистров периферии, внутренняя адресация по 16бит, мы же пишем выровнено по 32 и рассматриваем 16бит данных как 32бита. Не пишите туда по-байтно, только разом по 16бит, иначе будет дублирование старших/младших байт.
5) У одного USB регистра USB_EPnR куча toggle битов, нужно извращаться с XOR'ами и AND'ами.
6) Вообще реализацию USB на этих микроконтроллерах делал садист и получал удовольствие от каждого разработчика кто пытался разобраться в потрохах (ну она очень мудрено-извращенная), лучше используйте готовые библиотеки, RAW MODE только если нехватка памяти.
Спойлер
Код: Выделить всё
#include "stm32f10x.h"
#include "stdbool.h"
#include "string.h"
#include "usb_def.h"
#include "usb_hid.h"
volatile uint32_t g_msTicks = 0;
volatile uint32_t g_times = 0;
volatile uint32_t g_resets = 0;
volatile uint32_t g_controls = 0;
volatile uint32_t g_cntr = 0;
struct History
{
uint16_t EP_before;
uint16_t EP_after;
uint8_t signal;
uint8_t value;
uint16_t sz;
char cmd;
};
struct History history[100];
#define HISTORY_MAX 100
uint32_t historyCntr = 0;
const uint8_t *g_controlBuf = NULL;
uint32_t g_controlSize = 0;
uint8_t g_newAddr = 0;
#define HID_SIZE_DEVICE_DESC 18
#define E0_MAX_PACKET_SIZE 8
#define E1_MAX_PACKET_SIZE 8
#define E2_MAX_PACKET_SIZE 8
#define RHID_SIZ_CONFIG_DESC 41
#define RHID_SIZ_REPORT_DESC 79
#define wMaxPacketSize 8
#define USB_BASE_ADDR 0x40005C00 /* USB Registers Base Address */
#define USB_PMA_ADDR 0x40006000 /* USB Packet Memory Area Address */
#define LOWBYTE(v) ((unsigned char) (v))
#define HIGHBYTE(v) ((unsigned char) (((unsigned int) (v)) >> 8))
/* Common Registers */
#define USB_CNTR *((volatile unsigned int *)(USB_BASE_ADDR + 0x40)) /* Control Register */
#define USB_ISTR *((volatile unsigned int *)(USB_BASE_ADDR + 0x44)) /* Interrupt Status Register */
#define USB_FNR *((volatile unsigned int *)(USB_BASE_ADDR + 0x48)) /* Frame Number Register */
#define USB_DADDR *((volatile unsigned int *)(USB_BASE_ADDR + 0x4C)) /* Device Address Register */
#define USB_BTABLE *((volatile unsigned int *)(USB_BASE_ADDR + 0x50)) /* Buffer Table Address Register */
#define USB_EP0R *((volatile unsigned int *)(USB_BASE_ADDR + 4*0))
#define USB_EP1R *((volatile unsigned int *)(USB_BASE_ADDR + 4*1))
#define USB_EP2R *((volatile unsigned int *)(USB_BASE_ADDR + 4*2))
#define USB_EP3R *((volatile unsigned int *)(USB_BASE_ADDR + 4*3))
#define USB_EP4R *((volatile unsigned int *)(USB_BASE_ADDR + 4*4))
#define USB_EP5R *((volatile unsigned int *)(USB_BASE_ADDR + 4*5))
#define USB_EP6R *((volatile unsigned int *)(USB_BASE_ADDR + 4*6))
#define USB_EP7R *((volatile unsigned int *)(USB_BASE_ADDR + 4*7))
#define USB_CONTROL_TX_ADDR ((void*)(USB_PMA_ADDR + 3*16 + 0))
#define USB_CONTROL_RX_ADDR ((void*)(USB_PMA_ADDR + 3*16 + E0_MAX_PACKET_SIZE * 2))
#define USB_E0_TX_SIZE_ADDR ((void*)(USB_PMA_ADDR + 4))
#define USB_E0_RX_SIZE_ADDR ((void*)(USB_PMA_ADDR + 8 + 4))
#define USB_E1_TX_SIZE_ADDR ((void*)(USB_PMA_ADDR + 16 + 4))
#define USB_E1_RX_SIZE_ADDR ((void*)(USB_PMA_ADDR + 16 + 8 + 4))
#define USB_E1_TX_ADDR ((void*)(USB_PMA_ADDR + 3*16 + E0_MAX_PACKET_SIZE * 4 + 0))
#define USB_E1_RX_ADDR ((void*)(USB_PMA_ADDR + 3*16 + E0_MAX_PACKET_SIZE * 4 + E0_MAX_PACKET_SIZE * 2))
const uint8_t USB_StringSupportedLanguages[] =
{
4, USB_STRING_DESCRIPTOR_TYPE,
0x09, 0x4
};
const uint8_t USB_StringManufacturer[] =
{
12,
USB_STRING_DESCRIPTOR_TYPE,
'A',0,'l',0,'m',0,'a',0,'z',0
};
const uint8_t USB_StringProduct[] =
{
12,
USB_STRING_DESCRIPTOR_TYPE,
'S',0,'T',0,'M',0,'3',0,'2',0
};
const uint8_t USB_StringSerial[] =
{
14,
USB_STRING_DESCRIPTOR_TYPE,
'M',0,'Y',0,'0',0,'0',0,'0',0,'1',0
};
const uint8_t USB_AlternateSetting[1] = { 0 };
/* USB Standard Device Descriptor */
const uint8_t HID_DeviceDescriptor[HID_SIZE_DEVICE_DESC] =
{
HID_SIZE_DEVICE_DESC,
USB_DEVICE_DESCRIPTOR_TYPE, // bDescriptorType - Device descriptor
0x00, 0x02, // bcdUSB
0x00, // bDeviceClass
0x00, // bDeviceSubClass
0x00, // bDeviceProtocol
E0_MAX_PACKET_SIZE, // bMaxPacketSize - Endpoint 0
0x83, 0x04, // idVendor (0x0483)
0x11, 0x57, // idProduct (0x5711)
0, 1, // bcdDevice rel. DEVICE_VER_H.DEVICE_VER_L
1, // Index of string descriptor describing manufacturer
2, // Index of string descriptor describing product
3, // Index of string descriptor describing the device serial number
1 // bNumConfigurations
};
/* USB Configuration Descriptor */
/* All Descriptors (Configuration, Interface, Endpoint, Class, Vendor */
const uint8_t RHID_ConfigDescriptor[RHID_SIZ_CONFIG_DESC] =
{
0x09, // bLength: ????? ??????????? ????????????
USB_CONFIGURATION_DESCRIPTOR_TYPE, // bDescriptorType: ??? ??????????? - ????????????
RHID_SIZ_CONFIG_DESC, 0x00, // wTotalLength: ????? ?????? ????? ?????? ??? ?????? ????????????? ? ??????
0x01, // bNumInterfaces: ? ???????????? ????? ???? ?????????
0x01, // bConfigurationValue: ?????? ?????? ????????????
0x00, // iConfiguration: ?????? ??????, ??????? ????????? ??? ????????????
0xE0, // bmAttributes: ??????? ????, ??? ?????????? ????? ???????? ?? ???? USB
0x32, // MaxPower 100 mA: ? ??? ?????? 100 ??
/************** ?????????? ?????????? ****************/
0x09, // bLength: ?????? ??????????? ??????????
USB_INTERFACE_DESCRIPTOR_TYPE, // bDescriptorType: ??? ??????????? - ?????????
0x00, // bInterfaceNumber: ?????????? ????? ?????????? - 0
0x00, // bAlternateSetting: ??????? ??????????????? ??????????, ? ??? ?? ????????????
0x02, // bNumEndpoints - ?????????? ??????????.
0x03, // bInterfaceClass: ????? ????????? - HID
// ???? ?? ?? ?????? ??? ??????????? ??????????, ???????? ?????????? ??? ????, ?? ???? ???? ?? ??????? ????????? ????? ? ????????
// ? ??? ? ??? ????? HID-??????????
0x00, // bInterfaceSubClass : ???????? ??????????.
0x00, // nInterfaceProtocol : ???????? ??????????
0, // iInterface: ?????? ??????, ??????????? ?????????
// ?????? ????????? ?????????? ??? ????????? ????, ??? ?????? ????????? - ??? HID ??????????
/******************** HID ?????????? ********************/
0x09, // bLength: ????? HID-???????????
HID_HID_DESCRIPTOR_TYPE, // bDescriptorType: ??? ??????????? - HID
0x01, 0x01, // bcdHID: ????? ?????? HID 1.1
0x00, // bCountryCode: ??? ?????? (???? ?????)
0x01, // bNumDescriptors: ??????? ?????? ????? report ????????????
HID_REPORT_DESCRIPTOR_TYPE, // bDescriptorType: ??? ??????????? - report
RHID_SIZ_REPORT_DESC, 0x00, // wItemLength: ????? report-???????????
/******************** ?????????? ???????? ????? (endpoints) ********************/
0x07, // bLength: ????? ???????????
USB_ENDPOINT_DESCRIPTOR_TYPE, // ??? ??????????? - endpoints
0x81, // bEndpointAddress: ????? ???????? ????? ? ??????????? 1(IN)
0x03, // bmAttributes: ??? ???????? ????? - Interrupt endpoint
wMaxPacketSize, 0x00, // wMaxPacketSize: Bytes max
0x20, // bInterval: Polling Interval (32 ms)
0x07, /* bLength: Endpoint Descriptor size */
USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType: */
/* Endpoint descriptor type */
0x01, /* bEndpointAddress: */
/* Endpoint Address (OUT) */
0x03, /* bmAttributes: Interrupt endpoint */
wMaxPacketSize, /* wMaxPacketSize: Bytes max */
0x00,
0x20, /* bInterval: Polling Interval (32 ms) */
}
; /* RHID_ConfigDescriptor */
#define RPT3_COUNT 0x01 //PC->STM32
#define RPT4_COUNT 0x04 //STM32->PC
const uint8_t RHID_ReportDescriptor[RHID_SIZ_REPORT_DESC] =
{
0x06, 0x00, 0xff, // USAGE_PAGE (Generic Desktop)
0x09, 0x01, // USAGE (Vendor Usage 1)
0xa1, 0x01, // COLLECTION (Application)
0x85, 0x01, // REPORT_ID (1)
0x09, 0x01, // USAGE (Vendor Usage 1)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0x01, // LOGICAL_MAXIMUM (1)
0x75, 0x08, // REPORT_SIZE (8)
0x95, 0x01, // REPORT_COUNT (1)
0xb1, 0x82, // FEATURE (Data,Var,Abs,Vol)
0x85, 0x01, // REPORT_ID (1)
0x09, 0x01, // USAGE (Vendor Usage 1)
0x91, 0x82, // OUTPUT (Data,Var,Abs,Vol)
0x85, 0x02, // REPORT_ID (2)
0x09, 0x02, // USAGE (Vendor Usage 2)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0x01, // LOGICAL_MAXIMUM (1)
0x75, 0x08, // REPORT_SIZE (8)
0x95, 0x01, // REPORT_COUNT (1)
0xb1, 0x82, // FEATURE (Data,Var,Abs,Vol)
0x85, 0x02, // REPORT_ID (2)
0x09, 0x02, // USAGE (Vendor Usage 2)
0x91, 0x82, // OUTPUT (Data,Var,Abs,Vol)
0x85, 0x03, // REPORT_ID (3)
0x09, 0x03, // USAGE (Vendor Usage 3)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255)
0x75, 0x08, // REPORT_SIZE (8)
0x95, RPT3_COUNT, // REPORT_COUNT (N)
0xb1, 0x82, // FEATURE (Data,Var,Abs,Vol)
0x85, 0x03, // REPORT_ID (3)
0x09, 0x03, // USAGE (Vendor Usage 3)
0x91, 0x82, // OUTPUT (Data,Var,Abs,Vol)
0x85, 0x04, // REPORT_ID (4)
0x09, 0x04, // USAGE (Vendor Usage 4)
0x75, 0x08, // REPORT_SIZE (8)
0x95, RPT4_COUNT, // REPORT_COUNT (N)
0x81, 0x82, // INPUT (Data,Var,Abs,Vol)
0xc0 // END_COLLECTION
};
enum USB_State
{
USB_StateDefault = 0,
USB_StateAddress,
USB_StateConfigured,
};
enum USB_State g_usbState = USB_StateDefault;
void sup_copy(uint8_t *dst, const uint8_t *src, uint32_t size)
{
for (; size > 1; size -= 2, dst += 4, src += 2)
*(uint16_t*)dst = *(uint16_t*)src;
if (size == 1)
{
uint16_t tmp = *src;
*(uint16_t*)dst = tmp;
}
}
void SendStatusZero()
{
// fix size
*(uint16_t*)USB_E0_TX_SIZE_ADDR = 0;
// send
history[historyCntr % HISTORY_MAX].EP_before = USB_EP0R;
USB_EP0R = (USB_EP0R ^ USB_EP0R_STAT_TX) & (USB_EP0R_STAT_TX | USB_EP0R_EP_TYPE | USB_EP0R_EP_KIND | USB_EP0R_EA);
history[historyCntr % HISTORY_MAX].EP_after = USB_EP0R;
history[historyCntr++ % HISTORY_MAX].cmd = 'Z';
}
void ProcessData(void)
{
if (USB_EP1R & USB_EP1R_CTR_TX)
{
uint8_t buf[5] = { 4 };
g_cntr++;
buf[1] = g_cntr % 255;
buf[2] = g_cntr / 255 % 255;
buf[3] = g_cntr / 10 & 3;
// *(uint32_t*)&buf[1] = historyCntr;
*(uint16_t*)USB_E1_TX_SIZE_ADDR = 5;
sup_copy(USB_E1_TX_ADDR, buf, 5);
USB_EP1R = (USB_EP1R ^ USB_EP1R_STAT_TX) & (USB_EP1R_STAT_TX | USB_EP1R_EP_TYPE | USB_EP1R_EP_KIND | USB_EP1R_EA);
}
}
void ProcessControl(void)
{
g_controls++;
if (USB_EP0R & USB_EP0R_CTR_RX)
{
if (USB_EP0R & USB_EP0R_SETUP)
{
uint8_t *setup = (uint8_t*)USB_CONTROL_RX_ADDR;
uint16_t wValue, /*wIndex,*/ wLength;
USB_REQUEST_TYPE bmRequestType = *(USB_REQUEST_TYPE*)(setup++);
uint8_t bRequest = *(setup++);
setup += 2;
wValue = *(uint16_t*)setup;
setup += 4;
setup += 4;
wLength = *(uint16_t*)setup;
setup += 4;
history[historyCntr % HISTORY_MAX].EP_before = history[historyCntr % HISTORY_MAX].EP_after = USB_EP0R;
history[historyCntr % HISTORY_MAX].signal = bRequest;
history[historyCntr % HISTORY_MAX].value = HIGHBYTE(wValue);
history[historyCntr % HISTORY_MAX].sz = (*(uint16_t*)USB_E0_RX_SIZE_ADDR) & USB_COUNT0_RX_COUNT0_RX;
history[historyCntr++ % HISTORY_MAX].cmd = 'D';
if (bRequest == USB_REQUEST_GET_DESCRIPTOR)
{
if (HIGHBYTE(wValue) == USB_DEVICE_DESCRIPTOR_TYPE)
{
g_controlBuf = HID_DeviceDescriptor;
g_controlSize = wLength > sizeof(HID_DeviceDescriptor) ? sizeof(HID_DeviceDescriptor) : wLength;
}
else if (HIGHBYTE(wValue) == USB_CONFIGURATION_DESCRIPTOR_TYPE)
{
g_controlBuf = RHID_ConfigDescriptor;
g_controlSize = wLength > sizeof(RHID_ConfigDescriptor) ? sizeof(RHID_ConfigDescriptor) : wLength;
}
else if (HIGHBYTE(wValue) == USB_STRING_DESCRIPTOR_TYPE)
{
if (LOWBYTE(wValue) == 0)
{
g_controlBuf = USB_StringSupportedLanguages;
g_controlSize = wLength > sizeof(USB_StringSupportedLanguages) ? sizeof(USB_StringSupportedLanguages) : wLength;
}
else if (LOWBYTE(wValue) == 1)
{
g_controlBuf = USB_StringManufacturer;
g_controlSize = wLength > sizeof(USB_StringManufacturer) ? sizeof(USB_StringManufacturer) : wLength;
}
else if (LOWBYTE(wValue) == 2)
{
g_controlBuf = USB_StringProduct;
g_controlSize = wLength > sizeof(USB_StringProduct) ? sizeof(USB_StringProduct) : wLength;
}
else if (LOWBYTE(wValue) == 3)
{
g_controlBuf = USB_StringSerial;
g_controlSize = wLength > sizeof(USB_StringSerial) ? sizeof(USB_StringSerial) : wLength;
}
else
{
g_controlSize = 0;
return;
}
}
else if (HIGHBYTE(wValue) == USB_DEVICE_QUALIFIER_DESCRIPTOR_TYPE)
{
history[historyCntr % HISTORY_MAX].EP_before = USB_EP0R;
history[historyCntr % HISTORY_MAX].signal = bRequest;
history[historyCntr % HISTORY_MAX].value = HIGHBYTE(wValue);
history[historyCntr % HISTORY_MAX].sz = (*(uint16_t*)USB_E0_RX_SIZE_ADDR) & USB_COUNT0_RX_COUNT0_RX;
// send stall
USB_EP0R = (USB_EP0R ^ USB_EP0R_STAT_TX_0) & (USB_EP0R_STAT_TX | USB_EP0R_EP_TYPE | USB_EP0R_EP_KIND | USB_EP0R_EA);
history[historyCntr % HISTORY_MAX].EP_after = USB_EP0R;
history[historyCntr++ % HISTORY_MAX].cmd = 'S';
return;
}
else if (HIGHBYTE(wValue) == HID_REPORT_DESCRIPTOR_TYPE)
{
g_controlBuf = RHID_ReportDescriptor;
g_controlSize = wLength > sizeof(RHID_ReportDescriptor) ? sizeof(RHID_ReportDescriptor) : wLength;
}
else
{
g_controlSize = 0;
return;
}
}
else if (bRequest == USB_REQUEST_SET_ADDRESS)
{
g_newAddr = wValue;
SendStatusZero();
//USB_DADDR = wValue | USB_DADDR_EF;
g_controlSize = 0;
return;
}
else if (bRequest == USB_REQUEST_SET_CONFIGURATION)
{
SendStatusZero();
g_controlSize = 0;
g_usbState = USB_StateConfigured;
return;
}
else if (bRequest == USB_REQUEST_GET_INTERFACE)
{
g_controlBuf = USB_AlternateSetting;
g_controlSize = wLength > sizeof(USB_AlternateSetting) ? sizeof(USB_AlternateSetting) : wLength;
}
else if (bRequest == USB_REQUEST_CLEAR_FEATURE)
{
SendStatusZero();
g_controlSize = 0;
return;
}
else
{
g_controlSize = 0;
return;
}
}
else
{
// status zero or data
g_controlSize = 0;
}
}
// TX or TX after RX
if (g_controlSize > 0)
{
uint32_t send = g_controlSize > E0_MAX_PACKET_SIZE ? E0_MAX_PACKET_SIZE : g_controlSize;
// fix size
*(uint16_t*)USB_E0_TX_SIZE_ADDR = send;
sup_copy(USB_CONTROL_TX_ADDR, g_controlBuf, send);
g_controlBuf += send;
g_controlSize -= send;
// send
history[historyCntr % HISTORY_MAX].EP_before = USB_EP0R;
USB_EP0R = (USB_EP0R ^ USB_EP0R_STAT_TX) & (USB_EP0R_STAT_TX | USB_EP0R_EP_TYPE | USB_EP0R_EP_KIND | USB_EP0R_EA);
history[historyCntr % HISTORY_MAX].EP_after = USB_EP0R;
history[historyCntr++ % HISTORY_MAX].cmd = 'I';
}
else
{
if (g_newAddr > 0)
{
USB_DADDR = g_newAddr | USB_DADDR_EF;
g_usbState = USB_StateAddress;
g_newAddr = 0;
}
// force RX
// receive
history[historyCntr % HISTORY_MAX].EP_before = USB_EP0R;
USB_EP0R = (USB_EP0R ^ USB_EP0R_STAT_RX) & (USB_EP0R_STAT_RX | USB_EP0R_EP_TYPE | USB_EP0R_EP_KIND | USB_EP0R_EA);
history[historyCntr % HISTORY_MAX].EP_after = USB_EP0R;
history[historyCntr++ % HISTORY_MAX].cmd = 'O';
}
}
void ResetUSB()
{
// memory for buffers
uint16_t *usbBufs = (uint16_t*)USB_PMA_ADDR;
uint8_t buf[5] = { 4 };
g_cntr++;
buf[1] = g_cntr % 2 ? 1 : 0;
buf[2] = g_cntr % 2 ? 0 : 1;
buf[3] = 3;
// *(uint32_t*)&buf[1] = historyCntr;
g_usbState = USB_StateDefault;
g_newAddr = 0;
memset(usbBufs, 0, 1024); // remove
*usbBufs = 8 * 3;
usbBufs += 2;
*usbBufs = E0_MAX_PACKET_SIZE;
usbBufs += 2;
*usbBufs = 8 * 3 + E0_MAX_PACKET_SIZE;
usbBufs += 2;
*usbBufs = E0_MAX_PACKET_SIZE / 2 << 10; // 8 byte size
usbBufs += 2;
*usbBufs = 8 * 3 + 2 * E0_MAX_PACKET_SIZE;
usbBufs += 2;
*usbBufs = E1_MAX_PACKET_SIZE;
usbBufs += 2;
*usbBufs = 8 * 3 + 2 * E0_MAX_PACKET_SIZE + E1_MAX_PACKET_SIZE;
usbBufs += 2;
*usbBufs = E1_MAX_PACKET_SIZE / 2 << 10; // 8 byte size
usbBufs += 2;
*usbBufs = 8 * 3 + 2 * E0_MAX_PACKET_SIZE + 2 * E1_MAX_PACKET_SIZE;
usbBufs += 2;
*usbBufs = E2_MAX_PACKET_SIZE;
usbBufs += 2;
*usbBufs = 8 * 3 + 2 * E0_MAX_PACKET_SIZE + 2 * E1_MAX_PACKET_SIZE + E2_MAX_PACKET_SIZE;
usbBufs += 2;
*usbBufs = E2_MAX_PACKET_SIZE / 2 << 10; // 8 byte size
*(uint16_t*)USB_E1_TX_SIZE_ADDR = 5;
sup_copy(USB_E1_TX_ADDR, buf, 5);
USB_EP0R = USB_EP0R_EP_TYPE_0 | USB_EP0R_STAT_RX_0 | USB_EP0R_STAT_RX_1;
USB_EP1R = USB_EP1R_EP_TYPE | USB_EP1R_STAT_TX_0 | USB_EP1R_STAT_TX_1 | 1;
USB_EP2R = USB_EP2R_EP_TYPE | 2;
USB_DADDR = USB_DADDR_EF;
g_resets++;
}
void USB_HP_CAN1_TX_IRQHandler(void)
{
}
void USB_LP_CAN1_RX0_IRQHandler(void)
{
if (USB_ISTR & USB_ISTR_RESET)
{
history[historyCntr++ % HISTORY_MAX].cmd = 'R';
// function
ResetUSB();
// clear all interrupt status
USB_ISTR &= ~USB_ISTR_RESET;
// no more interrupts
return;
}
if (USB_ISTR & USB_ISTR_CTR)
{
// control endpoint
if (USB_EP0R & (USB_EP0R_CTR_RX | USB_EP0R_CTR_TX))
ProcessControl();
if (USB_EP1R & (USB_EP1R_CTR_RX | USB_EP1R_CTR_TX))
ProcessData();
}
}
// SysTick interrupt Handler.
void SysTick_Handler(void)
{
g_msTicks++;
}
void sleep(uint32_t amount)
{
uint32_t need = amount;
g_msTicks = 0;
while (g_msTicks < need)
{
// Wait for next SysTick Interrupt
__WFE(); // Power-Down until next Event/Interrupt
}
}
int main(void)
{
uint32_t sum = 0;
uint32_t waiter = 500;
bool minus = true;
SysTick_Config(SystemCoreClock / 1000);
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;
GPIOA->CRL &= ~(GPIO_CRL_MODE0 | GPIO_CRL_CNF0 | GPIO_CRL_MODE1 | GPIO_CRL_CNF1);
GPIOA->CRL |= GPIO_CRL_MODE0_1 | GPIO_CRL_CNF0_0 | GPIO_CRL_MODE1_1;
// printf("Hello, world!");
// GPIOA->BSRR = GPIO_BSRR_BR1;
sleep(2000);
GPIOA->BSRR = GPIO_BSRR_BS1;
// NVIC_SetPriority(USB_LP_CAN1_RX0_IRQn,
NVIC_EnableIRQ(USB_HP_CAN1_TX_IRQn);
NVIC_EnableIRQ(USB_LP_CAN1_RX0_IRQn);
RCC->APB1ENR |= RCC_APB1ENR_USBEN;
// reset power down alone
USB_CNTR &= ~USB_CNTR_PDWN;
sleep(100);
// clear interrupt status
USB_ISTR = 0;
// remove force reset
USB_CNTR = USB_CNTR_RESETM;
// sleep(100);
while(1)
{
sleep(waiter);
GPIOA->BSRR = GPIO_BSRR_BS0;
sleep(waiter);
GPIOA->BSRR = GPIO_BSRR_BR0;
sum += 2 * waiter;
if (sum >= 1000)
{
sum = 0;
if (minus)
{
if (waiter <= 20) waiter = 1, minus = false;
else waiter -= 20;
}
else
{
if (waiter >= 500) waiter = 500, minus = true;
else waiter += 20;
}
}
}
}
- B@R5uk
- Собутыльник Кота
- Сообщения: 2896
- Зарегистрирован: Сб ноя 13, 2010 12:53:25
- Откуда: приходит весна?
Re: Ручная настройка USB
Если код очень разветвлённый, то да, можно в ОЗУ, а если линейный, то что из флэша, что из ОЗУ будет одинаково. Контроллер осуществляет чтение флэша блоками по несколько команд, поэтому пока флэш готовится к выдаче следующего блока, ядро занято исполнением текущего. Причём всякие сишные "ветвления" типаIfoR писал(а):...пока не понял, что нужно поставить задержку на FLASH, а быстроисполняемый код переписывать в ОЗУ и от туда запускать.
Код: Выделить всё
if ( {условие} )
{
{делать раз}
}
else
{
{делать два}
}
Асло, помещайте, пожалуйста килобайты листингов программ под спойлеры.
Re: Ручная настройка USB
ST называет это ART accelerator.Контроллер осуществляет чтение флэша блоками по несколько команд, поэтому пока флэш готовится к выдаче следующего блока, ядро занято исполнением текущего.
Разница между теорией и практикой на практике гораздо больше, чем в теории.
- B@R5uk
- Собутыльник Кота
- Сообщения: 2896
- Зарегистрирован: Сб ноя 13, 2010 12:53:25
- Откуда: приходит весна?
Re: Ручная настройка USB
Кстати, а реально ли сделать виртуальный последовательный порт, которому не нужны будут никакие драйвера в любой операционке (стандартные чтобы подходили)? Типа дешёвой замены всяким FT232. Вроде же существует класс устройств связи (USB Communications Device Class).
Re: Ручная настройка USB
Виртуальный порт и не требует драйверов. Под Линуксом - совсем ничего не надо. Под Windows только текстовый файл чтобы сказать системе использовать стандартный драйвер для этого VID/PID.
Re: Ручная настройка USB
Насчёт термина "виртуальный" можно долго спорить, конечно, чем реально воткнутый в комп USB-COM виртуальнее нежели посконный COM on ISA bus.B@R5uk писал(а): ... виртуальный последовательный порт, которому не нужны будут никакие драйвера в любой операционке (стандартные чтобы подходили)?
Да, USB CDC должен поддерживаться всеми уважаюшими себя операциоными системами из коробки.B@R5uk писал(а): Типа дешёвой замены всяким FT232. Вроде же существует класс устройств связи (USB Communications Device Class).
ЕМНИП если Interface descriptor объявил стандартные класс/подкласс/протокол, то система выбирает стандартный драйвер не взирая на идентификаторы. В противном случае теряется смысл стандартности - например та-же флешка не увиделась-бы пока систему с её VID/PID-ами не познакомили.alexf58 писал(а):Под Windows только текстовый файл чтобы сказать системе использовать стандартный драйвер для этого VID/PID.
Одновременным нажатием LIGHT и POWER, РП Sangean ATS-909X (ver 1.29) превращается в ATS-909XR! 
- B@R5uk
- Собутыльник Кота
- Сообщения: 2896
- Зарегистрирован: Сб ноя 13, 2010 12:53:25
- Откуда: приходит весна?
Re: Ручная настройка USB
Спасибо. Всё стало предельно ясно и понятно.
Осталось только найти готовую прошивку.
Не думаю, что такая естественная вещь пришла только мне в голову. Может кто-нибудь уже знает такие решения?
Я видел довольно извращённый вариант на 8-ой меге с ногодрыгом, но он страдает нарушением стандартов: мега не способна держать никакой режим, кроме самого медленного, а в нём не поддерживается (по стандарту) Bulk-отправка. Поэтому изобретатели этого чудесного решения нашли в дровах винды дыру и заэксплойтили её. Разумеется, для других систем/более новых версий винды такое решение не прокатит. Хотелось бы что-нибудь грамотное либо с аппаратным USB, либо на более быстром контроллере (хотя за счёт быстроты МК ногодрыг извратом быть не перестанет).
Я видел довольно извращённый вариант на 8-ой меге с ногодрыгом, но он страдает нарушением стандартов: мега не способна держать никакой режим, кроме самого медленного, а в нём не поддерживается (по стандарту) Bulk-отправка. Поэтому изобретатели этого чудесного решения нашли в дровах винды дыру и заэксплойтили её. Разумеется, для других систем/более новых версий винды такое решение не прокатит. Хотелось бы что-нибудь грамотное либо с аппаратным USB, либо на более быстром контроллере (хотя за счёт быстроты МК ногодрыг извратом быть не перестанет).
Re: Ручная настройка USB
ATMega 16U2 стоит копейки и имеет настоящий USB. Прошивка для USB to Serial: ишите по слову LUFA.



