rtic/1/api/embedded_hal/index.html

530 lines
32 KiB
HTML
Raw Normal View History

<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="A Hardware Abstraction Layer (HAL) for embedded systems"><title>embedded_hal - Rust</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-46f98efaafac5295.ttf.woff2,FiraSans-Regular-018c141bf0843ffd.woff2,FiraSans-Medium-8f9a781e4970d388.woff2,SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2,SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../static.files/normalize-76eba96aa4d2e634.css"><link rel="stylesheet" href="../static.files/rustdoc-492a78a4a87dcc01.css"><meta name="rustdoc-vars" data-root-path="../" data-static-root-path="../static.files/" data-current-crate="embedded_hal" data-themes="" data-resource-suffix="" data-rustdoc-version="1.82.0 (f6e511eec 2024-10-15)" data-channel="1.82.0" data-search-js="search-a99f1315e7cc5121.js" data-settings-js="settings-4313503d2e1961c2.js" ><script src="../static.files/storage-118b08c4c78b968e.js"></script><script defer src="../crates.js"></script><script defer src="../static.files/main-921df33f47b8780c.js"></script><noscript><link rel="stylesheet" href="../static.files/noscript-3b12f09e550e0385.css"></noscript><link rel="alternate icon" type="image/png" href="../static.files/favicon-32x32-422f7d1d52889060.png"><link rel="icon" type="image/svg+xml" href="../static.files/favicon-2c020d218678b618.svg"></head><body class="rustdoc mod crate"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="mobile-topbar"><button class="sidebar-menu-toggle" title="show sidebar"></button></nav><nav class="sidebar"><div class="sidebar-crate"><h2><a href="../embedded_hal/index.html">embedded_<wbr>hal</a><span class="version">0.2.7</span></h2></div><div class="sidebar-elems"><ul class="block"><li><a id="all-types" href="all.html">All Items</a></li></ul><section><ul class="block"><li><a href="#modules">Modules</a></li><li><a href="#traits">Traits</a></li></ul></section></div></nav><div class="sidebar-resizer"></div><main><div class="width-limiter"><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="main-heading"><h1>Crate <a class="mod" href="#">embedded_hal</a><button id="copy-path" title="Copy item path to clipboard">Copy item path</button></h1><span class="out-of-band"><a class="src" href="../src/embedded_hal/lib.rs.html#1-999">source</a> · <button id="toggle-all-docs" title="collapse all docs">[<span>&#x2212;</span>]</button></span></div><details class="toggle top-doc" open><summary class="hideme"><span>Expand description</span></summary><div class="docblock"><p>A Hardware Abstraction Layer (HAL) for embedded systems</p>
<p><strong>NOTE</strong> This HAL is still is active development. Expect the traits presented here to be
tweaked, split or be replaced wholesale before being stabilized, i.e. before hitting the 1.0.0
release. That being said theres a part of the HAL thats currently considered unproven and is
hidden behind an “unproven” Cargo feature. This API is even more volatile and its exempt from
semver rules: it can change in a non-backward compatible fashion or even disappear in between
patch releases.</p>
<h2 id="design-goals"><a class="doc-anchor" href="#design-goals">§</a>Design goals</h2>
<p>The HAL</p>
<ul>
<li>
<p>Must <em>erase</em> device specific details. Neither register, register blocks or magic values should
appear in the API.</p>
</li>
<li>
<p>Must be generic <em>within</em> a device and <em>across</em> devices. The API to use a serial interface must
be the same regardless of whether the implementation uses the USART1 or UART4 peripheral of a
device or the UART0 peripheral of another device.</p>
</li>
<li>
<p>Where possible must <em>not</em> be tied to a specific asynchronous model. The API should be usable
in blocking mode, with the <code>futures</code> model, with an async/await model or with a callback model.
(cf. the <a href="https://crates.io/crates/nb"><code>nb</code></a> crate)</p>
</li>
<li>
<p>Must be minimal, and thus easy to implement and zero cost, yet highly composable. People that
want higher level abstraction should <em>prefer to use this HAL</em> rather than <em>re-implement</em>
register manipulation code.</p>
</li>
<li>
<p>Serve as a foundation for building an ecosystem of platform agnostic drivers. Here driver
means a library crate that lets a target platform interface an external device like a digital
sensor or a wireless transceiver. The advantage of this system is that by writing the driver as
a generic library on top of <code>embedded-hal</code> driver authors can support any number of target
platforms (e.g. Cortex-M microcontrollers, AVR microcontrollers, embedded Linux, etc.). The
advantage for application developers is that by adopting <code>embedded-hal</code> they can unlock all
these drivers for their platform.</p>
</li>
</ul>
<h2 id="out-of-scope"><a class="doc-anchor" href="#out-of-scope">§</a>Out of scope</h2>
<ul>
<li>Initialization and configuration stuff like “ensure this serial interface and that SPI
interface are not using the same pins”. The HAL will focus on <em>doing I/O</em>.</li>
</ul>
<h2 id="reference-implementation"><a class="doc-anchor" href="#reference-implementation">§</a>Reference implementation</h2>
<p>The <a href="https://crates.io/crates/stm32f30x-hal/0.1.0"><code>stm32f30x-hal</code></a> crate contains a reference implementation of this HAL.</p>
<h2 id="platform-agnostic-drivers"><a class="doc-anchor" href="#platform-agnostic-drivers">§</a>Platform agnostic drivers</h2>
<p>You can find platform agnostic drivers built on top of <code>embedded-hal</code> on crates.io by <a href="https://crates.io/keywords/embedded-hal">searching
for the <em>embedded-hal</em> keyword</a>.</p>
<p>If you writing a platform agnostic driver yourself you are highly encouraged to <a href="https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata">add the
embedded-hal keyword</a>
to your crate before publishing it!</p>
<h2 id="detailed-design"><a class="doc-anchor" href="#detailed-design">§</a>Detailed design</h2><h3 id="traits"><a class="doc-anchor" href="#traits">§</a>Traits</h3>
<p>The HAL is specified as traits to allow generic programming. These traits make use of the
<a href="https://crates.io/crates/nb"><code>nb</code></a> crate (<em>please go read that crate documentation before continuing</em>) to abstract over
the asynchronous model and to also provide a blocking operation mode.</p>
<p>Heres how a HAL trait may look like:</p>
<div class="example-wrap"><pre class="rust rust-example-rendered"><code><span class="kw">extern crate </span>nb;
<span class="doccomment">/// A serial interface
</span><span class="kw">pub trait </span>Serial {
<span class="doccomment">/// Error type associated to this serial interface
</span><span class="kw">type </span>Error;
<span class="doccomment">/// Reads a single byte
</span><span class="kw">fn </span>read(<span class="kw-2">&amp;mut </span><span class="self">self</span>) -&gt; nb::Result&lt;u8, <span class="self">Self</span>::Error&gt;;
<span class="doccomment">/// Writes a single byte
</span><span class="kw">fn </span>write(<span class="kw-2">&amp;mut </span><span class="self">self</span>, byte: u8) -&gt; nb::Result&lt;(), <span class="self">Self</span>::Error&gt;;
}</code></pre></div>
<p>The <code>nb::Result</code> enum is used to add a <a href="https://docs.rs/nb/0.1.0/nb/enum.Error.html"><code>WouldBlock</code></a> variant to the errors
of the serial interface. As explained in the documentation of the <code>nb</code> crate this single API,
when paired with the macros in the <code>nb</code> crate, can operate in a blocking manner, or in a
non-blocking manner compatible with <code>futures</code> and with the <code>await!</code> operator.</p>
<p>Some traits, like the one shown below, may expose possibly blocking APIs that cant fail. In
those cases <code>nb::Result&lt;_, Void&gt;</code> is used.</p>
<div class="example-wrap"><pre class="rust rust-example-rendered"><code><span class="kw">extern crate </span>nb;
<span class="kw">extern crate </span>void;
<span class="kw">use </span>void::Void;
<span class="doccomment">/// A count down timer
</span><span class="kw">pub trait </span>CountDown {
<span class="comment">// ..
</span><span class="doccomment">/// "waits" until the count down is over
</span><span class="kw">fn </span>wait(<span class="kw-2">&amp;mut </span><span class="self">self</span>) -&gt; nb::Result&lt;(), Void&gt;;
}
</code></pre></div>
<h3 id="suggested-implementation"><a class="doc-anchor" href="#suggested-implementation">§</a>Suggested implementation</h3>
<p>The HAL traits should be implemented for device crates generated via <a href="https://crates.io/crates/svd2rust"><code>svd2rust</code></a> to maximize
code reuse.</p>
<p>Shown below is an implementation of some of the HAL traits for the <a href="https://crates.io/crates/stm32f30x"><code>stm32f30x</code></a> crate. This
single implementation will work for <em>any</em> microcontroller in the STM32F30x family.</p>
<div class="example-wrap"><pre class="rust rust-example-rendered"><code><span class="comment">// crate: stm32f30x-hal
// An implementation of the `embedded-hal` traits for STM32F30x microcontrollers
</span><span class="kw">extern crate </span>embedded_hal <span class="kw">as </span>hal;
<span class="kw">extern crate </span>nb;
<span class="comment">// device crate
</span><span class="kw">extern crate </span>stm32f30x;
<span class="kw">use </span>stm32f30x::USART1;
<span class="doccomment">/// A serial interface
</span><span class="comment">// NOTE generic over the USART peripheral
</span><span class="kw">pub struct </span>Serial&lt;USART&gt; { usart: USART }
<span class="comment">// convenience type alias
</span><span class="kw">pub type </span>Serial1 = Serial&lt;USART1&gt;;
<span class="doccomment">/// Serial interface error
</span><span class="kw">pub enum </span>Error {
<span class="doccomment">/// Buffer overrun
</span>Overrun,
<span class="comment">// omitted: other error variants
</span>}
<span class="kw">impl </span>hal::serial::Read&lt;u8&gt; <span class="kw">for </span>Serial&lt;USART1&gt; {
<span class="kw">type </span>Error = Error;
<span class="kw">fn </span>read(<span class="kw-2">&amp;mut </span><span class="self">self</span>) -&gt; nb::Result&lt;u8, Error&gt; {
<span class="comment">// read the status register
</span><span class="kw">let </span>isr = <span class="self">self</span>.usart.isr.read();
<span class="kw">if </span>isr.ore().bit_is_set() {
<span class="comment">// Error: Buffer overrun
</span><span class="prelude-val">Err</span>(nb::Error::Other(Error::Overrun))
}
<span class="comment">// omitted: checks for other errors
</span><span class="kw">else if </span>isr.rxne().bit_is_set() {
<span class="comment">// Data available: read the data register
</span><span class="prelude-val">Ok</span>(<span class="self">self</span>.usart.rdr.read().bits() <span class="kw">as </span>u8)
} <span class="kw">else </span>{
<span class="comment">// No data available yet
</span><span class="prelude-val">Err</span>(nb::Error::WouldBlock)
}
}
}
<span class="kw">impl </span>hal::serial::Write&lt;u8&gt; <span class="kw">for </span>Serial&lt;USART1&gt; {
<span class="kw">type </span>Error = Error;
<span class="kw">fn </span>write(<span class="kw-2">&amp;mut </span><span class="self">self</span>, byte: u8) -&gt; nb::Result&lt;(), Error&gt; {
<span class="comment">// Similar to the `read` implementation
</span>}
<span class="kw">fn </span>flush(<span class="kw-2">&amp;mut </span><span class="self">self</span>) -&gt; nb::Result&lt;(), Error&gt; {
<span class="comment">// Similar to the `read` implementation
</span>}
}
</code></pre></div>
<h3 id="intended-usage"><a class="doc-anchor" href="#intended-usage">§</a>Intended usage</h3>
<p>Thanks to the <a href="https://crates.io/crates/nb"><code>nb</code></a> crate the HAL API can be used in a blocking manner,
with <code>futures</code> or with the <code>await</code> operator using the <a href="https://docs.rs/nb/0.1.0/nb/macro.block.html"><code>block!</code></a>,
<a href="https://docs.rs/nb/0.1.0/nb/index.html#how-to-use-this-crate"><code>try_nb!</code></a> and <a href="https://docs.rs/nb/0.1.0/nb/index.html#how-to-use-this-crate"><code>await!</code></a> macros respectively.</p>
<h4 id="blocking-mode"><a class="doc-anchor" href="#blocking-mode">§</a>Blocking mode</h4>
<p>An example of sending a string over the serial interface in a blocking
fashion:</p>
<div class="example-wrap"><pre class="rust rust-example-rendered"><code><span class="kw">extern crate </span>embedded_hal;
<span class="attr">#[macro_use(block)]
</span><span class="kw">extern crate </span>nb;
<span class="kw">use </span>stm32f30x_hal::Serial1;
<span class="kw">use </span>embedded_hal::serial::Write;
<span class="kw">let </span><span class="kw-2">mut </span>serial: Serial1 = {
<span class="comment">// ..
</span>};
<span class="kw">for </span>byte <span class="kw">in </span><span class="string">b"Hello, world!" </span>{
<span class="comment">// NOTE `block!` blocks until `serial.write()` completes and returns
// `Result&lt;(), Error&gt;`
</span><span class="macro">block!</span>(serial.write(<span class="kw-2">*</span>byte)).unwrap();
}
</code></pre></div>
<h4 id="futures"><a class="doc-anchor" href="#futures">§</a><code>futures</code></h4>
<p>An example of running two tasks concurrently. First task: blink an LED every
second. Second task: loop back data over the serial interface.</p>
<div class="example-wrap"><pre class="rust rust-example-rendered"><code><span class="kw">extern crate </span>embedded_hal <span class="kw">as </span>hal;
<span class="kw">extern crate </span>futures;
<span class="kw">extern crate </span>void;
<span class="attr">#[macro_use(try_nb)]
</span><span class="kw">extern crate </span>nb;
<span class="kw">use </span>hal::prelude::<span class="kw-2">*</span>;
<span class="kw">use </span>futures::{
future,
Async,
Future,
};
<span class="kw">use </span>futures::future::Loop;
<span class="kw">use </span>stm32f30x_hal::{Led, Serial1, Timer6};
<span class="kw">use </span>void::Void;
<span class="doccomment">/// `futures` version of `CountDown.wait`
///
/// This returns a future that must be polled to completion
</span><span class="kw">fn </span>wait&lt;T&gt;(<span class="kw-2">mut </span>timer: T) -&gt; <span class="kw">impl </span>Future&lt;Item = T, Error = Void&gt;
<span class="kw">where
</span>T: hal::timer::CountDown,
{
<span class="kw">let </span><span class="kw-2">mut </span>timer = <span class="prelude-val">Some</span>(timer);
future::poll_fn(<span class="kw">move </span>|| {
<span class="macro">try_nb!</span>(timer.as_mut().unwrap().wait());
<span class="prelude-val">Ok</span>(Async::Ready(timer.take().unwrap()))
})
}
<span class="doccomment">/// `futures` version of `Serial.read`
///
/// This returns a future that must be polled to completion
</span><span class="kw">fn </span>read&lt;S&gt;(<span class="kw-2">mut </span>serial: S) -&gt; <span class="kw">impl </span>Future&lt;Item = (S, u8), Error = S::Error&gt;
<span class="kw">where
</span>S: hal::serial::Read&lt;u8&gt;,
{
<span class="kw">let </span><span class="kw-2">mut </span>serial = <span class="prelude-val">Some</span>(serial);
future::poll_fn(<span class="kw">move </span>|| {
<span class="kw">let </span>byte = <span class="macro">try_nb!</span>(serial.as_mut().unwrap().read());
<span class="prelude-val">Ok</span>(Async::Ready((serial.take().unwrap(), byte)))
})
}
<span class="doccomment">/// `futures` version of `Serial.write`
///
/// This returns a future that must be polled to completion
</span><span class="kw">fn </span>write&lt;S&gt;(<span class="kw-2">mut </span>serial: S, byte: u8) -&gt; <span class="kw">impl </span>Future&lt;Item = S, Error = S::Error&gt;
<span class="kw">where
</span>S: hal::serial::Write&lt;u8&gt;,
{
<span class="kw">let </span><span class="kw-2">mut </span>serial = <span class="prelude-val">Some</span>(serial);
future::poll_fn(<span class="kw">move </span>|| {
<span class="macro">try_nb!</span>(serial.as_mut().unwrap().write(byte));
<span class="prelude-val">Ok</span>(Async::Ready(serial.take().unwrap()))
})
}
<span class="kw">fn </span>main() {
<span class="comment">// HAL implementers
</span><span class="kw">let </span>timer: Timer6 = {
<span class="comment">// ..
</span>};
<span class="kw">let </span>serial: Serial1 = {
<span class="comment">// ..
</span>};
<span class="kw">let </span>led: Led = {
<span class="comment">// ..
</span>};
<span class="comment">// Tasks
</span><span class="kw">let </span><span class="kw-2">mut </span>blinky = future::loop_fn::&lt;<span class="kw">_</span>, (), <span class="kw">_</span>, <span class="kw">_</span>&gt;(
(led, timer, <span class="bool-val">true</span>),
|(<span class="kw-2">mut </span>led, <span class="kw-2">mut </span>timer, state)| {
wait(timer).map(<span class="kw">move </span>|timer| {
<span class="kw">if </span>state {
led.on();
} <span class="kw">else </span>{
led.off();
}
Loop::Continue((led, timer, !state))
})
});
<span class="kw">let </span><span class="kw-2">mut </span>loopback = future::loop_fn::&lt;<span class="kw">_</span>, (), <span class="kw">_</span>, <span class="kw">_</span>&gt;(serial, |<span class="kw-2">mut </span>serial| {
read(serial).and_then(|(serial, byte)| {
write(serial, byte)
}).map(|serial| {
Loop::Continue(serial)
})
});
<span class="comment">// Event loop
</span><span class="kw">loop </span>{
blinky.poll().unwrap(); <span class="comment">// NOTE(unwrap) E = Void
</span>loopback.poll().unwrap();
}
}
</code></pre></div>
<h4 id="await"><a class="doc-anchor" href="#await">§</a><code>await</code></h4>
<p>Same example as above but using <code>await!</code> instead of <code>futures</code>.</p>
<div class="example-wrap"><pre class="rust rust-example-rendered"><code><span class="attr">#![feature(generator_trait)]
#![feature(generators)]
</span><span class="kw">extern crate </span>embedded_hal <span class="kw">as </span>hal;
<span class="attr">#[macro_use(<span class="kw">await</span>)]
</span><span class="kw">extern crate </span>nb;
<span class="kw">use </span>std::ops::Generator;
<span class="kw">use </span>std::pin::Pin;
<span class="kw">use </span>hal::prelude::<span class="kw-2">*</span>;
<span class="kw">use </span>stm32f30x_hal::{Led, Serial1, Timer6};
<span class="kw">fn </span>main() {
<span class="comment">// HAL implementers
</span><span class="kw">let </span><span class="kw-2">mut </span>timer: Timer6 = {
<span class="comment">// ..
</span>};
<span class="kw">let </span><span class="kw-2">mut </span>serial: Serial1 = {
<span class="comment">// ..
</span>};
<span class="kw">let </span><span class="kw-2">mut </span>led: Led = {
<span class="comment">// ..
</span>};
<span class="comment">// Tasks
</span><span class="kw">let </span><span class="kw-2">mut </span>blinky = (<span class="kw">move </span>|| {
<span class="kw">let </span><span class="kw-2">mut </span>state = <span class="bool-val">false</span>;
<span class="kw">loop </span>{
<span class="comment">// `await!` means "suspend / yield here" instead of "block until
// completion"
</span><span class="macro">await!</span>(timer.wait()).unwrap(); <span class="comment">// NOTE(unwrap) E = Void
</span>state = !state;
<span class="kw">if </span>state {
led.on();
} <span class="kw">else </span>{
led.off();
}
}
});
<span class="kw">let </span><span class="kw-2">mut </span>loopback = (<span class="kw">move </span>|| {
<span class="kw">loop </span>{
<span class="kw">let </span>byte = <span class="macro">await!</span>(serial.read()).unwrap();
<span class="macro">await!</span>(serial.write(byte)).unwrap();
}
});
<span class="comment">// Event loop
</span><span class="kw">loop </span>{
Pin::new(<span class="kw-2">&amp;mut </span>blinky).resume(());
Pin::new(<span class="kw-2">&amp;mut </span>loopback).resume(());
}
}
</code></pre></div>
<h3 id="generic-programming-and-higher-level-abstractions"><a class="doc-anchor" href="#generic-programming-and-higher-level-abstractions">§</a>Generic programming and higher level abstractions</h3>
<p>The core of the HAL has been kept minimal on purpose to encourage building <strong>generic</strong> higher
level abstractions on top of it. Some higher level abstractions that pick an asynchronous model
or that have blocking behavior and that are deemed useful to build other abstractions can be
found in the <code>blocking</code> module and, in the future, in the <code>futures</code> and <code>async</code> modules.</p>
<p>Some examples:</p>
<p><strong>NOTE</strong> All the functions shown below could have been written as trait
methods with default implementation to allow specialization, but they have
been written as functions to keep things simple.</p>
<ul>
<li>Write a whole buffer to a serial device in blocking a fashion.</li>
</ul>
<div class="example-wrap"><pre class="rust rust-example-rendered"><code><span class="kw">extern crate </span>embedded_hal <span class="kw">as </span>hal;
<span class="attr">#[macro_use(block)]
</span><span class="kw">extern crate </span>nb;
<span class="kw">use </span>hal::prelude::<span class="kw-2">*</span>;
<span class="kw">fn </span>write_all&lt;S&gt;(serial: <span class="kw-2">&amp;mut </span>S, buffer: <span class="kw-2">&amp;</span>[u8]) -&gt; <span class="prelude-ty">Result</span>&lt;(), S::Error&gt;
<span class="kw">where
</span>S: hal::serial::Write&lt;u8&gt;
{
<span class="kw">for </span><span class="kw-2">&amp;</span>byte <span class="kw">in </span>buffer {
<span class="macro">block!</span>(serial.write(byte))<span class="question-mark">?</span>;
}
<span class="prelude-val">Ok</span>(())
}
</code></pre></div>
<ul>
<li>Blocking serial read with timeout</li>
</ul>
<div class="example-wrap"><pre class="rust rust-example-rendered"><code><span class="kw">extern crate </span>embedded_hal <span class="kw">as </span>hal;
<span class="kw">extern crate </span>nb;
<span class="kw">use </span>hal::prelude::<span class="kw-2">*</span>;
<span class="kw">enum </span>Error&lt;E&gt; {
<span class="doccomment">/// Serial interface error
</span>Serial(E),
TimedOut,
}
<span class="kw">fn </span>read_with_timeout&lt;S, T&gt;(
serial: <span class="kw-2">&amp;mut </span>S,
timer: <span class="kw-2">&amp;mut </span>T,
timeout: T::Time,
) -&gt; <span class="prelude-ty">Result</span>&lt;u8, Error&lt;S::Error&gt;&gt;
<span class="kw">where
</span>T: hal::timer::CountDown,
S: hal::serial::Read&lt;u8&gt;,
{
timer.start(timeout);
<span class="kw">loop </span>{
<span class="kw">match </span>serial.read() {
<span class="comment">// raise error
</span><span class="prelude-val">Err</span>(nb::Error::Other(e)) =&gt; <span class="kw">return </span><span class="prelude-val">Err</span>(Error::Serial(e)),
<span class="prelude-val">Err</span>(nb::Error::WouldBlock) =&gt; {
<span class="comment">// no data available yet, check the timer below
</span>},
<span class="prelude-val">Ok</span>(byte) =&gt; <span class="kw">return </span><span class="prelude-val">Ok</span>(byte),
}
<span class="kw">match </span>timer.wait() {
<span class="prelude-val">Err</span>(nb::Error::Other(e)) =&gt; {
<span class="comment">// The error type specified by `timer.wait()` is `!`, which
// means no error can actually occur. The Rust compiler
// still forces us to provide this match arm, though.
</span><span class="macro">unreachable!</span>()
},
<span class="comment">// no timeout yet, try again
</span><span class="prelude-val">Err</span>(nb::Error::WouldBlock) =&gt; <span class="kw">continue</span>,
<span class="prelude-val">Ok</span>(()) =&gt; <span class="kw">return </span><span class="prelude-val">Err</span>(Error::TimedOut),
}
}
}
</code></pre></div>
<ul>
<li>Asynchronous SPI transfer</li>
</ul>
<div class="example-wrap"><pre class="rust rust-example-rendered"><code><span class="attr">#![feature(conservative_impl_trait)]
#![feature(generators)]
#![feature(generator_trait)]
</span><span class="kw">extern crate </span>embedded_hal <span class="kw">as </span>hal;
<span class="attr">#[macro_use(<span class="kw">await</span>)]
</span><span class="kw">extern crate </span>nb;
<span class="kw">use </span>std::ops::Generator;
<span class="doccomment">/// Transfers a byte buffer of size N
///
/// Returns the same byte buffer but filled with the data received from the
/// slave device
</span><span class="kw">fn </span>transfer&lt;S, B&gt;(
<span class="kw-2">mut </span>spi: S,
<span class="kw-2">mut </span>buffer: [u8; <span class="number">16</span>], <span class="comment">// NOTE this should be generic over the size of the array
</span>) -&gt; <span class="kw">impl </span>Generator&lt;Return = <span class="prelude-ty">Result</span>&lt;(S, [u8; <span class="number">16</span>]), S::Error&gt;, Yield = ()&gt;
<span class="kw">where
</span>S: hal::spi::FullDuplex&lt;u8&gt;,
{
<span class="kw">move </span>|| {
<span class="kw">let </span>n = buffer.len();
<span class="kw">for </span>i <span class="kw">in </span><span class="number">0</span>..n {
<span class="macro">await!</span>(spi.send(buffer[i]))<span class="question-mark">?</span>;
buffer[i] = <span class="macro">await!</span>(spi.read())<span class="question-mark">?</span>;
}
<span class="prelude-val">Ok</span>((spi, buffer))
}
}
</code></pre></div>
<ul>
<li>Buffered serial interface with periodic flushing in interrupt handler</li>
</ul>
<div class="example-wrap"><pre class="rust rust-example-rendered"><code><span class="kw">extern crate </span>embedded_hal <span class="kw">as </span>hal;
<span class="kw">extern crate </span>nb;
<span class="kw">extern crate </span>void;
<span class="kw">use </span>hal::prelude::<span class="kw-2">*</span>;
<span class="kw">use </span>void::Void;
<span class="kw">fn </span>flush&lt;S&gt;(serial: <span class="kw-2">&amp;mut </span>S, cb: <span class="kw-2">&amp;mut </span>CircularBuffer)
<span class="kw">where
</span>S: hal::serial::Write&lt;u8, Error = Void&gt;,
{
<span class="kw">loop </span>{
<span class="kw">if let </span><span class="prelude-val">Some</span>(byte) = cb.peek() {
<span class="kw">match </span>serial.write(<span class="kw-2">*</span>byte) {
<span class="prelude-val">Err</span>(nb::Error::Other(<span class="kw">_</span>)) =&gt; <span class="macro">unreachable!</span>(),
<span class="prelude-val">Err</span>(nb::Error::WouldBlock) =&gt; <span class="kw">return</span>,
<span class="prelude-val">Ok</span>(()) =&gt; {}, <span class="comment">// keep flushing data
</span>}
}
cb.pop();
}
}
<span class="comment">// The stuff below could be in some other crate
</span><span class="doccomment">/// Global singleton
</span><span class="kw">pub struct </span>BufferedSerial1;
<span class="comment">// NOTE private
</span><span class="kw">static </span>BUFFER1: Mutex&lt;CircularBuffer&gt; = {
<span class="comment">// ..
</span>};
<span class="kw">static </span>SERIAL1: Mutex&lt;Serial1&gt; = {
<span class="comment">// ..
</span>};
<span class="kw">impl </span>BufferedSerial1 {
<span class="kw">pub fn </span>write(<span class="kw-2">&amp;</span><span class="self">self</span>, byte: u8) {
<span class="self">self</span>.write_all(<span class="kw-2">&amp;</span>[byte])
}
<span class="kw">pub fn </span>write_all(<span class="kw-2">&amp;</span><span class="self">self</span>, bytes: <span class="kw-2">&amp;</span>[u8]) {
<span class="kw">let </span><span class="kw-2">mut </span>buffer = BUFFER1.lock();
<span class="kw">for </span>byte <span class="kw">in </span>bytes {
buffer.push(<span class="kw-2">*</span>byte).expect(<span class="string">"buffer overrun"</span>);
}
<span class="comment">// omitted: pend / enable interrupt_handler
</span>}
}
<span class="kw">fn </span>interrupt_handler() {
<span class="kw">let </span><span class="kw-2">mut </span>serial = SERIAL1.lock();
<span class="kw">let </span><span class="kw-2">mut </span>buffer = BUFFER1.lock();
flush(<span class="kw-2">&amp;mut *</span>serial, <span class="kw-2">&amp;mut </span>buffer);
}
</code></pre></div>
</div></details><h2 id="modules" class="section-header">Modules<a href="#modules" class="anchor">§</a></h2><ul class="item-table"><li><div class="item-name"><a class="mod" href="adc/index.html" title="mod embedded_hal::adc">adc</a></div><div class="desc docblock-short">Analog-digital conversion traits</div></li><li><div class="item-name"><a class="mod" href="blocking/index.html" title="mod embedded_hal::blocking">blocking</a></div><div class="desc docblock-short">Blocking API</div></li><li><div class="item-name"><a class="mod" href="can/index.html" title="mod embedded_hal::can">can</a></div><div class="desc docblock-short">Controller Area Network</div></li><li><div class="item-name"><a class="mod" href="digital/index.html" title="mod embedded_hal::digital">digital</a></div><div class="desc docblock-short">Digital I/O</div></li><li><div class="item-name"><a class="mod" href="fmt/index.html" title="mod embedded_hal::fmt">fmt</a></div><div class="desc docblock-short">Implementation of <code>core::fmt::Write</code> for the HALs <code>serial::Write</code>.</div></li><li><div class="item-name"><a class="mod" href="prelude/index.html" title="mod embedded_hal::prelude">prelude</a></div><div class="desc docblock-short">The prelude is a collection of all the traits in this crate</div></li><li><div class="item-name"><a class="mod" href="serial/index.html" title="mod embedded_hal::serial">serial</a></div><div class="desc docblock-short">Serial interface</div></li><li><div class="item-name"><a class="mod" href="spi/index.html" title="mod embedded_hal::spi">spi</a></div><div class="desc docblock-short">Serial Peripheral Interface</div></li><li><div class="item-name"><a class="mod" href="timer/index.html" title="mod embedded_hal::timer">timer</a></div><div class="desc docblock-short">Timers</div></li><li><div class="item-name"><a class="mod" href="watchdog/index.html" title="mod embedded_hal::watchdog">watchdog</a></div><div class="desc docblock-short">Traits for interactions with a processors watchdog timer.</div></li></ul><h2 id="traits-1" class="section-header">Traits<a href="#traits-1" class="anchor">§</a></h2><ul class="item-table"><li><div class="item-name"><a class="trait" href="trait.PwmPin.html" title="trait embedded_hal::PwmPin">PwmPin</a></div><div class="desc docblock-short">A single PWM channel / pin</div></li></ul></section></div></main></body></html>