Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Open sidebar
Raptor Engineering Public Development
dsview
Commits
f17c612c
Unverified
Commit
f17c612c
authored
6 years ago
by
DreamSourceLab
Committed by
GitHub
6 years ago
Browse files
Options
Download
Plain Diff
Merge pull request #148 from mjagdis/swim-decoder
Decoder for STM8 series MCUs SWIM protocol.
parents
da9e26f3
9bff1aa9
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
375 additions
and
0 deletions
+375
-0
libsigrokdecode4DSL/decoders/swim/__init__.py
libsigrokdecode4DSL/decoders/swim/__init__.py
+29
-0
libsigrokdecode4DSL/decoders/swim/pd.py
libsigrokdecode4DSL/decoders/swim/pd.py
+346
-0
No files found.
libsigrokdecode4DSL/decoders/swim/__init__.py
0 → 100755
View file @
f17c612c
##
## This file is part of the libsigrokdecode project.
##
## Copyright (C) 2018 Mike Jagdis <mjagdis@eris-associates.co.uk>
##
## 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
## the Free Software Foundation; either version 2 of the License, or
## (at your option) any later version.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with this program; if not, write to the Free Software
## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
##
'''
SWIM is a single wire interface for STM8 series 8-bit microcontrollers
that allows non-intrusive read/wite access to be performed on-the-fly
to the memory and registers of the MCU for debug and flashing purposes.
See the STMicroelectronics document UM0470 for details.
'''
from
.pd
import
Decoder
This diff is collapsed.
Click to expand it.
libsigrokdecode4DSL/decoders/swim/pd.py
0 → 100755
View file @
f17c612c
#
## This file is part of the libsigrokdecode project.
##
## Copyright (C) 2018 Mike Jagdis <mjagdis@eris-associates.co.uk>
##
## 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
## the Free Software Foundation; either version 2 of the License, or
## (at your option) any later version.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with this program; if not, write to the Free Software
## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
##
import
math
import
sigrokdecode
as
srd
class
SamplerateError
(
Exception
):
pass
class
Decoder
(
srd
.
Decoder
):
api_version
=
2
id
=
'swim'
name
=
'SWIM'
longname
=
'STM8 SWIM bus'
desc
=
'STM8 Single Wire Interface Module (SWIM).'
license
=
'gplv3+'
inputs
=
[
'logic'
]
outputs
=
[]
options
=
(
{
'id'
:
'debug'
,
'desc'
:
'Debug'
,
'default'
:
'no'
,
'values'
:
(
'yes'
,
'no'
)
},
)
channels
=
(
{
'id'
:
'swim'
,
'name'
:
'SWIM'
,
'desc'
:
'SWIM data line'
},
)
annotations
=
(
(
'108'
,
'bit'
,
'Bit'
),
(
'7'
,
'enterseq'
,
'SWIM enter sequence'
),
(
'111'
,
'start-host'
,
'Start bit (host)'
),
(
'112'
,
'start-target'
,
'Start bit (target)'
),
(
'6'
,
'parity'
,
'Parity bit'
),
(
'6'
,
'ack'
,
'Acknowledgement'
),
(
'0'
,
'nack'
,
'Negative acknowledgement'
),
(
'111'
,
'byte-write'
,
'Byte write'
),
(
'112'
,
'byte-read'
,
'Byte read'
),
(
'0'
,
'cmd-unknown'
,
'Unknown SWIM command'
),
(
'11'
,
'cmd'
,
'SWIM command'
),
(
'111'
,
'bytes'
,
'Byte count'
),
(
'111'
,
'address'
,
'Address'
),
(
'111'
,
'data-write'
,
'Data write'
),
(
'112'
,
'data-read'
,
'Data read'
),
(
'208'
,
'debug'
,
'Debug'
),
)
annotation_rows
=
(
(
'bits'
,
'Bits'
,
(
0
,)),
(
'framing'
,
'Framing'
,
(
2
,
3
,
4
,
5
,
6
,
7
,
8
,)),
(
'protocol'
,
'Protocol'
,
(
1
,
9
,
10
,
11
,
12
,
13
,
14
,)),
(
'debug'
,
'Debug'
,
(
15
,)),
)
binary
=
(
(
'tx'
,
'Dump of data written to target'
),
(
'rx'
,
'Dump of data read from target'
),
)
def
__init__
(
self
):
# SWIM clock for the target is normally HSI/2 where HSI is 8MHz +- 5% although the
# divisor can be removed by setting the SWIMCLK bit in the CLK_SWIMCCR register.
# There is no standard for the host so we will be generous and assume it is using
# an 8MHz +- 10% oscillator. We do not need to be accurate. We just need to avoid
# treating enter sequence pulses as bits. A synchronization frame will cause this
# to be adjusted.
self
.
HSI
=
8000000
self
.
HSI_min
=
self
.
HSI
*
0.9
self
.
HSI_max
=
self
.
HSI
*
1.1
self
.
swim_clock
=
self
.
HSI_min
/
2
self
.
eseq_edge
=
[[
-
1
,
None
],
[
-
1
,
None
]]
self
.
eseq_pairnum
=
0
self
.
eseq_pairstart
=
None
self
.
reset
()
def
reset
(
self
):
self
.
bit_edge
=
[[
-
1
,
None
],
[
-
1
,
None
]]
self
.
bit_maxlen
=
-
1
self
.
bitseq_len
=
0
self
.
bitseq_end
=
None
self
.
proto_state
=
'CMD'
def
metadata
(
self
,
key
,
value
):
if
key
==
srd
.
SRD_CONF_SAMPLERATE
:
self
.
samplerate
=
value
def
adjust_timings
(
self
):
# A low-speed bit is 22 SWIM clocks long.
# There are options to shorten bits to 10 clocks or use HSI rather than HSI/2 as
# the SWIM clock but the longest valid bit should be no more than this many samples.
# This does not need to be accurate. It exists simply to prevent bits extending
# unecessarily far into trailing bus-idle periods. This will be adjusted every
# time we see a synchronization frame or start bit in order to show idle periods
# as accurately as possible.
self
.
bit_reflen
=
math
.
ceil
(
self
.
samplerate
*
22
/
self
.
swim_clock
)
def
start
(
self
):
self
.
out_ann
=
self
.
register
(
srd
.
OUTPUT_ANN
)
self
.
out_binary
=
self
.
register
(
srd
.
OUTPUT_BINARY
)
if
not
self
.
samplerate
:
raise
SamplerateError
(
'Cannot decode without samplerate.'
)
# A synchronization frame is a low that lasts for more than 64 but no more than
# 128 SWIM clock periods based on the standard SWIM clock.
# Note: we also allow for the possibility that the SWIM clock divisor has been
# disabled here.
self
.
sync_reflen_min
=
math
.
floor
(
self
.
samplerate
*
64
/
self
.
HSI_max
)
self
.
sync_reflen_max
=
math
.
ceil
(
self
.
samplerate
*
128
/
(
self
.
HSI_min
/
2
))
if
self
.
options
[
'debug'
]
==
'yes'
:
self
.
debug
=
True
else
:
self
.
debug
=
False
# The SWIM entry sequence is four pulses at 2kHz followed by four at 1kHz.
self
.
eseq_reflen
=
math
.
ceil
(
self
.
samplerate
/
2048
)
self
.
adjust_timings
()
def
protocol
(
self
):
if
self
.
proto_state
==
'CMD'
:
# Command
if
self
.
bitseq_value
==
0x00
:
self
.
put
(
self
.
bitseq_start
,
self
.
bitseq_end
,
self
.
out_ann
,
[
10
,
[
'system reset'
,
'SRST'
,
'!'
]])
elif
self
.
bitseq_value
==
0x01
:
self
.
proto_state
=
'N'
self
.
put
(
self
.
bitseq_start
,
self
.
bitseq_end
,
self
.
out_ann
,
[
10
,
[
'read on-the-fly'
,
'ROTF'
,
'r'
]])
elif
self
.
bitseq_value
==
0x02
:
self
.
proto_state
=
'N'
self
.
put
(
self
.
bitseq_start
,
self
.
bitseq_end
,
self
.
out_ann
,
[
10
,
[
'write on-the-fly'
,
'WOTF'
,
'w'
]])
else
:
self
.
put
(
self
.
bitseq_start
,
self
.
bitseq_end
,
self
.
out_ann
,
[
9
,
[
'unknown'
,
'UNK'
]])
elif
self
.
proto_state
==
'N'
:
# Number of bytes
self
.
proto_byte_count
=
self
.
bitseq_value
self
.
proto_state
=
'@E'
self
.
put
(
self
.
bitseq_start
,
self
.
bitseq_end
,
self
.
out_ann
,
[
11
,
[
'byte count 0x%02x'
%
self
.
bitseq_value
,
'bytes 0x%02x'
%
self
.
bitseq_value
,
'0x%02x'
%
self
.
bitseq_value
,
'%02x'
%
self
.
bitseq_value
,
'%x'
%
self
.
bitseq_value
]])
elif
self
.
proto_state
==
'@E'
:
# Address byte 1
self
.
proto_addr
=
self
.
bitseq_value
self
.
proto_addr_start
=
self
.
bitseq_start
self
.
proto_state
=
'@H'
elif
self
.
proto_state
==
'@H'
:
# Address byte 2
self
.
proto_addr
=
(
self
.
proto_addr
<<
8
)
|
self
.
bitseq_value
self
.
proto_state
=
'@L'
elif
self
.
proto_state
==
'@L'
:
# Address byte 3
self
.
proto_addr
=
(
self
.
proto_addr
<<
8
)
|
self
.
bitseq_value
self
.
proto_state
=
'D'
self
.
put
(
self
.
proto_addr_start
,
self
.
bitseq_end
,
self
.
out_ann
,
[
12
,
[
'address 0x%06x'
%
self
.
proto_addr
,
'addr 0x%06x'
%
self
.
proto_addr
,
'0x%06x'
%
self
.
proto_addr
,
'%06x'
%
self
.
proto_addr
,
'%x'
%
self
.
proto_addr
]])
else
:
if
self
.
proto_byte_count
>
0
:
self
.
proto_byte_count
-=
1
if
self
.
proto_byte_count
==
0
:
self
.
proto_state
=
'CMD'
self
.
put
(
self
.
bitseq_start
,
self
.
bitseq_end
,
self
.
out_ann
,
[
13
+
self
.
bitseq_dir
,
[
'0x%02x'
%
self
.
bitseq_value
,
'%02x'
%
self
.
bitseq_value
,
'%x'
%
self
.
bitseq_value
]])
self
.
put
(
self
.
bitseq_start
,
self
.
bitseq_end
,
self
.
out_binary
,
[
0
+
self
.
bitseq_dir
,
bytes
([
self
.
bitseq_value
])
])
if
self
.
debug
:
self
.
put
(
self
.
bitseq_start
,
self
.
bitseq_end
,
self
.
out_ann
,
[
15
,
[
'%d more'
%
self
.
proto_byte_count
,
'%d'
%
self
.
proto_byte_count
]])
def
bitseq
(
self
,
bitstart
,
bitend
,
bit
):
if
self
.
bitseq_len
==
0
:
# Looking for start of a bit sequence (command or byte).
self
.
bit_reflen
=
bitend
-
bitstart
self
.
bitseq_value
=
0
self
.
bitseq_dir
=
bit
self
.
bitseq_len
=
1
self
.
put
(
bitstart
,
bitend
,
self
.
out_ann
,
[
2
+
self
.
bitseq_dir
,
[
'start'
,
's'
]])
elif
(
self
.
proto_state
==
'CMD'
and
self
.
bitseq_len
==
4
)
or
(
self
.
proto_state
!=
'CMD'
and
self
.
bitseq_len
==
9
):
# Parity bit
self
.
bitseq_end
=
bitstart
self
.
bitseq_len
+=
1
self
.
put
(
bitstart
,
bitend
,
self
.
out_ann
,
[
4
,
[
'parity'
,
'par'
,
'p'
]])
# The start bit is not data but was used for parity calculation.
self
.
bitseq_value
&=
0xff
self
.
put
(
self
.
bitseq_start
,
self
.
bitseq_end
,
self
.
out_ann
,
[
7
+
self
.
bitseq_dir
,
[
'0x%02x'
%
self
.
bitseq_value
,
'%02x'
%
self
.
bitseq_value
,
'%x'
%
self
.
bitseq_value
]])
elif
(
self
.
proto_state
==
'CMD'
and
self
.
bitseq_len
==
5
)
or
(
self
.
proto_state
!=
'CMD'
and
self
.
bitseq_len
==
10
):
# ACK/NACK bit.
if
bit
:
self
.
put
(
bitstart
,
bitend
,
self
.
out_ann
,
[
5
,
[
'ack'
,
'a'
]])
else
:
self
.
put
(
bitstart
,
bitend
,
self
.
out_ann
,
[
6
,
[
'nack'
,
'n'
]])
# We only pass data that was ack'd up the stack.
if
bit
:
self
.
protocol
()
self
.
bitseq_len
=
0
else
:
if
self
.
bitseq_len
==
1
:
self
.
bitseq_start
=
bitstart
self
.
bitseq_value
=
(
self
.
bitseq_value
<<
1
)
|
bit
self
.
bitseq_len
+=
1
def
bit
(
self
,
start
,
mid
,
end
):
if
mid
-
start
>=
end
-
mid
:
self
.
put
(
start
,
end
,
self
.
out_ann
,
[
0
,
[
'0'
]])
bit
=
0
else
:
self
.
put
(
start
,
end
,
self
.
out_ann
,
[
0
,
[
'1'
]])
bit
=
1
self
.
bitseq
(
start
,
end
,
bit
)
def
detect_synchronize_frame
(
self
,
start
,
end
):
# Strictly speaking, synchronization frames are only recognised when SWIM is
# active. A falling edge on reset disables SWIM and an enter sequence is needed
# to re-enable it. However we do not want to be reliant on seeing the NRST pin
# just for that and we also want to be able to decode SWIM even if we just sample
# parts of the dialogue. For this reason we limit ourselves to only recognizing
# synchronization frames that have believable lengths based on our knowledge
# of the range of possible SWIM clocks.
if
self
.
samplenum
-
self
.
eseq_edge
[
1
][
1
]
>=
self
.
sync_reflen_min
and
self
.
samplenum
-
self
.
eseq_edge
[
1
][
1
]
<=
self
.
sync_reflen_max
:
self
.
put
(
self
.
eseq_edge
[
1
][
1
],
self
.
samplenum
,
self
.
out_ann
,
[
1
,
[
'synchronization frame'
,
'synchronization'
,
'sync'
,
's'
,
]])
# A low that lasts for more than 64 SWIM clock periods causes a reset of the SWIM
# communication state machine and will switch the SWIM to low-speed mode (SWIM_CSR.HS
# is cleared)
self
.
reset
()
# The low SHOULD last 128 SWIM clocks. This is used to resynchronize in order to
# allow for variation in the frequency of the internal RC oscillator.
self
.
swim_clock
=
128
*
(
self
.
samplerate
/
(
self
.
samplenum
-
self
.
eseq_edge
[
1
][
1
]))
self
.
adjust_timings
()
def
eseq_potential_start
(
self
,
start
,
end
):
self
.
eseq_pairstart
=
start
self
.
eseq_reflen
=
end
-
start
self
.
eseq_pairnum
=
1
def
detect_enter_sequence
(
self
,
start
,
end
):
# According to the spec the enter sequence is four pulses at 2kHz followed by
# four at 1kHz. We do not check the frequency but simply check the lengths
# of successive pulses against the first. This means we have no need to account
# for the accuracy (or lack of) of the host's oscillator.
if
self
.
eseq_pairnum
==
0
or
abs
(
self
.
eseq_reflen
-
(
end
-
start
))
>
2
:
self
.
eseq_potential_start
(
start
,
end
)
elif
self
.
eseq_pairnum
<
4
:
# The next three pulses should be the same length as the first.
self
.
eseq_pairnum
+=
1
if
self
.
eseq_pairnum
==
4
:
self
.
eseq_reflen
/=
2
else
:
# The final four pulses should each be half the length of the initial
# pair. Again, a mismatch causes us to reset and use the current pulse
# as a new potential enter sequence start.
self
.
eseq_pairnum
+=
1
if
self
.
eseq_pairnum
==
8
:
# Four matching pulses followed by four more that match each other
# but are half the length of the first four. SWIM is active!
self
.
put
(
self
.
eseq_pairstart
,
end
,
self
.
out_ann
,
[
1
,
[
'enter sequence'
,
'enter seq'
,
'enter'
,
'ent'
,
'e'
]])
self
.
eseq_pairnum
=
0
def
decode
(
self
,
ss
,
es
,
data
):
for
(
self
.
samplenum
,
pins
)
in
data
:
(
swim
,)
=
pins
if
self
.
bit_maxlen
>=
0
:
self
.
bit_maxlen
-=
1
if
swim
!=
self
.
eseq_edge
[
1
][
0
]:
if
swim
==
1
and
self
.
eseq_edge
[
1
][
1
]
is
not
None
:
self
.
detect_synchronize_frame
(
self
.
eseq_edge
[
1
][
1
],
self
.
samplenum
)
if
self
.
eseq_edge
[
0
][
1
]
is
not
None
:
self
.
detect_enter_sequence
(
self
.
eseq_edge
[
0
][
1
],
self
.
samplenum
)
self
.
eseq_edge
.
pop
(
0
)
self
.
eseq_edge
.
append
([
swim
,
self
.
samplenum
])
if
(
swim
!=
self
.
bit_edge
[
1
][
0
]
and
(
swim
!=
1
or
self
.
bit_edge
[
1
][
0
]
!=
-
1
))
or
self
.
bit_maxlen
==
0
:
if
self
.
bit_maxlen
==
0
and
self
.
bit_edge
[
1
][
0
]
==
1
:
swim
=
-
1
if
self
.
bit_edge
[
1
][
0
]
!=
0
and
swim
==
0
:
self
.
bit_maxlen
=
self
.
bit_reflen
if
self
.
bit_edge
[
0
][
0
]
==
0
and
self
.
bit_edge
[
1
][
0
]
==
1
and
self
.
samplenum
-
self
.
bit_edge
[
0
][
1
]
<=
self
.
bit_reflen
+
2
:
self
.
bit
(
self
.
bit_edge
[
0
][
1
],
self
.
bit_edge
[
1
][
1
],
self
.
samplenum
)
self
.
bit_edge
.
pop
(
0
)
self
.
bit_edge
.
append
([
swim
,
self
.
samplenum
])
if
self
.
bit_maxlen
>=
0
:
data
.
logic_mask
=
0
data
.
edge_index
=
0
data
.
itercnt
+=
1
else
:
data
.
exp_logic
=
0b1
data
.
logic_mask
=
0b1
data
.
edge_index
=
-
1
data
.
cur_pos
=
self
.
samplenum
This diff is collapsed.
Click to expand it.
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment