ARM – Not9: DMA (UART-DAC)

Yayınlandı: 24 Eylül 2017 / ARM STM32F4DISCOVERY Programlama...
Etiketler:, , , ,

DMA (direct memory access) daha öncedeki yazılarımda da bahsettiğim gibi doğrudan bellek erişimi anlamına gelen bir isimlendirmedir. Bazı mikrodenetleyicilerde bu birim bulunur ve işlem yükünü azaltma konusunda oldukça işe yarar.  Hafızadaki verilerin bir yerden başka bir yere taşınması gibi zaman kaybı yaratan işlemleri CPU’ya yaptırmak mikrodenetleyiciye zaman kaybettirerek işlem gücünü azaltmaktadır.  DMA tam olarak burada devreye girerek verilerin hafızada bir yerden bir yere taşınması işlemini üstlenir ve mikrodenetleyici içerisindeki  CPU’yu  ( STM32F407 için konuşursak CPU+FPU’yu)  veri taşıma işlemlerinden kurtarır.

STM32F407 mikrodenetleyicisinde herbirinde 8’er adet akaç (-Stream, türkçe karşılığı yok malesef. Ben de bu sebeple “akaç” kelimesini uydurdum. Veri akışı için kullanılan bir terimdir “Stream” ) bulunan  DMA1 ve DMA2 isminde iki adet DMA birimi bulunur. Bu birimler

  • Peripheral to Memory ( Çevrebirimden hafızaya)
  • Memory to memory (Hafızadan hafızaya)
  • Memory to peripheral (Hafızadan çevrebirime)

veri aktarmaya olanak sağlarlar.  Bu birimler ayrıca Circular buffer management (Dairesel tampon yönetimi) özelliğine de sahiptirler. Bu sayede veri akışının sonuna gelindiğinde , daha açık ifade edecek olursak tampondaki gönderilecek  veri adedinin sonuna gelindiğinde otomatik olarak başa dönerek tekrar harici bir işlem yapmaya gerek kalmadan veri aktarımına devam edebilirler.  DMA aşağıdaki çevresel birimlerle birlikte çalışabilmektedir;

  • SPI and I2S
  • I2C
  • USART
  • General-purpose, basic and advanced-control timers TIMx
  • DAC
  • SDIO
  • Camera interface (DCMI)
  • ADC

Hangi DMA biriminin hangi çevresel birime hangi kanaldan bağlanacağını gösteren tablolara göz atalım:

Tablolardan görülebileceği gibi her DMA biriminin 8 adet akacı bulunur ve her akacın 8 er adet kanalı bulunur. Bu kanallardan bazıları kullanılmamaktadır.

DMA birimiyle ilgili yeterli miktarda bir ön incelemeden sonra artık uygulamaya geçebiliriz. Ben buradaki uygulamada uart üzerinden aldığım verilerin doğrudan DAC birimine aktarılmasını istedim . Bu sebeple öncelikle DMA1’in Stream 1’inin 4. kanalını yani  UART3_RX’i kullandım. Bu kanala yüksek öncelik atadım. Yani DMA birimi öncelikle UART3 birimine gelen verilere ulaşıp taşıma işlemini gerçekleştirecek.  Daha sonra DMA1’in Stream5’inin 7. kanalı olan DAC1’i de seçtim ve buraya düşük öncelik atadım. Bu sayede aynı anda iki işlem gerçekleştiğinde öncelikli olarak Usart’tan gelen veri gerekli yere taşınacak. Aslında buarada yapılan işlem usarttan alınan verinin hafızada oluşturulmuş olan bir değişkene atanması ve daha sonra o değişkendeki verinin DAC birimine aktarılması şeklinde işleyecek. Tabi burada bilinmesi gereken şey çevre birimlerinde gerekli ayarlamaların yapılması gerektiği. Herşey DMA birimlerini ayarladığımızda sona ermiyor. Kullanılacak çevrebirimlerde de gerekli ayarlamaların yapılması şart. Mesela DAC biriminin DMA ile kullanılabilmesi için harici bir tetikleme alması gerekiyor. Bu bilgiye sahip olmadan DAC DMA ile birlikte kullanılamaz.  Bu sebeple öncelikle datasheet okuyabilmek gerekiyor.  Ben DAC için gerekli olan harici tetiklemeyi Timer7’den 100 ms de bir oluşturdum. Yani her 100 ms’de bir DAC DMA’dan gelen veriyi çıkışa aktaracak.

Lafı fazla uzatmadan kodlarımıza gelelim:


char tampon=0;
void main()
{
UART3_Init(9600); //UART3 9600bps olarak kuruldu.
USART3_CR3.DMAR=1; //USART3'ün recevie DMA modu aktif edildi.

RCC_AHB1ENR |= 0x00200000; // DMA1 clock verildi.
DMA1_S1M0AR=&tampon; //DMA1_Stream1 Kaynak edresi tampon değişkeni
DMA1_S1PAR=&USART3_DR; //DMA1_Stream1 Hedef adresi Usart3'ün data registerı
DMA1_S1CR.B27=1; //DMA1_Stream1 kanalı seçiliyor. CHSEL3:0 arası 100, yani kanal 4 seçilmiş. O da zaten USART3_RX 'e denk geliyor
DMA1_S1CR.B26=0; // rehber: Table 42. DMA1 request mapping e bakılabilir.
DMA1_S1CR.B25=0;
DMA1_S1CR.B17=1; // Öncelik "very high" olarak ayarlandı.
DMA1_S1CR.B16=1;
DMA1_S1CR.B8=1; // Circular mode enable edildi.
DMA1_S1CR.B7=0; // Transfer yönü 00 seçilerek
DMA1_S1CR.B6=0; // peripheral to memory yapıldı.
DMA1_S1NDTR=1; // transfer edilecek veri sayısı 1 adet olarak belirlendi.
DMA1_S1CR.B0=1; // Transferi baslat

RCC_APB1ENR.DACEN=1; // DACa clock verildi.
GPIO_Analog_Input(&GPIOA_BASE, _GPIO_PINMASK_4); //DAC CH1 kuruldu. DAC'ın çıkış verebilmesi için ilgili pin analog giriş olarak ayarlanmalı.
DAC_CR.B12=1; // DMA modu aktif edildi.
DAC_CR.B4=1; // DAC DMA modunda kullanılabilmek için harici tetiklemeye ihtiyaç duyar. Timer 7 trigger olarak seçildi.
DAC_CR.B2=1; // Trigger ile değer alma işlemi aktif edildi.

RCC_APB1ENR.TIM7EN = 1;//Timer7 'ye clock veriliyor.
TIM7_CR2.B5=1; // TRGO çıkışı her update durumunda verilecek
TIM7_CR1.CEN = 0; // Counter pasif edildi.
TIM7_PSC = 139; // Timer7 100 ms olaraak ayarlandı.
TIM7_ARR = 59999;
TIM7_CR1.CEN = 1;// Counter aktif edildi.

DMA1_S5M0AR=&tampon; // Nereden okuyacagiz
DMA1_S5PAR=&DAC_DHR8R1;// Nereye yazacagiz
DMA1_S5FCR&=~0xFFFFFF40;
DMA1_S5CR.B27=1;// DMA1_Stream5 kanalı seçiliyor. CHSEL3:0 arası 111, yani kanal 7 seçilmiş. O da zaten DAC1 'e denk geliyor
DMA1_S5CR.B26=1;
DMA1_S5CR.B25=1;
DMA1_S5CR.B17=0; //Öncelik "low" olarak seçilmiş.
DMA1_S5CR.B16=0;
DMA1_S5CR.B8=1; // Circular mod enable edildi.
DMA1_S5CR.B7=0; // Transfer yönü "01" yani Memory to peripheral olarak belirlendi.
DMA1_S5CR.B6=1;
DMA1_S5NDTR=1; // 1 adet veri tasiyacagiz
DMA1_S5CR.B0=1; // Transferi baslat
DAC_CR.B0=1; // DAC aktif edildi.

while(1);
}

Burada önemli olan kısım, program içi boş olan sonsuz döngüye girdikten sonra DMA’nın çalışşmaya devam etmesidir. CPU sonsuz döngüde takılı kalmasına rağmen UART3’e gelen veriler DAC birimine aktarılmaya devam edecektir.

Bir sonraki yazıda görüşmek üzere.

İyi çalışmalar.

yorum
  1. ERKAN dedi ki:

    Hocam, verdiğiniz bilgiler için teşekkür ederim. Benim sorum şu olacak; DMA’nın kullanılabileceği birimleri maddeler halinde yazmışsınız ama ben diyorum ki benim özel bir fonksiyonum var, ben bu fonksiyon içerisinde sürekli bir display’i 0-9 saydırıyorum, 1 sn aralıklar ile. Bu durumu DMA ya yaptırabilir miyiz? Amacım DMA’ya tümleşik çift mikrodenetleyici olarak hükmetmek.

Bir Cevap Yazın

Aşağıya bilgilerinizi girin veya oturum açmak için bir simgeye tıklayın:

WordPress.com Logosu

WordPress.com hesabınızı kullanarak yorum yapıyorsunuz. Çıkış  Yap / Değiştir )

Twitter resmi

Twitter hesabınızı kullanarak yorum yapıyorsunuz. Çıkış  Yap / Değiştir )

Facebook fotoğrafı

Facebook hesabınızı kullanarak yorum yapıyorsunuz. Çıkış  Yap / Değiştir )

Google+ fotoğrafı

Google+ hesabınızı kullanarak yorum yapıyorsunuz. Çıkış  Yap / Değiştir )

Connecting to %s