]> sigrok.org Git - libsigrokdecode.git/blame - decoders/spi/pd.py
spi: Define annotation rows.
[libsigrokdecode.git] / decoders / spi / pd.py
CommitLineData
6eb87578 1##
50bd5d25 2## This file is part of the libsigrokdecode project.
6eb87578
GM
3##
4## Copyright (C) 2011 Gareth McMullin <gareth@blacksphere.co.nz>
12549f11 5## Copyright (C) 2012-2014 Uwe Hermann <uwe@hermann-uwe.de>
6eb87578
GM
6##
7## This program is free software; you can redistribute it and/or modify
8## it under the terms of the GNU General Public License as published by
9## the Free Software Foundation; either version 2 of the License, or
10## (at your option) any later version.
11##
12## This program is distributed in the hope that it will be useful,
13## but WITHOUT ANY WARRANTY; without even the implied warranty of
14## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15## GNU General Public License for more details.
16##
17## You should have received a copy of the GNU General Public License
18## along with this program; if not, write to the Free Software
19## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20##
ad2dc0de 21
677d597b 22import sigrokdecode as srd
67e847fd 23
0702e0cf 24'''
c515eed7 25OUTPUT_PYTHON format:
0702e0cf
UH
26
27SPI packet:
28[<cmd>, <data1>, <data2>]
29
30Commands:
31 - 'DATA': <data1> contains the MISO data, <data2> contains the MOSI data.
32 The data is _usually_ 8 bits (but can also be fewer or more bits).
12549f11
UH
33 Both data items are Python numbers (not strings), or None if the respective
34 probe was not supplied.
0702e0cf
UH
35 - 'CS CHANGE': <data1> is the old CS# pin value, <data2> is the new value.
36 Both data items are Python numbers (0/1), not strings.
37
38Examples:
39 ['CS-CHANGE', 1, 0]
40 ['DATA', 0xff, 0x3a]
41 ['DATA', 0x65, 0x00]
12549f11
UH
42 ['DATA', 0xa8, None]
43 ['DATA', None, 0x55]
0702e0cf
UH
44 ['CS-CHANGE', 0, 1]
45'''
46
8a7ce2a3 47# Key: (CPOL, CPHA). Value: SPI mode.
94bbdb9a
UH
48# Clock polarity (CPOL) = 0/1: Clock is low/high when inactive.
49# Clock phase (CPHA) = 0/1: Data is valid on the leading/trailing clock edge.
c94c8c91
UH
50spi_mode = {
51 (0, 0): 0, # Mode 0
52 (0, 1): 1, # Mode 1
53 (1, 0): 2, # Mode 2
54 (1, 1): 3, # Mode 3
55}
56
677d597b 57class Decoder(srd.Decoder):
a2c2afd9 58 api_version = 1
67e847fd 59 id = 'spi'
2b7d0e2b 60 name = 'SPI'
3d3da57d 61 longname = 'Serial Peripheral Interface'
a465436e 62 desc = 'Full-duplex, synchronous, serial bus.'
6eb87578
GM
63 license = 'gplv2+'
64 inputs = ['logic']
65 outputs = ['spi']
6b5b91d2 66 probes = [
bcd14870 67 {'id': 'clk', 'name': 'CLK', 'desc': 'SPI clock line'},
6b5b91d2 68 ]
efa64173 69 optional_probes = [
12549f11
UH
70 {'id': 'miso', 'name': 'MISO',
71 'desc': 'SPI MISO line (master in, slave out)'},
72 {'id': 'mosi', 'name': 'MOSI',
73 'desc': 'SPI MOSI line (master out, slave in)'},
efa64173
UH
74 {'id': 'cs', 'name': 'CS#', 'desc': 'SPI chip-select line'},
75 ]
238b4080 76 options = {
94bbdb9a
UH
77 'cs_polarity': ['CS# polarity', 'active-low'],
78 'cpol': ['Clock polarity', 0],
79 'cpha': ['Clock phase', 0],
80 'bitorder': ['Bit order within the SPI data', 'msb-first'],
c94c8c91 81 'wordsize': ['Word size of SPI data', 8], # 1-64?
3eda7779 82 'format': ['Data format', 'hex'],
238b4080 83 }
b1bb5eed 84 annotations = [
9f2f42c0
UH
85 ['miso-data', 'MISO SPI data'],
86 ['mosi-data', 'MOSI SPI data'],
87 ['warnings', 'Human-readable warnings'],
b1bb5eed 88 ]
06b52ebb
UH
89 annotation_rows = (
90 ('miso', 'MISO', (0,)),
91 ('mosi', 'MOSI', (1,)),
92 ('other', 'Other', (2,)),
93 )
6eb87578 94
3643fc3f 95 def __init__(self):
8a3c8792 96 self.samplerate = None
bcd14870 97 self.oldclk = 1
a10bfc48 98 self.bitcount = 0
4917bb31 99 self.mosidata = 0
d6bace96 100 self.misodata = 0
ec0afe27 101 self.startsample = -1
d6bace96 102 self.samplenum = -1
01329e88 103 self.cs_was_deasserted_during_data_word = 0
3e3c0330 104 self.oldcs = -1
2fcd7c22 105 self.oldpins = None
12549f11
UH
106 self.have_cs = None
107 self.have_miso = None
108 self.have_mosi = None
191ec8c5 109 self.state = 'IDLE'
6eb87578 110
8a3c8792
BV
111 def metadata(self, key, value):
112 if key == srd.SRD_CONF_SAMPLERATE:
113 self.samplerate = value
114
8915b346 115 def start(self):
c515eed7 116 self.out_python = self.register(srd.OUTPUT_PYTHON)
be465111 117 self.out_ann = self.register(srd.OUTPUT_ANN)
8a3c8792
BV
118 self.out_bitrate = self.register(srd.OUTPUT_META,
119 meta=(int, 'Bitrate', 'Bitrate during transfers'))
3643fc3f 120
ec0afe27 121 def putpw(self, data):
c515eed7 122 self.put(self.startsample, self.samplenum, self.out_python, data)
ec0afe27
UH
123
124 def putw(self, data):
125 self.put(self.startsample, self.samplenum, self.out_ann, data)
126
bcd14870 127 def handle_bit(self, miso, mosi, clk, cs):
191ec8c5
UH
128 # If this is the first bit, save its sample number.
129 if self.bitcount == 0:
130 self.startsample = self.samplenum
efa64173
UH
131 if self.have_cs:
132 active_low = (self.options['cs_polarity'] == 'active-low')
133 deasserted = cs if active_low else not cs
134 if deasserted:
135 self.cs_was_deasserted_during_data_word = 1
2fcd7c22 136
191ec8c5 137 ws = self.options['wordsize']
d6bace96 138
191ec8c5 139 # Receive MOSI bit into our shift register.
12549f11
UH
140 if self.have_mosi:
141 if self.options['bitorder'] == 'msb-first':
142 self.mosidata |= mosi << (ws - 1 - self.bitcount)
143 else:
144 self.mosidata |= mosi << self.bitcount
3e3c0330 145
191ec8c5 146 # Receive MISO bit into our shift register.
12549f11
UH
147 if self.have_miso:
148 if self.options['bitorder'] == 'msb-first':
149 self.misodata |= miso << (ws - 1 - self.bitcount)
150 else:
151 self.misodata |= miso << self.bitcount
c94c8c91 152
191ec8c5 153 self.bitcount += 1
1ea831e9 154
191ec8c5
UH
155 # Continue to receive if not enough bits were received, yet.
156 if self.bitcount != ws:
157 return
b1bb5eed 158
12549f11
UH
159 si = self.mosidata if self.have_mosi else None
160 so = self.misodata if self.have_miso else None
8a3c8792 161
12549f11
UH
162 # Pass MOSI and MISO to the next PD up the stack.
163 self.putpw(['DATA', si, so])
b1bb5eed 164
12549f11
UH
165 # Annotations.
166 if self.have_miso:
167 self.putw([0, ['%02X' % self.misodata]])
168 if self.have_mosi:
169 self.putw([1, ['%02X' % self.mosidata]])
170
171 # Meta bitrate.
8a3c8792
BV
172 elapsed = 1 / float(self.samplerate) * (self.samplenum - self.startsample + 1)
173 bitrate = int(1 / elapsed * self.options['wordsize'])
174 self.put(self.startsample, self.samplenum, self.out_bitrate, bitrate)
175
12549f11 176 if self.have_cs and self.cs_was_deasserted_during_data_word:
c1411010 177 self.putw([2, ['CS# was deasserted during this data word!']])
191ec8c5
UH
178
179 # Reset decoder state.
12549f11
UH
180 self.misodata = 0 if self.have_miso else None
181 self.mosidata = 0 if self.have_mosi else None
182 self.bitcount = 0
191ec8c5 183
bcd14870 184 def find_clk_edge(self, miso, mosi, clk, cs):
efa64173 185 if self.have_cs and self.oldcs != cs:
191ec8c5 186 # Send all CS# pin value changes.
c515eed7 187 self.put(self.samplenum, self.samplenum, self.out_python,
191ec8c5
UH
188 ['CS-CHANGE', self.oldcs, cs])
189 self.oldcs = cs
efa64173 190 # Reset decoder state when CS# changes (and the CS# pin is used).
12549f11
UH
191 self.misodata = 0 if self.have_miso else None
192 self.mosidata = 0 if self.have_mosi else None
193 self.bitcount = 0
191ec8c5
UH
194
195 # Ignore sample if the clock pin hasn't changed.
bcd14870 196 if clk == self.oldclk:
191ec8c5 197 return
b1bb5eed 198
bcd14870 199 self.oldclk = clk
b1bb5eed 200
191ec8c5
UH
201 # Sample data on rising/falling clock edge (depends on mode).
202 mode = spi_mode[self.options['cpol'], self.options['cpha']]
bcd14870 203 if mode == 0 and clk == 0: # Sample on rising clock edge
191ec8c5 204 return
bcd14870 205 elif mode == 1 and clk == 1: # Sample on falling clock edge
191ec8c5 206 return
bcd14870 207 elif mode == 2 and clk == 1: # Sample on falling clock edge
191ec8c5 208 return
bcd14870 209 elif mode == 3 and clk == 0: # Sample on rising clock edge
191ec8c5
UH
210 return
211
212 # Found the correct clock edge, now get the SPI bit(s).
bcd14870 213 self.handle_bit(miso, mosi, clk, cs)
191ec8c5
UH
214
215 def decode(self, ss, es, data):
8a3c8792
BV
216 if self.samplerate is None:
217 raise Exception("Cannot decode without samplerate.")
12549f11 218 # Either MISO or MOSI can be omitted (but not both). CS# is optional.
191ec8c5 219 for (self.samplenum, pins) in data:
01329e88 220
191ec8c5
UH
221 # Ignore identical samples early on (for performance reasons).
222 if self.oldpins == pins:
223 continue
bcd14870 224 self.oldpins, (clk, miso, mosi, cs) = pins, pins
12549f11
UH
225 self.have_miso = (miso in (0, 1))
226 self.have_mosi = (mosi in (0, 1))
efa64173 227 self.have_cs = (cs in (0, 1))
b1bb5eed 228
191ec8c5
UH
229 # State machine.
230 if self.state == 'IDLE':
bcd14870 231 self.find_clk_edge(miso, mosi, clk, cs)
191ec8c5
UH
232 else:
233 raise Exception('Invalid state: %s' % self.state)
ad2dc0de 234