Skip to content

Commit 16deb5c

Browse files
Fixes, tweaks, and clarifications.
1 parent 47d738f commit 16deb5c

1 file changed

Lines changed: 103 additions & 37 deletions

File tree

can/bit_timing.py

Lines changed: 103 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,111 +1,177 @@
1+
class BitTiming:
2+
"""Representation of a bit timing configuration.
3+
4+
The class can be constructed in various ways, depending on the information
5+
available or the capabilities of the interfaces that need to be supported.
16
7+
The preferred way is using bitrate, CAN clock frequency, TSEG1, TSEG2, SJW::
28
3-
class BitTiming:
9+
can.BitTiming(bitrate=1000000, f_clock=8000000, tseg1=5, tseg2=1, sjw=1)
10+
11+
If the clock frequency is unknown it may be omitted but some interfaces may
12+
require it.
13+
14+
Alternatively the BRP can be given instead of bitrate and clock frequency but this
15+
will limit the number of supported interfaces.
16+
17+
It is also possible specify BTR registers directly,
18+
but will not work for all interfaces::
19+
20+
can.BitTiming(btr0=0x00, btr1=0x14)
21+
"""
422

5-
# Is this always 1?
623
sync_seg = 1
724

825
def __init__(
926
self,
1027
bitrate=None,
28+
f_clock=None,
1129
brp=None,
12-
sjw=None,
1330
tseg1=None,
1431
tseg2=None,
32+
sjw=None,
1533
nof_samples=1,
16-
f_clock=None,
1734
btr0=None,
18-
btr1=None
35+
btr1=None,
1936
):
20-
if brp is not None and (brp < 1 or brp > 64):
21-
raise ValueError("brp must be 1 - 64")
22-
if sjw is not None and (sjw < 1 or sjw > 4):
23-
raise ValueError("sjw must be 1 - 4")
24-
if tseg1 is not None and (tseg1 < 1 or tseg1 > 16):
25-
raise ValueError("tseg1 must be 1 - 16")
26-
if tseg2 is not None and (tseg2 < 1 or tseg2 > 8):
27-
raise ValueError("tseg2 must be 1 - 8")
28-
if nof_samples is not None and nof_samples not in (1, 3):
29-
raise ValueError("nof_samples must be 1 or 3")
30-
if btr0 is not None and (btr0 < 0 or btr0 > 255):
31-
raise ValueError("btr0 must be 0 - 255")
32-
if btr1 is not None and (btr1 < 0 or btr1 > 255):
33-
raise ValueError("btr1 must be 0 - 255")
34-
37+
"""
38+
:param int bitrate:
39+
Bitrate in bits/s.
40+
:param int f_clock:
41+
The CAN system clock frequency in Hz.
42+
Usually the oscillator frequency divided by 2.
43+
:param int brp:
44+
Bit Rate Prescaler. Prefer to use bitrate and f_clock instead.
45+
:param int tseg1:
46+
Time segment 1, that is, the number of quanta from (but not including)
47+
the Sync Segment to the sampling point.
48+
:param int tseg2:
49+
Time segment 2, that is, the number of quanta from the sampling
50+
point to the end of the bit.
51+
:param int sjw:
52+
The Synchronization Jump Width. Decides the maximum number of time quanta
53+
that the controller can resynchronize every bit.
54+
:param int nof_samples:
55+
Either 1 or 3. Some CAN controllers can also sample each bit three times.
56+
In this case, the bit will be sampled three quanta in a row,
57+
with the last sample being taken in the edge between TSEG1 and TSEG2.
58+
Three samples should only be used for relatively slow baudrates.
59+
:param int btr0:
60+
The BTR0 register value used by many CAN controllers.
61+
:param int btr1:
62+
The BTR1 register value used by many CAN controllers.
63+
"""
3564
self._bitrate = bitrate
3665
self._brp = brp
3766
self._sjw = sjw
3867
self._tseg1 = tseg1
3968
self._tseg2 = tseg2
4069
self._nof_samples = nof_samples
4170
self._f_clock = f_clock
42-
self._btr0 = btr0
43-
self._btr1 = btr1
71+
72+
if btr0 is not None:
73+
self._brp = (btr0 & 0x3F) + 1
74+
self._sjw = (btr0 >> 6) + 1
75+
if btr1 is not None:
76+
self._tseg1 = (btr1 & 0xF) + 1
77+
self._tseg2 = ((btr1 >> 4) & 0x7) + 1
78+
self._nof_samples = 3 if btr1 & 0x80 else 1
4479

4580
@property
4681
def nbt(self):
82+
"""Nominal Bit Time."""
4783
return self.sync_seg + self.tseg1 + self.tseg2
4884

4985
@property
5086
def bitrate(self):
87+
"""Bitrate in bits/s."""
5188
if self._bitrate:
5289
return self._bitrate
90+
if self._f_clock and self._brp:
91+
return self._f_clock / (self._brp * self.nbt)
5392
raise ValueError("bitrate must be specified")
5493

5594
@property
5695
def brp(self):
96+
"""Bit Rate Prescaler."""
5797
if self._brp:
5898
return self._brp
59-
return round(self.f_clock / (2 * self.bitrate * self.nbt))
99+
if self._f_clock and self._bitrate:
100+
return round(self._f_clock / (self._bitrate * self.nbt))
101+
raise ValueError("Either bitrate and f_clock or brp must be specified")
60102

61103
@property
62104
def sjw(self):
105+
"""Synchronization Jump Width."""
63106
if not self._sjw:
64107
raise ValueError("sjw must be specified")
65108
return self._sjw
66109

67110
@property
68111
def tseg1(self):
112+
"""Time segment 1.
113+
114+
The number of quanta from (but not including) the Sync Segment to the sampling point.
115+
"""
69116
if not self._tseg1:
70117
raise ValueError("tseg1 must be specified")
71118
return self._tseg1
72119

73120
@property
74121
def tseg2(self):
122+
"""Time segment 2.
123+
124+
The number of quanta from the sampling point to the end of the bit.
125+
"""
75126
if not self._tseg2:
76127
raise ValueError("tseg2 must be specified")
77128
return self._tseg2
78129

79130
@property
80131
def nof_samples(self):
132+
"""Number of samples (1 or 3)."""
81133
if not self._nof_samples:
82134
raise ValueError("nof_samples must be specified")
83135
return self._nof_samples
84136

85137
@property
86138
def f_clock(self):
139+
"""The CAN system clock frequency in Hz.
140+
141+
Usually the oscillator frequency divided by 2.
142+
"""
87143
if not self._f_clock:
88144
raise ValueError("f_clock must be specified")
89145
return self._f_clock
90146

147+
@property
148+
def sample_point(self):
149+
"""Sample point in percent."""
150+
return 100.0 * (self.nbt - self.tseg2) / self.nbt
151+
91152
@property
92153
def btr0(self):
93-
if self._btr0 is not None:
94-
return self._btr0
95-
btr0 = (self.sjw - 1) << 5
96-
btr0 |= self.brp - 1
97-
return btr0
154+
sjw = self.sjw
155+
brp = self.brp
156+
157+
if brp < 1 or brp > 64:
158+
raise ValueError("brp must be 1 - 64")
159+
if sjw < 1 or sjw > 4:
160+
raise ValueError("sjw must be 1 - 4")
161+
162+
return (sjw - 1) << 6 | brp - 1
98163

99164
@property
100165
def btr1(self):
101-
if self._btr1 is not None:
102-
return self._btr1
103166
sam = 1 if self.nof_samples == 3 else 0
104-
btr1 = sam << 7
105-
btr1 |= (self.tseg2 - 1) << 4
106-
btr1 |= self.tseg1 - 1
107-
return btr1
167+
tseg1 = self.tseg1
168+
tseg2 = self.tseg2
108169

109-
@property
110-
def btr(self):
111-
return self.btr0 << 8 | self.btr1
170+
if tseg1 < 1 or tseg1 > 16:
171+
raise ValueError("tseg1 must be 1 - 16")
172+
if tseg2 < 1 or tseg2 > 8:
173+
raise ValueError("tseg2 must be 1 - 8")
174+
if nof_samples not in (1, 3):
175+
raise ValueError("nof_samples must be 1 or 3")
176+
177+
return sam << 7 | (tseg2 - 1) << 4 | tseg1 - 1

0 commit comments

Comments
 (0)