Skip to content

Commit d9fcaa0

Browse files
authored
Merge pull request #9488 from wyrdsec/main
Driver for Pervasive Display's Aurora based E-ink display
2 parents 5f7c42e + 5861363 commit d9fcaa0

File tree

15 files changed

+1012
-1
lines changed

15 files changed

+1012
-1
lines changed

locale/circuitpython.pot

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1214,6 +1214,11 @@ msgstr ""
12141214
msgid "Invalid BSSID"
12151215
msgstr ""
12161216

1217+
#: shared-module/aurora_epaper/aurora_framebuffer.c
1218+
#, c-format
1219+
msgid "Invalid CoG id=%d"
1220+
msgstr ""
1221+
12171222
#: shared-bindings/wifi/Radio.c
12181223
msgid "Invalid MAC address"
12191224
msgstr ""
@@ -2161,6 +2166,14 @@ msgstr ""
21612166
msgid "Unknown BLE error: %d"
21622167
msgstr ""
21632168

2169+
#: shared-module/aurora_epaper/aurora_framebuffer.c
2170+
msgid "Unknown device size."
2171+
msgstr ""
2172+
2173+
#: shared-module/aurora_epaper/aurora_framebuffer.c
2174+
msgid "Unknown display type!"
2175+
msgstr ""
2176+
21642177
#: ports/espressif/common-hal/max3421e/Max3421E.c
21652178
#: ports/raspberrypi/common-hal/wifi/__init__.c
21662179
#, c-format
@@ -2218,6 +2231,10 @@ msgstr ""
22182231
msgid "Unsupported colorspace"
22192232
msgstr ""
22202233

2234+
#: shared-module/aurora_epaper/aurora_framebuffer.c
2235+
msgid "Unsupported device size."
2236+
msgstr ""
2237+
22212238
#: shared-module/displayio/bus_core.c
22222239
msgid "Unsupported display bus type"
22232240
msgstr ""

py/circuitpy_defns.mk

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,9 @@ endif
137137
ifeq ($(CIRCUITPY_AUDIOMP3),1)
138138
SRC_PATTERNS += audiomp3/%
139139
endif
140+
ifeq ($(CIRCUITPY_AURORA_EPAPER),1)
141+
SRC_PATTERNS += aurora_epaper/%
142+
endif
140143
ifeq ($(CIRCUITPY_BITBANGIO),1)
141144
SRC_PATTERNS += bitbangio/%
142145
endif
@@ -621,6 +624,8 @@ SRC_SHARED_MODULE_ALL = \
621624
audiomp3/MP3Decoder.c \
622625
audiomp3/__init__.c \
623626
audiopwmio/__init__.c \
627+
aurora_epaper/aurora_framebuffer.c \
628+
aurora_epaper/__init__.c \
624629
bitbangio/I2C.c \
625630
bitbangio/SPI.c \
626631
bitbangio/__init__.c \

py/circuitpy_mpconfig.mk

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,9 @@ CFLAGS += -DCIRCUITPY_AUDIOCORE_DEBUG=$(CIRCUITPY_AUDIOCORE_DEBUG)
141141
CIRCUITPY_AUDIOMP3 ?= $(call enable-if-all,$(CIRCUITPY_FULL_BUILD) $(CIRCUITPY_AUDIOCORE))
142142
CFLAGS += -DCIRCUITPY_AUDIOMP3=$(CIRCUITPY_AUDIOMP3)
143143

144+
CIRCUITPY_AURORA_EPAPER ?= 0
145+
CFLAGS += -DCIRCUITPY_AURORA_EPAPER=$(CIRCUITPY_AURORA_EPAPER)
146+
144147
CIRCUITPY_BINASCII ?= $(CIRCUITPY_FULL_BUILD)
145148
CFLAGS += -DCIRCUITPY_BINASCII=$(CIRCUITPY_BINASCII)
146149

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#include <stdint.h>
2+
3+
#include "py/obj.h"
4+
#include "py/runtime.h"
5+
6+
#include "shared-bindings/aurora_epaper/aurora_framebuffer.h"
7+
8+
STATIC const mp_rom_map_elem_t aurora_epaper_module_globals_table[] = {
9+
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_aurora_epaper) },
10+
{ MP_ROM_QSTR(MP_QSTR_AuroraMemoryFramebuffer), MP_ROM_PTR(&aurora_framebuffer_type) },
11+
};
12+
13+
static MP_DEFINE_CONST_DICT(aurora_epaper_globals, aurora_epaper_module_globals_table);
14+
15+
const mp_obj_module_t aurora_epaper_module = {
16+
.base = {&mp_type_module},
17+
.globals = (mp_obj_dict_t *)&aurora_epaper_globals,
18+
};
19+
20+
MP_REGISTER_MODULE(MP_QSTR_aurora_epaper, aurora_epaper_module);
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
#pragma once
Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
/*
2+
* Copyright 2023 Cisco Systems, Inc. and its affiliates
3+
* Author: Wyrdsec
4+
*
5+
* Permission is hereby granted, free of charge, to any person obtaining a copy of
6+
* this software and associated documentation files (the "Software"), to deal in
7+
* the Software without restriction, including without limitation the rights to
8+
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9+
* the Software, and to permit persons to whom the Software is furnished to do so,
10+
* subject to the following conditions:
11+
* - The above copyright notice and this permission notice shall be included in
12+
* all copies or substantial portions of the Software.
13+
* - The Software is provided "as is", without warranty of any kind, express or
14+
* implied, including but not limited to the warranties of merchantability,
15+
* fitness for a particular purpose and noninfringement. In no event shall the
16+
* authors or copyright holders be liable for any claim, damages or other
17+
* liability, whether in an action of contract, tort or otherwise, arising from,
18+
* out of or in connection with the Software or the use or other dealings in the
19+
* Software.
20+
*/
21+
#include "py/objarray.h"
22+
#include "py/runtime.h"
23+
#include "py/objproperty.h"
24+
25+
26+
#include "shared-bindings/aurora_epaper/aurora_framebuffer.h"
27+
#include "shared-module/aurora_epaper/aurora_framebuffer.h"
28+
#include "shared-bindings/busio/SPI.h"
29+
#include "shared-bindings/microcontroller/Pin.h"
30+
#include "shared-module/displayio/__init__.h"
31+
32+
//| class AuroraMemoryFramebuffer:
33+
//| """A framebuffer for Pervasive Displays Aurora E-paper displays.
34+
//|
35+
//| These displays are 2 color only.
36+
//|
37+
//| This initializes a display and connects it to CircuitPython.
38+
//|
39+
//| For Example::
40+
//|
41+
//| import busio
42+
//| import framebufferio
43+
//| from aurora_epaper import AuroraMemoryFramebuffer
44+
//| spi = busio.SPI(EINK_CLKS, EINK_MOSI, EINK_MISO)
45+
//| aurora = AuroraMemoryFramebuffer(spi, EINK_CS, EINK_RST, EINK_BUSY, EINK_DISCHARGE, HEIGHT, WIDTH)
46+
//| display = framebufferio.FramebufferDisplay(t, auto_refresh=False)
47+
//| display.refresh()
48+
//|
49+
//| For more information on how these displays are driven see:
50+
//| https://www.pervasivedisplays.com/wp-content/uploads/2023/02/4P018-00_04_G2_Aurora-Mb_COG_Driver_Interface_Timing_for_small-size_20231107.pdf
51+
//| """
52+
//|
53+
//| def __init__(
54+
//| self,
55+
//| spi_bus: busio.SPI,
56+
//| chip_select: microcontroller.Pin,
57+
//| reset: microcontroller.Pin,
58+
//| busy: microcontroller.Pin,
59+
//| discharge: microcontroller.Pin,
60+
//| width: int,
61+
//| height: int,
62+
//| power: Optional[microcontroller.Pin] = None,
63+
//| free_bus: Optional[bool] = True,
64+
//| ) -> None:
65+
//| """Create a framebuffer for the Aurora CoG display.
66+
//|
67+
//| .. note:: Displays of size 1.9" and 2.6" are not tested, and may exibit unexpected behavior.
68+
//|
69+
//| :param busio.SPI spi_bus: The SPI bus that the display is connected to
70+
//| :param microcontroller.Pin chip_select: The pin connected to the displays chip select input
71+
//| :param microcontroller.Pin reset: The pin connected to the displays reset input
72+
//| :param microcontroller.Pin busy: The pin connected to the displays busy output
73+
//| :param microcontroller.Pin discharge: The pin connected to the displays discharge input
74+
//| :param int width: The width of the display in pixels
75+
//| :param int height: The height of the display in pixels
76+
//| :param microcontroller.Pin power: The pin that controls power to the display (optional).
77+
//| :param bool free_bus: Determines whether the SPI bus passed in will be freed when the frame buffer is freed (optional).
78+
//| """
79+
//| ...
80+
static mp_obj_t aurora_epaper_framebuffer_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
81+
enum { ARG_spi_bus, ARG_chip_select, ARG_reset, ARG_busy, ARG_discharge, ARG_width, ARG_height, ARG_power, ARG_free_bus, NUM_ARGS };
82+
static const mp_arg_t allowed_args[] = {
83+
{ MP_QSTR_spi_bus, MP_ARG_OBJ | MP_ARG_REQUIRED, {.u_obj = MP_OBJ_NULL} },
84+
{ MP_QSTR_chip_select, MP_ARG_OBJ | MP_ARG_REQUIRED, {.u_obj = MP_OBJ_NULL} },
85+
{ MP_QSTR_reset, MP_ARG_OBJ | MP_ARG_REQUIRED, {.u_obj = MP_OBJ_NULL} },
86+
{ MP_QSTR_busy, MP_ARG_OBJ | MP_ARG_REQUIRED, {.u_obj = MP_OBJ_NULL} },
87+
{ MP_QSTR_discharge, MP_ARG_OBJ | MP_ARG_REQUIRED, {.u_obj = MP_OBJ_NULL} },
88+
{ MP_QSTR_width, MP_ARG_INT | MP_ARG_REQUIRED, {.u_int = 0} },
89+
{ MP_QSTR_height, MP_ARG_INT | MP_ARG_REQUIRED, {.u_int = 0} },
90+
{ MP_QSTR_power, MP_ARG_OBJ, {.u_obj = mp_const_none} },
91+
{ MP_QSTR_free_bus, MP_ARG_BOOL, {.u_bool = true} },
92+
};
93+
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
94+
MP_STATIC_ASSERT(MP_ARRAY_SIZE(allowed_args) == NUM_ARGS);
95+
96+
mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
97+
98+
// Pins
99+
const mcu_pin_obj_t *chip_select = validate_obj_is_free_pin(args[ARG_chip_select].u_obj, MP_QSTR_chip_select);
100+
const mcu_pin_obj_t *reset = validate_obj_is_free_pin(args[ARG_reset].u_obj, MP_QSTR_reset);
101+
const mcu_pin_obj_t *busy = validate_obj_is_free_pin(args[ARG_busy].u_obj, MP_QSTR_busy);
102+
const mcu_pin_obj_t *discharge = validate_obj_is_free_pin(args[ARG_discharge].u_obj, MP_QSTR_discharge);
103+
const mcu_pin_obj_t *power = validate_obj_is_free_pin_or_none(args[ARG_power].u_obj, MP_QSTR_power);
104+
105+
busio_spi_obj_t *spi = validate_obj_is_spi_bus(args[ARG_spi_bus].u_obj, MP_QSTR_spi_bus);
106+
aurora_epaper_framebuffer_obj_t *self = &allocate_display_bus_or_raise()->aurora_epaper;
107+
self->base.type = &aurora_framebuffer_type;
108+
109+
common_hal_aurora_epaper_framebuffer_construct(self, spi, chip_select, reset, busy, discharge, power, args[ARG_width].u_int, args[ARG_height].u_int, args[ARG_free_bus].u_bool);
110+
return MP_OBJ_FROM_PTR(self);
111+
}
112+
113+
static mp_int_t aurora_epaper_framebuffer_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, mp_uint_t flags) {
114+
aurora_epaper_framebuffer_obj_t *self = self_in;
115+
if ((flags & MP_BUFFER_WRITE) && !(self->bufinfo.typecode & MP_OBJ_ARRAY_TYPECODE_FLAG_RW)) {
116+
return 1;
117+
}
118+
*bufinfo = self->bufinfo;
119+
return 0;
120+
}
121+
122+
//| def deinit(self) -> None:
123+
//| """Free the resources (pins, timers, etc.) associated with this
124+
//| AuroraMemoryFramebuffer instance. After deinitialization, no further operations
125+
//| may be performed."""
126+
//| ...
127+
static mp_obj_t aurora_epaper_framebuffer_deinit(mp_obj_t self_in) {
128+
aurora_epaper_framebuffer_obj_t *self = (aurora_epaper_framebuffer_obj_t *)self_in;
129+
common_hal_aurora_epaper_framebuffer_deinit(self);
130+
131+
return mp_const_none;
132+
}
133+
static MP_DEFINE_CONST_FUN_OBJ_1(aurora_epaper_framebuffer_deinit_obj, aurora_epaper_framebuffer_deinit);
134+
135+
//| def set_temperature(self, celsius: int) -> None:
136+
//| """Set the ambient temperature (in celsius) for the display driver.
137+
//| Higher temperature means faster update speed.
138+
//| """
139+
//| ...
140+
static mp_obj_t aurora_epaper_frambuffer_set_temperature(mp_obj_t self_in, mp_obj_t temperature) {
141+
aurora_epaper_framebuffer_obj_t *self = (aurora_epaper_framebuffer_obj_t *)self_in;
142+
143+
common_hal_aurora_epaper_framebuffer_set_temperature(self, mp_obj_get_float(temperature));
144+
145+
return mp_const_none;
146+
}
147+
static MP_DEFINE_CONST_FUN_OBJ_2(aurora_epaper_frambuffer_set_temperature_obj, aurora_epaper_frambuffer_set_temperature);
148+
149+
//| free_bus: bool
150+
//| """When True the spi bus passed into the device will be freed on deinit.
151+
//| If you have multiple displays this could be used to keep the other active on soft reset."""
152+
//| ...
153+
//|
154+
static mp_obj_t aurora_epaper_framebuffer_get_free_bus(mp_obj_t self_in) {
155+
aurora_epaper_framebuffer_obj_t *self = (aurora_epaper_framebuffer_obj_t *)self_in;
156+
return mp_obj_new_bool(self->free_bus);
157+
}
158+
static MP_DEFINE_CONST_FUN_OBJ_1(aurora_epaper_framebuffer_get_free_bus_obj, aurora_epaper_framebuffer_get_free_bus);
159+
160+
161+
static mp_obj_t aurora_epaper_framebuffer_set_free_bus(mp_obj_t self_in, mp_obj_t free_bus) {
162+
aurora_epaper_framebuffer_obj_t *self = (aurora_epaper_framebuffer_obj_t *)self_in;
163+
common_hal_aurora_epaper_framebuffer_set_free_bus(self, mp_obj_is_true(free_bus));
164+
return mp_const_none;
165+
}
166+
static MP_DEFINE_CONST_FUN_OBJ_2(aurora_epaper_framebuffer_set_free_bus_obj, aurora_epaper_framebuffer_set_free_bus);
167+
168+
MP_PROPERTY_GETSET(aurora_epaper_framebuffer_free_bus_obj,
169+
(mp_obj_t)&aurora_epaper_framebuffer_get_free_bus_obj,
170+
(mp_obj_t)&aurora_epaper_framebuffer_set_free_bus_obj);
171+
172+
static const mp_rom_map_elem_t aurora_epaper_framebuffer_locals_dict_table[] = {
173+
{ MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&aurora_epaper_framebuffer_deinit_obj) },
174+
{ MP_ROM_QSTR(MP_QSTR_set_temperature), MP_ROM_PTR(&aurora_epaper_frambuffer_set_temperature_obj) },
175+
{ MP_ROM_QSTR(MP_QSTR_free_bus), MP_ROM_PTR(&aurora_epaper_framebuffer_free_bus_obj) },
176+
};
177+
static MP_DEFINE_CONST_DICT(aurora_epaper_framebuffer_locals_dict, aurora_epaper_framebuffer_locals_dict_table);
178+
179+
MP_DEFINE_CONST_OBJ_TYPE(
180+
aurora_framebuffer_type,
181+
MP_QSTR_AuroraEpaperFramebuffer,
182+
MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS,
183+
make_new, aurora_epaper_framebuffer_make_new,
184+
locals_dict, &aurora_epaper_framebuffer_locals_dict,
185+
buffer, aurora_epaper_framebuffer_get_buffer,
186+
protocol, &aurora_epaper_framebuffer_proto
187+
);
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/*
2+
* Copyright 2023 Cisco Systems, Inc. and its affiliates
3+
* Author: Wyrdsec
4+
*
5+
* Permission is hereby granted, free of charge, to any person obtaining a copy of
6+
* this software and associated documentation files (the "Software"), to deal in
7+
* the Software without restriction, including without limitation the rights to
8+
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9+
* the Software, and to permit persons to whom the Software is furnished to do so,
10+
* subject to the following conditions:
11+
* - The above copyright notice and this permission notice shall be included in
12+
* all copies or substantial portions of the Software.
13+
* - The Software is provided "as is", without warranty of any kind, express or
14+
* implied, including but not limited to the warranties of merchantability,
15+
* fitness for a particular purpose and noninfringement. In no event shall the
16+
* authors or copyright holders be liable for any claim, damages or other
17+
* liability, whether in an action of contract, tort or otherwise, arising from,
18+
* out of or in connection with the Software or the use or other dealings in the
19+
* Software.
20+
*/
21+
#pragma once
22+
23+
#include "py/objtype.h"
24+
#include "shared-module/aurora_epaper/aurora_framebuffer.h"
25+
26+
extern const mp_obj_type_t aurora_framebuffer_type;
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
2+
// No module functions
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
2+
#pragma once

0 commit comments

Comments
 (0)