Rtos task

Başlatan mr.engineer, 08 Mayıs 2020, 17:10:38

mr.engineer

Merhaba,
Aşağıda basit şekilde iki tane task oluşturup, (ikisi de aynı önceliğe sahip) çalıştırıyorum. İkisi de fonksiyonda yazılan stringleri uart ile bilgisayara yolluyor.

void vTask1( void *pvParameters )
{
const char *pcTaskName = "Task 1 is running\r\n";
volatile uint32_t ul; /* volatile to ensure ul is not optimized away. */
	/* As per most tasks, this task is implemented in an infinite loop. */
	for( ;; )
	{
	/* Print out the name of this task. */
		HAL_UART_Transmit(&huart2, (uint8_t*)pcTaskName, sizeof(pcTaskName),100);
		//HAL_UART_Transmit_IT(&huart2,(uint8_t*)pcTaskName, sizeof(pcTaskName)); 
	/* Delay for a period. */
		osDelay(100);
	}
}


void vTask2( void *pvParameters )
{
const char *pcTaskName = "Task 2 is running\r\n";
volatile uint32_t ul; /* volatile to ensure ul is not optimized away. */
/* As per most tasks, this task is implemented in an infinite loop. */
for( ;; )
{
/* Print out the name of this task. */
HAL_UART_Transmit(&huart2, (uint8_t*)pcTaskName, sizeof(pcTaskName),100);
/* Delay for a period. */
osDelay(100);
}
}

Normalde şu şekilde bir output bekleniyor

Task 1 is running
Task 2 is running
Task 1 is running
Task 2 is running

Fakat bende çıkan sonuç şu:
TaskTaskTaskTaskTaskTaskTaskTask......

Benim anladığım iki task arasındaki geçişler çok hızlı ve bir stringi tamamen gönderemiyor. Yani her iki task da "Task" ile başladığından sadece ilk 4 karakter yani "Task" yollanıyor. Fakat anlamadığım şey Task2 bitip tekrar Task1'e dönüldüğünde stringi kaldığı yerden göndermeye devam etmesi gerekmiyor mu? Yani "Task 1 is running" cümlesinde "1 is running" yazısını da yollaması gerekmez mi? Buradaki sıkıntı nedir? HAL_UART fonksiyonu ile alakalı olabilir mi?

Tagli

HAL_UART_Transmit() fonksiyonu thread-safe (veya bir başka ifade ile re-entrant) olmadığı için her türlü acayiplikle karşılaşabilirsin. Bu fonksiyona aynı anda iki task (thread) erişmemeli. Bunun için de bir mutex oluşturmalı ve bu fonksiyona mutex koruması altında erişmelisin.
Gökçe Tağlıoğlu

mr.engineer

Alıntı yapılan: Tagli - 08 Mayıs 2020, 19:51:54HAL_UART_Transmit() fonksiyonu thread-safe (veya bir başka ifade ile re-entrant) olmadığı için her türlü acayiplikle karşılaşabilirsin. Bu fonksiyona aynı anda iki task (thread) erişmemeli. Bunun için de bir mutex oluşturmalı ve bu fonksiyona mutex koruması altında erişmelisin.

Mutexi bilmiyordum daha yeniyim. Bir çeşit semafor, flag gibi çalışıyor. Yani stringi tamamen yollayana kadar task'den çıkmasını engelliyoruz.
HAL_UART (kesmesiz) fonksiyonunun thread-safe olması nedir bilmiyorum ileride kitap bahsediyor ordan bakarım.

Peki HAL kütüphanesini kullanmasam register seviyesinde kodlayıp stringleri o şekilde yollasam bu sorun ortadan kalkar mı? Yani task kaldığı yerden devam edip stringin kalanını yollar mı? Bu durumda mutex falan kullanmaya gerek kalmaz heralde.

Tagli

Alıntı yapılan: mr.engineer - 08 Mayıs 2020, 21:18:55Peki HAL kütüphanesini kullanmasam register seviyesinde kodlayıp stringleri o şekilde yollasam bu sorun ortadan kalkar mı?
Muhtemelen hayır, yine olmaz. Kendi fonksiyonunu her seferinde 1 byte gönderecek şekilde yazarsan belki. Ama uğraşmaya değmez. Mutex kullanmak gözde büyütülecek bir şey değil.

Alıntı yapılan: mr.engineer - 08 Mayıs 2020, 21:18:55Yani stringi tamamen yollayana kadar task'den çıkmasını engelliyoruz.
Hayır, bu şekilde çalışmıyor. Mutex bir critical section tanımlamanı sağlıyor. O bölgeye ilk varan thread (A diyelim) işini bitirip oradan çıkana kadar başka bir thread (B diyelim) aynı bölgeye giremiyor. A işini bitirmeden B çalışmaya başlayabilir belki, ama kritik bölgeye vardığında ilerleyemez ve RTOS tarafından bloklanır, yerine bir başka thread çalışır (belki tekrar A, veya belki C).
Gökçe Tağlıoğlu

mufitsozen

sorunu yanlis teshis ettiniz, tasklar, suresi vsde bir problem yok. dizi boyutu olarak " sizeof(pcTaskName)" yazmissiniz. Bu degisken pointer ve boyuda 4 byte. Buraya dizinin boyunu (mesela strlen fonksiyonu ile) vermelisiniz. Hep ilk 4 karakteri yaziyorsunuz.
Aptalca bir soru yoktur ve hiç kimse soru sormayı bırakana kadar aptal olmaz.

yamak

Doğru olan @Tagli'nin dediği gibi. Mutex ile ya da critical section ile korumanız gerekir.Ama iki task da aynı priority de ise scheduling algoritması priority scheduling ise(Round Robin vs değil ise) yine düzgün çalışması gerekir aslında. Aynı priority de olduklarından dolayı os delay den önce context switching olmaması gerekir.

Ama dediğim gibi doğru olan @Tagli nin dediği gibi olması. Aynı priority de olsa mutex ile korumak gerekir her ihtimale karşı.

yamak

Alıntı yapılan: mufitsozen - 08 Mayıs 2020, 22:07:46sorunu yanlis teshis ettiniz, tasklar, suresi vsde bir problem yok. dizi boyutu olarak " sizeof(pcTaskName)" yazmissiniz. Bu degisken pointer ve boyuda 4 byte. Buraya dizinin boyunu (mesela strlen fonksiyonu ile) vermelisiniz. Hep ilk 4 karakteri yaziyorsunuz.
Evet. Ben dikkat etmedim açıkçası asıl sorun bu. Eğer algoritma priority scheduling ise düzgün çalışması gerekir.

mr.engineer

Alıntı yapılan: mufitsozen - 08 Mayıs 2020, 22:07:46sorunu yanlis teshis ettiniz, tasklar, suresi vsde bir problem yok. dizi boyutu olarak " sizeof(pcTaskName)" yazmissiniz. Bu degisken pointer ve boyuda 4 byte. Buraya dizinin boyunu (mesela strlen fonksiyonu ile) vermelisiniz. Hep ilk 4 karakteri yaziyorsunuz.


Evet, asıl hata buradaymış, teşekkürler. Pointerı diziye çevirince düzeldi. Şu an doğru bir şekilde çalışıyor.


Alıntı yapılan: Tagli - 08 Mayıs 2020, 21:41:40Muhtemelen hayır, yine olmaz. Kendi fonksiyonunu her seferinde 1 byte gönderecek şekilde yazarsan belki. Ama uğraşmaya değmez. Mutex kullanmak gözde büyütülecek bir şey değil.
Hayır, bu şekilde çalışmıyor. Mutex bir critical section tanımlamanı sağlıyor. O bölgeye ilk varan thread (A diyelim) işini bitirip oradan çıkana kadar başka bir thread (B diyelim) aynı bölgeye giremiyor. A işini bitirmeden B çalışmaya başlayabilir belki, ama kritik bölgeye vardığında ilerleyemez ve RTOS tarafından bloklanır, yerine bir başka thread çalışır (belki tekrar A, veya belki C).

Teşekkürler, şimdilik burada çalıştığına göre  mutexe ihtiyaç kalmadı bu örnek için.

Hatayı çözmeye çalışırken şöyle bir şey düşündüm. Aşağıdaki define tick periodu veriyor, yani periodum 1 ms. Yolladığım string uzunluğu ise 18 byte ve baud rate 38400. Yani bu stringin tamamen iletilmesi yaklaşık 4ms sürüyor, fakat benim tick periodum 1ms yani bu string gönderilmeden diğer taske geçmem gerekir ve outputun hatalı olması gerekir. Şu an outputu doğru alıyorum ama bu hesaba göre düzgün çalışmaması gerekiyor bana göre :)
Yanlış bildiğim yer nedir burada?


#define configTICK_RATE_HZ   ((TickType_t)1000)

yamak

Alıntı yapılan: mr.engineer - 08 Mayıs 2020, 23:10:55Evet, asıl hata buradaymış, teşekkürler. Pointerı diziye çevirince düzeldi. Şu an doğru bir şekilde çalışıyor.


Teşekkürler, şimdilik burada çalıştığına göre  mutexe ihtiyaç kalmadı bu örnek için.

Hatayı çözmeye çalışırken şöyle bir şey düşündüm. Aşağıdaki define tick periodu veriyor, yani periodum 1 ms. Yolladığım string uzunluğu ise 18 byte ve baud rate 38400. Yani bu stringin tamamen iletilmesi yaklaşık 4ms sürüyor, fakat benim tick periodum 1ms yani bu string gönderilmeden diğer taske geçmem gerekir ve outputun hatalı olması gerekir. Şu an outputu doğru alıyorum ama bu hesaba göre düzgün çalışmaması gerekiyor bana göre :)
Yanlış bildiğim yer nedir burada?


#define configTICK_RATE_HZ   ((TickType_t)1000)
Hocam yukarıda bundan bahsettim aslında.
İki taskın priority si eşit olduğu için bu dediğiniz olmuyo. Priority ler değiştirirseniz bu durumu yaşarsınız.

Aslında her 1 ms de bir scheduler çalışıyo. Ama iki task aynı önceliğe sahip olduğu için context switching olmuyo.

mr.engineer

Alıntı yapılan: yamak - 08 Mayıs 2020, 23:18:28Hocam yukarıda bundan bahsettim aslında.
İki taskın priority si eşit olduğu için bu dediğiniz olmuyo. Priority ler değiştirirseniz bu durumu yaşarsınız.

Aslında her 1 ms de bir scheduler çalışıyo. Ama iki task aynı önceliğe sahip olduğu için context switching olmuyo.

Bunu bilmiyordum kitapta yazılan şey her time slice da yani her tick interrupt da schedular diğer task a geçtiğini söylüyor. Peki neye göre ya da ne zaman diğer task'a geçiyor?
Yukarıda osdelay'den önce switching olmaz demişsiniz. Yani osdelay'den sonra fonksiyon(task) tamamen bittikten sonra mı diğer task a geçiş yapılıyor?

yamak

#10
Preemptive Scheduling için konuşuyorum,

Hocam her tick interruptı ile scheduler çalışır.Scheduler, bekleyen tasklara(Ready List'teki tasklara) bakar,eğer o an çalıştırılan tasktan daha yüksek öncelikli bir task varsa onu çalıştırır.

osDelay fonksiyonu çağırıldığında tick interruptı gelmemiş olsa bile, osDelay'i çağıran task, suspend edilir ve scheduler çağırılır. Yine Ready List'teki tasklara bakılır en yüksek öncelikli olan çalıştırılır.Eğer Ready List boşsa, Ready List'te bir task eklenene kadar Idle Task çalıştırılır.

mufitsozen

Hangi rtos'u kullaniyorsunuz.

Son mesajlarda timer/priority ile aciklamalar dogru degil.

referansiniz nedir?
Aptalca bir soru yoktur ve hiç kimse soru sormayı bırakana kadar aptal olmaz.

mr.engineer

Anladım hocam bizde priorityler aynı. Şu an bir task1'in içine 3 string daha ekleyip onları da uart ile yollayarak çalıştırmayı denedim ve oldu. Tüm stringler başarılı bir şekilde yollanıyor. Hangi scheduling'i kullandığımı bilmiyorum ama priorityler aynıyken her task bitene kadar bekleniyor ve diğerine geçiliyor.

Yani dediğiniz gibi frekans değiştirme olayı schedular çalışma şeklinden dolayı, aynı prioritye sahip taskler için bir şey değiştirmiyor.

mr.engineer

#13
Alıntı yapılan: mufitsozen - 09 Mayıs 2020, 00:10:07Hangi rtos'u kullaniyorsunuz.

Son mesajlarda timer/priority ile aciklamalar dogru degil.

referansiniz nedir?

FreeRtos
Mastering the FreeRTOS™ Real Time Kernel kitap da bu yani ben anladığımı yazdım fakat burada tartıştığımız kısımla ilgili bir şey yazılmamış ama tüm kitabı okumadım.

yamak

Alıntı yapılan: mufitsozen - 09 Mayıs 2020, 00:10:07Hangi rtos'u kullaniyorsunuz.

Son mesajlarda timer/priority ile aciklamalar dogru degil.

referansiniz nedir?
Bana mı soruyosunuz hocam?