]> sigrok.org Git - libsigrokdecode.git/blame - decoders/spi/pd.py
spi: Improve probe names/descriptions a bit.
[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 = [
49e8a4d6 67 {'id': 'clk', 'name': 'CLK', 'desc': 'Clock'},
6b5b91d2 68 ]
efa64173 69 optional_probes = [
49e8a4d6
UH
70 {'id': 'miso', 'name': 'MISO', 'desc': 'Master in, slave out'},
71 {'id': 'mosi', 'name': 'MOSI', 'desc': 'Master out, slave in'},
72 {'id': 'cs', 'name': 'CS#', 'desc': 'Chip-select'},
efa64173 73 ]
238b4080 74 options = {
94bbdb9a
UH
75 'cs_polarity': ['CS# polarity', 'active-low'],
76 'cpol': ['Clock polarity', 0],
77 'cpha': ['Clock phase', 0],
78 'bitorder': ['Bit order within the SPI data', 'msb-first'],
c94c8c91 79 'wordsize': ['Word size of SPI data', 8], # 1-64?
3eda7779 80 'format': ['Data format', 'hex'],
238b4080 81 }
b1bb5eed 82 annotations = [
9f2f42c0
UH
83 ['miso-data', 'MISO SPI data'],
84 ['mosi-data', 'MOSI SPI data'],
85 ['warnings', 'Human-readable warnings'],
b1bb5eed 86 ]
06b52ebb
UH
87 annotation_rows = (
88 ('miso', 'MISO', (0,)),
89 ('mosi', 'MOSI', (1,)),
90 ('other', 'Other', (2,)),
91 )
6eb87578 92
3643fc3f 93 def __init__(self):
8a3c8792 94 self.samplerate = None
bcd14870 95 self.oldclk = 1
a10bfc48 96 self.bitcount = 0
4917bb31 97 self.mosidata = 0
d6bace96 98 self.misodata = 0
ec0afe27 99 self.startsample = -1
d6bace96 100 self.samplenum = -1
01329e88 101 self.cs_was_deasserted_during_data_word = 0
3e3c0330 102 self.oldcs = -1
2fcd7c22 103 self.oldpins = None
12549f11
UH
104 self.have_cs = None
105 self.have_miso = None
106 self.have_mosi = None
191ec8c5 107 self.state = 'IDLE'
6eb87578 108
8a3c8792
BV
109 def metadata(self, key, value):
110 if key == srd.SRD_CONF_SAMPLERATE:
111 self.samplerate = value
112
8915b346 113 def start(self):
c515eed7 114 self.out_python = self.register(srd.OUTPUT_PYTHON)
be465111 115 self.out_ann = self.register(srd.OUTPUT_ANN)
8a3c8792
BV
116 self.out_bitrate = self.register(srd.OUTPUT_META,
117 meta=(int, 'Bitrate', 'Bitrate during transfers'))
3643fc3f 118
ec0afe27 119 def putpw(self, data):
c515eed7 120 self.put(self.startsample, self.samplenum, self.out_python, data)
ec0afe27
UH
121
122 def putw(self, data):
123 self.put(self.startsample, self.samplenum, self.out_ann, data)
124
bcd14870 125 def handle_bit(self, miso, mosi, clk, cs):
191ec8c5
UH
126 # If this is the first bit, save its sample number.
127 if self.bitcount == 0:
128 self.startsample = self.samplenum
efa64173
UH
129 if self.have_cs:
130 active_low = (self.options['cs_polarity'] == 'active-low')
131 deasserted = cs if active_low else not cs
132 if deasserted:
133 self.cs_was_deasserted_during_data_word = 1
2fcd7c22 134
191ec8c5 135 ws = self.options['wordsize']
d6bace96 136
191ec8c5 137 # Receive MOSI bit into our shift register.
12549f11
UH
138 if self.have_mosi:
139 if self.options['bitorder'] == 'msb-first':
140 self.mosidata |= mosi << (ws - 1 - self.bitcount)
141 else:
142 self.mosidata |= mosi << self.bitcount
3e3c0330 143
191ec8c5 144 # Receive MISO bit into our shift register.
12549f11
UH
145 if self.have_miso:
146 if self.options['bitorder'] == 'msb-first':
147 self.misodata |= miso << (ws - 1 - self.bitcount)
148 else:
149 self.misodata |= miso << self.bitcount
c94c8c91 150
191ec8c5 151 self.bitcount += 1
1ea831e9 152
191ec8c5
UH
153 # Continue to receive if not enough bits were received, yet.
154 if self.bitcount != ws:
155 return
b1bb5eed 156
12549f11
UH
157 si = self.mosidata if self.have_mosi else None
158 so = self.misodata if self.have_miso else None
8a3c8792 159
12549f11
UH
160 # Pass MOSI and MISO to the next PD up the stack.
161 self.putpw(['DATA', si, so])
b1bb5eed 162
12549f11
UH
163 # Annotations.
164 if self.have_miso:
165 self.putw([0, ['%02X' % self.misodata]])
166 if self.have_mosi:
167 self.putw([1, ['%02X' % self.mosidata]])
168
169 # Meta bitrate.
8a3c8792
BV
170 elapsed = 1 / float(self.samplerate) * (self.samplenum - self.startsample + 1)
171 bitrate = int(1 / elapsed * self.options['wordsize'])
172 self.put(self.startsample, self.samplenum, self.out_bitrate, bitrate)
173
12549f11 174 if self.have_cs and self.cs_was_deasserted_during_data_word:
c1411010 175 self.putw([2, ['CS# was deasserted during this data word!']])
191ec8c5
UH
176
177 # Reset decoder state.
12549f11
UH
178 self.misodata = 0 if self.have_miso else None
179 self.mosidata = 0 if self.have_mosi else None
180 self.bitcount = 0
191ec8c5 181
bcd14870 182 def find_clk_edge(self, miso, mosi, clk, cs):
efa64173 183 if self.have_cs and self.oldcs != cs:
191ec8c5 184 # Send all CS# pin value changes.
c515eed7 185 self.put(self.samplenum, self.samplenum, self.out_python,
191ec8c5
UH
186 ['CS-CHANGE', self.oldcs, cs])
187 self.oldcs = cs
efa64173 188 # Reset decoder state when CS# changes (and the CS# pin is used).
12549f11
UH
189 self.misodata = 0 if self.have_miso else None
190 self.mosidata = 0 if self.have_mosi else None
191 self.bitcount = 0
191ec8c5
UH
192
193 # Ignore sample if the clock pin hasn't changed.
bcd14870 194 if clk == self.oldclk:
191ec8c5 195 return
b1bb5eed 196
bcd14870 197 self.oldclk = clk
b1bb5eed 198
191ec8c5
UH
199 # Sample data on rising/falling clock edge (depends on mode).
200 mode = spi_mode[self.options['cpol'], self.options['cpha']]
bcd14870 201 if mode == 0 and clk == 0: # Sample on rising clock edge
191ec8c5 202 return
bcd14870 203 elif mode == 1 and clk == 1: # Sample on falling clock edge
191ec8c5 204 return
bcd14870 205 elif mode == 2 and clk == 1: # Sample on falling clock edge
191ec8c5 206 return
bcd14870 207 elif mode == 3 and clk == 0: # Sample on rising clock edge
191ec8c5
UH
208 return
209
210 # Found the correct clock edge, now get the SPI bit(s).
bcd14870 211 self.handle_bit(miso, mosi, clk, cs)
191ec8c5
UH
212
213 def decode(self, ss, es, data):
8a3c8792
BV
214 if self.samplerate is None:
215 raise Exception("Cannot decode without samplerate.")
12549f11 216 # Either MISO or MOSI can be omitted (but not both). CS# is optional.
191ec8c5 217 for (self.samplenum, pins) in data:
01329e88 218
191ec8c5
UH
219 # Ignore identical samples early on (for performance reasons).
220 if self.oldpins == pins:
221 continue
bcd14870 222 self.oldpins, (clk, miso, mosi, cs) = pins, pins
12549f11
UH
223 self.have_miso = (miso in (0, 1))
224 self.have_mosi = (mosi in (0, 1))
efa64173 225 self.have_cs = (cs in (0, 1))
b1bb5eed 226
191ec8c5
UH
227 # State machine.
228 if self.state == 'IDLE':
bcd14870 229 self.find_clk_edge(miso, mosi, clk, cs)
191ec8c5
UH
230 else:
231 raise Exception('Invalid state: %s' % self.state)
ad2dc0de 232