stm32f103c8t6 vektör tablosu içerisindeki handler fonksiyonunu değiştirme

Başlatan Emre_Tuncay_, 03 Ekim 2021, 01:37:40

Emre_Tuncay_

stm32f103c8t6 için uart,spi,i2c gibi çevre birimleri için kendi sürücümü geliştiriyorum. Projemi cube ide'de oluşturdum. Amacım uart kesmesi oluştuğunda programın USART1_IRQHandler isimli fonksiyona dallanması yerine kendi yazdığım başka bir fonksiyona dallanmasını sağlamak. Bunun için nvic vektör tablosundaki uart için ayrılmış olan USART1 global interrupt adresinin belirttiği fonksiyonun pointer değerini değiştirmek. Bu adreste hali hazırda USART1_IRQHandler  isimli fonksiyonun adresi bulunuyor.

Vektör tablosundaki ilgili adrese kendi yazdığım fonksiyonun adresini yazmaya çalıştığımda yapmak istediğim şeyde başarılı olamadım. Nasıl bir yöntem izlemeliyim.

z

Vectorler icin ramda yer ayarla ve bu alana vektorleri yaz. Vektor tablom flashda degil ramda de.

Daha sonra ramdaki vektor tablosunda istedigin adresi degistirebilirsin.

Eger zaten bir fonksiyon yazilmis ve buna dokunmadan sen kendi fonksiyonunun calismasini istiyorsan vektorleri Rama tasimaktan baska cozum yok gorunuyor.

Vector tablusunu aynen Rama kopyala, tabloda gerekli degisiklikleri yap.
Interruptlari yasakla
Vektor tablosunun adresini Ramdaki Vektor tablosunun adresi tanmla.
Interruptlari ac
Bana e^st de diyebilirsiniz.   www.cncdesigner.com

MrDarK

Vector tabloları startup asm dosyasında bulunuyor. Onun dışında yapmak istediğin şey için uart int fonksiyonu içindeki hal kütüphanesinin yönlendirmesini yorum satırına alıp kendi fonksiyonunu koyabilirsin.
Picproje Eğitim Gönüllüleri ~ MrDarK

Cemre.

Zaten CubeMX kullanarak projeyi init edecekseniz, kendi ilgili fonksiyonunuzu CubeMX tarafından oluşturulan fonksiyon içerisinde çağırmanız her seferinde bu detaylarla uğraşmamanız adına daha verimli olacaktır bence...

Emre_Tuncay_

Cube ide nin oluşturduğu HAL handler fonksiyonunu yorum satırına alırsam kodu her generate etmemde cube ide yorum satırını kaldıracaktır ve benim her seferinde oraya gidip yorum satırı eklemem gerekecektir. Bu durum çok iş yükü oluşturacak bir durum değil aslında ama bence kod kalitesini bozan bir durum. (Bu durumu engellemek için belki bir ayar olabilir o kısımı tam bilmiyorum)

Startup dosyası üzerinde değişiklik yapmayı deneyeceğim.

Z hocam vektör tablosunu RAM üzerinden çalıştırmakta mantıklı geldi bayağı. Bunun RAM'de ayarladığımız vektör tablosunun üzerinde eski vektör tablosunu bire bir yazmam gerekecek sanırım sonrada değiştirmek istediğim kısmı değiştirip VTOR register'ında offset değerini vermem gerekecek diye tahmin ediyorum. Bunuda deneyeceğim.


z

Alıntı Yap...Bunun için nvic vektör tablosundaki uart için ayrılmış olan USART1 global interrupt adresinin belirttiği fonksiyonun pointer değerini değiştirmek...

Burda ne demek istedigini anlamadim. nvic vector tablosu diye ayri bir tablo mu var?
Bana e^st de diyebilirsiniz.   www.cncdesigner.com

Emre_Tuncay_

NVIC vektör tablosu doğru bir tanımlama olmadı sanırım, vektör tablosundan bahsetmiştim. Vektör tablosunun USART1 global interrupt kısmını tanımlayan adresin içerdiği değere baktığımda USART1_IRQHandler() kesme fonksiyonunun adresini içerdiğini gördüm. Bende basitçe bu adrese dallanmasını istediğim yeni fonksiyonun adresini yazarsam o fonksiyona dallanır diye düşündüm. Bundan bahsetmiştim.



z

Evet dogru dusunmussun. Startup dosyasinda vektor tablosuna kendi fonksiyonunun adresini yazarsan olur.

Ha yalniz bu isi sen yapiyorsan adresin en dusuk bitini 1 yapmayi unutma. Fonksiyon cift adreslere yerlesir ama vektor tablosuna tek adres yazacaksin.
Bana e^st de diyebilirsiniz.   www.cncdesigner.com

Emre_Tuncay_

Bu işe biraz ara vermiştim bu hafta sonu çözeyim dedim bayağı bir uğraştırdı beni çözünce birisi faydalanır diye buraya yazayım dedim.
Flash'da tanımlı vektör tablosunu değiştiremeyince vektör tablosunu RAM'e taşımaya ardından da ramde tanımlı olan vektör tablosunun ilgili kısmını değiştirmeye karar verdim.

İlk olarak bir vektör tablosu tanımlamak gerekiyor (tanımlama işlemini yaparken önemli bir ayrıntı var onu sona bırakıyorum :) )

Stm32f103 medium density kullanıyorum ve aşağıdaki referance manuelde tüm vektörler 199. sayfada verilmiş bende bu vektör tablolarını barındıran bir struct oluşturdum.

typedef struct
{
//içi uzun olacağı için boş bıraktım aşağıdaki linkten bakabilirsiniz.
}f103_medium_density_vector_table_t;

https://www.st.com/resource/en/reference_manual/cd00171190-stm32f101xx-stm32f102xx-stm32f103xx-stm32f105xx-and-stm32f107xx-advanced-arm-based-32-bit-mcus-stmicroelectronics.pdf

Ardından vektör tablosunu struct tipinde tanımladığım değişkene yazdım. Bunuda aşağıdaki kod ile yaptım.

for(uint16_t i = 0; i < sizeof(f103_medium_density_vector_table_t)/4; i++)
{
  ((uint32_t*)&vector_table) = *((uint32_t*)((f103_medium_density_vector_table_t*)(void*)(SCB->VTOR + i*4)));
}

Ardından  aşağıdaki kod parçası ile yeni vektör tablosu nu SCB->VTOR'a yazdım.

__disable_irq();
SCB->VTOR = (uint32_t)&vector_table;
__enable_irq();

Buraya kadar herşey doğru olmasına rağmen çalışmadı ve beni 2 günlük bir araştırma yapmama neden oldu.
Çalışmamasının nedeni ise  aşağıdaki dökümanda 133. sayfada anlatılıyor. VTOR register'ının ilk 7 biti 0 olması gerekiyor.

https://www.st.com/resource/en/programming_manual/cd00228163-stm32f10xxx-20xxx-21xxx-l1xxxx-cortex-m3-programming-manual-stmicroelectronics.pdf

Ama bunu nasıl yapacağımı bulamamıştım. Çünkü bir değişken tanımladığımda boşta olan bir adrese tanımlanıyor bu adresin ilk 7 biti 0 olmayabiliyor bu nedenden VTOR registerına ilk 7 biti sıfır olan bir adres yazamıyordum. Ve mcu bir kesme olduğunda hardfault'ta düşüyordu.

Bunu yapabilmek için tanımladığımın vektör tablosunun başına bir attribute yazmam gerekiyormuş o da şu şekilde

f103_medium_density_vector_table_t vector_table __attribute__(( aligned (128) ));
_attribute__(( aligned (128) )) = bu kısım sayeesinde tanımadığım vektör tablosunun adresinin ilk 7 biti sıfır oldu bu sayede vektör tablom ram'de tanımlanmış oldu.

Ardından yazdığım uart driver'ında olan yeni kesme vektörümün adresini ram'deki vektör tablosuna yazdım.




Tagli

Araya ufak bir not düşeyim: STM32F0 gibi Cortex M0 çekirdekli bir işlemci ile çalışıyorsanız büyük ihtimalle VTOR özelliği olmayacak. Bu çiplerde adres 0'ı flash'a değil de RAM'a bağlamak (mapping) mümkün olabiliyor. Vektör tablosu için linker script'te RAM'in başında bir section oluşturup tabloyu tutacak array'ı bu section'da oluşturmak gerekiyor.
Gökçe Tağlıoğlu

kimlenbu

Neden bu kadar uğraştığını anlamadım. CubeMX'de interrupt'ı aktif ettikten sonra ***_it.c dosyasında handler fonksyionu oluşturuluyor. Hal library handler'ı sadece flagların düzgün resetlenmesini sağlıyor.

Bu handlerdan önceki 

/* USER CODE BEGIN USART3_IRQn 0 */

 /* USER CODE END USART3_IRQn 0 */

alanına kendi handler'ını ekleyip flagları da kontrol edersin, gerekli işlemleri de yapabilirsin. Biraz kitaba göre olmaktan çıkıyor ama daha kolay.

Örnek yapı :

void USART3_IRQHandler(void)
{
  /* USER CODE BEGIN USART3_IRQn 0 */
	
				if(__HAL_UART_GET_FLAG(&huart3, UART_FLAG_IDLE)!=RESET){
				__HAL_UART_CLEAR_IDLEFLAG(&huart3); 
//				USER_UART3_IDLECallback();
//				HAL_UART_DMAPause(&huart3);
//				HAL_UART_DMAStop(&huart3);
//				USER_UART3_IDLECallback(); dIKKAT TIMER OLMAZSA BURAYI AC
					__HAL_TIM_SET_COUNTER(&htim7, 0); //DIKKAT TIMER OLMAZSA BURAYI KAPAT
					HAL_TIM_Base_Start_IT(&htim7);
				//InputBDataReady=1;
				
			}

  /* USER CODE END USART3_IRQn 0 */
  HAL_UART_IRQHandler(&huart3);
  /* USER CODE BEGIN USART3_IRQn 1 */
	


  /* USER CODE END USART3_IRQn 1 */
}

Tagli

Alıntı yapılan: kimlenbu - 13 Aralık 2021, 11:05:24Neden bu kadar uğraştığını anlamadım.

@kimlenbu , kendi kütüphanelerini oluştururken bu gerekebiliyor. Aynı ihtiyacı ben de hissettim ve kendi projelerimde de uyguluyorum.

Ama daha çok bootloader yazanlar buna ihtiyaç duyuyor gördüğüm kadarıyla. Ben o olaya girmedim hiç.
Gökçe Tağlıoğlu

Emre_Tuncay_

@kimlenbu Uğraştığımı kabul ediyorum olayı basit olarak dediğiniz gibi çözebilirdim. Ama benim ihtiyacım bu şekilde çözmek değildi.

Kendi kod standartıma uygun C++ driver'ları geliştiriyorum elimin altında ilerde ticari olarakta kullanabileceğim hatta platform bağımsız olmasını istediğim çevresel birim driver'ları olsun istiyorum. Bu driver'ların olabildiği kadar HAL kütüphanelerinden bağımsız olmasını istiyorum. Bu iş ile tamamen bağımsız bir kaç driver geliştirdim bile.

Öbür türlü yazdığım driver'ın bir parçası HAL kütüphanesi içerisinde bir yerde kod çalıştırması gerekecekti buda kaliteli bir iş ve temiz bir kod olmayacaktı.

Bu kodu ufak değişiklikler yaparak NXP'nin cortex M3 çekirdeğine sahip bir MCU'sundada kullanabilirim mesela.

Ama biraz da tercih meselesi sizin dediğiniz yönteminde avantajları var tabi ki.

Cevaplarınız için teşekkürler.