STM32F429 USB Hid Endpoint1 üzerinden veri alışverişi yapamıyorum

Başlatan strom, 17 Mart 2015, 01:14:55

strom

Herkese iyi günler.
Yeni yeni USB iletişime bakmaya başladım. Önce 18f4550 ve microchip'in örnek kodları üzerinden denemeler yaptım. Örnek kodlarda microchip kendi report description tablosunu oluşturmuş ve ona göre PC ile veri alışverişi yaptırtmış. Devreyi kurdum ve sorunsuz çalıştırdım.

Daha sonra STM32F429 içinde çalışmalara başladım. STM'nin örnek dosyalarından klavye uygulaması yaptım. Daha sonra microchip'in örneğinin aynısını STM32 üzerinde de denemek istedim. Malum keyboard, mouse, gamepad kendine özgü report descriptorları var. Ben kendi custom protokolümü oluşturmak istemiştim (microchipte olduğu gibi).
Ancak ne yaptıysam başarılı olamadım. Kesinlikle endpoint1 ve kesme iletişimi kullanarak PC'den STM'ye veri gönderemiyorum. Endpoint0 üzerinden control transferiyle 64byte'lık veriyi rahatlıkla gönderim ama.
İletişimi bir USB analyzer program sayesinde takip ediyorum. Endpoint1'e veri gönderildiği görülüyor. STM32 keil üzerinden debug yapıp, register'ları gözlemliyorum. Endpoint1 için olan değerler veri gönderdiğimde değişiyor. Ancak program kesinlkle bu verileri almıyor. Veri alma işlemini usbd_hid_core.c dosyası içinde yapmaya çalışıyorum.
Main dosyam:
#include "stm32f4xx.h"
#include "usb_core.h"
#include "usbd_core.h"
#include "usbd_hid_core.h"

#include "usbd_desc.h"
#include "usbd_usr.h"

extern USB_OTG_CORE_HANDLE USB_OTG_dev;

int main()
{
  USBD_Init(&USB_OTG_dev,
	#ifdef USE_USB_OTG_HS 
			USB_OTG_HS_CORE_ID,
	#else            
			USB_OTG_FS_CORE_ID,
	#endif
			&USR_desc, 
			&USBD_HID_cb, 
			&USR_cb);

  while(1)
  {
    
  }
}


usbd_hid_core dosyası
/**
  ******************************************************************************
  * @file    usbd_hid_core.c
  * @author  MCD Application Team
  * @version V1.1.0
  * @date    19-March-2012
  * @brief   This file provides the HID core functions.
  *
  * @verbatim
  *      
  *          ===================================================================      
  *                                HID Class  Description
  *          =================================================================== 
  *           This module manages the HID class V1.11 following the "Device Class Definition
  *           for Human Interface Devices (HID) Version 1.11 Jun 27, 2001".
  *           This driver implements the following aspects of the specification:
  *             - The Boot Interface Subclass
  *             - The Mouse protocol
  *             - Usage Page : Generic Desktop
  *             - Usage : Joystick)
  *             - Collection : Application 
  *      
  * @note     In HS mode and when the DMA is used, all variables and data structures
  *           dealing with the DMA during the transaction process should be 32-bit aligned.
  *           
  *      
  *  @endverbatim
  *
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; COPYRIGHT 2012 STMicroelectronics</center></h2>
  *
  * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
  * You may not use this file except in compliance with the License.
  * You may obtain a copy of the License at:
  *
  *        http://www.st.com/software_license_agreement_liberty_v2
  *
  * Unless required by applicable law or agreed to in writing, software 
  * distributed under the License is distributed on an "AS IS" BASIS, 
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  *
  ******************************************************************************
  */ 

/* Includes ------------------------------------------------------------------*/
#include "usbd_hid_core.h"
#include "usbd_desc.h"
#include "usbd_req.h"


/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY
  * @{
  */


/** @defgroup USBD_HID 
  * @brief usbd core module
  * @{
  */ 

/** @defgroup USBD_HID_Private_TypesDefinitions
  * @{
  */ 
/**
  * @}
  */ 


/** @defgroup USBD_HID_Private_Defines
  * @{
  */ 

/**
  * @}
  */ 


/** @defgroup USBD_HID_Private_Macros
  * @{
  */ 
/**
  * @}
  */ 




/** @defgroup USBD_HID_Private_FunctionPrototypes
  * @{
  */


static uint8_t  USBD_HID_Init (void  *pdev, 
                               uint8_t cfgidx);

static uint8_t  USBD_HID_DeInit (void  *pdev, 
                                 uint8_t cfgidx);

static uint8_t  USBD_HID_Setup (void  *pdev, 
                                USB_SETUP_REQ *req);

static uint8_t  *USBD_HID_GetCfgDesc (uint8_t speed, uint16_t *length);

static uint8_t  USBD_HID_DataIn (void  *pdev, uint8_t epnum);
static uint8_t  USBD_HID_DataOut (void  *pdev, uint8_t epnum);
/**
  * @}
  */ 

/** @defgroup USBD_HID_Private_Variables
  * @{
  */ 

USBD_Class_cb_TypeDef  USBD_HID_cb = 
{
  USBD_HID_Init,
  USBD_HID_DeInit,
  USBD_HID_Setup,
  NULL, /*EP0_TxSent*/  
  NULL, /*EP0_RxReady*/
  USBD_HID_DataIn, /*DataIn*/
  USBD_HID_DataOut, /*DataOut*/
  NULL, /*SOF */
  NULL,
  NULL,      
  USBD_HID_GetCfgDesc,
#ifdef USB_OTG_HS_CORE  
  USBD_HID_GetCfgDesc, /* use same config as per FS */
#endif  
};

#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 static uint32_t  USBD_HID_AltSet  __ALIGN_END = 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 static uint32_t  USBD_HID_Protocol  __ALIGN_END = 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 static uint32_t  USBD_HID_IdleState __ALIGN_END = 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 */ 
/* USB HID device Configuration Descriptor */
__ALIGN_BEGIN static uint8_t USBD_HID_CfgDesc[USB_HID_CONFIG_DESC_SIZ] __ALIGN_END =
{
  0x09, /* bLength: Configuration Descriptor size */
  USB_CONFIGURATION_DESCRIPTOR_TYPE, /* bDescriptorType: Configuration */
  USB_HID_CONFIG_DESC_SIZ,
  /* wTotalLength: Bytes returned */
  0x00,
  0x01,         /*bNumInterfaces: 1 interface*/
  0x01,         /*bConfigurationValue: Configuration value*/
  0x00,         /*iConfiguration: Index of string descriptor describing
  the configuration*/
  0xE0,         /*bmAttributes: bus powered and Support Remote Wake-up */
  0x32,         /*MaxPower 100 mA: this current is used for detecting Vbus*/
  
  /************** Descriptor of Joystick Mouse interface ****************/
  /* 09 */
  0x09,         /*bLength: Interface Descriptor size*/
  USB_INTERFACE_DESCRIPTOR_TYPE,/*bDescriptorType: Interface descriptor type*/
  0x00,         /*bInterfaceNumber: Number of Interface*/
  0x00,         /*bAlternateSetting: Alternate setting*/
  0x02,         /*bNumEndpoints*/
  0x03,         /*bInterfaceClass: HID*/
  0x00,         /*bInterfaceSubClass : 1=BOOT, 0=no boot*/
  0x00,         /*nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse*/
  0,            /*iInterface: Index of string descriptor*/
  /******************** Descriptor of Joystick Mouse HID ********************/
  /* 18 */
  0x09,         /*bLength: HID Descriptor size*/
  HID_DESCRIPTOR_TYPE, /*bDescriptorType: HID*/
  0x11,         /*bcdHID: HID Class Spec release number*/
  0x01,
  0x00,         /*bCountryCode: Hardware target country*/
  0x01,         /*bNumDescriptors: Number of HID class descriptors to follow*/
  0x22,         /*bDescriptorType*/
  HID_MOUSE_REPORT_DESC_SIZE,/*wItemLength: Total length of Report descriptor*/
  0x00,
  /******************** Descriptor of Mouse endpoint ********************/
  /* 27 */
  0x07,          /*bLength: Endpoint Descriptor size*/
  USB_ENDPOINT_DESCRIPTOR_TYPE, /*bDescriptorType:*/
  
  HID_IN_EP,     /*bEndpointAddress: Endpoint Address (IN)*/
  0x03,          /*bmAttributes: Interrupt endpoint*/
  HID_IN_PACKET, /*wMaxPacketSize: 4 Byte max */
  0x00,
  0x01,          /*bInterval: Polling Interval (10 ms)*/
  /* 34 */
  
  0x07,          /*bLength: Endpoint Descriptor size*/
  USB_ENDPOINT_DESCRIPTOR_TYPE, /*bDescriptorType:*/
  
  HID_OUT_EP,     /*bEndpointAddress: Endpoint Address (OUT)*/
  0x03,          /*bmAttributes: Interrupt endpoint*/
  HID_OUT_PACKET, /*wMaxPacketSize: 4 Byte max */
  0x00,
  0x01,          /*bInterval: Polling Interval (10 ms)*/
} ;

#ifdef USB_OTG_HS_INTERNAL_DMA_ENABLED
  #if defined ( __ICCARM__ ) /*!< IAR Compiler */
    #pragma data_alignment=4   
  #endif
/* USB HID device Configuration Descriptor */
__ALIGN_BEGIN static uint8_t USBD_HID_Desc[USB_HID_DESC_SIZ] __ALIGN_END=
{
  /* 18 */
  0x09,         /*bLength: HID Descriptor size*/
  HID_DESCRIPTOR_TYPE, /*bDescriptorType: HID*/
  0x11,         /*bcdHID: HID Class Spec release number*/
  0x01,
  0x00,         /*bCountryCode: Hardware target country*/
  0x01,         /*bNumDescriptors: Number of HID class descriptors to follow*/
  0x22,         /*bDescriptorType*/
  HID_MOUSE_REPORT_DESC_SIZE,/*wItemLength: Total length of Report descriptor*/
  0x00,
};
#endif 


#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 static uint8_t HID_MOUSE_ReportDesc[HID_MOUSE_REPORT_DESC_SIZE] __ALIGN_END =
{
    0x06, 0x00, 0xFF,       // Usage Page = 0xFF00 (Vendor Defined Page 1)
    0x09, 0x01,             // Usage (Vendor Usage 1)
    0xA1, 0x01,             // Collection (Application)
    0x19, 0x01,             //      Usage Minimum 
    0x29, 0x40,             //      Usage Maximum   //64 input usages total (0x01 to 0x40)
    0x15, 0x00,             //      Logical Minimum (data bytes in the report may have minimum value = 0x00)
    0x26, 0xFF, 0x00,       //      Logical Maximum (data bytes in the report may have maximum value = 0x00FF = unsigned 255)
    0x75, 0x08,             //      Report Size: 8-bit field size
    0x95, 0x40,             //      Report Count: Make sixty-four 8-bit fields (the next time the parser hits an "Input", "Output", or "Feature" item)
    0x81, 0x00,             //      Input (Data, Array, Abs): Instantiates input packet fields based on the above report size, count, logical min/max, and usage.
    0x19, 0x01,             //      Usage Minimum 
    0x29, 0x40,             //      Usage Maximum 	//64 output usages total (0x01 to 0x40)
    0x91, 0x00,             //      Output (Data, Array, Abs): Instantiates output packet fields.  Uses same report size and count as "Input" fields, since nothing new/different was specified to the parser since the "Input" item.
    0xC0
}; 

/**
  * @}
  */ 

/** @defgroup USBD_HID_Private_Functions
  * @{
  */ 

/**
  * @brief  USBD_HID_Init
  *         Initialize the HID interface
  * @param  pdev: device instance
  * @param  cfgidx: Configuration index
  * @retval status
  */
static uint8_t  USBD_HID_Init (void  *pdev, 
                               uint8_t cfgidx)
{
  
  /* Open EP IN */
  DCD_EP_Open(pdev,
              HID_IN_EP,
              HID_IN_PACKET,
              USB_OTG_EP_INT);
  
  /* Open EP OUT */
  DCD_EP_Open(pdev,
              HID_OUT_EP,
              HID_OUT_PACKET,
              USB_OTG_EP_INT);
  
  return USBD_OK;
}

/**
  * @brief  USBD_HID_Init
  *         DeInitialize the HID layer
  * @param  pdev: device instance
  * @param  cfgidx: Configuration index
  * @retval status
  */
static uint8_t  USBD_HID_DeInit (void  *pdev, 
                                 uint8_t cfgidx)
{
  /* Close HID EPs */
  DCD_EP_Close (pdev , HID_IN_EP);
  DCD_EP_Close (pdev , HID_OUT_EP);
  
  
  return USBD_OK;
}


/**
  * @brief  USBD_HID_Setup
  *         Handle the HID specific requests
  * @param  pdev: instance
  * @param  req: usb requests
  * @retval status
  */

uint8_t buf[64] = {0};
uint8_t buf1[64] = {0};
static uint8_t  USBD_HID_Setup (void  *pdev, 
                                USB_SETUP_REQ *req)
{
  int i;
  uint16_t len = 0;
  uint8_t  *pbuf = NULL;
  
  switch (req->bmRequest & USB_REQ_TYPE_MASK)
  {
  case USB_REQ_TYPE_CLASS :  
    switch (req->bRequest)
    {
      
      
    case HID_REQ_SET_PROTOCOL:
      USBD_HID_Protocol = (uint8_t)(req->wValue);
      break;
      
    case HID_REQ_GET_PROTOCOL:
      USBD_CtlSendData (pdev, 
                        (uint8_t *)&USBD_HID_Protocol,
                        1);    
      break;
      
    case HID_REQ_SET_IDLE:
      USBD_HID_IdleState = (uint8_t)(req->wValue >> 8);
      break;
    
    case HID_REQ_SET_REPORT:
      
      DCD_EP_PrepareRx(pdev, 0, buf, 64);
    break;
      
    case HID_REQ_GET_IDLE:
      USBD_CtlSendData (pdev, 
                        (uint8_t *)&USBD_HID_IdleState,
                        1);        
      break;      
      
    default:
      USBD_CtlError (pdev, req);
      return USBD_FAIL; 
    }
    break;
    
  case USB_REQ_TYPE_STANDARD:
    switch (req->bRequest)
    {
    case USB_REQ_GET_DESCRIPTOR: 
      if( req->wValue >> 8 == HID_REPORT_DESC)
      {
        len = MIN(HID_MOUSE_REPORT_DESC_SIZE , req->wLength);
        pbuf = HID_MOUSE_ReportDesc;
      }
      else if( req->wValue >> 8 == HID_DESCRIPTOR_TYPE)
      {
        
#ifdef USB_OTG_HS_INTERNAL_DMA_ENABLED
        pbuf = USBD_HID_Desc;   
#else
        pbuf = USBD_HID_CfgDesc + 0x12;
#endif 
        len = MIN(USB_HID_DESC_SIZ , req->wLength);
      }
      
      USBD_CtlSendData (pdev, 
                        pbuf,
                        len);
      
      break;
      
    case USB_REQ_GET_INTERFACE :
      USBD_CtlSendData (pdev,
                        (uint8_t *)&USBD_HID_AltSet,
                        1);
      break;
      
    case USB_REQ_SET_INTERFACE :
      USBD_HID_AltSet = (uint8_t)(req->wValue);
      break;
    }
  }
  return USBD_OK;
}

/**
  * @brief  USBD_HID_SendReport 
  *         Send HID Report
  * @param  pdev: device instance
  * @param  buff: pointer to report
  * @retval status
  */
uint8_t USBD_HID_SendReport     (USB_OTG_CORE_HANDLE  *pdev, 
                                 uint8_t *report,
                                 uint16_t len)
{
  if (pdev->dev.device_status == USB_OTG_CONFIGURED )
  {
    DCD_EP_Tx (pdev, HID_IN_EP, report, len);
  }
  return USBD_OK;
}

/**
  * @brief  USBD_HID_GetCfgDesc 
  *         return configuration descriptor
  * @param  speed : current device speed
  * @param  length : pointer data length
  * @retval pointer to descriptor buffer
  */
static uint8_t  *USBD_HID_GetCfgDesc (uint8_t speed, uint16_t *length)
{
  *length = sizeof (USBD_HID_CfgDesc);
  return USBD_HID_CfgDesc;
}

/**
  * @brief  USBD_HID_DataIn
  *         handle data IN Stage
  * @param  pdev: device instance
  * @param  epnum: endpoint index
  * @retval status
  */
static uint8_t  USBD_HID_DataIn (void  *pdev, 
                              uint8_t epnum)
{
        DCD_EP_PrepareRx(pdev, 1, buf1, 64);
  /* Ensure that the FIFO is empty before a new transfer, this condition could 
  be caused by  a new transfer before the end of the previous transfer */
  DCD_EP_Flush(pdev, HID_IN_EP);
  return USBD_OK;
}

static uint8_t USBD_HID_DataOut(void *pdev, uint8_t epnum)
{
        DCD_EP_PrepareRx(pdev, 1, buf1, 64);
  

  
}

/**
  * @}
  */ 


/**
  * @}
  */ 


/**
  * @}
  */ 

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/


Projenin tamamı:
http://www.mediafire.com/download/l5857lwwp3d9f7k/NewExamples.rar

PC programı
http://www.mediafire.com/download/308pt71q5i7a5qf/HID_PnP_Demo.exe

yamak

Hocam USBD_HID_Init fonksiyonun aşağıdaki gibi düzeltip USBD_HID_DataIn fonsiyonundan da DCD_EP_PrepareRx(pdev, 1, buf1, 64); satırını kaldırıp dener misiniz?
static uint8_t  USBD_HID_Init (void  *pdev, 
                               uint8_t cfgidx)
{
  
  /* Open EP IN */
  DCD_EP_Open(pdev,
              HID_IN_EP,
              HID_IN_PACKET,
              USB_OTG_EP_INT);
  
  /* Open EP OUT */
  DCD_EP_Open(pdev,
              HID_OUT_EP,
              HID_OUT_PACKET,
              USB_OTG_EP_INT);
  DCD_EP_PrepareRx(pdev, 1, buf1, 64);
  return USBD_OK;
}

strom

Hocam mükemmelsin ya. Çalıştı çok sağolun.

Hayır sorun bende mi yoksa stm'de m anlamıyorum. Ne kadar kötü ve yetersiz (bana göre) bir dökümantasyonu var. Kendi USB driver'larını kendi sitesinde bulurken bile zorlandım. Başka bir siteden yönlenerek geldim.
Yeni başlayan biri için yönlendirici ve açıklayıcı bir dökümantasyonu olmadığına karar verdim. En basitinden kendi std library'si için DMA2D ve LTDC donanımlarının dökümantasyonu yoktu. Bunlarla ilgili bir application notu yoktu. Ne zaman stm donanımlarında bir yere takılsam kesinlikle stm dökümantasyonlarından yardım alamıyorum. Bilmiyorum sorun belki de bende (yüksek ihtimal bende)

Ekleme:
Bir soru daha takıldı kafama. USB protokolüne göre mikrodenetleyici kafasına göre istediği zaman veriyi gönderemiyor. Mesela cihazımızı keyboard olacak şekilde konfigüre ettik. Bu durumda PC düzenli olarak bizden veri mi talep ediyor? Eğer ediyorsa ben bu talepleri USB protokolünü gözlemdiğim programda göremiyorum. Ayrıca STM üzerinde debug yaptığımda, işlemci herhangi bir isteği yanıtlamıyor sanırım çünkü hiçbir yere dallanmıyor. Register yapısını gözlemdiğimde sadece FNSOF: Frame number of the received SOF isimli bir alan düzenli olarak değişiyor. Başka bir hareketlilik yok. Şimdi eğer düzenli bir istek geliyorsa, bu istek nerde?
Ne zamanki ben göndermek istediğim veriyi endpoint'in buffer'ına koyuyuorum, o zaman veri gönderiliyor. Bu durumda iletişimi başlatan ben olmuyor muyum? Yani PC'nin değil benim istediğim zamanda iletişim oluyor
Kafam biraz karıştı ama oturacak gibi.

yamak

Hocam enumeration tamamlandıktan sonra device istediği zaman host a veri gönderebilir.

strom

Hocam görünüşe göre öyle ama okuduğum bilgilerle çelişiyor. USB Complete kitabından kesme transferi için olan bölümünden örnek vereyim mesela;

4. Baskı / s.75'te şöyle bir yazı var;
In a USB 2.0 bus, both bulk and interrupt endpoints must wait for the host to request data before sending data

SuperSpeed bulk and interrupt endpoints can notify the host that they have data to send by sending an ERDY Transaction Packet but still must wait for the host to request data packets.

Yanlış anlamadıysam şöyle diyor; Bulk ve Kesme transferinde cihaz veri göndermeden önce hosttan gelecek request'i beklemek zorunda. Superspeed'te ise endpoint'ler, datanın hazır olduğunu bildiren bir sinyal gönderebilselerde, yinede hosttan gelecek request'i beklemek zorundalar.

Ayrıca Interrupt endpoint descriptor'ında şöyle bir alan var;
Interrupt IN Endpoint Descriptor
07 bLength Descriptor size in bytes
05 bDescriptorType Descriptor type (Endpoint)
81 bEndpointAddress Endpoint number and direction (1 IN)
03 bmAttributes Transfer type (interrupt)
0040 wMaxPacketSize Maximum packet size
0A bInterval polling interval (milliseconds)

Açıklamasıda;
The polling interval, together with the speed of the device and the type of host controller, determine the frequency with which the driver should initiate an interrupt or an isochronous transfer.

Yani bu değer ile belirlenen süre aralıklarında PC Device'tan kesme veya bulk transferi talep eder(miş)

Yanlış yorumluyor olabilirim okuduklarımı. Çünkü denemelerimle çelişiyor bu bilgiler

yamak

Hocam evet device'ın data gönderebilmesi için Host un poll etmesi gerekiyormuş.Zaten tüm transfer tiplerinde böylemiş.Ama Interrupt transferde bu polling süresi çok kısa oluyo.Onu da dediğiniz gibi endpoint descriptor da ayarlıyoruz.
USB Complete'ten alıntı:

Alıntı YapThe name interrupt transfer suggests that a device might spontaneously send
data that triggers a hardware interrupt on the host. But interrupt transfers,
like all other USB transfers, occur only when the host polls a device. The
transfers are interrupt-like, however, because they guarantee that the host
requests or sends data with minimal delay
USBlyzer bu request'leri göstermiyo olabilir.