-
Notifications
You must be signed in to change notification settings - Fork 152
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[RFC] API tailored for specific microcontrollers #122
Comments
If we were able to implement #96, then the solution to this problem would be greatly simplified. Then third-party crates could use not "stm32f103c8::TIM2" but something like "stm32::GPTimer" or "stm32::DAC". This should work very well for |
I think MSP430 is not affected by this issue yet, because we generate a separate SVD file for each specific MCU. But we can highly benefit from grouping devices into families and grouping peripherals across devices or even families. |
This is much more diverse than in STM32 devices (in them there are only two types of RTC). But not so bad as I was afraid. Benefits could still outweigh the need to write custom SVD files for this to work. |
Could you elaborate? I see #96 as the "dual" of this issue. #96 is about reducing the number of types to share them across different device crates. This issue is about restricting the use of instances (not types; i.e. |
@japaric I was referring to "re-exports" solution. If there was some way to tell svd2rust that peripherals in different devices are the same (like proposed in #96) then common crate could be not for stm32f103 but for the whole stm32f1 family or even more generic. Like @pftbest said
And #96 would allow to automate this process (if SVD files were modified to include such information). |
Original issue: japaric/stm32f103xx#9
The problem
SVD files usually describe a family of microcontrollers and contain
information about all the peripherals any member of the family could have.
When svd2rust produces a device crate from a SVD file it produces an API to
access every single of these peripherals.
The problem is that the lower density members of a family are likely to contain
less peripherals than the set of peripherals described by the SVD file. As a
result using the device crate with such devices lets you access nonexistent
peripherals.
As a concrete example the
stm32f103xx
crate exposes an API for the TIM6 andTIM7 peripherals (basic timers) but these peripherals are not available on the
STM32F103C8 microcontroller. So if you write an application for that
microcontroller using the
stm32f103xx
crate you may end up using those timerswithout realizing they are not available. Worst part is that the program won't
crash -- it won't hit an exception -- but rather it will likely have undefined
behavior (writes are no-op and reads return junk values or zero)
Possible solutions
Constraints
device X. So this information will have to be supplied by a human and most
likely we won't be able to add this information to the SVD file.
Cargo features
One of the ideas brought up in the original issue was to encode the presence of
each peripheral through a Cargo feature and then have one Cargo feature per
microcontroller. That microcontroller feature would enable all the peripherals,
through their features, that are present on that microcontroller. Example:
The device crate would make use
#[cfg]
attributes like this:to prevent exposing APIs not available to a certain microcontroller.
As you know Cargo features are additive so there's nothing stopping
you from enabling more than one microcontroller feature at the same time, even
by mistake (e.g. a dependency enables one microcontroller feature and another
dependency enables a different one). In those cases we can raise an error in the
device crate like this:
If more than one microcontroller feature is enabled this will raise a name
collision error.
Library crates that depend on the device crate can write device specific APIs
like this:
Testing a library crate that depends on a device crate for the different devices
that the device crate supports is as simple as calling the Cargo command with
different
--feature
arguments:Upsides
This is straightforward to implement in svd2rust.
Downsides
Due to the additive nature of Cargo features it seems to be easy to break the
device selection mechanism: it's just enough that a dependency directly enables
a peripheral feature:
This problem can be avoided if library crates never enable any feature of the
device crate but there's no mechanism to enforce this so discipline would be
required.
--cfg device=
Another approach is to not use Cargo features at all but to directly use
#[cfg]
attributes and the--cfg
rustc flag. With this approach the devicecrate would look like this:
Application crates that depend on the device crate can then pick one specific
device or other using the
--cfg
flag:Library crates would require
#[cfg]
attributes similar to the ones used in thedevice crate:
Enabling more than one device
cfg
seems hard to do by mistake but an error canbe raised in the device crate like this:
The more common error scenario is that people will likely forget to pass the
--cfg device=
flag. In that case a helpful error can be raised in the devicecrate:
Downsides
Implementing this is hard and would require teaching svd2rust to parse a file
that maps a device to the peripherals it has.
Writing library crates is tedious as it requires checking which peripheral is
available for each specific device the device crate supports.
RUSTFLAGS is not the first thing that comes to people's mind when they think
about configuring dependencies.
one crate per device
Another approach is to not solve this in svd2rust. Instead we can create device
specific SVD files from a more generic one, and then generate one device crate
for each of those files. This means that instead of a generic stm32f103xx crate
we would have several crates: stm32f103c8, stm32f103vg, etc.
Downsides
Lots of duplicated code.
More work would likely be required to write crates that abstract over device
specific details. Mainly because
stm32f103c8::TIM2
andstm32f103vg::TIM2
arenot the same type.
re-exports
Yet another approach is to have device specific crates but that only include
re-exports of a more generic device crate. For instance:
Downsides
Unless the application crate directly depends on a device specific crate some
intermediate library crate will end up looking like this:
Unresolved questions
cc @protomors
The text was updated successfully, but these errors were encountered: