Project currently uses an Arduino and 0.96" OLED. Written in assembly language using Atmel Studio 7.0
The Arduino is connected to the OLED using and SPI interface. Parts of Adafruit SSD1306 library are used and rewritten in assembly language to get the OLED working.
Currently, the program can display 8x8 maps and draw 8x8 bit sprites. The program is 524 bytes and contains one map and 4 sprites: wall, floor, player and enemy.
The map currently is 8x8 bits with a floor and wall tile. 8 bytes are used to represent a map. Each byte codes for one line horizontally. The map shown in the main project image is the following:
The display buffer is organized such that each byte corresponds to an 8 bit line of pixels going down. The display is 128x64 pixels. that means there are 128x8 bytes resulting in 1024 byte buffer. 8 bytes code for a 8x8 bit tile.
The following image describes how a tile is coded (Don't judge I'm not a pixel artist):
The following is the assembly code to copy this tile to the display buffer:
draw_player:
ldi yl, low(buffer)
ldi yh, high(buffer)
movw x, y
ldi zl, low(2*player_pos)
ldi zh, high(2*player_pos)
lpm r16, z+
lpm r17, z
ldi zl, low(2*player_sprite)
ldi zh, high(2*player_sprite)
lpm r19, z+
ldi r18, 8
ldi r21, 0
buf_pos_y:
dec r17
breq y_set
rcall next_line
rjmp buf_pos_y
y_set:
mul r16,r18
add xl, r0
adc xh, r1
movw y,x
rcall draw_tile
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;
draw_tile:
ldi r20, 8
fill_tile:
st y+, r19
lpm r19, z+
dec r20
brne fill_tile
end_draw:
ret
;;;;;;;;;;;;;;;;;;;;;;;;;
next_line:
adiw x, 60 ; increase buffer address by 128, new line
adiw x, 60
adiw x, 8
ret
To increase the line curser I have to add 128. I couldn't find a command to add 128 so I used the adiw (which allows to add a max value of 63 to a 16 bit register).
To send the display buffer, the adafruit display() command was converted to assembly:
Having the peripherals set-up I looked at the adafruit library. More specificially the display() and begin() functions. The begin is the initialization routine in the adafruit 1306 library. Converting begin() function to assembly looks like the following:
setup_spi:
ldi r16, (1<<5)|(1<<3)|(1<<rst)|(1<<cs)|(1<<dc)
out DDRB, r16
ldi r16, (1<<SPE)|(1<<MSTR)
out SPCR,r16
ldi r16, (1<<SPI2X)
out SPSR, r16
ret
To send a byte over spi I store it in r20 and invoke spi_send subroutine
spi_send:
out spdr, r20
wait_sprs:
in r16, SPSR
sbrs r16, SPIF
rjmp wait_sprs
ret
What assembler did you use?