Archive

Posts Tagged ‘Belajar AVR Assembler’

Akses Baca-Tulis EEPROM ATtiny2313

March 27, 2009 5 comments

avrmnemonic2AVR ATtiny2313 memiliki EEPROM dengan kapasitas 128 byte dengan alamat akses 0-127 ($00-$7F). Untuk mengakses EEPROM terlebih dahulu harus mengetahui register-register EEPROM, yakni: EEAR – EEPROM Address Register, EEDR – EEPROM Data Register, dan EECR – EEPROM Control Register.

EEAR adalah register yang berfungsi menyimpan alamat EEPROM yang akan diakses. Untuk ATtiny2313, EEAR disebut juga EEARL (EEAR Low). Yup, hanya perlu 7 bit LSB saja (EEAR0..EEAR6) untuk mengakses seluruh alamat EEPROM ATtiny2313. Nilai awal EEAR setelah direset tidak didefinisikan, jadi EEAR perlu diisi dengan alamat EEPROM yang benar sebelum data pada EEPROM diakses (dibaca/ditulis/dihapus).

EEDR adalah register yang berfungsi menyimpan data yang akan ditulis ke EEPROM dan data yang dibaca dari EEPROM.

EECR adalah register yang berfungsi untuk mengontrol sinyal-sinyal kontrol untuk proses akses EEPROM. Pada tulisan ini hanya dibahas tentang bagaimana menulis data ke EEPROM dan bagaimana membaca data dari EEPROM. Oleh karena itu, hanya 3 bit LSB dari EECR saja yang akan dibahas yakni:

  • Bit 2 – EEMPE (EEPROM Master Program Enable)
  • Bit 1 – EEPE (EEPROM Program Enable)
  • Bit 0 – EERE (EEPROM Read Enable)

Proses menulis data ke EEPROM memerlukan langkah-langkah berikut ini:

  1. Letakkan alamat EEPROM yang dituju dalam register EEAR
  2. Letakkan data dalam register EEDR
  3. Cek apakah bit EEPE=0, jika tidak maka tunggu
  4. Set bit EEMPE
  5. Set bit EEPE

Mudah bukan? Demikian juga halnya dengan proses membaca data dari EEPROM, berikut langkah-langkahnya:

  1. Letakkan alamat EEPROM yang akan diakses dalam register EEAR
  2. Cek apakah bit EEPE=0, jika tidak maka tunggu
  3. Set bit EERE
  4. Baca data dari EEDR dan simpan di register

Bit EEPE adalah bit untuk menulis data ke EEPROM. Jika EEPE diset 1 ketika EEMPE=1, maka data pada EEDR akan ditulis ke EEPROM pada alamat yang ditunjukkan oleh register EEAR. Setelah 4 siklus clock, maka CPU akan mereset kembali bit EEPE=0 yang menandakan bahwa proses penulisan telah selesai dilakukan. Oleh karena itu sebelum melakukan proses penulisan, program harus memastikan bahwa kondisi EEPE=0, yang artinya CPU tidak sedang melakukan proses penulisan ke EEPROM. Jika tidak maka proses penulisan akan gagal. Demikian juga halnya ketika membaca data dari EEPROM. Sebelum membaca data, program harus memastikan bahwa CPU tidak sedang dalam proses penulisan data ke EEPROM, jika tidak maka proses pembacaan akan gagal.

Contoh Program

; ***********************************************
; EEPROM.ASM
; Program contoh baca/tulis EEPROM pada ATtiny2313
; ***********************************************

.include “C:\MICROC~1\VMLAB\include\2313def.inc”

;Untuk AVR Studio 4, ganti include-nya dengan yang ini:
;.include “tn2313def.inc”

;Untuk VMLAB, ini diperlukan. Untuk AVR Studio 4 tidak.
.equ eepe = eewe
.equ eempe = eemwe

reset:
rjmp start
reti      ; Addr $01
reti      ; Addr $02
reti      ; Addr $03
reti      ; Addr $04
reti      ; Addr $05
reti      ; Addr $06
reti      ; Addr $07
reti      ; Addr $08
reti      ; Addr $09
reti      ; Addr $0A
reti      ; Addr $0B
reti      ; Addr $0C
reti      ; Addr $0D
reti      ; Addr $0E
reti      ; Addr $0F
reti      ; Addr $10

start:
;selalu diawali dengan pengesetan alamat stack
ldi    r16, low (ramend)
out    spl, r16

ldi    r16, $54    ; data di R16
ldi    r17, 0        ; alamat di R17
rcall    EEPROM_write    ; tulis $54 ke EEPROM alamat 0

ldi    r16, $CA    ; data di R16
ldi    r17, 5        ; alamat di R17
rcall    EEPROM_write    ; tulis $CA ke EEPROM alamat 5

ser    r16        ; R16 = $FF
ldi    r17, 0        ; R17 = 0
rcall    EEPROM_read    ; Baca EEPROM alamat 0 dan simpan di R16

forever:
rjmp forever        ; never ending jump

; Subrutin menulis data ke EEPROM dengan alamat 0-127
EEPROM_write:
sbic    eecr, eepe    ; apakah EEPE=0?
rjmp    EEPROM_write    ; tunggu jika EEPE=1
out    EEAR, r17    ; set alamat EEPROM
out    EEDR, r16    ; letakkan data di EEDR
sbi    EECR, eempe    ; set bit EEMPE
sbi    EECR, eepe    ; set bit EEPE
ret

; Subrutin membaca data dari EEPROM dengan alamat 0-127
EEPROM_read:
sbic    eecr, eepe    ; apakah EEPE=0?
rjmp    EEPROM_read    ; tunggu jika EEPE=1
out    eear, r17    ; set alamat EEPROM
sbi    eecr, eere    ; set bit EERE
in    r16, eedr    ; copy data dari EEDR ke R16
ret

Catatan: Program di atas dibuat dengan asumsi bahwa program sama sekali tidak menggunakan fitur interupsi dalam program. Gunakan instruksi CLI dan SEI sebelum dan sesudah proses baca-tulis EEPROM agar segala sesuatunya berjalan mulus, hehehe…

Berikut adalah cuplikan gambar Window Memori EEPROM dan Window Register dari VMLAB dan AVR Studio 4.

eepromvmlabWindow EEPROM VMLAB

registervmlabWindow Register VMLAB

eepromavrstudio4Window EEPROM AVR Studio 4

registeravrstudio4Window Register AVR Studio 4

Ok. Selamat belajar!

Mengakses Memori Program AVR Dengan Instruksi LPM (Load Program Memory)

March 21, 2009 2 comments

avrmnemonic1Memori program adalah memori dimana program mikrokontroler disimpan. Tidak hanya program, tapi juga konstanta-konstanta program.

Untuk mengakses memori program AVR digunakan instruksi LPM (Load Program Memory). Instruksi LPM berfungsi membaca satu byte data pada memori program dengan alamat yang ditunjuk oleh Register Z dan meng-copy-nya ke suatu register (R0-R31). Perlu diketahui bahwa tidak semua tipe mikrokontroler AVR mendukung instruksi LPM, salah satu contohnya adalah AT90S1200.

Memori program AVR diatur dalam satuan word (16-bit), sementara Register Z menunjuk alamat memori program dalam satuan byte. 1 word kan tersusun dari 2 byte yakni high-byte (8-bit MSB) dan low-byte (8-bit LSB).

Jadi, manakah yang dibaca oleh instruksi LPM? Byte atas atau byte bawah? Untuk menentukan hal itu, digunakan bit terendah (Least Significant Bit) dari Register Z (ZLSB). Jika ZLSB=0, maka instruksi LPM akan membaca byte bawah pada alamat memori program yang ditunjuk oleh Register Z. Sebaliknya, jika ZLSB=1, maka instruksi LPM akan membaca byte atas.

Instruksi LPM memiliki beberapa varian yakni:

  1. LPM R0 <- (Z)
  2. LPM Rd, Z Rd <- (Z)
  3. LPM Rd, Z+ Rd <- (Z); Z = Z + 1

LPM varian pertama (tanpa operand) membaca data pada memori program dengan alamat yang ditunjukkan oleh Register Z dan meng-copy-nya ke register R0.

Varian kedua membaca data pada memori program dengan alamat yang ditunjukkan oleh Register Z dan meng-copy-nya ke register Rd (R0-R31).

Varian ketiga bekerja seperti varian kedua, hanya saja setelah data di-copy ke register Rd, nilai Register Z akan bertambah satu sehingga pointer Z akan menunjuk ke data pada alamat berikutnya.

Untuk lebih mempertajam pemahaman, maka berikut adalah contoh penerapan instruksi LPM pada program Running LED yang disimulasikan menggunakan VMLAB.

Jika pada tulisan sebelumnya (VMLAB – Running LED) digunakan instruksi ROL (Rotate Left) untuk memutar komposisi bit, maka dalam program ini akan digunakan instruksi LPM. Anda bisa menggunakan proyek pada tulisan VMLAB – Running LED dan memodifikasi file program assemblernya saja. Berikut adalah file program assemblernya.

; ********************************************
; LPM.ASM
; Contoh aplikasi LPM pada program Running LED
; ********************************************

.include “C:\MICROC~1\VMLAB\include\m8def.inc”

.def  temp  =r16

reset:
rjmp start
reti
reti
reti
reti
reti
reti
reti
reti
reti
reti
reti
reti
reti
reti
reti
reti
reti
reti

; Program starts here after Reset
start:
ldi    temp, low (ramend)
out    spl, temp
ldi    temp, high (ramend)
out    sph, temp

ser    r16
out    ddrb, temp

point_to:
ldi    zl, low (tabel<<1)
ldi    zh, high (tabel<<1)

forever:
lpm   temp, z+
com    temp
out    portb, temp

cpi    temp, $7f
breq    point_to

rcall    delay

rjmp    forever

delay:
ldi temp, 3

satu:
dec temp
brne satu
ret

tabel:
.db 1, 2, 4, 8, 16, 32, 64, 128

Selanjutnya, Anda bisa menjalankan simulatornya. Hasilnya akan sama dengan VMLAB – Running LED yang menggunakan ROL.

Perhatikan bagian program yang dicetak tebal. Instruksi ldi zl, low (tabel<<1) berfungsi untuk mengambil data alamat byte bawah dari label tabel dalam memori program dan disimpan di byte bawah Register Z (ZL). Instruksi berikutnya, ldi zh, high (tabel<<1), berfungsi mengambil data alamat byte atas dari label tabel dan disimpan di byte atas Register Z (ZH). Operator bit shift-left (geser ke kiri), berfungsi untuk mengisi ZLSB=0 yang berarti instruksi LPM akan mengambil byte bawah dari alamat yang ditunjuk oleh Register Z.

Selanjutnya instruksi lpm temp, z+ akan mengambil data (1 byte) dari memori program dengan alamat yang ditunjuk oleh Register Z, dan kemudian menaikkan Register Z satu (Z=Z+1) sehingga secara otomatis Register Z akan menunjuk ke lokasi byte berikutnya dari tabel data.

Instruksi com temp berfungsi membalik semua bit pada register R16 (yang sudah diberi nama temp). Ingat, rangkaian LED yang digunakan adalah rangkaian common-anode, yang berarti LED aktif low.

Setelah itu instruksi out portb, temp akan meng-update tampilan LED. Instruksi cpi temp, $7f dan breq point_to berfungsi untuk mengecek apakah pembacaan data sudah sampai pada data kedelapan, kalau sudah pembacaan harus diulangi lagi dari data pertama.

Ok, selamat mencoba dan selamat belajar!

Instruksi LDI dan Direktif DEF

March 11, 2009 1 comment

avrmnemonicInstruksi LDI (Load Immediate) digunakan untuk meng-copy nilai konstanta 8-bit (1 byte) ke dalam suatu register (R16 – R31). Instruksi ini tidak mempengaruhi Register Status (SREG). Sintaksis: LDI Rn, <konstanta>. Rn adalah salah satu register dari R16 – R31. <konstanta> adalah bilangan 0 – 255 yang dapat ditulis dalam format biner, oktal, desimal, atau hexadesimal. Setelah instruksi dieksekusi, maka register yang bersangkutan akan berisi nilai konstanta. Instruksi yang dieksekusi dalam 1 siklus ini menempati 1 word dari memori program.

Direktif DEF berfungsi untuk memberi nama spesifik pada suatu register. Pemberian nama bertujuan untuk memudahkan penulisan program. Dibandingkan dengan menghafalkan nomor register, masih jauh lebih mudah menghafalkan nama spesifik yang biasanya sesuai dengan fungsinya dalam program atau subrutin.

Boleh juga dianalogikan begini. Pada pemrograman Pascal atau C/C++ kita harus mendeklarasikan variabel sebelum dapat digunakan dalam program. Menempati alamat memori manakah variabel-variabel yang kita deklarasikan? Kita baru akan tahu kalau program kita dieksekusi.

Pada pemrograman assembler, pemrogram telah dibekali dengan sejumlah register yang dapat digunakan sebagai variabel sementara dalam program. Nama register jelas dan jumlahnya terbatas. Register bisa langsung digunakan dalam program assembler, kita tidak perlu lagi mendeklarasikannya. Kita hanya perlu memberinya nama, nama yang spesifik sesuai dengan fungsinya dalam program. Itulah fungsi direktif DEF. Direktif DEF dapat diletakkan bebas di mana saja dalam program assembler.

Apabila membutuhkan variabel global dalam SRAM, maka dapat digunakan direktif DSEG yang dikombinasikan dengan label dan direktif BYTE, yang (maaf) tidak dibahas dalam tulisan ini.

Biar lebih gamblang, mari kita aplikasikan LDI dan DEF di dalam sebuah program menggunakan simulator VMLAB. Berikut adalah program assemblernya untuk ATmega8 yang berfungsi melakukan perkalian register dan menyimpan hasilnya dalam register.

; LDIDEF.ASM

.include “C:\MICROC~1\VMLAB\include\m8def.inc”

.def panjang1 = r16
.def lebar1 = r17
.def luas1 = r18

.def panjang2 = r16
.def lebar2 = r17
.def luas2 = r20

.cseg
.org 0000

rjmp start

start:
ldi    panjang1, 8
ldi    lebar1, $10
mul    panjang1, lebar1
movw    luas1, r0

ldi    panjang2, 0b1010
ldi    lebar2, 18
mul    panjang2, lebar2
movw    luas2, r0

forever:
rjmp forever

Penjelasan Program
Direktif INCLUDE memberitahu assembler untuk menyertakan file m8def.inc dalam proses kompilasi. Mungkin Anda perlu mengganti path-nya untuk disesuaikan dengan lokasi file m8def.inc dalam komputer Anda.

.def panjang1 = r16
.def lebar1 = r17
.def luas1 = r18

Selanjutnya, dengan menggunakan direktif DEF, register R16 diberi nama panjang1, register R17 diberi nama lebar1, dan register R18 diberi nama luas1. Tanpa dijelaskan pun, kita sudah tahu bahwa R16 digunakan untuk menyimpan data panjang, R17 untuk menyimpan data lebar, dan R18 untuk menyimpan data luas dari suatu persegipanjang.

.def panjang2 = r16
.def lebar2 = r17
.def luas2 = r20

Pada baris selanjutnya terdapat tiga baris direktif DEF lagi. Kali ini R16 diberi nama panjang2, R17 diberi nama lebar2, dan R20 diberi nama luas2. Lho? R16 dan R17 kok masing-masing punya dua nama? Iya, benar. Gak masalah kok. Kita memang dapat memberikan lebih dari satu nama kepada sebuah register! Hal ini akan semakin membantu pemrogram dalam proses penulisan program. Register yang sama yang digunakan dalam subrutin yang berbeda, dapat diberi nama berbeda sesuai dengan fungsinya dalam masing-masing subrutin.

.cseg
.org 0000

rjmp start

Selanjutnya, direktif CSEG dan ORG 0000 digunakan untuk memberitahu assembler bahwa mulai baris ini dan seterusnya harus ditempatkan dalam memori program mulai dari alamat 0000. rjmp start adalah baris program yang pertama kali dieksekusi setelah mikrokontroler direset.

start:
ldi    panjang1, 8
ldi    lebar1, $10
mul    panjang1, lebar1
movw    luas1, r0

Instruksi LDI yang pertama mengisi register R16 (panjang1) dengan konstanta 8 (panjang1=8). Instruksi LDI yang kedua mengisi register R17 (panjang2) dengan konstanta 10 hexa atau 16 desimal (panjang2=$10= 16).

Selanjutnya, dilakukan kalkulasi luasan persegipanjang1 dengan instruksi mul panjang1, lebar1. Instruksi MUL melakukan perkalian antara dua buah register 8-bit. Hasil perkalian (1 word) disimpan dalam pasangan register R1:R0. Hasil perkalian ini di-copy ke dalam pasangan register R19:R18 yang diberi nama luas1 menggunakan instruksi MOVW (luas1=128).

ldi    panjang2, 0b1010
ldi    lebar2, 18
mul    panjang2, lebar2
movw    luas2, r0

Empat baris selanjutnya mirip dengan empat baris sebelumnya namun untuk variabel yang berbeda. Instruksi LDI pertama mengisi register R16 (panjang2) dengan konstanta 0b1010 (panjang2=10). Instruksi LDI kedua mengisi register R17 (lebar2) dengan konstanta 18 (panjang2=18).

Hasil perkalian panjang2 dan lebar2 disimpan dalam pasangan register R21:R20 yang diberi nama luas2 (luas=180).

forever:
rjmp forever

Dua baris terakhir program adalah looping tanpa batas sebagai akhir dari program.

Berikut adalah cuplikan tampilan program VMLAB ketika mensimulasikan program di atas.

pmldidef

Tampilan Window Program Memori

watchldidef

Tampilan Window Watch

Tampilan Window Watch menunjukkan nilai variabel-variabel lebar1, lebar2, luas1, luas2, panjang1, dan panjang2 pada akhir program. Semoga bermanfaat.

Selamat belajar!

Follow

Get every new post delivered to your Inbox.

Join 167 other followers