2 ## This file is part of the libsigrokdecode project.
4 ## Copyright (C) 2018 Aleksander Alekseev <afiskon@gmail.com>
6 ## This program is free software; you can redistribute it and/or modify
7 ## it under the terms of the GNU General Public License as published by
8 ## the Free Software Foundation; either version 2 of the License, or
9 ## (at your option) any later version.
11 ## This program is distributed in the hope that it will be useful,
12 ## but WITHOUT ANY WARRANTY; without even the implied warranty of
13 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 ## GNU General Public License for more details.
16 ## You should have received a copy of the GNU General Public License
17 ## along with this program; if not, see <http://www.gnu.org/licenses/>.
19 import sigrokdecode
as srd
23 # Command ID -> name, short description
25 0x00: {'name': 'NOP ', 'desc': 'No operation'},
26 0x01: {'name': 'SWRESET', 'desc': 'Software reset'},
27 0x04: {'name': 'RDDID ', 'desc': 'Read display ID'},
28 0x09: {'name': 'RDDST ', 'desc': 'Read display status'},
29 0x10: {'name': 'SLPIN ', 'desc': 'Sleep in & booster off'},
30 0x11: {'name': 'SLPOUT ', 'desc': 'Sleep out & booster on'},
31 0x12: {'name': 'PTLON ', 'desc': 'Partial mode on'},
32 0x13: {'name': 'NORON ', 'desc': 'Partial off (normal)'},
33 0x20: {'name': 'INVOFF ', 'desc': 'Display inversion off'},
34 0x21: {'name': 'INVON ', 'desc': 'Display inversion on'},
35 0x28: {'name': 'DISPOFF', 'desc': 'Display off'},
36 0x29: {'name': 'DISPON ', 'desc': 'Display on'},
37 0x2A: {'name': 'CASET ', 'desc': 'Column address set'},
38 0x2B: {'name': 'RASET ', 'desc': 'Row address set'},
39 0x2C: {'name': 'RAMWR ', 'desc': 'Memory write'},
40 0x2E: {'name': 'RAMRD ', 'desc': 'Memory read'},
41 0x30: {'name': 'PTLAR ', 'desc': 'Partial start/end address set'},
42 0x36: {'name': 'MADCTL ', 'desc': 'Memory data address control'},
43 0x3A: {'name': 'COLMOD ', 'desc': 'Interface pixel format'},
44 0xB1: {'name': 'FRMCTR1', 'desc': 'Frame rate control (in normal mode / full colors)'},
45 0xB2: {'name': 'FRMCTR2', 'desc': 'Frame rate control (in idle mode / 8-colors)'},
46 0xB3: {'name': 'FRMCTR3', 'desc': 'Frame rate control (in partial mode / full colors) '},
47 0xB4: {'name': 'INVCTR ', 'desc': 'Display inversion control'},
48 0xB6: {'name': 'DISSET5', 'desc': 'Display function set 5'},
49 0xC0: {'name': 'PWCTR1 ', 'desc': 'Power control 1'},
50 0xC1: {'name': 'PWCTR2 ', 'desc': 'Power control 2'},
51 0xC2: {'name': 'PWCTR3 ', 'desc': 'Power control 3'},
52 0xC3: {'name': 'PWCTR4 ', 'desc': 'Power control 4'},
53 0xC4: {'name': 'PWCTR5 ', 'desc': 'Power control 5'},
54 0xC5: {'name': 'VMCTR1 ', 'desc': 'VCOM control 1'},
55 0xDA: {'name': 'RDID1 ', 'desc': 'Read ID1'},
56 0xDB: {'name': 'RDID2 ', 'desc': 'Read ID2'},
57 0xDC: {'name': 'RDID3 ', 'desc': 'Read ID3'},
58 0xDD: {'name': 'RDID4 ', 'desc': 'Read ID4'},
59 0xFC: {'name': 'PWCTR6 ', 'desc': 'Power control 6'},
60 0xE0: {'name': 'GMCTRP1', 'desc': 'Gamma \'+\'polarity correction characteristics setting'},
61 0xE1: {'name': 'GMCTRN1', 'desc': 'Gamma \'-\'polarity correction characteristics setting'},
65 BITS
, CMD
, DATA
, DESC
= range(4)
67 class Decoder(srd
.Decoder
):
71 longname
= 'Sitronix ST7735'
72 desc
= 'Sitronix ST7735 TFT controller protocol.'
76 tags
= ['Display', 'IC']
78 {'id': 'cs', 'name': 'CS#', 'desc': 'Chip-select'},
79 {'id': 'clk', 'name': 'CLK', 'desc': 'Clock'},
80 {'id': 'mosi', 'name': 'MOSI', 'desc': 'Master out, slave in'},
81 {'id': 'dc', 'name': 'DC', 'desc': 'Data or command'}
85 ('command', 'Command'),
87 ('description', 'Description'),
90 ('bits', 'Bits', (Ann
.BITS
,)),
91 ('fields', 'Fields', (Ann
.CMD
, Ann
.DATA
)),
92 ('descriptions', 'Descriptions', (Ann
.DESC
,)),
100 self
.accum_bits_num
= 0
103 self
.current_bit
= -1
106 self
.out_ann
= self
.register(srd
.OUTPUT_ANN
)
108 def put_desc(self
, ss
, es
, cmd
, data
):
112 self
.put(ss
, es
, self
.out_ann
, [Ann
.DESC
,
113 ['%s: %s' % (META
[cmd
]['name'].strip(), META
[cmd
]['desc'])]])
115 # Default description:
117 if len(data
) == MAX_DATA_LEN
:
122 data_str
= ' '.join(['%02X' % b
for b
in data
])
123 self
.put(ss
, es
, self
.out_ann
, [Ann
.DESC
,
124 ['Unknown command: %02X. Data: %s%s' % (cmd
, data_str
, dots
)]])
133 # Check data on both CLK edges.
134 (cs
, clk
, mosi
, dc
) = self
.wait({1: 'e'})
136 if cs
== 1: # Wait for CS = low, ignore the rest.
142 self
.bit_ss
= self
.samplenum
143 if self
.accum_bits_num
== 0:
144 self
.byte_ss
= self
.samplenum
145 self
.current_bit
= mosi
147 if (clk
== 0) and (self
.current_bit
>= 0):
149 self
.put(self
.bit_ss
, self
.samplenum
, self
.out_ann
,
150 [Ann
.BITS
, [str(self
.current_bit
)]])
151 self
.accum_byte
= (self
.accum_byte
<< 1) | self
.current_bit
# MSB-first.
152 self
.accum_bits_num
+= 1
153 if self
.accum_bits_num
== 8:
155 ann
= Ann
.DATA
if dc
else Ann
.CMD
# DC = low for commands.
156 self
.put(self
.byte_ss
, self
.samplenum
, self
.out_ann
,
157 [ann
, ['%02X' % self
.accum_byte
]])
159 self
.put_desc(desc_ss
, desc_es
, current_cmd
, current_data
)
160 desc_ss
= self
.byte_ss
161 desc_es
= self
.samplenum
# For cmds without data.
162 current_cmd
= self
.accum_byte
165 if len(current_data
) < MAX_DATA_LEN
:
166 current_data
+= [self
.accum_byte
]
167 desc_es
= self
.samplenum
169 self
.accum_bits_num
= 0
172 self
.current_bit
= -1