embassy-rs / stm32-data

77 stars 117 forks source link

Refactor timer taxonomy #495

Open honzasp opened 5 months ago

honzasp commented 5 months ago

This PR accompanies https://github.com/embassy-rs/embassy/pull/3123. It simplifies the register definitions for timers, unifies the naming of timers and supports the type-safe timer taxonomy from that PR.

However, as a necessary trade-off, it exposes registers and register fields for all channels even for timers that don't have the full number of channels: for example, all four CCR registers are exposed for Tim1ch. The idea here is that Tim1ch represents a timer that is at least as capable as a 1-channel timer, but might have up to 4 channels. For example, this allows us to implement a PWM driver that works for all timers with channels (it requires only the functionality of Tim1ch), but still supports up to 4 channels for timers that have them (so it can be used with Tim4ch or TimAdv2ch).

The idea is that the higher-level code ensures that only the available channels are used. For example, the SimplePwm driver ensures this by accessing only those channels that correspond to pins that belong to the timer peripheral: if there is a pin for channel 3, then the timer surely supports channel 3!

honzasp commented 5 months ago

Marked as draft because I want to double-check that I didn't introduce any unintentional breakage (in particular in the v2 and l0 versions).

embassy-ci[bot] commented 5 months ago

diff: https://ci.embassy.dev/jobs/a59b1c08ccfa/artifacts/diff.html

embassy-ci[bot] commented 5 months ago

diff: https://ci.embassy.dev/jobs/3d6adab5abc0/artifacts/diff.html

honzasp commented 5 months ago

This PR should now be ready for review :heavy_check_mark:

Dirbaio commented 4 months ago

However, as a necessary trade-off, it exposes registers and register fields for all channels even for timers that don't have the full number of channels: for example, all four CCR registers are exposed for Tim1ch. The idea here is that Tim1ch represents a timer that is at least as capable as a 1-channel timer, but might have up to 4 channels. For example, this allows us to implement a PWM driver that works for all timers with channels (it requires only the functionality of Tim1ch), but still supports up to 4 channels for timers that have them (so it can be used with Tim4ch or TimAdv2ch).

can't you already do this by unsafely casting a Tim1ch to a Tim4ch? For example, when you construct a SimplePwm, store it in self as a Tim4ch but record either in a field or in the type that it actually had only 1 ch, then avoid using the higher channels.

IMO this is better than changing the registers to allow 4ch in the 1ch timers, because:

There's 2 kinds of users of the PAC:

increasing the number of channels impacts end users (they can accidentally try using channels that don't exist), while requiring unsafe casting impacts only HAL authors, which are likely more "sophisticated" users.

honzasp commented 4 months ago

can't you already do this by unsafely casting a Tim1ch to a Tim4ch? For example, when you construct a SimplePwm, store it in self as a Tim4ch but record either in a field or in the type that it actually had only 1 ch, then avoid using the higher channels.

Sure, it's possible to treat any general-purpose timer as a Tim4ch, but the disadvantage is that Tim4ch gives you access to many registers and fields that are not available in Tim1ch and Tim2ch.

increasing the number of channels impacts end users (they can accidentally try using channels that don't exist), while requiring unsafe casting impacts only HAL authors, which are likely more "sophisticated" users.

I agree that this change makes life slightly harder for people who use this crate directly, but it should make life significantly easier for people who use Embassy.

In the current situation, we protect end users of the PAC crate from using non-existent channels in a timer (i.e., if they try to use channel 3 in a 2-channel timer, they get a compile-time or a runtime error), but we don't protect end users of Embassy from using the wrong timer type (e.g., if they try to use CountingMode::EdgeAlignedDown with a 2-channel timer, they get no error).

With the proposed changes, we won't be able to protect the users of the PAC from using more channels, but we will be able to ensure that users of Embassy use timer peripherals that actually support all operations that they need.

In my opinion, it's a good trade-off: it's quite simple to understand that a 2-channel timer has only two channels, but understanding all types of STM32 timers and their features takes a few days of detailed studying of reference manuals.

embassy-ci[bot] commented 1 month ago

diff: https://ci.embassy.dev/jobs/e38615ae252c/artifacts/diff.html