STM32F407 USB Adres Atama Sorunu

Başlatan Tagli, 18 Nisan 2019, 11:48:29

Tagli

İşlemcinin OTG_FS modülünü cihaz modunda kullanmaya çalışıyorum. Cube, HAL vs. kullanmadan kodu sıfırdan yazıyorum. Aslında internette HAL kullanmayan bir USB kütüphanesi buldum (burada), ancak epey incelememe rağmen üzerinde rahatça değişiklik yapamayacağım kadar karmaşık geldi bu kütüphaneden faydalanarak kendim sıfırdan yazmaya karar verdim.

İlk işim, yukarıda bahsedilen kütüphaneyi kurcalamak oldu. Hazır kütüphaneyi kullanmak için bile epey uğraştım. Sağını solunu kesip biçtim ve enumeration kısmını atlattım. Bu arada, STM32F4 Discovery üzerinde çalışıyorum. Daha sonra örnek kütüphaneden faydalanarak kendim sıfırdan yazma işine giriştim.

Malum olduğu üzere USB epey karmaşık bir konu. STM32F407'nin USB donanımı da öyle. Daha enumeration kısmında sorun yaşıyorum. Biraz uğraşarak Discovery üzerine iki tel lehimlemeyi başardım ve lojik analizör (çakma Saleae) ile USB hatlarını inceleyip paketleri görebiliyorum. Ayrıca yeri geldikçe SWO çıkışı ile printf'lerden de faydalanıyorum.

Vardığım noktada olanlar şunlar:
1) Bilgisayar önce device descriptör istiyor 64 byte. Tabi ben sadece 18 byte gönderiyorum cevap olarak.
2) Bilgisayar USB reset yolluyor.
3) Bilgisayar SetAddress komutu ile yeni adres yolluyor. Komutu işleyip ZLP ile onay gönderiyorum.
Bu noktada işler karışıyor...
4) Bilgisayar yeni adrese device descriptor talebi gönderiyor. İşlemci hiç sallamıyor. Birkaç denemeden sonra bilgisayar pes ediyor.

SetAddress komutunun diğer SETUP taleplerinden farklı olduğunu ve özel bir şekilde işlenmesi gerektiğini biliyorum ve buna dikkat ediyorum. Öyle ki, adres değişikliği komutu alır almaz değil, adres = 0 ile ZLP onayı gönderildikten sonra gerçekleştirilmeli. Bunun doğru çalıştığını biliyorum, çünkü bilgisayar sonraki GetDescriptor komutunu yeni adrese gönderiyor. Demek ki bilgisayar adres değişikliğinin gerçekleştiğini var saymış.

STM32F407'nin EndPoint ayarları epey karmaşık. Bir EndPoint'in kapanmasına sebep olabilecek ve hata yapmaya açık pek çok ayrıntı var. Ancak EP0_OUT ve SETUP paketleri bu konuda bir istisna. EP0 donanımsal olarak tamamen kapatılamıyor ve özellikle STALL yapılmadıysa SETUP paketlerini her zaman kabul ediyor ve ACK ile cevap veriyor. Bu zaten USB standartından gelen bir mecburiyet ve donanım tarafından da bu şekilde çalışması garantilenmiş. Sorun şu ki, adres değişiminden sonra lojik analizörden gördüğüm kadarıyla yeni adrese gelen SETUP paketine ACK bile yollanmıyor. Yani işlemci bunu tamamen gözardı ediyor. Benim bildiğim kadarıyla bu durum sadece adres, endpoint uyuşmazlığı veya CRC hatasında olabilir.

Bu noktada yeni adresin atanması ile ilgili bir sorunum olduğunu düşünüyorum. İlgili fonksiyonlarda printf'ler ile kontrol sağlıyorum ve atanacak adres doğru ulaşmış gibi gözüküyor. Ancak DCFG register'ı içindeki DAD (Device Address) bitlerini kontrol etmem mümkün değil, çünkü tam da bu noktada Errata'da da bahsedilen bir silikon hatası var. DAD bitleri doğru okunamıyor. Ancak errata'da, DAD doğru okunamasa bile yazma işleminin sorunsuz gerçekleşeceği söylenmiş.

Sonuçta bu noktada takıldım kaldım. Aramızda STM32F407'nin USB donanımıyla uğraşmış olanlar vardır diye düşünüyorum. Nereyi gözden kaçırmış olabilirim? İşlemcinin adres değişiminden sonra SETUP paketlerini göz ardı etmesinin sebebi ne olabilir?
Gökçe Tağlıoğlu

devrecii

Hocam böyle bir şeyle neden uğraşıyorsunuz , gençliğinize yazık değil mi? HAL library bende sevmiyorum ama baştan yazmak da nedir  :D

usb 3.0 kontoller  chipler bile aliexprese düşmüş bence uğraşmayın.

Tagli

Sorun çözüldü. Adres atamasını STATUS fazını (onay için gönderilen IN paketi) beklemeden yapmak gerekiyormuş. Aslında işlemci referansında da böyle yazılmış ama bu durum normalde USB spesifikasyonuna aykırı. Ben de referans dokümanında yanlış yazmışlar diye düşünmüştüm. Anlaşılan adres atama emri verildikten sonra (ilgili register'a yazıldıktan sonra), adres değişimi ilk IN paketine (STATUS fazında onay gönderimi yani) ZLP ile cevap verilene kadar donanım tarafından erteleniyor. Neden böyle yapmışlar bilmiyorum. Belki spesifikasyondaki bu ayrıntının gözden kaçacağını düşünerek önlem aldılar, veya uygulama kodunda durum makinesini yazımını kolaylaştırmak istediler. 1 günden fazla zamanımı aldı bu ayrıntı, uykularımı kaçırdı...

HAL'ı sevmesem de USB için kullanmayı ciddi ciddi düşündüm. Ancak bana custom class bir cihaz gerekiyor. HAL sadece HID, MSDC, CDC falan gibi standart uygulamaları destekliyor gibi, ya da ben öyle anladım. Custom class için sadece low level driver'ı üretip bırakıyor. Protokolle ilgili bir şey bulamadım içinde.

Yukarıda bağlantısını verdiğim kütüphaneyi o kadar karmaşık yazmamış olsalardı olduğu gibi kullanacaktım. Ama ileride işin içinden çıkamam diye kendim yazmaya karar verdim.

Şu anda iyi kötü enumeration kısmını atlatıyor gibiyim. Gerçi daha string descriptör desteği ve kendi endpoint'lerimi eklemedim. Yavaş yavaş sistemi oturtacağım artık... Ama gerçekten de USB tam bir ömür törpüsü.

USB 3'e hiç girmek zorunda kalmam umarım. Şu anda Full Speed ile uğraşıyorum. High Speed'den ötesi muhtemelen hiçbir zaman lazım olmayacak.
Gökçe Tağlıoğlu

ahmet35

@Tagli hocam kütüphaneyi yazarken kullandığınız kaynakları paylaşır mısınız?

Tagli

#4
Özel bir kaynak kullanmadım aslında. Faydalandıklarım standart ve bilinen kaynaklar:

1) Resmi USB 2.0 spesifikasyonu (2000 yılından kalma)

2) STM32F407'nin reference manual'i

3) Çok bilinen "USB Complete" kitabı (yazarın adını ezberden yazamayacağım)

4) İlk mesajımda bağlantısını verdiğim kütüphane. Bazı ufak kısımlarını kopyala yapıştır ile doğrudan kullandım.

5) Birkaç web sitesi, daha çok kontrol transferlerini anlamamda faydalı oldular. Telefondan yazdığım için link veremiyorum ama Google aramalarında çıkan (aklımda yanlış kalmadıysa) "beyondlogic" ve "usb made easy" siteleri idi en çok yararlandıklarım.

6) CubeMX'in ürettiği USB LL driver dosyasına da baktım ama pek faydası olmadı şimdilik. Belki gelecekte işime yarar.
Gökçe Tağlıoğlu