2022-10-21 11:10:28 +08:00

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