Skip to content
2 changes: 1 addition & 1 deletion sharp.dts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@
disp-gpios = <&gpio 22 0>;

spi-cs-high = <1>;
spi-max-frequency = <8000000>;
spi-max-frequency = <3000000>;
buswidth = <8>;
debug = <0>;
};
Expand Down
105 changes: 101 additions & 4 deletions src/drm_iface.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,34 @@
#define CMD_WRITE_LINE 0b10000000
#define CMD_CLEAR_SCREEN 0b00100000

// Whiter whites
static int ditherMatrix1[4] = {
1, 154,
103, 52
};

// Uniform range
static int ditherMatrix2[4] = {
51, 204,
153, 102
};

// Whiter whites
static int ditherMatrix3[16] = {
1, 83, 21, 103,
123, 42, 143, 62,
32, 113, 11, 93,
154, 72, 134, 52
};

// Uniform range
static int ditherMatrix4[16] = {
15, 195, 60, 240,
135, 75, 180, 120,
45, 225, 30, 210,
165, 105, 150, 90
};

struct sharp_memory_panel {
struct drm_device drm;
struct drm_simple_display_pipe pipe;
Expand Down Expand Up @@ -77,7 +105,7 @@ static void vcom_timer_callback(struct timer_list *t)

// Toggle the GPIO pin
vcom_setting = (vcom_setting) ? 0 : 1;
gpiod_set_value(panel->gpio_vcom, 1);
gpiod_set_value(panel->gpio_vcom, vcom_setting);

// Reschedule the timer
mod_timer(&panel->vcom_timer, jiffies + msecs_to_jiffies(1000));
Expand Down Expand Up @@ -177,6 +205,69 @@ static void draw_indicators(struct sharp_memory_panel *panel, u8* buf, int width
}
}

static size_t sharp_memory_gray8_to_mono_tagged_dither(u8 *buf, int width, int height, int y0)
{
int line, b8, b1, msize, *dM;
unsigned char d;
int const tagged_line_len = 2 + width / 8;

if (g_param_dither == 1) {
*dM=ditherMatrix1;
msize=2;
} else if (g_param_dither == 2) {
*dM=ditherMatrix2;
msize=2;
} else if (g_param_dither == 3) {
*dM=ditherMatrix3;
msize=4;
} else {
*dM=ditherMatrix4;
msize=4;
}

// Iterate over lines from [0, height)
for (line = 0; line < height; line++) {

// Iterate over chunks of 8 source grayscale bytes
// Each 8-byte source chunk will map to one destination mono byte
for (b8 = 0; b8 < width; b8 += 8) {
d = 0;

// Iterate over each of the 8 grayscale bytes in the chunk
// Build up the destination mono byte
for (b1 = 0; b1 < 8; b1++) {

// Apply dithering
if (buf[line * width + b8 + b1] >= dM[(b8 + b1) % msize + line % msize * msize])
d |= 0b10000000 >> b1;
}

// Apply inversion
if (g_param_mono_invert) {
d = ~d;
}

// Without the line number and trailer tags, each destination
// mono line would have a length `width / 8`. However, we are
// inserting the line number at the beginning of the line and
// the zero-byte trailer at the end.
// So the destination mono line is at index
// `line * tagged_line_len = line * (2 + width / 8)`
// The destination mono byte is offset by 1 to make room for
// the line tag, written at the end of converting the current
// line.
buf[(line * tagged_line_len) + 1 + (b8 / 8)] = d;
}

// Write the line number and trailer tags
buf[line * tagged_line_len] = sharp_memory_reverse_byte((u8)(y0 + 1)); // Indexed from 1
buf[(line * tagged_line_len) + tagged_line_len - 1] = 0;
y0++;
}

return height * tagged_line_len;
}

static size_t sharp_memory_gray8_to_mono_tagged(u8 *buf, int width, int height, int y0)
{
int line, b8, b1;
Expand Down Expand Up @@ -265,9 +356,15 @@ static int sharp_memory_clip_mono_tagged(struct sharp_memory_panel* panel, size_
}
}

// Convert in-place from 8-bit grayscale to mono
*result_len = sharp_memory_gray8_to_mono_tagged(buf,
(clip->x2 - clip->x1), (clip->y2 - clip->y1), clip->y1);
if (g_param_dither) {
// Convert in-place from 8-bit grayscale to dithered mono
*result_len = sharp_memory_gray8_to_mono_tagged_dither(buf,
(clip->x2 - clip->x1), (clip->y2 - clip->y1), clip->y1);
} else {
// Convert in-place from 8-bit grayscale to mono
*result_len = sharp_memory_gray8_to_mono_tagged(buf,
(clip->x2 - clip->x1), (clip->y2 - clip->y1), clip->y1);
}

// Success
return 0;
Expand Down
13 changes: 9 additions & 4 deletions src/params_iface.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
int g_param_mono_cutoff = 32;
int g_param_mono_invert = 0;
int g_param_indicators = 1;
int g_param_dither = 0;

static int set_param_u8(const char *val, const struct kernel_param *kp)
{
Expand All @@ -20,8 +21,8 @@ static int set_param_u8(const char *val, const struct kernel_param *kp)

rc = param_set_int(val, kp);

// Refresh framebuffer
(void)drm_refresh();
// Refresh framebuffer (disabled for stability)
//(void)drm_refresh();

return rc;
}
Expand All @@ -41,6 +42,10 @@ MODULE_PARM_DESC(mono_invert, "0 for no inversion, 1 for inversion");
module_param_cb(indicators, &u8_param_ops, &g_param_indicators, 0660);
MODULE_PARM_DESC(indicators, "0 for no indicators, 1 for indicators");

module_param_cb(dither, &u8_param_ops, &g_param_dither, 0660);
MODULE_PARM_DESC(dither,
"0: no dithering, 1: limited 2x2, 2: full 2x2, 3: limited 4x4, 4: full 4x4");

int params_probe(void)
{
return 0;
Expand All @@ -55,6 +60,6 @@ void params_set_mono_invert(int setting)
{
g_param_mono_invert = setting;

// Refresh framebuffer
(void)drm_refresh();
// Refresh framebuffer (disabled for stability)
//(void)drm_refresh();
}
1 change: 1 addition & 0 deletions src/params_iface.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
extern int g_param_mono_cutoff;
extern int g_param_mono_invert;
extern int g_param_indicators;
extern int g_param_dither;

int params_probe(void);
void params_remove(void);
Expand Down