|
4 | 4 |
|
5 | 5 |
|
6 | 6 | class BitTiming(Mapping):
|
7 |
| - """Representation of a bit timing configuration. |
| 7 | + """Representation of a bit timing configuration for a CAN 2.0 bus. |
8 | 8 |
|
9 |
| - The class can be constructed in various ways, depending on the information |
10 |
| - available or the capabilities of the interfaces that need to be supported. |
11 |
| -
|
12 |
| - The preferred way is using bitrate, CAN clock frequency, TSEG1, TSEG2, SJW:: |
| 9 | + The class can be constructed in multiple ways, depending on the information |
| 10 | + available. The preferred way is using bitrate, CAN clock frequency, tseg1, tseg2 and sjw:: |
13 | 11 |
|
14 | 12 | can.BitTiming(bitrate=1_000_000, f_clock=8_000_000, tseg1=5, tseg2=1, sjw=1)
|
15 | 13 |
|
16 |
| - It is also possible specify BTR registers directly:: |
| 14 | + It is also possible to specify BTR registers:: |
17 | 15 |
|
18 | 16 | can.BitTiming.from_registers(f_clock=8_000_000, btr0=0x00, btr1=0x14)
|
| 17 | +
|
| 18 | + or to calculate the timings for a given sample point:: |
| 19 | +
|
| 20 | + can.BitTiming.from_sample_point(f_clock=16_000_000, bitrate=500_000, sample_point=81.25) |
19 | 21 | """
|
20 | 22 |
|
21 | 23 | def __init__(
|
@@ -305,6 +307,35 @@ def __iter__(self) -> Iterator[str]:
|
305 | 307 |
|
306 | 308 |
|
307 | 309 | class BitTimingFd(Mapping):
|
| 310 | + """Representation of a bit timing configuration for a CAN FD bus. |
| 311 | +
|
| 312 | + The class can be constructed in multiple ways, depending on the information |
| 313 | + available. The preferred way is using bitrate, CAN clock frequency, tseg1, tseg2 and sjw |
| 314 | + for both the arbitration (nominal) and data phase:: |
| 315 | +
|
| 316 | + can.BitTimingFd( |
| 317 | + f_clock=80_000_000, |
| 318 | + nom_bitrate=1_000_000, |
| 319 | + nom_tseg1=59, |
| 320 | + nom_tseg2=20, |
| 321 | + nom_sjw=10, |
| 322 | + data_bitrate=8_000_000, |
| 323 | + data_tseg1=6, |
| 324 | + data_tseg2=3, |
| 325 | + data_sjw=2, |
| 326 | + ) |
| 327 | +
|
| 328 | + or to calculate the timings for a given pair of arbitration and data sample points:: |
| 329 | +
|
| 330 | + can.BitTimingFd.from_sample_point( |
| 331 | + f_clock=80_000_000, |
| 332 | + nom_bitrate=1_000_000, |
| 333 | + nom_sample_point=75.0, |
| 334 | + data_bitrate=8_000_000, |
| 335 | + data_sample_point=70.0, |
| 336 | + ) |
| 337 | + """ |
| 338 | + |
308 | 339 | def __init__(
|
309 | 340 | self,
|
310 | 341 | f_clock: int,
|
@@ -416,6 +447,20 @@ def from_sample_point(
|
416 | 447 | data_bitrate: int,
|
417 | 448 | data_sample_point: float,
|
418 | 449 | ) -> "BitTimingFd":
|
| 450 | + """Create a BitTimingFd instance for a given nominal/data sample point pair. |
| 451 | +
|
| 452 | + :param int f_clock: |
| 453 | + The CAN system clock frequency in Hz. |
| 454 | + Usually the oscillator frequency divided by 2. |
| 455 | + :param int nom_bitrate: |
| 456 | + Nominal bitrate in bit/s. |
| 457 | + :param int nom_sample_point: |
| 458 | + The sample point value of the arbitration phase in percent. |
| 459 | + :param int data_bitrate: |
| 460 | + Data bitrate in bit/s. |
| 461 | + :param int data_sample_point: |
| 462 | + The sample point value of the data phase in percent. |
| 463 | + """ |
419 | 464 | if nom_sample_point < 50.0:
|
420 | 465 | raise ValueError(
|
421 | 466 | f"nom_sample_point (={nom_sample_point}) must not be below 50%."
|
@@ -499,58 +544,84 @@ def from_sample_point(
|
499 | 544 |
|
500 | 545 | @property
|
501 | 546 | def nom_bitrate(self) -> int:
|
| 547 | + """Nominal (arbitration phase) bitrate.""" |
502 | 548 | return self["nom_bitrate"]
|
503 | 549 |
|
504 | 550 | @property
|
505 | 551 | def nom_brp(self) -> int:
|
| 552 | + """Prescaler value for the arbitration phase.""" |
506 | 553 | return int(round(self.f_clock / (self.nom_bitrate * self.nbt)))
|
507 | 554 |
|
508 | 555 | @property
|
509 | 556 | def nbt(self) -> int:
|
| 557 | + """Number of time quanta in a bit of the arbitration phase.""" |
510 | 558 | return 1 + self.nom_tseg1 + self.nom_tseg2
|
511 | 559 |
|
512 | 560 | @property
|
513 | 561 | def nom_tseg1(self) -> int:
|
| 562 | + """Time segment 1 value of the arbitration phase. |
| 563 | +
|
| 564 | + This is the sum of the propagation time segment and the phase buffer segment 1. |
| 565 | + """ |
514 | 566 | return self["nom_tseg1"]
|
515 | 567 |
|
516 | 568 | @property
|
517 | 569 | def nom_tseg2(self) -> int:
|
| 570 | + """Time segment 2 value of the arbitration phase. Also known as phase buffer segment 2.""" |
518 | 571 | return self["nom_tseg2"]
|
519 | 572 |
|
520 | 573 | @property
|
521 | 574 | def nom_sjw(self) -> int:
|
| 575 | + """Synchronization jump width of the arbitration phase. |
| 576 | +
|
| 577 | + The phase buffer segments may be shortened or lengthened by this value. |
| 578 | + """ |
522 | 579 | return self["nom_sjw"]
|
523 | 580 |
|
524 | 581 | @property
|
525 | 582 | def nom_sample_point(self) -> float:
|
| 583 | + """Sample point of the arbitration phase in percent.""" |
526 | 584 | return 100.0 * (1 + self.nom_tseg1) / (1 + self.nom_tseg1 + self.nom_tseg2)
|
527 | 585 |
|
528 | 586 | @property
|
529 | 587 | def data_bitrate(self) -> int:
|
| 588 | + """Bitrate of the data phase in bit/s.""" |
530 | 589 | return self["data_bitrate"]
|
531 | 590 |
|
532 | 591 | @property
|
533 | 592 | def data_brp(self) -> int:
|
| 593 | + """Prescaler value for the data phase.""" |
534 | 594 | return int(round(self.f_clock / (self.data_bitrate * self.dbt)))
|
535 | 595 |
|
536 | 596 | @property
|
537 | 597 | def dbt(self) -> int:
|
| 598 | + """Number of time quanta in a bit of the data phase.""" |
538 | 599 | return 1 + self.data_tseg1 + self.data_tseg2
|
539 | 600 |
|
540 | 601 | @property
|
541 | 602 | def data_tseg1(self) -> int:
|
| 603 | + """TSEG1 value of the data phase. |
| 604 | +
|
| 605 | + This is the sum of the propagation time segment and the phase buffer segment 1. |
| 606 | + """ |
542 | 607 | return self["data_tseg1"]
|
543 | 608 |
|
544 | 609 | @property
|
545 | 610 | def data_tseg2(self) -> int:
|
| 611 | + """TSEG2 value of the data phase. Also known as phase buffer segment 2.""" |
546 | 612 | return self["data_tseg2"]
|
547 | 613 |
|
548 | 614 | @property
|
549 | 615 | def data_sjw(self) -> int:
|
| 616 | + """Synchronization jump width of the data phase. |
| 617 | +
|
| 618 | + The phase buffer segments may be shortened or lengthened by this value. |
| 619 | + """ |
550 | 620 | return self["data_sjw"]
|
551 | 621 |
|
552 | 622 | @property
|
553 | 623 | def data_sample_point(self) -> float:
|
| 624 | + """Sample point of the data phase in percent.""" |
554 | 625 | return 100.0 * (1 + self.data_tseg1) / (1 + self.data_tseg1 + self.data_tseg2)
|
555 | 626 |
|
556 | 627 | @property
|
|
0 commit comments