Skip to content

Commit 857c625

Browse files
authored
Merge pull request #10505 from tannewt/magtag2025
Autodetect new MagTag displays
2 parents 3512e66 + f4316cb commit 857c625

File tree

1 file changed

+177
-36
lines changed
  • ports/espressif/boards/adafruit_magtag_2.9_grayscale

1 file changed

+177
-36
lines changed

ports/espressif/boards/adafruit_magtag_2.9_grayscale/board.c

Lines changed: 177 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ static const char *TAG = "board";
2121

2222
// This is an ILO373 control chip. The display is a 2.9" grayscale EInk.
2323

24-
const uint8_t display_start_sequence[] = {
24+
const uint8_t il0373_display_start_sequence[] = {
2525
0x01, 5, 0x03, 0x00, 0x2b, 0x2b, 0x13, // power setting
2626
0x06, 3, 0x17, 0x17, 0x17, // booster soft start
2727
0x04, DELAY, 200, // power on and wait 200 ms
@@ -83,17 +83,121 @@ const uint8_t display_start_sequence[] = {
8383
0x00, 0x00, 0x00, 0x00, 0x00, 0x00
8484
};
8585

86-
const uint8_t display_stop_sequence[] = {
86+
const uint8_t il0373_display_stop_sequence[] = {
8787
0x50, 0x01, 0x17, // CDI Setting
8888
0x82, 0x01, 0x00, // VCM DC to -0.1V
8989
0x02, 0x00 // Power off
9090
};
9191

92-
const uint8_t refresh_sequence[] = {
92+
const uint8_t il0373_display_refresh_sequence[] = {
9393
0x12, 0x00
9494
};
9595

96+
97+
// This is an SSD1680 control chip. The display is a 2.9" grayscale EInk.
98+
const uint8_t ssd1680_display_start_sequence[] = {
99+
0x12, DELAY, 0x00, 0x14, // soft reset and wait 20ms
100+
0x11, 0x00, 0x01, 0x03, // Ram data entry mode
101+
0x3c, 0x00, 0x01, 0x03, // border color
102+
0x2c, 0x00, 0x01, 0x28, // Set vcom voltage
103+
0x03, 0x00, 0x01, 0x17, // Set gate voltage
104+
0x04, 0x00, 0x03, 0x41, 0xae, 0x32, // Set source voltage
105+
0x4e, 0x00, 0x01, 0x01, // ram x count
106+
0x4f, 0x00, 0x02, 0x00, 0x00, // ram y count
107+
0x01, 0x00, 0x03, 0x27, 0x01, 0x00, // set display size
108+
0x32, 0x00, 0x99, // Update waveforms
109+
0x2a, 0x60, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // VS L0
110+
0x20, 0x60, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // VS L1
111+
0x28, 0x60, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // VS L2
112+
0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // VS L3
113+
0x00, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // VS L4
114+
0x00, 0x02, 0x00, 0x05, 0x14, 0x00, 0x00, // TP, SR, RP of Group0
115+
0x1E, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x01, // TP, SR, RP of Group1
116+
0x00, 0x02, 0x00, 0x05, 0x14, 0x00, 0x00, // TP, SR, RP of Group2
117+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // TP, SR, RP of Group3
118+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // TP, SR, RP of Group4
119+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // TP, SR, RP of Group5
120+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // TP, SR, RP of Group6
121+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // TP, SR, RP of Group7
122+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // TP, SR, RP of Group8
123+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // TP, SR, RP of Group9
124+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // TP, SR, RP of Group10
125+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // TP, SR, RP of Group11
126+
0x24, 0x22, 0x22, 0x22, 0x23, 0x32, 0x00, 0x00, 0x00, // FR, XON
127+
0x22, 0x00, 0x01, 0xc7 // display update mode
128+
};
129+
130+
const uint8_t ssd1680_display_stop_sequence[] = {
131+
0x10, DELAY, 0x01, 0x01, 0x64
132+
};
133+
134+
const uint8_t ssd1680_display_refresh_sequence[] = {
135+
0x20, 0x00, 0x00
136+
};
137+
138+
static bool detect_ssd1680(void) {
139+
// Bitbang 4-wire SPI with a bidirectional data line to read register 0x71.
140+
// On the IL0373 it will return 0x13 or similar. On the SSD1680 it is
141+
// unsupported and will be 0xff.
142+
digitalio_digitalinout_obj_t data;
143+
digitalio_digitalinout_obj_t clock;
144+
digitalio_digitalinout_obj_t chip_select;
145+
digitalio_digitalinout_obj_t data_command;
146+
digitalio_digitalinout_obj_t reset;
147+
data.base.type = &digitalio_digitalinout_type;
148+
clock.base.type = &digitalio_digitalinout_type;
149+
chip_select.base.type = &digitalio_digitalinout_type;
150+
data_command.base.type = &digitalio_digitalinout_type;
151+
reset.base.type = &digitalio_digitalinout_type;
152+
153+
common_hal_digitalio_digitalinout_construct(&data, &pin_GPIO35);
154+
common_hal_digitalio_digitalinout_construct(&clock, &pin_GPIO36);
155+
common_hal_digitalio_digitalinout_construct(&chip_select, &pin_GPIO8);
156+
common_hal_digitalio_digitalinout_construct(&data_command, &pin_GPIO7);
157+
common_hal_digitalio_digitalinout_construct(&reset, &pin_GPIO6);
158+
159+
// Set CS and DC low
160+
common_hal_digitalio_digitalinout_switch_to_output(&chip_select, false, DRIVE_MODE_PUSH_PULL);
161+
common_hal_digitalio_digitalinout_switch_to_output(&data_command, false, DRIVE_MODE_PUSH_PULL);
162+
common_hal_digitalio_digitalinout_switch_to_output(&data, false, DRIVE_MODE_PUSH_PULL);
163+
common_hal_digitalio_digitalinout_switch_to_output(&reset, true, DRIVE_MODE_PUSH_PULL);
164+
common_hal_digitalio_digitalinout_switch_to_output(&clock, false, DRIVE_MODE_PUSH_PULL);
165+
166+
uint8_t status_read = 0x71;
167+
for (int i = 0; i < 8; i++) {
168+
common_hal_digitalio_digitalinout_set_value(&data, (status_read & (1 << (7 - i))) != 0);
169+
common_hal_digitalio_digitalinout_set_value(&clock, true);
170+
common_hal_digitalio_digitalinout_set_value(&clock, false);
171+
}
172+
173+
// Set DC high for data and switch to input with pull-up in case the SSD1680 doesn't send any
174+
// data back (as it should.)
175+
common_hal_digitalio_digitalinout_switch_to_input(&data, PULL_UP);
176+
common_hal_digitalio_digitalinout_set_value(&data_command, true);
177+
uint8_t status = 0;
178+
for (int bit = 0; bit < 8; bit++) {
179+
status <<= 1;
180+
if (common_hal_digitalio_digitalinout_get_value(&data)) {
181+
status |= 1;
182+
}
183+
common_hal_digitalio_digitalinout_set_value(&clock, true);
184+
common_hal_digitalio_digitalinout_set_value(&clock, false);
185+
}
186+
187+
// Set CS high
188+
common_hal_digitalio_digitalinout_set_value(&chip_select, true);
189+
190+
common_hal_digitalio_digitalinout_deinit(&data);
191+
common_hal_digitalio_digitalinout_deinit(&clock);
192+
common_hal_digitalio_digitalinout_deinit(&chip_select);
193+
common_hal_digitalio_digitalinout_deinit(&data_command);
194+
common_hal_digitalio_digitalinout_deinit(&reset);
195+
return status == 0xff;
196+
}
197+
96198
void board_init(void) {
199+
bool is_ssd1680 = detect_ssd1680();
200+
97201
fourwire_fourwire_obj_t *bus = &allocate_display_bus()->fourwire_bus;
98202
busio_spi_obj_t *spi = &bus->inline_bus;
99203
common_hal_busio_spi_construct(spi, &pin_GPIO36, &pin_GPIO35, NULL, false);
@@ -111,39 +215,76 @@ void board_init(void) {
111215

112216
epaperdisplay_epaperdisplay_obj_t *display = &allocate_display()->epaper_display;
113217
display->base.type = &epaperdisplay_epaperdisplay_type;
114-
common_hal_epaperdisplay_epaperdisplay_construct(
115-
display,
116-
bus,
117-
display_start_sequence, sizeof(display_start_sequence),
118-
0, // start up time
119-
display_stop_sequence, sizeof(display_stop_sequence),
120-
296, // width
121-
128, // height
122-
160, // ram_width
123-
296, // ram_height
124-
0, // colstart
125-
0, // rowstart
126-
270, // rotation
127-
NO_COMMAND, // set_column_window_command
128-
NO_COMMAND, // set_row_window_command
129-
NO_COMMAND, // set_current_column_command
130-
NO_COMMAND, // set_current_row_command
131-
0x10, // write_black_ram_command
132-
false, // black_bits_inverted
133-
0x13, // write_color_ram_command
134-
false, // color_bits_inverted
135-
0x000000, // highlight_color
136-
refresh_sequence, sizeof(refresh_sequence),
137-
1.0, // refresh_time
138-
&pin_GPIO5, // busy_pin
139-
false, // busy_state
140-
5.0, // seconds_per_frame
141-
false, // always_toggle_chip_select
142-
true, // grayscale
143-
false, // acep
144-
false, // spectra6
145-
false, // two_byte_sequence_length
146-
false); // address_little_endian
218+
219+
if (is_ssd1680) {
220+
common_hal_epaperdisplay_epaperdisplay_construct(
221+
display,
222+
bus,
223+
ssd1680_display_start_sequence, sizeof(ssd1680_display_start_sequence),
224+
0, // start up time
225+
ssd1680_display_stop_sequence, sizeof(ssd1680_display_stop_sequence),
226+
296, // width
227+
128, // height
228+
250, // ram_width
229+
296, // ram_height
230+
0, // colstart
231+
0, // rowstart
232+
270, // rotation
233+
0x44, // set_column_window_command
234+
0x45, // set_row_window_command
235+
0x4e, // set_current_column_command
236+
0x4f, // set_current_row_command
237+
0x24, // write_black_ram_command
238+
false, // black_bits_inverted
239+
0x26, // write_color_ram_command
240+
false, // color_bits_inverted
241+
0x000000, // highlight_color
242+
ssd1680_display_refresh_sequence, sizeof(ssd1680_display_refresh_sequence),
243+
1.0, // refresh_time
244+
&pin_GPIO5, // busy_pin
245+
true, // busy_state
246+
5.0, // seconds_per_frame
247+
false, // always_toggle_chip_select
248+
true, // grayscale
249+
false, // acep
250+
false, // spectra6
251+
true, // two_byte_sequence_length
252+
true); // address_little_endian
253+
} else {
254+
common_hal_epaperdisplay_epaperdisplay_construct(
255+
display,
256+
bus,
257+
il0373_display_start_sequence, sizeof(il0373_display_start_sequence),
258+
0, // start up time
259+
il0373_display_stop_sequence, sizeof(il0373_display_stop_sequence),
260+
296, // width
261+
128, // height
262+
160, // ram_width
263+
296, // ram_height
264+
0, // colstart
265+
0, // rowstart
266+
270, // rotation
267+
NO_COMMAND, // set_column_window_command
268+
NO_COMMAND, // set_row_window_command
269+
NO_COMMAND, // set_current_column_command
270+
NO_COMMAND, // set_current_row_command
271+
0x10, // write_black_ram_command
272+
false, // black_bits_inverted
273+
0x13, // write_color_ram_command
274+
false, // color_bits_inverted
275+
0x000000, // highlight_color
276+
il0373_display_refresh_sequence, sizeof(il0373_display_refresh_sequence),
277+
1.0, // refresh_time
278+
&pin_GPIO5, // busy_pin
279+
false, // busy_state
280+
5.0, // seconds_per_frame
281+
false, // always_toggle_chip_select
282+
true, // grayscale
283+
false, // acep
284+
false, // spectra6
285+
false, // two_byte_sequence_length
286+
false); // address_little_endian
287+
}
147288
}
148289

149290
bool espressif_board_reset_pin_number(gpio_num_t pin_number) {

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy