How to hardware hack Android over UART. Планшет uart


How to hardware hack Android over UART

…with help from Lee Parkes.

“What’s UART?” I hear you ask. No, it’s not the noise made when you have a particularly virulent strain of lurgy, it stands for Universal Asynchronous Receiver/Transmitter. Does that help? Not much. Now, if I said RS232 or RS423 some of the older readers might be starting to get it: it’s a piece of hardware that translates system data into a serial data.

Those of us that remember the good (?) old days of Unix and Mainframe consoles will have spent many hours cursing serial ports, but they provide a mechanism to read and potentially write to the console of the device, thus allowing you to interrupt the boot process and provides an avenue to flash custom code to the device. The facilities are generally built in to the device at the design stage and cannot be disabled.

Most embedded consumer devices had some flavour of serial port available for the same reason that they have JTAG ports: to allow the debugging of the device during its development and for consumer returns (more on JTAG in a later blog post). Usually the headers of the port are not attached in the final commercial versions. For example, here’s the holes taken from an old Belkin wireless router that I have sitting around:

The four holes on the left are the UART port (the ones of the right are USB endpoints), the router makes made this easy for us as the pins are labelled. To actually read the data, we need to connect these to a USB receiver and then we can talk directly to the console of the router.

To make this easier the first step is to solder some header pins directly to the board, these can be seen below. Note, I’m not very good at soldering, so I won’t show the underside : )

Now we can wire this to a USB to UART module. These are quite easy to find and cheap, mine cost me less than £3.00. This handles all the USB gubbins to ensure that you can just plug it in and treat it like a serial connection.

Finally we need to join up the pins, as below:

Purpose Port on Router Port on USB/UART module
Receive RX TX
Transmit TX RX
3.3V power VCC Don’t attach
Ground GND GND

 

Finally, connect it all together and plug it into a computer:

The observant may have noticed that the above circuit board isn’t the same as the previous pictures. This was my testing device, an old Sagem router which I soldered up before I thought to take photos first.

Once it’s connected we can just load up a serial console program, such as HyperTerm or minicom and watch it boot:

This could be a simple way of uploading malicious firmware to an existing router to set up a wireless sniffer, except it’s over complicated and it would be easier just to hide a small wireless device, such as a wi-fi pineapple.

But, this works for other devices, such as some mobile phones! One of my colleagues found an interesting article on how to connect to UART on a Nexus 4 via the headphone jack.

Basically if the device sees a voltage of more than 2.8V on the microphone jack it turns the connector into a UART port.

So, once again the old soldering iron is produced and a cable is made, we actually left out the resistors as they’re a safety net and not actually required (voltage from the USB to UART convertor is 3.3V, so it meets the requirements).

This time I can’t hide my lack of soldering ability:

Which we can then connect to another USB to UART convertor and plug into my laptop:

And we can read the console as the device boots up:

After Android has finished booting it will continuously feed out data about the hardware state of the device. You can even connect whilst the device is running.

Some phones (such as the Samsung Galaxy S2) allow two way communication through a UART connection, which can allow low level communication, such as reset the “yellow flag” which shows if an unsigned image is written to the flash memory.

In conclusion, simple hardware hacking is quite quick to perform, the greatest delays I faced were waiting for components to arrive and the longest single period of time taken was spent when my soldering iron developed a short and tripped the house electrics’.

Although there’s no immediate security risks, it can present a way in to custom devices.

www.pentestpartners.com

%PDF-1.6 % 7 0 obj > endobj xref 7 411 0000000016 00000 n 0000009168 00000 n 0000009228 00000 n 0000012122 00000 n 0000012451 00000 n 0000012930 00000 n 0000013468 00000 n 0000013503 00000 n 0000021848 00000 n 0000028032 00000 n 0000030078 00000 n 0000033508 00000 n 0000037589 00000 n 0000044930 00000 n 0000052126 00000 n 0000059264 00000 n 0000061913 00000 n 0000062026 00000 n 0000062149 00000 n 0000062264 00000 n 0000062387 00000 n 0000062510 00000 n 0000062633 00000 n 0000062746 00000 n 0000062869 00000 n 0000062994 00000 n 0000063117 00000 n 0000063240 00000 n 0000064531 00000 n 0000064842 00000 n 0000066681 00000 n 0000067011 00000 n 0000071285 00000 n 0000071889 00000 n 0000071952 00000 n 0000072297 00000 n 0000072360 00000 n 0000072697 00000 n 0000072759 00000 n 0000101074 00000 n 0000101321 00000 n 0000101651 00000 n 0000102023 00000 n 0000102086 00000 n 0000102444 00000 n 0000102506 00000 n 0000102779 00000 n 0000102841 00000 n 0000103166 00000 n 0000103228 00000 n 0000103618 00000 n 0000103680 00000 n 0000104044 00000 n 0000104106 00000 n 0000104379 00000 n 0000104441 00000 n 0000104714 00000 n 0000104777 00000 n 0000105132 00000 n 0000105194 00000 n 0000105466 00000 n 0000105528 00000 n 0000105853 00000 n 0000105915 00000 n 0000106286 00000 n 0000106348 00000 n 0000106737 00000 n 0000106799 00000 n 0000107165 00000 n 0000107227 00000 n 0000107499 00000 n 0000107561 00000 n 0000107833 00000 n 0000107895 00000 n 0000108167 00000 n 0000108229 00000 n 0000108500 00000 n 0000108562 00000 n 0000108834 00000 n 0000108896 00000 n 0000109168 00000 n 0000109230 00000 n 0000109601 00000 n 0000109663 00000 n 0000110078 00000 n 0000110140 00000 n 0000110511 00000 n 0000110573 00000 n 0000110920 00000 n 0000110982 00000 n 0000111361 00000 n 0000111423 00000 n 0000111693 00000 n 0000111755 00000 n 0000112029 00000 n 0000112092 00000 n 0000112365 00000 n 0000112428 00000 n 0000112702 00000 n 0000112765 00000 n 0000113137 00000 n 0000113200 00000 n 0000113617 00000 n 0000113680 00000 n 0000114029 00000 n 0000114092 00000 n 0000114476 00000 n 0000114539 00000 n 0000114913 00000 n 0000114977 00000 n 0000115335 00000 n 0000115398 00000 n 0000115671 00000 n 0000115734 00000 n 0000116061 00000 n 0000116124 00000 n 0000116516 00000 n 0000116579 00000 n 0000116945 00000 n 0000117008 00000 n 0000117283 00000 n 0000117346 00000 n 0000117621 00000 n 0000117685 00000 n 0000118042 00000 n 0000118105 00000 n 0000118379 00000 n 0000118442 00000 n 0000118769 00000 n 0000118832 00000 n 0000119214 00000 n 0000119277 00000 n 0000119668 00000 n 0000119731 00000 n 0000120098 00000 n 0000120161 00000 n 0000120435 00000 n 0000120498 00000 n 0000120772 00000 n 0000120836 00000 n 0000121139 00000 n 0000121203 00000 n 0000121502 00000 n 0000121565 00000 n 0000121840 00000 n 0000121903 00000 n 0000122235 00000 n 0000122298 00000 n 0000122572 00000 n 0000122635 00000 n 0000123040 00000 n 0000123103 00000 n 0000123478 00000 n 0000123541 00000 n 0000123821 00000 n 0000123884 00000 n 0000124158 00000 n 0000124221 00000 n 0000124597 00000 n 0000124660 00000 n 0000125034 00000 n 0000125097 00000 n 0000125470 00000 n 0000125533 00000 n 0000125807 00000 n 0000125870 00000 n 0000126145 00000 n 0000126208 00000 n 0000126480 00000 n 0000126543 00000 n 0000126815 00000 n 0000126878 00000 n 0000127153 00000 n 0000127216 00000 n 0000127590 00000 n 0000127653 00000 n 0000127925 00000 n 0000127988 00000 n 0000128263 00000 n 0000128326 00000 n 0000128600 00000 n 0000128663 00000 n 0000128938 00000 n 0000129001 00000 n 0000129276 00000 n 0000129339 00000 n 0000129614 00000 n 0000129677 00000 n 0000129952 00000 n 0000130015 00000 n 0000130290 00000 n 0000130354 00000 n 0000130712 00000 n 0000130776 00000 n 0000131133 00000 n 0000131196 00000 n 0000131569 00000 n 0000131633 00000 n 0000131990 00000 n 0000132054 00000 n 0000132411 00000 n 0000132474 00000 n 0000132848 00000 n 0000132911 00000 n 0000133285 00000 n 0000133349 00000 n 0000133698 00000 n 0000133761 00000 n 0000134134 00000 n 0000134197 00000 n 0000134570 00000 n 0000134633 00000 n 0000135006 00000 n 0000135069 00000 n 0000135442 00000 n 0000135505 00000 n 0000135880 00000 n 0000135943 00000 n 0000136317 00000 n 0000136380 00000 n 0000136755 00000 n 0000136818 00000 n 0000137193 00000 n 0000137256 00000 n 0000137644 00000 n 0000137707 00000 n 0000138082 00000 n 0000138145 00000 n 0000138517 00000 n 0000138580 00000 n 0000138955 00000 n 0000139018 00000 n 0000139393 00000 n 0000139456 00000 n 0000139831 00000 n 0000139894 00000 n 0000140268 00000 n 0000140331 00000 n 0000140706 00000 n 0000140769 00000 n 0000141142 00000 n 0000141205 00000 n 0000141579 00000 n 0000141642 00000 n 0000142017 00000 n 0000142080 00000 n 0000142455 00000 n 0000142518 00000 n 0000142893 00000 n 0000142956 00000 n 0000143330 00000 n 0000143393 00000 n 0000143769 00000 n 0000143832 00000 n 0000144207 00000 n 0000144270 00000 n 0000144644 00000 n 0000144707 00000 n 0000145078 00000 n 0000145141 00000 n 0000145514 00000 n 0000145577 00000 n 0000145952 00000 n 0000146015 00000 n 0000146391 00000 n 0000146454 00000 n 0000146830 00000 n 0000146893 00000 n 0000147268 00000 n 0000147331 00000 n 0000147706 00000 n 0000147769 00000 n 0000148144 00000 n 0000148207 00000 n 0000148581 00000 n 0000148644 00000 n 0000149020 00000 n 0000149083 00000 n 0000149456 00000 n 0000149519 00000 n 0000149895 00000 n 0000149958 00000 n 0000150331 00000 n 0000150394 00000 n 0000150769 00000 n 0000150832 00000 n 0000151204 00000 n 0000151267 00000 n 0000151639 00000 n 0000151702 00000 n 0000152075 00000 n 0000152138 00000 n 0000152514 00000 n 0000152577 00000 n 0000152952 00000 n 0000153015 00000 n 0000153390 00000 n 0000153453 00000 n 0000153829 00000 n 0000153892 00000 n 0000154269 00000 n 0000154332 00000 n 0000154708 00000 n 0000154771 00000 n 0000155155 00000 n 0000155218 00000 n 0000155616 00000 n 0000155679 00000 n 0000156056 00000 n 0000156119 00000 n 0000156497 00000 n 0000156560 00000 n 0000156937 00000 n 0000157000 00000 n 0000157375 00000 n 0000157438 00000 n 0000157812 00000 n 0000157875 00000 n 0000158250 00000 n 0000158313 00000 n 0000158694 00000 n 0000158757 00000 n 0000159135 00000 n 0000159198 00000 n 0000159575 00000 n 0000159638 00000 n 0000160015 00000 n 0000160078 00000 n 0000160455 00000 n 0000160518 00000 n 0000160893 00000 n 0000160956 00000 n 0000161345 00000 n 0000161408 00000 n 0000161795 00000 n 0000161858 00000 n 0000162236 00000 n 0000162299 00000 n 0000162674 00000 n 0000162737 00000 n 0000163116 00000 n 0000163179 00000 n 0000163559 00000 n 0000163622 00000 n 0000164001 00000 n 0000164064 00000 n 0000164443 00000 n 0000164506 00000 n 0000164884 00000 n 0000164947 00000 n 0000165329 00000 n 0000165392 00000 n 0000165790 00000 n 0000165853 00000 n 0000166229 00000 n 0000166292 00000 n 0000166669 00000 n 0000166732 00000 n 0000167108 00000 n 0000167171 00000 n 0000167545 00000 n 0000167608 00000 n 0000167999 00000 n 0000168062 00000 n 0000168440 00000 n 0000168503 00000 n 0000168884 00000 n 0000168947 00000 n 0000169320 00000 n 0000169384 00000 n 0000169657 00000 n 0000169721 00000 n 0000169995 00000 n 0000170058 00000 n 0000170331 00000 n 0000170394 00000 n 0000170667 00000 n 0000170730 00000 n 0000171003 00000 n 0000171066 00000 n 0000171340 00000 n 0000171404 00000 n 0000171480 00000 n 0000172257 00000 n 0000172986 00000 n 0000175594 00000 n 0000194747 00000 n 0000199857 00000 n 0000201295 00000 n 0000203934 00000 n 0000207609 00000 n 0000216847 00000 n 0000225033 00000 n 0000233459 00000 n 0000240548 00000 n 0000255113 00000 n 0000272678 00000 n 0000287664 00000 n 0000307139 00000 n 0000320437 00000 n 0000333286 00000 n 0000347039 00000 n 0000349915 00000 n 0000362433 00000 n 0000385039 00000 n 0000408651 00000 n 0000427875 00000 n 0000449931 00000 n 0000472228 00000 n 0000495023 00000 n 0000008516 00000 n trailer ]/Prev 520520>> startxref 0 %%EOF 417 0 obj >stream hޜ?hQǿEs(# BKVKjDt Vu(uTk,}N \BSt{NKn~wI r3ڏDTj0y~:XwЙ.ĜeD8\f:G 5P &ֻkZY6>;w|L #aLc04{4'm!VN;@F&mV-4KK-!Y ##

qs/4Vi[*LcK`2#+',2wx^HKƨ`nDhW[b-yI"]ce+:qybNR4,y]ts5Z-o[Μ+'=;.h%o㴷},ʶƈ㾵38 .fqW6p÷ޮ]aG}3PTog_ķ'nM~ywjů^o&ԇ{09; X #

www.atlas-scientific.com

MCU Turkey – LPC1768 ile UART ve ADC Uygulaması

Merhaba arkadaşlar,Bu yazımda sizlere LPC1768’in uart ve adc çevre birimlerinin kullanımını anlatmaya çalışacağım.İlk olarak LPC1768 den bahsedelim biraz:

LPC1768, Arm Cortex-M3 mimarili NXP firmasına ait bir MCU’dur. Özellikleri ve çevre-birimleri:

  • 100 mhz’e kadar yükseltilebilen cpu clock hızı.
  • 512 mb flash rom ve 64 kb RAM
  • Ethernet
  • USB 2.0 arayüzü
  • 8 kanal DMA
  • 2 kanal CAN
  • 4  UART
  • 3 er kanal I2C ve SPI.
  • 8 kanal 12 bit ADC
  • 4 adet 32 bit timer
  • Standart PWM ve 3 fazlı motor kontrol PWM
  • RTC(Real Time Clock)

Genel olarak mikro-deneteyicimizin özellikleri bunlardır.Şimdi uygulamamızı yapmaya geçebiliriz.

Bu uygulamamızda MCB1700 kiti üzerindeki pot ile oynayarak değişen gerilim değerini UART üzerinden RS232-USB dönüştürücü kablo aracılığı ile bilgisarımıza göndereceğiz.

İlk olarak ADC çevre-biriminden bahsedecek olursak:

ADC(Analog/Dijital Converter) BİRİMİ

Yukarıda da belirttiğim gibi ADC çözünürlüğümüz 12 bit ve hızımız ise 200 ksps.

Biz bu uygulamamızda ADC biriminin 5.kanalını kullanacağız. Bu kanal da P1.31 pinine bağlıdır. Bu pini ADC pini olarak kullanmak istiyorsak ilk olarak PINSEL bloğundan bu pini ADC pini olarak seçmemiz gerekiyor. Böyle bir ayarlama yapmamızın nedeni MCU nun neredeyse tüm pinlerinin default olarak GPIO(General Purpose Input/Output)  olmasıdır. PINSEL aryarlamasını yaptıktan sonra güç ayarını yapmamız gerekiyor. ADC biririmiz başlangıçta power down modunda olduğundan dolayı PCONP register ı ile ADC yi aktif etmeliyiz.Ayrıca bunların yanında ADC olarak kullanılacak pinin “neither pull-up nor pull-down ”  modunun aktif edilmesi öneriliyor.Yani o pin ne pull-up yapılacak ne de pull-down olacak.Şimdi bu bilgiler eşiğinde aşağıdaki kodları yazmamız gerekir:

LPC_PINCON->PINSEL3 |=(3UL<<30); //p1.30.adc pini olarak ayarlanıyo. LPC_PINCON->PINMODE3=1<<29;// p1.30 neither pull up nor pull down modunda. LPC_SC->PCONP |=1<<12;//adc birimi aktif ediliyor(Power up moduna getiriliyor).

Bu registerlarda yukarıdaki bibideğişiklikleri yaptıktan sonra ADC birimimize ait register ayarlarına geçelim:

ADCR: Hangi ADC kanalını aktif edeceğimizi, ADC clock frekansını, ADC çalışma modunu ayarlamamıza ve ADC yi aktifleştirmeye ya da pasifleştirmeye yarayan registerdır.Bu registerı bit bit incelersek:

  • SEL: 0:7.bitleri ile istenilen adc kanalı aktif edilir.Biz bu uygulamamızda 5.kanalı aktif edeceğimizden dolayı 5. biti set etmeliyiz.
  • CLKDIV:15:8 bitleri ile adc clock ayarlaması yapılır.Formul şu şekildedir: ADC_CLK=PCLK_ADC/(<15-8>+1). Burada PCLK_ADC adc birimimiz bus hızıdır.Bu hız default olarak cpu çalışma frekansımızın 1/4 üne eşittir. İstenilirse bu oran PCLKSEL0 registerı ile değiştirilebir.Bir örnekle pekiştirirsek.Mesela cpu çalışma frekansımız 100 mhz olsun ve ADCR registerının 8. bitini set edersek. ADC_CLK=(100mhz/4)/(1+1)=25mhz/2=12,5 mhz olur. Bu hız en fazla 13 mhz olabilir.Burada çalışma frekansını yüksek tutmakta fayda var çünkü daha önceki uygulamalarımda düşük frekanslarda düzgün çalışmadığını gördüm.
  • BURST:16. bitin set edilmesi ile burst modu aktif edilir. Burst modu birden fazla kanaldan okuma yapılacağı zaman aktif edilir. Tüm kanallar sırası ile taranarak otomatik olarak  okunur.Böylelikle ile tek tek herbir kanalı aktif edip okumak zorunda kalmayız.Bu da performans açısından fayda sağlar. Biz bu uygulamamızda tek kanldan okuma yapacağımız için bu biti set etmeyeceğiz.Bu bit set edilmezse her bir adc çevrimi 65 cycleda tamamlanır.
  • PDN:21. bit adc’yi aktifleştirip pasifleştirmeye yarar. Set edilirse adc aktif hale gelir.
  • START: 26:24 bitleri adc nin başlama koşulunu belirtir.Eğer burst yani 16. bit ‘1’ ise bu bitlerde değişiklik yapmaya gerek yoktur. Eğer 0 ise “000” değeri ile A/D çevrimi başlatılmaz. “001”  ise A/D çevrimi o an başlatılır. Bu bitlerin farklı durumlarına göre adc başlama koşulu belirtilebilir.Bunları LPC1768 in datasheet’inden bakabilirsiniz.

ADDR(0-7):Bu register ile A/D çevriminin bititip bitmediği,A/D çevrimin sonucu ve çevrim sonuçlarında bir kayıp olup olmadığı anlaşılır.ADDR(0-7) yazmamın nedeni hangi kanal aktifse o kanal numarası yazılır.Örneğin 5. kanal için ADDR5.Bu registerı bit bit incelersek:

  • RESULT:15:4  bitleri ile çevrimin sonucu öğrenilir. Şimdi örnek bir hesaplama ile çevrim sonucu MV’a çevirelim. ADC pinine uygulanan gerilim 2v, Vref+=3.3V, Vref-=0v olsun. “MVa_dunuşturulmemiş_sonuc=   (ADDR5>>4)&0xFFF” . Buradan çıkan sonuç adc çözünürlüğü 12 bit olduğu için 0-4095 aralığında olur. ” MV_cinsinden_sonuc=(MVa_donusturulmemis_sonuc*3300)/4095 “  burada 3300 ile çarpamımızın nedeni Vref+ nın 3.3v,Vref-=0v olmasındandır.
  • OVERRUN: 30. bit, burst modu aktifken çevrim sonucunda kayıp varsa ya da bir önceki çevrimin üstüne yazılmışsa ‘1’ değerini alır.Fakat söylediğim gibi bu bitin kontrolü Burst biti set edilmişse kontrol edilir.
  • DONE: 31. bit A/D çevrimi bittiğinde bu bit set olur. Yani A/D çevrim sonucu almadan önce bu bit değeri kontrol edilip ‘1’ olana kadar beklenilmelidir.

Bu anlattıklarımıza göre adc birimine ait oluşturduğumuz kütüphane aşağıdadır:

#ifndef __ADC_H #define __ADC_H void adc_init(void); uint32_t adc_hesapla(void); void adc_basla(void); void adc_dur(void); uint32_t adc_sonuc_al(void); #endif #include <lpc17xx.h> #include "lpc17xx_adc.h" void adc_init(void) { LPC_PINCON->PINSEL3 &= ~(3UL<<30); LPC_PINCON->PINSEL3 |=(3UL<<30); //p1.30.adc pini olarak ayarlanıyo. LPC_PINCON->PINMODE3=1<<29;// p1.30 neither pull up nor pull down modunda. LPC_SC->PCONP |=1<<12;//adc birimi aktif ediliyor(Power up moduna getiriliyor). LPC_ADC->ADCR=1<<5|1<<8|1<<21; //5.kanal seçiliyor,adc_clk_freq ayarlanıyor,Adc power down modundan çıkarılıyor,   } uint32_t adc_hesapla(void) { uint32_t sonuc; while(!(LPC_ADC->ADDR5&(1UL<<31))); //Çevrim bitene kadar bekleniliyor sonuc=LPC_ADC->ADDR5; return((sonuc>>4)&0xFFF); } void adc_basla(void) { LPC_ADC->ADCR |=(1<<24); } void adc_dur(void) { LPC_ADC->ADCR &=~(1<<24); } uint32_t adc_sonuc_al(void) { uint32_t hesap; adc_basla(); hesap =adc_hesapla(); adc_dur(); hesap=((hesap*3300)/(4096)); return(hesap); }

ADC çevre-birimine ait ayarlamaları tamamladıktan sonra UART birimine geçebiliriz.

UART BİRİMİ

İlk olarak uarttan bahsedelim.

Uart bilgisayar ile donanımlar arası bir haberleşme standartıdır.Açılımı Universal asynchronous receiver/transmitter dır.Bunu biraz açacak olursak. Adından da anlaşılacağı gibi UART da asenkron haberleşme kullanılır. Asenkron haberleşmede her bir karakter frame ler halinde gönderilir. Her bir frame de start biti,data,parity(isteğe bağlı) ve stop bitinden oluşur. Asenkron denmesinin nedeni bir cümle gönderileceği zaman cümle içindeki karakterler birbirinden bağımsız olarak iletilir.Yani her bir karaktere ait start ve stop biti bulunur. Cihazlar arası senkronizasyonun sağlanması için  clock sinyali olmadığından dolayı  alıcı ve verici nin baud rate lerinin aynı olması gerekir.Bunun için de kullanıcı tarafından alıcının ve vericinin baud rate’lerinin manuel olarak ayarlanması gerekir. Frame’lerin içeriğinden bahsedersek:

İletişim olmadığında hat high durumundadır iletişim başlatılacağı zaman start biti ile low seviyeye indirilir ardından 5,6,7 ya da 8  bitlik data gönderilir. En sık kullanılan 8 bitlik datadır. Datanın ardından parity yani kontrol biti gönderilir. Bu isteğe bağlıdır.Sadece hata olduğunu belirtip hatanın hangi bitte olduğunu belirtmediğinden dolayı genelde kullanılmaz. Parity bitinin ardından stop biti de gönderilerek bir frame tamamlanmış olur.Aşağıdaki resim parity bitsiz bir frame’e aittir.

 Uart hakkında verdiğimiz bu bilgilerden sonra.LPC1768 in UART biriminin kullanımına geçebiliriz.

Biz bu uygulamızda UART0 birimini kullanacağımızdan dolayı aşağıda anlatacağım herşey bu birime aittir.

İlk olarak UART birimine ait register ayarlamalarına geçmeden.PINSEL bloğundan Uart0’ın Rx ve Tx pinlerini Uart pini olarak ayarlamamız gerekmektedir.Bunun için aşağıdaki kodları yazmalıyız.

LPC_PINCON->PINSEL0 |=1<<4;//P0.2 pini TXD0 pini olarak ayarlanıyor. LPC_PINCON->PINSEL0 |=1<<6;//P0.3 pini RXD0 pini olarak ayarlanıyor.

UART birimine ait registerları inceleyecek olursak:

U0RBR: Bu register ile  Rx FIFO ‘suna en son eklenmiş data okunur.Yani uarttan en son gelen veri bu register aracılığı ile okunur.Bu işlem için ilk 8 bit kullanılır.Geri kalan bitler rezervedir hiç bir amaçla kullanılmaz.Bu işlemlerin yapılabilmesi için DLAB biti ‘0’ olmalıdır

U0THR: Bu registera UART’tan gönderilecek veri kaydedilir. Bu işlem için ilk 8 bit kullanılır.Geri kalan bitler rezervedir hiç bir amaçla kullanılmaz. Bu işlemlerin yapılabilmesi için DLAB biti ‘0’ olmalıdır.    

U0DLL: Bu registerın ilk 8 biti  ile baud rate ayalanır. Bu registerı kullanarak baud rate ayarlanmasına ait örnek, register tanımlamalarının bitiminde yapılacaktır.

U0DLM: Bu registerın ilk 8 biti  ile baud rate ayarlanır.Bu registerı kullanarak baud rate ayarlanmasına ait örnek, register tanımlamalarının bitiminde yapılacaktır.

U0FCR: Bu register ile Rx,Tx FIFO ları kontrol edilir.Bu registerı bit bit inceleyecek olursak:

  • FIFO Enable: 0. bitin set edilmesi ile Rx,Tx FIFO’ları aktif edilir ve U0FCR registerının [7:1] bitlerine erişim izni verilir. UART ın düzgün çalışabilmesi için bu bit set edilmelidir. Bu bitteki değişim FIFO ları resetler.
  • Rx FIFO Reset:1.bitin set edilmesi ile tüm Rx FIFO ları temizlenir.
  • Tx FIFO Reset: 2.bitin set edilmesi ile tüm Tx FIFO ları temizlenir.
  • DMA Mode Select: Bu bit ile DMA(Direct Memory Access) modu seçilir. Biz bu uygulamamızda DMA kullanmayacağımız için bu bitte herhangi bir değişiklik yapmayacağız.
  • Rx Trigger Level: 7. ve 6. bitler ile kesme veya DMA talebi ile FIFOlar dan kaç karakter okunacağını belirlenir. Biz bu uygulamamızda Kesme ve DMA kullanmayacağımız için bu bitlerde herhangi bir değişiklik yapmayacağız.

U0LCR: Bu register ile UARTtan gönderilecek frame in formatı belirlenir.Bu registerı bit bit inceleyecek olursak:

  • Word Length Select:0. ve 1. bitler ili gönderilecek datanın uzunluğu belirtilir.      

00->5 bit uzunluğunda

01->6 bit uzunluğunda

10->7 bit uzunluğunda

11->8 bit uzunluğunda.Biz bu modu kullanacağız.

  • Stop Bit Select:2.bit ile stop biti sayısı belirlenir. ‘0’ iken 1 stop biti ‘1’ iken 2 stop biti kullanılır.Biz uygulamamızda tek stop biti kullancağız.
  • Parity Enable: 3.bit ile parity biti seçilir. ‘0’ iken parity kullanılmaz ‘1’ iken kullanılır.
  • Parity Select: 4. ve 5. bitler ile parity bitinin tek mi çift mi olduğu belirlenir.Biz bu uygulamamızda parity biti kullanmayacağımız için bu bitlerde bir değişiklik yapmayacağız.
  • Break Control: 6. bitin set edilmesi ile TXD pini yani gönderim yapan pin ‘0’ seviyesine düşürülerek UARTtan veri gönderimi durdurulur.
  • Divisor Latch(DLAB):7. bit ile Divisor Latch aktif edilir. Baud rate ayarlanması için Divisor Latch in aktif olması gerekir.Baud rate ayarlaması bittikten sonra bu bit ‘0’ yapılmalıdır.

U0LSR:Bu register ile UART0 ın Rx ve Tx bloklarının durum bilgisi alınır.

  • Receive Data Ready(RDR):0. bit 0 ise Rx fifoları boştur ‘1 ise doludur. Veri alınacağı zaman bu bit 1 olana kadar beklenir.
  • Transmitter Holding Register Empty:5. bit 0 ise gönderim bitmemiştir ‘1’ ise bitmiştir. Gönderim yapılacağı zaman bu bit ‘1’ olana kadar beklenir. 

U0FDR:U0DLL VE U0DLM registerları ile ayarlanan baud rate istenilenden farklı çıkarsa bu sorunu ortadan kaldırmak için bu register kullanılır . Baud rate’in farklı çıkması iletişim düzgün yapılamamasına neden olur.Örneğin 9600 baud rate oluşturmak istiyorsak ve hesaplamalarımızla 9700 gibi sayı çıkmışsa bu sayı bu register ile 9600 yapılmaya çalışılır.Bu registera ait bitler:

  • DIVADDVAL:3:0 bitleri ile DIVADDVAL değeri belirlenir. Bu değerin ne işe yaradığı aşağıda örnekle beraber açıklanmıştır.
  • MULVAL: 7:4 bitleri ile MULVAL değeri belirlenir. Bu değerin ne işe yaradığı aşağıda örnekle beraber açıklanmıştır.

Bu bilgileri verdikten sonra bir kaç örnekle beraber baud rate ayarlaması nasıl yapılır görelim.

İlk olarak yan taraftaki baud rate hesaplama algoritmasını inceleyelim.

Örnek1:Uart birimimiz clock frekansı 28,2624 mhz olsun. İstediğimiz baudrate de 19200 olsun. 

DLest= PCLK/(16*BR) formülünden DLest=28,2624mhz/(16*19200)=92. Değerimiz tam çıktığı için DIVADVAL=0,MULVAL=1,DLM=0,DLL=92 olur.

 

Örnek2: Uart birimimizin clock frekansı 46,08 mhz olsun. İstediğimiz baudrate de 9600 olsun.

DLest=PCLK/(16*BR) formülünden DLest=46,08mhz/(16*9600)=300. Değerimiz tam çıktı fakat 255 ten büyük çıktığı için bu değerin tamamını  DLL registerına yazamayız çünkü bu registera en fazla 8 bitlik bir değer yazabiliriz. Bu yüzden DLM=(int)(300/256)=1, DLL=300%256=44 olur. Bu durumda DIVADVAL=0,MULVAL=1,DLM=1,DLL=44 olur.

 

Örnek3: Uart birimimizin clock frekansı 12 mhz olsun. İstediğimiz baudrate de 115200 olsun. 

DLest=PCLK/(16*BR) formülünden DLest=12mhz/(16*115200)=6,51. Görüldüğü gibi sonucumuz küsüratlı çıkmıştır. Bu durumda algoritma akış diyagramında belirtildiği üzere FRest=1,5 alınır ve DLest yeniden hesaplanır.

DLest=(int)12mhz(16*115200*1,5)=4. Bunun sonucunda gerçek FR değerimiz FR=6,51/4=1,6275 olur. Eğer bu değer 1,1 ile 1,9 arasında çıkmasayda bu işlemler o aralıkta çıkana kadar tekrar edilecekti. Şimdi FR değerine göre aşağıdaki Tabloda DIVADDVAL ve MULVAL değerleri bulunur.

Tabloya göre DIVADDVAL=5 MULVAL=8 çıkar. Bu durumda DLL=4,DLM=0,DIVADDVAL=5 MULVAL=8  olar hesaplanır.

Şimdi bu anlattıklarımıza göre aşağıdaki gibi bir kütüphane oluştururuz.

#ifndef __UART_H #define __UART_H extern void uart_init(void); extern int send_char(int data); extern unsigned char get_char(void); extern void send_string(char *str); #endif #include <lpc17xx.h> #include "lpc17xx_uart.h" void uart_init(void) {   LPC_PINCON->PINSEL0 |=1<<4;//PINSEL ayarlamaları yaapılıyor. LPC_PINCON->PINSEL0 |=1<<6; LPC_UART0->LCR=0x83;//frame formatı belirleniyor LPC_UART0->DLL=9;// baud rate 115200'e ayarlanıyor LPC_UART0->DLM=0; LPC_UART0->FCR=0x7; LPC_UART0->FDR=1<<0|1<<5; LPC_UART0->LCR=0x03;// Alım ve gönderim yapılabilmesi için DLAB biti '0'a çekildi. } int send_char(int data) { while (!(LPC_UART0->LSR & 0x20));//THRE boşalana kadar bekleniyor. return(LPC_UART0->THR=data); } unsigned char get_char(void) { while(!(LPC_UART0->LSR&(0x01)));//RDR dolana kadar bekleniyor. return(LPC_UART0->RBR); } void send_string(char *str) { while(*str!=0) { send_char(*str++); }   }

 

ADC ve UART kütüphanelerimizi oluşturduktan sonra PLL ve clock ayarlarını yapalım. PLL ve clock ayarlarını yapmak için kullanılacak olan registerlardan bahsedecek olursak:

PLL(PHASE LOCKED LOOP) VE CLOCK AYARLARI

LPC1768 in clock üretimine ait block diyagramı aşağıdadır.

SCS: Bu register ile ana osilatör kontrol edilir ve durum bilgisi alınır.

  • OSCRANGE: 4. bit,eğer kullandığımız ana osilatör 1mhz-20mhz aralığında ise ‘0’ yapılır.15mhz-25mhz aralığında ise ‘1’ yapılır.Bizim kullandığımız kitte 12mhz lik kristal olduğundan bit ‘0’ yapılır.
  • OSCEN:5. bit set edilirse ana osilatör aktifleştirilir.’0′ yapılırsa pasifleştirilir.
  • OSCSTAT: 6. bitin durumu ile ana osilatörün hazır olup olmadığı anlaşılır. ‘0’ ise hazır değildir.’1′ ise hazırdır.

CLKSRCSEL:Bu registerın 0.ve 1. bitleri ile PLL0 için saat kaynağı seçilir.

00->Internal RC osilatör seçilir.

01->Main Osilatör seçilir.(Biz uygulamamızda bunu seçeceğiz)

10->RTC osilatörü seçilir.

11->Rezerve (Kullanılmıyor).

CLKCFG:Bu registerın ilk 7 biti ile pll frekansını kaça böleceğimizi belirleriz. Mesela 0. biti aktif ettiğimizde 1 e 1.biti aktif ettiğimizde 2 ye… bölünür.

PLL0CON:Bu register ile pll aktifleştirilir ve pll bağlantısı sağlanır.

  • PLLE0:0. bit set edilirse PLL0 aktifleşir.Edilmezse pasif durumda kalır.
  • PLLC0:1. bit set edilirse PLL0 cpu saat kaynağı olur ve PLL0 AHB ve APB çevre birimlerine bağlanır.

PLL0CFG: Bu register ile PLL0’ın multiplier ve divider değerleri belirlenir.

  • MSEL0:14:0 bitleri ile M değeri belirlenir.Bu bitlerde M-1 değerinin saklanması gerekir.
  • NSEL0:23:16 bitleri ile N değeri belirlenir. Bu bitlerde N-1 değerinin saklanması gerekir.

örnek: 12 mhz lik kristal osilatörden 100 mhz elde etmek istersek.

FCCO=(2x(MSEL0+1)xFin)/(NSEL0+1)   formülünde MSEL0=49,NSEL0=2 olursa FCCO=400 çıkar. Burada FCCO PLLCLK frekansımız Fin ise osilatör frekansımızdır. Buradan çıkan FCCO değerini de PLLCFG registerı ile de 4’e bölersek 100 mhz lik çalışma frekansı elde etmiş oluruz.

PLL0FEED :Yapılan pll ayarlarının aktif olabilmesi için bu register’a ilk olarak 0xAA daha sonra 0x55 değerlerinin yüklenmesi gerekir.

PLL0STAT: Bu register ile PLL0’ın o andaki kontrol ve konfigürasyon bitlerinin durumu öğrenilir.

  • MSEL0:14:0 bitleri ile MSEL0’ın değeri öğrenilir.
  • NSEL0:23:16 bitleri ile NSEL0’ın değeri öğrenilir.
  • PLLE0_STAT: 24.bit ile PLL0 ın aktif olup olmadığı öğrenilir.Bu bit ‘1’ ise PLL0 aktiftir.’0′ ise pasiftir.
  • PLLC0_STAT:25.bit ile PLL0’ın CPU saat kaynağı olup olmadığı öğrenilir. Eğer PLLE0_STAT ve PLLC0_STAT  ‘1’ ise PLL0 cpu saat kaynağı olarak bağlanmıştır.
  • PLOCK0:PLL0 ın kilitlenip kilitlenmediğini gösterir. PLL0 ayarları yapıldıktan sonra bu bit ‘1’ olana kadar beklenir. Aksi halde pll kitlenemez.

Not: PLL ayarları ile cpu frekansını en fazla 100 mhz’e çıkarmanızı öneririm ve pll ayarlarını yapmadan önce for ya while döngüleri ile bekleme koymakta fayda var. Pll ayarlarını yaptıktan sonra istenilen frekansa kilitlenip kilitlenmediğini öğrenmek için simülatör modunda debug yapabilirsiniz.

PLL ve clock ayarlarını yaptıktan sonra artık uygulamamızın tamamını yazabiliriz. Uygulamadan bahsedecek olursak:

ADC pinine bağlı pot ile oynayarak gerilim değişimlerini timer kesmesi kullanarak 250 ms de bir uart üzerinden pc ye göndereceğiz.

#include <lpc17xx.h> #include <stdio.h> #include "lpc17xx_uart.h" #include "lpc17xx_adc.h" void pll_init(void) { int i;  for(i=0;i<10000;i++);//her ihtimale karşı bekleniyor.   LPC_SC->SCS=0x20; LPC_SC->CLKSRCSEL=0x01; //select main oscilator LPC_SC->CCLKCFG=0x03; //pllclk/4 LPC_SC->PLL0CON=0x01; //pll'aktifleştiriliyor LPC_SC->PLL0CFG=0x20031; //msel=49,nsel=2; LPC_SC->PLL0FEED=0xAA; //ayalar aktifleştiriliyor LPC_SC->PLL0FEED=0x55; while(!(LPC_SC->PLL0STAT&(1<<26))); //pll'in kilitlenmesi bekleniyor. LPC_SC->PLL0CON=0x07; //pll cpu saat kaynağı oluyor. LPC_SC->PLL0FEED=0xAA;//ayarlar aktifleştiriliyor. LPC_SC->PLL0FEED=0x55; } void TIMER1_IRQHandler(void) //timer kesmesi { uint32_t gerilim,kusurat,tam; char f[10]=" "; LPC_TIM1->IR=0xFF;; gerilim=adc_sonuc_al(); tam=gerilim/1000; // mv değeri volt'a dönüştürülüyor. kusurat=gerilim%1000; kusurat=kusurat/10; LPC_GPIO2->FIOPIN=tam; //gerilimin tam kısmı Port2 deki ledlerde gözlemkeniyor. sprintf(f,"%d,%d v\n\r",tam,kusurat); send_string(f); // gerilim değeri uarttan gönderiliyor. } void timer_init(void) { LPC_TIM1->TCR=0x02;//reset timer LPC_TIM1->IR=0xFF;//tüm kesmeleri restle LPC_TIM1->MR0=250*25000;//timer1 250ms'de bir kesme oluşturacak şekilde ayarlanıyor. LPC_TIM1->MCR=3;//timer counter MR0 değerine eşit olduğunda kesme oluşturuluyor ve MR0 resetleniyor. LPC_TIM1->TCR=0x01;//start timer LPC_TIM1->PR=0x00;//prescalar deger.Örnegin 2 oldugun her 3 tick de bir sayar. NVIC_EnableIRQ(TIMER1_IRQn);// Timer1 kesmesi aktifleştiriliyor. } int main(void) { pll_init(); uart_init(); adc_init(); timer_init(); LPC_GPIO2->FIODIR=255; LPC_GPIO2->FIOCLR=255; while(1) { } }

Seri porttan veri okumak için yazmış olduğum seri port monitör programını kullanabilirsiniz.

Option sekmesinden stop bit,parity biti handshake,baud rate gibi her türlü bağlatı ayarını yapabilirsiniz.

Process sekmesinden de veri alıp veri gönderebilirsiniz. Save butonu ile alınan verileri .txt dosyası olarak kaydedebilirsiniz.Add butonu ile de herhangi bir .txt dosyasındaki verileri uarttan gönderebilirsiniz.

Proramı Buradan indirebilrsiniz

Uygulamamızı böylelikle bitirmiş olduk. Uygulamaya ait çekdiğim video aşağıdadır. Eğer takıldığınız bir yer varsa sorabilirsiniz. Umarım faydalı olabilmişimdir. İyi çalışmalar.

Yusuf  YAMAK

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

www.mcu-turkey.com

Basics of UART Communication

Remember when printers, mice, and modems had thick cables with those huge clunky connectors? The ones that literally had to be screwed into your computer? Those devices were probably using UARTs to communicate with your computer. While USB has almost completely replaced those old cables and connectors, UARTs are definitely not a thing of the past. You’ll find UARTs being used in many DIY electronics projects to connect GPS modules, Bluetooth modules, and RFID card reader modules to your Raspberry Pi, Arduino, or other microcontrollers.

UART stands for Universal Asynchronous Receiver/Transmitter. It’s not a communication protocol like SPI and I2C, but a physical circuit in a microcontroller, or a stand-alone IC. A UART’s main purpose is to transmit and receive serial data.

One of the best things about UART is that it only uses two wires to transmit data between devices. The principles behind UART are easy to understand, but if you haven’t read part one of this series, Basics of the SPI Communication Protocol, that might be a good place to start.

Introduction to UART Communication

In UART communication, two UARTs communicate directly with each other. The transmitting UART converts parallel data from a controlling device like a CPU into serial form, transmits it in serial to the receiving UART, which then converts the serial data back into parallel data for the receiving device. Only two wires are needed to transmit data between two UARTs. Data flows from the Tx pin of the transmitting UART to the Rx pin of the receiving UART:

UARTs transmit data asynchronously, which means there is no clock signal to synchronize the output of bits from the transmitting UART to the sampling of bits by the receiving UART. Instead of a clock signal, the transmitting UART adds start and stop bits to the data packet being transferred. These bits define the beginning and end of the data packet so the receiving UART knows when to start reading the bits.

When the receiving UART detects a start bit, it starts to read the incoming bits at a specific frequency known as the baud rate. Baud rate is a measure of the speed of data transfer, expressed in bits per second (bps). Both UARTs must operate at about the same baud rate. The baud rate between the transmitting and receiving UARTs can only differ by about 10% before the timing of bits gets too far off.

Both UARTs must also must be configured to transmit and receive the same data packet structure.

How UART Works

The UART that is going to transmit data receives the data from a data bus. The data bus is used to send data to the UART by another device like a CPU, memory, or microcontroller. Data is transferred from the data bus to the transmitting UART in parallel form. After the transmitting UART gets the parallel data from the data bus, it adds a start bit, a parity bit, and a stop bit, creating the data packet. Next, the data packet is output serially, bit by bit at the Tx pin. The receiving UART reads the data packet bit by bit at its Rx pin. The receiving UART then converts the data back into parallel form and removes the start bit, parity bit, and stop bits. Finally, the receiving UART transfers the data packet in parallel to the data bus on the receiving end:

UART transmitted data is organized into packets. Each packet contains 1 start bit, 5 to 9 data bits (depending on the UART), an optional parity bit, and 1 or 2 stop bits:

Start Bit

The UART data transmission line is normally held at a high voltage level when it’s not transmitting data. To start the transfer of data, the transmitting UART pulls the transmission line from high to low for one clock cycle. When the receiving UART detects the high to low voltage transition, it begins reading the bits in the data frame at the frequency of the baud rate.

Data Frame

The data frame contains the actual data being transferred. It can be 5 bits up to 8 bits long if a parity bit is used. If no parity bit is used, the data frame can be 9 bits long. In most cases, the data is sent with the least significant bit first.

Parity

Parity describes the evenness or oddness of a number. The parity bit is a way for the receiving UART to tell if any data has changed during transmission. Bits can be changed by electromagnetic radiation, mismatched baud rates, or long distance data transfers. After the receiving UART reads the data frame, it counts the number of bits with a value of 1 and checks if the total is an even or odd number. If the parity bit is a 0 (even parity), the 1 bits in the data frame should total to an even number. If the parity bit is a 1 (odd parity), the 1 bits in the data frame should total to an odd number. When the parity bit matches the data, the UART knows that the transmission was free of errors. But if the parity bit is a 0, and the total is odd; or the parity bit is a 1, and the total is even, the UART knows that bits in the data frame have changed.

Stop Bits

To signal the end of the data packet, the sending UART drives the data transmission line from a low voltage to a high voltage for at least two bit durations.

Steps of UART Transmission

1. The transmitting UART receives data in parallel from the data bus:

2. The transmitting UART adds the start bit, parity bit, and the stop bit(s) to the data frame:

3. The entire packet is sent serially from the transmitting UART to the receiving UART. The receiving UART samples the data line at the pre-configured baud rate:

4.  The receiving UART discards the start bit, parity bit, and stop bit from the data frame:

5. The receiving UART converts the serial data back into parallel and transfers it to the data bus on the receiving end:

Advantages and Disadvantages of UARTs

No communication protocol is perfect, but UARTs are pretty good at what they do. Here are some pros and cons to help you decide whether or not they fit the needs of your project:

Advantages

  • Only uses two wires
  • No clock signal is necessary
  • Has a parity bit to allow for error checking
  • The structure of the data packet can be changed as long as both sides are set up for it
  • Well documented and widely used method

Disadvantages

  • The size of the data frame is limited to a maximum of 9 bits
  • Doesn’t support multiple slave or multiple master systems
  • The baud rates of each UART must be within 10% of each other

Continue on to part three of this series, Basics of the I2C Communication Protocol to learn about another way electronic devices communicate. Or if you haven’t already, check out part one, Basics of the SPI Communication Protocol.

And as always, let us know in the comments if you have questions or anything else to add! If you liked this article and want to see more like it, be sure to subscribe- we send out an email when ever we publish new posts.

www.circuitbasics.com

MCU Turkey – FPGA İle Uart-Tx Modülü Tasarımı

Merhaba Arkadaşlar,

Bu yazımda sizlere FPGA ile UART-TX Modülü tasarımını anlatmaya çalışacağım.

Uygulamamızda Xilinx firmasının X3CS500E FPGA’sını kullanarak Uart-Tx modülü tasarlayıp bilgisayarımıza her 1 saniyede bir “Merhaba,Dünya” yazısı göndereceğiz.

İlk olarak uart protokolünden bahsedecek olursak:

UART=Universal Asynchronous Receiver/Transmitter  bir iletişim protokolüdür. Gönderilen veriler frameler halinde gönderilir. Bir frame’in içerisinde 1 start biti genelllikle 8 data biti (nadiren 5,6,7,9 da kullanılır), isteğe bağlı olarak 1 parity biti,1,1.5 veya 2 stop biti bulunur. Genellikle bir uart frame’inin yapısı aşağıdaki gibidir.

Uart protokolü rs-232,rs-485 gibi standartlar ile kullanılabir. Biz uygulamamızda rs-232’yi kullanacağız.

Bu uygulamada Nexys2 board’unu kullanacağım ve uygulamayı VHDL dilini kullanarak gerçekleştireceğiz. Bu kadar ön bilginin ardından uygulamamıza geçebiliriz.

Uygulamamız BaudRate Generator,TX modülü, TX FIFO,UART Unit ve Top Modül olmak üzere 5 modülden oluşmaktadır.

Baudrate Generator:

Bu modülde devremizin çalışma hızına uygun tick üretilmektedir. Genelde uart modülleri gelen sinyalden ayarlanan baud hızının 16 katı hızda örnek alır. Örneğin kristal hızımız 50 mhz ve baud hızımız 115200 olsun. Bu durumda bizim baud rate üreticimiz  saniyede 115200*16=1843200 puls üretmesi gerekir. Kristal hızımız da 50 mhz olduğu için (50*10^6)/1843200=27 dir. Bu durumda baud rete üreticimiz her 27 cycle’da bir pulse üretmesi gerekir.  115200 baud hızına göre tasarlanmış modülün kodları aşağıdadır:

  1. library IEEE;

  2. use IEEE.STD_LOGIC_1164.ALL;

  3. use IEEE.STD_LOGIC_ARITH.ALL;

  4. use IEEE.STD_LOGIC_UNSIGNED.ALL;

  5. entity mod_m_counter is

  6. generic( M:integer:=163; N:integer:=8);

  7. port(

  8. clk,reset:in std_logic;

  9. tick_out:out std_logic

  10. );

  11. end mod_m_counter;

  12. architecture Behavioral of mod_m_counter is

  13. signal count_reg,count_next:unsigned(N-1 downto 0);

  14. begin

  15. process(clk,reset)

  16. begin

  17. if reset='1' then

  18. count_reg<=(others=>'0');

  19. elsif clk'event and clk='1' then

  20. count_reg<=count_next;

  21. end if;

  22. end process;

  23. count_next<=(others=>'0') when count_reg=(M-1) else

  24. count_reg+1;

  25. tick_out<='1' when count_reg=(M-1) else

  26. '0';

  27. end Behavioral;

TX FIFO MODÜLÜ

Bu modülü seri port üzerinden göndereceğimiz verile için buffer görevi üstlenmektedir. Yani göndereceğimiz veriler ilk olarak bu modülde depolanır ve sırayala tek tek gönderilir. FIFO (First In First Out)’lar çalışma mantığı şöyledir:

İsminden de anlaşılacağı gibi FIFO ya ilk giren veri ilk olarak çıkar.

Bizim tasarımımızda wr_ptr ve rd_ptr adında iki adet gösterici mevcuttur. wr_ptr her zaman veri yazılacak adresi gösterir ve her veri girişinde değeri 1 artar. rd_ptr de her zaman okuma yapılacak olan adresi gösterir ve her okumada değeri 1 artar. Bu anlatığımı aşağıdaki şekilleri inceleyerek daha iyi anlayabilirsiniz.

Şimdi bu anlattıklarımızı gerçekleştirdiğimiz vhdl kodları aşağıdadır:

  1. library IEEE;

  2. use IEEE.STD_LOGIC_1164.ALL;

  3. use IEEE.STD_LOGIC_ARITH.ALL;

  4. use IEEE.STD_LOGIC_UNSIGNED.ALL;

  5. entity transmitter_fifo is

  6. generic(

  7. B:natural:=8;

  8. W:natural:=3

  9. );

  10. port(

  11. clk,reset:in std_logic;

  12. w_data:in std_logic_vector(B-1 downto 0);

  13. rd,wr:in std_logic;

  14. empty,full:out std_logic;

  15. rd_data:out std_logic_vector(B-1 downto 0)

  16. );

  17. end transmitter_fifo;

  18.  

  19. architecture Behavioral of transmitter_fifo is

  20. type reg_file_type is array (2**W-1 downto 0) of

  21. std_logic_vector(B-1 downto 0);

  22. signal array_reg:reg_file_type;

  23. signal w_ptr_reg,w_ptr_next,w_ptr_succ:std_logic_vector(W-1 downto 0);

  24. signal r_ptr_reg,r_ptr_next,r_ptr_succ:std_logic_vector(W-1 downto 0);

  25. signal full_reg,empty_reg,full_next,empty_next:std_logic;

  26. signal wr_op:std_logic_vector(1 downto 0);

  27. signal wr_en:std_logic;

  28. begin

  29. process(clk,reset)

  30. begin

  31. if(reset='1') then

  32. array_reg<=(others=>(others=>'0'));

  33. elsif(clk'event and clk='1' ) then

  34. if wr_en='1' then

  35. array_reg(conv_integer(unsigned(w_ptr_reg)))<=w_data;

  36. end if;

  37. end if;

  38. end process;

  39. rd_data<=array_reg(conv_integer(unsigned(r_ptr_reg)));

  40. wr_en<=wr and (not full_reg);

  41.  

  42. process(clk,reset)

  43. begin

  44. if reset='1' then

  45. w_ptr_reg<= (others=>'0');

  46. r_ptr_reg<= (others=>'0');

  47. full_reg<='0';

  48. empty_reg<='1';

  49. elsif clk'event and clk='1' then

  50. w_ptr_reg<=w_ptr_next;

  51. r_ptr_reg<=r_ptr_next;

  52. full_reg<=full_next;

  53. empty_reg<=empty_next;

  54. end if;

  55. end process;

  56.  

  57. w_ptr_succ<=std_logic_vector(w_ptr_reg+1);

  58. r_ptr_succ<=std_logic_vector(r_ptr_reg+1);

  59.  

  60. wr_op<=wr&rd;

  61.  

  62. process(wr_op,w_ptr_reg,r_ptr_reg,r_ptr_succ,w_ptr_succ,

  63. empty_reg,full_reg)

  64. begin

  65. w_ptr_next<=w_ptr_reg;

  66. r_ptr_next<=r_ptr_reg;

  67. empty_next<=empty_reg;

  68. full_next<=full_reg;

  69. case wr_op is

  70. when "00"=> -- no op

  71. when "01"=> --read

  72. if(empty_reg/='1') then

  73. r_ptr_next<=r_ptr_succ;--okuma yapıldıgı icin asla full olamaz

  74. full_next<='0';

  75. if(r_ptr_succ=w_ptr_reg) then--okuma yapılrken yazma poiter'ı ile okuma pointer'ı

  76. empty_next<='1'; --birbirine eişt olduğu iin fifo tamamen boşaldı

  77. end if;

  78. end if;

  79. when "10"=> --write

  80. if(full_reg/='1') then

  81. w_ptr_next<=w_ptr_succ;

  82. empty_next<='0';

  83. if(w_ptr_succ<=r_ptr_reg) then-- yazma yaplırken yazma pointer'ı ile okuma pointer'ı

  84. birbirine eşit olduu için fifo doldu

  85. full_next<='1';

  86. end if;

  87. end if;

  88. when others=>--eğer hem yazma hem okuma yapılırsa

  89. w_ptr_next<=w_ptr_succ;

  90. r_ptr_next<=r_ptr_succ;

  91. end case;

  92. end process;

  93. full<=full_reg;

  94. empty<=empty_reg;

  95. end Behavioral;

UART-TX Modülü

Bu modülde FIFO’dan gelen datalar baud rate generatorden gelen baud hızına göre uart protokolüne uygun hale getirelecektir. Yazının başında anlattığım gibi uart modülleri gelen veriden genellikle baud hızının 16 katı hızda örnek alır. Bu sebeple baud rate generator baud hızının 16 katı hızda puls üretir. Bu nedenle biz de baud rate generatorden gelen puls hızının 1/16 hızında bit göndermemiz gerekir. Yani bau rate generator’den gelen puls’lar sayılır ve her 16 olduğunda bir bit iletilir. Ayrıca uart protokülünde hat boşta iken hat ‘1’ seviyesindedir. İletişm başlayacağı zaman start biti sayesinde hat ‘0’ durumuna çekilir ve data bitleri gönderilmeye başlanır. Son olarak da isteğe bağlı olarak 1,1.5 veya 2 stop biti gönderilir ve bir frame tamamlanmış olur. Tüm bu anlattıkrımızı gerçekleştirdiğimiz FSM kod aşağıdadır:

  1. library IEEE;

  2. use IEEE.STD_LOGIC_1164.ALL;

  3. use IEEE.STD_LOGIC_ARITH.ALL;

  4. use IEEE.STD_LOGIC_UNSIGNED.ALL;

  5.  

  6. entity uart_tx is

  7. generic(

  8. DBIT:integer:=8;

  9. SB_TICK:integer:=16

  10. );

  11. port(

  12. clk,reset:in std_logic;

  13. tx_start:in std_logic;

  14. s_tick:in std_logic;

  15. data_in:in std_logic_vector(DBIT-1 downto 0);

  16. tx_done_tick:out std_logic;

  17. tx:out std_logic

  18. );

  19. end uart_tx;

  20.  

  21. architecture Behavioral of uart_tx is

  22. type state_type is (idle,start,data,stop);

  23. signal state_reg,state_next:state_type;

  24. signal b_reg,b_next:std_logic_vector(DBIT-1 downto 0);

  25. signal s_reg,s_next:unsigned(3 downto 0);

  26. signal n_reg,n_next:unsigned(2 downto 0);

  27. signal tx_reg,tx_next: std_logic;

  28. begin

  29. process(clk,reset)

  30. begin

  31. if reset='1' then

  32. state_reg<=idle;

  33. b_reg<=(others=>'0');

  34. n_reg<=(others=>'0');

  35. s_reg<=(others=>'0');

  36. tx_reg<='1';

  37. elsif clk'event and clk='1' then

  38. state_reg<=state_next;

  39. b_reg<=b_next;

  40. n_reg<=n_next;

  41. s_reg<=s_next;

  42. tx_reg<=tx_next;

  43. end if;

  44. end process;

  45.  

  46. process(state_reg,s_reg,n_reg,b_reg,tx_reg,

  47. data_in,s_tick,tx_start)

  48. begin

  49. state_next<=state_reg;-- latch oluşması engelleniyor

  50. b_next<=b_reg;

  51. n_next<=n_reg;

  52. s_next<=s_reg;

  53. tx_next<=tx_reg;

  54. tx_done_tick<='0';

  55.  

  56. case state_reg is

  57. when idle=> --bekleme durumu

  58. tx_next<='1';

  59. if tx_start='1' then

  60. state_next<=start;

  61. s_next<=(others=>'0');

  62. b_next<=data_in;

  63. end if;

  64. when start=> --start biti ekleniyor

  65. tx_next<='0';

  66. if s_tick='1' then

  67. if s_reg=15 then -- mod_m counter 1/16 hızda gönderiliyor

  68. state_next<=data;

  69. s_next<=(others=>'0');

  70. n_next<=(others=>'0');

  71. else

  72. s_next<=s_reg+1;

  73. end if;

  74. end if;

  75. when data=> --data bitleri ekleneyir

  76. tx_next<=b_reg(0);

  77. if s_tick='1' then

  78. if s_reg=15 then --mod_m counter'ın 1/16 hızda gönderiliyor

  79. s_next<=(others=>'0');

  80. b_next<='0'&b_reg(7 downto 1);

  81. if n_reg=(DBIT-1) then

  82. state_next<=stop;

  83. else

  84. n_next<=n_reg+1;

  85. end if;

  86. else

  87. s_next<=s_reg+1;

  88. end if;

  89. end if;

  90. when stop=>

  91. tx_next<='1';

  92. if s_tick='1' then

  93. if s_reg=(SB_TICK-1) then

  94. state_next<=idle;

  95. tx_done_tick<='1';

  96. else

  97. s_next<=s_reg+1;

  98. end if;

  99. end if;

  100. end case;

  101. end process;

  102. tx<=tx_reg;

  103. end Behavioral;

UART CORE

Bu modülde diğer 3 modülü birleştirip uart çekirdeğini tamamlamış olacağız. Bunu bir mikro-deneteleyicinin uart çevre birimi olarak düşünebilirsiniz. Bu modüle ait kodlar aşağıdadır:

  1. library IEEE;

  2. use IEEE.STD_LOGIC_1164.ALL;

  3. use IEEE.STD_LOGIC_ARITH.ALL;

  4. use IEEE.STD_LOGIC_UNSIGNED.ALL;

  5.  

  6. entity uart_main is

  7. generic(

  8. DVSR:integer:=27;

  9. DVSR_BIT:integer:=5;

  10. FIFO_W:integer:=5;

  11. SB_TICK:integer:=16;

  12. DBIT:integer:=8

  13. );

  14. port(

  15. clk,reset:in std_logic;

  16. wr_uart:in std_logic;

  17. w_data:in std_logic_vector(DBIT-1 downto 0);

  18. tx:out std_logic;

  19. tx_full: out std_logic

  20. );

  21. end uart_main;

  22.  

  23. architecture Behavioral of uart_main is

  24. signal baud_rate_tick:std_logic;

  25. signal fifo_data_out:std_logic_vector(DBIT-1 downto 0);

  26. signal tx_done_tick:std_logic;

  27. signal tx_fifo_empty,tx_fifo_not_empty:std_logic;

  28.  

  29. begin

  30. baud_gen_unit:entity work.mod_m_counter(Behavioral)

  31. generic map(M=>DVSR,N=>DVSR_BIT)

  32. port map(clk=>clk,reset=>reset,tick_out=>baud_rate_tick);

  33.  

  34. uart_tx_unit:entity work.uart_tx(Behavioral)

  35. generic map(DBIT=>DBIT,SB_TICK=>SB_TICK)

  36. port map(clk=>clk,reset=>reset,

  37. tx_start=>tx_fifo_not_empty,

  38. s_tick=>baud_rate_tick,

  39. data_in=>fifo_data_out,

  40. tx_done_tick=>tx_done_tick,tx=>tx);

  41.  

  42. tx_fifo_unit:entity work.transmitter_fifo(Behavioral)

  43. generic map(B=>DBIT,W=>FIFO_W)

  44. port map(clk=>clk,reset=>reset,

  45. w_data=>w_data,rd=>tx_done_tick,wr=>wr_uart,

  46. empty=>tx_fifo_empty,full=>tx_full,

  47. rd_data=>fifo_data_out);

  48.  

  49. tx_fifo_not_empty<=not tx_fifo_empty;

  50. end Behavioral;

Top Modül

Uart modülümüzü tasarladığımıza göre artık bu modülü kullanacağımız bi devre tasarlamamız gerekir. Bu modülü de bir mikro-denetleyicinin uart modülünü kullanarak seri-port ile iletişim kurduğunuz bir program gibi düşünebilirsiniz.

  1. library IEEE;

  2. use IEEE.STD_LOGIC_1164.ALL;

  3. use IEEE.STD_LOGIC_ARITH.ALL;

  4. use IEEE.STD_LOGIC_UNSIGNED.ALL;

  5. entity uart_test is

  6. port(

  7. clk,reset:in std_logic;

  8. data_out:out std_logic;

  9. led :out std_logic;

  10. led2:out std_logic

  11. );

  12. end uart_test;

  13.  

  14. architecture Behavioral of uart_test is

  15. type state_type is (wait_tick,send);

  16. signal state_reg,state_next:state_type;

  17. signal data_reg:std_logic_vector(7 downto 0);

  18. signal data_next:std_logic_vector(7 downto 0);

  19. signal data_out_reg:std_logic;

  20. signal wr_uart:std_logic;

  21. signal send_tick:std_logic;

  22. type word_array is array(0 to 14) of std_logic_vector(7 downto 0);

  23. constant sentence:word_array:=((X"4D"),(X"65"),(X"72"),(X"68"),(X"61"),(X"62"),(X"61"),

  24. (X"20"),(X"44"),(X"75"),(X"6E"),(X"79"),(X"61"),(X"0A"),(X"0D")); --Merhaba,Dünya Yazısının ascii kodları

  25. signal wrd:integer:=-1;

  26. signal yaz:std_logic;

  27. begin

  28. uart_unit: entity work.uart_main(BEHAVIORAL)

  29. port map(clk=>clk,reset=>reset,

  30. wr_uart=>wr_uart,w_data=>data_reg,

  31. tx=>data_out_reg,tx_full=>led);

  32.  

  33. process(clk,reset) --bir saniyelik tick oluturuluyo

  34. variable say,say2:integer;

  35. begin

  36. if reset='1' then

  37. say:=0;

  38. elsif clk'event and clk='1' then

  39. say:=say+1;

  40. if say=50000000 then

  41. send_tick<='1';

  42. say:=0;

  43. end if;

  44. if send_tick='1' then

  45. say2:=say2+1;

  46. if say2=1000 then-- her 1000/50000000 saniye de FIFO'ya bir harf gönderiliyor.

  47. say2:=0;

  48. yaz<='1';

  49. wrd<=wrd+1;

  50. if wrd=15 then

  51. wrd<=-1;

  52. send_tick<='0';

  53. yaz<='0';

  54. end if;

  55. else

  56. yaz<='0';

  57. end if;

  58. end if;

  59. end if;

  60. end process;

  61.  

  62. process(clk,reset)

  63. variable say,i:integer;

  64. begin

  65. if reset='1' then

  66. data_reg<="00000000";

  67. state_reg<=wait_tick;

  68. elsif clk'event and clk='1' then

  69. say:=say+1;

  70. state_reg<=state_next;

  71. data_reg<=data_next;

  72. end if;

  73. end process;

  74.  

  75. process(state_reg,send_tick,data_reg,yaz)

  76. begin

  77. state_next<=state_reg;

  78. data_next<=data_reg;

  79. wr_uart<='0';

  80. case state_reg is

  81. when wait_tick=>

  82. if send_tick='1' then

  83. state_next<=send;

  84. end if;

  85. when send=>

  86. if yaz='1' then

  87. wr_uart<='1';

  88. data_next<=sentence(wrd);

  89. end if;

  90. if wrd=14 then

  91. state_next<=wait_tick;

  92. end if;

  93. end case;

  94. end process;

  95. data_out<=data_out_reg;

  96. led2<=data_out_reg;

  97. end Behavioral;

Son olarak da projeye ait .ucf dosyası:

NET "data_out" LOC="P9"; NET "led" LOC="J14"; NET "led2" LOC="J15"; NET "reset" LOC="h23"; NET "clk" LOC="B8"; NET "clk" period=20 ns high 50%;

Uygulamaya ait video dosyası:

Seri porttan gelen verileri okumak için screen programını kullandım.

Takıldığınız yerleri cevaplamaktan memnuniyet duyarım.

İyi çalışmalar…

www.mcu-turkey.com

MCU Turkey – STM8S – UART Modülü Kullanımı

Merhaba arkadaşlar, bu yazımızda STM8S serisinde bulunan UART biriminden bahsedeceğiz. İlk olarak nasıl kullandıldığını ve konfigürasyon ayarlarının nasıl yapıldığını anlatıp sonrasında ise gönderdiğimiz dataları lojik analizör ile takip edeceğiz.  STM8S serisinde üç adet UART modülü (UART1, UART2 ve UART3) bulunabilmektedir. Bizim kullandığımız, STM8S VL Discovery kitimizde bulunan STM8S003K3 modelinde ise sadece UART1 modülü bulunmaktadır.

İlk olarak UART1 modülünün özelliklerinden kısaca bahsedelim.

  • Çift yönlü asenkron haberleşme
  • Yüksek doğrulukta baudrate üretebilme
  • 8 veya 9 bit data uzunluğunda kullanabilme
  • Ayarlanabilir stop biti sayısı (1-2bit)
  • Senkron haberleşme için sinyal çıkışı
  • IrDA ve SmartCard arayüzü
  • Tek hat üzerinden, tek yönlü haberleşebilme
  • 4 adet hata tespit bayrağı(overrun, noise, frame, parity)
  • 6 adet kesme alabilme özelliği
  • 2 adet kesme vektör adresi(RXI, TXI)
  • Azaltılmış güç tüketim modu
  • Çoklu işlemci haberleşme gibi özellikleri bulunmaktadır.

Özelliklerinden bahsettiğimiz UART1 modülünü, mcu içerisindeki tüm çevre birimlerinin olduğu yukarıdaki grafikten görebiliriz.

 — UART ÜZERİNE —

USART modülü mikrodenetleyicilerin çoğunda bulunan kullanımı basit ve standart seri RS232 haberleşme birimidir. Universal Synchronous Aynchronous Receiver Transmitter (Evrensel Senkron Asenkron Alıcı Verici) anlamına gelmektedir. Bu modülden gönderilmek istenen datalar, sıra ile lsb den msb ye doğru yani en düşük değerlikli bitten en yüksek değerlikli bite doğru gönderilir.  Gönderici taraf TX (transmitter) hattını data göndermezken Lojik1 seviyesinde tutar. Data gönderileceği anda hat Lojik 0 seviyesine çekilerek data gönderilmeye başlanır. Bu işlemdeki hattı Lojik 1 den Lojik 0 seviyesine çekme olayına start biti denir.  Yukarıdaki şekilde bunu daha iyi görmekteyiz zaten. Start bitinden sonra, datalar bit bit gönderilip dataların sonunda ise Stop biti gönderilir. Stop biti ise, son bitten sonra(MSB den sonra) hattı lojik 1 seviyesine çıkarma işlemidir. Eğer 9 bitlik data gönderimi veya parity(eşlik biti gönderimi yapılmıyor ise) bir byte data gönderimi için toplam 10 bit gönderilir. 1 start bit + 8 data bit + 1 stop bit..

Alıcı taraf ise hattın lojik1 den lojik0 seviyesine çekildiğinde data gönderiminin başladığını anlar gelen bitleri ayarlanan baudrate süresince alır ve buffer ı na yazar. Stop biti ile buffera gelen data yazılmış olur. Ve ilgili flag set edilir. Eğer kesme kullanıyorsak, kesme alt programına dallanır. Kesme kullanmıyor isek, buffer dolduğunda set edilen barağı sürekli kontrol ederek datanın gelmiş olduğunu anlarız.

Baudrate meselesine gelince… Baudrate 1 bitin ne kadar sürede gönderileceğini ve alınacağını belirleyen bps(bit per second – 1 saniyede gönderilen bit sayısı) birimi ile ölçülür.  Sizde birçok yerde görmüşsünüzdürki, Baudrate parametresi 1200,2400,4800,9600,19200,115200 gibi değerler almaktadır. Alıcı taraf ile gönderici tarafın baudrate değeri aynı olmalıdır ki, gönderilen datalar alıcı tarafında doğru bir şekilde alınabilsin.

Şimdi de bu modülün konfigürasyonunun yapılabilmesi için kullanacağımız register lara sıra ile bir göz atalım.

1. STATUS REGISTER (UARTx_SR)

RXNE : Read Data Register Not Empty

0 : Data alınmadı.

1 :  Data alındı ve okunmaya hazır.

TC : Transmission Completed

0 : Data gönderimi tamamlanmadı.

1 :  Data gönderimi tamamlandı.

TXE : Transmit Data Register Empty

0 : Data shift register a aktarılmadı.

1 :  Data shift register a aktarıldı.

2. DATA REGISTER (UART1_DR)

UART1_DR :

Data alınırken veya gönderilirken kullanılan 8 bitlik register

3.BAUDRATE REGISTER 1 (UART1_BRR1)

Baudrate register larından ilkidir. 16 bitlik baudrate önbölücü değerinin [11:4] bitlerini tutar. 

4.BAUDRATE REGISTER 2 (UART1_BRR2)

Baudrate register larından ikincisidir.. 16 bitlik baudrate önbölücü değerinin [15:12] bitlerini [3:0] bitlerinive  tutar. Nedenini bilmiyorum ama baudrate register larını garip bir şekilde bölmüşler..  Bu register lara yazılacak değerlerin nasıl hesaplanacağı konusuna, register lardan bahsedildikten sonra girilecektir. Birde şunu hatırlatmakta fayda var. UART1_BRR1 register ına değer yazıldığı anda baudrate değeri güncellendiğinden, önce BRR2 register ına, sonra BRR1 register ına gerekli değerin yüklenmesinde fayda vardır.

5. CONTROL REGISTER 2 (UART1_CR2)

 

REN : Receiver Enable

0 : Data alım birimi kapalı

1 : Data alım birimi açık, start sinyali bekleniyor.

TEN : Transmitter Enable

0 : Data gönderim birimi kapalı

1 : Data gönderim birimi açık.

RIEN : Receiver Interrupt Enable

0 : Data alındığında kesme üretilmez.

1 : Data alındığında kesme üretilir.

TCIEN : Transmission Complete Interrupt Enable

0 : Data gönderimi tamamlandığında kesme üretilmez.

1 : Data gönderimi tamamlandığında kesme üretilir.

TIEN : Transmitter Interrupt Enable

0 : Data shift register a aktarıldığında kesme üretilmez.

1 : Data shift register a aktarıldığında kesme üretilmez.

Toplamda UART birimi ile ilgili 6 adet kontrol register ı bulunmaktadır. Diğerlerinden burada bahsetmeyeceğiz. Detaylı bilgi için Reference Manual i inceleyebilirsiniz. Şimdi de baudrate değerinin hesaplanması konusundan bahsedelim.

BAUDRATE İÇİN UART1_BRR1 VE UART1_BRR2 DEĞERLERİNİN HESAPLANMASI

     

Yani hesaplanan 16 bitlik  UART1_DIV değerinin ortada kalan 8 bitlik kısmı UART1_BRR1 değerini, kenarlarda kalan 4 er bitlik nibble lardan oluşan 8 bitlik değeri ise UART1_BRR2 değerini oluşturmaktadır. UART biriminden bu kadar bahsettikten sonra, basit bir uygulama yapalım. İlk olarak yapacağımız uygulamamız şöyle olsun, UART birimiyle sürekli olarak aralarda gecikmeler olması şartıyla bir string veya sayı gönderelim. Ve sonucu izleyelim.

#include <iostm8s003k3.h> #include <intrinsics.h>   void InitClock(void) { CLK_ICKR_HSIEN = 1; while(!CLK_ICKR_HSIRDY); CLK_CKDIVR = 0x00; }   void InitUART(void) { UART1_BRR2 = 0x01; UART1_BRR1 = 0x34; UART1_CR2_REN = 1; UART1_CR2_TEN = 1; }   void SendByte(char i) { while(UART1_SR_TXE!=1); UART1_DR = i; }   void SendString(const char *s) { while(*s) SendByte(*s++); }   void __delay(void) { unsigned long int j=30000; while(j--); }   void main(void) { InitClock(); InitUART();   for(;;) { SendString("STM8S SERIES"); __delay(); } }

Gördüğünüz üzere STM8S serisi ile UART üzerinden istediğimiz datayı gönderebiliyoruz. Geldik bir yazımızın daha sonuna. Konu ilgili sorunuz varsa sorabilirsiniz. Bir sonraki yazımızda görüşmek dileğiyle, hoşçakalın..

Ferudun GÖKCEGÖZ

[email protected]

www.mcu-turkey.com

How to use UART in ARM Cortex-M3 LPC1768

 

This Project demonstrates how to use UART in ARM Cortex-M3 LPC1768. In this project we are doing serial communication between PC and LPC1768 Board using MAX232. We are using 9600 baud rate for serial communication. Here data will be sent by PC (Teraterm) and on the other end we are receiving data in LPC1768 Microcontroller Board. Data received in microcontroller now will be sent back again to PC to show on terminal.

 

First of all we will see how to configure UART in LPC1768 –

  1. Power: In the PCONP (Power Control for Peripherals) register set bit  PCUART0. It will make the UART0 operational.

2)     Baud rate: In register U0LCR, set bit DLAB =1. This enables access to registers DLL and DLM for setting the baud rate. Also, if needed, set the fractional baud rate in the fractional divider register.

3)     UART FIFO: Use bit FIFO enable (bit 0) in register U0FCR to enable FIFO.

4)     Pins: Select UART pins through the PINSEL registers (For UART0 we should use PINSEL0).

5)     Tx/Rx: Use U0THR and U0RBR for data transmission and reception.

6)     Status: Use U0LSR register for the status of data.

Baud rate Calculation: The Baud rate of this Microcontroller can be calculated by following equation –

DL = PCLK/(16 x BR)

Here,

            PCLK = Peripheral Clock Frequency

            BR = Required Baud rate i.e. 9600

            DL = It is the combination of DLM and DLL registers.

There are two conditions for calculating baud rate –

Example 1 :  BR = 9600 and PCLK = 14.7456 MHz

According to the provided algorithm DLest = PCLK/(16 x BR) = 14.7456 MHz / (16 x 9600) = 96. Since this DLest is an integer number, DIVADDVAL = 0, MULVAL = 1, DLM = 0, and DLL = 96.

Example 2 :  BR = 115200 and PCLK = 12 MHz

According to the provided algorithm DLest = PCLK/(16 x BR) = 12 MHz / (16 x 115200) = 6.51. This DLest is not an integer number and the next step is to estimate the FR parameter. Using an initial estimate of FRest = 1.5 a new DLest = 4 is calculated and FRest is recalculated as FRest = 1.628. Since FRest = 1.628 is within the specified range of 1.1 and 1.9, DIVADDVAL and MULVAL values can be obtained from the attached look-up table.

The closest value for FRest = 1.628 in the look-up table is FR = 1.625. It is equivalent to DIVADDVAL = 5 and MULVAL = 8.

Based on these findings, the suggested UART setup would be: DLM = 0, DLL = 4, DIVADDVAL = 5, and MULVAL = 8. According to equation the UART rate is 115384.This rate has a relative error of 0.16% from the originally specified 115200.

Code Explanation:

1)     SystemInit : This will initialize the system clock frequency, PLL settings and peripheral clock frequency for the LPC1768. It will generate System clock = 72 MHz, PCLK(Peripheral clock) = 18 MHz.

2)     uart0_pinconfig : It will configure the P0.2 pin as UART0 Tx and P0.3 pin as UART0 Rx to enable the serial communication over these pins.

3)     init_uart0 : This routine will initialize the uart0 at 9600 baud rate. First of all to access the DLL and DLM registers we need to make DLAB bit high in LCR register. After  this we have to move baud rate value into DLL and DLM registers. After moving baud rate values, we again need to clear the DLAB bit of LCR register so that we can access the THR and RBR registers.

4)     uart0_rx : In this routine we are monitoring the receive status bit RDR in U0LSR register for complete data reception. If the data has been arrived in U0RBR register then this bit will become high. Now you can move the data to any variable.

5)     uart0_tx : This routine will send the data byte into U0THR register and after that it will monitor the THRE bit in the U0LSR register until this bit become high.

So we are continuously sending the data byte through PC and receiving the data in LPC1768  microcontroller and again we are sending back the data byte which has been received to the PC and that data byte will be shown on terminal(i.e. Hyper terminal, Tera term etc).

.

www.engineersgarage.com


Смотрите также