Skip to content

Commit

Permalink
add previously black 8ppB LUT
Browse files Browse the repository at this point in the history
  • Loading branch information
vroland committed Sep 1, 2024
1 parent 7f64ad4 commit a1049d6
Show file tree
Hide file tree
Showing 5 changed files with 111 additions and 41 deletions.
59 changes: 36 additions & 23 deletions examples/fb_mode_test/main/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,46 +49,59 @@ void clear() {
memset(framebuffer, 0xFF, fb_size);
}

void test_8ppB() {
clear();

// bytes in a line in 8ppB mode
/**
* Draw triangles at varying alignments into the framebuffer in 8ppB mode.
* start_line, start_column specify the start position.
* The bits that belong to a triangle are flipped, i.e., it is drawn at the
* inverse color to the background it is drawn onto.
*/
void draw_8bpp_triangles(int start_line, int start_column) {
start_column /= 8;
int line_bytes = epd_width() / 8;

int start_line = 100;
int start_column = 80 / 8;

// draw differently aligned triangles to check for uniformity
for (int align = 0; align < 16; align++) {
for (int height = 0; height < 16; height++) {
for (int len = 0; len < height; len++) {
int line = (start_line + 16 * align + height);
int column = align + len;
uint8_t* line_address = framebuffer + (line_bytes * line);
*(line_address + start_column + column / 8) &= ~(1 << (column % 8));
*(line_address + start_column + column / 8) ^= 1 << (column % 8);
}
}
}
}

int black_start_column = 160 / 8;
void test_8ppB() {
clear();
EpdRect area = epd_full_screen();

// draw a black area for later
for (int line = 0; line < 200; line++) {
// bytes in a line in 8ppB mode
int line_bytes = epd_width() / 8;

int start_line = 100;

// draw differently aligned black triangles to check for uniformity
draw_8bpp_triangles(start_line, 80);

int black_start_column = 160;

// draw a black area
for (int line = 0; line < 300; line++) {
uint8_t* line_address = framebuffer + (line_bytes * (start_line + line));
memset(line_address + black_start_column, 0, 32);
memset(line_address + black_start_column / 8, 0, 32);
}

// draw white triangles on the black background
draw_8bpp_triangles(start_line, black_start_column + 16);

// update the display. In the first update, white pixels are no-opps,
// in the second update, black pixels are no-ops.
enum EpdDrawMode mode;
epd_poweron();
checkError(epd_draw_base(
epd_full_screen(),
framebuffer,
epd_full_screen(),
MODE_PACKING_8PPB | MODE_DU | PREVIOUSLY_WHITE,
25,
NULL,
NULL,
&epdiy_ED047TC2
));
mode = MODE_PACKING_8PPB | MODE_DU | PREVIOUSLY_WHITE;
checkError(epd_draw_base(area, framebuffer, area, mode, 25, NULL, NULL, &epdiy_ED047TC2));
mode = MODE_PACKING_8PPB | MODE_DU | PREVIOUSLY_BLACK;
checkError(epd_draw_base(area, framebuffer, area, mode, 25, NULL, NULL, &epdiy_ED047TC2));
epd_poweroff();
}

Expand Down
4 changes: 2 additions & 2 deletions examples/test/main/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ static void print_banner(const char* text) {
void app_main(void) {
print_banner("Running all the registered tests");
UNITY_BEGIN();
unity_run_tests_by_tag("lut", false);
// unity_run_all_tests();
// unity_run_tests_by_tag("lut", false);
unity_run_all_tests();
UNITY_END();
}
62 changes: 51 additions & 11 deletions src/output_common/lut.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,15 @@
* Since we disable the PSRAM workaround here for performance reasons.
*/

/* Python script for generating the 8ppB lookup table:
* for i in range(256):
/* Python script for generating the 8ppB, starting at white lookup table:
for i in range(256):
number = 0;
for b in range(8):
if not (i & (b << 1)):
if not (i & (1 << b)):
number |= 1 << (2*b)
print ('0x%04x,'%number)
*/
const uint32_t lut_8ppB_black[256] = {
const uint32_t lut_8ppB_start_at_white[256] = {
0x5555, 0x5554, 0x5551, 0x5550, 0x5545, 0x5544, 0x5541, 0x5540, 0x5515, 0x5514, 0x5511, 0x5510,
0x5505, 0x5504, 0x5501, 0x5500, 0x5455, 0x5454, 0x5451, 0x5450, 0x5445, 0x5444, 0x5441, 0x5440,
0x5415, 0x5414, 0x5411, 0x5410, 0x5405, 0x5404, 0x5401, 0x5400, 0x5155, 0x5154, 0x5151, 0x5150,
Expand All @@ -52,6 +52,39 @@ const uint32_t lut_8ppB_black[256] = {
0x0005, 0x0004, 0x0001, 0x0000
};

/* Python script for generating the 8ppB, starting at black lookup table:
for i in range(256):
number = 0;
for b in range(8):
if (i & (1 << b)):
number |= 2 << (2*b)
print ('0x%04x,'%number)
*/
const uint32_t lut_8ppB_start_at_black[256] = {
0x0000, 0x0002, 0x0008, 0x000a, 0x0020, 0x0022, 0x0028, 0x002a, 0x0080, 0x0082, 0x0088, 0x008a,
0x00a0, 0x00a2, 0x00a8, 0x00aa, 0x0200, 0x0202, 0x0208, 0x020a, 0x0220, 0x0222, 0x0228, 0x022a,
0x0280, 0x0282, 0x0288, 0x028a, 0x02a0, 0x02a2, 0x02a8, 0x02aa, 0x0800, 0x0802, 0x0808, 0x080a,
0x0820, 0x0822, 0x0828, 0x082a, 0x0880, 0x0882, 0x0888, 0x088a, 0x08a0, 0x08a2, 0x08a8, 0x08aa,
0x0a00, 0x0a02, 0x0a08, 0x0a0a, 0x0a20, 0x0a22, 0x0a28, 0x0a2a, 0x0a80, 0x0a82, 0x0a88, 0x0a8a,
0x0aa0, 0x0aa2, 0x0aa8, 0x0aaa, 0x2000, 0x2002, 0x2008, 0x200a, 0x2020, 0x2022, 0x2028, 0x202a,
0x2080, 0x2082, 0x2088, 0x208a, 0x20a0, 0x20a2, 0x20a8, 0x20aa, 0x2200, 0x2202, 0x2208, 0x220a,
0x2220, 0x2222, 0x2228, 0x222a, 0x2280, 0x2282, 0x2288, 0x228a, 0x22a0, 0x22a2, 0x22a8, 0x22aa,
0x2800, 0x2802, 0x2808, 0x280a, 0x2820, 0x2822, 0x2828, 0x282a, 0x2880, 0x2882, 0x2888, 0x288a,
0x28a0, 0x28a2, 0x28a8, 0x28aa, 0x2a00, 0x2a02, 0x2a08, 0x2a0a, 0x2a20, 0x2a22, 0x2a28, 0x2a2a,
0x2a80, 0x2a82, 0x2a88, 0x2a8a, 0x2aa0, 0x2aa2, 0x2aa8, 0x2aaa, 0x8000, 0x8002, 0x8008, 0x800a,
0x8020, 0x8022, 0x8028, 0x802a, 0x8080, 0x8082, 0x8088, 0x808a, 0x80a0, 0x80a2, 0x80a8, 0x80aa,
0x8200, 0x8202, 0x8208, 0x820a, 0x8220, 0x8222, 0x8228, 0x822a, 0x8280, 0x8282, 0x8288, 0x828a,
0x82a0, 0x82a2, 0x82a8, 0x82aa, 0x8800, 0x8802, 0x8808, 0x880a, 0x8820, 0x8822, 0x8828, 0x882a,
0x8880, 0x8882, 0x8888, 0x888a, 0x88a0, 0x88a2, 0x88a8, 0x88aa, 0x8a00, 0x8a02, 0x8a08, 0x8a0a,
0x8a20, 0x8a22, 0x8a28, 0x8a2a, 0x8a80, 0x8a82, 0x8a88, 0x8a8a, 0x8aa0, 0x8aa2, 0x8aa8, 0x8aaa,
0xa000, 0xa002, 0xa008, 0xa00a, 0xa020, 0xa022, 0xa028, 0xa02a, 0xa080, 0xa082, 0xa088, 0xa08a,
0xa0a0, 0xa0a2, 0xa0a8, 0xa0aa, 0xa200, 0xa202, 0xa208, 0xa20a, 0xa220, 0xa222, 0xa228, 0xa22a,
0xa280, 0xa282, 0xa288, 0xa28a, 0xa2a0, 0xa2a2, 0xa2a8, 0xa2aa, 0xa800, 0xa802, 0xa808, 0xa80a,
0xa820, 0xa822, 0xa828, 0xa82a, 0xa880, 0xa882, 0xa888, 0xa88a, 0xa8a0, 0xa8a2, 0xa8a8, 0xa8aa,
0xaa00, 0xaa02, 0xaa08, 0xaa0a, 0xaa20, 0xaa22, 0xaa28, 0xaa2a, 0xaa80, 0xaa82, 0xaa88, 0xaa8a,
0xaaa0, 0xaaa2, 0xaaa8, 0xaaaa,
};

static inline int min(int x, int y) {
return x < y ? x : y;
}
Expand All @@ -64,8 +97,6 @@ uint32_t skipping;

__attribute__((optimize("O3"))) void IRAM_ATTR
reorder_line_buffer(uint32_t* line_data, int buf_len) {
uint16_t* load = (uint16_t*)line_data;
uint16_t* store = (uint16_t*)line_data;
for (uint32_t i = 0; i < buf_len / 4; i++) {
uint32_t val = *line_data;
*(line_data++) = val >> 16 | ((val & 0x0000FFFF) << 16);
Expand Down Expand Up @@ -390,8 +421,16 @@ static void build_2ppB_lut_64k_from_15(uint8_t* lut, const EpdWaveformPhases* ph
build_2ppB_lut_64k_static_from(lut, phases, 0xF, frame);
}

static void build_8ppB_lut_256b_from_15(uint8_t* lut, const EpdWaveformPhases* phases, int frame) {
memcpy(lut, lut_8ppB_black, sizeof(lut_8ppB_black));
static void build_8ppB_lut_256b_from_white(
uint8_t* lut, const EpdWaveformPhases* phases, int frame
) {
memcpy(lut, lut_8ppB_start_at_white, sizeof(lut_8ppB_start_at_white));
}

static void build_8ppB_lut_256b_from_black(
uint8_t* lut, const EpdWaveformPhases* phases, int frame
) {
memcpy(lut, lut_8ppB_start_at_black, sizeof(lut_8ppB_start_at_black));
}

LutFunctionPair find_lut_functions(enum EpdDrawMode mode, uint32_t lut_size) {
Expand Down Expand Up @@ -433,16 +472,17 @@ LutFunctionPair find_lut_functions(enum EpdDrawMode mode, uint32_t lut_size) {
}
}
} else if (mode & MODE_PACKING_8PPB) {
if (lut_size < sizeof(lut_8ppB_black)) {
if (lut_size < sizeof(lut_8ppB_start_at_white)) {
return pair;
}

if (mode & PREVIOUSLY_WHITE) {
pair.build_func = &build_8ppB_lut_256b_from_15;
pair.build_func = &build_8ppB_lut_256b_from_white;
pair.lookup_func = &calc_epd_input_8ppB;
return pair;
} else if (mode & PREVIOUSLY_BLACK) {
// FIXME: to implement
pair.build_func = &build_8ppB_lut_256b_from_black;
pair.lookup_func = &calc_epd_input_8ppB;
return pair;
}
}
Expand Down
5 changes: 2 additions & 3 deletions test/test_diff.c
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ TEST_CASE("simple aligned diff works", "[epdiy,unit]") {
diff_test_buffers_init(&bufs, example_len);

// This should trigger use of vector extensions on the S3
TEST_ASSERT((uint32_t)bufs.to % 16 == 0)
TEST_ASSERT((uint32_t)bufs.to % 16 == 0);

// fully aligned
dirty = _epd_interlace_line(
Expand All @@ -109,7 +109,7 @@ TEST_CASE("dirtynes for diff without changes is correct", "[epdiy,unit]") {
diff_test_buffers_init(&bufs, example_len);

// This should trigger use of vector extensions on the S3
TEST_ASSERT((uint32_t)bufs.to % 16 == 0)
TEST_ASSERT((uint32_t)bufs.to % 16 == 0);

// both use "from" buffer
dirty = _epd_interlace_line(
Expand All @@ -132,7 +132,6 @@ TEST_CASE("dirtynes for diff without changes is correct", "[epdiy,unit]") {

TEST_CASE("different 4-byte alignments work", "[epdiy,unit]") {
const int example_len = DEFAULT_EXAMPLE_LEN;
const uint8_t NULL_ARRAY[DEFAULT_EXAMPLE_LEN * 2] = { 0 };
DiffTestBuffers bufs;
bool dirty;

Expand Down
22 changes: 20 additions & 2 deletions test/test_lut.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,14 @@ static const uint8_t result_pattern_2ppB_white[8]
= { 0x00, 0x01, 0x50, 0x55, 0x55, 0x55, 0x00, 0x55 };
static const uint8_t result_pattern_2ppB_black[8]
= { 0xAA, 0xA8, 0x0A, 0x82, 0xAA, 0xAA, 0xAA, 0x20 };
static const uint8_t result_pattern_8ppB[32]
static const uint8_t result_pattern_8ppB_on_white[32]
= { 0x00, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55,
0x55, 0x54, 0x55, 0x55, 0x54, 0x44, 0x11, 0x44, 0x11, 0x11, 0x44,
0x11, 0x44, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x15, 0x55 };
static const uint8_t result_pattern_8ppB_on_black[32]
= { 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00,
0x00, 0x02, 0x00, 0x00, 0x02, 0x22, 0x88, 0x22, 0x88, 0x88, 0x22,
0x88, 0x22, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x80, 0x00 };

typedef void (*lut_func_t)(const uint32_t*, uint8_t*, const uint8_t*, uint32_t);
static uint8_t waveform_phases[16][4];
Expand Down Expand Up @@ -252,7 +256,7 @@ TEST_CASE("2ppB lookup LCD, 1k LUT, previously black", "[epdiy,unit,lut]") {

TEST_CASE("8ppB lookup LCD, 1k LUT, previously white", "[epdiy,unit,lut]") {
LutTestBuffers bufs;
lut_test_buffers_init(&bufs, DEFAULT_EXAMPLE_LEN / 2, result_pattern_8ppB, 0.5);
lut_test_buffers_init(&bufs, DEFAULT_EXAMPLE_LEN / 2, result_pattern_8ppB_on_white, 0.5);

enum EpdDrawMode mode = MODE_DU | MODE_PACKING_8PPB | PREVIOUSLY_WHITE;
LutFunctionPair func_pair = find_lut_functions(mode, 1 << 10);
Expand All @@ -261,5 +265,19 @@ TEST_CASE("8ppB lookup LCD, 1k LUT, previously white", "[epdiy,unit,lut]") {
func_pair.build_func(bufs.lut, &test_waveform, 0);
test_with_alignments(&bufs, func_pair.lookup_func);

diff_test_buffers_free(&bufs);
}

TEST_CASE("8ppB lookup LCD, 1k LUT, previously black", "[epdiy,unit,lut]") {
LutTestBuffers bufs;
lut_test_buffers_init(&bufs, DEFAULT_EXAMPLE_LEN / 2, result_pattern_8ppB_on_black, 0.5);

enum EpdDrawMode mode = MODE_DU | MODE_PACKING_8PPB | PREVIOUSLY_BLACK;
LutFunctionPair func_pair = find_lut_functions(mode, 1 << 10);
TEST_ASSERT_NOT_NULL(func_pair.build_func);
TEST_ASSERT_NOT_NULL(func_pair.lookup_func);
func_pair.build_func(bufs.lut, &test_waveform, 0);
test_with_alignments(&bufs, func_pair.lookup_func);

diff_test_buffers_free(&bufs);
}

0 comments on commit a1049d6

Please sign in to comment.