DMA Nedir ?

Mikrodenetleyici içerisinde farklı arabirimler bulunur. Bunları mikrodenetleyicilerin temellerini bilen herkes bilir.

DMA, Mikrodenetleyici içerisindeki RAM bellek ile diğer arabirimler arasında veri iletişimini sağlar. Bunu yaparken DMA kullanmanın avantajı, veri aktarımı sırasında CPU’yu tamamen devre dışı bırakarak; CPU’ya ek yük binmesine engel olur. Böylece CPU işlem kapasitesini veri aktarımına değil, diğer işlemlere ayırabilecektir. Veri aktarımı için ekstradan saykıl harcanmamış olacaktır.

Yüksek boyutlu veriler düşünüldüğünde, bu işlemi DMA ile yapmak CPU’yu büyük bir yükten kurtaracak ve hayati önemi olan komutlar daha hızlı bir çevrim ile işletilebilecektir. İşlemcimizin çalışma çevrim süresi düşmüş olacaktır.

DMA’nın ADC için kullanımı

Uygulamayı STM32F103 mikrodenetleyicisi üzerinden anlatacağım. 2 adet ADC arabirimi var. ADC1 üzerinden gidelim..

10 adet kanalı bulunuyor. Her kanal 16 bit’lik çözünürlüğe sahip. Göstereceğim uygulamada 8 kanalı DMA ile okutacağım. Böylece CPU sürekli olarak 8 kanaldan 2’şer byte’lık veri okuyup aktarmak için saykıl harcamayacak. Ve örneğin programda if(adc_buffer[0]>1043) yazdığınızda, Channel 0’ın değerini yorumlayabileceksiniz. Hem de programın hiç bir yerinde ADC_Read fonksiyonu kullanmayacaksınız. Her çevrimde bir 8 adet ADC_Read fonksiyonu çalıştırmadan 8 adet ADC’nin değerini programda kullanabileceksiniz 🙂

Hayati işlemler için çevrim süresinden süper bir kazanç demek bu ! 🙂

Şimdi işimize başlayalım 🙂 Makaledeki tüm resimler üstüne tıklandığında büyür.

1) CubeMX’i açın. Gerekli ADC ayarlarını yapın. GPIO ayarlarını yapın. Programı ST-Link kullanarak attığım için SWDIO ve SWCLK pinlerini de tanımladım. Aksi takdirde programı atmıyor !

1

2) MCU’nun clock ayarlarını yapın.

2

3) Configuration bölümüne geçerek, ADC1 için gerekli ayarları yapalım. ADC1’e tıklayın.

3

4) ADC1 ayarları

Bu kısımda kanallara Rank değeri vererek, kanallar arasında öncelik sıralaması yapabilirsiniz 🙂

4

5

Daha ayarlarımız bitmedi. Şimdi DMA Settings sekmesine tıklayın.

6

DMA Request bölümüne tıklayıp ADC1’i seçin.

Alt kısımda Mode bulunuyor. Burayı Normal olarak ayarlamalısınız.
Veriler memory’e kaydolacağından Memory‘i işaretleyin.
Her bir kanal 16 bit çözünürlüğünde olduğu için “Word” seçeneğini seçin.

CubeMX ayarlarımız tamamlandı. Şimdi kodu generate edin ve projeyi açın.

Projedeki main.c dosyasını açın.

Programın main kısmı aşağıdaki gibi olmalıdır. Satır yanlarında ve altlarında açıklamalar yapılmıştır. Lütfen dikkatlice takip edin. 🙂

int main(void)
{

/* USER CODE BEGIN 1 */
uint16_t adc_buffer[8]; // 8 adet ADC kanalı için 16 bitlik dizi tanımlandı.
/* USER CODE END 1 */

/* MCU Configuration———————————————————-*/

/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();

/* Configure the system clock */
SystemClock_Config();

/* Initialize all configured peripherals */
MX_GPIO_Init(); // GPIO ayarları etkinleşir.
MX_DMA_Init(); // DMA ayarları etkinleşir.
MX_ADC1_Init(); // ADC ayarları etkinleşir.

/* USER CODE BEGIN 2 */
// Alt satırdaki komut ile ADC’nin DMA üzerinden okutulması başlatılır. ADC1 okunacağından hadc1 instance’ı kullanılır. Okunan veriler adc_buffer dizisine yazılacaktır. 8 yazılarak, 8 kanal okunacağı belirtilir.

HAL_ADC_Start_DMA(&hadc1,(uint32_t *)adc_buffer,8);


// Bu komuttan sonra ADC ismi geçen herhangi bir başka komut yazmanıza gerek kalmaz.

/* USER CODE END 2 */

/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{

// Bu kısımda programınızı istediğiniz gibi yazın.

/* Programın herhangi bir yerinde bir ADC kanalındaki değer lazım olursa
adc_buffer[0] , adc_buffer[1] , adc_buffer[3] gibi dizi değişkeni kullanabilirsiniz. Herhangi bir ADC okuyucu komuta gerek yoktur.
Siz değişkeni çağırdığınızda CPU’ya yine ek bir yük binmeyecek. Zaten mevcut DMA tarafından okunmuş olan değeri kullanmış olacaksınız 🙂 */

}
/* USER CODE END 3 */

}

İyi çalışmalar dilerim.

Çağatay KAYNAK
Elektronik Mühendisi
cagataykaynak@gmail.com