Home
JAQForum Ver 20.06
Log In or Join  
Active Topics
Local Time 12:45 17 May 2024 Privacy Policy
Jump to

Notice. New forum software under development. It's going to miss a few functions and look a bit ugly for a while, but I'm working on it full time now as the old forum was too unstable. Couple days, all good. If you notice any issues, please contact me.

Forum Index : Microcontroller and PC projects : MM-all: E-ink display drivers

     Page 1 of 2    
Author Message
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 8603
Posted: 04:03pm 25 Jan 2018
Copy link to clipboard 
Print this post



Attached are display drivers for the 2.7" and 2.9" E-ink displays.

These are written entirely in Basic using the new "User" driver capability in the latest release of the MM2, MM+ and MMX firmware.

The displays are S.....L.....O.....W

A screen refresh on the 2.9" display takes just less than 3 seconds and somewhat over 5 seconds on the 2.7" display (note this is not significantly affected by the Basic code - re-writing in C wouldn't help). Also the displays flash from a normal image to an inverted one and back to a normal one as they refresh.

but they are Very low power

As seen in the picture the 2.9" display is drawing 0 amps as it isn't connected.

When in circuit is draws about 0.7mA. I haven't measured the 2.7" display but I assume it is similar. The 2.7" display also has 4 switch inputs, useful for controlling an application.

The 2.7" display is mounted on one of my MM+ HAT stands (the red one). and the pinout in the code suits this layout but can be altered for any other layout. NB for the MM2 you also need to change SPI2 to SPI in the code (4 places)

Despite the adverts the displays are orientated in portrait mode:
176 x 264 for the 2.7" display
128 x 296 for the 2.9" display

I'm using the Rotated Text facility on the MM+ to print the text in Landscape (MM+ manual - page 27).

There a number of other E-ink displays available in various sizes and it should be easy to modify the code to suit (just look at the supplied Arduino "init" routine for the likely differences)


2.9" display

'
'
' driver for 2.9" e-INK display
' The MMBasic graphics commands update a memory image of the display and the user should call REFRESH
' to update the physical display
' Updates take just less than 3 seconds
'
' EPD2IN9 commands
const DRIVER_OUTPUT_CONTROL =&H01
const BOOSTER_SOFT_START_CONTROL =&H0C
const GATE_SCAN_START_POSITION =&H0F
const DEEP_SLEEP_MODE =&H10
const DATA_ENTRY_MODE_SETTING =&H11
const SW_RESET =&H12
const TEMPERATURE_SENSOR_CONTROL =&H1A
const MASTER_ACTIVATION =&H20
const DISPLAY_UPDATE_CONTROL_1 =&H21
const DISPLAY_UPDATE_CONTROL_2 =&H22
const WRITE_RAM =&H24
const WRITE_VCOM_REGISTER =&H2C
const WRITE_LUT_REGISTER =&H32
const SET_DUMMY_LINE_PERIOD =&H3A
const SET_GATE_TIME =&H3B
const BORDER_WAVEFORM_CONTROL =&H3C
const SET_RAM_X_ADD_START_END_POS =&H44
const SET_RAM_Y_ADD_START_END_POS =&H45
const SET_RAM_X_ADDRESS_COUNTER =&H4E
const SET_RAM_Y_ADDRESS_COUNTER =&H4F
const TERMINATE_FRAME_READ_WRITE =&HFF
const CE0 = 62
const DC = 64
const RST = 28
const BUSY = 11
dim integer lut_full_update(29)=(2,2,1,&H11,&H12,&H12,&H22,&H22,&H66,&H69,&H69,&H59,&H58,&H99,&H99,&H88,0,0,0,0,&HF8,&HB4,&H13,&H51, &H35,&H51,&H51,&H19,1,0)
'
userdisplayinit(0)
line 0,0,mm.hres-1,mm.vres-1
line mm.hres-1,0,0,mm.vres-1
box 0,0,mm.hres,mm.vres
text mm.hres/2,mm.vres/2,"Hello World",CMU,5
refresh
end

sub userdisplayinit(wipe as integer)
option explicit
option default none
'if OPTION is already set then ignore the error
on error skip
OPTION LCDPANEL USER, 128,296
'don't error if Global variables not yet defined
on error skip
erase S$(), tmaskarray(), bmaskarray()
DIM S$(MM.VRES-1) length MM.HRES\8
DIM integer bmaskarray(7)=(128,192,224,240,248,252,254,255)
DIM integer tmaskarray(7)=(255,127,63,31,15,7,3,1)
local i%
PIN(RST)=1
setpin RST,DOUT
PIN(DC)=0
setpin DC,DOUT
PIN(CE0)=1
setpin CE0,DOUT
SETPIN BUSY,DIN
DO_RESET
'don't error if SPI already open
on error skip
spi2 open 10000000,0,8
SendCommand(DRIVER_OUTPUT_CONTROL)
SendData((MM.VRES - 1) AND &HFF)
SendData(((MM.VRES - 1) >> 8) AND &HFF)
SendData(&H00) ' GD = 0; SM = 0; TB = 0;
SendCommand(BOOSTER_SOFT_START_CONTROL)
SendData(&HD7)
SendData(&HD6)
SendData(&H9D)
SendCommand(WRITE_VCOM_REGISTER)
SendData(&HA8); ' VCOM 7C
SendCommand(SET_DUMMY_LINE_PERIOD)
SendData(&H1A) ' 4 dummy lines per gate
SendCommand(SET_GATE_TIME)
SendData(&H08) ' 2us per line
SendCommand(DATA_ENTRY_MODE_SETTING);
SendData(&H03) ' X increment; Y increment
sendLUT()
for i% = 0 to MM.VRES-1
s$(i%)=string$(MM.HRES\8,chr$(&HFF))
next i%
if wipe then 'erase both frame buffers
refresh
refresh
endif
end sub
'
' This routine outputs a rectangle to the display. Thi limiting case is a single pixel
' The calling sequence is defined and must be adhered to
' The parameters are the coordinates of one of the extreme diagonals of the rectangle but we don't know which way diagonal.
'
sub MM.USER_RECTANGLE(x1%, y1%, x2%, y2%, fc%)
if x1%=0 and y1%=0 and x2%=MM.HRES-1 and y2%=MM.VRES-1 then
local b$, i%
if fc% then
b$=string$(MM.HRES\8,chr$(0))
else
b$=string$(MM.HRES\8,chr$(&HFF))
endif
for i% = 0 to MM.VRES-1
s$(i%)=b$
next i%
else
local integer i, j, k, l, t, left_x,right_x, mask,emask, fcol%
local b$
if fc%<>0 then
fcol%=0
else
fcol%=1
endif
'print "userrectangle ", x1%, y1%, x2%, y2%, fcol%
if x2% <= x1% then
t = x1%
x1% = x2%
x2% = t
endif
if y2% <= y1% then
t = y1%
y1% = y2%
y2% = t
endif
if x1% < 0 then x1% = 0
if x1% >= MM.HRES then x1% = MM.HRES - 1
if x2% < 0 then x2% = 0
if x2% >= MM.HRES then x2% = MM.HRES - 1
if y1% < 0 then y1% = 0
if y1% >= MM.VRES then y1% = MM.VRES - 1
if y2% < 0 then y2% = 0
if y2% >= MM.VRES then y2% = MM.VRES - 1
left_x=x1%\8
right_x=x2%\8
if left_x=right_x then
if (fcol%) then
mask =(tmaskarray(x1% mod 8) AND bmaskarray(x2% mod 8))
else
mask = notmask%(tmaskarray(x1% mod 8) AND bmaskarray(x2% mod 8))
endif
for t=y1% to y2%
l= peek(var S$(t),left_x+1)
if (fcol%) then
l=l OR mask
else
l=l AND mask
endif
poke var S$(t),left_x+1, l
next t
else
if (fcol%) then
mask =tmaskarray(x1% mod 8)
emask=bmaskarray(x2% mod 8)
else
mask = notmask%(tmaskarray(x1% mod 8))
emask= notmask%(bmaskarray(x2% mod 8))
endif
for t=y1% to y2%
if fcol% then
l=peek(var S$(t),left_x+1)
l=l OR mask
poke var S$(t),left_x+1, l
l=peek(var S$(t),right_x+1)
l=l OR emask
poke var S$(t),right_x+1, l
else
l=peek(var S$(t),left_x+1)
l=l AND mask
poke var S$(t),left_x+1, l
l=peek(var S$(t),right_x+1)
l=l AND emask
poke var S$(t),right_x+1, l
endif
next t

if left_x+1<=right_x-1 then
if fcol% then
b$=string$(right_x-left_x-1, chr$(255))
else
b$=string$(right_x-left_x-1, chr$(0))
endif
for t=y1% to y2%
s$(t)=left$(s$(t),left_x+1)+b$+right$(s$(t),MM.HRES\8-right_x)
next t
endif
endif
endif
end sub
'
'
'
' output a bitmap to the screen
' the bitmap is supplied as a pointer to an area of memory so we use
' peek(byte bitmap%+x) to access the x'th byte in the bitmap
' each byte is a horizontal row of pixels starting with the most significant bit
' e.g. for an 8x8 bitmap
' Byte0Bit7, Byte0Bit6, Byte0Bit5, Byte0Bit4, Byte0Bit3, Byte0Bit2, Byte0Bit1, Byte0Bit0
' Byte1Bit7, ........., ........., ........., ........., ........., ........., .........
' Byte2Bit7, ........., ........., ........., ........., ........., ........., .........
' Byte3Bit7, ........., ........., ........., ........., ........., ........., .........
' Byte4Bit7, ........., ........., ........., ........., ........., ........., .........
' Byte5Bit7, ........., ........., ........., ........., ........., ........., .........
' Byte6Bit7, ........., ........., ........., ........., ........., ........., .........
' Byte7Bit7, ........., ........., ........., ........., ........., ........., Byte7bit0
'
'
sub MM.USER_BITMAP(x1%, y1%, width%, height%, scale%, fc%, bc%, bitmap%)'bitmap is in string bitmap$
' print "userbitmap ", x1%, y1%, width%, height%, scale%, fcol%, bcol%
local INTEGER i, j, k, mask, m, l, ll, t, tt, vCd, hCd, x, y, a%=height% * width%, ln%, c2%, c3%, c4%, fcol%, bcol%
if fc%<>0 then
fcol%=0
else
fcol%=1
endif
if bc%<>0 then
bcol%=0
else
bcol%=1
endif
vCd = y1%
if y1% < 0 then y1% = 0 ' the y coord is above the top of the screen
for i = 0 to height%-1 ' step thru the font scan line by line
ln%=i * width%
for j = 0 to scale%-1 ' repeat lines to scale the font
vCd=vCd+1
if vCd >= 0 then ' we are above the top of the screen
y=vCd - 1
if vCd > MM.VRES then goto D_UP ' we have extended beyond the bottom of the screen
hCd = x1%
for k = 0 to width%-1 ' step through each bit in a scan line
c2%=ln% + k
c4%=(a% - c2% - 1) mod 8
t=peek(BYTE bitmap% + c2%\8)
tt = (t >> c4%) AND 1 'we now know if the pixel is on or off
for m = 0 to scale% -1 ' repeat pixels to scale in the x axis
hCd = hCd +1' we have not reached the left margin
if hCd >= 0 then
if hCd <= MM.HRES then ' check are we beyond the right margin
x=hCd -1
mask=1<<(7-(x mod 8))
c3%=notmask%(mask)
ll= peek(var S$(y),x\8+1)
if tt then
if fcol% then
ll = ll OR mask
else
ll = ll AND c3%
endif
else
if bcol%<>-1 then 'transparent text
if bcol% then
ll = ll OR mask
else
ll = ll AND c3%
endif
endif
endif
poke var S$(y), x\8+1, ll
endif
endif
next m
next k
endif
next j
next i
D_UP:
end sub
'
sub DO_RESET
pin(RST)=0
pause 200
PIN(RST)=1
pause 200
end sub
'
sub WaitUntilIdle
do while(pin(BUSY)= 1)' 1: busy, 0: idle
pause(100)
loop
end sub
'
sub sendLUT
local integer i
SendCommand(WRITE_LUT_REGISTER) 'vcom
for i= 0 to 29
SendData(lut_full_update(i))
next i
end sub
'
sub SendCommand(databyte as integer)
local integer i
PIN(CE0)=0
PIN(DC)=0
i=SPI2(databyte)
PIN(CE0)=1
end sub
'
sub SendData(databyte as integer)
local integer i
PIN(CE0)=0
PIN(DC)=1
i=SPI2(databyte)
PIN(CE0)=1
end sub
'
sub SetMemoryArea(x_start as integer, y_start as integer, x_end as integer, y_end as integer) {
SendCommand(SET_RAM_X_ADD_START_END_POS)
'/* x point must be the multiple of 8 or the last 3 bits will be ignored */
SendData((x_start >> 3) AND &HFF)
SendData((x_end >> 3) AND &HFF)
SendCommand(SET_RAM_Y_ADD_START_END_POS)
SendData(y_start AND &HFF)
SendData((y_start >> 8) AND &HFF)
SendData(y_end AND &HFF)
SendData((y_end >> 8) AND &HFF)
end sub
'
sub SetMemoryPointer(x as integer, y as integer) {
SendCommand(SET_RAM_X_ADDRESS_COUNTER)
'/* x point must be the multiple of 8 or the last 3 bits will be ignored */
SendData((x >> 3) AND &HFF)
SendCommand(SET_RAM_Y_ADDRESS_COUNTER)
SendData(y AND &HFF)
SendData((y >> 8) AND &HFF)
WaitUntilIdle()
end sub
'
sub displayframe
SendCommand(DISPLAY_UPDATE_CONTROL_2)
SendData(&HC4)
SendCommand(MASTER_ACTIVATION)
SendCommand(TERMINATE_FRAME_READ_WRITE)
WaitUntilIdle()
end sub
'
sub refresh
local integer i,j, k, l
timer=0
setmemoryarea(0,0,MM.HRES-1,MM.VRES-1)
SetMemoryPointer(0,0)
SendCommand(WRITE_RAM)
PIN(DC)=1
for i = 0 to MM.VRES-1
k=peek(varADDR s$(i))
for j=1 to mm.hres\8
PIN(CE0)=0
l=SPI2(peek(byte k+j))
PIN(CE0)=1
next j
next i
displayframe
end sub
'
function notmask%(x%)
notmask% = (-1 XOR x%) AND &HFF
end function



2.7" display

'
'
' driver for 2.7" e-INK display
' The MMBasic graphics commands update a memory image of the display and the user should call REFRESH
' to update the physical display
' Updates take somewhat more than 5 seconds
'
' EPD2IN7 commands
const PANEL_SETTING =&H00
const POWER_SETTING =&H01
const POWER_OFF =&H02
const POWER_OFF_SEQUENCE_SETTING =&H03
const POWER_ON =&H04
const POWER_ON_MEASURE =&H05
const BOOSTER_SOFT_START =&H06
const DEEP_SLEEP =&H07
const DATA_START_TRANS_1 =&H10
const DATA_STOP =&H11
const DISPLAY_REFRESH =&H12
const DATA_START_TRANS_2 =&H13
const PARTIAL_DATA_START_TRANS_1 =&H14
const PARTIAL_DATA_START_TRANS_2 =&H15
const PARTIAL_DISPLAY_REFRESH =&H16
const LUT_FOR_VCOM =&H20
const LUT_WHITE_TO_WHITE =&H21
const LUT_BLACK_TO_WHITE =&H22
const LUT_WHITE_TO_BLACK =&H23
const LUT_BLACK_TO_BLACK =&H24
const PLL_CONTROL =&H30
const TEMPERATURE_SENSOR_COMMAND =&H40
const TEMPERATURE_SENSOR_CALIBRATION =&H41
const TEMPERATURE_SENSOR_WRITE =&H42
const TEMPERATURE_SENSOR_READ =&H43
const VCOM_AND_DATA_INTERVAL_SETTING =&H50
const LOW_POWER_DETECTION =&H51
const TCON_SETTING =&H60
const TCON_RESOLUTION =&H61
const SOURCE_AND_GATE_START_SETTING =&H62
const GET_STATUS =&H71
const AUTO_MEASURE_VCOM =&H80
const VCOM_VALUE =&H81
const VCM_DC_SETTING_REGISTER =&H82
const PROGRAM_MODE =&HA0
const ACTIVE_PROGRAM =&HA1
const READ_OTP_DATA =&HA2
const key1 = 23
const key2 = 52
const key3 = 42
const key4 = 45
const CE0 = 62
const DC = 64
const RST = 28
const BUSY = 11
dim integer lut_vcom_dc(43)=(0,0,0,15,15,0,0,5,0,&H32,&H32,0,0,2,0,15,15,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)
dim integer lut_ww(41)=(&H50,15,15,0,0,5,&H60,&H32,&H32,0,0,2,&HA0,15,15,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)
dim integer lut_bw(41)=(&H50,15,15,0,0,5,&H60,&H32,&H32,0,0,2,&HA0,15,15,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)
dim integer lut_bb(41)=(&HA0,15,15,0,0,5,&H60,&H32,&H32,0,0,2,&H50,15,15,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)
dim integer lut_wb(41)=(&HA0,15,15,0,0,5,&H60,&H32,&H32,0,0,2,&H50,15,15,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)

userdisplayinit(0)
line 0,0,mm.hres-1,mm.vres-1
line mm.hres-1,0,0,mm.vres-1
box 0,0,mm.hres,mm.vres
text mm.hres/2,mm.vres/2,"Hello World",CMU,4
refresh
end

sub userdisplayinit(wipe as integer)
option explicit
option default none
'if OPTION is already set then ignore the error
on error skip
OPTION LCDPANEL USER, 176,264
'don't error if Global variables not yet defined
on error skip
erase S$(), tmaskarray(), bmaskarray()
DIM S$(MM.VRES-1) length MM.HRES\8
DIM integer bmaskarray(7)=(128,192,224,240,248,252,254,255)
DIM integer tmaskarray(7)=(255,127,63,31,15,7,3,1)
local i%
setpin key1,din,pullup
setpin key2,din,pullup
setpin key3,din,pullup
setpin key4,din,pullup
PIN(RST)=1
setpin RST,DOUT
PIN(DC)=0
setpin DC,DOUT
PIN(CE0)=1
setpin CE0,DOUT
SETPIN BUSY,DIN
DO_RESET
'don't error if SPI already open
on error skip
spi2 open 10000000,0,8
SendCommand(POWER_SETTING)
SendData(&H03) ' VDS_EN, VDG_EN
SendData(&H00) ' VCOM_HV, VGHL_LV[1], VGHL_LV[0]
SendData(&H2b) ' VDH
SendData(&H2b) ' VDL
SendData(&H09) ' VDHR
SendCommand(BOOSTER_SOFT_START)
SendData(&H07)
SendData(&H07)
SendData(&H17)
' Power optimization
SendCommand(&HF8)
SendData(&H60)
SendData(&HA5)
' Power optimization
SendCommand(&HF8)
SendData(&H89)
SendData(&HA5)
' Power optimization
SendCommand(&HF8)
SendData(&H90)
SendData(&H00)
' Power optimization
SendCommand(&HF8)
SendData(&H93)
SendData(&H2A)
' Power optimization
SendCommand(&HF8)
SendData(&HA0)
SendData(&HA5)
' Power optimization
SendCommand(&HF8)
SendData(&HA1)
SendData(&H00)
' Power optimization
SendCommand(&HF8)
SendData(&H73)
SendData(&H41)
SendCommand(PARTIAL_DISPLAY_REFRESH)
SendData(&H00)
SendCommand(POWER_ON)
WaitUntilIdle()

SendCommand(PANEL_SETTING)
SendData(&H8F) 'KW-BF KWR-AF BWROTP 0f
SendCommand(PLL_CONTROL)
SendData(&H3A) '3A 100HZ 29 150Hz 39 200HZ 31 171HZ
SendCommand(VCM_DC_SETTING_REGISTER)
SendData(&H12)
PAUSE(2)
sendLUT()
for i% = 0 to MM.VRES-1
s$(i%)=string$(MM.HRES\8,chr$(&HFF))
next i%
if wipe then refresh
end sub
'
' This routine outputs a rectangle to the display. Thi limiting case is a single pixel
' The calling sequence is defined and must be adhered to
' The parameters are the coordinates of one of the extreme diagonals of the rectangle but we don't know which way diagonal.
'
sub MM.USER_RECTANGLE(x1%, y1%, x2%, y2%, fc%)

if x1%=0 and y1%=0 and x2%=MM.HRES-1 and y2%=MM.VRES-1 then
local b$, i%
if fc% then
b$=string$(MM.HRES\8,chr$(0))
else
b$=string$(MM.HRES\8,chr$(&HFF))
endif
for i% = 0 to MM.VRES-1
s$(i%)=b$
next i%
else
local integer i, j, k, l, t, left_x,right_x, mask,emask, fcol%
local b$
if fc%<>0 then
fcol%=0
else
fcol%=1
endif
'print "userrectangle ", x1%, y1%, x2%, y2%, fcol%
if x2% <= x1% then
t = x1%
x1% = x2%
x2% = t
endif
if y2% <= y1% then
t = y1%
y1% = y2%
y2% = t
endif
if x1% < 0 then x1% = 0
if x1% >= MM.HRES then x1% = MM.HRES - 1
if x2% < 0 then x2% = 0
if x2% >= MM.HRES then x2% = MM.HRES - 1
if y1% < 0 then y1% = 0
if y1% >= MM.VRES then y1% = MM.VRES - 1
if y2% < 0 then y2% = 0
if y2% >= MM.VRES then y2% = MM.VRES - 1
left_x=x1%\8
right_x=x2%\8
if left_x=right_x then
if (fcol%) then
mask =(tmaskarray(x1% mod 8) AND bmaskarray(x2% mod 8))
else
mask = notmask%(tmaskarray(x1% mod 8) AND bmaskarray(x2% mod 8))
endif
for t=y1% to y2%
l= peek(var S$(t),left_x+1)
if (fcol%) then
l=l OR mask
else
l=l AND mask
endif
poke var S$(t),left_x+1, l
next t
else
if (fcol%) then
mask =tmaskarray(x1% mod 8)
emask=bmaskarray(x2% mod 8)
else
mask = notmask%(tmaskarray(x1% mod 8))
emask= notmask%(bmaskarray(x2% mod 8))
endif
for t=y1% to y2%
if fcol% then
l=peek(var S$(t),left_x+1)
l=l OR mask
poke var S$(t),left_x+1, l
l=peek(var S$(t),right_x+1)
l=l OR emask
poke var S$(t),right_x+1, l
else
l=peek(var S$(t),left_x+1)
l=l AND mask
poke var S$(t),left_x+1, l
l=peek(var S$(t),right_x+1)
l=l AND emask
poke var S$(t),right_x+1, l
endif
next t

if left_x+1<=right_x-1 then
if fcol% then
b$=string$(right_x-left_x-1, chr$(255))
else
b$=string$(right_x-left_x-1, chr$(0))
endif
for t=y1% to y2%
s$(t)=left$(s$(t),left_x+1)+b$+right$(s$(t),MM.HRES\8-right_x)
next t
endif
endif
endif
end sub
'
'
'
' output a bitmap to the screen
' the bitmap is supplied as a pointer to an area of memory so we use
' peek(byte bitmap%+x) to access the x'th byte in the bitmap
' each byte is a horizontal row of pixels starting with the most significant bit
' e.g. for an 8x8 bitmap
' Byte0Bit7, Byte0Bit6, Byte0Bit5, Byte0Bit4, Byte0Bit3, Byte0Bit2, Byte0Bit1, Byte0Bit0
' Byte1Bit7, ........., ........., ........., ........., ........., ........., .........
' Byte2Bit7, ........., ........., ........., ........., ........., ........., .........
' Byte3Bit7, ........., ........., ........., ........., ........., ........., .........
' Byte4Bit7, ........., ........., ........., ........., ........., ........., .........
' Byte5Bit7, ........., ........., ........., ........., ........., ........., .........
' Byte6Bit7, ........., ........., ........., ........., ........., ........., .........
' Byte7Bit7, ........., ........., ........., ........., ........., ........., Byte7bit0
'
sub MM.USER_BITMAP(x1%, y1%, width%, height%, scale%, fc%, bc%, bitmap%)'bitmap is in string bitmap$
' print "userbitmap ", x1%, y1%, width%, height%, scale%, fcol%, bcol%
local INTEGER i, j, k, mask, m, l, ll, t, tt, vCd, hCd, x, y, a%=height% * width%, ln%, c2%, c3%, c4%, fcol%, bcol%
if fc%<>0 then
fcol%=0
else
fcol%=1
endif
if bc%<>0 then
bcol%=0
else
bcol%=1
endif
vCd = y1%
if y1% < 0 then y1% = 0 ' the y coord is above the top of the screen
for i = 0 to height%-1 ' step thru the font scan line by line
ln%=i * width%
for j = 0 to scale%-1 ' repeat lines to scale the font
vCd=vCd+1
if vCd >= 0 then ' we are above the top of the screen
y=vCd - 1
if vCd > MM.VRES then goto D_UP ' we have extended beyond the bottom of the screen
hCd = x1%
for k = 0 to width%-1 ' step through each bit in a scan line
c2%=ln% + k
c4%=(a% - c2% - 1) mod 8
t=peek(BYTE bitmap% + c2%\8)
tt = (t >> c4%) AND 1 'we now know if the pixel is on or off
for m = 0 to scale% -1 ' repeat pixels to scale in the x axis
hCd = hCd +1' we have not reached the left margin
if hCd >= 0 then
if hCd <= MM.HRES then ' check are we beyond the right margin
x=hCd -1
mask=1<<(7-(x mod 8))
c3%=notmask%(mask)
ll= peek(var S$(y),x\8+1)
if tt then
if fcol% then
ll = ll OR mask
else
ll = ll AND c3%
endif
else
if bcol%<>-1 then 'transparent text
if bcol% then
ll = ll OR mask
else
ll = ll AND c3%
endif
endif
endif
poke var S$(y), x\8+1, ll
endif
endif
next m
next k
endif
next j
next i
D_UP:
end sub
'
sub DO_RESET
pin(RST)=0
pause 200
PIN(RST)=1
pause 200
end sub
'
sub WaitUntilIdle
do while(pin(BUSY)= 0)' 0: busy, 1: idle
pause(100)
loop
end sub
'
sub sendLUT
local integer i
SendCommand(LUT_FOR_VCOM) 'vcom
for i= 0 to 43
SendData(lut_vcom_dc(i))
next i
'
SendCommand(LUT_WHITE_TO_WHITE) 'ww --
for i= 0 to 41
SendData(lut_ww(i))
next i
'
SendCommand(LUT_BLACK_TO_WHITE) 'bw r
for i= 0 to 41
SendData(lut_bw(i))
next i
'
SendCommand(LUT_WHITE_TO_BLACK) 'wb w
for i= 0 to 41
SendData(lut_bb(i))
next i
'
SendCommand(LUT_BLACK_TO_BLACK) 'bb b
for i= 0 to 41
SendData(lut_wb(i))
next i
end sub
'
sub SendCommand(databyte as integer)
local integer i
PIN(CE0)=0
PIN(DC)=0
i=SPI2(databyte)
PIN(CE0)=1
end sub
'
sub SendData(databyte as integer)
local integer i
PIN(CE0)=0
PIN(DC)=1
i=SPI2(databyte)
PIN(CE0)=1
end sub
'
SUB EpdSleep
SendCommand(DEEP_SLEEP)
SendData(&Ha5);
end sub
'
sub refresh
local integer i,j,k,l
local d$
SendCommand(DATA_START_TRANS_2)
pause 2
PIN(DC)=1
for i = 0 to MM.VRES-1
k=peek(varaddr s$(i))
for j=1 to mm.hres\8
PIN(CE0)=0
l=SPI2(peek(byte k+j))
PIN(CE0)=1
next j
next i
pause 2
SendCommand(DISPLAY_REFRESH)
WaitUntilIdle()
end sub
'
function notmask%(x%)
notmask% = (-1 XOR x%) AND &HFF
end function

Edited by matherp 2018-01-27
 
Grogster

Admin Group

Joined: 31/12/2012
Location: New Zealand
Posts: 9080
Posted: 11:56pm 25 Jan 2018
Copy link to clipboard 
Print this post

Serious question: do you ever sleep?

Sleeping aside, these look very interesting. I wonder why they are so slow to update.
The likes of the Kindle pad etc can update the whole huge screen in a matter of a second or so. Not a complaint. Just curious as to why the wee ones you use here, can't update just as fast if it is really the same technology.
Smoke makes things work. When the smoke gets out, it stops!
 
Azure

Guru

Joined: 09/11/2017
Location: Australia
Posts: 446
Posted: 03:30am 26 Jan 2018
Copy link to clipboard 
Print this post

These look great. I saw there are even 4 colour versions (red, black, grey, white).

@Grogster
I just did a quick browse of the display specs and there are a lot (did I just say a LOT) of timing parameters that can be set to improve speed. The defaults appear to be set for best compatibility which is not the fastest.
 
palcal

Guru

Joined: 12/10/2011
Location: Australia
Posts: 1805
Posted: 05:23am 01 Feb 2018
Copy link to clipboard 
Print this post

@ matherp

I have ordered one of the 2.9" displays for a project, I am trying to work out the
connections. In your code is 'const CE0 = 62' the CS pin.
Paul.

edit. Silly question, why CE0 and not just CEEdited by palcal 2018-02-02
"It is better to be ignorant and ask a stupid question than to be plain Stupid and not ask at all"
 
Azure

Guru

Joined: 09/11/2017
Location: Australia
Posts: 446
Posted: 07:43am 01 Feb 2018
Copy link to clipboard 
Print this post

The reference to CE0 is using the same documentation for the e-ink connecting to a RPi 3B.

  Quote  
e-Paper Raspberry Pi 3B
3.3V 3.3V
GND GND
DIN MOSI
CLK SCLK
CS CE0
DC 25
RST 17
BUSY 24
 
palcal

Guru

Joined: 12/10/2011
Location: Australia
Posts: 1805
Posted: 08:37am 01 Feb 2018
Copy link to clipboard 
Print this post

Thanks for that.
Paul.
"It is better to be ignorant and ask a stupid question than to be plain Stupid and not ask at all"
 
davematt
Regular Member

Joined: 27/09/2011
Location: Australia
Posts: 49
Posted: 06:36am 05 Mar 2018
Copy link to clipboard 
Print this post

@ Matherp
I'm trying to drive a 2.13 in display (3 colours) with your 2.7in driver above. My unit has 104 x 212 pixels.
It appears to initialise, but stops at the drawline command , with "display not configured"
The option lcdpanel user, 104, 212 command says error, arguments.
Is there any info about the option user command available?
I would love to get this panel going because they have the priceless virtue of being readable using sunglasses!
TIA Dave.
 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 8603
Posted: 08:12am 05 Mar 2018
Copy link to clipboard 
Print this post

  Quote  Is there any info about the option user command available?


Which micromite, what version of the firmware?
 
davematt
Regular Member

Joined: 27/09/2011
Location: Australia
Posts: 49
Posted: 10:16am 05 Mar 2018
Copy link to clipboard 
Print this post

Sorry, should have said.
28 pin pic 32 MX170 running version 5.04.08...
D
 
palcal

Guru

Joined: 12/10/2011
Location: Australia
Posts: 1805
Posted: 02:11am 08 Mar 2018
Copy link to clipboard 
Print this post

My Display arrived today BUT my old box running Win XP that has been faithful to me for over 15 years has packed it in. Graphics card I think but is so old I will get another one, there is a computer recycler in town who is seeing what he can find for me.
Paul.
"It is better to be ignorant and ask a stupid question than to be plain Stupid and not ask at all"
 
palcal

Guru

Joined: 12/10/2011
Location: Australia
Posts: 1805
Posted: 01:15am 10 Mar 2018
Copy link to clipboard 
Print this post

@ Matherp
Finally got a chance to try my 2.9" E-Ink display using an E-28 Micromite. I get an error....
  Quote  [53] Dim S$(MM.VRes-1) length MM.HRes\8
Error: Dimensions

I tried using 'Option LCD USER, 128, 296' at the command prompt but get an error
'Argument Count'.
any ideas?
Paul

Edit:
I used the following pins.
CLK = 25
DIN = 3
CS = 2
DC = 17
RST = 18
BUSY= 9
I changed the Constants to these pin nos. and changed the 4 instances of SPI2 to SPI.

Edited by palcal 2018-03-11
"It is better to be ignorant and ask a stupid question than to be plain Stupid and not ask at all"
 
palcal

Guru

Joined: 12/10/2011
Location: Australia
Posts: 1805
Posted: 03:51am 11 Mar 2018
Copy link to clipboard 
Print this post

Ok I have now loaded the file into an E-64 but now get an error...
  Quote  [297] i=SPI2(databyte)
Error: Not open


Paul.
Edit..
Thinking there maybe a problem with SPI2 I changed to SPI1 and it works OK.
I loaded it into the library, now how do I use it, do I have to delete the lines
  Quote  userdisplayinit(0)
line 0,0,mm.hres-1,mm.vres-1
line mm.hres-1,0,0,mm.vres-1
box 0,0,mm.hres,mm.vres
text mm.hres/2,mm.vres/2,"Hello World",CMU,5
refresh
end

Edited by palcal 2018-03-12
"It is better to be ignorant and ask a stupid question than to be plain Stupid and not ask at all"
 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 8603
Posted: 08:27am 11 Mar 2018
Copy link to clipboard 
Print this post

  Quote  I loaded it into the library, now how do I use it, do I have to delete the lines


You need the line

userdisplayinit(0)


at the top of your program as this initialises the display.

Then just use exactly like any other display except that you need to call "refresh" when you want the display to be actually updated.
 
palcal

Guru

Joined: 12/10/2011
Location: Australia
Posts: 1805
Posted: 09:23am 11 Mar 2018
Copy link to clipboard 
Print this post

OK thanks for that.
Paul.
"It is better to be ignorant and ask a stupid question than to be plain Stupid and not ask at all"
 
palcal

Guru

Joined: 12/10/2011
Location: Australia
Posts: 1805
Posted: 09:18pm 11 Mar 2018
Copy link to clipboard 
Print this post

I have it working OK but it is much slower than you stated. Using this small piece of code,
timer=0
userdisplayinit(0)
line 0,0,mm.hres-1,mm.vres-1
line mm.hres-1,0,0,mm.vres-1
box 0,0,mm.hres,mm.vres
text mm.hres/2,mm.vres/2,"Thanks Peter",CMU,5
refresh
print timer


It takes 18 seconds to display but the timer is only reading 2655 ?

Paul.
Edit.... Does the timer stop while the library code is executing?Edited by palcal 2018-03-13
"It is better to be ignorant and ask a stupid question than to be plain Stupid and not ask at all"
 
lew247

Guru

Joined: 23/12/2015
Location: United Kingdom
Posts: 1676
Posted: 06:38am 31 Jan 2019
Copy link to clipboard 
Print this post

Peter
Will this work with a Picromite?

I've tried it by changing the pin numbers to the correct ones I'm using but it's coming up with this error

[code]Refresh
Error: Invalid command for display type USER[/code]
 
WhiteWizzard
Guru

Joined: 05/04/2013
Location: United Kingdom
Posts: 2794
Posted: 06:54am 31 Jan 2019
Copy link to clipboard 
Print this post

@palcal,

Does your timer result (2655) display on your computer screen about 2.6 seconds after running your program AND then another 15 odd seconds more before the e-ink display shows?

If so, then is it not just a hardware 'thing'. I'm thinking that it could be that some e-inks take an age to actually 'show' the result (long after the code is finished).

Hope you follow my thoughts . . .
For everything Micromite visit micromite.org

Direct Email: whitewizzard@micromite.o
 
palcal

Guru

Joined: 12/10/2011
Location: Australia
Posts: 1805
Posted: 08:37am 31 Jan 2019
Copy link to clipboard 
Print this post

Fair go WW that was 10 months ago, I am flat out remembering what happened yesterday.
Anyhow I dumped the E-Ink, too slow.
I might resurrect it for a battery project with the ArmMite L4 one day, but it needs to be something that doesn't need updating very often.
"It is better to be ignorant and ask a stupid question than to be plain Stupid and not ask at all"
 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 8603
Posted: 02:34pm 31 Jan 2019
Copy link to clipboard 
Print this post

  Quote  I've tried it by changing the pin numbers to the correct ones I'm using but it's coming up with this error


REFRESH is a valid Pi-cromite command for use with buffered display drivers. Just change the name of the subroutine to nyREFRESH or something else
 
lew247

Guru

Joined: 23/12/2015
Location: United Kingdom
Posts: 1676
Posted: 09:11pm 31 Jan 2019
Copy link to clipboard 
Print this post

I've now got the program running but it's not displaying anything
I have a feeling I've made an error on the board but not sure

Does pin 3,DIN of the E-Ink display go to pin 21 or 19 on the Pi Zero W?
 
     Page 1 of 2    
Print this page
© JAQ Software 2024