mirror of
https://github.com/DreamSourceLab/DSView.git
synced 2025-01-13 13:32:53 +08:00
297 lines
12 KiB
Python
297 lines
12 KiB
Python
import sigrokdecode as srd
|
|
|
|
COMMAND_MAP = {
|
|
0x00: {"name": "NOP", "desc": "Empty command",},
|
|
0x01: {"name": "SWRESET", "desc": "Software Reset",},
|
|
0x04: {"name": "RDDID", "desc": "Read Display ID",},
|
|
0x09: {"name": "RDDST", "desc": "Read Display Status",},
|
|
0x0A: {"name": "RDDPM", "desc": "Read Display Power Mode",},
|
|
0x0B: {"name": "RDDMADCTL", "desc": "Read Display MADCTL",},
|
|
0x0C: {"name": "RDDCOLMOD", "desc": "Read Display Pixel Format",},
|
|
0x0D: {"name": "RDDIM", "desc": "Read Display Image Mode",},
|
|
0x0E: {"name": "RDDSM", "desc": "Read Display Signal Mode",},
|
|
0x0F: {"name": "RDDSDR", "desc": "Read Display Self-Diagnostic Result",},
|
|
0x10: {"name": "SLPIN", "desc": "Sleep in",},
|
|
0x11: {"name": "SLPOUT", "desc": "Sleep Out",},
|
|
0x12: {"name": "PTLON", "desc": "Partial Display Mode On",},
|
|
0x13: {"name": "NORON", "desc": "Normal Display Mode On",},
|
|
0x20: {"name": "INVOFF", "desc": "Display Inversion Off",},
|
|
0x21: {"name": "INVON", "desc": "Display Inversion On",},
|
|
0x26: {"name": "GAMSET", "desc": "Gamma Set",},
|
|
0x28: {"name": "DISPOFF", "desc": "Display Off",},
|
|
0x29: {"name": "DISPON", "desc": "Display On",},
|
|
0x2A: {"name": "CASET", "desc": "Column Address Set",},
|
|
0x2B: {"name": "RASET", "desc": "Row Address Set",},
|
|
0x2C: {"name": "RAMWR", "desc": "Memory Write",},
|
|
0x2E: {"name": "RAMRD", "desc": "Memory Read",},
|
|
0x30: {"name": "PTLAR", "desc": "Partial Area",},
|
|
0x33: {"name": "VSCRDEF", "desc": "Vertical Scrolling Definition",},
|
|
0x34: {"name": "TEOFF", "desc": "Tearing Effect Line OFF",},
|
|
0x35: {"name": "TEON", "desc": "Tearing Effect Line On",},
|
|
0x36: {"name": "MADCTL", "desc": "Memory Data Access Control",},
|
|
0x37: {"name": "VSCSAD", "desc": "Vertical Scroll Start Address of RAM",},
|
|
0x38: {"name": "IDMOFF", "desc": "Idle Mode Off",},
|
|
0x39: {"name": "IDMON", "desc": "Idle mode on",},
|
|
0x3A: {"name": "COLMOD", "desc": "Interface Pixel Format",},
|
|
0x3C: {"name": "WRMEMC", "desc": "Write Memory Continue",},
|
|
0x3E: {"name": "RDMEMC", "desc": "Read Memory Continue",},
|
|
0x44: {"name": "STE", "desc": "Set Tear Scanline",},
|
|
0x45: {"name": "GSCAN", "desc": "Get Scanline",},
|
|
0x51: {"name": "WRDISBV", "desc": "Write Display Brightness",},
|
|
0x52: {"name": "RDDISBV", "desc": "Read Display Brightness Value",},
|
|
0x53: {"name": "WRCTRLD", "desc": "Write CTRL Display",},
|
|
0x54: {"name": "RDCTRLD", "desc": "Read CTRL Value Display",},
|
|
0x55: {
|
|
"name": "WRCACE",
|
|
"desc": "Write Content Adaptive Brightness Control and Color Enhancement",
|
|
},
|
|
0x56: {"name": "RDCABC", "desc": "Read Content Adaptive Brightness Control",},
|
|
0x5E: {"name": "WRCABCMB", "desc": "Write CABC Minimum Brightness",},
|
|
0x5F: {"name": "RDCABCMB", "desc": "Read CABC Minimum Brightness",},
|
|
0x68: {
|
|
"name": "RDABCSDR",
|
|
"desc": "Read Automatic Brightness Control Self-Diagnostic Result",
|
|
},
|
|
0xDA: {"name": "RDID1", "desc": "Read ID1",},
|
|
0xDB: {"name": "RDID2", "desc": "Read ID2",},
|
|
0xDC: {"name": "RDID3", "desc": "Read ID3",},
|
|
0xB0: {"name": "RAMCTRL", "desc": "RAM Control",},
|
|
0xB1: {"name": "RGBCTRL", "desc": "RGB Interface Control",},
|
|
0xB2: {"name": "PORCTRL", "desc": "Porch Setting",},
|
|
0xB3: {
|
|
"name": "FRCTRL1",
|
|
"desc": "Frame Rate Control 1 (In partial mode/ idle colors)",
|
|
},
|
|
0xB5: {"name": "PARCTRL", "desc": "Partial mode Control",},
|
|
0xB7: {"name": "GCTRL", "desc": "Gate Control",},
|
|
0xB8: {"name": "GTADJ", "desc": "Gate On Timing Adjustment",},
|
|
0xBA: {"name": "DGMEN", "desc": "Digital Gamma Enable",},
|
|
0xBB: {"name": "VCOMS", "desc": "VCOMS Setting",},
|
|
0xC0: {"name": "LCMCTRL", "desc": "LCM Control",},
|
|
0xC1: {"name": "IDSET", "desc": "ID Code Setting",},
|
|
0xC2: {"name": "VDVVRHEN", "desc": "VDV and VRH Command Enable",},
|
|
0xC3: {"name": "VRHS", "desc": "VRH Set",},
|
|
0xC4: {"name": "VDVS", "desc": "VDV Set",},
|
|
0xC5: {"name": "VCMOFSET", "desc": "VCOMS Offset Set",},
|
|
0xC6: {"name": "FRCTRL2", "desc": "Frame Rate Control in Normal Mode",},
|
|
0xC7: {"name": "CABCCTRL", "desc": "CABC Control",},
|
|
0xC8: {"name": "REGSEL1", "desc": "Register Value Selection 1",},
|
|
0xCA: {"name": "REGSEL2", "desc": "Register Value Selection 2",},
|
|
0xCC: {"name": "PWMFRSEL", "desc": "PWM Frequency Selection",},
|
|
0xD0: {"name": "PWCTRL1", "desc": "Power Control 1",},
|
|
0xD2: {"name": "VAPVANEN", "desc": "Enable VAP/VAN signal output",},
|
|
0xDF: {"name": "CMD2EN", "desc": "Command 2 Enable",},
|
|
0xE0: {"name": "PVGAMCTRL", "desc": "Positive Voltage Gamma Control",},
|
|
0xE1: {"name": "NVGAMCTRL", "desc": "Negative Voltage Gamma Control",},
|
|
0xE2: {"name": "DGMLUTR", "desc": "Digital Gamma Look-up Table for Red",},
|
|
0xE3: {"name": "DGMLUTB", "desc": "Digital Gamma Look-up Table for Blue",},
|
|
0xE4: {"name": "GATECTRL", "desc": "Gate Control",},
|
|
0xE7: {"name": "SPI2EN", "desc": "SPI2 Enable",},
|
|
0xE8: {"name": "PWCTRL2", "desc": "Power Control 2",},
|
|
0xE9: {"name": "EQCTRL", "desc": "Equalize time control",},
|
|
0xEC: {"name": "PROMCTRL", "desc": "Program Mode Control",},
|
|
0xFA: {"name": "PROMEN", "desc": "Program Mode Enable",},
|
|
0xFC: {"name": "NVMSET", "desc": "NVM Setting",},
|
|
0xFE: {"name": "PROMACT", "desc": "Program action",},
|
|
}
|
|
|
|
|
|
def _get_annotation_index(annotations, name):
|
|
for index, annotation in enumerate(annotations):
|
|
if annotation[0] == name:
|
|
return index
|
|
raise RuntimeError(f"Unknown annotation {repr(name)}: {repr(annotations)}")
|
|
|
|
|
|
class Decoder(srd.Decoder):
|
|
api_version = 3
|
|
id = "st7789"
|
|
name = "ST7789"
|
|
longname = "Sitronix ST7789"
|
|
desc = "Sitronix ST7789 TFT controller protocol."
|
|
license = "gplv2+"
|
|
inputs = ["logic"]
|
|
outputs = []
|
|
channels = (
|
|
{"id": "csx", "name": "CSX", "desc": "Chip selection signal", 'idn':'dec_st7789_chan_csx'},
|
|
{"id": "dcx", "name": "DCX", "desc": "Clock signal", 'idn':'dec_st7789_chan_dcx'},
|
|
{"id": "sdo", "name": "SDO", "desc": "Serial output data", 'idn':'dec_st7789_chan_sdo'},
|
|
{"id": "wrx", "name": "WRX", "desc": "Command / data", 'idn':'dec_st7789_chan_wrx'},
|
|
)
|
|
optional_channels = tuple()
|
|
tags = ["Display", "SPI"]
|
|
annotations = (
|
|
("bit", "Bit"),
|
|
("command", "Command"),
|
|
("data", "Data"),
|
|
("cmd_data", "Command + Data"),
|
|
("asserted", "Assertion"),
|
|
)
|
|
|
|
annotation_rows = (
|
|
("bits", "Bits", (_get_annotation_index(annotations, "bit"),)),
|
|
(
|
|
"bytes",
|
|
"Bytes",
|
|
(
|
|
_get_annotation_index(annotations, "command"),
|
|
_get_annotation_index(annotations, "data"),
|
|
),
|
|
),
|
|
(
|
|
"cmd_data",
|
|
"Command + Data",
|
|
(_get_annotation_index(annotations, "cmd_data"),),
|
|
),
|
|
("asserted", "Assertion", (_get_annotation_index(annotations, "asserted"),)),
|
|
)
|
|
|
|
def _get_channel_index(self, name):
|
|
for index, channel in enumerate(self.channels):
|
|
if channel["name"] == name:
|
|
return index
|
|
raise RuntimeError("Implementation bug.")
|
|
|
|
def __init__(self):
|
|
self.reset()
|
|
|
|
def reset(self):
|
|
pass
|
|
|
|
def start(self):
|
|
self.out_ann = self.register(srd.OUTPUT_ANN)
|
|
|
|
def _get_cmd_str(self, cmd):
|
|
if cmd in COMMAND_MAP:
|
|
return COMMAND_MAP[cmd]["name"] + "(%02X)" % cmd
|
|
else:
|
|
return "Unknown(%02X)" % cmd
|
|
|
|
def _get_cmd_data_str(self, cmd, data_list):
|
|
cmd_str = self._get_cmd_str(cmd)
|
|
|
|
if data_list:
|
|
ret_str = f"{cmd_str}: "
|
|
for v in data_list:
|
|
ret_str += " %02X" % v
|
|
return ret_str
|
|
else:
|
|
return cmd_str
|
|
|
|
def decode(self):
|
|
last_cmd = None
|
|
last_cmd_data_sample_startnum = None
|
|
last_cmd_data_sample_endnum = None
|
|
last_cmd_data_list = []
|
|
|
|
while True:
|
|
self.wait({self._get_channel_index("CSX"): "f"})
|
|
csx_start_samplenum = self.samplenum
|
|
|
|
bit = None
|
|
bit_count = 0
|
|
byte = 0
|
|
byte_sample_startnum = None
|
|
|
|
while True:
|
|
# FIXME {self._get_channel_index("DCX"): "r"}
|
|
(csx, dcx, sdo, wrx) = self.wait(
|
|
[
|
|
{self._get_channel_index("CSX"): "r"},
|
|
{self._get_channel_index("DCX"): "e"},
|
|
]
|
|
)
|
|
if csx == 1:
|
|
self.put(
|
|
csx_start_samplenum,
|
|
self.samplenum,
|
|
self.out_ann,
|
|
[
|
|
_get_annotation_index(self.annotations, "asserted"),
|
|
["Asserted"],
|
|
],
|
|
)
|
|
|
|
if last_cmd is not None:
|
|
self.put(
|
|
last_cmd_data_sample_startnum,
|
|
last_cmd_data_sample_endnum,
|
|
self.out_ann,
|
|
[
|
|
_get_annotation_index(self.annotations, "cmd_data"),
|
|
[self._get_cmd_data_str(last_cmd, last_cmd_data_list)],
|
|
],
|
|
)
|
|
last_cmd = None
|
|
last_cmd_data_sample_startnum = None
|
|
last_cmd_data_sample_endnum = None
|
|
last_cmd_data_list = []
|
|
|
|
break
|
|
|
|
if dcx == 1 and bit is None:
|
|
bit = sdo
|
|
bit_start_samplenum = self.samplenum
|
|
bit_count += 1
|
|
byte = (byte << 1) | bit
|
|
if byte_sample_startnum is None:
|
|
byte_sample_startnum = self.samplenum
|
|
|
|
if dcx == 0 and bit is not None:
|
|
self.put(
|
|
bit_start_samplenum,
|
|
self.samplenum,
|
|
self.out_ann,
|
|
[_get_annotation_index(self.annotations, "bit"), [str(bit)]],
|
|
)
|
|
bit = None
|
|
if bit_count == 8:
|
|
if wrx:
|
|
last_cmd_data_sample_endnum = self.samplenum
|
|
last_cmd_data_list.append(byte)
|
|
self.put(
|
|
byte_sample_startnum,
|
|
self.samplenum,
|
|
self.out_ann,
|
|
[
|
|
_get_annotation_index(self.annotations, "data"),
|
|
["Data(%02X)" % byte],
|
|
],
|
|
)
|
|
else:
|
|
self.put(
|
|
byte_sample_startnum,
|
|
self.samplenum,
|
|
self.out_ann,
|
|
[
|
|
_get_annotation_index(self.annotations, "command"),
|
|
[self._get_cmd_str(byte)],
|
|
],
|
|
)
|
|
|
|
if last_cmd is not None:
|
|
self.put(
|
|
last_cmd_data_sample_startnum,
|
|
last_cmd_data_sample_endnum,
|
|
self.out_ann,
|
|
[
|
|
_get_annotation_index(
|
|
self.annotations, "cmd_data"
|
|
),
|
|
[
|
|
self._get_cmd_data_str(
|
|
last_cmd, last_cmd_data_list
|
|
)
|
|
],
|
|
],
|
|
)
|
|
last_cmd_data_list = []
|
|
|
|
last_cmd = byte
|
|
last_cmd_data_sample_startnum = byte_sample_startnum
|
|
last_cmd_data_sample_endnum = self.samplenum
|
|
|
|
byte = 0
|
|
bit_count = 0
|
|
byte_sample_startnum = None
|