Commit 702f8ce4 authored by Timothy Pearson's avatar Timothy Pearson
Browse files

Add basic QSPI support to SPI protocol decoder

parent 1de76d1e
......@@ -4,6 +4,7 @@
## Copyright (C) 2011 Gareth McMullin <gareth@blacksphere.co.nz>
## Copyright (C) 2012-2014 Uwe Hermann <uwe@hermann-uwe.de>
## Copyright (C) 2019 DreamSourceLab <support@dreamsourcelab.com>
## Copyright (C) 2020 Raptor Engineering, LLC <support@raptorengineering.com>
##
## This program is free software; you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
......@@ -88,8 +89,10 @@ class Decoder(srd.Decoder):
{'id': 'clk', 'type': 0, 'name': 'CLK', 'desc': 'Clock'},
)
optional_channels = (
{'id': 'miso', 'type': 107, 'name': 'MISO', 'desc': 'Master in, slave out'},
{'id': 'mosi', 'type': 109, 'name': 'MOSI', 'desc': 'Master out, slave in'},
{'id': 'dq3', 'type': -1, 'name': 'DQ3', 'desc': 'DQ3'},
{'id': 'dq2', 'type': -1, 'name': 'DQ2', 'desc': 'DQ2'},
{'id': 'miso', 'type': 107, 'name': 'MISO', 'desc': 'Master in, slave out / DQ1'},
{'id': 'mosi', 'type': 109, 'name': 'MOSI', 'desc': 'Master out, slave in / DQ0'},
{'id': 'cs', 'type': -1, 'name': 'CS#', 'desc': 'Chip-select'},
)
options = (
......@@ -106,10 +109,14 @@ class Decoder(srd.Decoder):
annotations = (
('106', 'miso-data', 'MISO data'),
('108', 'mosi-data', 'MOSI data'),
('110', 'qspi-data', 'QSPI data'),
('112', 'qspi-byte', 'QSPI byte'),
)
annotation_rows = (
('miso-data', 'MISO data', (0,)),
('mosi-data', 'MOSI data', (1,)),
('qspi-data', 'QSPI data', (2,)),
('qspi-byte', 'QSPI byte', (3,)),
)
def __init__(self):
......@@ -118,14 +125,18 @@ class Decoder(srd.Decoder):
def reset(self):
self.samplerate = None
self.bitcount = 0
self.misodata = self.mosidata = 0
self.nibblecount = 0
self.bytecount_cs_qspi = 0
self.qspidata = self.misodata = self.mosidata = 0
self.misobits = []
self.mosibits = []
self.qspibits = []
self.ss_block = -1
self.qspi_ss_block = -1
self.samplenum = -1
self.ss_transfer = -1
self.cs_was_deasserted = False
self.have_cs = self.have_miso = self.have_mosi = None
self.have_cs = self.have_qspi = self.have_miso = self.have_mosi = None
def start(self):
self.out_ann = self.register(srd.OUTPUT_ANN)
......@@ -154,24 +165,46 @@ class Decoder(srd.Decoder):
if self.have_mosi:
self.put(ss, es, self.out_ann, [1, ['%02X' % self.mosidata]])
def putqspidata(self):
if self.have_qspi:
ss, es = self.qspibits[-1][1], self.qspibits[0][2]
# Dataword annotations.
if self.have_qspi:
self.put(ss, es, self.out_ann, [2, ['%02X' % self.qspidata]])
self.put(ss, es, self.out_ann, [3, ['%d' % self.bytecount_cs_qspi]])
self.bytecount_cs_qspi += 1
def reset_decoder_state(self):
self.misodata = 0 if self.have_miso else None
self.mosidata = 0 if self.have_mosi else None
self.qspidata = 0 if self.have_qspi else None
self.misobits = [] if self.have_miso else None
self.mosibits = [] if self.have_mosi else None
self.qspibits = [] if self.have_qspi else None
self.bitcount = 0
self.nibblecount = 0
def reset_qspi_decoder_state(self):
self.qspidata = 0 if self.have_qspi else None
self.qspibits = [] if self.have_qspi else None
self.nibblecount = 0
def cs_asserted(self, cs):
active_low = (self.options['cs_polarity'] == 'active-low')
return (cs == 0) if active_low else (cs == 1)
def handle_bit(self, miso, mosi, clk, cs):
def handle_bit(self, dq3, dq2, miso, mosi, clk, cs):
# If this is the first bit of a dataword, save its sample number.
if self.bitcount == 0:
self.nibblecount = 0;
self.ss_block = self.samplenum
self.cs_was_deasserted = \
not self.cs_asserted(cs) if self.have_cs else False
if self.nibblecount == 0:
self.qspi_ss_block = self.samplenum
ws = self.options['wordsize']
bo = self.options['bitorder']
......@@ -189,6 +222,15 @@ class Decoder(srd.Decoder):
else:
self.mosidata |= mosi << self.bitcount
if self.have_qspi:
nibble = 0
nibble |= dq3 << 3
nibble |= dq2 << 2
nibble |= miso << 1
nibble |= mosi << 0
self.qspidata = self.qspidata << 4
self.qspidata |= nibble
# Guesstimate the endsample for this bit (can be overridden below).
es = self.samplenum
if self.bitcount > 0:
......@@ -202,27 +244,44 @@ class Decoder(srd.Decoder):
if self.have_mosi:
self.mosibits.insert(0, [mosi, self.samplenum, es])
# Guesstimate the endsample for this word (can be overridden below).
es = self.samplenum
if self.nibblecount > 0:
if self.have_qspi:
es += self.samplenum - self.qspibits[0][1]
if self.have_qspi:
self.qspibits.insert(0, [dq3, self.samplenum, es])
if self.bitcount > 0 and self.have_miso:
self.misobits[1][2] = self.samplenum
if self.bitcount > 0 and self.have_mosi:
self.mosibits[1][2] = self.samplenum
if self.nibblecount > 0 and self.have_qspi:
self.qspibits[1][2] = self.samplenum
self.bitcount += 1
self.nibblecount += 1
if self.nibblecount > 1:
self.putqspidata()
self.reset_qspi_decoder_state()
# Continue to receive if not enough bits were received, yet.
if self.bitcount != ws:
return
self.putdata()
self.reset_decoder_state()
def find_clk_edge(self, miso, mosi, clk, cs, first):
def find_clk_edge(self, dq3, dq2, miso, mosi, clk, cs, first):
if self.have_cs and (first or (self.matched & (0b1 << self.have_cs))):
# Send all CS# pin value changes.
oldcs = None if first else 1 - cs
# Reset decoder state when CS# changes (and the CS# pin is used).
self.bytecount_cs_qspi = 0
self.reset_decoder_state()
# We only care about samples if CS# is asserted.
......@@ -234,7 +293,7 @@ class Decoder(srd.Decoder):
return
# Found the correct clock edge, now get the SPI bit(s).
self.handle_bit(miso, mosi, clk, cs)
self.handle_bit(dq3, dq2, miso, mosi, clk, cs)
def decode(self):
# The CLK input is mandatory. Other signals are (individually)
......@@ -242,11 +301,12 @@ class Decoder(srd.Decoder):
# Tell stacked decoders when we don't have a CS# signal.
if not self.has_channel(0):
raise ChannelError('CLK pin required.')
self.have_miso = self.has_channel(1)
self.have_mosi = self.has_channel(2)
self.have_qspi = self.has_channel(1) and self.has_channel(2)
self.have_miso = self.has_channel(3)
self.have_mosi = self.has_channel(4)
if not self.have_miso and not self.have_mosi:
raise ChannelError('Either MISO or MOSI (or both) pins required.')
self.have_cs = self.has_channel(3)
self.have_cs = self.has_channel(5)
# We want all CLK changes. We want all CS changes if CS is used.
# Map 'have_cs' from boolean to an integer index. This simplifies
......@@ -260,15 +320,15 @@ class Decoder(srd.Decoder):
if self.have_cs:
self.have_cs = len(wait_cond)
wait_cond.append({3: 'e'})
wait_cond.append({5: 'e'})
# "Pixel compatibility" with the v2 implementation. Grab and
# process the very first sample before checking for edges. The
# previous implementation did this by seeding old values with
# None, which led to an immediate "change" in comparison.
(clk, miso, mosi, cs) = self.wait({})
self.find_clk_edge(miso, mosi, clk, cs, True)
(clk, dq3, dq2, miso, mosi, cs) = self.wait({})
self.find_clk_edge(dq3, dq2, miso, mosi, clk, cs, True)
while True:
(clk, miso, mosi, cs) = self.wait(wait_cond)
self.find_clk_edge(miso, mosi, clk, cs, False)
(clk, dq3, dq2, miso, mosi, cs) = self.wait(wait_cond)
self.find_clk_edge(dq3, dq2, miso, mosi, clk, cs, False)
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment