TIM7 ve DMA Handler sorunu

Başlatan camby, 18 Kasım 2012, 00:35:58

camby

Şu başlıkta da benzer sorun yaşanmış : https://www.picproje.org/index.php/topic,42375.msg306582.html#msg306582


Amacım DMA transfer işleminin süresini TIM7 ile ölçmek. Ölçüm tüm fonksiyonlarda sorunsuz çalışıyor fakat DMA işin içine geçince bozuluyor.

Programda timer enable yapıp transferi başlatıyorum , DMA kesmesi gelince timer'ı durduruyorum.

İşlemi takip etmek için kullandığım led mantıklı bir şekilde çok kısa bir süre ışıldıyor. Handler düzgün bir şekilde çalışıyor , veriler kopyalanıyor onları da kontrol ettim LCD'den.

Fakat TIM7 aynı saçma sabit değer. Dökümanları karıştırdım ancak birşey bulamadım DMA Handler TIM7'yi nasıl bozar, neyi kaçırıyorum acaba ?

char Source[1024];
char Target[1024];

void DMA1_Channel2_IRQHandler()
{
	
	TIM7->CR1 &=~ 0x0001;            		// Counter Disable
	GPIOC->ODR &=~ 0x00000100;				// Test Led OFF
	DMA1->IFCR |= (1<<5);					// clear flag
	
}
//======================== Timer7 Init ========================================
void Timer7_Init(void) 
{
	/* Timer7 clock 24 MHZ , Prescaler 24.000 -> Her 1/1000 sn(1ms)' de bir deger 1 artar.*/
	
	RCC->APB1ENR |= (1UL << 5);               	// Enable Timer7 clock   
	TIM7->CR1 = 0x0080;              			// 1: TIMx_ARR register is buffered
	TIM7->PSC = 24000-1;           				// Prescaler : 24000
	TIM7->ARR = 1000;                			// Auto-Reload : 1000
	
}

void DMA_Kopyala(void)
{
	RCC->AHBENR |= 1;       					// DMA1EN: DMA1 clock enable 
		
	DMA1_Channel2->CNDTR = 1024;				// Tasinacak veri sayisi 1024
    DMA1_Channel2->CMAR = (int)&Source[0];  	// Source array dan datalari alacagiz
    DMA1_Channel2->CPAR = (int)&Target[0];  	// Target array a datalari tasiyacagiz
	
	DMA1_Channel2->CCR |= (1<<14);				// MEM2MEM: Memory to memory mode
	DMA1_Channel2->CCR |= (3<<12);				// PL[1:0]: Channel priority level - 11: Very high
	DMA1_Channel2->CCR |= (1<<7);				// MINC: Memory increment mode - enabled
	DMA1_Channel2->CCR |= (1<<6);				// PINC: Peripheral increment mode - enabled
	DMA1_Channel2->CCR |= (1<<4);				// DIR: Data transfer direction - 1: Read from memory
	
	DMA1_Channel2->CCR |= (1<<1);				// TCIE: Transfer complete interrupt enable
 
	NVIC->ISER[0] |= (1<<12);					// DMA1 Channel 2 global Interrupt
	
    DMA1_Channel2->CCR |= 1;     				// EN: Channel enable
	
}

/*----------------------------------------------------------------------------
  MAIN function
 *----------------------------------------------------------------------------*/
int main (void) 
 {	 
 
	volatile int i;
	 
	GPIO_Init(); 	 
	Timer7_Init();
	  
	for(i=0;i<1024;i++) Source[i]=i;  			

	TIM7->CR1 |= 0x0001;            			// Counter Enable
	GPIOC->ODR |= 0x00000100;                 // Test Led ON
	DMA_Kopyala();
	
}
	while(1) 
	{						// Loop forever
	}

Klein

sayıcıyı başlatmadan önce sıfırlamayı, bir de sayıcıyıdurdurmadan önce değerini alıp sonra sayıcıyı durdurmayı deneyebilir misin?
Her zaman aynı ama saçma bir değer mi görüyorsun? Saçma olduğu fikrini uyandıran nedir? Olması gerekenden çok mu uzak bir değer?

camby

Sayıcı başlatmadan önce sıfırlamayı da denedim.

Sayıcıyı durdurmadan önce Handler içerisinde kayıt etmeyi de denedim. Handler içinde durdurduktan sonra kayıt etmeyi de dedim.


Ledin açık kalma süresi tahminimce 10 ms'nin altında,belki 1ms'nin de altında.

TIM7'nin içeriği her 1ms'de bir 1 artıyor. Yani almam gereken sayı çok küçük bir sayı.

Aldığım değer hep 6200 küsür. Hiç değişmiyor. Timer'ın prescaler değerleri ile oynuyorum yine de değişmiyor. Değişecek mi diye bakmak için kopyalama startını vermeden önce araya delay_ms koyuyorum bir şey değişmiyor.

---------

İşlemin ne kadar sürede tamamlandığını görmek için şöyle bir şey denedim :

TIM7->CR1 |= 0x0001;            			// Counter Enable
	GPIOC->ODR |= 0x00000100;
	DMA_Kopyala();
	
	lcd_veri_yaz(35,50,Target[1024],1,1,255,255,255);


Yukarıdaki durumda arka plandaki kopyalama işlemi henüz  tamamlanmadığı için yeni değerler ekrana yansımıyor.

fakat araya 1 ms delay koyunca Target dizisine veriler yerleşmiş oluyor.

Yani buradan dolayı işlemin 1ms'den kısa olduğunu söyleyebilrim.

TIM7->CR1 |= 0x0001;            			// Counter Enable
	GPIOC->ODR |= 0x00000100;
	DMA_Kopyala();
	delay_ms(1);
	lcd_veri_yaz(35,50,Target[1024],1,1,255,255,255);


ancak TIM7 olaya karışmamakta ısrar ediyor...

z

Timerı en yüksek clock ile saydırın. Bunun için prescaler değerini iyice düşür.
Ayrıca Auto Reloaddeğerini en büyük değere set etmeyi dene. Sürekli yuvarlanıyor olabilir.
Bana e^st de diyebilirsiniz.   www.cncdesigner.com

camby

Alıntı yapılan: z - 18 Kasım 2012, 12:30:00
Timerı en yüksek clock ile saydırın. Bunun için prescaler değerini iyice düşür.
Ayrıca Auto Reloaddeğerini en büyük değere set etmeyi dene. Sürekli yuvarlanıyor olabilir.

Hocam ikisini de denedim çıkan sonuç hiç etkilenmiyor hep 6293. Auto Reload 1000 iken , çıkan sonucun 6293 gelmesi de ilginç.

Şimdi tekrar denedim emin olmak için ARR 50000 , prescaler 240 yaptım , sonuç yine aynı 6293.

DMA handler yok iken TIM7 ölçüm işinde sorunsuz işini yapıyor.

//======================== Timer7 Init ========================================
void Timer7_Init(void) 
{
	/* Timer7 clock 24 MHZ , Prescaler 24.000 -> Her 1/1000 sn(1ms)' de bir deger 1 artar.*/
	
	RCC->APB1ENR |= (1UL << 5);               	// Enable Timer7 clock   
	TIM7->CR1 = 0x0080;              			// 1: TIMx_ARR register is buffered
	TIM7->PSC = 2400-1;           				// Prescaler : 24000
	TIM7->ARR = 50000;                			// Auto-Reload : 1000
//	TIM7->DIER = 0x0001;                     	// Update interrupt enabled.
//	NVIC->ISER[1] = 0X00800000;        			// NVIC ISER 55 , TIM7
	

}

Klein

#5
Şöyle bir deneme yaptım.  Timer 2 kullanıyorum.  STM32F103. 
Timer prescaler değerini değiştirdiğimde veya adaradan led kodunu çıkardığımda değerler değişiyor.

  io_array[10] = TIM2->CNT;
	GPIOA->ODR ^= (0x100);
	DMA_Kopyala();
    io_array[11] = TIM2->CNT;
    io_array[12] = io_array[11]-io_array[10];


İlk denemede sizin gibi sabit bir değer almıştım. Çok saçma bir hatadan ötürü.
source dizisini 1,2,3,4,5,...n  ile doldurdum.  onu dma ile io_array dizime kopyalıyordum.Bu dizi modbus holding registerleri. Aynı diziyi hem hedef , hem de monitör olarak kullanınca, doğal olarak dma işini bitirdiğinde, monitör olarak kullandığım hücrenin içeriği de sabit bir değer oluyordu.
Benzer bir hata olabilir mi?


Ekleme:
  İşin içine kesmeleri de dahil ederek yeni bir deneme yaptım.
  Önce sayıcıyı sıfırladım. Enable yaptım.
  Dma kesmesinde de sayıcıyı okudum.
Disable yaptım.
Timer kesmesinin içinde de bir sayacın değerini artırdım ki, timer kaç kez taşmış göreyim.
DMA ile 1024 veri kopyalama ile  512 veri kopyalama ayasında  yaklaşık yarı yarıya fark ediyor.
Timer Presicaler değeririni değiştirdiğimde ,  öçüm sonucu da hemen hemen orantılı biçimde değişiyor.
bir sorun göremedim.

 

camby

Hocam ilk denemelerimde şu şekilde yapmıştım , TIM7'yi içeriği her 1ms'de 1 artacak şekilde kuruyorum ve TIM7 kesmelerini aktif hale getirmiyorum.. İstediğim işlem sonlandığında direk TIM7->CNT registerının içeriğine bakıyorum.

Fakat burada DMA_Handler kullandığımda ( başka handler'larda da aynı durum olabilir bilemiyorum şu an için ) TIM7->CNT çalışmaz hale geliyordu.

Şimdi ben de TIM7 Interrupt kullanarak deneme yaptım ve başarılı oldu denebilir . TIM7'yi 10us'de bir kesme üretecek şekilde ayarladım. Taşma sayacını DMA_Handler içinde arttırdım ve işlem bittiğinde değeri 26 olarak okudum , CNT'da kalan değer ise 7 : yani 267us.


Sonuç 1 : TIM7 Interrupt kullanınca sorun düzeldi. Interrupt kullanılmıyor iken başka bir Handler'da müdahale edince bozuluyor.

Sonuç 2 : 24 MHz STM32F100RB ile 1024 adet verinin taşınması. Yaklaşık 267us sürüyor.

===============================

Ancak sorun devam ediyor ve TIM7->CNT registerının içeriğini bazı durumlarda durdurmama rağmen okuyamıyorum yada içeriği direk kaybediyorum.

Sorun :

Aşağıda basit 2 program var , ikisinde de TIM7 kesmesi kapalı , TIM7->CNT içeriği gözleniyor , biri çalışıyor biri çalışmıyor.

İlkinde sorun yok , delay_ms(10) fonksiyonunun işlenme süresini TIM7->CNT ile gözlüyorum.

//======================== Main ===============================================

#include "stm32f10x.h"
#include "GPIO_STM32F100RB.h"
#include "SSD1963_Driver.h"
#include "delay_ms.h"

char Source[1024];
char Target[1024];

//======================== Timer7 Init ========================================
void Timer7_Init(void) 
{
	/* Timer7 clock 24 MHZ , Prescaler 24.000 -> Her 1/1000 sn(1ms)' de bir deger 1 artar.*/
	
	RCC->APB1ENR |= (1UL << 5);               	// Enable Timer7 clock   
	TIM7->CR1 = 0x0080;              			// 1: TIMx_ARR register is buffered
	TIM7->PSC = 24000-1;           				// Prescaler : 24000
	TIM7->ARR = 50000;                			// Auto-Reload : 1000
	TIM7->CR1 |= 0x0001;            			// Counter Enable

}

/*----------------------------------------------------------------------------
  MAIN function
 *----------------------------------------------------------------------------*/
int main (void) 
 {	 
	volatile int i;
	 
	char* p;
	char* z;
	 
	p = &Source[0];
	z = &Target[0];	  
 
	GPIO_Init(); 
	Initial_SSD1963();
	 
	for(i=0;i<1024;i++) Source[i]=i;  			// Source alanina datalarimizi koyalim	
 
	Timer7_Init();
	delay_ms(10);
    TIM7->CR1 &=~ 0x0001;            			// Counter disable
	lcd_veri_yaz(35,200,TIM7->CNT,1,1,255,255,255);


	while(1) 
	{						// Loop forever
	}
}



2.sinde ise DMA kullanmadan kopyalama işleminin süresini ölçmek istiyorum ancak 7212 hep aynı saçma değer geliyor. Herhangi bir kesme hiçbir şey yok , basit main içinde çalışan program sadece.

//======================== Main ===============================================

#include "stm32f10x.h"
#include "GPIO_STM32F100RB.h"
#include "SSD1963_Driver.h"
#include "delay_ms.h"

char Source[1024];
char Target[1024];

//======================== Timer7 Init ========================================
void Timer7_Init(void) 
{
	/* Timer7 clock 24 MHZ , Prescaler 24.000 -> Her 1/1000 sn(1ms)' de bir deger 1 artar.*/
	
	RCC->APB1ENR |= (1UL << 5);               	// Enable Timer7 clock   
	TIM7->CR1 = 0x0080;              			// 1: TIMx_ARR register is buffered
	TIM7->PSC = 24000-1;           				// Prescaler : 24000
	TIM7->ARR = 50000;                			// Auto-Reload : 1000
	TIM7->CR1 |= 0x0001;            			// Counter Enable

}

/*----------------------------------------------------------------------------
  MAIN function
 *----------------------------------------------------------------------------*/
int main (void) 
 {	 
	volatile int i;
	 
	char* p;
	char* z;
	 
	p = &Source[0];
	z = &Target[0];	  
 
	GPIO_Init(); 
	Initial_SSD1963();
	 
	for(i=0;i<1024;i++) Source[i]=i;  			// Source alanina datalarimizi koyalim	
 

	Timer7_Init();
	for(i=0;i<1024;i++)
	{
		*z++ = *p++;
	}
	TIM7->CR1 &=~ 0x0001;            			// Counter disable
	lcd_veri_yaz(35,200,TIM7->CNT,1,1,255,255,255);


	while(1) 
	{						// Loop forever
	}
}



Sonucu değiştirmek adına kopyalama işleminin arasına bir de delay_ms(10) koyuyorum. Çıkan sonuç bu sefer 1. program ile aynı yani 10 ms   . Kopyalama işlemi yine de yapılıyor ancak saçma TIM7->CNT içindeki değer kayboldu delay_ms(10)'un süresi gözüküyor sadece , kopyalama işlemi sorunsuz yapılıyor.

//======================== Main ===============================================

#include "stm32f10x.h"
#include "GPIO_STM32F100RB.h"
#include "SSD1963_Driver.h"
#include "delay_ms.h"

char Source[1024];
char Target[1024];

//======================== Timer7 Init ========================================
void Timer7_Init(void) 
{
	/* Timer7 clock 24 MHZ , Prescaler 24.000 -> Her 1/1000 sn(1ms)' de bir deger 1 artar.*/
	
	RCC->APB1ENR |= (1UL << 5);               	// Enable Timer7 clock   
	TIM7->CR1 = 0x0080;              			// 1: TIMx_ARR register is buffered
	TIM7->PSC = 24000-1;           				// Prescaler : 24000
	TIM7->ARR = 50000;                			// Auto-Reload : 1000
	TIM7->CR1 |= 0x0001;            			// Counter Enable

}

/*----------------------------------------------------------------------------
  MAIN function
 *----------------------------------------------------------------------------*/
int main (void) 
 {	 
	volatile int i;
	 
	char* p;
	char* z;
	 
	p = &Source[0];
	z = &Target[0];	  
 
	GPIO_Init(); 
	Initial_SSD1963();
	 
	for(i=0;i<1024;i++) Source[i]=i;  			// Source alanina datalarimizi koyalim	
 
	Timer7_Init();
	delay_ms(10);
	for(i=0;i<512;i++)
	{
		*z++ = *p++;
	}
	TIM7->CR1 &=~ 0x0001;            			// Counter disable
	lcd_veri_yaz(35,200,TIM7->CNT,1,1,255,255,255);


	while(1) 
	{						// Loop forever
	}
}