Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
137 changes: 137 additions & 0 deletions lib/eink/driver/ws2in13v4.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
defmodule EInk.Driver.WaveshareV4 do
# 2.13" e-Paper HAT (B) V4, 250x122, Black/White, full refresh only currently
use EInk.Driver, width: 250, height: 122, palette: :bw, partial_refresh: false

alias EInk.Driver.SpiDriver
alias Circuits.GPIO

require Logger

# Full refresh LUT
@lut_vcom <<
0x00, 0x08, 0x00, 0x00, 0x00, 0x02,
0x60, 0x28, 0x28, 0x00, 0x00, 0x01,
0x00, 0x14, 0x00, 0x00, 0x00, 0x01,
0x00, 0x12, 0x12, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00
>>

@lut_ww <<
0x40, 0x08, 0x00, 0x00, 0x00, 0x02,
0x90, 0x28, 0x28, 0x00, 0x00, 0x01,
0x40, 0x14, 0x00, 0x00, 0x00, 0x01,
0xA0, 0x12, 0x12, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00
>>

@lut_bw <<
0x40, 0x17, 0x00, 0x00, 0x00, 0x02,
0x90, 0x0F, 0x0F, 0x00, 0x00, 0x03,
0x40, 0x0A, 0x01, 0x00, 0x00, 0x01,
0xA0, 0x0E, 0x0E, 0x00, 0x00, 0x02,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00
>>

@lut_wb <<
0x80, 0x08, 0x00, 0x00, 0x00, 0x02,
0x90, 0x28, 0x28, 0x00, 0x00, 0x01,
0x80, 0x14, 0x00, 0x00, 0x00, 0x01,
0x50, 0x12, 0x12, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00
>>

@lut_bb <<
0x80, 0x08, 0x00, 0x00, 0x00, 0x02,
0x90, 0x28, 0x28, 0x00, 0x00, 0x01,
0x80, 0x14, 0x00, 0x00, 0x00, 0x01,
0x50, 0x12, 0x12, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00
>>

@lut_full <<@lut_vcom, @lut_ww, @lut_bw, @lut_wb, @lut_bb>>

@impl EInk.Driver
def new(opts \\ []) do
spi_driver = SpiDriver.open(opts)
{:ok, %{driver: spi_driver}}
end

@impl EInk.Driver
def reset(state) do
:ok = GPIO.write(state.driver.reset, 0)
Process.sleep(1)
:ok = GPIO.write(state.driver.reset, 1)
Process.sleep(1)

:ok = SpiDriver.wait_for_busy(state.driver)
{:ok, state}
end

@impl EInk.Driver
def init(state, _opts \\ []) do
# Software-Reset
SpiDriver.write(state.driver, 0x12, <<>>)
:ok = SpiDriver.wait_for_busy(state.driver)

# Display size & driver output control
SpiDriver.write(state.driver, 0x01, <<0xF9, 0x00, 0x00>>)
# RAM data entry mode
SpiDriver.write(state.driver, 0x11, <<0x01>>)
# RAM X address
SpiDriver.write(state.driver, 0x44, <<0x01, 0x10>>)
# RAM Y address range
SpiDriver.write(state.driver, 0x45, <<0x00, 0x00, 0x00, 0x00>>)
# Border
SpiDriver.write(state.driver, 0x3C, <<0x05>>)

# Voltages
SpiDriver.write(state.driver, 0x2C, <<0x36>>) # VCOM
SpiDriver.write(state.driver, 0x03, <<0x17>>) # Gate voltage
SpiDriver.write(state.driver, 0x04, <<0x41, 0x00, 0x32>>) # Source voltage

# load LUT (Fulll Refresh)
SpiDriver.write(state.driver, 0x32, @lut_full)

{:ok, state}
end

@impl EInk.Driver
def draw(state, image, _opts \\ []) do
# Set RAM-Address Counter
SpiDriver.write(state.driver, 0x4E, <<0x01>>)
SpiDriver.write(state.driver, 0x4F, <<0xF9, 0x00>>)

# Picture data (B/W channel only)
SpiDriver.write(state.driver, 0x24, image)

# Display-Update
SpiDriver.write(state.driver, 0x22, <<0xC7>>)
SpiDriver.write(state.driver, 0x20, <<>>)
:ok = SpiDriver.wait_for_busy(state.driver)

{:ok, state}
end

@impl EInk.Driver
def sleep(state) do
SpiDriver.write(state.driver, 0x10, <<0x01>>)
{:ok, state}
end

@impl EInk.Driver
def wake(state) do
{:ok, state} = reset(state)
init(state)
end
end