DMA interrupt rutininde enteresan olaylar ?

Başlatan seyityildirim, 21 Şubat 2017, 18:55:28

seyityildirim

Programın başında sample isimli değişken tanımlı

uint16_t sample=0;


DMA kullanarak 2 kanal ADC okuyorum.aşağıda ilgili kısımların kodları mevcut. Kodlarda göreceğiniz üzere sample değişkeni 0 ile 199 arasında değişebiliyor. Ama Debug yaparken sample değişkenini gözlediğimde 2000'ler 3000'ler civarında değişiyor. Bu neden olabilir ? Teşekkürler

clock ayarları
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2,  ENABLE);
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,  ENABLE);
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC2,  ENABLE);
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,  ENABLE);



GPIO ayarları
GPIO_InitTypeDef GPIO_InitStructure;
  /* ADC Channel 10 -> PC0
     ADC Channel 11 -> PC1
  */
  GPIO_InitStructure.GPIO_Pin 	= GPIO_Pin_0 | GPIO_Pin_1;
  GPIO_InitStructure.GPIO_Mode 	= GPIO_Mode_AN;
  GPIO_InitStructure.GPIO_PuPd 	= GPIO_PuPd_NOPULL ;
  GPIO_Init(GPIOC, &GPIO_InitStructure);



ADC ayarı
  ADC_CommonInitTypeDef ADC_CommonInitStructure;
	
  ADC_CommonInitStructure.ADC_Mode = ADC_DualMode_RegSimult;			// Güç ölçümü için Dual mode 
  ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;				// Adc clock frekansi 2'ye bölünür => APB2:2
  ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_2;	// Dual ADC ölçümü yapilirken DMA mode 2 kullanilir
  ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;		// 2 Örnekleme arasi bekleme süresi
 ADC_CommonInit(&ADC_CommonInitStructure);



ADC ayarı
  ADC_InitTypeDef ADC_InitStructure;

  ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;					// 12 Bit Adc çözünürlügü
  ADC_InitStructure.ADC_ScanConvMode  = DISABLE;							// Tarama modu kapali
  ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;						// Sürekli çevrim modu açik
  ADC_InitStructure.ADC_ExternalTrigConvEdge= ADC_ExternalTrigConvEdge_Rising;	// Timer3 yükselen kenar tetigi	
  ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T3_TRGO;	        // Timer 3 ile tetiklenecek
  ADC_InitStructure.ADC_DataAlign  = ADC_DataAlign_Right;					// Datalar saga dayali biçimde dizilecek
  ADC_InitStructure.ADC_NbrOfConversion = 1;								// Adc1'de 1 adet kanal kullanilacak
  ADC_Init(ADC1, &ADC_InitStructure);

  /* ADC1 regular channels 10 configuration */ 
  ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 1, ADC_SampleTime_3Cycles);			// Örnekleme süresi de belirtildi



ADC ayarı
  ADC_InitTypeDef ADC_InitStructure;

  ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;					// 12 Bit Adc çözünürlügü
  ADC_InitStructure.ADC_ScanConvMode  = DISABLE;							// Tarama modu kapali
  ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;						// Sürekli çevrim modu açik
  ADC_InitStructure.ADC_ExternalTrigConvEdge= ADC_ExternalTrigConvEdge_Rising;	// Timer3 yükselen kenar tetigi	
  ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T3_TRGO;	        // Timer 3 ile tetiklenecek
  ADC_InitStructure.ADC_DataAlign  = ADC_DataAlign_Right;					// Datalar saga dayali biçimde dizilecek
  ADC_InitStructure.ADC_NbrOfConversion = 1;								// Adc1'de 1 adet kanal kullanilacak
  ADC_Init(ADC1, &ADC_InitStructure);

  /* ADC2 regular channels 10 configuration */ 
  ADC_RegularChannelConfig(ADC2, ADC_Channel_11, 1, ADC_SampleTime_3Cycles);			// Örnekleme süresi de belirtildi



DMA ayarı
DMA_InitTypeDef DMA_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
	
  DMA_InitStructure.DMA_Channel = DMA_Channel_0;  // Dma kanal 0 
  DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&aADCDualConvertedValue;	// Adc degerlerinin aktarilacagi adres
  DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)ADC_CCR_ADDRESS;		// Adc kaynagi
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;					// Aktarim yönü donanimdan hafizaya
  DMA_InitStructure.DMA_BufferSize = 2;									// Buffer boyutu 2
  DMA_InitStructure.DMA_PeripheralInc 	= DMA_PeripheralInc_Disable;			// Adc hedefi arttirilmayacak
  DMA_InitStructure.DMA_MemoryInc 	= DMA_MemoryInc_Enable;				// Hafiza hedefi her adc için arttirilacak
  DMA_InitStructure.DMA_PeripheralDataSize  = DMA_PeripheralDataSize_Word;				// Adc veri boyutu 16 bit
  DMA_InitStructure.DMA_MemoryDataSize	= DMA_MemoryDataSize_Word;				// Hafiza veri boyutu 16 bit
  DMA_InitStructure.DMA_Mode 	= DMA_Mode_Circular;									// Çevrim olacak
  DMA_InitStructure.DMA_Priority 	= DMA_Priority_High;									// DMA öncelik yüksek
  DMA_InitStructure.DMA_FIFOMode 	= DMA_FIFOMode_Disable; 							// FIFO mod kapali
  DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull; 				// Önemi yok (FIFO kapali oldugundan)
  DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;							// Hafiza Veri paketleri kesintisiz aktarim
  DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; 				// Adc Veri paketleri kesintisiz aktarim
  DMA_Init(DMA2_Stream0, &DMA_InitStructure);
	
	 
	NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream0_IRQn;			// DMA2 Stream0 kesmesi kullanilacak
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;	 	// Kesme önceligi yüksek
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;				// Alt öncelik seviyesi de yüksek
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			// Kesme kanali aktif edildi
	NVIC_Init(&NVIC_InitStructure);
	
	DMA_ITConfig(DMA2_Stream0, DMA_IT_TC, ENABLE); // Dma2 Stream0 transfer tamamlandi kesmesi aktif edildi

  DMA_Cmd(DMA2_Stream0, ENABLE);			 // DMA2 Stream0 aktif edildi.



ADC yi tetikleyecek TIM ayarı
/*
	Ftimer=(84MHz/(PSC+1))
	PSC=8399 => Ftimer= 10KHz
	ARR=1 => ADC örnekleme periyodu= (1/10KHz)*ARR= 100us 
	*/
TIM_PrescalerConfig(TIM3,8399,TIM_PSCReloadMode_Update); 
TIM_SetAutoreload(TIM3,1); 
TIM_SelectOutputTrigger(TIM3, TIM_TRGOSource_Update);

 TIM_Cmd(TIM3, ENABLE);



Doanaımlar aktif ediliyor
/* Enable DMA request after last transfer (Multi-ADC mode)  */
  ADC_MultiModeDMARequestAfterLastTransferCmd(ENABLE);
	
	/* Enable ADC DMA */
	ADC_DMACmd(ADC1, ENABLE);
	ADC_DMACmd(ADC2, ENABLE);
	
        ADC_Cmd(ADC1, ENABLE);
	ADC_Cmd(ADC2, ENABLE);
	
	sample=0;


  ADC_SoftwareStartConv(ADC1);
  ADC_SoftwareStartConv(ADC2);




VE gelelim DMA interruptuna. sadece ilgili yerleri verdim

void DMA2_Stream0_IRQHandler(void)
{
  //Test on DMA1 Channel0 Transfer Complete interrupt
  if(DMA_GetITStatus(DMA2_Stream0,DMA_IT_TCIF0))
  {
			/* 15 satırlık çeşitli matematiksel işlemler*/
			
			if(sample>198)
			{
				/*matematiksel işlemler var */
				sample=0;
				
			}
			
			sample++;
			/*------------------------------------------------------------------------------*/
			
			
		
			DMA_ClearITPendingBit(DMA2_Stream0,DMA_IT_TCIF0); // Yeni kesme olusabilmesi için
  }
}



Debug yaparken sample değişkenine bakıyorum adam 1200 lerde 2000 lerde 4000'lerde geziyor. Bu neden olabilir?

seyityildirim

Sorunu tazeleyim. aşağıdaki kod parçasında sample=0; satırına breakpoint koydum. Kod bu satıra geliyor. sample 3500 lerde. bu satırdan sonra da 0 olmuyor. lafın kısası sample değişkeni beni dinlemiyor. ayrıca değeri sürekli değişiyor. hiçbir yerde değiştirme yapmıyorum. üstelik 0'a eşitliyorum ama durum değişmiyor. sorun ne olabilir ?

void DMA2_Stream0_IRQHandler(void)
{
  //Test on DMA1 Channel0 Transfer Complete interrupt
  if(DMA_GetITStatus(DMA2_Stream0,DMA_IT_TCIF0))
  {

			sample=0;
			
		
			DMA_ClearITPendingBit(DMA2_Stream0,DMA_IT_TCIF0); // Yeni kesme olusabilmesi için
  }
}

yldzelektronik

CubeMX ile mi oluşturdunuz projeyi?

Proje ayarlarına gidip optimizasyona bakın.Sorun sanki optimizasyon ile ilgili.
Kişinin başına gelen hayır Allah'tandır. Kişinin başına gelen şer nefsindendir. Nefislerimizle kendimize zulüm ediyoruz.

kantirici

Muhtemelen compiler optimizasyon yapıyor.

Değişken tanımlamayı bu şekilde yapıp dener misin?

volatile uint16_t sample=0;

seyityildirim

Alıntı yapılan: yldzelektronik - 22 Şubat 2017, 08:11:59
CubeMX ile mi oluşturdunuz projeyi?

Proje ayarlarına gidip optimizasyona bakın.Sorun sanki optimizasyon ile ilgili.

Hayır Cume Mx kullanmadım. std periph kütüphanesi kullanıyorum. Proje ayarlarında optimizasyon kutucuğu işaretli değil

Alıntı yapılan: kantirici - 22 Şubat 2017, 08:29:31
Muhtemelen compiler optimizasyon yapıyor.

Değişken tanımlamayı bu şekilde yapıp dener misin?

volatile uint16_t sample=0;


İlk başta o şekilde düşündüm volatile yapmama rağmen sorun değişmedi

Klein

aADCDualConvertedValue

dizisi nerede tanımlı? tipi 32 bit m?
ADC registeri 16 bit sen 32 bit seçmişsin.
Taşma oluyor olabilir. Veri tiplerini kontrol et.

seyityildirim

Alıntı yapılan: Klein - 22 Şubat 2017, 11:31:37
aADCDualConvertedValue

dizisi nerede tanımlı? tipi 32 bit m?
ADC registeri 16 bit sen 32 bit seçmişsin.
Taşma oluyor olabilir. Veri tiplerini kontrol et.

Hocam global olarak şu şekilde tanımlı
volatile uint16_t aADCDualConvertedValue[2]; 	// Adc degerlerinin tutuldugu yer
volatile int sample=0;						// bir periyotta örnek sayi indexi


ayrıca adc registerlarındaki taşma sample değişkenine nasıl etki edebilir ki ?

Klein

DMA ayarlarını yaparken memory genişliğini 32 bit seçmişsin. fakat registerlerin 16 bit.
DMA 32 bit yazıyor, doğal olarak hemen peşindeki sample değişkeninin üzerine yazıyor.

hem memory hem de peripherial genişliğini Half word yap.

seyityildirim

@Klein  Hocam söylediğinizi yaptım sorun çözüldü fakat Memory genişliğinin 32 bit olduğunu nasıl çıkardınız ? word zaten 16 bit demek değil mi ?
İlk verdiğim kodda Word yazmıştım. Ancak dediğiniz gibi halfword yapınca çözüldü.

Klein

Çalıştığın kontrolör 32 bit.  word genişliği 32 bit. 

seyityildirim

Anladım hocam çok teşekkürler :)

internete word kaç bittir yazmıştım kodu ilk yazarken 16 bit dediler :)

Tekrar herkese teşekkürler

Klein

Evet WORD tipi değişken 16 bit.  Muhtemelen geçmiş uyumluluğu sebebiyle öyle kalmış. Fakat  dokümanda bahsedilen WORD tipi değişken değil.
Bu sebeple  WORD, int gibi değişkenler yerine uint32_t , u16 , gibi net ifdesi olan değişkenler kullanılması öneriliyor.