Property definitions

bcm2835 $ HD44780 :: defaultinit
# Hitachi HD44780 or similar 2-4 lines LCD displays
class HD44780
	var rs: RPiPin
	var en: RPiPin
	var d4: RPiPin
	var d5: RPiPin
	var d6: RPiPin
	var d7: RPiPin

	var ds = new Array[RPiPin]

	# commands
	fun flag_clear_display: Int do return 1
	fun flag_return_home: Int do return 2
	fun flag_entry_mode_set: Int do return 4
	fun flag_display_control: Int do return 8
	fun flag_cursor_shift: Int do return 16
	fun flag_function_set: Int do return 32
	fun flag_set_cgram_addr: Int do return 64
	fun flag_set_ggram_addr: Int do return 128

	# entry mode
	fun flag_entry_right: Int do return 0
	fun flag_entry_left: Int do return 2
	fun flag_entry_shift_increment: Int do return 1
	fun flag_entry_shift_decrement: Int do return 0

	# display flags
	fun flag_display_on: Int do return 4
	fun flag_display_off: Int do return 0
	fun flag_cursor_on: Int do return 2
	fun flag_cursor_off: Int do return 0
	fun flag_blink_on: Int do return 1
	fun flag_blink_off: Int do return 0

	# display/cursor shift
	fun flag_display_move: Int do return 8
	fun flag_cursor_move: Int do return 0
	fun flag_move_right: Int do return 4
	fun flag_move_left: Int do return 0

	# function set
	fun flag_8bit_mode: Int do return 16
	fun flag_4bit_mode: Int do return 0
	fun flag_2_lines: Int do return 8
	fun flag_1_line: Int do return 0
	fun flag_5x10_dots: Int do return 4
	fun flag_5x8_dots: Int do return 0

	# last text displayed
	private var last_text: nullable String = null

	fun function_set(bits, lines, dots_wide: Int)
	do
		var fs = flag_function_set
		if bits == 8 then
			fs = fs | 16
		else if bits != 4 then abort

		if lines == 2 then
			fs = fs | 8
		else if lines != 1 then abort

		if dots_wide == 10 then
			fs = fs | 4
		else if dots_wide != 8 then abort

		write(true, fs)
	end

	fun display_control(on, cursor, blink: Bool)
	do
		var fs = flag_display_control

		fs |= if on then flag_display_on else flag_display_off

		fs |= if cursor then flag_cursor_on else flag_cursor_off

		fs |= if blink then flag_blink_on else flag_blink_off

		write(true, fs)
	end

	fun entry_mode(left, incr: Bool)
	do
		var fs = flag_entry_mode_set

		fs |= if left then flag_entry_left else flag_entry_right

		fs |= if incr then flag_entry_shift_increment else flag_entry_shift_decrement

		write(true, fs)
	end

	fun setup_alt
	do
		ds = [d4,d5,d6,d7]

		rs.fsel = new FunctionSelect.outp
		en.fsel = new FunctionSelect.outp
		d4.fsel = new FunctionSelect.outp
		d5.fsel = new FunctionSelect.outp
		d6.fsel = new FunctionSelect.outp
		d7.fsel = new FunctionSelect.outp

		rs.write(false)
		en.write(false)

		# wait 20ms for power up
		50.bcm2835_delay

		write_4bits(true,true,false,false)
		write_4_bits(3)

		5.bcm2835_delay

		write_4bits(true,true,false,false)
		write_4_bits(3)

		5.bcm2835_delay

		write_4bits(true,true,false,false)
		write_4_bits(3)

		200.bcm2835_delay_micros

		write_4bits(false,true,false,false)
		write_4_bits(2)

		# wait 5ms
		5.bcm2835_delay

		# set interface
		# 4bits, 2 lines
		function_set(4, 2, 8)

		# cursor
		# don't shift & hide
		display_control(true, true, true)

		# clear & home
		clear

		# set cursor move direction
		# move right
		write(true, 6)

		# turn on display
		write(true, 4)

		# set entry mode
		entry_mode(true, true)
	end

	fun setup
	do
		ds = [d4,d5,d6,d7]

		rs.fsel = new FunctionSelect.outp
		en.fsel = new FunctionSelect.outp
		d4.fsel = new FunctionSelect.outp
		d5.fsel = new FunctionSelect.outp
		d6.fsel = new FunctionSelect.outp
		d7.fsel = new FunctionSelect.outp

		rs.write(false)
		en.write(false)

		write(true, "33".to_hex) # init
		write(true, "32".to_hex) # init
		write(true, "28".to_hex) # 2 lines, 5x7
		write(true, "0C".to_hex) # hide cursor
		write(true, "06".to_hex) # cursor move right
		write(true, "04".to_hex) # turn on display
		write(true, "01".to_hex) # clear display
	end

	fun write_4_bits(v: Int)
	do
		var lb = once [1,2,4,8]
		for i in [0..4[ do
			var b = lb[i]
			var r = b & v != 0
			var d = ds[i]
			d.write(r)
		end
		pulse_enable
	end

	fun write_4bits(a,b,c,d:Bool)
	do
		d4.write(a)
		d5.write(b)
		d6.write(c)
		d7.write(d)
		pulse_enable
	end

	fun pulse_enable
	do
		en.write(false)
		1.bcm2835_delay_micros
		en.write(true)
		100.bcm2835_delay_micros
		en.write(false)
		1.bcm2835_delay_micros
	end

	fun write(is_cmd: Bool, cmd: Int)
	do
		en.write(false)
		rs.write(not is_cmd)

		# high byte
		var hb = once [16,32,64,128]
		for i in [0..4[ do
			var b = hb[i]
			var r = b & cmd != 0
			var d = ds[i]
			d.write(r)
		end

		pulse_enable

		if is_cmd then
			# wait 5ms
			5.bcm2835_delay
		else
			# wait 200us
			200.bcm2835_delay_micros
		end

		# low byte
		var lb = once [1,2,4,8]
		for i in [0..4[ do
			var b = lb[i]
			var r = b & cmd != 0
			var d = ds[i]
			d.write(r)
		end

		pulse_enable

		if is_cmd then
			# wait 5ms
			5.bcm2835_delay
		else
			# wait 200us
			200.bcm2835_delay_micros
		end
	end

	fun clear
	do
		write(true,1)
		2.bcm2835_delay
	end

	fun return_home
	do
		write(true,2)
		2.bcm2835_delay
	end

	fun text=(v: String)
	do
		# do not redraw the samething
		var last_text = last_text
		if last_text != null and last_text == v then return

		clear
		return_home
		var count = 0
		for c in v.chars do
			if c == '\n' then
				# FIXME, this should work
				#write(true, "C0".to_hex)
				# instead we use the following which may not be portable

				for s in [count..40[ do write(false, ' '.code_point)
				count = 0
			else
				write(false, c.code_point)
				count += 1
			end
		end

		self.last_text = v
	end
end
lib/bcm2835/bcm2835.nit:164,1--453,3