stm32f4discovery и usb hid-устройство - быстрый старт.
Добавлено: Пт июл 05, 2013 1:42 pm
Не то чтобы примеров на данную тему для STM32 не было - они есть, но использовать их можно только целиком, когда навязано еще куча всякого хлама. Как убрать из проекта все что не нужно и оставить только реально необходимые элементы модуля? Есть пример работы HID-устройства для передачи данных датчика температуры - ну не нужен мне этот датчик, я просто хочу создать свое HID-устройство, передающее какие-то свои данные, т.е. мне нужно только включить USB, настроить там свои конфигурационные заголовки, а периферией обрасти успеем. Почему-то вся периферия просто включается добавлением нужной либы, а USB нет, USB надо обязательно тянуть из примера. Даже люди, с благими намерениями, пытаясь помочь, собирают вместе множество хороших примеров, не вытаскивают от туда отдельно библиотеки, чтобы тупо включить ТОЛЬКО USB.
Разбираться с USB - это довольно сложная задача и будем считать, что эта тема так или иначе ранее разбиралась не зависимо от контроллера (я ранее ковырял v-usb для AVR). Тогда мы знаем, что надо проинициализировать каким-то образом сам интерфейс, настроить некую функцию "USBD_HID_Setup", для обработки типовых запросов от Хоста и научиться отправлять хосту, когда надо, некоторые данные функцией "USBD_HID_SendReport". Конечно же еще где-то надо прописать заголовки, чтобы наше устройство правильно определялось Хостом. А где же это все можно сделать?
Все найденные мной примеры были вроде "Вон исходники подходящего примера - используй!", а что есть что? Где там нужные мне разделы? А почему не убрать все лишнее и не оставить только необходимое для произвольного проекта? Самое инетерсное, что пример может и рабочий, но примеры используют общие файлы, которые для разных примеров еще и конфликтуют! Нет, они работают, но не так как ожидает пользователь, но об этом чуть позже.
Итак, идем на сайт производителя и тянем набор примеров (блин, но библиотеки для работы с USB есть почему-то только там): http://www.st.com/web/catalog/tools/FM116/SC959/SS1532/PF252419?s_searchtype=partnumber
А что же нам от туда надо? Из документации очень полезна только схема Discovery "STM32F4DISCOVERY schematics", документацию на чип сюда положить не судьба была, т.е. datasheet, кому надо, ищем отдельно (иногда помогает). Нам нужен раздел "Associated Software", где есть: "STM-STUDIO" - что-то похожее на отладчик, но вид с боку, надо попробовать; "STSW-STM32068" - никто и не знал, а это и есть примеры, которые называются везде как "STM32F4-Discovery_FW_V1.1.0".
Из примеров нас интересует по сути только папка "Libraries\", а в ней "STM32_USB_Device_Library", "STM32_USB_HOST_Library" и "STM32_USB_OTG_Driver". Остальное, как правило, уже знает среда программирования.
- "STM32_USB_Device_Library/Core" - отвечает за разработку Устройства USB.
- "STM32_USB_HOST_Library/Core" - отвечает за разработку Хоста USB.
- "STM32_USB_OTG_Driver" - тут, и Хост, и Устройство сразу. От сюда надо тянуть библиотеки ВСЕГДА, но не все сразу. Файлики с "dcd" НЕ нужны хосту, а устройству НЕ нужны "hcd". Интересно, что эти либы друг с другом конфликтуют, поэтому в проект подтягиваем только все кроме не нужных
Теперь идем в пример.
"\Project\Demonstration\" - Тут пример заводской прошивки, демонстрирующей всю работу stm32f4discovery. Из него нам понадобится все что касается USB, т.е. Все файлики начинающиеся с "usb".
А еще "stm32f4xx_it".
"stm32f4xx_it" - тут во всех примерах обосновались ВСЕ обработчики прерываний. Если такие у Вас уже есть где-то еще, то не забудьте их как-то объединить. Не то чтобы они нам понадобятся, но удобство точно принесут
Нам еще понадобиться класс нашего устройства.
- "STM32_USB_Device_Library/Class" - Классы Устройства USB.
- "STM32_USB_HOST_Library/Class" - Классы Хоста USB.
Итого, что я скопировал себе в проект:
- Libraries\STM32_USB_Device_Library/Core
- Libraries\STM32_USB_OTG_Driver
- Libraries\STM32_USB_Device_Library/Class/hid/
- Project\Demonstration\usb*
- Project\Demonstration\stm32f4xx_it*
- из "STM32_USB_OTG_Driver" удалил "usb_hcd*"
- и "Utilities\STM32F4-Discovery\stm32f4_discovery.*" - Оказалась очень полезной
Теперь надо что-то из периферии включить в проект.
В файле "stm32f4xx_conf.h" прописываем необходимые инклуды. У меня получился такой набор:
Для работы только USB, очевидно, что не нужны "usart и spi". "tim" тоже, в общем-то, не понадобится.
"hid/src/usbd_hid_core.c" - тут самое важное - определение нашего USB, заголовки. Я поменял HID_MOUSE_ReportDesc на свой. Во-первых, предложенный в примере вариант мыши избыточен, а Во-вторых, мой с комментариями
. Пример мыши типа Logitec
В "hid/inc/usbd_hid_core.h" надо поменять длину заголовка, который только что поменяли на
В "hid/src/usbd_hid_core.c" находится и функция "USBD_HID_Setup", в которой можно дописать свои доп. обработчики, вроде ответа на "HID_REQ_GET_REPORT" и т.п., или изменить отправку заголовка "HID_MOUSE_ReportDesc" на какой-то другой - все тут!
В "usbd_desc.c" находятся такие важные элементы как VID, PID и PRODUCT_*_STRING. Можно менять на что-то иное. Не забудьте только, что VID и PID надо покупать
или использовать предоставленные, но помним, что их все используют!
В "stm32f4xx_it.c" Я заменил функцию вычисления сдвига курсора на пример из v-usb:
Но, ввиду того что у AVR и STM32 несколько разный подход к 8-ми или 16-ти битным исчислениям, то и результат немного отличается, хотя смысл тот же: мышка носится по кругу.
В обработчике прерывания "SysTick_Handler" тоже надо навести порядок. Для работы только c USB надо оставить вот так:
Обработка "TimingDelay" тоже не нужна, но используется в другом месте - это далее...
Теперь начнем заполнять функцию "main()"
Мы должны сперва проинициализировать тактирование нашего процессора, так чтобы заработал USB, тут есть масса тонкостей. Поскольку USB должен работать на 48MHz, что зависит и от др. настроек, поэтому не удивляйтесь, если при подключении к компу вы увидите "Устройство не опознано!" - у Вас, скорее всего, неверное тактирование. Чтобы наверняка вливаем из примера к себе файл "system_stm32f4xx.c" и будет нам счастье.
SysTick инициализируем на срабатывание прерывания 1 раз в одну милисекунду. Это самый удобный вариант для всех модулей, которые Вы возможно будете еще где использовать.
Например, реализация задержки:
1-й косяк примера. В примере SysTick настраивается на 10мсек., а в "Delay" это никак не упоминается и не корректируется, а ведь мы привыкли, что "nTime" для данной функции в милисекундах.
Добавим также функцию (ну и некоторые определения):
Теперь в "main()" можно добавить "USBConfig();" и у нас ничего не компилируется. А просто в настройках компилятора надо еще проинициализировать константу "USE_USB_OTG_FS", например так "-DUSE_USB_OTG_FS;". Или другую "USE_USB_OTG_HS" - это просто выбор типа USB: Full speed или High Speed.
Теперь все должно компилироваться. Если нет, то скорее всего Вы не почистили все лишнее от использования "LIS302DL". Поэтому я предлагаю к использванию целиком мой пример для Coocox, в котором как и ранее используется USART и подключена SD карта по SPI2 (см. более ранние посты), зато из файлов для USB вырезано все к нему не относящееся.
2-й косяк примера. Я долго не мог понять почему SysTick не срабатывает как я хочу раз в 1мс. Оказалось, что есть еще файлик "usbd_usr.c", в котором при инициализации USB дергается функция "USBD_USR_Init". Вообще файлик видимо сделан для дополнительных пользовательских обработчиков, но что-то смысла использования именно его не вижу, чаще нужно что-то еще, собственно он есть. В общем, там вызывается:
Ой, а это же перенастройка таймера на 41,(6) милисекунд. Какие там обещанные "40 msec"? Считать видимо не умеют, частота-то нашего МК 168MHz. Но блин, ЗАЧЕМ тогда инициализировали ранее на "10 msec"? Кто в лес, кто по дрова! Комментируем все это или удаляем!
В примере также есть файлик "selftest.c", который я не копировал. Ну не нужен он. Но там есть интересные функции. Например, "USB_Test()".
Но для ее работы понадобится еще одна функция:
Объясню, что она делает. Прежде чем инициализировать USB данная функция проверяет, что USB разъем не подключен, используя свойства схемы подключения USB на Discovery. Затем, ждет пока пользователь нажмет кнопку, но нажать он ее должен только после подключения шнурка USB. Как подключили шнурок от девайса к компу, нажмем кнопку и теперь эта функция начнет проверять подключили вы устройство к хосту. В случае, если что-то подключено или не подключено не вовремя, программа впадет в ступор на функции "Fail_Handler()".
Повторю, что данная функция ВООБЩЕ НЕ НУЖНА, но можно использовать как пример проверок подключения
. Если Вы просто проинициализируете устройство USB, то не важно подключено оно или нет к хосту. Он просто начнет работать, а если подключите его к компу, то оно определится и будет работать, а вся эта доп. логика только сбивает пользователя. Ну какой дружественный интерфейс, когда надо знать за ранее процедуру включения проводка USB? Мы же привыкли, когда надо - включить, а когда не надо - выключить, а тут еще и в нужный момент кнопку надо нажать, а если что-то забыли, то все - намертво зависший контроллер.
Это пример чисто usb hid-устройства, а именно мышки. Легко теперь переделать на что-то другое, т.к. лишнего нет, но мы уже знаем, что и где надо искать в примерах, если что-то не получается
STM32, очень неплохо справляется со своими задачами
UPD: В проект включена библиотека от ChaN`а для поддержки файловой системы FAT. Подразумевается, что если подключить по SPI2 флешку, то ее можно будет прочитать или на нее что-то записать, а вся отладочная информация пойдет на настроенный UART. К самому примеру с мышкой не имеет никакого отношения. Получить доступ, эта библиотека, к файловой системе компа по интерфейсу USB мыши также никак не сможет
Все что ее касается, а также все что касается UART, можно смело удалять и на работу мыши это никак не скажется!
Разбираться с USB - это довольно сложная задача и будем считать, что эта тема так или иначе ранее разбиралась не зависимо от контроллера (я ранее ковырял v-usb для AVR). Тогда мы знаем, что надо проинициализировать каким-то образом сам интерфейс, настроить некую функцию "USBD_HID_Setup", для обработки типовых запросов от Хоста и научиться отправлять хосту, когда надо, некоторые данные функцией "USBD_HID_SendReport". Конечно же еще где-то надо прописать заголовки, чтобы наше устройство правильно определялось Хостом. А где же это все можно сделать?
Все найденные мной примеры были вроде "Вон исходники подходящего примера - используй!", а что есть что? Где там нужные мне разделы? А почему не убрать все лишнее и не оставить только необходимое для произвольного проекта? Самое инетерсное, что пример может и рабочий, но примеры используют общие файлы, которые для разных примеров еще и конфликтуют! Нет, они работают, но не так как ожидает пользователь, но об этом чуть позже.
Итак, идем на сайт производителя и тянем набор примеров (блин, но библиотеки для работы с USB есть почему-то только там): http://www.st.com/web/catalog/tools/FM116/SC959/SS1532/PF252419?s_searchtype=partnumber
А что же нам от туда надо? Из документации очень полезна только схема Discovery "STM32F4DISCOVERY schematics", документацию на чип сюда положить не судьба была, т.е. datasheet, кому надо, ищем отдельно (иногда помогает). Нам нужен раздел "Associated Software", где есть: "STM-STUDIO" - что-то похожее на отладчик, но вид с боку, надо попробовать; "STSW-STM32068" - никто и не знал, а это и есть примеры, которые называются везде как "STM32F4-Discovery_FW_V1.1.0".
Из примеров нас интересует по сути только папка "Libraries\", а в ней "STM32_USB_Device_Library", "STM32_USB_HOST_Library" и "STM32_USB_OTG_Driver". Остальное, как правило, уже знает среда программирования.
- "STM32_USB_Device_Library/Core" - отвечает за разработку Устройства USB.
- "STM32_USB_HOST_Library/Core" - отвечает за разработку Хоста USB.
- "STM32_USB_OTG_Driver" - тут, и Хост, и Устройство сразу. От сюда надо тянуть библиотеки ВСЕГДА, но не все сразу. Файлики с "dcd" НЕ нужны хосту, а устройству НЕ нужны "hcd". Интересно, что эти либы друг с другом конфликтуют, поэтому в проект подтягиваем только все кроме не нужных

Теперь идем в пример.
"\Project\Demonstration\" - Тут пример заводской прошивки, демонстрирующей всю работу stm32f4discovery. Из него нам понадобится все что касается USB, т.е. Все файлики начинающиеся с "usb".
А еще "stm32f4xx_it".
"stm32f4xx_it" - тут во всех примерах обосновались ВСЕ обработчики прерываний. Если такие у Вас уже есть где-то еще, то не забудьте их как-то объединить. Не то чтобы они нам понадобятся, но удобство точно принесут

Нам еще понадобиться класс нашего устройства.
- "STM32_USB_Device_Library/Class" - Классы Устройства USB.
- "STM32_USB_HOST_Library/Class" - Классы Хоста USB.
Итого, что я скопировал себе в проект:
- Libraries\STM32_USB_Device_Library/Core
- Libraries\STM32_USB_OTG_Driver
- Libraries\STM32_USB_Device_Library/Class/hid/
- Project\Demonstration\usb*
- Project\Demonstration\stm32f4xx_it*
- из "STM32_USB_OTG_Driver" удалил "usb_hcd*"
- и "Utilities\STM32F4-Discovery\stm32f4_discovery.*" - Оказалась очень полезной

Теперь надо что-то из периферии включить в проект.
В файле "stm32f4xx_conf.h" прописываем необходимые инклуды. У меня получился такой набор:
Код: Выделить всё
#include "stm32f4xx_dma.h"
#include "stm32f4xx_exti.h"
#include "stm32f4xx_flash.h"
#include "stm32f4xx_gpio.h"
#include "stm32f4xx_pwr.h"
#include "stm32f4xx_rcc.h"
#include "stm32f4xx_spi.h"
#include "stm32f4xx_syscfg.h"
#include "stm32f4xx_tim.h"
#include "stm32f4xx_usart.h"
"hid/src/usbd_hid_core.c" - тут самое важное - определение нашего USB, заголовки. Я поменял HID_MOUSE_ReportDesc на свой. Во-первых, предложенный в примере вариант мыши избыточен, а Во-вторых, мой с комментариями

Код: Выделить всё
__ALIGN_BEGIN static uint8_t HID_MOUSE_ReportDesc[HID_MOUSE_REPORT_DESC_SIZE] __ALIGN_END =
{
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x02, // USAGE (Mouse)
0xa1, 0x01, // COLLECTION (Application)
0x09, 0x01, // USAGE (Pointer)
0xA1, 0x00, // COLLECTION (Physical)
0x05, 0x09, // USAGE_PAGE (Button)
0x19, 0x01, // USAGE_MINIMUM
0x29, 0x03, // USAGE_MAXIMUM
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0x01, // LOGICAL_MAXIMUM (1)
0x95, 0x03, // REPORT_COUNT (3)
0x75, 0x01, // REPORT_SIZE (1)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x95, 0x01, // REPORT_COUNT (1)
0x75, 0x05, // REPORT_SIZE (5)
0x81, 0x03, // INPUT (Const,Var,Abs)
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x30, // USAGE (X)
0x09, 0x31, // USAGE (Y)
0x09, 0x38, // USAGE (Wheel)
0x15, 0x81, // LOGICAL_MINIMUM (-127)
0x25, 0x7F, // LOGICAL_MAXIMUM (127)
0x75, 0x08, // REPORT_SIZE (8)
0x95, 0x03, // REPORT_COUNT (3)
0x81, 0x06, // INPUT (Data,Var,Rel)
0xC0, // END_COLLECTION
0xC0 // END COLLECTION
};
Код: Выделить всё
#define HID_MOUSE_REPORT_DESC_SIZE 52
В "usbd_desc.c" находятся такие важные элементы как VID, PID и PRODUCT_*_STRING. Можно менять на что-то иное. Не забудьте только, что VID и PID надо покупать

В "stm32f4xx_it.c" Я заменил функцию вычисления сдвига курсора на пример из v-usb:
Код: Выделить всё
static uint8_t *USBD_HID_GetPos (void)
{
static int8_t HID_Buffer[4] = {0};
static int8_t sinus = 7 << 6, cosinus = 0;
char d;
#define DIVIDE_BY_64(val) ((val + (val > 0 ? 32 : -32))) >> 6 /* rounding divide */
HID_Buffer[1] = (d = DIVIDE_BY_64(cosinus));
sinus += d;
HID_Buffer[2] = (d = DIVIDE_BY_64(sinus));
cosinus -= d;
return HID_Buffer;
}
В обработчике прерывания "SysTick_Handler" тоже надо навести порядок. Для работы только c USB надо оставить вот так:
Код: Выделить всё
void SysTick_Handler(void)
{
uint8_t *buf;
if (TimingDelay != 0x00)
{
TimingDelay--;
}
static uint8_t cnt=0;
cnt++;
if(cnt>10){
cnt=0;
buf = USBD_HID_GetPos();
if((buf[1] != 0) ||(buf[2] != 0))
{
USBD_HID_SendReport (&USB_OTG_dev,
buf,
4);
}
}
}
Теперь начнем заполнять функцию "main()"
Код: Выделить всё
RCC_ClocksTypeDef RCC_Clocks;
SystemInit();
/* SysTick end of count event each 1ms */
RCC_GetClocksFreq(&RCC_Clocks);
SysTick_Config(RCC_Clocks.HCLK_Frequency / 1000);
SysTick инициализируем на срабатывание прерывания 1 раз в одну милисекунду. Это самый удобный вариант для всех модулей, которые Вы возможно будете еще где использовать.
Например, реализация задержки:
Код: Выделить всё
void Delay(__IO uint32_t nTime)
{
TimingDelay = nTime;
while(TimingDelay != 0);
}
Добавим также функцию (ну и некоторые определения):
Код: Выделить всё
#ifdef USB_OTG_HS_INTERNAL_DMA_ENABLED
#if defined ( __ICCARM__ ) /*!< IAR Compiler */
#pragma data_alignment = 4
#endif
#endif /* USB_OTG_HS_INTERNAL_DMA_ENABLED */
__ALIGN_BEGIN USB_OTG_CORE_HANDLE USB_OTG_dev __ALIGN_END;
//uint16_t PrescalerValue = 0;
void Delay(__IO uint32_t nTime);
volatile __IO uint32_t TimingDelay;
volatile __IO uint32_t UserTimingDelay=0;
/* Private function prototypes -----------------------------------------------*/
static uint32_t USBConfig(void);
/* .......................*/
static uint32_t USBConfig(void)
{
USBD_Init(&USB_OTG_dev,
USB_OTG_FS_CORE_ID,
&USR_desc,
&USBD_HID_cb,
&USR_cb);
return 0;
}
Теперь все должно компилироваться. Если нет, то скорее всего Вы не почистили все лишнее от использования "LIS302DL". Поэтому я предлагаю к использванию целиком мой пример для Coocox, в котором как и ранее используется USART и подключена SD карта по SPI2 (см. более ранние посты), зато из файлов для USB вырезано все к нему не относящееся.
2-й косяк примера. Я долго не мог понять почему SysTick не срабатывает как я хочу раз в 1мс. Оказалось, что есть еще файлик "usbd_usr.c", в котором при инициализации USB дергается функция "USBD_USR_Init". Вообще файлик видимо сделан для дополнительных пользовательских обработчиков, но что-то смысла использования именно его не вижу, чаще нужно что-то еще, собственно он есть. В общем, там вызывается:
Код: Выделить всё
void USBD_USR_Init(void)
{
/* Setup SysTick Timer for 40 msec interrupts
This interrupt is used to probe the joystick */
if (SysTick_Config(SystemCoreClock / 24))
{
// Capture error
while (1);
}
}
В примере также есть файлик "selftest.c", который я не копировал. Ну не нужен он. Но там есть интересные функции. Например, "USB_Test()".
Код: Выделить всё
/**
* @brief Test USB Hardware.
* The main objectif of this test is to check the hardware connection of the
* Audio and USB peripheral.
* @param None
* @retval None
*/
void USB_Test(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/******************************** USB Test **********************************/
/*----------------- Part1: without cables connected ------------------------*/
/* GPIOA, GPIOC and GPIOD clock enable */
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOC | \
RCC_AHB1Periph_GPIOD, ENABLE);
/* GPIOD Configuration: Pins 5 in output push-pull */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOD, &GPIO_InitStructure);
/* Turn LED8 ON using PD5 */
GPIO_ResetBits(GPIOD, GPIO_Pin_5);
/* GPIOC Configuration: Pin 0 in output push-pull */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOC, &GPIO_InitStructure);
/* GPIOA Configuration: Pin 9 in input pull-up */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* Turn LED7 ON using PC0 (5v) */
GPIO_ResetBits(GPIOC, GPIO_Pin_0);
/* Waiting delay 10ms */
Delay(1);
if (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_9) == Bit_RESET)
{
Fail_Handler();
}
/* GPIOA Configuration: Pins 10 in output push-pull */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* Waiting delay 10ms */
Delay(1);
/* Check the ID level without cable connected */
if (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_10) == Bit_RESET)
{
Fail_Handler();
}
/* Turn LED7 OFF using PC0 */
GPIO_SetBits(GPIOC, GPIO_Pin_0);
/* GPIOA Configuration: Pins 11, 12 in input pull-up */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11 | GPIO_Pin_12;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* GPIOA Configuration: Pin 9 in output push-pull */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_ResetBits(GPIOA, GPIO_Pin_9);
/* Waiting delay 10ms */
Delay(1);
/* Check PA11 and PA12 level without cable connected */
if ((GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_11) == Bit_RESET) || \
(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_12) == Bit_RESET))
{
Fail_Handler();
}
/* GPIOA Configuration: Pins 12 in input pull-up */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* GPIOA Configuration: Pin 11 in output push-pull */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_ResetBits(GPIOA, GPIO_Pin_11);
/* Waiting delay 10ms */
Delay(1);
/* Check PA12 level without cable connected */
if (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_12) == Bit_RESET)
{
Fail_Handler();
}
/* GPIOA Configuration: Pins 11 in input pull-up */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* GPIOA Configuration: Pin 12 in output push-pull */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_ResetBits(GPIOA, GPIO_Pin_12);
/* Waiting delay 10ms */
Delay(1);
/* Check PA12 level without cable connected */
if (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_11) == Bit_RESET)
{
Fail_Handler();
}
/* GPIOA Configuration: Pins 9 in output push-pull */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* Turn LED7 ON using PA9 */
GPIO_SetBits(GPIOA, GPIO_Pin_9);
/* Turn Green LED ON: signaling Audio USB Test part1 PASS */
STM_EVAL_LEDOn(LED4);
/* Waiting User Button is pressed */
while (STM_EVAL_PBGetState(BUTTON_USER) == Bit_RESET)
{}
/* Waiting User Button is Released */
while (STM_EVAL_PBGetState(BUTTON_USER) != Bit_RESET)
{}
/* Turn Green LED OFF: signaling the end of Audio USB Test part1 and switching to
the part2 */
STM_EVAL_LEDOff(LED4);
/* Turn LED7 OFF using PA9 */
GPIO_ResetBits(GPIOA, GPIO_Pin_9);
/* Turn LED8 OFF using PD5 */
GPIO_SetBits(GPIOD, GPIO_Pin_5);
/*--------------- Part2: with Audio USB cables connected ------------------*/
/*********************************** USB Test *******************************/
/* Check the ID level with cable connected */
if (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_10) != Bit_RESET)
{
Fail_Handler();
}
/* GPIOA Configuration: Pins 11, 12 in input pull-down */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11 | GPIO_Pin_12;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* GPIOA Configuration: Pin 9 in output push-pull */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_SetBits(GPIOA, GPIO_Pin_9);
/* Waiting delay 10ms */
Delay(1);
/* Check PA11 and PA12 level with cable connected */
if ((GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_11) == Bit_RESET) || \
(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_12) == Bit_RESET))
{
Fail_Handler();
}
/* GPIOA Configuration: Pins 9, 12 in input pull-down */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_12;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* GPIOA Configuration: Pin 11 in output push-pull */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_SetBits(GPIOA, GPIO_Pin_11);
/* Waiting delay 10ms */
Delay(1);
/* Check PA9 and PA12 level with cable connected */
if ((GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_9) == Bit_RESET)|| \
(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_12) == Bit_RESET))
{
Fail_Handler();
}
/* GPIOA Configuration: Pins 9, 11 in input pull-down */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_11;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* GPIOA Configuration: Pin 12 in output push-pull */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_SetBits(GPIOA, GPIO_Pin_12);
/* Waiting delay 10ms */
Delay(1);
/* Check PA9 and PA12 level with cable connected */
if ((GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_9) == Bit_RESET)|| \
(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_11) == Bit_RESET))
{
Fail_Handler();
}
/* GPIOA Configuration: Pins 11, 12 in input pull-down */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11 | GPIO_Pin_12;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* GPIOA Configuration: Pin 9 in output push-pull */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* Turn LED7 OFF using PA9 */
GPIO_ResetBits(GPIOA, GPIO_Pin_9);
}
Код: Выделить всё
void Fail_Handler(void)
{
/* Erase last sector */
FLASH_EraseSector(FLASH_Sector_11, VoltageRange_3);
/* Write FAIL code at last word in the flash memory */
FLASH_ProgramWord(TESTRESULT_ADDRESS, ALLTEST_FAIL);
while(1)
{
/* Toggle Red LED */
STM_EVAL_LEDToggle(LED5);
Delay(5);
}
}
Повторю, что данная функция ВООБЩЕ НЕ НУЖНА, но можно использовать как пример проверок подключения

Это пример чисто usb hid-устройства, а именно мышки. Легко теперь переделать на что-то другое, т.к. лишнего нет, но мы уже знаем, что и где надо искать в примерах, если что-то не получается

STM32, очень неплохо справляется со своими задачами

UPD: В проект включена библиотека от ChaN`а для поддержки файловой системы FAT. Подразумевается, что если подключить по SPI2 флешку, то ее можно будет прочитать или на нее что-то записать, а вся отладочная информация пойдет на настроенный UART. К самому примеру с мышкой не имеет никакого отношения. Получить доступ, эта библиотека, к файловой системе компа по интерфейсу USB мыши также никак не сможет
