hardbyte / hardbyte/python-can

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

Abierto
#2,083 0 comentarios 0 reacciones 0 asignados Ver en GitHub
bug
Lenguaje dominante
Python
Estrellas
1.6k
Forks
697
Métricas de merge de PR
Sin PR fusionados en 30 d

Descripción

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

Guía de contribución

Abrir la guía de contribución

Línea de trabajo

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.

Escrito por el modelo de indexación a partir del texto del issue.

Evaluación

Stack tecnológico
python
Área
embedded-iot
Tipo de issue
Error
Dificultad
3/5
Tiempo estimado
1-2 días
Estado de actividad
Tranquilo
Claridad
Bien especificado
Aptitud para principiantes
72/100

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.