hardbyte / hardbyte/python-can

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

Ouverte
#2,083 0 commentaires 0 réactions 0 personnes assignées Voir sur GitHub
bug
Langage dominant
Python
Étoiles
1.6k
Forks
697
Métriques de merge des PR
Aucune PR mergée en 30 j

Description

## 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`)

Guide de contribution

Ouvrir le guide de contribution

Piste de recherche

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.

Rédigé par le modèle d'indexation à partir du texte de l'issue.

Évaluation

Stack technique
python
Domaine
embedded-iot
Type d'issue
Bug
Difficulté
3/5
Temps estimé
1-2 jours
Activité
Calme
Clarté
Clairement spécifiée
Accessibilité débutants
72/100

Recevez les nouvelles issues par e-mail

Un résumé court des issues GitHub adaptées aux débutants.