diff --git a/Documentation/conf.py b/Documentation/conf.py index 0404784a6a45cee049eb6461f8a772742bc107f2..ba4ea4a9ed78bcd6a715bb084345d366544558d1 100644 --- a/Documentation/conf.py +++ b/Documentation/conf.py @@ -87,6 +87,7 @@ html_context = { # -- Options for Auto-Doc ---------------------------------------------------- {{{ autodoc_mock_imports = [ + "sys_display", "ucollections", "urandom", "utime", diff --git a/Documentation/index.rst b/Documentation/index.rst index d9a7339a5fcb8f241fad2a66395d91ed318123f9..f850b08e35da948d938517e06337009d2c43041c 100644 --- a/Documentation/index.rst +++ b/Documentation/index.rst @@ -22,6 +22,7 @@ Last but not least, if you want to start hacking the lower-level firmware, the pycardium/overview pycardium/color + pycardium/display pycardium/leds pycardium/vibra diff --git a/Documentation/pycardium/display.rst b/Documentation/pycardium/display.rst new file mode 100644 index 0000000000000000000000000000000000000000..08bd0274c80f6d28a6d834a06ca59f1b70ce1a7a --- /dev/null +++ b/Documentation/pycardium/display.rst @@ -0,0 +1,5 @@ +``display`` - Display +===================== + +.. automodule:: display + :members: diff --git a/epicardium/epicardium.h b/epicardium/epicardium.h index 00562f1c6c0db9bcc65652a10928a2642f4c0ba2..4ded292bf9132e1079adcb726b7288cb617e12f6 100644 --- a/epicardium/epicardium.h +++ b/epicardium/epicardium.h @@ -35,6 +35,15 @@ typedef unsigned int size_t; #define API_STREAM_READ 0x6 #define API_INTERRUPT_ENABLE 0x7 #define API_INTERRUPT_DISABLE 0x8 + +#define API_DISP_OPEN 0x10 +#define API_DISP_CLOSE 0x11 +#define API_DISP_PRINT 0x12 +#define API_DISP_CLEAR 0x13 +#define API_DISP_UPDATE 0x14 +#define API_DISP_LINE 0x15 +#define API_DISP_RECT 0x16 +#define API_DISP_CIRC 0x17 /* clang-format on */ typedef uint32_t api_int_id_t; @@ -222,4 +231,153 @@ API(API_VIBRA_SET, void epic_vibra_set(int status)); */ API(API_VIBRA_VIBRATE, void epic_vibra_vibrate(int millis)); +/** + * Display + * ======= + */ + +/** Line-Style */ +enum disp_linestyle { + /** */ + LINESTYLE_FULL = 0, + /** */ + LINESTYLE_DOTTED = 1 +}; + +/** Fill-Style */ +enum disp_fillstyle { + /** */ + FILLSTYLE_EMPTY = 0, + /** */ + FILLSTYLE_FILLED = 1 +}; + +/** + * Locks the display. + * + * :return: ``0`` on success or a negative value in case of an error: + * + * - ``-EBUSY``: Display was already locked from another task. + */ +API(API_DISP_OPEN, int epic_disp_open()); + +/** + * Unlocks the display again. + * + * :return: ``0`` on success or a negative value in case of an error: + * + * - ``-EBUSY``: Display was already locked from another task. + */ +API(API_DISP_CLOSE, int epic_disp_close()); + +/** + * Causes the changes that have been written to the framebuffer + * to be shown on the display + */ +API(API_DISP_UPDATE, int epic_disp_update()); + +/** + * Prints a string into the display framebuffer + * + * :param posx: x position to print to. 0 <= x <= 160 + * :param posy: y position to print to. 0 <= y <= 80 + * :param pString: string to print + * :param fg: foreground color in rgb565 + * :param bg: background color in rgb565 + * :return: ``0`` on success or a negative value in case of an error: + * + * - ``-EBUSY``: Display was already locked from another task. + */ +API(API_DISP_PRINT, + int epic_disp_print( + uint16_t posx, + uint16_t posy, + const char *pString, + uint16_t fg, + uint16_t bg) + ); + +/** + * Fills the whole screen with one color + * + * :param color: fill color in rgb565 + * :return: ``0`` on success or a negative value in case of an error: + * + * - ``-EBUSY``: Display was already locked from another task. + */ +API(API_DISP_CLEAR, int epic_disp_clear(uint16_t color)); + +/** + * Draws a line on the display + * + * :param xstart: x starting position; 0 <= x <= 160 + * :param ystart: y starting position; 0 <= y <= 80 + * :param xend: x ending position; 0 <= x <= 160 + * :param yend: y ending position; 0 <= y <= 80 + * :param color: line color in rgb565 + * :param linestyle: 0 for solid, 1 for dottet (almost no visual difference) + * :param pixelsize: thickness of the line; 1 <= pixelsize <= 8 + * :return: ``0`` on success or a negative value in case of an error: + * + * - ``-EBUSY``: Display was already locked from another task. + */ +API(API_DISP_LINE, + int epic_disp_line( + uint16_t xstart, + uint16_t ystart, + uint16_t xend, + uint16_t yend, + uint16_t color, + enum disp_linestyle linestyle, + uint16_t pixelsize) + ); + +/** + * Draws a rectangle on the display + * + * :param xstart: x coordinate of top left corner; 0 <= x <= 160 + * :param ystart: y coordinate of top left corner; 0 <= y <= 80 + * :param xend: x coordinate of bottom right corner; 0 <= x <= 160 + * :param yend: y coordinate of bottom right corner; 0 <= y <= 80 + * :param color: line color in rgb565 + * :param fillstyle: 0 for empty, 1 for filled + * :param pixelsize: thickness of the rectangle outline; 1 <= pixelsize <= 8 + * :return: ``0`` on success or a negative value in case of an error: + * + * - ``-EBUSY``: Display was already locked from another task. + */ +API(API_DISP_RECT, + int epic_disp_rect( + uint16_t xstart, + uint16_t ystart, + uint16_t xend, + uint16_t yend, + uint16_t color, + enum disp_fillstyle fillstyle, + uint16_t pixelsize) + ); + +/** + * Draws a circle on the display + * + * :param x: x coordinate of the center; 0 <= x <= 160 + * :param y: y coordinate of the center; 0 <= y <= 80 + * :param rad: radius of the circle + * :param color: fill and outline color of the circle (rgb565) + * :param fillstyle: 0 for empty, 1 for filled + * :param pixelsize: thickness of the circle outline; 1 <= pixelsize <= 8 + * :return: ``0`` on success or a negative value in case of an error: + * + * - ``-EBUSY``: Display was already locked from another task. + */ +API(API_DISP_CIRC, + int epic_disp_circ( + uint16_t x, + uint16_t y, + uint16_t rad, + uint16_t color, + enum disp_fillstyle fillstyle, + uint16_t pixelsize) + ); + #endif /* _EPICARDIUM_H */ diff --git a/epicardium/modules/display.c b/epicardium/modules/display.c new file mode 100644 index 0000000000000000000000000000000000000000..26db0d136baba57f0dca00733e063da574e92437 --- /dev/null +++ b/epicardium/modules/display.c @@ -0,0 +1,144 @@ +#include "epicardium.h" +#include "tmr_utils.h" +#include "gpio.h" +#include "GUI_DEV/GUI_Paint.h" +#include "Fonts/fonts.h" +#include "tmr.h" +#include "FreeRTOS.h" +#include "task.h" + +static TaskHandle_t lock = NULL; + +static int check_lock() +{ + TaskHandle_t task = xTaskGetCurrentTaskHandle(); + if (task != lock) { + return -EBUSY; + } else { + return 0; + } +} + +int epic_disp_print( + uint16_t posx, + uint16_t posy, + const char *pString, + uint16_t fg, + uint16_t bg +) { + int cl = check_lock(); + if (cl < 0) { + return cl; + } else { + Paint_DrawString_EN(posx, posy, pString, &Font20, bg, fg); + return 0; + } +} + +int epic_disp_clear(uint16_t color) +{ + int cl = check_lock(); + if (cl < 0) { + return cl; + } else { + LCD_Clear(color); + return 0; + } +} + +int epic_disp_line( + uint16_t xstart, + uint16_t ystart, + uint16_t xend, + uint16_t yend, + uint16_t color, + enum disp_linestyle linestyle, + uint16_t pixelsize +) { + int cl = check_lock(); + if (cl < 0) { + return cl; + } else { + Paint_DrawLine( + xstart, ystart, xend, yend, color, linestyle, pixelsize + ); + return 0; + } +} + +int epic_disp_rect( + uint16_t xstart, + uint16_t ystart, + uint16_t xend, + uint16_t yend, + uint16_t color, + enum disp_fillstyle fillstyle, + uint16_t pixelsize +) { + int cl = check_lock(); + if (cl < 0) { + return cl; + } else { + Paint_DrawRectangle( + xstart, ystart, xend, yend, color, fillstyle, pixelsize + ); + return 0; + } +} + +int epic_disp_circ( + uint16_t x, + uint16_t y, + uint16_t rad, + uint16_t color, + enum disp_fillstyle fillstyle, + uint16_t pixelsize +) { + int cl = check_lock(); + if (cl < 0) { + return cl; + } else { + Paint_DrawCircle(x, y, rad, color, fillstyle, pixelsize); + return 0; + } +} + +int epic_disp_update() +{ + int cl = check_lock(); + if (cl < 0) { + return cl; + } else { + LCD_Update(); + return 0; + } +} + +int epic_disp_open() +{ + TaskHandle_t task = xTaskGetCurrentTaskHandle(); + if (lock == task) { + return 0; + } else if (lock == NULL) { + lock = task; + return 0; + } else { + return -EBUSY; + } +} + +int epic_disp_close() +{ + if (check_lock() < 0 && lock != NULL) { + return -EBUSY; + } else { + lock = NULL; + return 0; + } +} + +void disp_forcelock() +{ + TaskHandle_t task = xTaskGetCurrentTaskHandle(); + lock = task; +} diff --git a/epicardium/modules/meson.build b/epicardium/modules/meson.build index a038fb21d7f5ef7c650a10851503150a27c0b1eb..d552623e237ef83efa144b5dbf7690f61e922deb 100644 --- a/epicardium/modules/meson.build +++ b/epicardium/modules/meson.build @@ -1,4 +1,5 @@ module_sources = files( + 'display.c', 'fatfs.c', 'leds.c', 'log.c', diff --git a/epicardium/modules/modules.h b/epicardium/modules/modules.h index 0db3d11bf84ca07f8a65f499fa1497a55940968c..214545f6029e5201db4f3518a1224bc8ad6f12bd 100644 --- a/epicardium/modules/modules.h +++ b/epicardium/modules/modules.h @@ -14,4 +14,7 @@ void vSerialTask(void *pvParameters); #define PMIC_PRESS_POWEROFF 40 void vPmicTask(void *pvParameters); +// Forces an unlock of the display. Only to be used in epicardium +void disp_forcelock(); + #endif /* MODULES_H */ diff --git a/pycardium/meson.build b/pycardium/meson.build index 50398d58d43022015feb04e98bb69eee176e7f83..ad48e91ccff44b82d88dfafbae695de210764947 100644 --- a/pycardium/meson.build +++ b/pycardium/meson.build @@ -1,10 +1,11 @@ name = 'pycardium' modsrc = files( - 'modules/utime.c', + 'modules/interrupt.c', 'modules/leds.c', + 'modules/sys_display.c', + 'modules/utime.c', 'modules/vibra.c', - 'modules/interrupt.c', ) ################################# diff --git a/pycardium/modules/py/display.py b/pycardium/modules/py/display.py new file mode 100644 index 0000000000000000000000000000000000000000..2f7f85a8774886815f3e00d8ee049adbb5ce1f81 --- /dev/null +++ b/pycardium/modules/py/display.py @@ -0,0 +1,135 @@ +import sys_display +import color + +class Display: + """ + The display class provides methods to allow the lcd display + in card10 to be used in a safe way. All draw methods return + the display object so that it is possible to chain calls. + It is recommended to use a context manager as following: + + .. code-block:: python + + import display + with display.open() as disp: + disp.clear().update() + """ + + def __init__(self): + """ + Opens the display. Will fail the display can't be locked + """ + sys_display.open() + + def __enter__(self): + return self + + def __exit__(self, _et, _ev, _t): + self.close() + + @classmethod + def open(cls): + """ + Opens the display. Will fail the display can't be locked + """ + return cls() + + @staticmethod + def close(): + """ + Closes and unlocks the display. To be able to use it again, + it is necessary to open and lock it again with Display.open() + """ + sys_display.close() + + def update(self): + """ + Updates the display based on the changes previously made by + various draw functions + """ + sys_display.update() + + def clear(self, col=None): + """ + Clears the display using the color provided, or the default + color black + + :param col: Clearing color (expects RGB triple) + """ + col = col or color.BLACK + sys_display.clear(col) + return self + + def print(self, text, *, fg=None, bg=None, posx=0, posy=0): + """ + Prints a string on the display. Font size is locked to 20px + + :param text: Text to print + :param fg: Foreground color (expects RGB triple) + :param bg: Background color (expects RGB triple) + :param posx: X-Position of the first character, 0 <= posx <= 160 + :param posy: Y-Position of the first character, 0 <= posy <= 80 + """ + fg = fg or color.WHITE + bg = bg or color.BLACK + + sys_display.print(text, posx, posy, fg, bg) + return self + + def line(self, xs, ys, xe, ye, *, col=None, dotted=False, size=1): + """ + Draws a line on the display. + + :param xs: X start coordinate, 0 <= xs <= 160 + :param ys: Y start coordinate, 0 <= ys <= 80 + :param xe: X end coordinate, 0 <= xe <= 160 + :param ye: Y end coordinate, 0 <= ye <= 80 + :param col: color of the line (expects RGB triple) + :param dotted: whether the line should be dotted or not + (questionable implementation: draws every other pixel white, draws + white squares at higher pixel sizes) + :param size: size of the individual pixels, ranges from 1 to 8 + """ + + col = col or color.WHITE + + sys_display.line(xs, ys, xe, ye, col, dotted, size) + return self + + def rect(self, xs, ys, xe, ye, *, col=None, filled=True, size=1): + """ + Draws a rectangle on the display. + + :param xs: X start coordinate, 0 <= xs <= 160 + :param ys: Y start coordinate, 0 <= ys <= 80 + :param xe: X end coordinate, 0 <= xe <= 160 + :param ye: Y end coordinate, 0 <= ye <= 80 + :param col: color of the outline and fill (expects RGB triple) + :param filled: whether the rectangle should be filled or not + :param size: size of the individual pixels, ranges from 1 to 8 + """ + + col = col or color.WHITE + + sys_display.rect(xs, ys, xe, ye, col, filled, size) + return self + + def circ(self, x, y, rad, *, col=None, filled=True, size=1): + """ + Draws a circle on the display. + + :param x: center x coordinate, 0 <= x <= 160 + :param y: center y coordinate, 0 <= y <= 80 + :param rad: radius + :param col: color of the outline and fill (expects RGB triple) + :param filled: whether the rectangle should be filled or not + :param size: size of the individual pixels, ranges from 1 to 8 + """ + + col = col or color.WHITE + + sys_display.circ(x, y, rad, col, filled, size) + return self + +open = Display.open +close = Display.close diff --git a/pycardium/modules/py/meson.build b/pycardium/modules/py/meson.build index 4184cb5f45aa1f1937dd1de4482ff8b19d6749e8..eab92f959051c62bfc4ab065d3385e721d6711f2 100644 --- a/pycardium/modules/py/meson.build +++ b/pycardium/modules/py/meson.build @@ -1,6 +1,7 @@ python_modules = files( 'color.py', 'htmlcolor.py', + 'display.py', ) frozen_modules = mpy_cross.process(python_modules) diff --git a/pycardium/modules/qstrdefs.h b/pycardium/modules/qstrdefs.h index 4c7e2f753eb0f12f98f8ea1d4490297284be5408..61ee2c74f6e070aec715c10c1f82c52b1a9f0456 100644 --- a/pycardium/modules/qstrdefs.h +++ b/pycardium/modules/qstrdefs.h @@ -30,3 +30,12 @@ Q(set_callback) Q(enable_callback) Q(disable_callback) Q(BHI160) + +/* display */ +Q(sys_display) +Q(display) +Q(print) +Q(line) +Q(rect) +Q(circ) +Q(clear) diff --git a/pycardium/modules/sys_display.c b/pycardium/modules/sys_display.c new file mode 100644 index 0000000000000000000000000000000000000000..1e5d61d3c682fef8ec4767169bebd2b1bf47a653 --- /dev/null +++ b/pycardium/modules/sys_display.c @@ -0,0 +1,213 @@ +#include "py/obj.h" +#include "py/objstr.h" +#include "py/objint.h" +#include "py/runtime.h" + +#include "epicardium.h" +#include <stdio.h> + +static uint16_t rgb888_to_rgb565(uint8_t *bytes) +{ + return ((bytes[0] & 0b11111000) << 8) | ((bytes[1] & 0b11111100) << 3) | + (bytes[2] >> 3); +} + +static uint16_t get_color(mp_obj_t color_in) +{ + if (mp_obj_get_int(mp_obj_len(color_in)) < 3) { + mp_raise_ValueError("color must have 3 elements"); + } + + uint8_t red = mp_obj_get_int( + mp_obj_subscr(color_in, mp_obj_new_int(0), MP_OBJ_SENTINEL) + ); + uint8_t green = mp_obj_get_int( + mp_obj_subscr(color_in, mp_obj_new_int(1), MP_OBJ_SENTINEL) + ); + uint8_t blue = mp_obj_get_int( + mp_obj_subscr(color_in, mp_obj_new_int(2), MP_OBJ_SENTINEL) + ); + uint8_t colors[3] = { red, green, blue }; + return rgb888_to_rgb565(colors); +} + +/* print something on the display */ +static mp_obj_t mp_display_print(size_t n_args, const mp_obj_t *args) +{ + if (!mp_obj_is_str_or_bytes(args[0])) { + mp_raise_TypeError("input text must be a string"); + } + GET_STR_DATA_LEN(args[0], print, print_len); + uint32_t posx = mp_obj_get_int(args[1]); + uint32_t posy = mp_obj_get_int(args[2]); + uint32_t fg = get_color(args[3]); + uint32_t bg = get_color(args[4]); + int res = epic_disp_print(posx, posy, (const char *)print, fg, bg); + if (res < 0) { + mp_raise_OSError(-res); + } + return mp_const_none; +} + +/* draw line on the display */ +static mp_obj_t mp_display_line(size_t n_args, const mp_obj_t *args) +{ + uint16_t xs = mp_obj_get_int(args[0]); + uint16_t ys = mp_obj_get_int(args[1]); + uint16_t xe = mp_obj_get_int(args[2]); + uint16_t ye = mp_obj_get_int(args[3]); + uint16_t col = get_color(args[4]); + uint16_t ls = mp_obj_get_int(args[5]); + uint16_t ps = mp_obj_get_int(args[6]); + + //TODO: Move sanity checks to epicardium + if (xs > 160 || xs < 0 || xe > 160 || xe < 0) { + mp_raise_ValueError("X-Coords have to be 0 < x < 160"); + } + + if (ys > 80 || ys < 0 || ye > 80 || ye < 0) { + mp_raise_ValueError("Y-Coords have to be 0 < x < 80"); + } + + if (ls > 1 || ls < 0) { + mp_raise_ValueError("Line style has to be 0 or 1"); + } + + int res = epic_disp_line(xs, ys, xe, ye, col, ls, ps); + if (res < 0) { + mp_raise_OSError(-res); + } + return mp_const_none; +} + +/* draw rectangle on the display */ +static mp_obj_t mp_display_rect(size_t n_args, const mp_obj_t *args) +{ + uint16_t xs = mp_obj_get_int(args[0]); + uint16_t ys = mp_obj_get_int(args[1]); + uint16_t xe = mp_obj_get_int(args[2]); + uint16_t ye = mp_obj_get_int(args[3]); + uint16_t col = get_color(args[4]); + uint16_t fs = mp_obj_get_int(args[5]); + uint16_t ps = mp_obj_get_int(args[6]); + + //TODO: Move sanity checks to epicardium + if (xs > 160 || xs < 0 || xe > 160 || xe < 0) { + mp_raise_ValueError("X-Coords have to be 0 < x < 160"); + } + + if (ys > 80 || ys < 0 || ye > 80 || ye < 0) { + mp_raise_ValueError("Y-Coords have to be 0 < x < 80"); + } + + if (fs > 1 || fs < 0) { + mp_raise_ValueError("Fill style has to be 0 or 1"); + } + + int res = epic_disp_rect(xs, ys, xe, ye, col, fs, ps); + if (res < 0) { + mp_raise_OSError(-res); + } + return mp_const_none; +} + +/* draw rectangle on the display */ +static mp_obj_t mp_display_circ(size_t n_args, const mp_obj_t *args) +{ + uint16_t x = mp_obj_get_int(args[0]); + uint16_t y = mp_obj_get_int(args[1]); + uint16_t rad = mp_obj_get_int(args[2]); + uint16_t col = get_color(args[3]); + uint16_t fs = mp_obj_get_int(args[4]); + uint16_t ps = mp_obj_get_int(args[5]); + + if (fs > 1 || fs < 0) { + mp_raise_ValueError("Fill style has to be 0 or 1"); + } + + int res = epic_disp_circ(x, y, rad, col, fs, ps); + if (res < 0) { + mp_raise_OSError(-res); + } + return mp_const_none; +} + +/* clear the display */ +static mp_obj_t mp_display_clear(mp_obj_t col) +{ + uint16_t color = get_color(col); + int res = epic_disp_clear(color); + if (res < 0) { + mp_raise_OSError(-res); + } + return mp_const_none; +} + +static mp_obj_t mp_display_update() +{ + int res = epic_disp_update(); + if (res < 0) { + mp_raise_OSError(-res); + } + return mp_const_none; +} + +static mp_obj_t mp_display_open() +{ + int res = epic_disp_open(); + if (res < 0) { + mp_raise_OSError(-res); + } + return mp_const_none; +} + +static mp_obj_t mp_display_close() +{ + int res = epic_disp_close(); + if (res < 0) { + mp_raise_OSError(-res); + } + return mp_const_none; +} + +/* Create an object for this function */ +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN( + display_print_obj, 5, 5, mp_display_print +); +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN( + display_line_obj, 7, 7, mp_display_line +); +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN( + display_rect_obj, 7, 7, mp_display_rect +); +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN( + display_circ_obj, 6, 6, mp_display_circ +); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(display_clear_obj, mp_display_clear); +STATIC MP_DEFINE_CONST_FUN_OBJ_0(display_update_obj, mp_display_update); +STATIC MP_DEFINE_CONST_FUN_OBJ_0(display_open_obj, mp_display_open); +STATIC MP_DEFINE_CONST_FUN_OBJ_0(display_close_obj, mp_display_close); + +/* The globals table for this module */ +static const mp_rom_map_elem_t display_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_sys_display) }, + { MP_ROM_QSTR(MP_QSTR_open), MP_ROM_PTR(&display_open_obj) }, + { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&display_close_obj) }, + { MP_ROM_QSTR(MP_QSTR_print), MP_ROM_PTR(&display_print_obj) }, + { MP_ROM_QSTR(MP_QSTR_line), MP_ROM_PTR(&display_line_obj) }, + { MP_ROM_QSTR(MP_QSTR_rect), MP_ROM_PTR(&display_rect_obj) }, + { MP_ROM_QSTR(MP_QSTR_circ), MP_ROM_PTR(&display_circ_obj) }, + { MP_ROM_QSTR(MP_QSTR_clear), MP_ROM_PTR(&display_clear_obj) }, + { MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&display_update_obj) }, +}; +static MP_DEFINE_CONST_DICT( + display_module_globals, display_module_globals_table +); + +const mp_obj_module_t display_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t *)&display_module_globals, +}; + +/* clang-format off */ +MP_REGISTER_MODULE(MP_QSTR_sys_display, display_module, MODULE_DISPLAY_ENABLED); diff --git a/pycardium/mpconfigport.h b/pycardium/mpconfigport.h index d71bf5d4d34d8aec39eff5f027c52fa69f8df14b..b348861acb31ca0b6697f266e4edeb133c7adf10 100644 --- a/pycardium/mpconfigport.h +++ b/pycardium/mpconfigport.h @@ -41,6 +41,7 @@ #define MODULE_LEDS_ENABLED (1) #define MODULE_VIBRA_ENABLED (1) #define MODULE_INTERRUPT_ENABLED (1) +#define MODULE_DISPLAY_ENABLED (1) /* * This port is intended to be 32-bit, but unfortunately, int32_t for