About

Ahmad Edi Saputra

Thursday, November 17, 2016

Direct Addressing AVR GPIO with C

Pada dasarnya GPIO hanyalah peripheral yang tersambung pada prosesor dengan address tertentu, penulisan terhadap alamat memori ini dapat mengakibatkan perubahan output pada GPIO. Register PORTx, DDRx, dan PINx pada prosesor arsitektur AVR tentu sudah sangat familiar. Namun sudah tahukah kemana definisi PORTx, DDRx, dan PINx ini mengarah? jawabanya ada di datasheet atau di library iomXXX.h misalnya pada arduino Uno ada pada "iom328p.h". berikut ini contoh memory map pada datasheet




Pada kolom address, PORTD ada pada address 0x2B, dan DDRD ada pada address 0x2A. Penulisan pada alamat 0x2A dan 0x2B akan mempengaruhi pin D pada ATMega, dengan kata lain, menuliskan 0x2A=0xFF akan sama dengan menulis DDRD=0xFF dan port D akan berfungsi sebagai output. Tetapi kompiler akan bingung dalam proses kompilasi, untuk itu perlu dilakukan konversi yang menjadikan 0x2A  di anggap kompiler sebagai alamat, bukan sebuah nilai. Untuk itu, dengan menggunakan fitur paling power full yang disediakan bahasa C, yaitu pointer, 0x2A dapat dijadikan sebagai alamat.

Untuk mengingat kembali sistem pointer pada C,berikut ini merupakan contoh penggunaan pointer C secara sederhana

unsigned char *pointer = 0x00;

Inisialisasi diatas akan menyebabkan variabel pointer diatas memiliki alamat yang tidak tetap, tergantung compiler. dan biasanya alamat tersebut akan mendapat alamat terkecil dari RAM. Karena bahasa merupakan bahasa paling fleksibel, maka untuk memberi tahu kompiler bahwa variabel pointer harus berada pada alamat tertentu adalah dengan cara mengkonversi nilai menjadi pointer itu sendiri seperti

unsigned char *pDDRD  = (unsigned char *)0x2A; //agar sesuai dengan alamat DDRD


Setelah inisialisasi diatas maka alamat dari variable pDDRD akan menjadi 0x2A. untuk mengisi nilai dari pDDRD itu sendiri sama dengan pengisian nilai pointer pada umumnya yaitu dengan menggunakan tanda * seperti

*pDDRD = 0xFF;

penulisan diatas akan sama dengan DDRD = 0xFF, sedangkan untuk menulis logika high pada port D, karena port D berada pada alamat 0x2B, maka

unsigned char * pPORTD = (unsinged char *)0x2B;
*pPORTD = 0xFF;

untuk menghindari variable yang digunakan sebagai alamat dari GPIO, sebaiknya gunakan identifier volatile, dimana volatile mencegah kompiler untuk mengoptimasi objek dengan identifier volatile, meskipun dengan tingkat optimasi tertinggi. berikut contohnya:

volatile unsigned char *pPORTD = (volatile unsigned char *)0x2B;

Lalu bagaimana dengan file iom328.h yang disebut sebelumnya, apakah sesuai dengan penjelasan?
Berikut ini isi filenya
 

Kenapa berbeda? kenapa PORTD 0x0B bukan 0x2B seperti yang dibahas sebelumnya??? karena offset dari fungsi _SFR_IO8 sendiri memiliki offset ox20 seperti yang dapat dilihat pada file "avr/sfr_defs.h"

Sekian tutorialnya, semoga bermanfaat