Stm32f4 - Assembly ile UART Haberleşme

Bu yazımda assembly dilini kullanarak STM32F4 Discovery kiti ile Uart haberleşmeyi göstereceğim. İlk olarak Uart’ın ne olduğu ile başlayalım. Uart yani Universal Asynchronous Receiver/Transmitter, elektronik iki cihaz arasında kullanılan en eski ve en basit haberleşme protokollerinden biridir. İletişim Rx + Tx olmak üzere iki tel ile yapılır. Full-duplex yapıdadır.

uart_protokol

Yukarıdaki resimde protokol görülebilir. İletişim 1 start biti ile başlar, bu bit her zaman ‘0’ değerindedir. Start bitinin ardından veriyi içeren bitler gelir, veri uzunluğu genelde 8 bit bittir ancak uygulamaya göre 5, 6, 7 … şeklinde de ayarlanabilir. Veri bitlerinin ardından parity bitleri gelir. Parity verinin doğruluğunu sağlamak için kullanılır , kullanılması zorunlu değildir, 1 ya da 2 bit olabilir. Son olarak iletişimin sonlandığını belirten stop biti vardır, bu bit her zaman ‘1’ değerindedir.
İletişimin hızı baudrate ile ölçülür. 1 baudrate, 1 saniyede 1 baud aktarıldığını gösterir. Genelde 9600, 19200, 57600 gibi değerler kullanılır ancak uygulamaya göre farklı değerler de kullanılabilir.

Şimdi Stm32f4 Discovery kiti üzerinde uygulamasini yapalim. İlk olarak mikrodenetleyicinin clock ayarını yapalım. Bunun için STM Stm324f için nin yayınladığı Referance Manuel’in (RM0090) RCC kısmına bakalım. Referance Manuelde gördüğümüz gibi Stm32f407’nin clock donanımı aşağıdaki gibidir.

rcc

Biz uygulamada kitin üzerinde bulunan 8Mhz kristali kullanacağız. PLL ve bölücü kullanmadan işlemci 8Mhz'de çalışacak. Bunun için HSE donanımını aktifleştirip, clock kaynağını HSE seçeceğiz. Bunları yapabilmek için Reference Manuel’den RCC donanımının registerlerine bakıyoruz. RCC_CR registerinin 16.bitini ‘1’ yaparak HSE’yi aktifleştirmiş oluyoruz. İkinci olarak RCC_CFGR registerinin 1:0 bitlerini ‘01’ yaparak işlemcinin clock kaynağını HSE olarak belirlemiş oluyoruz. Son olarak kullanacağımız GPIO (GPIOA) ve USART (USART2) donanımlarının clocklarını AHB1 ve APB1 clock hattına bağlamamız gerekiyor. USART2 için RCC_APB1ENR registerinin 17.bitini ‘1’ yapmamız, GPIOB için de RCC_AHB1ENR registerinin 0. Bitini ‘1’ yapmamız gerekiyor. Clocking ile ilgili yaptığımız işlemleri assembly ile yazarsak:

RCC                    EQU            0x40023800

RCC_Ayarları
PROC
LDR                     R0, =RCC                         ;RCC register adresini R0'a yükle
LDR                     R1, [R0]
ORR                    R1, R1, #0x00010000      
STR                     R1, [R0]                            ;HSE yi aktif et
LDR                     R1, [R0, #0x08]
ORR                    R1, R1, #0x0001
STR                     R1, [R0, #0x08]                 ;Mikrodenetleyicinin clock kaynağını HSE yap
MOVT                  R1, #0x0002
STR                     R1, [R0, #0x40]                 ;APB1 den USART2 nin clock unu aktif et
MOV                    R1, #0x0001
STR                     R1, [R0, #0x30]                 ;AHB1 den GPIOB nin clock unu aktif et
ENDP

Sırada GPIO ayarları var. Bu projede iletişim için USART2 donanımına bağlı PA2 ve PA3 pinleri kullanıldı. USART haberleşmesi için pinlerin pull-up şeklinde konfigürasyon edilmesi gerekir. Bunun için yine Referance Manuelin GPIO registerlerine baktığımızda, GPIOA_PUPDR registerinin 5:2 bitlerinin ‘1010’ yapılması gerekiyor. İkinci olarak bu pinlerin USART2 donanımına bağlanabilmesi için pinllerin, Alternate function tipinde olması ve Alternate function'ın USART2 olarak ayarlanması gerekiyor. Alternate function için GPIOA_MODER registerinin 5:2 bitlerinin ‘1010’ şekline, GPIOA_AFRL registerinin 15:8 bitlerinin ‘0111 0111’ şekline ayarlanması gerekiyor. Yaptılarımızı assembly ile yazarsak:

GPIOA                    EQU               0x40020000

GPIO_Ayarları
PROC
LDR                       R0, =GPIOA                         ;GPIOA register adresini R0 a yaz
LDR                       R1, [R0]
ORR                      R1, R1, #0x00A0
STR                       R1, [R0]                                ;GPIOA_2,3 ü alternate function olarak ayarla
LDR                       R1, [R0, #0x0C]
ORR                      R1, R1, #0x0050
STR                       R1, [R0, #0x0C]                   ;GPIOA_2,3 pinlerini pull-up yap
LDR                       R1, [R0, #0x20]
ORR                      R1, R1, #0x7700
STR                       R1, [R0, #0x20]                    ;GPIOA_2,3 ü USART2 ye bağla
ENDP

Son olarak USART donanımının konfigürasyonu var. Bu uygulamada baud rate 9600 olarak seçilmiştir. Referance Manuel in USART kısmında Baudrate hesabı için aşağıdaki denklem verilmiş.

\textrm{Tx/Rx Baud} = \frac{f_{CK}}{8\times(2-\textrm{OVER8})\times\textrm{USARTDIV}}

Burada \textrm{Tx/Rx Baud} baud rate, f_{CK} USART donanımının çalışma frekansı yani APB1 üzererinden gelen clock frekansı, \textrm{USARTDIV} donanımın istenilen baud rate için ayaralanmasını sağlayan değer, \textrm{OVER8} ise oversampling'dir. Biz oversampling kullanmayacağımızdan bu bitin değeri ‘0’ olacaktır. İşlemi 9600 baud rate için yaparsak;

9600 = \frac{8000000}{8\times(2-0)\times\textrm{USARTDIV}}

 \textrm{USARTDIV} = \frac{500000}{9600} = 52.08\bar{3}

Bulduğumuz bu değeri USART2_BRR registerine yazmak için mantissa ve fraction şeklinde ikiye ayırmamız gerekmekte.

\textrm{Fraction} = 16\times0.08\bar{3} \approx 1

\textrm{Mantissa} = 52

Mantissa değerini USART2_BRR registerinin 15:4, Fraction değerini ise 3:0 değerine yazıyoruz. USART donanımını, veri gönderme ve almayi aktif etmek için USART2_CR1 registerinin 2, 3 ve 13. bitlerini ‘1’ yapıyoruz. Yaptıklarımızı assembly ile yazarsak:

USART2                  EQU                 0x40004400

USART_Ayarları
PROC
LDR                        R0, =USART2
MOV                       R1, #0x0341
STR                        R1, [R0, #0x08]                  ;USART2 nin baudrate sini 9600 olarak ayarla
MOV                       R1, #0x200C
STR                        R1, [R0, #0x0C]                  ;USART2 yi aktif et
ENDP

Bu ayarları yaptıktan sonra USART donanımı çalışmaya hazır. Test için echo uyglaması yapalım. Programın algoritması aşağıdaki gibi olacaktır:

echo

Rx’ten gelen bir veri olup olmadığını USART2_SR registerindeki RXNE (Read Data Register not Empty) bitinden öğrenebiliriz. Program aşağıdaki gibi olacaktır:

USART2              EQU                  0x40004400

LDR                    R0, =USART2

Echo

LDR                    R1, [R0]
AND                   R1, R1, #0x0020
CMP                   R1, #0x0020                     ;USART2 nin RXNE bitini kontrol et
BNE                    Echo                                 ;Eğer veri gelmemişse başa dön
LDR                    R1, [R0, #0x04]                ;USART2 ye gelen veriyi R1 e yaz
STR                    R1, [R0, #0x04]                ;R1 deki veriyi USART2 ile gönder
B                         Echo                                 ;Başa dön

Ve sonuç:

sonuc

2 thoughts on “Stm32f4 - Assembly ile UART Haberleşme”

  1. çok iyi benim için önemli olan assembler programdır , emeklemeden yürümemek gerekir
    assembler programla ilgili yazılarınıza (PWM - TİMER - RTC) vs... devam etmenizde fayda var
    sadece STM32F degil DSPIC lerle ilgili assembler programlarınızı görmek istiyorum

  2. Bertan bey yazılarınızı yeni keşfetmenin hem üzüntüsü hem de sevinci içerisindeyim. Ellerinize sağlık. Sizlere bir mail attım FPGA programlama ile ilgili, olumsuz da olsa geri dönüş yapabilir misiniz ? Kolaylıklar diliyorum, Bu güzel işlerinizin devamının gelmesi dileği ile, hoşçakalın.

Bir cevap yazın

E-posta hesabınız yayımlanmayacak.