]> sigrok.org Git - libsigrokdecode.git/blob - decoders/st7735/pd.py
Simple decoder for ST7735 TFT controller
[libsigrokdecode.git] / decoders / st7735 / pd.py
1 ##
2 ## This file is part of the libsigrokdecode project.
3 ##
4 ## Copyright (C) 2018 Aleksander Alekseev <afiskon@gmail.com>
5 ##
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.
10 ##
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.
15 ##
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/>.
18
19 import sigrokdecode as srd
20
21 MAX_DATA_LEN = 128
22
23 # Command ID -> name, short description
24 META = {
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'},
62 }
63
64 class Ann:
65     BITS, CMD, DATA, DESC = range(4)
66
67 class Decoder(srd.Decoder):
68     api_version = 3
69     id = 'st7735'
70     name = 'ST7735'
71     longname = 'Sitronix ST7735'
72     desc = 'Sitronix ST7735 TFT controller protocol.'
73     license = 'gplv2+'
74     inputs = ['logic']
75     outputs = ['st7735']
76     channels = (
77         {'id': 'cs', 'name': 'CS#', 'desc': 'Chip-select'},
78         {'id': 'clk', 'name': 'CLK', 'desc': 'Clock'},
79         {'id': 'mosi', 'name': 'MOSI', 'desc': 'Master out, slave in'},
80         {'id': 'dc', 'name': 'DC', 'desc': 'Data or command'}
81     )
82     annotations = (
83         ('bit', 'Bit'),
84         ('command', 'Command'),
85         ('data', 'Data'),
86         ('description', 'Description'),
87     )
88     annotation_rows = (
89         ('bits', 'Bits', (Ann.BITS,)),
90         ('fields', 'Fields', (Ann.CMD, Ann.DATA)),
91         ('description', 'Description', (Ann.DESC,)),
92     )
93
94     def __init__(self):
95         self.reset()
96
97     def reset(self):
98         pass
99
100     def start(self):
101         self.out_ann = self.register(srd.OUTPUT_ANN)
102
103     def reset_state(self):
104         self.accum_byte = 0
105         self.accum_bits_num = 0
106         self.bit_ss = -1
107         self.byte_ss = -1
108         self.current_bit = -1
109
110     def put_desc(self, ss, es, cmd, data):
111         if cmd == -1:
112             return
113         if META[cmd]:
114             self.put(ss, es, self.out_ann, [Ann.DESC,
115                 ['%s: %s' % (META[cmd]['name'].strip(), META[cmd]['desc'])]])
116         else:
117             # Default description:
118             dots = ''
119             if len(data) == MAX_DATA_LEN:
120                 data = data[:-1]
121                 dots = '...'
122             data_str = '(none)'
123             if len(data) > 0:
124                 data_str = ' '.join(['%02X' % b for b in data])
125             self.put(ss, es, self.out_ann, [Ann.DESC,
126                 ['Unknown command: %02X. Data: %s%s' % (cmd, data_str, dots)]])
127
128     def decode(self):
129         current_cmd = -1
130         current_data = []
131         desc_ss = -1
132         desc_es = -1
133         self.reset_state()
134         while True:
135             # Check data on both CLK edges.
136             (cs, clk, mosi, dc) = self.wait({1: 'e'})
137
138             if cs == 1: # Wait for CS = low, ignore the rest.
139                 self.reset_state()
140                 continue
141
142             if clk == 1:
143                 # Read one bit.
144                 self.bit_ss = self.samplenum
145                 if self.accum_bits_num == 0:
146                     self.byte_ss = self.samplenum
147                 self.current_bit = mosi
148
149             if (clk == 0) and (self.current_bit >= 0):
150                 # Process one bit.
151                 self.put(self.bit_ss, self.samplenum, self.out_ann,
152                          [Ann.BITS, [str(self.current_bit)]])
153                 self.accum_byte = (self.accum_byte << 1) | self.current_bit # MSB-first.
154                 self.accum_bits_num += 1
155                 if self.accum_bits_num == 8:
156                     # Process one byte.
157                     ann = Ann.DATA if dc else Ann.CMD # DC = low for commands.
158                     self.put(self.byte_ss, self.samplenum, self.out_ann,
159                              [ann, ['%02X' % self.accum_byte]])
160                     if ann == Ann.CMD:
161                         self.put_desc(desc_ss, desc_es, current_cmd, current_data)
162                         desc_ss = self.byte_ss
163                         desc_es = self.samplenum # For cmds without data.
164                         current_cmd = self.accum_byte
165                         current_data = []
166                     else:
167                         if len(current_data) < MAX_DATA_LEN:
168                             current_data += [self.accum_byte]
169                         desc_es = self.samplenum
170
171                     self.accum_bits_num = 0
172                     self.accum_byte = 0
173                     self.byte_ss = -1
174                 self.current_bit = -1
175                 self.bit_ss = -1