Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

💾 hal::dma

Direct Memory Access - High Performance Data Transfer

391 satır ~15 fonksiyon Zero-Copy

📖 Genel Bakış

DMA (Direct Memory Access), CPU müdahalesi olmadan bellek ve çevre birimleri arasında veri transferi sağlar. ADC, USART, SPI gibi modüllerle yüksek hızlı veri aktarımı için kullanılır.

🔑 Temel Özellikler

  • Memory-to-memory transfers
  • Peripheral-to-memory transfers
  • Memory-to-peripheral transfers
  • Circular/Normal mode
  • Priority levels (4)
  • 8/16/32-bit data width
  • Transfer complete interrupts
  • Multiple channels/streams

🚀 Hızlı Başlangıç

içe_aktar hal::dma

// Memory-to-memory transfer
değişken src = [1, 2, 3, 4, 5]
değişken dst = [0; 5]

değişken dma_ch = dma.init(dma.DMA1, dma.CH1, yap
    direction: dma.M2M,  // Memory to Memory
    src_increment: doğru,
    dst_increment: doğru,
    data_size: dma.SIZE_8BIT
son)

dma.transfer(dma_ch, src.as_ptr(), dst.as_ptr(), 5)
dma.wait(dma_ch)  // Wait for completion

💡 Örnek: ADC with DMA (Continuous Sampling)

içe_aktar hal::dma, hal::adc

sabit SAMPLE_COUNT = 1000

değişken adc_buffer = [0u16; SAMPLE_COUNT]

fonksiyon adc_dma_init() yap
    // Initialize ADC
    adc.clock_enable()
    değişken adc1 = adc.init(adc.ADC1, yap
        resolution: adc.RESOLUTION_12BIT,
        continuous: doğru,
        dma_enable: doğru
    son)
    
    adc.channel_config(adc1, adc.CHANNEL_0, yap
        sampling_time: adc.SAMPLETIME_480CYCLES
    son)
    
    // Setup DMA
    dma.clock_enable(dma.DMA2)
    değişken dma_ch = dma.init(dma.DMA2, dma.STREAM0, yap
        direction: dma.P2M,  // Peripheral to Memory
        src_address: adc.get_data_register(adc1),
        dst_address: adc_buffer.as_ptr(),
        data_count: SAMPLE_COUNT,
        src_increment: yanlış,  // Same ADC register
        dst_increment: doğru,   // Increment buffer
        circular: doğru,        // Continuous sampling
        data_size: dma.SIZE_16BIT,
        priority: dma.PRIORITY_HIGH
    son)
    
    dma.start(dma_ch)
    adc.start(adc1)
son

fonksiyon calculate_average() -> kesir yap
    değişken toplam = 0
    her sample içinde adc_buffer için yap
        toplam += sample
    son
    dön toplam.kesir() / SAMPLE_COUNT.kesir()
son

fonksiyon ana() yap
    adc_dma_init()
    
    döngü yap
        değişken avg = calculate_average()
        değişken voltage = avg * 3.3 / 4095.0
        io.println("Average voltage: {:.3f}V".formatla(voltage))
        core.delay_ms(1000)
    son
son

💡 Örnek: USART TX with DMA

içe_aktar hal::dma, hal::usart

değişken dma_complete = yanlış

fonksiyon dma_complete_callback() yap
    dma_complete = doğru
son

fonksiyon usart_dma_send(uart: usart.Handle, data: yazı) -> Sonuç[Hiçbir, Hata] yap
    // Setup DMA for USART TX
    değişken dma_ch = dma.init(dma.DMA1, dma.CH4, yap
        direction: dma.M2P,  // Memory to Peripheral
        src_address: data.as_ptr(),
        dst_address: usart.get_tx_register(uart),
        data_count: data.uzunluk(),
        src_increment: doğru,
        dst_increment: yanlış,  // Same USART register
        data_size: dma.SIZE_8BIT,
        priority: dma.PRIORITY_MEDIUM,
        callback: dma_complete_callback
    son)
    
    dma_complete = yanlış
    dma.start(dma_ch)
    
    // Enable USART DMA mode
    usart.enable_dma_tx(uart)
    
    // Wait for completion
    döngü dma_complete değilse yap
        core.delay_ms(1)
    son
    
    dön Tamam(Hiçbir)
son

fonksiyon ana() yap
    değişken uart = usart.init(usart.USART1, yap
        baud_rate: 115200
    son)
    
    usart_dma_send(uart, "Hello from DMA!\n")?
    io.println("DMA transfer complete!")
son

💡 Örnek: Memory-to-Memory Fast Copy

içe_aktar hal::dma

fonksiyon fast_memcpy(dest: *değişken u8, src: *u8, size: sayı) yap
    // DMA memory-to-memory is much faster than CPU copy
    değişken dma_ch = dma.init(dma.DMA2, dma.STREAM0, yap
        direction: dma.M2M,  // Memory to Memory
        src_address: src,
        dst_address: dest,
        data_count: size,
        src_increment: doğru,
        dst_increment: doğru,
        data_size: dma.SIZE_32BIT,  // 32-bit for efficiency
        priority: dma.PRIORITY_VERY_HIGH
    son)
    
    dma.start(dma_ch)
    dma.wait(dma_ch)
son

fonksiyon ana() yap
    // Large buffer copy test
    sabit SIZE = 10000
    değişken src_buffer = [0u8; SIZE]
    değişken dst_buffer = [0u8; SIZE]
    
    // Fill source with test data
    her i içinde 0..SIZE için yap
        src_buffer[i] = (i % 256).u8()
    son
    
    // Benchmark
    değişken start = core.uptime_us()
    fast_memcpy(dst_buffer.as_mut_ptr(), src_buffer.as_ptr(), SIZE)
    değişken elapsed = core.uptime_us() - start
    
    io.println("DMA copy {}KB in {}us", SIZE/1024, elapsed)
    io.println("Speed: {:.2f}MB/s", SIZE.kesir() / elapsed.kesir())
son

💡 Örnek: Double Buffer (Ping-Pong)

içe_aktar hal::dma, hal::adc

sabit BUFFER_SIZE = 512

değişken buffer_a = [0u16; BUFFER_SIZE]
değişken buffer_b = [0u16; BUFFER_SIZE]
değişken current_buffer = 0

fonksiyon buffer_half_complete() yap
    // Buffer A is full, start processing while DMA fills B
    process_samples(buffer_a)
    current_buffer = 1
son

fonksiyon buffer_complete() yap
    // Buffer B is full, start processing while DMA fills A
    process_samples(buffer_b)
    current_buffer = 0
son

fonksiyon process_samples(buffer: []u16) yap
    değişken max_val = 0u16
    her sample içinde buffer için yap
        eğer sample > max_val ise max_val = sample
    son
    io.println("Max value: {}", max_val)
son

fonksiyon adc_double_buffer_init() yap
    // Init ADC
    değişken adc1 = adc.init(adc.ADC1, yap
        resolution: adc.RESOLUTION_12BIT,
        continuous: doğru,
        dma_enable: doğru
    son)
    
    // DMA double buffer mode
    değişken dma_ch = dma.init(dma.DMA2, dma.STREAM0, yap
        direction: dma.P2M,
        src_address: adc.get_data_register(adc1),
        dst_address_0: buffer_a.as_ptr(),  // Ping buffer
        dst_address_1: buffer_b.as_ptr(),  // Pong buffer
        data_count: BUFFER_SIZE,
        circular: doğru,
        double_buffer: doğru,
        src_increment: yanlış,
        dst_increment: doğru,
        data_size: dma.SIZE_16BIT,
        half_complete_callback: buffer_half_complete,
        complete_callback: buffer_complete
    son)
    
    dma.start(dma_ch)
    adc.start(adc1)
son

fonksiyon ana() yap
    adc_double_buffer_init()
    
    // Process in background via interrupts
    döngü yap
        core.sleep()  // CPU sleeps while DMA works
    son
son

💡 Örnek: SPI Display with DMA Burst

içe_aktar hal::dma, hal::spi, hal::gpio

// Display framebuffer (128x64 OLED = 1024 bytes)
sabit WIDTH = 128
sabit HEIGHT = 64
değişken framebuffer = [0u8; (WIDTH * HEIGHT) / 8]

fonksiyon display_update() yap
    // CS low
    gpio.pin_write(gpio.PORT_A, 4, gpio.LOW)
    
    // Command: set column/page address
    spi.write_byte(spi1, 0x00)  // Command mode
    
    // DMA burst transfer entire framebuffer
    değişken dma_ch = dma.init(dma.DMA1, dma.STREAM3, yap
        direction: dma.M2P,
        src_address: framebuffer.as_ptr(),
        dst_address: spi.get_data_register(spi1),
        data_count: framebuffer.uzunluk(),
        src_increment: doğru,
        dst_increment: yanlış,
        data_size: dma.SIZE_8BIT,
        priority: dma.PRIORITY_HIGH
    son)
    
    dma.start(dma_ch)
    dma.wait(dma_ch)
    
    // CS high
    gpio.pin_write(gpio.PORT_A, 4, gpio.HIGH)
son

fonksiyon draw_pixel(x: sayı, y: sayı, color: bool) yap
    değişken byte_index = x + (y / 8) * WIDTH
    değişken bit_index = y % 8
    
    eğer color ise yap
        framebuffer[byte_index] |= (1 << bit_index)
    son yoksa yap
        framebuffer[byte_index] &= ~(1 << bit_index)
    son
son

fonksiyon ana() yap
    // Draw test pattern
    her x içinde 0..WIDTH için yap
        her y içinde 0..HEIGHT için yap
            draw_pixel(x, y, (x + y) % 2 == 0)
        son
    son
    
    // Fast DMA update (instead of slow SPI byte-by-byte)
    display_update()  // ~8ms with DMA vs 100ms+ without
son

💡 Örnek: USART RX with DMA Circular Buffer

içe_aktar hal::dma, hal::usart

sabit RX_BUFFER_SIZE = 256
değişken rx_buffer = [0u8; RX_BUFFER_SIZE]
değişken read_pos = 0

fonksiyon uart_dma_rx_init(uart: usart.Handle) yap
    // DMA in circular mode for continuous RX
    değişken dma_ch = dma.init(dma.DMA1, dma.STREAM5, yap
        direction: dma.P2M,
        src_address: usart.get_rx_register(uart),
        dst_address: rx_buffer.as_ptr(),
        data_count: RX_BUFFER_SIZE,
        src_increment: yanlış,
        dst_increment: doğru,
        circular: doğru,  // Never stops, wraps around
        data_size: dma.SIZE_8BIT,
        priority: dma.PRIORITY_MEDIUM
    son)
    
    usart.enable_dma_rx(uart)
    dma.start(dma_ch)
son

fonksiyon available() -> sayı yap
    // Get DMA write position
    değişken write_pos = RX_BUFFER_SIZE - dma.get_counter(dma_ch)
    
    eğer write_pos >= read_pos ise yap
        dön write_pos - read_pos
    son yoksa yap
        dön RX_BUFFER_SIZE - read_pos + write_pos
    son
son

fonksiyon read_byte() -> Seçenek[u8] yap
    eğer available() > 0 ise yap
        değişken data = rx_buffer[read_pos]
        read_pos = (read_pos + 1) % RX_BUFFER_SIZE
        dön Bazı(data)
    son
    dön Hiçbir
son

fonksiyon ana() yap
    değişken uart = usart.init(usart.USART1, yap
        baud_rate: 115200
    son)
    
    uart_dma_rx_init(uart)
    
    döngü yap
        eğer available() > 0 ise yap
            eşle read_byte() yap
                Bazı(byte) => io.print("{:c}", byte),
                Hiçbir => {}
            son
        son
        core.delay_ms(10)
    son
son

⚙️ DMA Yapılandırma Tipleri

// DMA Direction
enum Direction {
    P2M,  // Peripheral to Memory (ADC, USART RX)
    M2P,  // Memory to Peripheral (USART TX, DAC)
    M2M   // Memory to Memory (fast copy)
}

// Data Size
enum DataSize {
    SIZE_8BIT,   // Byte
    SIZE_16BIT,  // Half-word
    SIZE_32BIT   // Word
}

// Priority
enum Priority {
    LOW,
    MEDIUM,
    HIGH,
    VERY_HIGH
}

// DMA Configuration
yapı DMAConfig yap
    direction: Direction,
    src_address: *u8,
    dst_address: *u8,
    data_count: sayı,
    src_increment: bool,
    dst_increment: bool,
    circular: bool,
    data_size: DataSize,
    priority: Priority,
    double_buffer: bool,         // Optional
    dst_address_1: *u8,          // For double buffer
    half_complete_callback: fn(), // Optional
    complete_callback: fn()       // Optional
son

📚 DMA Fonksiyonları

// DMA channel initialization
fonksiyon init(dma: DMAInstance, channel: Channel, config: DMAConfig) -> Handle

// Transfer control
fonksiyon start(handle: Handle)
fonksiyon stop(handle: Handle)
fonksiyon wait(handle: Handle)  // Blocking wait
fonksiyon is_complete(handle: Handle) -> bool

// Status queries
fonksiyon get_counter(handle: Handle) -> sayı  // Remaining transfers
fonksiyon get_current_buffer(handle: Handle) -> sayı  // 0 or 1 (double buffer)

// Advanced
fonksiyon transfer(handle: Handle, src: *u8, dst: *u8, count: sayı)
fonksiyon circular_transfer(handle: Handle, src: *u8, dst: *u8, count: sayı)

// Clock control
fonksiyon clock_enable(dma: DMAInstance)
fonksiyon clock_disable(dma: DMAInstance)

⚡ Performans İpuçları

  • 32-bit transfers: 4x faster than 8-bit for aligned data
  • Circular mode: Zero overhead for continuous streaming (ADC, USART)
  • Double buffer: Process one buffer while filling the other (zero data loss)
  • Priority: Set VERY_HIGH for time-critical transfers
  • Burst mode: Use for large block transfers (framebuffers, files)

📊 DMA Kullanım Senaryoları

Senaryo Direction Mode Avantaj
ADC Continuous Sampling P2M Circular CPU-free data acquisition
USART High-Speed TX M2P Normal Non-blocking transmission
SPI Display Update M2P Normal 10-20x faster refresh
Audio Streaming M2P (DAC) Double Buffer Glitch-free playback
Large Buffer Copy M2M Normal Hardware acceleration

🖥️ Platform Desteği

  • STM32F1: DMA1 (7 channels), DMA2 (5 channels)
  • STM32F4: DMA1/DMA2 (8 streams each, FIFO support)
  • STM32L4: DMA1/DMA2 (7 channels each, low-power)
  • GD32: Compatible with STM32 DMA architecture
  • ESP32: GDMA (general purpose DMA)

⚠️ Önemli Notlar

  • Memory Alignment: DMA buffer'ları RAM'de olmalıdır (not flash/peripheral memory)
  • Circular Mode: Infinite loop için kullanılır, ADC/USART streaming ideal
  • NVIC Enable: DMA interrupt kullanırken NVIC enable edilmelidir
  • Double Buffer: Zero data loss için ping-pong buffering kullanın
  • Buffer Safety: DMA transfer sırasında buffer modify edilmemelidir
  • Cache Coherency: STM32F7/H7'de cache invalidation gerekir
  • Data Width: 32-bit aligned data için SIZE_32BIT kullanın (4x hızlı)
  • Priority: Aynı öncelikte multiple DMA kullanımında arbitration olur

🔗 İlgili Modüller

  • hal::adc - ADC with DMA (continuous sampling)
  • hal::dac - DAC with DMA (waveform generation)
  • hal::usart - UART with DMA (high-speed serial)
  • hal::spi - SPI with DMA (display, SD card)
  • hal::i2c - I2C with DMA (sensor reading)
  • hal::int - DMA interrupts (NVIC configuration)
  • hal::timer - Timer-triggered DMA

📖 Referanslar

← HAL Modülleri