![]() |
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 KingdomPosts: 10066 |
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 |
||||
Grogster![]() Admin Group ![]() Joined: 31/12/2012 Location: New ZealandPosts: 9483 |
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: AustraliaPosts: 446 |
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: AustraliaPosts: 1965 |
@ 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 CE "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: AustraliaPosts: 446 |
The reference to CE0 is using the same documentation for the e-ink connecting to a RPi 3B. |
||||
palcal![]() Guru ![]() Joined: 12/10/2011 Location: AustraliaPosts: 1965 |
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: AustraliaPosts: 55 |
@ 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 KingdomPosts: 10066 |
Which micromite, what version of the firmware? |
||||
davematt Regular Member ![]() Joined: 27/09/2011 Location: AustraliaPosts: 55 |
Sorry, should have said. 28 pin pic 32 MX170 running version 5.04.08... D |
||||
palcal![]() Guru ![]() Joined: 12/10/2011 Location: AustraliaPosts: 1965 |
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: AustraliaPosts: 1965 |
@ Matherp Finally got a chance to try my 2.9" E-Ink display using an E-28 Micromite. I get an error.... 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. "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: AustraliaPosts: 1965 |
Ok I have now loaded the file into an E-64 but now get an error... 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 "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 KingdomPosts: 10066 |
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: AustraliaPosts: 1965 |
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: AustraliaPosts: 1965 |
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? "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 KingdomPosts: 1702 |
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 KingdomPosts: 2927 |
@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 ![]() ![]() |
||||
palcal![]() Guru ![]() Joined: 12/10/2011 Location: AustraliaPosts: 1965 |
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 KingdomPosts: 10066 |
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 KingdomPosts: 1702 |
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 ![]() ![]() |
![]() |
![]() |
The Back Shed's forum code is written, and hosted, in Australia. | © JAQ Software 2025 |