stm32f4discovery и usb hid-устройство - быстрый старт.

dtvims
Site Admin
Сообщения: 134
Зарегистрирован: Пн авг 02, 2010 2:43 pm

stm32f4discovery и usb hid-устройство - быстрый старт.

Сообщение dtvims » Пт июл 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" прописываем необходимые инклуды. У меня получился такой набор:

Код: Выделить всё

#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"

Для работы только USB, очевидно, что не нужны "usart и spi". "tim" тоже, в общем-то, не понадобится.
"hid/src/usbd_hid_core.c" - тут самое важное - определение нашего USB, заголовки. Я поменял HID_MOUSE_ReportDesc на свой. Во-первых, предложенный в примере вариант мыши избыточен, а Во-вторых, мой с комментариями :). Пример мыши типа Logitec

Код: Выделить всё

__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
};

В "hid/inc/usbd_hid_core.h" надо поменять длину заголовка, который только что поменяли на

Код: Выделить всё

#define HID_MOUSE_REPORT_DESC_SIZE    52

В "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:

Код: Выделить всё

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;
}

Но, ввиду того что у AVR и STM32 несколько разный подход к 8-ми или 16-ти битным исчислениям, то и результат немного отличается, хотя смысл тот же: мышка носится по кругу.
В обработчике прерывания "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);

      }
   }
}

Обработка "TimingDelay" тоже не нужна, но используется в другом месте - это далее...
Теперь начнем заполнять функцию "main()"

Код: Выделить всё

   RCC_ClocksTypeDef RCC_Clocks;

   SystemInit();

    /* SysTick end of count event each 1ms */
    RCC_GetClocksFreq(&RCC_Clocks);
   SysTick_Config(RCC_Clocks.HCLK_Frequency / 1000);

Мы должны сперва проинициализировать тактирование нашего процессора, так чтобы заработал USB, тут есть масса тонкостей. Поскольку USB должен работать на 48MHz, что зависит и от др. настроек, поэтому не удивляйтесь, если при подключении к компу вы увидите "Устройство не опознано!" - у Вас, скорее всего, неверное тактирование. Чтобы наверняка вливаем из примера к себе файл "system_stm32f4xx.c" и будет нам счастье.
SysTick инициализируем на срабатывание прерывания 1 раз в одну милисекунду. Это самый удобный вариант для всех модулей, которые Вы возможно будете еще где использовать.
Например, реализация задержки:

Код: Выделить всё

void Delay(__IO uint32_t nTime)
{
  TimingDelay = nTime;

  while(TimingDelay != 0);
}

1-й косяк примера. В примере SysTick настраивается на 10мсек., а в "Delay" это никак не упоминается и не корректируется, а ведь мы привыкли, что "nTime" для данной функции в милисекундах.
Добавим также функцию (ну и некоторые определения):

Код: Выделить всё

#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;
}

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

Код: Выделить всё

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);
  }
}

Ой, а это же перенастройка таймера на 41,(6) милисекунд. Какие там обещанные "40 msec"? Считать видимо не умеют, частота-то нашего МК 168MHz. Но блин, ЗАЧЕМ тогда инициализировали ранее на "10 msec"? Кто в лес, кто по дрова! Комментируем все это или удаляем!
В примере также есть файлик "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 данная функция проверяет, что USB разъем не подключен, используя свойства схемы подключения USB на Discovery. Затем, ждет пока пользователь нажмет кнопку, но нажать он ее должен только после подключения шнурка USB. Как подключили шнурок от девайса к компу, нажмем кнопку и теперь эта функция начнет проверять подключили вы устройство к хосту. В случае, если что-то подключено или не подключено не вовремя, программа впадет в ступор на функции "Fail_Handler()".
Повторю, что данная функция ВООБЩЕ НЕ НУЖНА, но можно использовать как пример проверок подключения :). Если Вы просто проинициализируете устройство USB, то не важно подключено оно или нет к хосту. Он просто начнет работать, а если подключите его к компу, то оно определится и будет работать, а вся эта доп. логика только сбивает пользователя. Ну какой дружественный интерфейс, когда надо знать за ранее процедуру включения проводка USB? Мы же привыкли, когда надо - включить, а когда не надо - выключить, а тут еще и в нужный момент кнопку надо нажать, а если что-то забыли, то все - намертво зависший контроллер.

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

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

vanyaacido
Сообщения: 9
Зарегистрирован: Вс дек 14, 2014 9:36 pm
Откуда: Россия
Контактная информация:

stm32f4discovery и usb hid устройство быстрый старт

Сообщение vanyaacido » Ср янв 14, 2015 4:39 am

Помогите пожалуйста с внешним прерыванием Проблема в том, что при возникновении внешнего прерывания процессор на него реагирует, но не переходит в обработчик прерываний, а зависает где то И в основной цикл не возвращается. Может кто знает в чем дело?

Код: Выделить всё

#include "stm32f10x.h"

int main

RCC->APB2ENR = RCC_APB2ENR_IOPCEN;
RCC->APB2ENR = RCC_APB2ENR_IOPAEN;

GPIOC->CRH = GPIO_CRH_MODE9;
GPIOC->CRH &= GPIO_CRH_CNF9;

GPIOA->CRL = GPIO_CRL_MODE0;
GPIOA->CRL &= GPIO_CRL_CNF0_0;

RCC->APB2ENR = RCC_APB2ENR_AFIOEN;
AFIO->EXTICR0 = AFIO_EXTICR1_EXTI0_PA;

EXTI->IMR = EXTI_IMR_MR0;
EXTI->EMR = EXTI_EMR_MR0;

EXTI->RTSR = EXTI_RTSR_TR0;

NVIC_SetPriorityEXTI0_IRQn, 7;
NVIC_EnableIRQEXTI0_IRQn;

__enable_irq ;

while 1

GPIOC->BSRR = GPIO_BSRR_BS8;
for volatile int x=0; x<100000; x
GPIOC->BRR = GPIO_BRR_BR8;
for volatile int x=0; x<100000; x



//Сам обработчик прерывания
void EXTI0_IRQHandlervoid
 
if EXTI->PR & EXTI_PR_PR0==0
 
GPIOC->BSRR = GPIO_BSRR_BS9;
EXTI->PR = EXTI_PR_PR0;

dtvims
Site Admin
Сообщения: 134
Зарегистрирован: Пн авг 02, 2010 2:43 pm

Re: stm32f4discovery и usb hid-устройство - быстрый старт.

Сообщение dtvims » Ср янв 14, 2015 10:24 am

Используйте тег [Code] чтобы обрамлять код, а то форматирование непонятным становится.
Если правильно понял, проблема с прерыванием по дерганию ножки. Надо смотреть помимо кода, еще и схему подключения. Например, если ножка висит в воздухе, на нее может наводится случайный сигнал, таким образом он занимает всю очередь прерываний и просто из них не выходит, вернее выходит из прерывания и тут же заходит снова или, еще хуже, вошло в прерывание, еще не вышло, а уже входит в следующее. Без полного кода можно только гадать, что у Вас там...
Сперва хорошо бы проверить точно работающий пример, а затем делать то что Вам надо.

Vladimir
Сообщения: 1
Зарегистрирован: Вс мар 29, 2015 5:15 pm

Re: stm32f4discovery и usb hid-устройство - быстрый старт.

Сообщение Vladimir » Вс мар 29, 2015 5:25 pm

Здравствуйте! Хотел потестить этот пример на TRUEStudio, не удалось: находит отсутствующий #include "ARMCM4.h" в CMSIS.
Тогда решил попробовать готовый проект для CooCox. Компилятор выдал ошибку:
GCC HOME: C:\Program Files (x86)\GNU Tools ARM Embedded\4.6 2012q2\bin
compile:
[mkdir] Created dir: C:\PROJECTS\STM\HID\test\test\Debug\bin
[mkdir] Created dir: C:\PROJECTS\STM\HID\test\test\Debug\obj
[cc] 31 total files to be compiled.
[cc] arm-none-eabi-gcc -mcpu=cortex-m4 -mthumb -Wall -ffunction-sections -g -O1 -c -DSTM32F407VG -DSTM32F4XX -DUSE_STDPERIPH_DRIVER -DHSE_VALUE=8000000 -D__ASSEMBLY__ -DUSE_USB_OTG_FS -IC:\PROJECTS\STM\HID\test -IC:\PROJECTS\STM\HID\test\otg -IC:\PROJECTS\STM\HID\test\hid\inc -IC:\PROJECTS\STM -IC:\PROJECTS\STM\HID\test\hid -IC:\PROJECTS\STM\HID\test\cmsis_boot -IC:\PROJECTS\STM\HID -IC:\PROJECTS\STM\HID\test\otg\inc -IC:\PROJECTS\STM\HID\test\discovery -IC:\PROJECTS\STM\HID\test\cmsis -IC:\PROJECTS\STM\HID\test\fat_fs -IC:\PROJECTS\STM\HID\test\Coreusb -IC:\PROJECTS\STM\HID\test\Coreusb\inc -IC:\PROJECTS\STM\HID\test\cmsis_lib\include -IC:\PROJECTS\STM\HID\test\fat_fs\include -IC:\PROJECTS\STM\HID\test\cmsis_lib C:\PROJECTS\STM\HID\test\cmsis_lib\source\stm32f4xx_syscfg.c C:\PROJECTS\STM\HID\test\otg\src\usb_core.c C:\PROJECTS\STM\HID\test\usbd_usr.c C:\PROJECTS\STM\HID\test\cmsis_lib\source\stm32f4xx_usart.c C:\PROJECTS\STM\HID\test\cmsis_lib\source\stm32f4xx_pwr.c C:\PROJECTS\STM\HID\test\fat_fs\source\diskio.c C:\PROJECTS\STM\HID\test\cmsis_boot\startup\startup_stm32f4xx.c C:\PROJECTS\STM\HID\test\discovery\stm32f4_discovery.c C:\PROJECTS\STM\HID\test\hid\src\usbd_hid_core.c C:\PROJECTS\STM\HID\test\Coreusb\src\usbd_core.c C:\PROJECTS\STM\HID\test\main.c C:\PROJECTS\STM\HID\test\cmsis_lib\source\stm32f4xx_rcc.c C:\PROJECTS\STM\HID\test\stm32f4xx_it.c C:\PROJECTS\STM\HID\test\stdio\printf.c C:\PROJECTS\STM\HID\test\usbd_desc.c C:\PROJECTS\STM\HID\test\cmsis_lib\source\stm32f4xx_gpio.c C:\PROJECTS\STM\HID\test\cmsis_lib\source\stm32f4xx_flash.c C:\PROJECTS\STM\HID\test\cmsis_boot\system_stm32f4xx.c C:\PROJECTS\STM\HID\test\syscalls\syscalls.c C:\PROJECTS\STM\HID\test\cmsis_lib\source\stm32f4xx_dma.c C:\PROJECTS\STM\HID\test\usb_bsp.c C:\PROJECTS\STM\HID\test\Coreusb\src\usbd_req.c C:\PROJECTS\STM\HID\test\otg\src\usb_dcd_int.c C:\PROJECTS\STM\HID\test\fat_fs\source\ff.c C:\PROJECTS\STM\HID\test\cmsis_lib\source\stm32f4xx_spi.c C:\PROJECTS\STM\HID\test\cmsis_lib\source\stm32f4xx_exti.c C:\PROJECTS\STM\HID\test\cmsis_lib\source\misc.c C:\PROJECTS\STM\HID\test\otg\src\usb_dcd.c C:\PROJECTS\STM\HID\test\fat_fs\source\fattime.c C:\PROJECTS\STM\HID\test\Coreusb\src\usbd_ioreq.c C:\PROJECTS\STM\HID\test\cmsis_lib\source\stm32f4xx_tim.c
[cc] C:\PROJECTS\STM\HID\test\fat_fs\source\diskio.c:13:2: warning: #warning Information only - using DMA [-Wcpp]
[cc] C:\PROJECTS\STM\HID\test\fat_fs\source\diskio.c: In function 'power_on':
[cc] C:\PROJECTS\STM\HID\test\fat_fs\source\diskio.c:289:16: warning: variable 'dummyread' set but not used [-Wunused-but-set-variable]
[cc] C:\PROJECTS\STM\HID\test\main.c: In function 'scan_files':
[cc] C:\PROJECTS\STM\HID\test\main.c:188:9: warning: implicit declaration of function 'strlen' [-Wimplicit-function-declaration]
[cc] C:\PROJECTS\STM\HID\test\main.c:188:13: warning: incompatible implicit declaration of built-in function 'strlen' [enabled by default]
[cc] C:\PROJECTS\STM\HID\test\main.c: In function 'main':
[cc] C:\PROJECTS\STM\HID\test\main.c:243:2: warning: format '%d' expects argument of type 'int', but argument 2 has type 'uint32_t' [-Wformat]
[cc] C:\PROJECTS\STM\HID\test\main.c:243:2: warning: format '%d' expects argument of type 'int', but argument 2 has type 'uint32_t' [-Wformat]
[cc] C:\PROJECTS\STM\HID\test\main.c:265:2: warning: passing argument 1 of 'sprintf' from incompatible pointer type [enabled by default]
[cc] c:\program files (x86)\gnu tools arm embedded\4.6 2012q2\bin\../lib/gcc/arm-none-eabi/4.6.2/../../../../arm-none-eabi/include/stdio.h:226:5: note: expected 'char *' but argument is of type 'char (*)[256]'
[cc] C:\PROJECTS\STM\HID\test\stm32f4xx_it.c: In function 'SysTick_Handler':
[cc] C:\PROJECTS\STM\HID\test\stm32f4xx_it.c:174:3: warning: implicit declaration of function 'disk_timerproc' [-Wimplicit-function-declaration]
[cc] C:\PROJECTS\STM\HID\test\stm32f4xx_it.c: In function 'USBD_HID_GetPos':
[cc] C:\PROJECTS\STM\HID\test\stm32f4xx_it.c:245:3: warning: overflow in implicit constant conversion [-Woverflow]
[cc] C:\PROJECTS\STM\HID\test\stm32f4xx_it.c:256:3: warning: pointer targets in return differ in signedness [-Wpointer-sign]
[cc] C:\PROJECTS\STM\HID\test\usbd_desc.c: In function 'USBD_USR_ProductStrDescriptor':
[cc] C:\PROJECTS\STM\HID\test\usbd_desc.c:215:5: warning: pointer targets in passing argument 1 of 'USBD_GetString' differ in signedness [-Wpointer-sign]
[cc] C:\PROJECTS\STM\HID\test\usbd_desc.c:219:5: warning: pointer targets in passing argument 1 of 'USBD_GetString' differ in signedness [-Wpointer-sign]
[cc] C:\PROJECTS\STM\HID\test\Coreusb\inc/usbd_req.h:86:6: note: expected 'uint8_t *' but argument is of type 'char *'
[cc] C:\PROJECTS\STM\HID\test\Coreusb\inc/usbd_req.h:86:6: note: expected 'uint8_t *' but argument is of type 'char *'
[cc] C:\PROJECTS\STM\HID\test\usbd_desc.c: In function 'USBD_USR_ManufacturerStrDescriptor':
[cc] C:\PROJECTS\STM\HID\test\usbd_desc.c:233:3: warning: pointer targets in passing argument 1 of 'USBD_GetString' differ in signedness [-Wpointer-sign]
[cc] C:\PROJECTS\STM\HID\test\Coreusb\inc/usbd_req.h:86:6: note: expected 'uint8_t *' but argument is of type 'char *'
[cc] C:\PROJECTS\STM\HID\test\usbd_desc.c: In function 'USBD_USR_SerialStrDescriptor':
[cc] C:\PROJECTS\STM\HID\test\usbd_desc.c:248:5: warning: pointer targets in passing argument 1 of 'USBD_GetString' differ in signedness [-Wpointer-sign]
[cc] C:\PROJECTS\STM\HID\test\Coreusb\inc/usbd_req.h:86:6: note: expected 'uint8_t *' but argument is of type 'char *'
[cc] C:\PROJECTS\STM\HID\test\usbd_desc.c:252:5: warning: pointer targets in passing argument 1 of 'USBD_GetString' differ in signedness [-Wpointer-sign]
[cc] C:\PROJECTS\STM\HID\test\Coreusb\inc/usbd_req.h:86:6: note: expected 'uint8_t *' but argument is of type 'char *'
[cc] C:\PROJECTS\STM\HID\test\usbd_desc.c: In function 'USBD_USR_ConfigStrDescriptor':
[cc] C:\PROJECTS\STM\HID\test\Coreusb\inc/usbd_req.h:86:6: note: expected 'uint8_t *' but argument is of type 'char *'
[cc] C:\PROJECTS\STM\HID\test\usbd_desc.c:268:5: warning: pointer targets in passing argument 1 of 'USBD_GetString' differ in signedness [-Wpointer-sign]
[cc] C:\PROJECTS\STM\HID\test\Coreusb\inc/usbd_req.h:86:6: note: expected 'uint8_t *' but argument is of type 'char *'
[cc] C:\PROJECTS\STM\HID\test\usbd_desc.c:272:5: warning: pointer targets in passing argument 1 of 'USBD_GetString' differ in signedness [-Wpointer-sign]
[cc] C:\PROJECTS\STM\HID\test\usbd_desc.c:289:5: warning: pointer targets in passing argument 1 of 'USBD_GetString' differ in signedness [-Wpointer-sign]
[cc] C:\PROJECTS\STM\HID\test\Coreusb\inc/usbd_req.h:86:6: note: expected 'uint8_t *' but argument is of type 'char *'
[cc] C:\PROJECTS\STM\HID\test\usbd_desc.c: In function 'USBD_USR_InterfaceStrDescriptor':
[cc] C:\PROJECTS\STM\HID\test\usbd_desc.c:293:5: warning: pointer targets in passing argument 1 of 'USBD_GetString' differ in signedness [-Wpointer-sign]
[cc] C:\PROJECTS\STM\HID\test\Coreusb\inc/usbd_req.h:86:6: note: expected 'uint8_t *' but argument is of type 'char *'
[cc] Starting link
[cc] arm-none-eabi-gcc -mcpu=cortex-m4 -mthumb -g -nostartfiles -Wl,-Map=test.map -O1 -Wl,--gc-sections -LC:\CooCox\CoIDE\configuration\ProgramData\test -Wl,-TC:\CooCox\CoIDE\configuration\ProgramData\test/arm-gcc-link.ld -g -o test.elf ..\obj\stm32f4xx_syscfg.o ..\obj\usb_core.o ..\obj\usbd_usr.o ..\obj\stm32f4xx_usart.o ..\obj\stm32f4xx_pwr.o ..\obj\diskio.o ..\obj\startup_stm32f4xx.o ..\obj\stm32f4_discovery.o ..\obj\usbd_hid_core.o ..\obj\usbd_core.o ..\obj\main.o ..\obj\stm32f4xx_rcc.o ..\obj\stm32f4xx_it.o ..\obj\printf.o ..\obj\usbd_desc.o ..\obj\stm32f4xx_gpio.o ..\obj\stm32f4xx_flash.o ..\obj\system_stm32f4xx.o ..\obj\syscalls.o ..\obj\stm32f4xx_dma.o ..\obj\usb_bsp.o ..\obj\usbd_req.o ..\obj\usb_dcd_int.o ..\obj\ff.o ..\obj\stm32f4xx_spi.o ..\obj\stm32f4xx_exti.o ..\obj\misc.o ..\obj\usb_dcd.o ..\obj\fattime.o ..\obj\usbd_ioreq.o ..\obj\stm32f4xx_tim.o
[cc] c:/program files (x86)/gnu tools arm embedded/4.6 2012q2/bin/../lib/gcc/arm-none-eabi/4.6.2/../../../../arm-none-eabi/lib/armv7e-m\libg.a(lib_a-impure.o):(.data._impure_ptr+0x0): multiple definition of `_impure_ptr'
[cc] collect2: ld returned 1 exit status
[cc] ..\obj\printf.o:printf.c:(.data+0x0): first defined here

BUILD FAILED
Total time: 7 seconds

Подскажете, в чем дело?

dtvims
Site Admin
Сообщения: 134
Зарегистрирован: Пн авг 02, 2010 2:43 pm

Re: stm32f4discovery и usb hid-устройство - быстрый старт.

Сообщение dtvims » Пт апр 10, 2015 5:14 pm

поиск по ошибке сразу дает решение:
http://forum.easyelectronics.ru/viewtopic.php?f=7&t=14584

MoskKsusBiz
Сообщения: 10
Зарегистрирован: Пн окт 19, 2015 10:43 am

stm32f4discovery и usb hid устройство быстрый старт

Сообщение MoskKsusBiz » Чт фев 04, 2016 6:46 am

Есть конкретное USB HID устройство. Его дескрипторы во вложенном файле. Количество endpoints в нем - 1шт, а Report - ы в нем как IN так и OUT. По моему представлению, в этом случае должно быть 2 endpoints - один на IN, другой на OUT. В чем мое заблуждение?


Вернуться в «Микроконтроллеры и автоматизация»

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 2 гостя