Merhaba,
Bugünkü yazımızda daha önce yapmış olduğumuz UART kesmelerine ek olarak HAL kütüphanesi kullanmadan ve UART registerlarına erişim sağlayarak nasıl veri alımı gerçekleştireceğimizi irdeleyeceğiz. Her zaman işaret ettiğimiz üzere öncelikle Google üzerinden elimizde uygulamalarımızı gerçekleştirdiğimiz kartın referans dokümanına erişim sağlamamız gerekmektedir. Bu doküman daha önce elde ettiğimiz dokümanlara göre bir miktar farklı olacaktır. Bunun nedeni çok daha uzun ve her bir birime ait register bilgilerini içeriyor olmasıdır. Şimdi ilk adımımız Google’ a “stm32f7xx reference manual” yazarak muhtemelen ilk sıralarda çıkacak olan dokümanı indirmektir. Burada dikkat etmeniz gereken eğer benim gibi 7 serisi bir işlemci ile çalışmıyorsanız buna uygun arama yapmanız gerektiğidir (Örneğin STM32F303 ise stm32f3xx reference manual şeklinde arama yapmalısınız ?).
Dokümanın içerisinde bulunan Universal Synchronous/Asynchronous Receiver Transmitter başılığı altında bulunan bilgileri okuyarak her registera ait her bitin ne işe yaradığını öğrenebilirsiniz. Uygulamaya bağlı kalmak amacıyla burada bulunan ISR (Interrupt and Status Register) ve CR1 (Control Register 1) registerlarına göz atalım.
Burada bulunan RXNE bitinin durumu uygulamamız için önem arz etmektedir. Bu nedenle bu bite ait durumu kontrol etmek adına iki farklı yolu seçme şansımız bulunmaktadır. İlki diğer bitleri maskeleyip bu bitin durumunu kontrol etmek, ikincisi ise bu maskeleme işlemini bizim yerimize yapan USART_ISR_RXNE macrosunu kullanmaktır.
Control Register 1 için ise Şekil 2’ de göreceğiniz 5 numaralı bit olan RXNEIE (Interrupt Enable) bitinin durumunu uygulamamızda kontrol etmeliyiz. Aynı şekilde maskeleme işlemi yapabilir ya da USART_CR1_RXNEIE macrosunu kullanabilirsiniz. Uygulamamızda macroları kullanarak işimizi kolaylaştırmayı planlıyoruz. ?
Uygulamamızda bizim için bir diğer önemli register ise UART kanalı ile okunan verinin kaydedildiği data registerıdır. Bu register Şekil 3’te gösterildiği üzere 8 bitlik bir alanda gelen veriyi tutmaktadır. Bu registerı okuyarak gelen veriyi bir buffer içerisinde tutacağız.
Daha önce CubeMX üzerinde UART kesmeleri ile nasıl veri alımı gerçekleştirildiğinden bahsetmiş ve uygulamasını yapmıştık. Bu uygulama için tekrar aynı konfigürasyonların geçerli olduğundan emin olabilirsiniz. Bir miktar alıştırma olması açısından konfigürasyonları size bırakıp, program kısmına geçiyoruz. Öncelikle KEIL ekranında main.c kodu içerisinde uint8_t veri tipinde ve 32 byte büyüklüğünde bir buffer ve buffer içerisindeki pozisyonu tutmak adına pos adında bir değişkeni ilk değeri 0 olarak şekilde tanımlıyoruz.
uint8_t buffer[32], pos = 0;
Ardından sonsuz döngünün hemen öncesinde bir defaya mahsus olmak üzere __HAL_UART_ENABLE_IT fonksiyonunu kullanarak Receive kesmesini aktifleştiriyoruz. Daha önce hatırlarsanız HAL_UART_Receive_IT komutu kullanarak kesmeyi aktifleştirmiştik. İkisinin arasındaki farka değinecek olursak, bu fonksiyon aşağıda gösterildiği üzere veriyi tutmak için bir bufferı argüman olarak almaz, sadece kesmeyi açar!
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_USART3_UART_Init();
/* USER CODE BEGIN 2 */
__HAL_UART_ENABLE_IT(&huart3,UART_IT_RXNE); // Kesme bu satırda aktifleştirildi
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
Project sekmesi içerisinde bulunan Application/User dosyasının altında bulunan stm32f7xx_it.c dosyasına çift tıklayarak açıyoruz. CubeMX konfigürasyonları esnasında aktifleştirdiğiniz UART kanalına ait IRQ_Handler (Interrupt Request Handler) fonksiyonuna giderek düzenlemelerimizi yapmaya başlıyoruz. Bu fonksiyon normalde içerisinde HAL_UART_IRQHandler(&huart3) gibi bir ifadeyle gelir. Fakat biz kendimize ait bir handler yazmayı hedeflediğimiz için bu kısmı yoruma çekiyoruz. Sonrasında ise stm32f7xx_it.c dosyasının en altında bulunan user code kısmına eklediğimiz ve aşağıda da sizlerle paylaştığımız USART_ISR adlı fonksiyonu yazıyoruz. Son olarak ise USART3_IRQHandler içerisinde daha önce yoruma çektiğimiz fonksiyonun yerine bu fonksiyonu çağırıyoruz.
/**
* @brief This function handles USART3 global interrupt.
*/
void USART3_IRQHandler(void)
{
/* USER CODE BEGIN USART3_IRQn 0 */
/* USER CODE END USART3_IRQn 0 */
//HAL_UART_IRQHandler(&huart3);
/* USER CODE BEGIN USART3_IRQn 1 */
UART_ISR(&huart3);
/* USER CODE END USART3_IRQn 1 */
}
/* USER CODE BEGIN 1 */
void UART_ISR(UART_HandleTypeDef *huart) {
if (((huart->Instance->ISR & USART_ISR_RXNE) != RESET)&& ((huart->Instance->CR1 & USART_CR1_RXNEIE) != RESET))
{
unsigned char c = huart->Instance->RDR;
buffer[pos++] = c;
if (c == '\n') pos = 0;
}
}
/* USER CODE END 1 */
Kısaca yaptığımız bu basit işlemleri açıklayalım. UART_ISR fonksiyonu ile önce kesme bayraklarını ilgili registerları okuyarak kontrol ediyoruz. Eğer bir kesme söz konusu ise RDR registerı içerisine alınmış olan karakteri buffer içerisine kaydediyoruz. Bu uygulamanın avantajı gelen verinin ne boyutta olduğunu bilmiyorsanız fakat hangi karakter ile bittiğini biliyorsanız kullanabilecek olmanızdır. Bu nedenle de eğer son gelen karakter new line karakteri ise pos değişkeni sıfırlanır ve böylece sıradaki veri bloğu bufferın en başından itibaren kaydedilmeye başlanır.
Uygulama linkini sizlerle paylaşmak üzere yazının sonuna ekliyoruz. Bir sonraki yazımızda görüşmek üzere, hoşça kalın! 🙂
GitHub Linki: https://github.com/karamelekrobotics/karamelektech_halkullanmadan_uartkesmeleri
iki stm32f4 arasında iki pin üzerinden, uart kesme programınız var , bu programın register kodlaması varmı , kütüphane kullanmadan , programı register kodlamayla yazılması, veya önericeginiz link …
Register kodlamalarıyla alakalı sitemizde bir uygulama yok henüz. Ancak kullandığınız işlemcinin datasheeti üzerinden adım adım hangi registerlara hangi değerlerin yazılması gerektiğini bulabilir ve konfigürasyonlarınızı yapabilirsiniz. HAL kütüphanesinin yaptığı aslında tam olarak bu. Yani Cube üzerinden kod ürettiğinizde örneğin MX_UART_Init fonksiyonu ilgili registerlara uygun değerleri yazmaktadır. Öneri olarak önce datasheeti edinip ilgili çevre birimine dair olan kısımları incelemeniz ve ardından Cube ile kod üreterek MX_xx_Init fonksiyonunun içini incelemenizi söyleyebilirim. Böylelikle yazılarda da sıkça değindiğimiz üzere dosyalar içerisinde bulunan yapıları da keşfedebilirsiniz.