32 level grayscale out on an E-ink display

2018-01-04

A quick research shows that all current commercial E-ink devices have a maximum grayscale level of 16. Is it a hardware limitation? Or is it possible to get more grayscales just like people have done on CGA, Commodore 64, GameBoy Color and many other vintage hardware that have a color limitation?

Sure, why not.

/uploads/blog/2018/1515077686525-DSC_4049_small.jpg

Just as said on the screen, happy new year 2018! (The upper right is one in 4bpp mode for reference)

Now, how it is done? Basically, to display an image on an Eink display, one need to apply multiple frames to the screen, and the result of superposition would be the image. In order to decide what to apply to display a specific color, a look-up table is used, and it is called “waveform table”. This is usually provided by the driver solution provider and I have no direct access to it as it is confidential. Now all commercial displays can only do 4bpp because there is simply no 5bpp LUT available.

So if I can create one and it would be able to do 5bpp right? Yes, but only if I can. The waveform table is actually a 4 dimension LUT, the output depends on the previous grayscale, the target grayscale, the current frame number in a series of superposition, and temperature. Basically it’s just way too hard for me to create such a LUT. Maybe this is also the reason why there is no commerical 5bpp LUT available?

So in order to archive that, I need to first “trim down” the LUT. 4D is way too much. Firstly, I decided to ignore the temperature. Then we can always start at white. Now it is already a 2D LUT. Then I decided to make the target grayscale equals to the frame number: I would use fixed 32 frame sequence for 5bpp mode and one frame correspond to one level grayscale. This requires a big change to the LUT: It is no longer looking up for the data to output since we have made it match, the output have to equal to the grayscale input. So instead it is looking up for the line time. By adjusting the line time we can fine control the grayscale. And here it is.

const unsigned char timA[32] =
{
// 1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
  30,30,30,20,20,20,20,30,30,30,30,30,30,30,30,30,30,30,40,40,40,40,50,50,50,50,60,90,90,100,120,160
};