You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
There have been _a lot_ of changes in `embedded_hal` between versions 0.2.x and 1.0.0.
32
+
We understand the significance of `embedded-hal` in the Rust embedded
33
+
ecosystem and thus intend to release a version that stays compatible for a long time.
34
+
35
+
In this version, among many other changes, we have addressed several big topics that have emerged over the years:
36
+
-[Associated type compatibiilty](#removed-traits)
37
+
-[Trait fragmentation](#trait-organization)
38
+
-[Bus/device separation](#bus-device-separation)
39
+
-[Fallibility](#fallibility)
40
+
-[Execution model support](#trait-organization)
41
+
23
42
## Trait organization
24
43
25
-
All traits have been organized in modules for each feature, each of these containing sub-modules depending on their execution model. That includes `blocking` and `nb` for
26
-
non-blocking. In the future when we add asynchronous traits, we envision adding a `futures` (or similarly-named) module.
44
+
All traits have been organized in modules for each feature. For example `embedded_hal::spi` and `embedded_hal::i2c`.
45
+
We only foresee having blocking traits in `embedded-hal`. We have put the traits for different execution models
46
+
into separate crates. Notably `embedded-hal-async` and `embedded-hal-nb`. See [companion crates](#companion-crates).
47
+
This allows for a separate and more tailored evolution.
48
+
49
+
<!-- TODO assumes nb separation merged -->
50
+
51
+
Execution-model-independent definitions have been moved into the feature module. For example, SPI `Phase` is now defined in `embedded_hal::spi::Phase`.
52
+
53
+
### Trait unification
54
+
55
+
Previously, there were multiple traits for the same feature. In order to avoid fragmentation and ensure
56
+
interoperability for generic code, these have now been united.
57
+
58
+
For example, most generic code should simply use the `SpiDevice` trait instead of
59
+
choosing from `Transactional`, `Transfer`, `Write` and `WriteIter`.
60
+
61
+
For HAL implementations and some specialized use-cases there are still a few traits to implement for SPI
62
+
but the number has been reduced.
63
+
64
+
Please see more about this separation [below](#bus-device-separation).
65
+
66
+
## Removed traits
67
+
68
+
These traits have been removed in the 1.0.0 release:
69
+
70
+
-[`adc::OneShot`][adc]
71
+
-[`adc::Channel`][adc]
72
+
-[`capture::Capture`][capture]
73
+
-`delay::DelayMs` (replaced by `DelayUs`)
74
+
-[`digital::IoPin`][iopin]
75
+
-[`pwm::Pwm`][pwm]
76
+
-[`pwm::PwmPin`][pwm]
77
+
-[`qei::Qei`][qei]
78
+
-[`timer::Cancel`][timer]
79
+
-[`timer::CountDown`][timer]
80
+
-[`timer::Periodic`][timer]
81
+
-[`watchdog::Disable`][watchdog]
82
+
-[`watchdog::Enable`][watchdog]
83
+
-[`watchdog::Watchdog`][watchdog]
84
+
85
+
Please find a general [roadmap with further guidance here][roadmap-rm-traits] about
86
+
how to get these traits back in a future release.
87
+
If you need them, we would like to hear from you. Please add your use case to the appropriate issue for the trait affected.
Traits defined in `embedded-hal` pursue creating an interface for interoperability between generic code (be it generic user code, generic application code, generic device drivers, etc.).
101
+
When a trait has an unconstrained associated type, it is not possible to write generic code around it. Each side (implementer and user) need to specify which type the associated type will be. If the types match, the both parts can work together, however, this is not truly generic code.
102
+
103
+
For example, if somebody creates a device driver that receives a `CountDown` struct, it needs to specify what its `Time` type should be. If they choose a type coming from `fugit`, somebody else cannot use this driver if the HAL implementation for the MCU they are using only provides `CountDown` with `Time` types defined in `embedded-time`. It is also not possible for the user to implement `CountDown` for `Time` types defined by `fugit` in a straight-forward way due to the orphan rule.
104
+
In summary, it is not possible for anybody to start a countdown for a certain duration in a generic way, without it being tied to a particular time implementation and thus forcing everybody to use that one.
105
+
106
+
At the moment no solution for this has been found so we have decided to remove such traits hoping that a solution may be found
107
+
and we can add them back in a future 1.x release.
108
+
109
+
### Impractical traits
110
+
111
+
The [`digital::IoPin` trait][iopin] and the [`adc` traits][adc] have been deemed impractical for use and have thus been removed.
112
+
Please feel free to comment on the appropriate issue if you need any of these crates and propose a solution.
113
+
114
+
### Delay traits
115
+
116
+
The `DelayMs` trait has been removed. The functionality provided by this trait should now be provided by the `DelayUs` trait,
117
+
which also features a convenience `delay_ms()` method, so changes should be minimal.
27
118
28
-
Execution-model-independent definitions have been moved into the feature module. For example, SPI `Phase` is now defined in `embedded_hal::spi::Phase`. For convenience, these definitions are reexported in both of its blocking and non-blocking submodules.
119
+
This allowed us to reduce the API surface while still keeping the main functionality. We intend to add a generic `Delay` trait
120
+
in the future, once the time representation issue has been resolved.
121
+
122
+
## Bus/device separation
123
+
<!-- TODO assumes I2C bus/device merged -->
29
124
30
125
## Fallibility
31
126
@@ -34,19 +129,19 @@ However, HAL implementations can also provide infallible versions of the methods
34
129
35
130
For example, an implementation similar to the one below would allow to use the GPIO pins as `OutputPin`s
36
131
in any generic driver or implementation-agnostic code (by importing the `OutputPin` trait),
37
-
as well as using the infallible methods in non-generic code, thus avoiding the need to use `unwrap()`
38
-
the results in many cases and resulting in more succinct code.
132
+
as well as using the infallible methods in non-generic code.
133
+
This avoids the need to use `unwrap()` the results in many cases and results in more succinct code.
39
134
40
135
It should be noted that given this implementation, importing the `OutputPin` trait can result in
41
136
ambiguous calls, so please remove the trait imports if you do not need them.
42
137
43
138
```rust
44
139
usecore::convert::Infallible;
45
-
useembedded_hal::blocking::digital::OutputPin;
140
+
useembedded_hal::digital::blocking::OutputPin;
46
141
47
-
structGpioPin;
142
+
structHalImplGpioPin;
48
143
49
-
implOutputPinforGpioPin {
144
+
implOutputPinforHalImplGpioPin {
50
145
typeError=Infallible;
51
146
52
147
fnset_high(&mutself) ->Result<(), Self::Error> {
@@ -60,7 +155,7 @@ impl OutputPin for GpioPin {
60
155
}
61
156
}
62
157
63
-
implGpioPin {
158
+
implHalImplGpioPin {
64
159
fnset_high(&mutself) {
65
160
// ...
66
161
}
@@ -71,24 +166,15 @@ impl GpioPin {
71
166
}
72
167
```
73
168
74
-
## Method renaming
75
-
76
-
The methods in `SPI`, `I2C` and `Serial` traits for both `blocking` and `nb` execution models have been renamed
77
-
to `write()`, `read()` and `flush()` for consistency.
78
-
79
-
In order to avoid method call ambiguity, only the traits from the corresponding execution model should be imported
80
-
into the relevant scope. This is the reason why we have removed the prelude.
81
-
82
-
For more on this, see [Prelude](#prelude).
83
-
84
169
## SPI transfer return type
85
170
86
-
The `transfer()` method in the trait `spi::blocking::Transfer` previously returned
87
-
a slice of the output data.
171
+
Previously the `transfer()` method in SPI returned a slice of the output data.
88
172
This slice is the same as the output buffer which is passed to the method, though, thus redundant and potentially confusing.
89
173
The `transfer()` method now returns `Result<(), Self::Error>`.
90
174
If you were using this return value, adapting the code should be straight forward by simply using the reception buffer which is passed.
175
+
91
176
See an example:
177
+
92
178
```rust
93
179
lettx_data= [1, 2, 3, 4];
94
180
letmutrx_data= [0; 4];
@@ -113,38 +199,52 @@ pub enum MyError {
113
199
}
114
200
```
115
201
116
-
## `nb` dependency
202
+
Additionally, for the I2C, SPI and Serial communication interfaces we have added a dedicated mechanism
203
+
which allows for two crucial requirements:
204
+
1. Generic code like drivers can interpret and act on errors if they want to.
205
+
2. HAL implementations can have arbitrarily-precise error types.
117
206
118
-
The `Result` type and `block!` macro from the [`nb`] crate are now reexported in `embeddeh_hal::nb`.
119
-
This ensures there are no version mismatches.
120
-
You should remove the `nb` crate dependency in your `Cargo.toml` in any version and use the reexported items.
207
+
This works in the following way:
121
208
122
-
In your `Cargo.toml`:
123
-
```diff
124
-
- nb = "1"
125
-
```
209
+
For each interface, `embedded-hal` defines an `ErrorKind``enum` type with all sensible error variants as well
210
+
as an `Error` trait featuring a method that converts the type into that `ErrorKind`.
126
211
127
-
In your code:
128
-
```diff
129
-
- use nb;
130
-
+ use embedded_hal::nb;
131
-
```
132
-
You can also drop `#[macro_use]` if you are using Rust edition 2018.
212
+
`embedded-hal` still allows for implementation-defined error types associated to each trait, but requires these to
213
+
implement the appropriate `Error` trait, thus providing a mapping to a defined set of error variants.
133
214
134
-
Alternatively (needs Rust edition 2018):
135
-
```diff
136
-
- use nb::{Result, block};
137
-
+ use embedded_hal::nb::{Result, block};
215
+
With this mechanism, HAL implementations can continue to define their own error types which can carry as much
216
+
information as they want. On the other hand it is now possible for generic code to inspect those errors
217
+
and act on common errors like I2Cs NACK.
218
+
219
+
Furthermore, implementation-specific code can access the original error type and retrieve any information contained.
220
+
221
+
An example of a driver which looks for I2C NACK errors and returns its own `DeviceBusy` or `Comm` error
0 commit comments