hardbyte / hardbyte/python-can

`BitTiming.from_sample_point` rejects valid timing solutions due to hardcoded register limits

Đang mở
#2,083 0 bình luận 0 reaction 0 người được giao Xem trên GitHub
bug
Ngôn ngữ chính
Python
Star
1.6k
Fork
697
Chỉ số merge pull request
Không có pull request nào được merge trong 30 ngày

Mô tả

## Description

`BitTiming.from_sample_point` cannot find valid bit timings for some clock/bitrate combinations. The method calls `iterate_from_sample_point`, which constructs each `BitTiming` with `strict=True`. This parameter cannot be changed by the caller.

The `_validate` method enforces hardcoded register limits:

- `tseg1` ≤ 16
- `tseg2` ≤ 8
- `brp` ≤ 64

The strict mode tightens `brp` further to 32. These limits follow the CAN 2.0 minimum register specification. Many modern controllers support larger register ranges.

When a clock/bitrate combination produces timing values that all exceed at least one of these limits, the solver rejects every solution and raises `ValueError`.

## Example

STM32G431 with candlelight v2.5 firmware from https://github.com/Elmue/CANable-2.5-firmware-Slcan-and-Candlelight has a 160 MHz CAN clock. The FDCAN peripheral supports `brp` up to 512 and `tseg1` up to 256.

```python
from can import BitTiming
bt = BitTiming.from_sample_point(f_clock=160_000_000, bitrate=250_000, sample_point=87.5)
# Raises: ValueError: No suitable bit timings found.
```

The valid solution is `brp=40, tseg1=13, tseg2=2` (sample point = 87.5% exact). The solver finds this combination but rejects it because `brp=40` exceeds the strict limit of 32.

All lower prescaler values produce `tseg1` values that exceed 16:

| brp | tseg1 | tseg2 | sample point | rejected by |
|-----|-------|-------|--------------|-------------|
| 16 | 34 | 5 | 87.50% | `tseg1 > 16` |
| 20 | 27 | 4 | 87.50% | `tseg1 > 16` |
| 32 | 17 | 2 | 90.00% | `tseg1 > 16` |
| 40 | 13 | 2 | 87.50% | `brp > 32` (strict) |

## Affected code

- `bit_timing.py` — `iterate_from_sample_point` passes `strict=True` with no option to override
- `bit_timing.py` — `_restrict_to_minimum_range` limits `brp` to 32
- `bit_timing.py` — `_validate` limits `tseg1` to 16, `tseg2` to 8, `brp` to 64

## Suggested fix

Add optional limit parameters to `from_sample_point` and `iterate_from_sample_point`:

```python
@classmethod
def from_sample_point(
cls,
f_clock: int,
bitrate: int,
sample_point: float = 69.0,
tseg1_max: int = 16,
tseg2_max: int = 8,
brp_max: int = 64,
) -> "BitTiming":
```

Pass these limits through to `_validate` instead of using hardcoded values. This approach lets callers supply the actual register ranges reported by the hardware. The defaults remain unchanged, so existing behavior is not affected.

The gs_usb interface could populate these limits automatically from the device's `GS_USB_BREQ_BT_CONST` capability response, which already reports `tseg1_max`, `tseg2_max`, and `brp_max`.

## Workaround

Construct the `BitTiming` object directly. The constructor defaults to `strict=False`:

```python
bt = BitTiming(f_clock=160_000_000, brp=40, tseg1=13, tseg2=2, sjw=2)
```

## Affected version

4.6.1 (also present on `main`)

Hướng dẫn đóng góp

Mở hướng dẫn đóng góp

Hướng nghiên cứu

Start in bit_timing.py with BitTiming.from_sample_point and follow its call to iterate_from_sample_point, then inspect _restrict_to_minimum_range and _validate. Verify that caller-supplied register limits allow the STM32G431 example to produce brp=40, tseg1=13, and tseg2=2, while the existing default limits preserve current behavior.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Đánh giá

Công nghệ
python
Lĩnh vực
embedded-iot
Loại issue
Lỗi
Độ khó
3/5
Thời gian dự kiến
1-2 ngày
Mức độ hoạt động
Ít trao đổi
Độ rõ ràng
Đặc tả rõ ràng
Mức phù hợp với người mới
72/100

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.