Project Deck
UYGULAMA RAPORU DONANIM · STM32 · SPI NUCLEO-L432KC 2026

STM32 ile Canon EF
Lens Kontrolü.

NUCLEO-L432KC'yi doğrudan Canon EF lensin mount kontaklarına bağlayarak kamerasız focus ve diyafram kontrolü. 74AHCT125 seviye çevirici, SPI Mode 3, HAL sürücü kodu ve UART komut arayüzü — donanımdan koda eksiksiz rehber.

00 Genel Bakış — STM32, Lens ve Aralarındaki Bağlantı

Canon EF lensler focus ve diyaframlarını 3 sinyal hattı üzerinden elektronik olarak kontrol eder. Bu hatları bir kamera gövdesi yerine STM32 sürdüğünde lens kameradan habersiz olarak tam olarak itaat eder.

Ne yapıyoruz?

STM32, Canon EF mount üzerindeki 3 sinyal hattına (Dclk · Dout · Din) doğrudan bağlanır ve SPI Master olarak çalışır. PC'den UART üzerinden gönderilen komutlar (ör. f+ 200, a 5.6) STM32 tarafından Canon EF byte dizilerine çevrilip lense iletilir.

  ┌─────────────────────────────────────────────────────────────────┐
  │                     Genel sistem akışı                          │
  └─────────────────────────────────────────────────────────────────┘

  PC / Terminal                                        Canon EF Lens
  (PuTTY, minicom)                                    (herhangi EF/EF-S)
       │                                                      │
       │  USB — ST-Link VCP                                   │
       │  115200 baud                                         │
       ▼                                                      │
  ┌────────────────────────────────────────┐                  │
  │         NUCLEO-L432KC                  │                  │
  │                                        │                  │
  │  USART2 ──► CLI parser                 │                  │
  │                │                       │                  │
  │                ▼                       │                  │
  │           ef_lens.c                   │  3 sinyal hattı  │
  │                │                       │  (5 V CMOS)      │
  │                ▼                       │                  │
  │           SPI1 Master ────────────────►├── Dclk ─────────►│
  │                                        ├── Dout ─────────►│
  │                                        │◄─ Din  ──────────│
  │                                        │                  │
  │  VBUS (5 V) ──────────────────────────►├── VDD  ─────────►│
  │  Boost (6 V) ─────────────────────────►├── VBAT ─────────►│
  │  GND ─────────────────────────────────►├── GND  ─────────►│
  └────────────────────────────────────────┘                  │
                                                              │

Kamera gerekmez

STM32 lensin bakış açısından tam olarak bir Canon kamera gövdesidir: clock'u o üretir, komutları o gönderir, yanıtları o okur. Lens bu ayrımı yapamaz.

Bu rapordaki dosyalar

DosyaRol
Core/Inc/ef_lens.hEF protokol sabitleri, struct tanımları, fonksiyon prototipleri
Core/Src/ef_lens.cSPI transaction motoru, tüm EF komut implementasyonları
Core/Src/main.cUART CLI döngüsü, printf yönlendirmesi
*.iocCubeMX: SPI1 Mode 3, USART2, 80 MHz PLL

01 Canon EF Mount Pinout — 7 Kontak, Voltajlar, Fiziksel Konum

Canon EF-S mount lensin arkasında 7 altın kaplama kontak bulunur: iki güç hattı, iki toprak ve üç sinyal hattı. Kamera cephesinden bakışta soldan sağa sıralanır: Vbat · A_GND · VDD · Dout · Din · Dclk · D_GND.

Resmi pinout diyagramı

Canon EF-S mount kontak pinout — kamera cephesinden görünüm
Canon EF-S mount kontak düzeni — kamera cephesinden (face) görünüm

Kontak sırası (kamera cephesinden, soldan sağa)

  Kamera cephesinden görünüm — lensin arka yüzüne bakış:

    ╔═══════════════════════════════════════════════════════╗
    ║                                                       ║
    ║   ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐
    ║   │Vbat │ │A_GND│ │ VDD │ │Dout │ │ Din │ │Dclk │ │D_GND│
    ║   └─────┘ └─────┘ └─────┘ └─────┘ └─────┘ └─────┘ └─────┘
    ║
    ╚═══════════════════════════════════════════════════════╝

   Vbat:  ~6 V  Motor güç                A_GND: 0 V  Motor toprağı
   VDD:    5 V  Mantık beslemesi         D_GND: 0 V  Dijital toprak
   Dout:   5 V  STM32 → Lens  (MOSI)    Din:   5 V  Lens → STM32 (MISO)
   Dclk:   5 V  STM32 → Lens  (SCK)

Pin tablosu

KontakSinyalVoltajYönİşlev
1Vbat~6 V STM32 → Lens Focus motor güç kaynağı (Focusing Motor Power). USM / STM motorlar bu hattan beslenir. MT3608 boost converter veya 4×AA pil.
2A_GND0 V Motor toprağı (Motor Ground). Vbat geri dönüş hattı. STM32 GND'ye bağlanır.
3VDD5 V STM32 → Lens Lens dijital güç (Lens Digital Power). Lens MCU ve sinyal devresi beslemesi. USB VBUS doğrudan kullanılabilir.
4Dout5 V CMOS STM32 → Lens SPI Data Camera Output — kamera/STM32'nin lense gönderdiği veri (MOSI). Komut byte'ları bu hattan gönderilir.
5Din5 V CMOS Lens → STM32 SPI Data Camera Input — lensin kameraya/STM32'ye gönderdiği yanıt (MISO). Lens yanıtları bu hattan okunur.
6Dclk5 V CMOS STM32 → Lens SPI Clock and signalisation — senkron seri saat. STM32 üretir, lens alır. Idle HIGH (SPI Mode 3).
7D_GND0 V Dijital sinyal toprağı (Lens Digital Ground). A_GND'den bağımsız, gürültü yalıtımı için ayrı tutulur.
VOLTAJ ÖZETİ

VDD = 5 V (mantık), Vbat = 6 V (motor), sinyal hatları (Dout · Din · Dclk) = 5 V CMOS. STM32L432KC 3.3 V çıkışı üretir; Dout ve Dclk için 74AHCT125 seviye çevirici, Vbat için 6 V boost converter veya 4×AA pil gerekir.

Konektör seçenekleri

EF uzatma tüpüAliexpress "Canon EF extension tube" — plastik halkaya kontak pimler yerleşiktir, üzerine ince kablo lehimlenir. En pratik yöntem, ~80–150 ₺.
EF PCB konektörüAliexpress "Canon EF mount electrical contact board" — pad'lere direkt lehimlenebilir. En temiz çözüm, ~150–200 ₺.
Kırık body capCanon EF body kapağının kontak şeridi dremel ile çıkarılır, kablolar lehimlenir. Ücretsiz ama hassas çalışma gerektirir.
RF MOUNT UYARISI

Canon RF mount (EOS R serisi) tamamen farklı protokol kullanır: farklı pin sayısı, farklı voltajlar, farklı komut seti. EF-M mount da farklıdır. Bu rehber yalnızca klasik EF ve EF-S lenslere uygulanır.

02 NUCLEO-L432KC Pin Haritası — Hangi Pin Nereye?

NUCLEO-L432KC, Arduino Nano uyumlu başlık pinlerine sahip küçük bir geliştirme kartıdır. SPI1 çevrimi PA5/PA6/PA7 pinlerine, USART2 ise PA2/PA3 pinlerine yönlendirilmiştir.

NUCLEO-L432KC kart düzeni

                   NUCLEO-L432KC
              ┌──────────────────────┐
    USB/ST-Link│  ┌──────────────┐   │
    (VCP+güç) ─┤  │  STM32L432KC │   │
              │  └──────────────┘   │
              │                      │
     CN3 (sol)│                      │CN4 (sağ)
    ═══════════                      ════════════
    D1  PA2 TX│                      │PA5  D13  SCK  ← SPI1_SCK  → Dclk
    D0  PA3 RX│                      │PA6  D12  MISO ← SPI1_MISO ← Din
        PA4   │                      │PA7  D11  MOSI ← SPI1_MOSI → Dout
        PB0   │                      │PB0  D10  (CS — kullanılmaz)
        PB7   │                      │
        PB6   │                      │
    5V  VBUS──┤                      ├── 5V (VDD'ye)
    GND       │                      ├── GND
    3V3       │                      │
              └──────────────────────┘

  PA2 (TX) → ST-Link → USB → PC terminal (115200 baud)
  PA3 (RX) → ST-Link → USB → PC terminal

SPI1 pin ataması

STM32 PinArduino EtiketiSPI FonksiyonuCanon EF SinyaliKontak #
PA5D13SPI1_SCKDclk (saat)6
PA7D11SPI1_MOSIDout (veri: STM32→lens)4
PA6D12SPI1_MISODin (veri: lens→STM32)5

Güç pinleri

NUCLEO PinVoltajCanon EF PinSinyal
5V (VBUS)5 VKontak 3VDD (mantık beslemesi)
Boost çıkışı6 VKontak 1Vbat (motor beslemesi)
GND0 VKontak 2A_GND (motor toprağı)
GND0 VKontak 7D_GND (sinyal toprağı)
FT PİN — PA6 (MISO)

STM32L432KC veri sayfasına göre PA6 FT (Five-Volt Tolerant) giriş pinidir. Lens'ten gelen 5 V Din sinyalini doğrudan alabilir. Buna rağmen voltaj bölücü kullanmak MCU ömrü açısından iyi bir pratiktir.

03 Devre Şeması — 74AHCT125, Voltaj Bölücü ve 6 V Güç Kaynağı

STM32 3.3 V GPIO çıkışı üretir; Canon EF mount 5 V CMOS seviyesi bekler. Dout ve Dclk çıkış hatları için 74AHCT125 seviye çevirici, Din giriş hattı için voltaj bölücü ve lens motoru için 6 V kaynak gereklidir.

Neden seviye çevirici?

STM32 GPIO çıkışıHer zaman 3.3 V. PA5 ve PA7 çıkış pinleridir; FT olsalar bile çıkış voltajları 3.3 V'tur.
Canon EF giriş eşiği5 V CMOS: yüksek seviye eşiği ≥ 3.5 V. 3.3 V bu eşiği güvenli şekilde geçemez — lens Dclk ve Dout'u doğru okuyamayabilir.
Çözüm74AHCT125: 3.3 V girişi alıp 5 V çıkış verir. VCC = 5 V olduğunda AHCT serisi 3.3 V'u HIGH olarak kabul eder, 5 V çıkışı garantiler.

74AHCT125 — devre bağlantısı

  74AHCT125 (DIP-14 veya SOIC-14) iç yapısı:
  Her kapı: 1 giriş (nA) + 1 output enable (nOE, active LOW) + 1 çıkış (nY)

   ┌─────────────────────────────────────┐
   │           74AHCT125                 │
   │                                     │
   │  VCC ── 14 (5V bağlanır)           │
   │  GND ──  7                          │
   │                                     │
   │  1OE ──  1 → GND (her zaman aktif) │
   │  1A  ──  2 ← PA5  (SCK,  3.3V)    │
   │  1Y  ──  3 → Dclk (Canon kontak 6) │ → 5V çıkış
   │                                     │
   │  2OE ──  4 → GND (her zaman aktif) │
   │  2A  ──  5 ← PA7  (MOSI, 3.3V)    │
   │  2Y  ──  6 → Dout (Canon kontak 4) │ → 5V çıkış
   │                                     │
   │  3A, 3OE, 3Y, 4A, 4OE, 4Y:        │
   │    kullanılmaz (bağlama veya float) │
   └─────────────────────────────────────┘

  Din → PA6 (MISO) için voltaj bölücü:

  Canon kontak 5 (Din, 5V)
          │
         10 kΩ
          │
          ├──────── PA6 (MISO, 3.3V max input)
          │
         20 kΩ
          │
         GND

  Bölücü çıkışı = 5V × 20/(10+20) = 3.33 V ✓

6 V motor güç kaynağı (VBAT)

USB VBUS 5 V verir; lens USM motoru için 6 V gerekir. Düşük voltajda motor yeterli tork üretemez, odak atlar veya hiç hareket etmez.

YöntemMaliyetNotlar
MT3608 boost modülü~20 ₺USB 5V → ayarlanabilir boost. Trimpotu çevirerek tam 6.00 V'a getir. Aliexpress: "MT3608 step up module". En pratik çözüm.
4 × AA alkalin pil~15 ₺Yeni pilde 6.4 V, kullanıldıkça düşer. Prototip için yeterli ama düzensiz voltaj.
IP2312 + Li-Ion 2S~80 ₺Şarj edilebilir, sabit voltaj. Taşınabilir setup için ideal.
MT3608 AYARI

MT3608'in çıkışına multimetre bağla, trimpotu yavaşça saat yönünde çevir. Tam olarak 6.00 V'ta durdur. 6.5 V üzeri lens motor sürücüsüne kalıcı hasar verebilir.

Tam bağlantı şeması

  NUCLEO-L432KC                74AHCT125           Canon EF Mount
  ─────────────                ─────────           ──────────────

  PA5 (D13, SCK ) ────────────► 1A → 1Y ──────────► kontak 6  Dclk
  PA7 (D11, MOSI) ────────────► 2A → 2Y ──────────► kontak 4  Dout
  PA6 (D12, MISO) ◄──[10k+20k]───────────────────── kontak 5  Din
                                      ▲
                       VCC(5V)────────┘ (74AHCT125 VCC)

  5V  (VBUS) ──────────────────────────────────────► kontak 3  VDD
  MT3608 (6V) ─────────────────────────────────────► kontak 1  Vbat
  GND ─────────────────────────────────────────────► kontak 2  A_GND
  GND ─────────────────────────────────────────────► kontak 7  D_GND

  Güç sırası: VDD (5V) önce → Vbat (6V) sonra
GÜÇ SIRASI

Canon lenslerin büyük çoğunluğu VDD'nin önce gelmesini bekler: önce 5 V mantık gerilimi, ardından 6 V motor gerilimi. Ters sıra lens firmware'ini undefined state'e sokabilir. Pratik uygulama: VBUS (VDD) her zaman açık, VBAT hattına küçük bir anahtar veya jumper koy.

04 SPI Mode 3 — Neden Bu Ayarlar, Nasıl Çalışır?

Canon EF low-side protokolü elektriksel olarak tam olarak SPI Mode 3'tür: clock idle HIGH, veriler clock'un yükselen kenarında örneklenir. Chip select yoktur, yarı-çift yönlü akış STM32'nin full-duplex SPI'ı ile yönetilir.

SPI mod matrisi

ModCPOLCPHAClock idleÖrnekleme
000LOWYükselen kenar
101LOWDüşen kenar
210HIGHDüşen kenar
311HIGHYükselen kenar

Canon EF: Dclk idle HIGH → CPOL=1. Veri yükselen kenarda latçlanır → CPHA=1. Sonuç: Mode 3.

Zamanlama diyagramı

  Örnek — 0xEB baytının iletimi (lens ID, binary: 1110 1011)

        İşlem:    7    6    5    4    3    2    1    0
                  MSB                            LSB

  Dclk  ‾‾‾‾‾|___|‾|___|‾|___|‾|___|‾|___|‾|___|‾|___|‾|___|‾‾‾‾‾
              ↑                                             ↑
           idle HIGH                                    idle HIGH

  Dout  ─────╔═══╗ ╔═══╗ ╔═══╗ ╔═══╗ ╔═══╗ ╔╗  ╔═══╗ ╔═══╗─────
  (MOSI)     ║ 1 ║ ║ 1 ║ ║ 1 ║ ║ 0 ║ ║ 1 ║ ║0║ ║ 1 ║ ║ 1 ║
             ╚═══╝ ╚═══╝ ╚═══╝ ╚═══╝ ╚═══╝ ╚╝  ╚═══╝ ╚═══╝

  Din   ─────╔════════════════════════════════════════════╗────
  (MISO)     ║  lens yanıtı (önceki komutun sonucu)       ║
             ╚════════════════════════════════════════════╝

              ↑ Her bit Dclk düşen kenarda değişir,
                yükselen kenarda örneklenir (CPHA=1) 

Saat frekansı

STM32L432KC @ 80 MHz. Canon EF tolerans bandı: 62.5 – 125 kHz.

  SPI1 prescaler seçenekleri (80 MHz PCLK):

  Prescaler │ Frekans    │ Canon EF uyumu
  ──────────┼────────────┼──────────────────
      256   │  312.5 kHz │ ✗  Çok hızlı
      512   │  156.3 kHz │ ✗  Sınırın üstünde
     1024   │   78.1 kHz │ ✓  Tam ortada ← SEÇ
     2048   │   39.1 kHz │ ✗  Gereksiz yavaş

Chip select yok

Canon EF'de CS (chip select / NSS) yoktur. STM32 SPI1'de NSS Software moduna alınır ve hiçbir pin CS olarak atanmaz. Clock yükselince lens transaction başladığını anlar, idle HIGH'a dönünce biter.

Half-duplex yönetimi

Canon EF fiziksel olarak half-duplex gibi davranır: komut gönderirken lens susarken, yanıt alırken STM32 anlamlı veri göndermez. STM32 SPI1 full-duplex modunda çalışır; bu fark şöyle yönetilir:

Komut göndermeMOSI'dan gerçek byte'lar gönderilir. Aynı anda MISO'dan gelen veriler dummy tampona alınır, yok sayılır.
Yanıt okumaMOSI'dan 0x00 dummy byte'lar gönderilir — yalnızca Dclk üretmek için. MISO'dan lens yanıtı okunur.
Byte arası gecikmeLens MCU her byte'ı işlemek için 5–15 µs'ye ihtiyaç duyar. Her byte arasına ~5 µs gecikme eklenir.

05 CubeMX Konfigürasyonu — SPI1, USART2 ve Saat Ağacı

STM32CubeMX ile çevre birimi yapılandırması yapılır, HAL başlatma kodu üretilir. Board seçimi: NUCLEO-L432KC.

1 — Saat ağacı: 80 MHz

Clock Configuration
PLL Source  : HSI (16 MHz)
PLL/M       : 1   → 16 MHz
PLL/N       : ×10 → 160 MHz
PLL/R       : /2  → 80 MHz
SYSCLK      : 80 MHz
AHB Prescaler  : /1 → HCLK  = 80 MHz
APB1 Prescaler : /1 → PCLK1 = 80 MHz  ← SPI1 buradan beslenecek
APB2 Prescaler : /1 → PCLK2 = 80 MHz

2 — SPI1 ayarları

ModeFull-Duplex Master
Hardware NSS SignalDisable — Canon EF'de CS yoktur
Frame FormatMotorola
Data Size8 Bits
First BitMSB First
Clock Polarity (CPOL)High
Clock Phase (CPHA)2 Edge ← CPOL=1 + CPHA=1 = Mode 3
Prescaler1024 → 78.125 kHz
CRC CalculationDisabled

3 — USART2 ayarları

ModeAsynchronous
Baud Rate115200
Word Length8 Bits
ParityNone
Stop Bits1
PinlerPA2 = TX (ST-Link'e), PA3 = RX (ST-Link'ten) — otomatik atanır

4 — Üretilen başlatma kodu

main.c — MX_SPI1_Init() (CubeMX üretimi)
static void MX_SPI1_Init(void)
{
    hspi1.Instance               = SPI1;
    hspi1.Init.Mode              = SPI_MODE_MASTER;
    hspi1.Init.Direction         = SPI_DIRECTION_2LINES;   /* full-duplex */
    hspi1.Init.DataSize          = SPI_DATASIZE_8BIT;
    hspi1.Init.CLKPolarity       = SPI_POLARITY_HIGH;      /* CPOL = 1 */
    hspi1.Init.CLKPhase          = SPI_PHASE_2EDGE;        /* CPHA = 1 → Mode 3 */
    hspi1.Init.NSS               = SPI_NSS_SOFT;           /* CS yok */
    hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_1024; /* 78.125 kHz */
    hspi1.Init.FirstBit          = SPI_FIRSTBIT_MSB;
    hspi1.Init.TIMode            = SPI_TIMODE_DISABLE;
    hspi1.Init.CRCCalculation    = SPI_CRCCALCULATION_DISABLE;
    HAL_SPI_Init(&hspi1);
}
KAYAN NOKTA printf

Diyafram değerlerini yazdırmak için (f/%.1f) kayan nokta printf desteği gerekir. CubeMX Project Manager → Advanced Settings → "Use float with printf from newlib-nano" kutusunu işaretle. Yoksa diyafram çıktıları boş gelir.

06 Canon EF Protokolü — Komut Formatı ve Bilinen Byte Dizileri

Canon EF low-side protokolü resmi olarak belgelenmemiştir. Buradaki komutlar Magic Lantern, OpenEF ve çeşitli topluluk RE projelerinden derlenen kamuya açık bilgiye dayanır. Standart EF/EF-S lenslerin büyük çoğunluğunda çalışır.

Transaction yapısı

  Her Canon EF işlemi şu sırayı izler:

  ① STM32 → Lens : komut byte'ı gönderilir  (Dout hattı, 1 byte)
  ② 5–20 µs beklenir                         (lens MCU işleme süresi)
  ③ STM32 → Lens : varsa parametre byte'ları  (yine Dout, N byte)
  ④ 20 µs beklenir
  ⑤ Lens → STM32 : yanıt byte'ları okunur    (Din hattı, M byte)
                   (STM32 dummy 0x00 gönderir, Dclk üretmek için)
  ⑥ ≥ 1 ms beklenir → sonraki transaction

Komut tablosu

ByteKomutParametreYanıtAçıklama
0x0AINIT8–16 byteLens başlatma. Lens ID, tip bayrakları, diyafram aralığı, focal length.
0x0DSTATUS4 byteAnlık durum: motor hareketli mi, encoder pozisyonu.
0x44FOCUS MOVEyön + hız + 2× adım1 byte ACKFocus motoru belirli adım hareket ettir.
0x06FOCUS STOP1 byte ACKHareket eden focus motorunu durdur.
0xA0FOCUS INF1 byte ACKFocus motorunu sonsuz yönünde tam hızda çalıştır.
0xB0FOCUS NEAR1 byte ACKFocus motorunu minimum yönünde tam hızda çalıştır.
0x13APERTUREAv × 8 (1 byte)1 byte ACKDiyafram bıçaklarını ayarla.
0x72APERTURE OPEN1 byte ACKDiyaframı tam açık konuma getir.

FOCUS MOVE byte formatı

  Gönderilen 5 byte:

  ┌────────┬────────┬────────┬────────┬────────┐
  │  0x44  │  yön   │  hız   │ adım H │ adım L │
  └────────┴────────┴────────┴────────┴────────┘
     komut   0=yakın  1=yavaş  16-bit adım sayısı
             1=uzak   4=hızlı  MSB önce

  Örnek — 300 adım uzağa, hız 2:
  0x44  0x01  0x02  0x01  0x2C

INIT yanıt formatı ve decode

  0x0A komutuna gelen 8 byte yanıt (EF v1 standart lensler):

  ┌──────┬──────┬────────┬────────┬──────┬──────┬──────┬──────┐
  │ [0]  │ [1]  │  [2]   │  [3]   │ [4]  │ [5]  │ [6]  │ [7]  │
  │ tip  │ lens │ Ap_max │ Ap_min │  FL  │  FL  │  ?   │  ?   │
  │bayrak│  ID  │ (Av×8) │ (Av×8) │  lo  │  hi  │      │      │
  └──────┴──────┴────────┴────────┴──────┴──────┴──────┴──────┘

  Tip bayrağı [0] bitleri:
    bit 1 → USM motor (1 = var)
    bit 2 → IS (image stabilizer, 1 = var)
    bit 3 → Full-time manual focus (1 = var)

  Av × 8 → f-stop: fstop = 2^(Av/2)
    0x08 = 8  → Av=1.0 → f/1.4
    0x20 = 32 → Av=4.0 → f/4.0
    0x30 = 48 → Av=6.0 → f/8.0
    0x48 = 72 → Av=9.0 → f/22.6

  Örnek — Canon EF 50mm f/1.4 USM yanıtı:
  02  EB  08  60  32  00  00  00
  ↑   ↑   ↑   ↑   ↑
  │   │   │   │   └── 0x32 = 50 → 50mm ✓
  │   │   │   └────── 0x60 = 96 → Av=12 → f/22.6 ✓
  │   │   └────────── 0x08 = 8  → Av=1  → f/1.4  ✓
  │   └────────────── 0xEB = lens ID
  └────────────────── 0x02 = USM var, IS yok

Diyafram Av kodlaması

f-stopAvWire byte (Av × 8)Hex
f/1.41.080x08
f/2.02.0160x10
f/2.83.0240x18
f/4.04.0320x20
f/5.65.0400x28
f/8.06.0480x30
f/11.07.0560x38
f/16.08.0640x40
f/22.09.0720x48

07 ef_lens Sürücü Katmanı — Tam C Kodu

Tüm Canon EF protokol mantığı iki dosyada toplanır. Transaction motoru her byte gönderimini bireysel olarak yönetir; byte'lar arası DWT tabanlı µs gecikme lens MCU'nun işleme süresini garanti altına alır.

ef_lens.h

Core/Inc/ef_lens.h
#ifndef EF_LENS_H
#define EF_LENS_H

#include "main.h"
#include <stdint.h>
#include <stdbool.h>

/* ── Komut byte'ları ──────────────────────────────────────────── */
#define EF_CMD_INIT          0x0A
#define EF_CMD_STATUS        0x0D
#define EF_CMD_FOCUS_MOVE    0x44
#define EF_CMD_FOCUS_STOP    0x06
#define EF_CMD_FOCUS_INF     0xA0
#define EF_CMD_FOCUS_NEAR    0xB0
#define EF_CMD_APERTURE      0x13
#define EF_CMD_APERTURE_OPEN 0x72

/* ── Focus yön sabitleri ──────────────────────────────────────── */
#define EF_DIR_NEAR  0x00
#define EF_DIR_FAR   0x01

/* ── Lens bilgi yapısı ────────────────────────────────────────── */
typedef struct {
    uint8_t  lens_id;
    uint8_t  type_flags;
    float    aperture_max;     /* f-stop, ör. 1.4 */
    float    aperture_min;     /* f-stop, ör. 22.6 */
    uint16_t focal_length_mm;
    bool     has_usm;
    bool     has_is;
    uint8_t  raw[16];          /* ham INIT yanıtı */
} ef_lens_info_t;

/* ── API ──────────────────────────────────────────────────────── */
HAL_StatusTypeDef ef_init(SPI_HandleTypeDef *hspi);
HAL_StatusTypeDef ef_get_info(ef_lens_info_t *out);
HAL_StatusTypeDef ef_focus_move(uint8_t dir, uint8_t speed, uint16_t steps);
HAL_StatusTypeDef ef_focus_stop(void);
HAL_StatusTypeDef ef_focus_inf(void);
HAL_StatusTypeDef ef_focus_near(void);
HAL_StatusTypeDef ef_aperture_set(float fstop);
HAL_StatusTypeDef ef_aperture_open(void);
HAL_StatusTypeDef ef_status_read(uint8_t *buf, uint8_t len);

#endif

ef_lens.c — transaction motoru

Core/Src/ef_lens.c — DWT + transaction katmanı
#include "ef_lens.h"
#include <math.h>
#include <string.h>

static SPI_HandleTypeDef *_spi;

/* ── µs gecikmesi (DWT cycle counter) ────────────────────────── */
static void dwt_enable(void)
{
    CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
    DWT->CYCCNT = 0;
    DWT->CTRL  |= DWT_CTRL_CYCCNTENA_Msk;
}

static void delay_us(uint32_t us)
{
    uint32_t start = DWT->CYCCNT;
    uint32_t ticks = us * (SystemCoreClock / 1000000UL);
    while ((DWT->CYCCNT - start) < ticks);
}

/*
 * ef_send — tek byte gönder, dummy byte al (yanıt yok sayılır)
 * ef_recv — dummy byte gönder (Dclk üret), yanıt byte'ı al
 */
static HAL_StatusTypeDef ef_send(uint8_t b)
{
    uint8_t dummy;
    return HAL_SPI_TransmitReceive(_spi, &b, &dummy, 1, 10);
}

static HAL_StatusTypeDef ef_recv(uint8_t *b)
{
    uint8_t zero = 0x00;
    return HAL_SPI_TransmitReceive(_spi, &zero, b, 1, 10);
}

/*
 * ef_cmd — genel transaction:
 *   komut gönder → parametre gönder → yanıt al
 *   Her byte arasına 5 µs, komut/yanıt arasına 20 µs eklenir.
 */
static HAL_StatusTypeDef ef_cmd(uint8_t cmd,
                                   const uint8_t *params, uint8_t plen,
                                   uint8_t *rx,          uint8_t rlen)
{
    HAL_StatusTypeDef ret;

    ret = ef_send(cmd);
    if (ret != HAL_OK) return ret;

    for (uint8_t i = 0; i < plen; i++) {
        delay_us(5);
        ret = ef_send(params[i]);
        if (ret != HAL_OK) return ret;
    }

    delay_us(20);

    for (uint8_t i = 0; i < rlen; i++) {
        ret = ef_recv(&rx[i]);
        if (ret != HAL_OK) return ret;
        delay_us(5);
    }

    HAL_Delay(1);  /* transaction bitiş boşluğu */
    return HAL_OK;
}

ef_lens.c — yüksek seviye komutlar

Core/Src/ef_lens.c — init, bilgi, focus, diyafram
HAL_StatusTypeDef ef_init(SPI_HandleTypeDef *hspi)
{
    _spi = hspi;
    dwt_enable();

    /*
     * Lens güç aldıktan sonra MCU'sunun boot etmesi için bekle.
     * USM serisi ~500 ms, STM serisi ~200 ms.
     * 600 ms tüm EF/EF-S lenslerde güvenlidir.
     */
    HAL_Delay(600);

    uint8_t rx[8];
    return ef_cmd(EF_CMD_INIT, NULL, 0, rx, 8);
}

HAL_StatusTypeDef ef_get_info(ef_lens_info_t *out)
{
    uint8_t rx[16] = {0};
    HAL_StatusTypeDef ret = ef_cmd(EF_CMD_INIT, NULL, 0, rx, 16);
    if (ret != HAL_OK) return ret;

    memcpy(out->raw, rx, 16);
    out->type_flags      = rx[0];
    out->lens_id         = rx[1];
    out->focal_length_mm = (uint16_t)rx[4] | ((uint16_t)rx[5] << 8);
    out->has_usm         = (rx[0] & 0x02) != 0;
    out->has_is          = (rx[0] & 0x04) != 0;

    /* Av × 8 → f-stop: fstop = 2^(Av/2) */
    out->aperture_max = powf(2.0f, (rx[2] / 8.0f) / 2.0f);
    out->aperture_min = powf(2.0f, (rx[3] / 8.0f) / 2.0f);

    return HAL_OK;
}

HAL_StatusTypeDef ef_focus_move(uint8_t dir, uint8_t speed, uint16_t steps)
{
    uint8_t p[4] = { dir, speed,
                     (uint8_t)(steps >> 8),
                     (uint8_t)(steps & 0xFF) };
    uint8_t rx[1];
    return ef_cmd(EF_CMD_FOCUS_MOVE, p, 4, rx, 1);
}

HAL_StatusTypeDef ef_focus_stop(void)
{
    uint8_t rx[1];
    return ef_cmd(EF_CMD_FOCUS_STOP, NULL, 0, rx, 1);
}

HAL_StatusTypeDef ef_focus_inf(void)
{
    uint8_t rx[1];
    return ef_cmd(EF_CMD_FOCUS_INF, NULL, 0, rx, 1);
}

HAL_StatusTypeDef ef_focus_near(void)
{
    uint8_t rx[1];
    return ef_cmd(EF_CMD_FOCUS_NEAR, NULL, 0, rx, 1);
}

HAL_StatusTypeDef ef_aperture_set(float fstop)
{
    /*
     * f-stop → Av → wire byte:
     *   Av   = 2 × log2(fstop)
     *   wire = round(Av × 8)
     *
     *   f/1.4 → wire = 8
     *   f/5.6 → wire = 40
     *   f/16  → wire = 64
     */
    float   av   = 2.0f * (logf(fstop) / logf(2.0f));
    uint8_t wire = (uint8_t)(av * 8.0f + 0.5f);

    uint8_t p[1] = { wire };
    uint8_t rx[1];
    HAL_StatusTypeDef ret = ef_cmd(EF_CMD_APERTURE, p, 1, rx, 1);
    if (ret != HAL_OK) return ret;

    HAL_Delay(80);  /* diyafram bıçakları kapanana kadar bekle */
    return HAL_OK;
}

HAL_StatusTypeDef ef_aperture_open(void)
{
    uint8_t rx[1];
    return ef_cmd(EF_CMD_APERTURE_OPEN, NULL, 0, rx, 1);
}

HAL_StatusTypeDef ef_status_read(uint8_t *buf, uint8_t len)
{
    if (len > 32) len = 32;
    return ef_cmd(EF_CMD_STATUS, NULL, 0, buf, len);
}

08 UART Komut Arayüzü — Seri Konsoldan Lens Kontrolü

USART2, ST-Link virtual COM port üzerinden PC'ye bağlıdır. PuTTY, minicom veya herhangi bir terminal programıyla 115200 baud bağlanıp komut gönderilebilir.

printf yönlendirmesi

Core/Src/main.c — newlib hook
/* Bu fonksiyon syscalls.c içine veya doğrudan main.c'ye yazılabilir */
int __io_putchar(int ch)
{
    HAL_UART_Transmit(&huart2, (uint8_t *)&ch, 1, 10);
    return ch;
}

static void uprint(const char *s)
{
    HAL_UART_Transmit(&huart2, (const uint8_t *)s, strlen(s), 200);
}

CLI ana döngüsü

Core/Src/main.c — process_cmd() ve app_main()
static char    rx_buf[64];
static uint8_t rx_idx = 0;

static void process_cmd(char *line)
{
    char *tok = strtok(line, " \r\n");
    if (!tok) return;

    if (strcmp(tok, "?") == 0 || strcmp(tok, "h") == 0) {
        uprint("\r\n--- Canon EF Lens Kontrolu ---\r\n");
        uprint("info          : Lens bilgisi\r\n");
        uprint("fi            : Focus sonsuza\r\n");
        uprint("fn            : Focus minimuma\r\n");
        uprint("f+ <n> [hiz] : N adim uzaga (hiz 1-4)\r\n");
        uprint("f- <n> [hiz] : N adim yakina\r\n");
        uprint("fs            : Motoru durdur\r\n");
        uprint("a <fstop>    : Diyafram ayarla (a 5.6)\r\n");
        uprint("ao            : Diyafram tam ac\r\n");
        uprint("st [n]        : Ham durum (n byte)\r\n");
        uprint("------------------------------\r\n");

    } else if (strcmp(tok, "info") == 0) {
        ef_lens_info_t info = {0};
        if (ef_get_info(&info) == HAL_OK) {
            printf("Lens ID   : 0x%02X\r\n",  info.lens_id);
            printf("Focal len : %d mm\r\n",    info.focal_length_mm);
            printf("Diyafram  : f/%.1f - f/%.1f\r\n",
                   info.aperture_max, info.aperture_min);
            printf("USM: %s  IS: %s\r\n",
                   info.has_usm ? "EVET" : "HAYIR",
                   info.has_is  ? "EVET" : "HAYIR");
            uprint("Ham yanit : ");
            for (int i = 0; i < 8; i++)
                printf("%02X ", info.raw[i]);
            uprint("\r\n");
        } else {
            uprint("HATA: lens yanit vermedi\r\n");
        }

    } else if (strcmp(tok, "fi") == 0) {
        ef_focus_inf();
        uprint("Focus → sonsuz\r\n");

    } else if (strcmp(tok, "fn") == 0) {
        ef_focus_near();
        uprint("Focus → minimum\r\n");

    } else if (strcmp(tok, "f+") == 0) {
        char *ns = strtok(NULL, " ");
        char *ss = strtok(NULL, " ");
        uint16_t steps = ns ? (uint16_t)atoi(ns) : 100;
        uint8_t  speed = ss ? (uint8_t)atoi(ss)  : 2;
        ef_focus_move(EF_DIR_FAR, speed, steps);
        printf("FAR %u adim hiz=%u\r\n", steps, speed);

    } else if (strcmp(tok, "f-") == 0) {
        char *ns = strtok(NULL, " ");
        char *ss = strtok(NULL, " ");
        uint16_t steps = ns ? (uint16_t)atoi(ns) : 100;
        uint8_t  speed = ss ? (uint8_t)atoi(ss)  : 2;
        ef_focus_move(EF_DIR_NEAR, speed, steps);
        printf("NEAR %u adim hiz=%u\r\n", steps, speed);

    } else if (strcmp(tok, "fs") == 0) {
        ef_focus_stop();
        uprint("STOP\r\n");

    } else if (strcmp(tok, "a") == 0) {
        char *fs = strtok(NULL, " ");
        if (!fs) { uprint("Kullanim: a <fstop>\r\n"); return; }
        float fstop = strtof(fs, NULL);
        if (fstop < 1.0f || fstop > 32.0f) {
            uprint("Gecersiz fstop\r\n"); return;
        }
        ef_aperture_set(fstop);
        printf("Diyafram f/%.1f\r\n", fstop);

    } else if (strcmp(tok, "ao") == 0) {
        ef_aperture_open();
        uprint("Diyafram tam acik\r\n");

    } else if (strcmp(tok, "st") == 0) {
        char *ns = strtok(NULL, " ");
        uint8_t n   = ns ? (uint8_t)atoi(ns) : 4;
        uint8_t buf[32] = {0};
        if (ef_status_read(buf, n) == HAL_OK) {
            printf("Status: ");
            for (uint8_t i = 0; i < n; i++)
                printf("%02X ", buf[i]);
            uprint("\r\n");
        } else {
            uprint("HATA\r\n");
        }

    } else {
        printf("? → %s\r\n", tok);
    }

    uprint("> ");
}

void app_main(void)
{
    uprint("\r\nCanon EF / NUCLEO-L432KC\r\n");
    uprint("SPI1 78kHz Mode3 | USART2 115200\r\n");

    if (ef_init(&hspi1) == HAL_OK)
        uprint("Lens HAZIR. '?' yaz.\r\n> ");
    else
        uprint("Lens yanit vermedi. Baglanti kontrol et.\r\n> ");

    uint8_t ch;
    while (1) {
        if (HAL_UART_Receive(&huart2, &ch, 1, 1) == HAL_OK) {
            HAL_UART_Transmit(&huart2, &ch, 1, 5);
            if (ch == '\r' || ch == '\n') {
                rx_buf[rx_idx] = '\0';
                uprint("\r\n");
                if (rx_idx > 0) process_cmd(rx_buf);
                rx_idx = 0;
            } else if (ch == 0x7F && rx_idx > 0) {
                rx_idx--;
            } else if (rx_idx < sizeof(rx_buf) - 1) {
                rx_buf[rx_idx++] = ch;
            }
        }
    }
}

Örnek oturum

PuTTY · COM3 · 115200-8N1
Canon EF / NUCLEO-L432KC
SPI1 78kHz Mode3 | USART2 115200
Lens HAZIR. '?' yaz.
> info
Lens ID   : 0xEB
Focal len : 50 mm
Diyafram  : f/1.4 - f/22.6
USM: EVET  IS: HAYIR
Ham yanit : 02 EB 08 60 32 00 00 00

> ao
Diyafram tam acik

> a 5.6
Diyafram f/5.6

> fi
Focus → sonsuz

> f- 300 2
NEAR 300 adim hiz=2

> f- 300 2
NEAR 300 adim hiz=2

> st
Status: 00 05 7B 00

> fn
Focus → minimum

09 Özet ve Sorun Giderme

Hızlı başvuru kartı ve kurulumda karşılaşılan yaygın sorunların çözümleri.

Tam bağlantı tablosu

NUCLEOAra ElemanCanon EFSinyal
PA5 / D1374AHCT125 1A → 1YKontak 6 — DclkSaat (SCK)
PA7 / D1174AHCT125 2A → 2YKontak 4 — DoutVeri gönder (MOSI)
PA6 / D1210 kΩ + 20 kΩ bölücüKontak 5 — DinVeri al (MISO)
5V (VBUS)Kontak 3 — VDDMantık beslemesi
MT3608 çıkışı6.00 V ayarlıKontak 1 — VbatMotor beslemesi
GNDKontak 2 — A_GNDMotor toprağı
GNDKontak 7 — D_GNDDijital toprak

CubeMX SPI1 özeti

ModeFull-Duplex Master
CPOL / CPHAHIGH / 2 Edge = Mode 3
Prescaler1024 → 78.125 kHz
First BitMSB First
NSSSoftware (CS yok)

Sorun giderme

BelirtiOlası nedenÇözüm
info → 00 00 00 00 Din hattı okunmuyor PA6'yı ölç: idle ~3.3 V görünmeli. Voltaj bölücü bağlantısını kontrol et.
Lens yanıt vermiyor (HAL_ERROR) Dclk/Dout seviyesi yetersiz 74AHCT125 VCC'nin 5 V'ta olduğunu ölç. 1OE ve 2OE GND'de mi kontrol et.
Focus komutu gidiyor ama motor hareket etmiyor VBAT düşük MT3608 çıkışını ölç: tam 6.00 V olmalı. 5.5 V altında USM motor tork üretemez.
Diyafram ayarlanmıyor Lens beklenmedik başlangıç durumunda Önce ao (tam aç) gönder, ardından a 5.6 dene.
printf float basmıyor Newlib-nano float desteği kapalı CubeMX → Project Manager → "Use float with printf" kutusunu işaretle.
Lens hazır mesajı çıkıyor ama komutlar yanıtsız Güç sırası yanlış VDD önce, VBAT sonra. Lensi söküp takarak veya VBAT'ı kapatıp açarak dene.

Diyafram Av hızlı tablo

  f/1.4 → 0x08   f/4.0 → 0x20   f/11  → 0x38
  f/2.0 → 0x10   f/5.6 → 0x28   f/16  → 0x40
  f/2.8 → 0x18   f/8.0 → 0x30   f/22  → 0x48