STM32F4 usart 3 tx interrupt ile karşıya veri gönderimi

Başlatan alper0017, 13 Şubat 2013, 15:16:41

alper0017

Merhaba herkese.Bildiğiniz üzere rx interrupt'u kolaylıkla yapabiliyoruz fakat kimse tx interrupt üzerinde durmamış.Loop içersinde veri gönderimi yaptığımız zamanlarda baud rate'imiz küçük rakamlardaysa döngüde gereksiz beklemelere sebep olmaktadır.Bu sorunu çözmek için göndericeğimiz değerleri bir buffer'e atıp oradan tx interrupt ile göndermek istemekteyiz.Bununla ilgili çok fazla kod yazmayı denedim fakat başarılı olamadım.Bu sorunu çözenler varsa ve yardımcı olurlarsa çok sevinirim


alper0017

Yazmış olduğunuz cevap için öncelikle teşekkür ediyorum fakat kodunuzda bazı sıkıntılar var.Yazmış olduğunuz kodu Real Time olarak denedim ve hala gecikmeye neden olan bitakım şeylerin olduğunu sezdim.Daha sonra kodu detaylı bir şekilde inceledim.Gönderimin tamamlanması için bekle şeklinde yazdığınız while(!send_ok); kod parçacığı ana döngüyü bekletmektedir.Loop süresinde bi değişme olmadı.

while(!send_ok);  yerine başka bir şey kullanılmalıki, loop verinin gidip gitmediğini denetlemekle uğraşmamalı.Bu durumda kesmenin bir manası kalmamış malesef.Yinede emeğinize sağlık.Kendi kodlarımı paylaşmak isterim.

void USART3_IRQHandler(void)
{
	//RX Interrupt
  if (USART_GetITStatus(USART3, USART_IT_RXNE) != 0)
  {
	usart3_buffer_rx[get_usart3]=USART_ReceiveData(USART3);
	get_usart3++;
		if(get_usart3==500)
		get_usart3=0;
		
	Encrypted_Read();
  }
	//RX Interrupt
	
	
	//TX Interrupt
	if(tx_flag==1)
	{
		for(put_usart3=0;*(usart3_buffer_tx+put_usart3)!=0;)
		{
			if(USART_GetFlagStatus(USART3,USART_FLAG_TXE)!=0)
			{
			USART_SendData(USART3,usart3_buffer_tx[put_usart3]);
			put_usart3++;
			}
		}
	tx_flag=0;
	USART_ITConfig(USART3,USART_IT_TXE,DISABLE);
	USART_ITConfig(USART3,USART_IT_TC,ENABLE);
	}

  if(USART_GetITStatus(USART3,USART_IT_TC))    			 // Son bit de yerine ulasti mi? 
	{
    USART_ITConfig(USART3,USART_IT_TC,DISABLE);			 // Verimizin tümü gitti Artik TC bayragina da ihtiyaç yok.
    USART_ClearITPendingBit(USART3,USART_IT_TC);
    send_ok=1;
  }
	//TX Interrupt
}

	void USART_Write_Text(USART_TypeDef* USARTx,char *Adr)
	{		
		if(tx_flag==0)
		{	
		send_ok=0;
		tx_flag=1;
			
 			for(put_usart3=0;put_usart3!=50;put_usart3++)
 			usart3_buffer_tx[put_usart3]=0;
			
   		for(put_usart3=0;*(Adr+put_usart3)!=0;put_usart3++)
   		usart3_buffer_tx[put_usart3]=*(Adr+put_usart3);
			
		USART_ITConfig(USARTx,USART_IT_TXE,1);
		while(!send_ok);
		}
	}

	void loop(void)
	{
	USART_Write_Text(USART3,"S. ");
	USART_Write_Text(USART3,"ALPER ");
	USART_Write_Text(USART3,"OGAN\n\r");
	}

SERRO EFE

Klein in kodlarında while kullanma sebebi bekleme yapmak değil arka arkaya veri gönderdiğinde data karışmasını önlemek. O örnek sadece tx kesmesinin nasıl kullanılacağına örnek teşkil eder. Amaca uygun düzenlemelerle gayet güzel çalışır.

Klein

Oradaki  "while(!send_ok);" Verinin gidip gitmesini beklemek için değil.
Örnek kodda  fonksiyonun farklı şekillerde ve farklı verilerle nasıl kullanıldığınıgöstermek için, peşpeşe sıralanması gerekliydi. Kodu çalıştıracaklar biri bitmeden  diğer veri bloğunun gönderilemeyeceğini daha kolay kavrasın diye while döngüsü koydum.

Sisin düzenlediğiniz koda baktığımda while döngüsünü USART_Write_Text() fonksiyonunun içine aldığınızı görüyorum. Kesinlikle hatalı.

if(send_ok) USART_Write_Text(USART3,"S. ");

SERRO_EFE açıklamış. Ben yazarken gelmiş görmedim.

alper0017

while(send ok) komutunu write_text fonksiyonu ile loop fonksiyonunda kullanmamın farkı nedir?Çünkü write_text fonksiyonunu zaten loop içersinde kullanıyoruz.

SERRO_EFE amaca uygun düzenlemeye çalıştım fakat bekleme yapmadan sağlıklı veriler alamıyorum.While(send ok) komutu hernekadar bekleme yapılması amacıyla yapılmasada beklemeye sebep oluyor.Bu beklemeyi engelleyebilecek ne uygulanabilir?Aklıma gelmiyor şuan için

Klein

Alıntı yapılan: alper0017 - 13 Şubat 2013, 17:40:42
while(send ok) komutunu write_text fonksiyonu ile loop fonksiyonunda kullanmamın farkı nedir?Çünkü write_text fonksiyonunu zaten loop içersinde kullanıyoruz.

SERRO_EFE amaca uygun düzenlemeye çalıştım fakat bekleme yapmadan sağlıklı veriler alamıyorum.While(send ok) komutu hernekadar bekleme yapılması amacıyla yapılmasada beklemeye sebep oluyor.Bu beklemeyi engelleyebilecek ne uygulanabilir?Aklıma gelmiyor şuan için

Fark var.  Çünkü bu fonksiyon ilgili registerlere gerekli veriyi yazıyor ve işi bitiyor. Bu fonksiyonun içinde bekleme yapılmasının hiç bir anlamı yok.
Dışarıda bekleme yapmak ta anlamsız. Ama en azından isteğe bağlı. Duruma göre bekleme yaparsınız ya da yapmazsınız. Fonksiyon içerisinde olunca her şart altında bekleme yapıyorsunuz.

İşin özüne gelirsek, İçeride ya da dışarıda  bekleme yapmak, zaten bu örnekte  gösterilmeye çalışılan kesme kullanımının özüne aykırı.
Interrupt  ya da DMA  kullanmaktaki amaç;  yüksek miktarda veriyi  işlemciye yük bindirmeden gönderebilmek.
Senin örnekte yapmaya çalıştığın gibi, loop hızında istediğin zamanda istediğin kadar veriyi göndermek  değil.  Kodlarda görüldüğü gibi loop hızında  veri göndermek,loop hızın haberleşme hızından yüksek olduğu sürece mümkün değil.

Gönderecek mesajların önceden tanımlı , sayısı belli ise:
switch-case ile veya  dizileri peş peşe göndermekyerine , büyük bir tampon kullanıp yeni veriyi tamponun sonuna eklemek suretiyle istediğin şey mümkün olabilir. Ama veri sabit değil duruma göre değişiyor ve  tampoun boşalıp boşalmadığını kontrol edemem , veri hazır olur olmaz hiç birşeyi beklemeden göndermem gerekir dersen olmaz.
Olur ama, tüm verilerine yetecek kapasitede  scheduler yazman gerekir.


Amacın yazdığın kodaki gibi

mesaj birleştirme:: 13 Şubat 2013, 20:20:09

sabit sayıda önceden tanımlı mesaj gönderimine basit bir örnek.

void msg_loop(void)
{
uint16_t pc;
    switch(pc){
      case 0:
         if(send_ok)
         {
             USART_Write_Text(USART3,"S. ");
             pc++;
         }     
         break;
      case 1:
         if(send_ok)
         {
             USART_Write_Text(USART3,"ALPER ");            
              pc++;
         }     
         break;
      case 2:
         if(send_ok)
         {
             USART_Write_Text(USART3,"OGAN\n\r");
             pc=0;
         }     
         break;
   }
}

int main(void)
{

while(1)
{
  msg_loop();
}

alper0017

Klein, tam da bahsettiğin şeyler söylemek istediklerim.Derdimi anlatabilecek birini bulmama sevindim fakat bu sorunu çözmek zaman alıcak gibi.Bunun yerine kullandığım bluetooth modulünü programlayıp baud-rate yükseltmesi yaptım.Şuan 1.384 mbit/s hız kullanıyorum.Böylesi daha pratik oldu.Zaman içersinde bahsettiğimiz sistemide araştıracağım, daha doğrusu araştırmaya devam edeceğim.Bilgilerimi, kodlarımı sitede paylaşırım.İlgin için Teşekkür Ederim.İyi akşamlar diliyorum.

Ege University E.E Engineering
ALSA Technology
S.Alper Oğan

LukeSkywalker

Sizin için tek yol DMA kullanmak gibi gözüküyor. Her halukarda  TX bufferının boşalması beklenecek.

Klein

DMA'da kullansa olmaz. Bu sefer de DMA'nın işinin bitmesi beklenecek.
görünen en iyi yol,  scheduler yazmak.

haydarpasamikro

#10
RTOS veya bir Txbuffer ve paket sayacı. Her tx kesmesinde kesme içerisinde sadece çağrılan bir fonksiyon. Her byte transferi sonunda bir sonraki byte buffera yüklenir. Taki paket sayaci sifira dusene kadar. Siz kesmeden çıkınca yeni yeni byte ile tekrar kesme oluşacak. Böylece siz başka işlerle uğraşın. Ayrıca set pending interrupt gibi manuel yolla kesmelerin dizginlerini elinize alarakta halledebiliriz.

mesaj birleştirme:: 13 Şubat 2013, 22:16:59

Ayrica biraz daha zaman kazanmak için tx shift reg e aktarılır aktarilmaz buffer yeni byte ile beslenebilir.
Mikro Dünyası.Haydarpaşa Teknik ve Endüstri Meslek Lisesi Mikrodenetleyici Atl. Şefi

LukeSkywalker

TC kesme ürettiğinde register boşalmış oluyor, TXE  ise buffer boşaldığında kesme üretiyor değil mi?
@Klein hocam sizin örneğinizde dizi 28 elemanlı, fakat ilk stringi (28 baytlık) sanki bir eleman eksik gönderiliyor gibi anladım, yanlış mıyım?

Klein

Evet TC  Veri gönderimi tümden bitince , TXE de tampondaki bilgi donanıma aktarılınca üetiliyor.

28 baytlık text yazıp , 27 baytını göndermişim. Muhtemelen sayarken hata yapmışım.