diff --git a/_oasis b/_oasis index a6a378b..89d9ec3 100644 --- a/_oasis +++ b/_oasis @@ -17,4 +17,10 @@ Executable "wpi-button-example" Path: examples/ BuildTools: ocamlbuild MainIs: button.ml - BuildDepends: WiringPi,unix \ No newline at end of file + BuildDepends: WiringPi,unix + +Executable "adafruit-lcd-example" + Path: examples/ + BuildTools: ocamlbuild + MainIs: lcd.ml + BuildDepends: WiringPi,unix diff --git a/examples/lcd.ml b/examples/lcd.ml new file mode 100644 index 0000000..014a81e --- /dev/null +++ b/examples/lcd.ml @@ -0,0 +1,139 @@ +(** An example with Adafruit character LCD, HD44780. *) +open Gpio3 + +(** Parameters *) +type mono_lcd = { + columns: int; + rows: int; + rs: pin; + en: pin; + d4: pin; + d5: pin; + d6: pin; + d7: pin +} +let lcd = { + columns = 16; + rows = 2; + rs = GPIO20; + en = GPIO16; + d4 = GPIO19; + d5 = GPIO5; + d6 = GPIO11; + d7 = GPIO10; +} + +(** MAGIC NUMBERS *) +(* Commands *) +let _lcd_cleardisplay = (0x01) +let _lcd_returnhome = (0x02) +let _lcd_entrymodeset = (0x04) +let _lcd_displaycontrol = (0x08) +let _lcd_cursorshift = (0x10) +let _lcd_functionset = (0x20) +let _lcd_setcgramaddr = (0x40) +let _lcd_setddramaddr = (0x80) + +(* Entry flags *) +let _lcd_entryleft = (0x02) +let _lcd_entryshiftdecrement = (0x00) + +(* Control flags *) +let _lcd_displayon = (0x04) +let _lcd_cursoron = (0x02) +let _lcd_cursoroff = (0x00) +let _lcd_blinkon = (0x01) +let _lcd_blinkoff = (0x00) + +(* Move flags *) +let _lcd_displaymove = (0x08) +let _lcd_moveright = (0x04) +let _lcd_moveleft = (0x00) + +(* Function set flags *) +let _lcd_4bitmode = (0x00) +let _lcd_2line = (0x08) +let _lcd_1line = (0x00) +let _lcd_5x8dots = (0x00) + +(* Offset for up to 4 rows. *) +let _lcd_row_offsets = [|0x00; 0x40; 0x14; 0x54|] + +let pulse_enable lcd = + digital_write lcd.en LOW; + (* 1 microsec pause *) + Unix.sleepf(0.0000001); + digital_write lcd.en HIGH; + Unix.sleepf(0.0000001); + digital_write lcd.en LOW; + Unix.sleepf(0.00001) + +(** write 8 bits of data *) +let write8 lcd ?(char_mode=false) value = + (* one ms delay to prevent writing too quickly *) + Unix.sleepf(0.001); + let char_mode_value = if char_mode then HIGH else LOW in + digital_write lcd.rs char_mode_value; + let val_of_int i = if i > 0 then HIGH else LOW in + let ival = Char.code value in + (* write the UPPER 4 bits (in reverse order) *) + digital_write lcd.d4 (val_of_int ((ival lsr 4) land 1)); + digital_write lcd.d5 (val_of_int ((ival lsr 5) land 1)); + digital_write lcd.d6 (val_of_int ((ival lsr 6) land 1)); + digital_write lcd.d7 (val_of_int ((ival lsr 7) land 1)); + pulse_enable lcd; + (* write the LOWER 4 bits *) + digital_write lcd.d4 (val_of_int (ival land 1)); + digital_write lcd.d5 (val_of_int ((ival lsr 1) land 1)); + digital_write lcd.d6 (val_of_int ((ival lsr 2) land 1)); + digital_write lcd.d7 (val_of_int ((ival lsr 3) land 1)); + pulse_enable lcd + +(** same as [write8] but write an int (must be within the range) *) +let write8_unsafe lcd ?(char_mode=false) ival = + write8 lcd ~char_mode (Char.unsafe_chr ival) + +let setup lcd = + Gpio3.setup (); + pin_mode lcd.rs OUT; + pin_mode lcd.en OUT; + pin_mode lcd.d4 OUT; + pin_mode lcd.d5 OUT; + pin_mode lcd.d6 OUT; + pin_mode lcd.d7 OUT; + (* MAGIC *) + write8_unsafe lcd 0x33; + write8_unsafe lcd 0x32; + (* set up some stuff *) + let displayctrl = _lcd_displayon lor _lcd_cursoroff lor _lcd_blinkoff in + let displayfn = _lcd_4bitmode lor _lcd_1line lor _lcd_2line lor _lcd_5x8dots in + let displaymode = _lcd_entryleft lor _lcd_entryshiftdecrement in + write8_unsafe lcd (displayctrl lor _lcd_displaycontrol); + write8_unsafe lcd (displayfn lor _lcd_functionset); + write8_unsafe lcd (displaymode lor _lcd_entrymodeset); + Unix.sleepf(0.003) + +let clear lcd = + write8_unsafe lcd _lcd_cleardisplay; + Unix.sleepf(0.003) + +let shift_left lcd = + write8_unsafe lcd (_lcd_cursorshift lor _lcd_displaymove lor _lcd_moveleft) + +let shift_right lcd = + write8_unsafe lcd (_lcd_cursorshift lor _lcd_displaymove lor _lcd_moveright) + +let set_position lcd x y = + let c = x mod lcd.columns in + let r = y mod lcd.rows in + if (c < 0 || r < 0) then failwith "Lcd.set_position: Negative row or column"; + write8_unsafe lcd (_lcd_setddramaddr lor (c + _lcd_row_offsets.(r))) + +let write_bytes lcd bts = + Bytes.iter (fun c -> write8 lcd c ~char_mode:true) bts + +let _ = + setup lcd; + clear lcd; + set_position lcd 0 0; + write_bytes lcd (Bytes.of_string "Hello, world.")