2 puan yazan GN⁺ 2024-06-04 | 1 yorum | WhatsApp'ta paylaş
  • İlk kez USB cihazı yaparken gereken akışı fiziksel kablolamadan PCB’ye, USB 2.0 hızlarına, protokol katmanlarına ve STM32 uygulamasına kadar baştan sona izlenebilir şekilde derliyor
  • USB 2.0’ın temel bağlantısı +5V, GND, D+, D- olmak üzere dört hattan oluşur; D+ ve D-, birlikte 1 bit taşıyan diferansiyel bir çifttir
  • PCB’de diferansiyel çiftin uzunluk eşleştirmesi, birbirine yakın yerleştirilmesi ve empedansı önemlidir; ancak 12 Mbit/s full speed prototipler nispeten toleranslı çalışabilir
  • Uygulamada NUCLEO-F103RB üzerinde PA12, USB_DP; PA11, USB_DM olarak ayarlanır; CDC sanal COM portu olarak tanınan bir USB serial cihazı yapılır ve 1 girdisiyle LED yakılır
  • STM32CubeIDE yaklaşımı, UI tabanlı kod üretimi ile boilerplate’in birleşmesi nedeniyle yük getirir; Linux tabanlı USB cihaz uygulamaları ise daha standartlaştırılmış API’ler ve ayrılmış bir yapı sunabilir

USB’yi ilk kez uygularken kapsam

  • Amaç, bilgisayara takıldığında tanınan bir USB cihazını en basit biçimiyle baştan sona yapmaktır
  • Burada cihaz, bilgisayarın işlevlerini genişleten çevre birimi anlamına gelir; bilgisayar ise host olarak adlandırılır
  • Kapsam, USB cihazı ile host arasındaki fiziksel bağlantıdan host üzerinde USB cihazıyla etkileşen basit bir uygulamaya kadar uzanır
  • Yetkin bir şartname açıklamasından çok, en basit uçtan uca USB cihazı yapım projesi ve referans kaynak dizini niteliğindedir

USB’nin temel kavramları

  • USB, çeşitli elektronik cihazlar arasında veri alışverişi ve güç beslemesi sağlayan bir endüstri standardıdır
  • USB bir seri veri yolu olduğu için bitler paralel değil, veri yolu üzerinden tek tek aktarılır
  • Modern veri yolları çoğunlukla seri yapıdadır; USB, host ile device arasında bitlerin seri olarak değiş tokuş edildiği bir yöntem olarak anlaşılabilir
  • USB yalnızca iki cihazı bağlayıp bit alışverişi yapan fiziksel bir standart değil, veri aktarımı ve güç iletimi için iletişim protokollerini de içerir
  • Açıklamanın odağı USB 2.0 üzerindedir

USB kablolaması ve diferansiyel çift

  • Tipik bir USB 2.0 bağlantısı en az dört hatla açıklanır
    • +5 V: host’un device’a güç sağladığı hat
    • D-, D+: birlikte çalışarak 1 bit taşıyan diferansiyel çift
    • GND: toprak
  • Bazı bağlantılarda ID gibi ek pinler olabilir; ancak uygulama yalnızca yukarıdaki dört hattı ele alır
  • USB-C hakkında dikkat edilmesi gerekenler

    • USB-C de içeride diferansiyel çift kullanır; ancak ters yönde takıldığında da çalışması gerekmesi gibi yönlerden genel USB 2.0 açıklamasından ayrılır
    • USB-C konnektörü kullanılması hızın ya da USB sürümünün belirli olduğu anlamına gelmez
    • Bir USB-C cihazı USB 2.0 da olabilir, daha modern bir USB 3.0 cihazı da olabilir
    • Sonraki uygulamada USB-C ayrıca ele alınmaz
  • Diferansiyel çiftin gürültüyü azaltma yöntemi

    • Tek bir hat, gerilimi GND ile karşılaştırarak bit değerini ifade eder; ancak uzun kablolu bağlantılarda gürültü etkisi artabilir
    • Diferansiyel çift iki hat kullanır; bir hat V, diğer hat -V taşır
    • Alıcı taraf iki hat arasındaki gerilim farkına bakar
    • İki hatta da aynı gürültü Vn eklendiği varsayımıyla basitleştirirsek, (V + Vn) - (-V + Vn) = 2V olur ve gürültü iptal edilir
    • Bu model çok basitleştirilmiş bir açıklamadır; diferansiyel çifti daha derinlemesine anlamak için Zach Peterson’ın Altium YouTube videosuna bakılabilir
    • Video 15

PCB’de USB ile çalışırken

  • Doğrudan donanım yapmayıp geliştirme kartı kullanıyorsanız PCB bölümünü atlayabilirsiniz; ancak USB konnektörünü PCB’ye yerleştirirken temel ilkeler faydalıdır
  • USB konnektörü kütüphane bileşenlerinde yukarıda belirtilen pinler bulunur; diferansiyel çiftin de mikrodenetleyici veya SoC üzerindeki ilgili komşu pinlere yönlendirilmesi gerekir
  • Diferansiyel çift yönlendirmesinin üç temel ilkesi vardır
    • D+ hattından çipin plus pinine giden trace ile diğer trace’in uzunluğunu eşitlemek
    • İki trace’i birbirine çok yakın yerleştirmek
    • Sinyale uygun empedansı dikkate almak
  • İki hattın neredeyse aynı ortamdan geçmesini sağladığınız için, önceki basit modelde iki hattaki gürültünün aynı olduğu varsayılabilir
  • Empedans hesabı, üreticinin hesaplayıcısına hedef empedans, ground plane ile mesafe, diferansiyel çift arasındaki mesafe gibi değerler girilerek gerekli trace genişliğini bulma şeklinde ele alınabilir
  • Zach Peterson’ın diferansiyel çift ve USB yönlendirme videoları referans kaynak olarak dahil edilmiştir

USB 2.0 hızları

  • USB 2.0 denildiğinde hız tek bir değere sabitlenmiş olmaz
  • USB 2.0 örneğin iki hız seviyesine sahip olabilir
    • full speed: 12 Mbit/s
    • high speed: 480 Mbit/s
  • Device ve host, bağlantı sırasında hangi hızın kullanılacağına karar vermelidir
  • PCB üzerinde high speed’i kararlı biçimde elde etmek için empedansı eşleştirmek önemlidir
  • Temel prototiplerde 12 Mbit/s full speed yeterli olabilir; USB konnektöründen çipe giden trace’ler kısaysa trace genişliği vb. konularda nispeten toleranslı olunabilir

Protokol ve yazılım katmanları

  • USB yalnızca donanımı değil, host ve device taraflarındaki yazılım katmanlarını da birlikte değerlendirmeyi gerektirir
  • Linux açısından USB’yi anlatan yaklaşık 45 dakikalık bir video önerilen kaynaklar arasındadır
  • Bu video USB frame’lerini, endpoint’leri, configuration’ı ve tek bir device’ın birden fazla USB işlevini nasıl yerine getirebileceğini ele alır
  • USB’yi cihazlardan oluşan bir ağ gibi düşünme bakışı önemlidir
  • Host işletim sisteminin her USB cihazı için ayrı ayrı sürücü uygulaması gerçekçi olmadığından, işletim sistemi çeşitli USB device class’larını tanır
    • mass storage device
    • serial device
    • diğer çeşitli sınıflar
  • Uygulama cihazı, host açısından serial port cihazı olarak çalışır

STM32 ile USB serial port cihazı yapmak

  • Uygulama cihazı, host’tan istek aldığında LED yakan basit bir USB cihazıdır
  • Host bu cihazı serial port device olarak tanır
  • Uygulama yöntemi genel olarak ikiye ayrılır
    • USB destekli mikrodenetleyici kullanmak
    • Linux çalıştırabilen bir SoC kullanıp işlerin çoğunu çekirdeğin halletmesini sağlamak
  • Uygulamada basitlik için mikrodenetleyici yöntemi kullanılır
  • NUCLEO-F103RB kartı

    • Geliştirme kartı olarak NUCLEO-F103RB kullanılır
    • ABD’de Digikey gibi yerlerden 10 doların biraz üzerinde bir fiyata satın alınabilir
    • Bu kart, birbirine bağlı iki bölümden oluşan bir yapıya sahiptir
    • Küçük taraf programmer bölgesi, büyük taraf ise gerçekten programlanacak main MCU bölgesidir
    • Kartın varsayılan USB bağlantısı main MCU’ya değil, programmer tarafındaki MCU’ya bağlıdır
    • Bu programmer, ST-LINK protokolünü kullanarak bilgisayarla USB mesajları alışverişi yapar ve ardından main MCU’yu programlar
    • Doğrudan STM32 tabanlı bir PCB yapıyorsanız karta yalnızca bir çip koyup USB üzerinden programladıktan sonra aynı USB portunu cihaz mantığı için de kullanabilirsiniz
    • STM32 tabanlı PCB ve USB programlama için referans kaynak olarak Phil’s Lab videoları dahil edilmiştir
    • Video 19
    • Video 20

Gerçek USB portunun kablolanması

  • Nucleo kartının varsayılan USB bağlantısı main MCU’ya bağlı olmadığından, main MCU’nun USB portunu doğrudan host’a bağlamak gerekir
  • Programı yükledikten sonra ST-LINK programmer bilgisayardan ayrılır ve main MCU gerçek USB portu üzerinden güç alır
  • Yazılım geliştirmek için STM32CubeIDE, karta yükleme işlemi için STM32CubeProgrammer kullanılır
  • Gerekli pinler ve ayarlar

    • USB 2.0 cihazı yapmak için gereken pinler dörttür
    • host’tan gelen 5V güç
    • GND
    • D+
    • D-
    • NUCLEO-F103RB’de main MCU tarafındaki USB portundan güç almak için JP5 jumper’ı değiştirilerek kartın external 5 V besleme alacak şekilde ayarlanması gerekir
    • STM32CubeIDE’de pinler şu şekilde ayarlanır
    • PA12USB_DP
    • PA11USB_DM
    • Bu karttaki çip, USB bağlantısı için harici 1.5 kΩ pull-up direnci gerektirir
    • Direnç PA12 hattını 3.3V’a pull-up eder
    • Bu devre breadboard üzerinde kurulur
    • MacBook Pro ile tek tek pinleri bağlamak için Amazon’dan bir USB breakout cable kullanılmış; terminal block çıkarılarak USB pinleri açığa çıkarılmış ve jumper wire ile Nucleo kartına ve breadboard’a bağlanmıştır
    • Diferansiyel çift uzunluk eşleştirmesi ve empedans kontrolüne katı biçimde uyulmasa da bu uygulamada 12 Mbit/s bağlantı mümkün olmuştur

USB CDC yazılımının yazılması

  • CubeIDE’de USB pinleri ayarlandığında clock ayarlarıyla ilgili bir bildirim çıkar; CubeIDE’nin bunu otomatik işleyeceği seçenek seçilebilir
  • Pinout & Configuration içindeki Middleware and Software Packs altında USB_DEVICE ayarlanır
  • Uygulamada önemli mod şudur
Communication Device Class (Virtual Port Com)
  • Bu ayarla Nucleo kartı, host açısından CDC serial port cihazı olarak çalışır
  • Host, bu class bilgisine dayanarak custom device ile iletişim kurmak için uygun sürücüyü ayarlayabilir
  • CubeIDE C kodu üretir; main.c içinde şu başlatma çağrısı yer alır
MX_USB_DEVICE_Init();
  • LED’i yakmak için CDC_Receive_FS rutinine şu kod eklenir
/* USER CODE BEGIN 6 */
if (Buf[0] == '1') {
	HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, 1);
}
  • Bu HAL çağrısı, port A’nın pin 5’ine bağlı onboard LED’i yakar
  • Adım adım referans video şöyledir

Flashlama ve çalıştırma

  • ELF dosyası build edildikten sonra CubeProgrammer ile kod karta yüklenir
  • Ardından programmer ayrılır ve kart, yukarıda açıklanan şekilde external 5V besleme kullanılarak kablolanır
  • Kart açıldığında işletim sisteminin device manager’ında COM port veya Serial port benzeri bir öğe olarak görünmelidir
  • CubeIDE’nin USB_DEVICE middleware menüsünde Device Descriptor değerleri değiştirilerek işletim sisteminin device manager’ında gösterilecek custom device name ayarlanabilir
  • Mac OS’te yeni cihaz /dev dosya sistemi altında görünür
    • Örnek yol: /dev/tty.usbmodem497A0F6739561
  • Linux’ta /dev/ttyUSB0 gibi bir adla görünebilir
  • Minicom ile serial device’a bağlanma örneği şöyledir
minicom --device /dev/tty.usbmodem497A0F6739561
  • Bağlandıktan sonra klavyeden 1 girildiğinde Nucleo kartındaki yeşil LED yanar

STM32 yöntemi ile Linux yönteminin yazılım farkları

  • Uygulamanın sonucu, mainstream işletim sistemleri tarafından tanınan bir USB serial port device oluşturmaktır
  • STM32CubeIDE tabanlı yöntemde yazılım mühendisliği açısından rahatsızlıklar vardır
    • UI menülerine tıklayarak çok miktarda boilerplate üretmek gerekir
    • InitUsbDevice(UsbClass.CDC) gibi kod içinde esnek biçimde parametreleştirilmiş bir kütüphane kullanma yaklaşımı değildir
    • Üretilen kod kullanıcı koduyla sıkı biçimde birleştiği için code review zorlaşabilir
    • Yeni sürüm çıktığında boilerplate’in nasıl güncelleneceği net değildir
    • Mevcut ayar STM32 ekosistemine güçlü biçimde bağlıdır
  • Linux’un USB device gibi davranma biçimi daha temiz bir yaklaşım olarak değerlendirilir
    • Linux API’si daha sağlam ve standartlaştırılmıştır
    • pseudo-file ve system call’larla etkileşime dayanabilir
    • user space ile kernel space ayrılmıştır
    • Linux, HAL katmanı gibi görülebilir
  • Ancak hafif, ucuz ve üretimi kolay USB cihazlarına ihtiyaç duyulan durumlarda Linux SoC ağır kalabilir; birçok kullanım senaryosunda gereğinden fazla olabilir
  • Sonuç olarak bare metal USB cihaz geliştirme için daha portable ve daha az opinionated bir framework olsaydı iyi olurdu

1 yorum

 
GN⁺ 2024-06-04
Hacker News yorumları
  • USB’ye giriş yazısı olarak çok iyi, ancak ST mikrodenetleyicileri kullanımına fazlasıyla ağırlık veriyor; güncel ESP32 ekosistemindeki gibi USB aygıtlarını kolayca bağlayıp kullanmaya kıyasla adımlar ve araç zinciri çok daha fazla görünüyor
    Ayrıca diferansiyel çiftler, bizzat birkaç USB kartı yapmış biri olarak, yeni başlayanların çok endişelenmesi gereken bir konu değil; daha çok yüksek hızlı çalışmalarda önem kazanıyor
    Arduino/ESP’de yaygın kullanılan USB denetleyici IC’leri ayrıntıların çoğunu hallettiği için, ilk aygıtını yapan birine hesap yaptırmak biraz fazla geliyor

    • Yakın zamanda ATmega32U4’lü Arduino Pro Micro ile elle kablolanmış bir makro pad yaptım; özel klavye yapma hobisi olanlar arasında epey popüler görünüyor
      Yeni başlayan biri için hızlı ve eğlenceli bir projeydi; en zahmetli kısmı ahşap kasayı oymaktı
    • Diferansiyel çiftler ve empedans konusunda temel bir anlayışın olmasının iyi olduğunu düşünüyorum
      Gerçek hesaplamaları neredeyse hiç yapmadım; kullandığım ECAD yazılımı diferansiyel çift yönlendirme ve empedans sinyal analizi araçları sunuyor
      Yine de izleri çok kısa tutarsanız genellikle büyük bir sorun çıkmaz
    • USB denetleyici IC önerisi almak isterim
      Genelde yalnızca USB yerleşik mikrodenetleyiciler kullandım
  • Uzun zaman önce USB uygunluk testi yapmıştım; sık sorun gördüğüm kalemlerden biri ani akım testiydi
    Temel olarak 5V tarafında çok fazla bypass kapasitörü olması durumuydu; yazıda bu kısmı görmedim sanırım
    Yüksek hızlı dijital tasarıma odaklanmak kolay, ama uygunlukta bazen daha az havalı görünen kısımlar ayağa dolanıyor
    Güncel standartlarda nasıl işlediğini bilmiyorum ama test hâlâ var gibi görünüyor; yazının kendisi iyiydi
    https://compliance.usb.org/index.asp?UpdateFile=Electrical#:...

    • Ani akım sınırlama için hangi bileşenlerin kullanıldığını merak ediyorum
      Birkaç transistörle akım sınırlayıcı yapılabilir ama sıcaklık koruması gibi işlevleri olan daha iyi entegre çözümler var gibi
  • USB-C konusunda yazıya ek olarak, CC pinlerini uygun dirençlere bağlamak gerekir
    Aksi hâlde büyük olasılıkla çalışmaz
    Ayrıca diferansiyel yönlendirme ve empedans USB 2.0’da o kadar büyük mesele değil
    İz uzunluklarını benzer tutmak, makul şekilde doğrudan bağlamak ve mümkünse birbirine yakın tutmak yeterli
    Uzunluk/iz genişliği ince ayarı, empedans kontrolü ve RF en iyi uygulamalarıyla aşırı uğraşmaya gerek yok; netleri bağlayın yeter

    • 480Mbit/s yeterince hızlı olduğu için en iyi uygulamalara ve kabaca %10 içinde empedans eşleşmesine dikkat etmek gerekir
      Birçok MCU’da USB PHY pinleri ile konnektör arasında seri direnç de gerekir
      24mil yerine 20mil iz kullanmanız gerektiği için kartı yeniden yaptırmanız muhtemelen gerekmez; ancak USB 2.0 diferansiyel çift yerleşimi görece düşük stresli olsa da doğru yapmaya çalışmak iyi bir pratik olur
  • ARM işlemciler gibi lehimlemesi zor bileşenlerden endişe ediyorsanız, illa bu kadar büyük parçalar kullanmanız gerekmez
    STM32 performans gerektiğinde iyi, ama küçük işler için daha küçük denetleyiciler daha uygun olabilir
    Örneğin VUSB, küçük Atmel mikrodenetleyicilerde USB’yi bit-banging ile uygulayan bir kütüphanedir: https://www.obdev.at/products/vusb/index.html
    Öğrencilere Linux çekirdek modülü programlamayı öğretirken kullandığım örnek kartın şeması da var: https://gitlab.cs.fau.de/i4/passt/passtboard-v2
    Firmware: http://www.poempelfox.de/ds1820tousb/ ve https://gitlab.cs.fau.de/i4/passt/ds1820tousb
    Arduino tarzı programlamayı tercih ediyorsanız, yalnızca birkaç include kütüphanesi satırıyla USB aygıtı gibi kullanılabilen çok sayıda kart da var; örneğin https://www.az-delivery.de/en/products/digispark-board

    • Lehimleme konusunda endişeniz varsa, mikrodenetleyici USB portu zaten takılı ve çalışır durumda olan geliştirme kartlarını oldukça makul fiyatlara satın alabilirsiniz
      Örneğin NUCLEO-F429ZI var: https://www.st.com/en/evaluation-tools/nucleo-f429zi.html
      Yazarın kullandığı NUCLEO-F103RB’ye çok benziyor, ancak yerleşik programlayıcı/hata ayıklayıcı için üstteki USB konnektörüne ek olarak altta da doğrudan mikrodenetleyiciye bağlı bir USB konnektörü var
      ESD koruması gibi seçimlere bakmak isterseniz kart şemasını da indirebilirsiniz
    • CH32V203 gibi seçenekler de var
      Donanımsal USB içeren TSSOP-20 ve tekil fiyatı yaklaşık 0,81 dolar
      Ancak yazılım tarafı biraz daha zahmetli olabilir
      https://www.wch-ic.com/products/CH32V203.html?
  • MCU üzerinde bare-metal USB kodu yazmayı denedim; SPI veya I2C gibi basit dijital protokollerle karşılaştırınca epey sarsıcıydı.
    Fiziksel katman ve veri bağlantı katmanı CAN’dan çok daha karmaşık sayılmaz, ama hemen ardından descriptor’lar, endpoint’ler ve driver yapılandırması duvarına çarpıyorsunuz.
    USB en başından PC’ler için plug-and-play ekosistemi olarak tasarlanmış ve bu özelliği çok belirgin.
    Mümkünse üreticinin sağladığı yazılımı olabildiğince kullanmak kesinlikle daha iyi bir yol.
    Silik hatırladığım bir ipucu: yüksek throughput için bulk transfer kullanın, isochronous transferlere ise hiç bulaşmayın.
    USB bir master/slave protokolü olduğu için maksimum throughput alınamıyorsa sebep genelde host olan PC tarafındadır.
    Lisansı olan LGPL gereksinimlerinizle uyuyorsa libusb oldukça kullanımı kolay.
    Üretici driver’ını kullanmıyorsanız donanımsal bir USB protokol analizörü gerçekten yararlı olur; USB in a NutShell de protokolü anlamak için iyi bir web kaynağı: https://www.beyondlogic.org/usbnutshell/usb1.shtml

  • STM32’de USB ile uğraşmışken sorayım: tek bir frame’de 64 bayttan fazla almayı nasıl destekleyeceğini bilen var mı?
    Şu anda yazılımda 64 baytlık frame’leri tekrar tekrar işliyorum, ama daha büyüklerinin mümkün olduğunu biliyorum.
    Sanırım en fazla 1 MB’a kadardı.
    Sorun şu ki Reference Manual’da bu ayarlar normal register’lar olarak değil, bir tür sözde register olarak geçiyor.
    Kolay bir workaround var mı merak ediyorum.
    OTG olmayan USB çevre birimi için soruyorum.

    • USB full-speed bulk transfer 64 baytla sınırlıdır.
      Hangi STM32’den bahsettiğini bilmiyorum ama stm32g4 yalnızca full-speed destekliyor.
  • Çoğunlukla ESP32 kullanıyorum, ama birçok projeye uyan ucuz bir hack yöntemi var.
    Çok hızlı ve kolay bir özel controller gerekiyorsa, atılmış bir USB klavyenin kontrol kartını söküp kullanmayı da düşünebilirsiniz.
    Lehim yerine iletken yapıştırıcıyla kontaklara kablo tutturup glue gun ile sağlamca sabitlemek yeterli.
    Spacebar girdisi gönderen, arcade button tabanlı tek düğmeli bir oyun controller’ını ucuza ama oldukça sağlam şekilde yapmıştım; debounce vb. her şey hallediliyor ve kod gerekmiyor.

  • USB 3 destekli geliştirme kartı var mı merak ediyorum.
    Bir USB-C monitör sink’i prototiplemek istiyorum, ama USB üzerinden DisplayPort alabilecek performansta bir kart bulmakta zorlanıyorum.

    • USB üzerinden DisplayPort almak için büyük bir performans gerekmez.
      Zaten DisplayPort sinyalini alabileceğiniz veya harici bir monitöre yönlendirebileceğiniz varsayımıyla tabii.
      Bir USB billboard cihazı implemente edip doğru alternate mode’u sinyallemeniz yeterli.
      Çalışması için aslında opsiyonel, ama hatırladığım kadarıyla spesifikasyon açısından gerekli.
      Böylece USB-C fişinde DisplayPort sinyali çıkar; uygun AUX hatlarını DisplayPort konnektörüne bağlamanız yeterli olur.
    • Böyle bir kart var: https://octopart.com/cyusb3kit-003-cypress+semiconductor-494...
      Fiyatı da makul görünüyor.
      2 yıl önce benzer bir şey aradığımda fiyatı bir basamak daha pahalıydı.
    • Transceiver’ı olan çoğu FPGA ile mümkün.
  • Raspberry Pi’yi PC’ye takılı tutup https://github.com/xairy/raw-gadget ile sanal USB cihazı oluşturuyorum.
    Şimdilik bunu proprietary yazılımı kandırmak için bir MTP kamerayı emüle etmekte kullanıyorum.

  • Raspberry Pi Zero ve Linux kernel’in composite USB özelliğiyle birkaç USB cihazı prototiplemiştim.
    En azından storage ve serial cihazları oldukça kolay çalıştırabildim.
    Raspberry Pi’de composite kernel modülünü başlatan bir shell script gibi bir şeye ihtiyaç var; boilerplate kodu kernel dokümantasyonunda bulabilirsiniz.

    • Pi ile webcam gibi sanal USB cihazı yapmayı denemek istiyorum.
      pikvm de ilginç bir proje.
      PC’ye bağlandığında USB bağlantısı yalnızca klavye ve fare gibi çalışmakla kalmıyor, sistemi boot etmek için kullanılabilecek bir USB drive da olabiliyor.
      Kurulum işleri için epey ilginç bir yöntem.