Drawing to the display buffer

A project log for 1 kB Arduino Roguelike

1 kB roguelike using an Arduino and 0.96" OLED

RadekRadek 12/03/2016 at 18:430 Comments

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):

This translates to the following in assembly:

player_sprite:	.db 0x0e,0x1f,0xff,0xfb, 0xfb, 0xfb, 0x37, 0xfa
player_pos:		.db 4, 4

The following is the assembly code to copy this tile to the display buffer:

	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

	dec		r17
	breq	y_set
	rcall	next_line
	rjmp	buf_pos_y
	mul		r16,r18
	add		xl, r0
	adc		xh, r1
	movw	y,x
	rcall	draw_tile
	ldi		r20, 8
	st		y+, r19
	lpm		r19, z+
	dec		r20
	brne	fill_tile
	adiw	x, 60	; increase buffer address by 128, new line
	adiw	x, 60
	adiw	x, 8

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:

	mcommand 0x21
	mcommand 0x00
	mcommand 127
	mcommand 0x22
	mcommand 0x0
	mcommand 0x7

	sbi PORTB, 2 ;cs high
	sbi PORTB, 1 ;dc low
	cbi PORTB, 2 ;cs high

	ldi r23,4
	ldi r22,0
	ldi r21,0
	ldi YL, low(buffer)
	ldi YH, high(buffer)

	ld r20, Y+
	rcall spi_send
	inc r21
	brne send_buffer
	inc r22
	cpse r22,r23
	brne send_buffer

	sbi PORTB, 2 ;cs


My way of counting to 1024 which is hex 0x400 is to use two registers r21 and r22. When (r22 ==4) I know I sent 1024 bytes.