|
28 | 28 |
|
29 | 29 | """ |
30 | 30 |
|
| 31 | +import time |
| 32 | + |
| 33 | +import digitalio |
31 | 34 | from epaperdisplay import EPaperDisplay |
32 | 35 |
|
33 | 36 | try: |
|
58 | 61 | _STOP_SEQUENCE = b"\x10\x80\x01\x01\x64" # Deep Sleep |
59 | 62 |
|
60 | 63 |
|
| 64 | +# LUT for original MagTag panel: FPC-A005 (SSD1680, User ID first byte 0x00) |
| 65 | +FPC_A005_LUT = ( |
| 66 | + b"\x2a\x60\x15\x00\x00\x00\x00\x00\x00\x00\x00\x00" # VS L0 |
| 67 | + b"\x20\x60\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00" # VS L1 |
| 68 | + b"\x28\x60\x14\x00\x00\x00\x00\x00\x00\x00\x00\x00" # VS L2 |
| 69 | + b"\x00\x60\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" # VS L3 |
| 70 | + b"\x00\x90\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" # VS L4 |
| 71 | + b"\x00\x02\x00\x05\x14\x00\x00" # TP, SR, RP Group0 |
| 72 | + b"\x1e\x1e\x00\x00\x00\x00\x01" # TP, SR, RP Group1 |
| 73 | + b"\x00\x02\x00\x05\x14\x00\x00" # TP, SR, RP Group2 |
| 74 | + b"\x00\x00\x00\x00\x00\x00\x00" # TP, SR, RP Group3 |
| 75 | + b"\x00\x00\x00\x00\x00\x00\x00" # TP, SR, RP Group4 |
| 76 | + b"\x00\x00\x00\x00\x00\x00\x00" # TP, SR, RP Group5 |
| 77 | + b"\x00\x00\x00\x00\x00\x00\x00" # TP, SR, RP Group6 |
| 78 | + b"\x00\x00\x00\x00\x00\x00\x00" # TP, SR, RP Group7 |
| 79 | + b"\x00\x00\x00\x00\x00\x00\x00" # TP, SR, RP Group8 |
| 80 | + b"\x00\x00\x00\x00\x00\x00\x00" # TP, SR, RP Group9 |
| 81 | + b"\x00\x00\x00\x00\x00\x00\x00" # TP, SR, RP Group10 |
| 82 | + b"\x00\x00\x00\x00\x00\x00\x00" # TP, SR, RP Group11 |
| 83 | + b"\x24\x22\x22\x22\x23\x32\x00\x00\x00" # FR, XON |
| 84 | +) |
| 85 | + |
| 86 | +# LUT for FPC-7519rev.b and newer panels (User ID first byte != 0x00). |
| 87 | +# GxEPD2_4G (GDEM029T94) waveform with L0/L3 swapped to match CircuitPython's luma mapping |
| 88 | +# (luma 0→L0=black, luma 255→L3=white) and 0x48 flag for DC-balanced drive. |
| 89 | +FPC7519_LUT = ( |
| 90 | + b"\x20\x48\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00" # VS L0 (black) |
| 91 | + b"\x08\x48\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00" # VS L1 (dark gray) |
| 92 | + b"\x02\x48\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00" # VS L2 (light gray) |
| 93 | + b"\x40\x48\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00" # VS L3 (white) |
| 94 | + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" # VS L4 (VCOM) |
| 95 | + b"\x0a\x19\x00\x03\x08\x00\x00" # TP, SR, RP Group0 |
| 96 | + b"\x14\x01\x00\x14\x01\x00\x03" # TP, SR, RP Group1 |
| 97 | + b"\x0a\x03\x00\x08\x19\x00\x00" # TP, SR, RP Group2 |
| 98 | + b"\x01\x00\x00\x00\x00\x00\x01" # TP, SR, RP Group3 |
| 99 | + b"\x00\x00\x00\x00\x00\x00\x00" # TP, SR, RP Group4 |
| 100 | + b"\x00\x00\x00\x00\x00\x00\x00" # TP, SR, RP Group5 |
| 101 | + b"\x00\x00\x00\x00\x00\x00\x00" # TP, SR, RP Group6 |
| 102 | + b"\x00\x00\x00\x00\x00\x00\x00" # TP, SR, RP Group7 |
| 103 | + b"\x00\x00\x00\x00\x00\x00\x00" # TP, SR, RP Group8 |
| 104 | + b"\x00\x00\x00\x00\x00\x00\x00" # TP, SR, RP Group9 |
| 105 | + b"\x00\x00\x00\x00\x00\x00\x00" # TP, SR, RP Group10 |
| 106 | + b"\x00\x00\x00\x00\x00\x00\x00" # TP, SR, RP Group11 |
| 107 | + b"\x22\x22\x22\x22\x22\x22\x00\x00\x00" # FR, XON |
| 108 | +) |
| 109 | + |
| 110 | + |
| 111 | +def detect_ssd1680_panel(data_pin, clk_pin, cs_pin, dc_pin, rst_pin): |
| 112 | + """Read SSD1680 User ID (register 0x2E) via half-duplex bitbang SPI. |
| 113 | +
|
| 114 | + Must be called before the SPI bus is initialized (FourWire claims the pins). |
| 115 | + The SSD1680 responds on the MOSI/DATA line in half-duplex mode, not MISO. |
| 116 | +
|
| 117 | + Returns first byte of User ID: |
| 118 | + 0x00 -> FPC-A005 (original/legacy MagTag panel) |
| 119 | + anything else -> FPC-7519rev.b or newer panel; use FPC7519_LUT |
| 120 | + """ |
| 121 | + data = digitalio.DigitalInOut(data_pin) |
| 122 | + clk = digitalio.DigitalInOut(clk_pin) |
| 123 | + cs = digitalio.DigitalInOut(cs_pin) |
| 124 | + dc = digitalio.DigitalInOut(dc_pin) |
| 125 | + rst = digitalio.DigitalInOut(rst_pin) |
| 126 | + |
| 127 | + for pin in (data, clk, cs, dc, rst): |
| 128 | + pin.direction = digitalio.Direction.OUTPUT |
| 129 | + pin.value = False |
| 130 | + |
| 131 | + rst.value = False |
| 132 | + time.sleep(0.001) |
| 133 | + rst.value = True |
| 134 | + time.sleep(0.010) |
| 135 | + |
| 136 | + cmd = 0x2E |
| 137 | + for i in range(8): |
| 138 | + data.value = bool(cmd & (1 << (7 - i))) |
| 139 | + clk.value = True |
| 140 | + clk.value = False |
| 141 | + |
| 142 | + data.switch_to_input(pull=digitalio.Pull.UP) |
| 143 | + dc.value = True |
| 144 | + |
| 145 | + result = 0 |
| 146 | + for _ in range(8): |
| 147 | + result = (result << 1) | (1 if data.value else 0) |
| 148 | + clk.value = True |
| 149 | + clk.value = False |
| 150 | + |
| 151 | + cs.value = True |
| 152 | + |
| 153 | + for pin in (data, clk, cs, dc, rst): |
| 154 | + pin.deinit() |
| 155 | + |
| 156 | + return result |
| 157 | + |
| 158 | + |
61 | 159 | # pylint: disable=too-few-public-methods |
62 | 160 | class SSD1680(EPaperDisplay): |
63 | 161 | r"""SSD1680 driver |
|
0 commit comments