stm32f4 VCP DMA ile buffer göndermek

Başlatan Gökhan BEKEN, 10 Eylül 2015, 17:10:31

memo333

USByi bayağı unutmuşum..

http://www.beyondlogic.org/usbnutshell/usb6.shtml#SetupPacket

SETUP Packet HOST tarafından gönderiliyor. Burada her transaction'da alıancak total byte sayısı wLength içinde saklanıyor. Muhtemelen PC tarafında sen 128 bytelık veri istiyorsun.

http://www.st.com/st-web-ui/static/active/cn/resource/technical/document/user_manual/CD00158241.pdf

sayfa 18. Burada HOST'tan gönderilen SETUP Packet'in bir kopyasının saklandığını söylüyor.

wLength burada

uint16_t_uint8_t USBwLengths

USBwLengths is defined as type: uint16_t_uint8_t and can be accessed
through 3 macros:
#define USBwLength USBwLengths.w
#define USBwLength0 USBwLengths.bw.bb0
#define USBwLength1 USBwLengths.bw.bb1


olarak tanımlanmış ve ulaşılabilir. Debug'da bakabilirsin..

INTERRUPT konusu da şöyle açıklanmış

Alıntı YapA bulk transfer is considered complete when it has transferred the exact amount of data requested, transferred a packet less than the maximum endpoint size, or transferred a zero-length packet.

Toplarsak: Teorime göre sen PC tarfındaki programda SETUP PACKET'te wlength 128 olarak gönderiyorsun. Device'da bunu alıyor ve 2 64byte transaction olarak gönderiyor. 128 byte tamamlanınca BULK transfer Interruptı oluşuyor ve sen PC programında datayı FIFO'dan alıp işliyorsun..

Gömülü Linux Notları --> http://linuxedu.xyz/

fatih6761

@memo333 hocam doğru olabilir teoriniz zaten USB hard işlemleri ben yapmıyorum linux çekirdeğine gömülü sürücü yapıyor. 128 baytlık transfer mevzusuna da şöyle ulaştım:
En verimli paket boyutunu seçmek için bir deneme yaptım. C de bir program yazıp fifo dosyasından sürekli 10000 bayt veri çekmeye çalıştım tabi dosyayı NONBLOCKING modda açarak.
Her paket 128 baytlık geliyordu. Yani ben 129 da istesem 10milyon da istesem 128 tane geliyor ama bu muhtemelen çekirdek tarafı sürücüsünde bahsettiğiniz ayardan kaynaklanıyor.
Sonra bir deneme daha yaptım. 100 bayt istedim. İkinci transferi de 100 bayt isteyerek yaptım. İlkinde tam 100 bayt gelirken ikincide 28 bayt geldi. Sonra tekrar 100 28 100 28 ... gidiyordu.
Durum böyle olunca paket boyutunu 128 bayt seçtim. (4 bayt magic 4 bayt data lenght 120bayt-60sample veri)

memo333

deneme fırsatın olursa debugda

#define USBwLength USBwLengths.w
#define USBwLength0 USBwLengths.bw.bb0
#define USBwLength1 USBwLengths.bw.bb1

yukarıdakilere bakabilir misin?
Gömülü Linux Notları --> http://linuxedu.xyz/

fatih6761

#18
@memo333 hocam ne PC tarafında ne de mcu tarafında böyle bir tanım bulamadım.
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Buldum hocam. O tanımı değil ama neden 128 olduğunu buldum. HAL Init kısmında tx fifo boyutu 128 byte olarak ayarlanıyor.
usbd_conf.c dosyasında:
USBD_StatusTypeDef  USBD_LL_Init (USBD_HandleTypeDef *pdev)
{ 
 ...

  HAL_PCD_SetTxFiFo(&hpcd_USB_OTG_FS, 0, 0x40);
  HAL_PCD_SetTxFiFo(&hpcd_USB_OTG_FS, 1, 0x80);

...
}

Burada 0 ve 1 olan FIFO index miş. Son parametre fifo boyutu olarak tanımlanmış. 0x40 = 64 ve 0x80 = 128
Yani 0. fifo 64 baytlık, 1. fifo 128 baytlık. Bende sadece 1. fifoyu kullandığı yönünde bir izlenim oluştu.
Şimdi bu fonksiyona bakalım.

stm32f4_hal_pcd_ex.c dosyasında:
HAL_StatusTypeDef HAL_PCDEx_SetTxFiFo(PCD_HandleTypeDef *hpcd, uint8_t fifo, uint16_t size)
{
  uint8_t i = 0;
  uint32_t Tx_Offset = 0;

  /*  TXn min size = 16 words. (n  : Transmit FIFO index)
      When a TxFIFO is not used, the Configuration should be as follows: 
          case 1 :  n > m    and Txn is not used    (n,m  : Transmit FIFO indexes)
         --> Txm can use the space allocated for Txn.
         case2  :  n < m    and Txn is not used    (n,m  : Transmit FIFO indexes)
         --> Txn should be configured with the minimum space of 16 words
     The FIFO is used optimally when used TxFIFOs are allocated in the top 
         of the FIFO.Ex: use EP1 and EP2 as IN instead of EP1 and EP3 as IN ones.
     When DMA is used 3n * FIFO locations should be reserved for internal DMA registers */
  
  /* vv Receive FIFO Size Register vv */
  /* Bu register Tx den önce çağırılan SetRxFifo tarafından yazılıyor. Değeri 0x80 (128) olacak. */
  Tx_Offset = hpcd->Instance->GRXFSIZ;
  
  if(fifo == 0)
  {
    /* vv EP0 / Non Periodic Tx FIFO Size Register vv */
   /* buraya geldiğinde size=64 ve Tx_Offset = 128 */
    hpcd->Instance->DIEPTXF0_HNPTXFSIZ = (size << 16) | Tx_Offset;
  }
  else
  {
    // bu fonksiyonu ikinci çağırışımızda Tx_Offset'e 0x40 (64) eklenmiş oluyor.
    Tx_Offset += (hpcd->Instance->DIEPTXF0_HNPTXFSIZ) >> 16;
    // Tx_Offset = 128 + 64 = 192

    // fifo sadece 1 olduğundan bu döngüye girmeyecek.
    for (i = 0; i < (fifo - 1); i++)
    {
      Tx_Offset += (hpcd->Instance->DIEPTXF[i] >> 16);
    }
    
    /* Multiply Tx_Size by 2 to get higher performance */

   /* vv Device Periodic Transmit FIFO vv */
   // Buraya geldiğinde size=128 ve Tx_Offset = 192 
    hpcd->Instance->DIEPTXF[fifo - 1] = (size << 16) | Tx_Offset;
    
  }
  
  return HAL_OK;
}

Bu kodun ve yazılan değerlerin ne anlattığını çözersek ne olup bittiğini kavrayacağız sanırım.
Özellikle fonk. başındaki yorumda "used optimally" derken ne yaptığını tam olarak açıklayan bir şey lazım.

memo333

#19
@fatih6761 hangi libi kullanıyorsun? ben o yazdıklarımı USB-FS Libinden aldım. Sonra bana da dank etti senin f4 kullandığın.

http://www.st.com/web/catalog/tools/FM147/CL1794/SC961/SS1743/PF257882#

Buradan indirdiğim kütüphanede usb_conf.h

#ifdef USB_OTG_FS_CORE
 #define RX_FIFO_FS_SIZE                          128
 #define TX0_FIFO_FS_SIZE                          32
 #define TX1_FIFO_FS_SIZE                         128
 #define TX2_FIFO_FS_SIZE                          32 
 #define TX3_FIFO_FS_SIZE                           0

// #define USB_OTG_FS_LOW_PWR_MGMT_SUPPORT
// #define USB_OTG_FS_SOF_OUTPUT_ENABLED
#endif


böyle birşey gördüm. senin yazdıklarına da bakıp yorum yazacağım..

EDIT-1: Sen Cube üzerinden gidiyorsun ben STDLIB üzerinden. CUBE üzerinden devam edelim..
Gömülü Linux Notları --> http://linuxedu.xyz/

fatih6761

Alıntı yapılan: memo333 - 12 Eylül 2015, 18:48:05
EDIT-1: Sen Cube üzerinden gidiyorsun ben STDLIB üzerinden. CUBE üzerinden devam edelim..
@memo333 doğru hocam, CUBE yani HAL kütüphanesini kullanıyorum, belirtmeyi unuttum sanırım.
Bu arada hocam eğer önceki mesjaımda yazan "used optimally" ifadesi
"büyük boyutta aktarım yapılacaksa performansı arttırmak için büyük boyutlu TX1 fifosunu kullan" anlamına geliyorsa 128'i açıklar.
Ama bu sefer şu soru akla geliyor: neden? Eğer EP sınırı 64-bayt ise 128 baytımız 2 x 64-bayt şeklinde gider. Bunun da performansa hiçbir katkısının olmaması gerekir.
Ancak 64-baytlık paketle de 128-baytlık paketle de 1.1mb/sn hıza ulaştım, dolayısıyla bir fark yok gibi.

memo333

Gömülü Linux Notları --> http://linuxedu.xyz/

Klein

HID ile bir yere varamayınca bir de CDC deneyeyim dedim. Cube ile CDC konfigürasyonu oluşturdum ama o da başarısız.
PC Aygıtı  "Stm32 Virtual com Port" ismiyle tanıyor, ancak Aygıt başlatılamıyor.

memo333

@Klein hocam stack ve hesap size'ı bir artırabilir misiniz?
Gömülü Linux Notları --> http://linuxedu.xyz/

Klein

#24
Alıntı yapılan: memo333 - 12 Eylül 2015, 20:54:37
@Klein hocam stack ve hesap size'ı bir artırabilir misiniz?
Hap ve Stack boyunu artırınca
Bğlantı noktalarının altna "Usb Seri Cihaz (COM4)" aygıtı geldi. 
Fakat onda da sorun var. Stack ve Hap boyutlarını 8K ya kadar çıkardım durum aynı.

Bu aygıt başlatılamıyor. (Kod 10)

Varolmayan bir aygıt belirtildi.
https://drive.google.com/open?id=0B6TH7G8C3IkBQm9vWlFhMDRrSjA

mesaj birleştirme:: 12 Eylül 2015, 21:19:21

Sürücüyü cebir ve şiddet kullanarak güncelleyince  oldu gibi.  Veri gönderme rutinlerini yazıp bi deneyeyim.

memo333

@gokhan BEKEN

6.5.7 CDC known limitations
When using this driver with the OTG HS core, enabling DMA mode (define 
USB_OTG_HS_INTERNAL_DMA_ENABLED in usb_conf.h file) results in data being sent 
only by multiple of 4 bytes. This is due to the fact that USB DMA does not allow sending 
data from non word-aligned addresses. For this specific application, it is advised not to 
enable this option unless required.


kaynak : http://www.st.com/web/en/resource/technical/document/user_manual/DM00108129.pdf

Toparlayacak olursam;

USB'de FS hızda bir transaction'da 64byte gönderebiliyoruz. Ancak BULK transfer bize bir frame'de (USB_FS için 1mS) birden çok transaction olanağı tanıyor.

STM32f4 ailesinde USB için FIFO RAM ayrılmış. F1lerde böyle bir durum yoktu. Ref Manual'da yazdığına göre uygulamaya daha az yük bindirmesi amaçlanıyormuş ve max 4 TX_IN FIFO tanımlanabiliyor.

Management of up to 4 dedicated Tx-IN FIFOs (one for each active IN EP) to put less
load on the application
Gömülü Linux Notları --> http://linuxedu.xyz/

fatih6761

Alıntı yapılan: memo333 - 12 Eylül 2015, 20:39:54
@fatih6761 veriyi gönderdiğin fonksiyon nedir?
CDC kütüphanesinin kendi fonksiyonları hocam. Şu an 8-bit örnekleme ile 525ksample/sn hıza ulaştım stabil olarak. Üstüne çıkınca Pc tarafındaki program sapıtıyor bir de STM32F4 çipi ısınmaya başlıyor :)
USBD_CDC_SetTxBuffer(&hUsbDeviceFS, (uint8_t*) &currentPacket, sizeof(currentPacket));
uint8_t result = USBD_CDC_TransmitPacket(&hUsbDeviceFS);

memo333

#27
Alıntı yapılan: fatih6761 - 13 Eylül 2015, 00:48:49
CDC kütüphanesinin kendi fonksiyonları hocam. Şu an 8-bit örnekleme ile 525ksample/sn hıza ulaştım stabil olarak. Üstüne çıkınca Pc tarafındaki program sapıtıyor bir de STM32F4 çipi ısınmaya başlıyor :)
USBD_CDC_SetTxBuffer(&hUsbDeviceFS, (uint8_t*) &currentPacket, sizeof(currentPacket));
uint8_t result = USBD_CDC_TransmitPacket(&hUsbDeviceFS);


Bu fonksiyon herhangi bir zaman kısıtlamasında değil gibi gözüküyor. Bu durumda BULK'ın tüm hızı kullanılabilir.Neden 128 byte interrupt olduğu ise Linux driver ile ilgili olabilir yada 64bytten çok transfer yapılacaksa FIFO1'e otomatik olarak aktarıyor mu? FIFO1'i biraz büyüterek denemek lazım.

mesaj birleştirme:: 13 Eylül 2015, 02:32:19

biraz geç oldu düşmeler başladı.

Alıntı YapThe CPU submits data over the USB by writing 32-bit words to dedicated OTG_FS locations
(push registers). The data are then automatically stored into Tx-data FIFOs configured
within the USB data RAM. There is one Tx-FIFO push register for each in-endpoint
(peripheral mode) or out-channel (host mode).
The CPU receives the data from the USB by reading 32-bit words from dedicated OTG_FS
addresses (pop registers). The data are then automatically retrieved from a shared Rx-FIFO
configured within the 1.25 KB USB data RAM. There is one Rx-FIFO pop register for each
out-endpoint or in-channel.
The USB protocol layer is driven by the serial interface engine (SIE) and serialized over the
USB by the full-/low-speed transceiver module within the on-chip physical layer (PHY).
Gömülü Linux Notları --> http://linuxedu.xyz/

memo333

if(CDC_Transmit_HS(data,2)==USBD_BUSY)


Bu fonksiyon sürekli USB Busy döndürüyor. Sebebini bilen var mı?
Gömülü Linux Notları --> http://linuxedu.xyz/

fatih6761

Alıntı yapılan: memo333 - 15 Eylül 2015, 20:14:47
if(CDC_Transmit_HS(data,2)==USBD_BUSY)


Bu fonksiyon sürekli USB Busy döndürüyor. Sebebini bilen var mı?

Hocam bu durum benim de başıma gelmişti. HS kullanacağınız zaman USB: kütüphanesi (STM32F4 için) 512byte'lık bufferlar ayırmak istiyor malloc ile. Linker scriptinizden HEAP boyutunu arttırmanız gerekiyor.
Nasıl yapılacağı tamamen derleyiciye bağlı.İnternette "[derleyici adı] stm32f4 increase heap size" diye ararsanız bulabilirsiniz.