<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://lonesometraveler.github.io/feed.xml" rel="self" type="application/atom+xml" /><link href="https://lonesometraveler.github.io/" rel="alternate" type="text/html" /><updated>2026-08-09T11:36:27+00:00</updated><id>https://lonesometraveler.github.io/feed.xml</id><title type="html">Alone on a Mountaintop</title><subtitle>Stuff about embedded Rust. </subtitle><author><name>lonesometraveler</name><email>lonesometraveler@mac.com</email></author><entry><title type="html">Schedule Software Tasks With RTFM</title><link href="https://lonesometraveler.github.io/2020/06/13/RTFM-3.html" rel="alternate" type="text/html" title="Schedule Software Tasks With RTFM" /><published>2020-06-13T22:01:42+00:00</published><updated>2020-06-13T22:01:42+00:00</updated><id>https://lonesometraveler.github.io/2020/06/13/RTFM-3</id><content type="html" xml:base="https://lonesometraveler.github.io/2020/06/13/RTFM-3.html"><![CDATA[<p>This week, we will look at the task scheduling feature of the RTFM framework.  This is a redo of <a href="https://lonesometraveler.github.io/2020/05/29/RTFM-2.html">the last project that reads when new data is available on USART and sends the accumulated data through USART every second</a>.</p>

<p>Here are three things we implement:</p>

<ol>
  <li>initialize USART TX, RX, and producer/consumer for a buffer and store them for later use.</li>
  <li>When new data arrives on USART, enter an interrupt context to read the data and write it to the buffer.</li>
  <li>Every second, see if there are any data available in the buffer and send them through USART.</li>
</ol>

<p>Instead of using a Timer to trigger an interrupt every second, we will schedule a software task this time.</p>

<p><strong>Hardware</strong></p>

<ul>
  <li><a href="https://www.st.com/en/evaluation-tools/nucleo-f429zi.html">Nucleo-F429ZI</a></li>
</ul>

<p><strong>Crates</strong></p>

<ul>
  <li><a href="https://crates.io/crates/stm32f4xx-hal">stm32f4xx-hal</a></li>
  <li><a href="https://crates.io/crates/cortex-m-rtfm">cortex-m-rtfm</a></li>
  <li><a href="https://github.com/jamesmunns/bbqueue">BBQueue</a></li>
</ul>

<p><strong>Code</strong></p>

<p>Full code is available on <a href="https://github.com/lonesometraveler/stm32f4xx-examples/blob/master/examples/rtfm_3.rs">GitHub</a></p>

<h2 id="implementation">Implementation</h2>

<p>1 and 2 in the list above are the same as the last project. In this post, I will only focus on 3, how to schedule software tasks.</p>

<p>This shows an overview of the application.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// import crates, declare buffer queue, etc.</span>

<span class="k">const</span> <span class="n">PERIOD</span><span class="p">:</span> <span class="nb">u32</span> <span class="o">=</span> <span class="mi">16_000_000</span><span class="p">;</span>

<span class="nd">#[rtfm::app(device</span> <span class="nd">=</span> <span class="nd">hal::stm32,</span> <span class="nd">peripherals</span> <span class="nd">=</span> <span class="kc">true</span><span class="nd">,</span> <span class="nd">monotonic</span> <span class="nd">=</span> <span class="nd">rtfm::cyccnt::CYCCNT)]</span>
<span class="k">const</span> <span class="n">APP</span><span class="p">:</span> <span class="p">()</span> <span class="o">=</span> <span class="p">{</span>
    <span class="k">struct</span> <span class="n">Resources</span> <span class="p">{</span>
        <span class="n">cons</span><span class="p">:</span> <span class="n">Consumer</span><span class="o">&lt;</span><span class="k">'static</span><span class="p">,</span> <span class="n">U1024</span><span class="o">&gt;</span><span class="p">,</span>
        <span class="n">prod</span><span class="p">:</span> <span class="n">Producer</span><span class="o">&lt;</span><span class="k">'static</span><span class="p">,</span> <span class="n">U1024</span><span class="o">&gt;</span><span class="p">,</span>
        <span class="n">tx</span><span class="p">:</span> <span class="nn">hal</span><span class="p">::</span><span class="nn">serial</span><span class="p">::</span><span class="n">Tx</span><span class="o">&lt;</span><span class="n">USART3</span><span class="o">&gt;</span><span class="p">,</span>
        <span class="n">rx</span><span class="p">:</span> <span class="nn">hal</span><span class="p">::</span><span class="nn">serial</span><span class="p">::</span><span class="n">Rx</span><span class="o">&lt;</span><span class="n">USART3</span><span class="o">&gt;</span><span class="p">,</span>
    <span class="p">}</span>

    <span class="nd">#[init(schedule</span> <span class="nd">=</span> <span class="err">[</span><span class="nd">tx_write]</span><span class="p">)]</span>
    <span class="k">fn</span> <span class="nf">init</span><span class="p">(</span><span class="n">cx</span><span class="p">:</span> <span class="nn">init</span><span class="p">::</span><span class="n">Context</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="nn">init</span><span class="p">::</span><span class="n">LateResources</span> <span class="p">{</span>
        <span class="c1">// Schedule a tx_write task</span>
        <span class="c1">// Split bbqueue Producer and Consumer</span>
        <span class="c1">// Set up USART, enable interrupt</span>
        <span class="c1">// Initialization of late resources</span>
    <span class="p">}</span>

    <span class="nd">#[task(binds</span> <span class="nd">=</span> <span class="nd">USART3,</span> <span class="nd">resources</span> <span class="nd">=</span> <span class="err">[</span><span class="nd">prod,</span> <span class="nd">rx]</span><span class="p">)]</span>
    <span class="k">fn</span> <span class="nf">usart3</span><span class="p">(</span><span class="n">cx</span><span class="p">:</span> <span class="nn">usart3</span><span class="p">::</span><span class="n">Context</span><span class="p">)</span> <span class="p">{</span>
        <span class="c1">// receive data from USART</span>
        <span class="c1">// write to the queue</span>
    <span class="p">}</span>

    <span class="nd">#[task(schedule</span> <span class="nd">=</span> <span class="err">[</span><span class="nd">tx_write]</span><span class="p">,</span> <span class="n">resources</span> <span class="o">=</span> <span class="p">[</span><span class="n">cons</span><span class="p">,</span> <span class="n">tx</span><span class="p">])]</span>
    <span class="k">fn</span> <span class="nf">tx_write</span><span class="p">(</span><span class="n">cx</span><span class="p">:</span> <span class="nn">tx_write</span><span class="p">::</span><span class="n">Context</span><span class="p">)</span> <span class="p">{</span>
        <span class="c1">// read from the queue and write to USART</span>
        <span class="c1">// reschedule tx_write</span>
    <span class="p">}</span>

    <span class="c1">// This is required for the software task fn tx_write()</span>
    <span class="c1">// This can be any interrupt not used by the hardware</span>
    <span class="k">extern</span> <span class="s">"C"</span> <span class="p">{</span>
        <span class="k">fn</span> <span class="nf">USART1</span><span class="p">();</span>
    <span class="p">}</span>
<span class="p">};</span>
</code></pre></div></div>

<p>There are two tasks here: <code class="language-plaintext highlighter-rouge">usart3</code> and <code class="language-plaintext highlighter-rouge">tx_write</code>.</p>

<p><code class="language-plaintext highlighter-rouge">usart3</code> is a hardware task. We enable RX interrupt in <code class="language-plaintext highlighter-rouge">init</code>.</p>

<p><code class="language-plaintext highlighter-rouge">tx_write</code> is the software task we want to focus on.</p>

<h3 id="schedule-a-task-to-run-sometime-in-the-future">Schedule a task to run sometime in the future</h3>

<p>To schedule a task, we use a <code class="language-plaintext highlighter-rouge">Monotonic</code> timer.</p>

<p>Let’s look at the <code class="language-plaintext highlighter-rouge">#[app]</code> attribute where we specify the microcontroller’s 32-bit cycle counter as our monotonic timer.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">#[rtfm::app(device</span> <span class="nd">=</span> <span class="nd">hal::stm32,</span> 
	<span class="nd">peripherals</span> <span class="nd">=</span> <span class="kc">true</span><span class="nd">,</span> 
	<span class="nd">monotonic</span> <span class="nd">=</span> <span class="nd">rtfm::cyccnt::CYCCNT)]</span>
</code></pre></div></div>

<p>Since we set the system clock to 16MHz, clocking 16,000,000 times equals to 1 second. We declare a constant like this.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">const</span> <span class="n">PERIOD</span><span class="p">:</span> <span class="nb">u32</span> <span class="o">=</span> <span class="mi">16_000_000</span><span class="p">;</span>
</code></pre></div></div>

<p>Just like we specify which resources to use in the context attribute, we need to pass tasks to the schedule arguments of the context attribute.</p>

<p>Let’s look at <code class="language-plaintext highlighter-rouge">init</code> and <code class="language-plaintext highlighter-rouge">tx_write</code> where we schedule tasks. See we have <code class="language-plaintext highlighter-rouge">schedule</code> argument in the context attribute. We pass our <code class="language-plaintext highlighter-rouge">tx_write</code> as an argument.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code>    <span class="nd">#[init(schedule</span> <span class="nd">=</span> <span class="err">[</span><span class="nd">tx_write]</span><span class="p">)]</span>
    <span class="k">fn</span> <span class="nf">init</span><span class="p">(</span><span class="n">cx</span><span class="p">:</span> <span class="nn">init</span><span class="p">::</span><span class="n">Context</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="nn">init</span><span class="p">::</span><span class="n">LateResources</span> <span class="p">{</span>
	    <span class="n">cx</span><span class="py">.schedule</span>
	        <span class="nf">.tx_write</span><span class="p">(</span><span class="n">cx</span><span class="py">.start</span> <span class="o">+</span> <span class="n">PERIOD</span><span class="nf">.cycles</span><span class="p">())</span>
	        <span class="nf">.unwrap</span><span class="p">();</span>
		<span class="c1">// ...</span>
    <span class="p">}</span>

    <span class="nd">#[task(schedule</span> <span class="nd">=</span> <span class="err">[</span><span class="nd">tx_write]</span><span class="p">,</span> <span class="n">resources</span> <span class="o">=</span> <span class="p">[</span><span class="n">cons</span><span class="p">,</span> <span class="n">tx</span><span class="p">])]</span>
    <span class="k">fn</span> <span class="nf">tx_write</span><span class="p">(</span><span class="n">cx</span><span class="p">:</span> <span class="nn">tx_write</span><span class="p">::</span><span class="n">Context</span><span class="p">)</span> <span class="p">{</span>
		<span class="n">cx</span><span class="py">.schedule</span>
	        <span class="nf">.tx_write</span><span class="p">(</span><span class="n">cx</span><span class="py">.scheduled</span> <span class="o">+</span> <span class="n">PERIOD</span><span class="nf">.cycles</span><span class="p">())</span>
	        <span class="nf">.unwrap</span><span class="p">();</span>
        <span class="c1">// ...</span>
    <span class="p">}</span>

</code></pre></div></div>

<p>In the tasks, we schedule a task by calling <code class="language-plaintext highlighter-rouge">Context</code>’s <code class="language-plaintext highlighter-rouge">schedule</code> API. In <code class="language-plaintext highlighter-rouge">init()</code>, we schedule <code class="language-plaintext highlighter-rouge">tx_write</code> to run 16,000,000 cycles (= 1 second) in the future.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">cx</span><span class="py">.schedule</span><span class="nf">.tx_write</span><span class="p">(</span><span class="n">cx</span><span class="py">.start</span> <span class="o">+</span> <span class="n">PERIOD</span><span class="nf">.cycles</span><span class="p">())</span><span class="nf">.unwrap</span><span class="p">();</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">cx.start</code> returns start time of the system, which should be <code class="language-plaintext highlighter-rouge">0</code>. The line above schedules a task to run after the specified cycles (<code class="language-plaintext highlighter-rouge">PERIOD: u32 = 16_000_000</code>).</p>

<p>In <code class="language-plaintext highlighter-rouge">tx_write</code>, we write to USART and reschedule a task so that it is called again after the specified clock cycles.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">cx</span><span class="py">.schedule</span><span class="nf">.tx_write</span><span class="p">(</span><span class="n">cx</span><span class="py">.scheduled</span> <span class="o">+</span> <span class="n">PERIOD</span><span class="nf">.cycles</span><span class="p">())</span><span class="nf">.unwrap</span><span class="p">();</span>
</code></pre></div></div>

<p>We  can access the previously scheduled time through <code class="language-plaintext highlighter-rouge">cx.scheduled</code>. We add 16,000,000 cycles to the whatever scheduled time.</p>

<p>Nice. We can now fire a task every second using RTFM framework.</p>

<h3 id="nvic-as-a-dispatcher">NVIC as a dispatcher</h3>
<p>By the way, you may wonder why we have these lines.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code>    <span class="k">extern</span> <span class="s">"C"</span> <span class="p">{</span>
        <span class="k">fn</span> <span class="nf">USART1</span><span class="p">();</span>
    <span class="p">}</span>
</code></pre></div></div>
<p>My understanding is that RTFM uses the NVIC to handle scheduling. We just need to specify enough unused extern interrupts so that RTFM can dispatch software tasks.</p>

<p>Since we only have one software task for this project, one is enough here. It doesn’t have to be <code class="language-plaintext highlighter-rouge">fn USART1()</code>. It can be <code class="language-plaintext highlighter-rouge">TIM2</code> or whatever interrupt not used by the hardware. If we have two software tasks with different priorities, we need two extern interrupts.</p>]]></content><author><name>lonesometraveler</name><email>lonesometraveler@mac.com</email></author><category term="Rust" /><category term="embedded" /><summary type="html"><![CDATA[This week, we will look at the task scheduling feature of the RTFM framework. This is a redo of the last project that reads when new data is available on USART and sends the accumulated data through USART every second.]]></summary></entry><entry><title type="html">Serial Communication with RTFM</title><link href="https://lonesometraveler.github.io/2020/05/29/RTFM-2.html" rel="alternate" type="text/html" title="Serial Communication with RTFM" /><published>2020-05-29T15:05:48+00:00</published><updated>2020-05-29T15:05:48+00:00</updated><id>https://lonesometraveler.github.io/2020/05/29/RTFM-2</id><content type="html" xml:base="https://lonesometraveler.github.io/2020/05/29/RTFM-2.html"><![CDATA[<p>Our experiment with RTFM continues. This week’s project involves USART read/write and Timer interrupt. We will read when new data is available on USART, and send the accumulated data through USART every second.</p>

<p><strong>Hardware</strong></p>

<ul>
  <li><a href="https://www.st.com/en/evaluation-tools/nucleo-f429zi.html">Nucleo-F429ZI</a></li>
</ul>

<p><strong>Crates</strong></p>

<ul>
  <li><a href="https://crates.io/crates/stm32f4xx-hal">stm32f4xx-hal</a></li>
  <li><a href="https://crates.io/crates/cortex-m-rtfm">cortex-m-rtfm</a></li>
  <li><a href="https://github.com/jamesmunns/bbqueue">BBQueue</a></li>
</ul>

<p><strong>Code</strong></p>

<p>Full code is available on <a href="https://github.com/lonesometraveler/stm32f4xx-examples/blob/master/examples/rtfm_1.rs">GitHub</a></p>

<h2 id="implementation">Implementation</h2>

<p>Here are three things we need to implement:</p>

<ol>
  <li>initialize USART TX, RX, Timer, and producer/consumer for a global shared buffer and store them for later use.</li>
  <li>When new data arrives on USART, enter an interrupt context to read the data and write it to the buffer.</li>
  <li>Every second, retrieve available data from the buffer and send them through USART.</li>
</ol>

<p>Here is the pseudo code:</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">#[rtfm::app(device</span> <span class="nd">=</span> <span class="nd">hal::stm32,</span> <span class="nd">peripherals</span> <span class="nd">=</span> <span class="kc">true</span><span class="nd">)]</span>
<span class="k">const</span> <span class="n">APP</span><span class="p">:</span> <span class="p">()</span> <span class="o">=</span> <span class="p">{</span>
    <span class="k">struct</span> <span class="n">Resources</span> <span class="p">{</span>
        <span class="n">cons</span><span class="p">:</span> <span class="n">Consumer</span><span class="o">&lt;</span><span class="k">'static</span><span class="p">,</span> <span class="n">U1024</span><span class="o">&gt;</span><span class="p">,</span>
        <span class="n">prod</span><span class="p">:</span> <span class="n">Producer</span><span class="o">&lt;</span><span class="k">'static</span><span class="p">,</span> <span class="n">U1024</span><span class="o">&gt;</span><span class="p">,</span>
        <span class="n">tx</span><span class="p">:</span> <span class="nn">hal</span><span class="p">::</span><span class="nn">serial</span><span class="p">::</span><span class="n">Tx</span><span class="o">&lt;</span><span class="n">USART3</span><span class="o">&gt;</span><span class="p">,</span>
        <span class="n">rx</span><span class="p">:</span> <span class="nn">hal</span><span class="p">::</span><span class="nn">serial</span><span class="p">::</span><span class="n">Rx</span><span class="o">&lt;</span><span class="n">USART3</span><span class="o">&gt;</span><span class="p">,</span>
        <span class="n">timer</span><span class="p">:</span> <span class="n">Timer</span><span class="o">&lt;</span><span class="nn">stm32</span><span class="p">::</span><span class="n">TIM2</span><span class="o">&gt;</span><span class="p">,</span>
    <span class="p">}</span>

    <span class="nd">#[init]</span>
    <span class="k">fn</span> <span class="nf">init</span><span class="p">(</span><span class="n">cx</span><span class="p">:</span> <span class="nn">init</span><span class="p">::</span><span class="n">Context</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="nn">init</span><span class="p">::</span><span class="n">LateResources</span> <span class="p">{</span>
        <span class="c1">// initialization of resources</span>
		<span class="c1">// ...</span>

        <span class="nn">init</span><span class="p">::</span><span class="n">LateResources</span> <span class="p">{</span>
            <span class="n">cons</span><span class="p">,</span>
            <span class="n">prod</span><span class="p">,</span>
            <span class="n">tx</span><span class="p">,</span>
            <span class="n">rx</span><span class="p">,</span>
            <span class="n">timer</span><span class="p">,</span>
        <span class="p">}</span>
    <span class="p">}</span>

    <span class="c1">// UART interrupt</span>
    <span class="nd">#[task(binds</span> <span class="nd">=</span> <span class="nd">USART3,</span> <span class="nd">resources</span> <span class="nd">=</span> <span class="err">[</span><span class="nd">prod,</span> <span class="nd">rx]</span><span class="p">)]</span>
    <span class="k">fn</span> <span class="nf">usart3</span><span class="p">(</span><span class="n">cx</span><span class="p">:</span> <span class="nn">usart3</span><span class="p">::</span><span class="n">Context</span><span class="p">)</span> <span class="p">{</span>
		<span class="c1">// read from the RX buffer and write to the queue</span>
    <span class="p">}</span>

    <span class="c1">// Timer interrupt </span>
    <span class="nd">#[task(binds</span> <span class="nd">=</span> <span class="nd">TIM2,</span> <span class="nd">resources</span> <span class="nd">=</span> <span class="err">[</span><span class="nd">timer,</span> <span class="nd">cons,</span> <span class="nd">tx]</span><span class="p">)]</span>
    <span class="k">fn</span> <span class="nf">tim2</span><span class="p">(</span><span class="n">cx</span><span class="p">:</span> <span class="nn">tim2</span><span class="p">::</span><span class="n">Context</span><span class="p">)</span> <span class="p">{</span>
        <span class="c1">// read the currently available data from the queue and write to the TX buffer</span>
    <span class="p">}</span>
<span class="p">};</span>
</code></pre></div></div>

<h3 id="bbqueue-a-spsc-lockless-no_std-thread-safe-queue">BBQueue: A SPSC, lockless, no_std, thread safe, queue</h3>

<p>The challenge is how to write and read the shared buffer. Writing to the buffer occurs in USART ISR contexts and reading from it occurs in Timer ISR contexts. For this project, we use <a href="https://github.com/jamesmunns/bbqueue">BBQueue</a>, First-In-First-Out queue, to safely perform write/read transactions.</p>

<p>First, we create a large enough buffer. Here is how we create a buffer with 1024 elements.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">static</span> <span class="n">BB</span><span class="p">:</span> <span class="n">BBBuffer</span><span class="o">&lt;</span><span class="n">U1024</span><span class="o">&gt;</span> <span class="o">=</span> <span class="nf">BBBuffer</span><span class="p">(</span><span class="nn">ConstBBBuffer</span><span class="p">::</span><span class="nf">new</span><span class="p">());</span>
</code></pre></div></div>

<p>To access the buffer, we use <code class="language-plaintext highlighter-rouge">Producer</code> and <code class="language-plaintext highlighter-rouge">Consumer</code>. In <code class="language-plaintext highlighter-rouge">init()</code>, we split BBQueue <code class="language-plaintext highlighter-rouge">Producer</code> and <code class="language-plaintext highlighter-rouge">Consumer</code> and store them in our <code class="language-plaintext highlighter-rouge">Resources</code>. We will later use <code class="language-plaintext highlighter-rouge">prod</code> (for writing) in the USART ISR and <code class="language-plaintext highlighter-rouge">cons</code> (for reading) in the Timer ISR.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">#[init]</span>
<span class="k">fn</span> <span class="nf">init</span><span class="p">(</span><span class="n">cx</span><span class="p">:</span> <span class="nn">init</span><span class="p">::</span><span class="n">Context</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="nn">init</span><span class="p">::</span><span class="n">LateResources</span> <span class="p">{</span>
	<span class="c1">// Set up USART, Timer</span>
	<span class="c1">// ...</span>

    <span class="c1">// Split bbqueue Producer and Consumer</span>
    <span class="k">let</span> <span class="p">(</span><span class="n">prod</span><span class="p">,</span> <span class="n">cons</span><span class="p">)</span> <span class="o">=</span> <span class="n">BB</span><span class="nf">.try_split</span><span class="p">()</span><span class="nf">.unwrap</span><span class="p">();</span>

    <span class="c1">// Initialization of late resources</span>
    <span class="nn">init</span><span class="p">::</span><span class="n">LateResources</span> <span class="p">{</span>
        <span class="n">cons</span><span class="p">,</span>
        <span class="n">prod</span><span class="p">,</span>
        <span class="n">tx</span><span class="p">,</span>
        <span class="n">rx</span><span class="p">,</span>
        <span class="n">timer</span><span class="p">,</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="usart-and-timer-resources">USART and Timer Resources</h3>

<p>The initialization of USART resources is straightforward. Crate a <code class="language-plaintext highlighter-rouge">Serial</code> instance with pins and clocks. When we call <code class="language-plaintext highlighter-rouge">listen(SerialEvent::Rxne)</code>, our <code class="language-plaintext highlighter-rouge">Serial</code> starts listening on RX and triggers an interrupt when a new data arrives. Finally, we split TX and RX so that we can use them in separate contexts.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="n">gpioc</span> <span class="o">=</span> <span class="n">cx</span><span class="py">.device.GPIOC</span><span class="nf">.split</span><span class="p">();</span>
<span class="k">let</span> <span class="n">tx</span> <span class="o">=</span> <span class="n">gpioc</span><span class="py">.pc10</span><span class="nf">.into_alternate_af7</span><span class="p">();</span>
<span class="k">let</span> <span class="n">rx</span> <span class="o">=</span> <span class="n">gpioc</span><span class="py">.pc11</span><span class="nf">.into_alternate_af7</span><span class="p">();</span>
<span class="k">let</span> <span class="k">mut</span> <span class="n">serial</span> <span class="o">=</span> <span class="nn">Serial</span><span class="p">::</span><span class="nf">usart3</span><span class="p">(</span>
    <span class="n">cx</span><span class="py">.device.USART3</span><span class="p">,</span>
    <span class="p">(</span><span class="n">tx</span><span class="p">,</span> <span class="n">rx</span><span class="p">),</span>
    <span class="nn">Config</span><span class="p">::</span><span class="nf">default</span><span class="p">()</span><span class="nf">.baudrate</span><span class="p">(</span><span class="mi">9_600</span><span class="nf">.bps</span><span class="p">()),</span>
    <span class="n">clocks</span><span class="p">,</span>
<span class="p">)</span>
<span class="nf">.unwrap</span><span class="p">();</span>
<span class="c1">// Start listening on RX</span>
<span class="n">serial</span><span class="nf">.listen</span><span class="p">(</span><span class="nn">SerialEvent</span><span class="p">::</span><span class="n">Rxne</span><span class="p">);</span>
<span class="c1">// Split TX and RX</span>
<span class="k">let</span> <span class="p">(</span><span class="n">tx</span><span class="p">,</span> <span class="n">rx</span><span class="p">)</span> <span class="o">=</span> <span class="n">serial</span><span class="nf">.split</span><span class="p">();</span>
</code></pre></div></div>

<p>We also initialize a Timer in <code class="language-plaintext highlighter-rouge">init()</code> and let it start running.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="k">mut</span> <span class="n">timer</span> <span class="o">=</span> <span class="nn">Timer</span><span class="p">::</span><span class="nf">tim2</span><span class="p">(</span><span class="n">cx</span><span class="py">.device.TIM2</span><span class="p">,</span> <span class="mi">1</span><span class="nf">.hz</span><span class="p">(),</span> <span class="n">clocks</span><span class="p">);</span>
<span class="n">timer</span><span class="nf">.listen</span><span class="p">(</span><span class="nn">TimerEvent</span><span class="p">::</span><span class="n">TimeOut</span><span class="p">);</span>
</code></pre></div></div>

<p>After initializing all the resources, we store them as <code class="language-plaintext highlighter-rouge">LateResources </code>.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nn">init</span><span class="p">::</span><span class="n">LateResources</span> <span class="p">{</span>
    <span class="n">cons</span><span class="p">,</span>
    <span class="n">prod</span><span class="p">,</span>
    <span class="n">tx</span><span class="p">,</span>
    <span class="n">rx</span><span class="p">,</span>
    <span class="n">timer</span><span class="p">,</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="interrupt-handlers">Interrupt Handlers</h3>

<p>Now, let’s look at the interrupt handlers. <code class="language-plaintext highlighter-rouge">USART3</code> interrupt is handled like this.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">#[task(binds</span> <span class="nd">=</span> <span class="nd">USART3,</span> <span class="nd">resources</span> <span class="nd">=</span> <span class="err">[</span><span class="nd">prod,</span> <span class="nd">rx]</span><span class="p">)]</span>
<span class="k">fn</span> <span class="nf">usart3</span><span class="p">(</span><span class="n">cx</span><span class="p">:</span> <span class="nn">usart3</span><span class="p">::</span><span class="n">Context</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">match</span> <span class="nd">block!</span><span class="p">(</span><span class="n">cx</span><span class="py">.resources.rx</span><span class="nf">.read</span><span class="p">())</span> <span class="p">{</span>
        <span class="nf">Ok</span><span class="p">(</span><span class="n">byte</span><span class="p">)</span> <span class="k">=&gt;</span> <span class="p">{</span>
            <span class="k">if</span> <span class="k">let</span> <span class="nf">Ok</span><span class="p">(</span><span class="k">mut</span> <span class="n">wgr</span><span class="p">)</span> <span class="o">=</span> <span class="n">cx</span><span class="py">.resources.prod</span><span class="nf">.grant_exact</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
                <span class="n">wgr</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="n">byte</span><span class="p">;</span>
                <span class="n">wgr</span><span class="nf">.commit</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span>
            <span class="p">}</span>
        <span class="p">}</span>
        <span class="nf">Err</span><span class="p">(</span><span class="n">error</span><span class="p">)</span> <span class="k">=&gt;</span> <span class="p">{</span>
            <span class="nd">iprintln!</span><span class="p">(</span><span class="nf">itm</span><span class="p">(),</span> <span class="s">"[RX] Err: {:?}"</span><span class="p">,</span> <span class="n">error</span><span class="p">);</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">binds = USART3</code> establishes a link to USART3 hardware interrupt. In this ISR context, we use <code class="language-plaintext highlighter-rouge">rx: hal::serial::Rx&lt;USART3&gt;</code> to read a new byte and write to the buffer using <code class="language-plaintext highlighter-rouge">prod: bbqueue::Producer</code>.</p>

<p><code class="language-plaintext highlighter-rouge">prod.grant_exact(1)</code> request space for one byte. We write the value of the received byte to it and call <code class="language-plaintext highlighter-rouge">commit</code>. Committing returns the space for later use. Next time around, we request another grant and write a new value.</p>

<p>While we accumulate incoming data and put them in the buffer in USART interrupts, we read from the buffer and send the data out through USART’s TX in Timer interrupts.</p>

<p>Here is the <code class="language-plaintext highlighter-rouge">TIM2</code> interrupt handler.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">#[task(binds</span> <span class="nd">=</span> <span class="nd">TIM2,</span> <span class="nd">resources</span> <span class="nd">=</span> <span class="err">[</span><span class="nd">timer,</span> <span class="nd">cons,</span> <span class="nd">tx]</span><span class="p">)]</span>
<span class="k">fn</span> <span class="nf">tim2</span><span class="p">(</span><span class="n">cx</span><span class="p">:</span> <span class="nn">tim2</span><span class="p">::</span><span class="n">Context</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">cx</span><span class="py">.resources.timer</span><span class="nf">.clear_interrupt</span><span class="p">(</span><span class="nn">TimerEvent</span><span class="p">::</span><span class="n">TimeOut</span><span class="p">);</span>
    <span class="k">let</span> <span class="n">rgr</span> <span class="o">=</span> <span class="k">match</span> <span class="n">cx</span><span class="py">.resources.cons</span><span class="nf">.read</span><span class="p">()</span> <span class="p">{</span>
        <span class="nf">Ok</span><span class="p">(</span><span class="n">it</span><span class="p">)</span> <span class="k">=&gt;</span> <span class="n">it</span><span class="p">,</span>
        <span class="n">_</span> <span class="k">=&gt;</span> <span class="k">return</span><span class="p">,</span>
    <span class="p">};</span>
    
    <span class="n">rgr</span><span class="nf">.buf</span><span class="p">()</span>
        <span class="nf">.iter</span><span class="p">()</span>
        <span class="nf">.for_each</span><span class="p">(|</span><span class="o">&amp;</span><span class="n">byte</span><span class="p">|</span> <span class="nd">block!</span><span class="p">(</span><span class="n">cx</span><span class="py">.resources.tx</span><span class="nf">.write</span><span class="p">(</span><span class="n">byte</span><span class="p">))</span><span class="nf">.unwrap</span><span class="p">());</span>

    <span class="c1">// Release the space for later writes</span>
    <span class="k">let</span> <span class="n">len</span> <span class="o">=</span> <span class="n">rgr</span><span class="nf">.len</span><span class="p">();</span>
    <span class="n">rgr</span><span class="nf">.release</span><span class="p">(</span><span class="n">len</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>
<p>We use <code class="language-plaintext highlighter-rouge">cons: bbqueue::Consumer</code> to read the buffer. When the buffer is empty, <code class="language-plaintext highlighter-rouge">cons.read()</code> returns <code class="language-plaintext highlighter-rouge">Err</code>. If there are bytes to read, we access the data slice by calling <code class="language-plaintext highlighter-rouge">buf()</code>. The size of the slice could be anywhere between 1 byte and the size of the buffer. Whatever the size is, it is guaranteed to be contiguous.</p>

<p>We then iterate through it and write to TX. When we are done with writing, we <code class="language-plaintext highlighter-rouge">release</code> the space for later writes.</p>]]></content><author><name>lonesometraveler</name><email>lonesometraveler@mac.com</email></author><category term="Rust" /><category term="embedded" /><summary type="html"><![CDATA[Our experiment with RTFM continues. This week’s project involves USART read/write and Timer interrupt. We will read when new data is available on USART, and send the accumulated data through USART every second.]]></summary></entry><entry><title type="html">Rust’s Real Time For the Masses (RTFM): Between bare metal and Real Time OS</title><link href="https://lonesometraveler.github.io/2020/05/22/RTFM.html" rel="alternate" type="text/html" title="Rust’s Real Time For the Masses (RTFM): Between bare metal and Real Time OS" /><published>2020-05-22T23:45:41+00:00</published><updated>2020-05-22T23:45:41+00:00</updated><id>https://lonesometraveler.github.io/2020/05/22/RTFM</id><content type="html" xml:base="https://lonesometraveler.github.io/2020/05/22/RTFM.html"><![CDATA[<p>In this post, I will talk about my first experiment with <a href="https://github.com/rtfm-rs/cortex-m-rtfm">Real Time For the Masses (RTFM) Framework</a>. My understanding is that RTFM finds itself between bare metal and Real Time OS. Bare metal’s small footprint is great for a resource-constrained platform. But managing resources and tasks can be very difficult. Real Time OS provides rich features. However, it comes with so much overhead. RTFM provides an ability to easily schedule tasks and guarantees safe access to shared resources without much runtime overhead.</p>

<p>Here are RTFM’s features listed in <a href="https://rtfm.rs/0.5/book/en/preface.html">the doc</a>.</p>

<blockquote>
  <ul>
    <li>
      <p><strong>Tasks</strong> as the unit of concurrency. Tasks can be event triggered
(fired in response to asynchronous stimuli) or spawned by the application on
demand.</p>
    </li>
    <li>
      <p><strong>Message passing</strong> between tasks. Specifically, messages can be passed to
software tasks at spawn time.</p>
    </li>
    <li>
      <p><strong>A timer queue</strong>. Software tasks can be scheduled to run at some time
in the future. This feature can be used to implement periodic tasks.</p>
    </li>
    <li>
      <p>Support for prioritization of tasks and, thus, <strong>preemptive multitasking</strong>.</p>
    </li>
    <li>
      <p><strong>Efficient and data race free memory sharing</strong> through fine grained *priority
based* critical sections.</p>
    </li>
    <li>
      <p><strong>Deadlock free execution</strong> guaranteed at compile time. This is an stronger
guarantee than what’s provided by the standard Mutex
abstraction.</p>
    </li>
    <li>
      <p><strong>Minimal scheduling overhead</strong>. The task scheduler has minimal software
footprint; the hardware does the bulk of the scheduling.</p>
    </li>
    <li>
      <p><strong>Highly efficient memory usage</strong>: All the tasks share a single call stack and
there’s no hard dependency on a dynamic memory allocator.</p>
    </li>
  </ul>
</blockquote>

<h2 id="timer-interrupt-with-rtfm">Timer interrupt with RTFM</h2>

<p>This week’s program toggles an LED when triggered by timer interrupts.</p>

<p><strong>Hardware</strong></p>

<ul>
  <li><a href="https://www.st.com/en/evaluation-tools/nucleo-f429zi.html">Nucleo-F429ZI</a></li>
</ul>

<p><strong>Crates</strong></p>

<ul>
  <li><a href="https://crates.io/crates/stm32f4xx-hal">stm32f4xx-hal</a></li>
  <li><a href="https://crates.io/crates/cortex-m-rtfm">cortex-m-rtfm</a></li>
</ul>

<p><strong>Code</strong></p>

<p>Full code is available on <a href="https://github.com/lonesometraveler/stm32f4xx-examples/blob/master/examples/rtfm_2.rs">GitHub</a></p>

<h3 id="implementation">Implementation</h3>

<p>This experiment is a redo of <a href="https://github.com/lonesometraveler/stm32f4xx-examples/blob/master/examples/timer_interrupt_2.rs">my timer interrupt experiment from a few weeks ago</a>. Let’s look at how I did it without RTFM.</p>

<p><strong>Without RTFM</strong></p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">static</span> <span class="n">LED</span><span class="p">:</span> <span class="n">Mutex</span><span class="o">&lt;</span><span class="n">RefCell</span><span class="o">&lt;</span><span class="nb">Option</span><span class="o">&lt;</span><span class="n">PB7</span><span class="o">&lt;</span><span class="n">Output</span><span class="o">&lt;</span><span class="n">PushPull</span><span class="o">&gt;&gt;&gt;&gt;&gt;</span> <span class="o">=</span> <span class="nn">Mutex</span><span class="p">::</span><span class="nf">new</span><span class="p">(</span><span class="nn">RefCell</span><span class="p">::</span><span class="nf">new</span><span class="p">(</span><span class="nb">None</span><span class="p">));</span>
<span class="k">static</span> <span class="n">TIMER_TIM2</span><span class="p">:</span> <span class="n">Mutex</span><span class="o">&lt;</span><span class="n">RefCell</span><span class="o">&lt;</span><span class="nb">Option</span><span class="o">&lt;</span><span class="n">Timer</span><span class="o">&lt;</span><span class="nn">stm32</span><span class="p">::</span><span class="n">TIM2</span><span class="o">&gt;&gt;&gt;&gt;</span> <span class="o">=</span> <span class="nn">Mutex</span><span class="p">::</span><span class="nf">new</span><span class="p">(</span><span class="nn">RefCell</span><span class="p">::</span><span class="nf">new</span><span class="p">(</span><span class="nb">None</span><span class="p">));</span>

<span class="nd">#[entry]</span>
<span class="k">fn</span> <span class="nf">main</span><span class="p">()</span> <span class="k">-&gt;</span> <span class="o">!</span> <span class="p">{</span>
    <span class="k">let</span> <span class="n">dp</span> <span class="o">=</span> <span class="nn">stm32</span><span class="p">::</span><span class="nn">Peripherals</span><span class="p">::</span><span class="nf">take</span><span class="p">()</span><span class="nf">.unwrap</span><span class="p">();</span>
    <span class="k">let</span> <span class="n">rcc</span> <span class="o">=</span> <span class="n">dp</span><span class="py">.RCC</span><span class="nf">.constrain</span><span class="p">();</span>
    <span class="k">let</span> <span class="n">clocks</span> <span class="o">=</span> <span class="n">rcc</span><span class="py">.cfgr</span><span class="nf">.sysclk</span><span class="p">(</span><span class="mi">48</span><span class="nf">.mhz</span><span class="p">())</span><span class="nf">.freeze</span><span class="p">();</span>

    <span class="c1">// Set up the LED</span>
    <span class="k">let</span> <span class="n">gpiob</span> <span class="o">=</span> <span class="n">dp</span><span class="py">.GPIOB</span><span class="nf">.split</span><span class="p">();</span>
    <span class="k">let</span> <span class="n">led</span> <span class="o">=</span> <span class="n">gpiob</span><span class="py">.pb7</span><span class="nf">.into_push_pull_output</span><span class="p">();</span>

    <span class="c1">// Set up the timer</span>
    <span class="k">let</span> <span class="k">mut</span> <span class="n">timer</span> <span class="o">=</span> <span class="nn">Timer</span><span class="p">::</span><span class="nf">tim2</span><span class="p">(</span><span class="n">dp</span><span class="py">.TIM2</span><span class="p">,</span> <span class="mi">5</span><span class="nf">.hz</span><span class="p">(),</span> <span class="n">clocks</span><span class="p">);</span>
    <span class="n">timer</span><span class="nf">.listen</span><span class="p">(</span><span class="nn">Event</span><span class="p">::</span><span class="n">TimeOut</span><span class="p">);</span>
	
    <span class="c1">// Move shared resources to Mutex</span>
    <span class="nf">free</span><span class="p">(|</span><span class="n">cs</span><span class="p">|</span> <span class="p">{</span>
        <span class="n">TIMER_TIM2</span><span class="nf">.borrow</span><span class="p">(</span><span class="n">cs</span><span class="p">)</span><span class="nf">.replace</span><span class="p">(</span><span class="nf">Some</span><span class="p">(</span><span class="n">timer</span><span class="p">));</span>
        <span class="n">LED</span><span class="nf">.borrow</span><span class="p">(</span><span class="n">cs</span><span class="p">)</span><span class="nf">.replace</span><span class="p">(</span><span class="nf">Some</span><span class="p">(</span><span class="n">led</span><span class="p">));</span>
    <span class="p">});</span>

    <span class="c1">// Enable interrupt</span>
    <span class="nn">stm32</span><span class="p">::</span><span class="nn">NVIC</span><span class="p">::</span><span class="nf">unpend</span><span class="p">(</span><span class="nn">stm32</span><span class="p">::</span><span class="nn">Interrupt</span><span class="p">::</span><span class="n">TIM2</span><span class="p">);</span>
    <span class="k">unsafe</span> <span class="p">{</span>
        <span class="nn">stm32</span><span class="p">::</span><span class="nn">NVIC</span><span class="p">::</span><span class="nf">unmask</span><span class="p">(</span><span class="nn">stm32</span><span class="p">::</span><span class="nn">Interrupt</span><span class="p">::</span><span class="n">TIM2</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="k">loop</span> <span class="p">{}</span>
<span class="p">}</span>

<span class="nd">#[interrupt]</span>
<span class="k">fn</span> <span class="nf">TIM2</span><span class="p">()</span> <span class="p">{</span>
    <span class="nf">free</span><span class="p">(|</span><span class="n">cs</span><span class="p">|</span> <span class="p">{</span>
        <span class="k">if</span> <span class="k">let</span> <span class="nf">Some</span><span class="p">(</span><span class="k">ref</span> <span class="k">mut</span> <span class="n">tim2</span><span class="p">)</span> <span class="o">=</span> <span class="n">TIMER_TIM2</span><span class="nf">.borrow</span><span class="p">(</span><span class="n">cs</span><span class="p">)</span><span class="nf">.borrow_mut</span><span class="p">()</span><span class="nf">.deref_mut</span><span class="p">()</span> <span class="p">{</span>
            <span class="n">tim2</span><span class="nf">.clear_interrupt</span><span class="p">(</span><span class="nn">Event</span><span class="p">::</span><span class="n">TimeOut</span><span class="p">);</span>
        <span class="p">}</span>
        <span class="k">if</span> <span class="k">let</span> <span class="nf">Some</span><span class="p">(</span><span class="k">ref</span> <span class="k">mut</span> <span class="n">led</span><span class="p">)</span> <span class="o">=</span> <span class="n">LED</span><span class="nf">.borrow</span><span class="p">(</span><span class="n">cs</span><span class="p">)</span><span class="nf">.borrow_mut</span><span class="p">()</span><span class="nf">.deref_mut</span><span class="p">()</span> <span class="p">{</span>
            <span class="n">led</span><span class="nf">.toggle</span><span class="p">()</span><span class="nf">.unwrap</span><span class="p">();</span>
        <span class="p">}</span>
    <span class="p">});</span>
<span class="p">}</span>
</code></pre></div></div>

<p>The application does these:</p>
<ol>
  <li>use Mutex for shared resources that can be accessed from user and ISR contexts</li>
  <li>enable TIM2 interrupt with NVIC</li>
  <li>handle interrupt requests in <code class="language-plaintext highlighter-rouge">#[interrupt]</code> and toggle the LED</li>
</ol>

<p>Now, let’s do the same with RTFM. Implementation with RTFM looks like this.</p>

<p><strong>With RTFM</strong></p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">#[rtfm::app(device</span> <span class="nd">=</span> <span class="nd">hal::stm32,</span> <span class="nd">peripherals</span> <span class="nd">=</span> <span class="kc">true</span><span class="nd">)]</span>
<span class="k">const</span> <span class="n">APP</span><span class="p">:</span> <span class="p">()</span> <span class="o">=</span> <span class="p">{</span>
    <span class="k">struct</span> <span class="n">Resources</span> <span class="p">{</span>
        <span class="n">led</span><span class="p">:</span> <span class="n">PB7</span><span class="o">&lt;</span><span class="n">Output</span><span class="o">&lt;</span><span class="n">PushPull</span><span class="o">&gt;&gt;</span><span class="p">,</span>
        <span class="n">timer</span><span class="p">:</span> <span class="n">Timer</span><span class="o">&lt;</span><span class="nn">stm32</span><span class="p">::</span><span class="n">TIM2</span><span class="o">&gt;</span><span class="p">,</span>
    <span class="p">}</span>

    <span class="nd">#[init]</span>
    <span class="k">fn</span> <span class="nf">init</span><span class="p">(</span><span class="n">cx</span><span class="p">:</span> <span class="nn">init</span><span class="p">::</span><span class="n">Context</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="nn">init</span><span class="p">::</span><span class="n">LateResources</span> <span class="p">{</span>
        <span class="k">let</span> <span class="n">rcc</span> <span class="o">=</span> <span class="n">cx</span><span class="py">.device.RCC</span><span class="nf">.constrain</span><span class="p">();</span>
        <span class="k">let</span> <span class="n">clocks</span> <span class="o">=</span> <span class="n">rcc</span><span class="py">.cfgr</span><span class="nf">.freeze</span><span class="p">();</span>

        <span class="c1">// Set up the LED</span>
        <span class="k">let</span> <span class="n">gpiob</span> <span class="o">=</span> <span class="n">cx</span><span class="py">.device.GPIOB</span><span class="nf">.split</span><span class="p">();</span>
        <span class="k">let</span> <span class="n">led</span> <span class="o">=</span> <span class="n">gpiob</span><span class="py">.pb7</span><span class="nf">.into_push_pull_output</span><span class="p">();</span>

        <span class="c1">// Set up the timer</span>
        <span class="k">let</span> <span class="k">mut</span> <span class="n">timer</span> <span class="o">=</span> <span class="nn">Timer</span><span class="p">::</span><span class="nf">tim2</span><span class="p">(</span><span class="n">cx</span><span class="py">.device.TIM2</span><span class="p">,</span> <span class="mi">5</span><span class="nf">.hz</span><span class="p">(),</span> <span class="n">clocks</span><span class="p">);</span>
        <span class="n">timer</span><span class="nf">.listen</span><span class="p">(</span><span class="nn">Event</span><span class="p">::</span><span class="n">TimeOut</span><span class="p">);</span>

        <span class="c1">// Initialization of late resources</span>
        <span class="nn">init</span><span class="p">::</span><span class="n">LateResources</span> <span class="p">{</span> <span class="n">led</span><span class="p">,</span> <span class="n">timer</span> <span class="p">}</span>
    <span class="p">}</span>

    <span class="nd">#[task(binds</span> <span class="nd">=</span> <span class="nd">TIM2,</span> <span class="nd">resources</span> <span class="nd">=</span> <span class="err">[</span><span class="nd">timer,</span> <span class="nd">led]</span><span class="p">)]</span>
    <span class="k">fn</span> <span class="nf">tim2</span><span class="p">(</span><span class="n">cx</span><span class="p">:</span> <span class="nn">tim2</span><span class="p">::</span><span class="n">Context</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">cx</span><span class="py">.resources.timer</span><span class="nf">.clear_interrupt</span><span class="p">(</span><span class="nn">Event</span><span class="p">::</span><span class="n">TimeOut</span><span class="p">);</span>
        <span class="n">cx</span><span class="py">.resources.led</span><span class="nf">.toggle</span><span class="p">()</span><span class="nf">.unwrap</span><span class="p">();</span>
    <span class="p">}</span>
<span class="p">};</span>
</code></pre></div></div>

<p>This looks very different from what we have seen so far. To start, there is no <code class="language-plaintext highlighter-rouge">#[entry]</code> attribute. This may be confusing. We are supposed to initialize resources, enable interrupts, and infinitely loop in <code class="language-plaintext highlighter-rouge">main</code> like this.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">#[entry]</span>
<span class="k">fn</span> <span class="nf">main</span><span class="p">()</span> <span class="k">-&gt;</span> <span class="o">!</span> <span class="p">{</span>
	<span class="c1">// configure pins, set up interrupt, wrap shared resouces with Mutex, etc.</span>
    <span class="k">loop</span> <span class="p">{}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Also, we can’t find <code class="language-plaintext highlighter-rouge">NVIC</code> anywhere either. Below is how we normally enable a timer interrupt without RTFM.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nn">stm32</span><span class="p">::</span><span class="nn">NVIC</span><span class="p">::</span><span class="nf">unpend</span><span class="p">(</span><span class="nn">Interrupt</span><span class="p">::</span><span class="n">TIM2</span><span class="p">);</span>
<span class="k">unsafe</span> <span class="p">{</span>
    <span class="nn">stm32</span><span class="p">::</span><span class="nn">NVIC</span><span class="p">::</span><span class="nf">unmask</span><span class="p">(</span><span class="nn">Interrupt</span><span class="p">::</span><span class="n">TIM2</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>So, where are our <code class="language-plaintext highlighter-rouge">#[entry]</code> and functions to enable interrupts?</p>

<p>RTFM framework uses macros. When we use attributes like <code class="language-plaintext highlighter-rouge">#[init]</code> and <code class="language-plaintext highlighter-rouge">#[task]</code>, they expand and generate <code class="language-plaintext highlighter-rouge">main</code> and all that.</p>

<p>Code generation happens in the background and we don’t need to see the expanded code. We can just build an app and flash it to a device. But I think it is a good idea to see what exactly RTFM is doing first. At least for me, seeing the expanded code helped me understand what was going on.</p>

<p><strong>Expanded Code</strong></p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">#[allow(non_snake_case)]</span>
<span class="k">fn</span> <span class="nf">init</span><span class="p">(</span><span class="n">cx</span><span class="p">:</span> <span class="nn">init</span><span class="p">::</span><span class="n">Context</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="nn">init</span><span class="p">::</span><span class="n">LateResources</span> <span class="p">{</span>
    <span class="k">let</span> <span class="n">rcc</span> <span class="o">=</span> <span class="n">cx</span><span class="py">.device.RCC</span><span class="nf">.constrain</span><span class="p">();</span>
    <span class="k">let</span> <span class="n">clocks</span> <span class="o">=</span> <span class="n">rcc</span><span class="py">.cfgr</span><span class="nf">.freeze</span><span class="p">();</span>
    <span class="k">let</span> <span class="n">gpiob</span> <span class="o">=</span> <span class="n">cx</span><span class="py">.device.GPIOB</span><span class="nf">.split</span><span class="p">();</span>
    <span class="k">let</span> <span class="n">led</span> <span class="o">=</span> <span class="n">gpiob</span><span class="py">.pb7</span><span class="nf">.into_push_pull_output</span><span class="p">();</span>
    <span class="k">let</span> <span class="k">mut</span> <span class="n">timer</span> <span class="o">=</span> <span class="nn">Timer</span><span class="p">::</span><span class="nf">tim2</span><span class="p">(</span><span class="n">cx</span><span class="py">.device.TIM2</span><span class="p">,</span> <span class="mi">5</span><span class="nf">.hz</span><span class="p">(),</span> <span class="n">clocks</span><span class="p">);</span>
    <span class="n">timer</span><span class="nf">.listen</span><span class="p">(</span><span class="nn">Event</span><span class="p">::</span><span class="n">TimeOut</span><span class="p">);</span>
    <span class="nn">init</span><span class="p">::</span><span class="n">LateResources</span> <span class="p">{</span> <span class="n">led</span><span class="p">,</span> <span class="n">timer</span> <span class="p">}</span>
<span class="p">}</span>
<span class="nd">#[allow(non_snake_case)]</span>
<span class="k">fn</span> <span class="nf">tim2</span><span class="p">(</span><span class="n">cx</span><span class="p">:</span> <span class="nn">tim2</span><span class="p">::</span><span class="n">Context</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">use</span> <span class="nn">rtfm</span><span class="p">::</span><span class="n">Mutex</span> <span class="k">as</span> <span class="n">_</span><span class="p">;</span>
    <span class="n">cx</span><span class="py">.resources.timer</span><span class="nf">.clear_interrupt</span><span class="p">(</span><span class="nn">Event</span><span class="p">::</span><span class="n">TimeOut</span><span class="p">);</span>
    <span class="n">cx</span><span class="py">.resources.led</span><span class="nf">.toggle</span><span class="p">()</span><span class="nf">.unwrap</span><span class="p">();</span>
<span class="p">}</span>
<span class="nd">#[doc</span> <span class="nd">=</span> <span class="s">r" Resources initialized at runtime"</span><span class="nd">]</span>
<span class="nd">#[allow(non_snake_case)]</span>
<span class="k">pub</span> <span class="k">struct</span> <span class="n">initLateResources</span> <span class="p">{</span>
    <span class="k">pub</span> <span class="n">led</span><span class="p">:</span> <span class="n">PB7</span><span class="o">&lt;</span><span class="n">Output</span><span class="o">&lt;</span><span class="n">PushPull</span><span class="o">&gt;&gt;</span><span class="p">,</span>
    <span class="k">pub</span> <span class="n">timer</span><span class="p">:</span> <span class="n">Timer</span><span class="o">&lt;</span><span class="nn">stm32</span><span class="p">::</span><span class="n">TIM2</span><span class="o">&gt;</span><span class="p">,</span>
<span class="p">}</span>
<span class="nd">#[allow(non_snake_case)]</span>
<span class="nd">#[doc</span> <span class="nd">=</span> <span class="s">"Initialization function"</span><span class="nd">]</span>
<span class="k">pub</span> <span class="k">mod</span> <span class="n">init</span> <span class="p">{</span>
    <span class="nd">#[doc(inline)]</span>
    <span class="k">pub</span> <span class="k">use</span> <span class="k">super</span><span class="p">::</span><span class="n">initLateResources</span> <span class="k">as</span> <span class="n">LateResources</span><span class="p">;</span>
    <span class="nd">#[doc</span> <span class="nd">=</span> <span class="s">r" Execution context"</span><span class="nd">]</span>
    <span class="k">pub</span> <span class="k">struct</span> <span class="n">Context</span> <span class="p">{</span>
        <span class="nd">#[doc</span> <span class="nd">=</span> <span class="s">r" Core (Cortex-M) peripherals"</span><span class="nd">]</span>
        <span class="k">pub</span> <span class="n">core</span><span class="p">:</span> <span class="nn">rtfm</span><span class="p">::</span><span class="nn">export</span><span class="p">::</span><span class="n">Peripherals</span><span class="p">,</span>
        <span class="nd">#[doc</span> <span class="nd">=</span> <span class="s">r" Device peripherals"</span><span class="nd">]</span>
        <span class="k">pub</span> <span class="n">device</span><span class="p">:</span> <span class="nn">hal</span><span class="p">::</span><span class="nn">stm32</span><span class="p">::</span><span class="n">Peripherals</span><span class="p">,</span>
    <span class="p">}</span>
    <span class="k">impl</span> <span class="n">Context</span> <span class="p">{</span>
        <span class="nd">#[inline(always)]</span>
        <span class="k">pub</span> <span class="k">unsafe</span> <span class="k">fn</span> <span class="nf">new</span><span class="p">(</span><span class="n">core</span><span class="p">:</span> <span class="nn">rtfm</span><span class="p">::</span><span class="nn">export</span><span class="p">::</span><span class="n">Peripherals</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="k">Self</span> <span class="p">{</span>
            <span class="n">Context</span> <span class="p">{</span>
                <span class="n">device</span><span class="p">:</span> <span class="nn">hal</span><span class="p">::</span><span class="nn">stm32</span><span class="p">::</span><span class="nn">Peripherals</span><span class="p">::</span><span class="nf">steal</span><span class="p">(),</span>
                <span class="n">core</span><span class="p">,</span>
            <span class="p">}</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
<span class="nd">#[allow(non_snake_case)]</span>
<span class="nd">#[doc</span> <span class="nd">=</span> <span class="s">"Resources `tim2` has access to"</span><span class="nd">]</span>
<span class="k">pub</span> <span class="k">struct</span> <span class="n">tim2Resources</span><span class="o">&lt;</span><span class="nv">'a</span><span class="o">&gt;</span> <span class="p">{</span>
    <span class="k">pub</span> <span class="n">timer</span><span class="p">:</span> <span class="o">&amp;</span><span class="nv">'a</span> <span class="k">mut</span> <span class="n">Timer</span><span class="o">&lt;</span><span class="nn">stm32</span><span class="p">::</span><span class="n">TIM2</span><span class="o">&gt;</span><span class="p">,</span>
    <span class="k">pub</span> <span class="n">led</span><span class="p">:</span> <span class="o">&amp;</span><span class="nv">'a</span> <span class="k">mut</span> <span class="n">PB7</span><span class="o">&lt;</span><span class="n">Output</span><span class="o">&lt;</span><span class="n">PushPull</span><span class="o">&gt;&gt;</span><span class="p">,</span>
<span class="p">}</span>
<span class="nd">#[allow(non_snake_case)]</span>
<span class="nd">#[doc</span> <span class="nd">=</span> <span class="s">"Hardware task"</span><span class="nd">]</span>
<span class="k">pub</span> <span class="k">mod</span> <span class="n">tim2</span> <span class="p">{</span>
    <span class="nd">#[doc(inline)]</span>
    <span class="k">pub</span> <span class="k">use</span> <span class="k">super</span><span class="p">::</span><span class="n">tim2Resources</span> <span class="k">as</span> <span class="n">Resources</span><span class="p">;</span>
    <span class="nd">#[doc</span> <span class="nd">=</span> <span class="s">r" Execution context"</span><span class="nd">]</span>
    <span class="k">pub</span> <span class="k">struct</span> <span class="n">Context</span><span class="o">&lt;</span><span class="nv">'a</span><span class="o">&gt;</span> <span class="p">{</span>
        <span class="nd">#[doc</span> <span class="nd">=</span> <span class="s">r" Resources this task has access to"</span><span class="nd">]</span>
        <span class="k">pub</span> <span class="n">resources</span><span class="p">:</span> <span class="n">Resources</span><span class="o">&lt;</span><span class="nv">'a</span><span class="o">&gt;</span><span class="p">,</span>
    <span class="p">}</span>
    <span class="k">impl</span><span class="o">&lt;</span><span class="nv">'a</span><span class="o">&gt;</span> <span class="n">Context</span><span class="o">&lt;</span><span class="nv">'a</span><span class="o">&gt;</span> <span class="p">{</span>
        <span class="nd">#[inline(always)]</span>
        <span class="k">pub</span> <span class="k">unsafe</span> <span class="k">fn</span> <span class="nf">new</span><span class="p">(</span><span class="n">priority</span><span class="p">:</span> <span class="o">&amp;</span><span class="nv">'a</span> <span class="nn">rtfm</span><span class="p">::</span><span class="nn">export</span><span class="p">::</span><span class="n">Priority</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="k">Self</span> <span class="p">{</span>
            <span class="n">Context</span> <span class="p">{</span>
                <span class="n">resources</span><span class="p">:</span> <span class="nn">Resources</span><span class="p">::</span><span class="nf">new</span><span class="p">(</span><span class="n">priority</span><span class="p">),</span>
            <span class="p">}</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
<span class="nd">#[doc</span> <span class="nd">=</span> <span class="s">r" Implementation details"</span><span class="nd">]</span>
<span class="k">const</span> <span class="n">APP</span><span class="p">:</span> <span class="p">()</span> <span class="o">=</span> <span class="p">{</span>
    <span class="nd">#[doc</span> <span class="nd">=</span> <span class="s">r" Always include the device crate which contains the vector table"</span><span class="nd">]</span>
    <span class="k">use</span> <span class="nn">hal</span><span class="p">::</span><span class="n">stm32</span> <span class="k">as</span> <span class="n">_</span><span class="p">;</span>
    <span class="nd">#[cfg(core</span> <span class="nd">=</span> <span class="s">"1"</span><span class="nd">)]</span>
    <span class="nd">compile_error!</span><span class="p">(</span><span class="s">"specified 1 core but tried to compile for more than 1 core"</span><span class="p">);</span>
    <span class="nd">#[allow(non_upper_case_globals)]</span>
    <span class="nd">#[link_section</span> <span class="nd">=</span> <span class="s">".uninit.rtfm0"</span><span class="nd">]</span>
    <span class="k">static</span> <span class="k">mut</span> <span class="n">timer</span><span class="p">:</span> <span class="nn">core</span><span class="p">::</span><span class="nn">mem</span><span class="p">::</span><span class="n">MaybeUninit</span><span class="o">&lt;</span><span class="n">Timer</span><span class="o">&lt;</span><span class="nn">stm32</span><span class="p">::</span><span class="n">TIM2</span><span class="o">&gt;&gt;</span> <span class="o">=</span> <span class="nn">core</span><span class="p">::</span><span class="nn">mem</span><span class="p">::</span><span class="nn">MaybeUninit</span><span class="p">::</span><span class="nf">uninit</span><span class="p">();</span>
    <span class="nd">#[allow(non_upper_case_globals)]</span>
    <span class="nd">#[link_section</span> <span class="nd">=</span> <span class="s">".uninit.rtfm1"</span><span class="nd">]</span>
    <span class="k">static</span> <span class="k">mut</span> <span class="n">led</span><span class="p">:</span> <span class="nn">core</span><span class="p">::</span><span class="nn">mem</span><span class="p">::</span><span class="n">MaybeUninit</span><span class="o">&lt;</span><span class="n">PB7</span><span class="o">&lt;</span><span class="n">Output</span><span class="o">&lt;</span><span class="n">PushPull</span><span class="o">&gt;&gt;&gt;</span> <span class="o">=</span>
        <span class="nn">core</span><span class="p">::</span><span class="nn">mem</span><span class="p">::</span><span class="nn">MaybeUninit</span><span class="p">::</span><span class="nf">uninit</span><span class="p">();</span>
    <span class="nd">#[allow(non_snake_case)]</span>
    <span class="nd">#[no_mangle]</span>
    <span class="k">unsafe</span> <span class="k">fn</span> <span class="nf">TIM2</span><span class="p">()</span> <span class="p">{</span>
        <span class="k">const</span> <span class="n">PRIORITY</span><span class="p">:</span> <span class="nb">u8</span> <span class="o">=</span> <span class="mi">1u8</span><span class="p">;</span>
        <span class="nn">rtfm</span><span class="p">::</span><span class="nn">export</span><span class="p">::</span><span class="nf">run</span><span class="p">(</span><span class="n">PRIORITY</span><span class="p">,</span> <span class="p">||</span> <span class="p">{</span>
            <span class="k">crate</span><span class="p">::</span><span class="nf">tim2</span><span class="p">(</span><span class="nn">tim2</span><span class="p">::</span><span class="nn">Context</span><span class="p">::</span><span class="nf">new</span><span class="p">(</span><span class="o">&amp;</span><span class="nn">rtfm</span><span class="p">::</span><span class="nn">export</span><span class="p">::</span><span class="nn">Priority</span><span class="p">::</span><span class="nf">new</span><span class="p">(</span><span class="n">PRIORITY</span><span class="p">)))</span>
        <span class="p">});</span>
    <span class="p">}</span>
    <span class="k">impl</span><span class="o">&lt;</span><span class="nv">'a</span><span class="o">&gt;</span> <span class="n">tim2Resources</span><span class="o">&lt;</span><span class="nv">'a</span><span class="o">&gt;</span> <span class="p">{</span>
        <span class="nd">#[inline(always)]</span>
        <span class="k">unsafe</span> <span class="k">fn</span> <span class="nf">new</span><span class="p">(</span><span class="n">priority</span><span class="p">:</span> <span class="o">&amp;</span><span class="nv">'a</span> <span class="nn">rtfm</span><span class="p">::</span><span class="nn">export</span><span class="p">::</span><span class="n">Priority</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="k">Self</span> <span class="p">{</span>
            <span class="n">tim2Resources</span> <span class="p">{</span>
                <span class="n">timer</span><span class="p">:</span> <span class="o">&amp;</span><span class="k">mut</span> <span class="o">*</span><span class="n">timer</span><span class="nf">.as_mut_ptr</span><span class="p">(),</span>
                <span class="n">led</span><span class="p">:</span> <span class="o">&amp;</span><span class="k">mut</span> <span class="o">*</span><span class="n">led</span><span class="nf">.as_mut_ptr</span><span class="p">(),</span>
            <span class="p">}</span>
        <span class="p">}</span>
    <span class="p">}</span>
    <span class="nd">#[no_mangle]</span>
    <span class="k">unsafe</span> <span class="k">extern</span> <span class="s">"C"</span> <span class="k">fn</span> <span class="nf">main</span><span class="p">()</span> <span class="k">-&gt;</span> <span class="o">!</span> <span class="p">{</span>
        <span class="nn">rtfm</span><span class="p">::</span><span class="nn">export</span><span class="p">::</span><span class="nn">assert_send</span><span class="p">::</span><span class="o">&lt;</span><span class="n">PB7</span><span class="o">&lt;</span><span class="n">Output</span><span class="o">&lt;</span><span class="n">PushPull</span><span class="o">&gt;&gt;&gt;</span><span class="p">();</span>
        <span class="nn">rtfm</span><span class="p">::</span><span class="nn">export</span><span class="p">::</span><span class="nn">assert_send</span><span class="p">::</span><span class="o">&lt;</span><span class="n">Timer</span><span class="o">&lt;</span><span class="nn">stm32</span><span class="p">::</span><span class="n">TIM2</span><span class="o">&gt;&gt;</span><span class="p">();</span>
        <span class="nn">rtfm</span><span class="p">::</span><span class="nn">export</span><span class="p">::</span><span class="nn">interrupt</span><span class="p">::</span><span class="nf">disable</span><span class="p">();</span>
        <span class="k">let</span> <span class="k">mut</span> <span class="n">core</span><span class="p">:</span> <span class="nn">rtfm</span><span class="p">::</span><span class="nn">export</span><span class="p">::</span><span class="n">Peripherals</span> <span class="o">=</span> <span class="nn">core</span><span class="p">::</span><span class="nn">mem</span><span class="p">::</span><span class="nf">transmute</span><span class="p">(());</span>
        <span class="k">let</span> <span class="n">_</span> <span class="o">=</span> <span class="p">[();</span> <span class="p">((</span><span class="mi">1</span> <span class="o">&lt;&lt;</span> <span class="nn">hal</span><span class="p">::</span><span class="nn">stm32</span><span class="p">::</span><span class="n">NVIC_PRIO_BITS</span><span class="p">)</span> <span class="o">-</span> <span class="mi">1u8</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">)];</span>
        <span class="n">core</span><span class="py">.NVIC</span><span class="nf">.set_priority</span><span class="p">(</span>
            <span class="nn">hal</span><span class="p">::</span><span class="nn">stm32</span><span class="p">::</span><span class="nn">Interrupt</span><span class="p">::</span><span class="n">TIM2</span><span class="p">,</span>
            <span class="nn">rtfm</span><span class="p">::</span><span class="nn">export</span><span class="p">::</span><span class="nf">logical2hw</span><span class="p">(</span><span class="mi">1u8</span><span class="p">,</span> <span class="nn">hal</span><span class="p">::</span><span class="nn">stm32</span><span class="p">::</span><span class="n">NVIC_PRIO_BITS</span><span class="p">),</span>
        <span class="p">);</span>
        <span class="nn">rtfm</span><span class="p">::</span><span class="nn">export</span><span class="p">::</span><span class="nn">NVIC</span><span class="p">::</span><span class="nf">unmask</span><span class="p">(</span><span class="nn">hal</span><span class="p">::</span><span class="nn">stm32</span><span class="p">::</span><span class="nn">Interrupt</span><span class="p">::</span><span class="n">TIM2</span><span class="p">);</span>
        <span class="n">core</span><span class="py">.SCB.scr</span><span class="nf">.modify</span><span class="p">(|</span><span class="n">r</span><span class="p">|</span> <span class="n">r</span> <span class="p">|</span> <span class="mi">1</span> <span class="o">&lt;&lt;</span> <span class="mi">1</span><span class="p">);</span>
        <span class="k">let</span> <span class="n">late</span> <span class="o">=</span> <span class="nf">init</span><span class="p">(</span><span class="nn">init</span><span class="p">::</span><span class="nn">Context</span><span class="p">::</span><span class="nf">new</span><span class="p">(</span><span class="n">core</span><span class="nf">.into</span><span class="p">()));</span>
        <span class="n">led</span><span class="nf">.as_mut_ptr</span><span class="p">()</span><span class="nf">.write</span><span class="p">(</span><span class="n">late</span><span class="py">.led</span><span class="p">);</span>
        <span class="n">timer</span><span class="nf">.as_mut_ptr</span><span class="p">()</span><span class="nf">.write</span><span class="p">(</span><span class="n">late</span><span class="py">.timer</span><span class="p">);</span>
        <span class="nn">rtfm</span><span class="p">::</span><span class="nn">export</span><span class="p">::</span><span class="nn">interrupt</span><span class="p">::</span><span class="nf">enable</span><span class="p">();</span>
        <span class="k">loop</span> <span class="p">{</span>
            <span class="nn">rtfm</span><span class="p">::</span><span class="nn">export</span><span class="p">::</span><span class="nf">wfi</span><span class="p">()</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">};</span>
</code></pre></div></div>

<p>I find it very interesting to read the expanded code line by line. I can see <code class="language-plaintext highlighter-rouge">fn main()</code> at the bottom of the expanded code. In <code class="language-plaintext highlighter-rouge">main</code>, interrupt is enabled with <code class="language-plaintext highlighter-rouge">NVIC</code> and it infinitely waits for interrupts.</p>

<p>Although I don’t understand everything, it seems to me that resources are nicely managed with <code class="language-plaintext highlighter-rouge">mod</code>. I guess RTFM makes it a bit easier to handle resources and tasks.</p>

<h3 id="attributes">Attributes</h3>

<p>This is how our RTFM application is constructed.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">#[rtfm::app(device</span> <span class="nd">=</span> <span class="nd">hal::stm32,</span> <span class="nd">peripherals</span> <span class="nd">=</span> <span class="kc">true</span><span class="nd">)]</span>
<span class="k">const</span> <span class="n">APP</span><span class="p">:</span> <span class="p">()</span> <span class="o">=</span> <span class="p">{</span>

    <span class="k">struct</span> <span class="n">Resources</span> <span class="p">{</span>
        <span class="n">led</span><span class="p">:</span> <span class="n">PB7</span><span class="o">&lt;</span><span class="n">Output</span><span class="o">&lt;</span><span class="n">PushPull</span><span class="o">&gt;&gt;</span><span class="p">,</span>
        <span class="n">timer</span><span class="p">:</span> <span class="n">Timer</span><span class="o">&lt;</span><span class="nn">stm32</span><span class="p">::</span><span class="n">TIM2</span><span class="o">&gt;</span><span class="p">,</span>
    <span class="p">}</span>

    <span class="nd">#[init]</span>
    <span class="k">fn</span> <span class="p">(</span><span class="n">cx</span><span class="p">:</span> <span class="nn">init</span><span class="p">::</span><span class="n">Context</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="nn">init</span><span class="p">::</span><span class="n">LateResources</span>  <span class="p">{</span>
        <span class="c1">// omitted</span>
    <span class="p">}</span>
	
    <span class="c1">// not used for this week's experiment</span>
    <span class="c1">// #[idle]</span>
    <span class="c1">// fn idle(c: idle::Context) -&gt; ! {}</span>

    <span class="nd">#[task(binds</span> <span class="nd">=</span> <span class="nd">TIM2,</span> <span class="nd">resources</span> <span class="nd">=</span> <span class="err">[</span><span class="nd">timer,</span> <span class="nd">led]</span><span class="p">)]</span>
    <span class="k">fn</span> <span class="nf">tim2</span><span class="p">(</span><span class="n">c</span><span class="p">:</span> <span class="nn">tim2</span><span class="p">::</span><span class="n">Context</span><span class="p">)</span> <span class="p">{</span>
        <span class="c1">// omitted</span>
    <span class="p">}</span>
<span class="p">};</span>
</code></pre></div></div>
<p>Let’s look at the four attributes: <code class="language-plaintext highlighter-rouge">app</code>, <code class="language-plaintext highlighter-rouge">init</code>, <code class="language-plaintext highlighter-rouge">idle</code> and <code class="language-plaintext highlighter-rouge">task</code>.</p>

<h4 id="1app">1.<code class="language-plaintext highlighter-rouge">app</code></h4>

<p>All RTFM applications start with <code class="language-plaintext highlighter-rouge">app</code>.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">#[rtfm::app(device</span> <span class="nd">=</span> <span class="nd">hal::stm32,</span> <span class="nd">peripherals</span> <span class="nd">=</span> <span class="kc">true</span><span class="nd">)]</span>
<span class="k">const</span> <span class="nf">App</span><span class="p">():</span> <span class="o">=</span> <span class="p">{</span>
    <span class="c1">//</span>
<span class="p">}</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">device</code> argument is mandatory. We want to specify a path to our PAC crate here. In my case, it is <code class="language-plaintext highlighter-rouge">stm32f4xx-hal</code>’s <code class="language-plaintext highlighter-rouge">stm32</code>.</p>

<p><code class="language-plaintext highlighter-rouge">periperals = true</code> makes it possible to access PAC’s core and device modules. For example, <code class="language-plaintext highlighter-rouge">let rcc = cx.device.RCC.constrain();</code></p>

<h4 id="2-init">2. <code class="language-plaintext highlighter-rouge">init</code></h4>
<p><code class="language-plaintext highlighter-rouge">app</code> expects initialization functions in <code class="language-plaintext highlighter-rouge">#[init]</code>. This is the first thing that runs in an RTFM application. Interrupts are always disabled in this. We initialize resources in here.</p>

<h4 id="3-idle">3. <code class="language-plaintext highlighter-rouge">idle</code></h4>
<p>We don’t use this for this week’s experiment. But when we have this task, it runs after <code class="language-plaintext highlighter-rouge">init</code> with interrupt enabled.</p>

<h4 id="4-task">4. <code class="language-plaintext highlighter-rouge">task</code></h4>
<p><code class="language-plaintext highlighter-rouge">#[task]</code> attribute makes it possible to declare interrupt handler. Use <code class="language-plaintext highlighter-rouge">binds</code> to attach a handler to a specific interrupt.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">#[task(binds</span> <span class="nd">=</span> <span class="nd">UART0)]</span>
<span class="k">fn</span> <span class="nf">uart0</span><span class="p">(</span><span class="n">_</span><span class="p">:</span> <span class="nn">uart0</span><span class="p">::</span><span class="n">Context</span><span class="p">)</span> <span class="p">{</span>
    <span class="c1">//</span>
<span class="p">}</span>
</code></pre></div></div>
<p>It is possible to set priority using <code class="language-plaintext highlighter-rouge">priority</code> argument. A higher priority task preempts a lower priority task. If not specified, the priority is set to 1. (<code class="language-plaintext highlighter-rouge">idle</code> task has the lowest priority, 0.)</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">#[task(binds</span> <span class="nd">=</span> <span class="nd">UART0,</span> <span class="nd">priority</span> <span class="nd">=</span> <span class="mi">1</span><span class="nd">)]</span>
<span class="k">fn</span> <span class="nf">uart0</span><span class="p">(</span><span class="n">_</span><span class="p">:</span> <span class="nn">uart0</span><span class="p">::</span><span class="n">Context</span><span class="p">)</span> <span class="p">{</span>
    <span class="c1">//</span>
<span class="p">}</span>

<span class="nd">#[task(binds</span> <span class="nd">=</span> <span class="nd">UART1,</span> <span class="nd">priority</span> <span class="nd">=</span> <span class="mi">2</span><span class="nd">)]</span>
<span class="k">fn</span> <span class="nf">uart1</span><span class="p">(</span><span class="n">_</span><span class="p">:</span> <span class="nn">uart1</span><span class="p">::</span><span class="n">Context</span><span class="p">)</span> <span class="p">{</span>
    <span class="c1">//</span>
<span class="p">}</span>
</code></pre></div></div>

<p><a href="https://rtfm.rs/0.5/book/en/by-example/app.html">See the RTFM doc for more info</a>.</p>

<h3 id="shared-resources">Shared Resources</h3>

<p>Before <code class="language-plaintext highlighter-rouge">#[init]</code>, we have <code class="language-plaintext highlighter-rouge">Resources</code>. These are the late resources we want to initialize at runtime.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">struct</span> <span class="n">Resources</span> <span class="p">{</span>
    <span class="n">led</span><span class="p">:</span> <span class="n">PB7</span><span class="o">&lt;</span><span class="n">Output</span><span class="o">&lt;</span><span class="n">PushPull</span><span class="o">&gt;&gt;</span><span class="p">,</span>
    <span class="n">timer</span><span class="p">:</span> <span class="n">Timer</span><span class="o">&lt;</span><span class="nn">stm32</span><span class="p">::</span><span class="n">TIM2</span><span class="o">&gt;</span><span class="p">,</span>
<span class="p">}</span>
</code></pre></div></div>

<p>These are like Mutexes we used in a previous experiment.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">static</span> <span class="n">LED</span><span class="p">:</span> <span class="n">Mutex</span><span class="o">&lt;</span><span class="n">RefCell</span><span class="o">&lt;</span><span class="nb">Option</span><span class="o">&lt;</span><span class="n">PB7</span><span class="o">&lt;</span><span class="n">Output</span><span class="o">&lt;</span><span class="n">PushPull</span><span class="o">&gt;&gt;&gt;&gt;&gt;</span> 
    <span class="o">=</span> <span class="nn">Mutex</span><span class="p">::</span><span class="nf">new</span><span class="p">(</span><span class="nn">RefCell</span><span class="p">::</span><span class="nf">new</span><span class="p">(</span><span class="nb">None</span><span class="p">));</span>
    
<span class="k">static</span> <span class="n">TIMER_TIM2</span><span class="p">:</span> <span class="n">Mutex</span><span class="o">&lt;</span><span class="n">RefCell</span><span class="o">&lt;</span><span class="nb">Option</span><span class="o">&lt;</span><span class="n">Timer</span><span class="o">&lt;</span><span class="nn">stm32</span><span class="p">::</span><span class="n">TIM2</span><span class="o">&gt;&gt;&gt;&gt;</span> 
    <span class="o">=</span> <span class="nn">Mutex</span><span class="p">::</span><span class="nf">new</span><span class="p">(</span><span class="nn">RefCell</span><span class="p">::</span><span class="nf">new</span><span class="p">(</span><span class="nb">None</span><span class="p">));</span>
</code></pre></div></div>

<p>Instead of Mutex, RTFM uses <code class="language-plaintext highlighter-rouge">LateResources</code>. We declare <code class="language-plaintext highlighter-rouge">struct Resources</code> for all the resources we want to share across different contexts. These resources must be initialized in <code class="language-plaintext highlighter-rouge">init</code> and returned.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">struct</span> <span class="n">Resources</span> <span class="p">{</span>
    <span class="n">led</span><span class="p">:</span> <span class="n">PB7</span><span class="o">&lt;</span><span class="n">Output</span><span class="o">&lt;</span><span class="n">PushPull</span><span class="o">&gt;&gt;</span><span class="p">,</span>
    <span class="n">timer</span><span class="p">:</span> <span class="n">Timer</span><span class="o">&lt;</span><span class="nn">stm32</span><span class="p">::</span><span class="n">TIM2</span><span class="o">&gt;</span><span class="p">,</span>
<span class="p">}</span>

<span class="nd">#[init]</span>
<span class="k">fn</span> <span class="nf">init</span><span class="p">(</span><span class="n">cx</span><span class="p">:</span> <span class="nn">init</span><span class="p">::</span><span class="n">Context</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="nn">init</span><span class="p">::</span><span class="n">LateResources</span> <span class="p">{</span>
    <span class="k">let</span> <span class="n">rcc</span> <span class="o">=</span> <span class="n">cx</span><span class="py">.device.RCC</span><span class="nf">.constrain</span><span class="p">();</span>
    <span class="k">let</span> <span class="n">clocks</span> <span class="o">=</span> <span class="n">rcc</span><span class="py">.cfgr</span><span class="nf">.freeze</span><span class="p">();</span>

    <span class="c1">// Set up the LED</span>
    <span class="k">let</span> <span class="n">gpiob</span> <span class="o">=</span> <span class="n">cx</span><span class="py">.device.GPIOB</span><span class="nf">.split</span><span class="p">();</span>
    <span class="k">let</span> <span class="n">led</span> <span class="o">=</span> <span class="n">gpiob</span><span class="py">.pb7</span><span class="nf">.into_push_pull_output</span><span class="p">();</span>

    <span class="c1">// Set up the timer</span>
    <span class="k">let</span> <span class="k">mut</span> <span class="n">timer</span> <span class="o">=</span> <span class="nn">Timer</span><span class="p">::</span><span class="nf">tim2</span><span class="p">(</span><span class="n">cx</span><span class="py">.device.TIM2</span><span class="p">,</span> <span class="mi">5</span><span class="nf">.hz</span><span class="p">(),</span> <span class="n">clocks</span><span class="p">);</span>
    <span class="n">timer</span><span class="nf">.listen</span><span class="p">(</span><span class="nn">Event</span><span class="p">::</span><span class="n">TimeOut</span><span class="p">);</span>

    <span class="c1">// Initialization of late resources</span>
    <span class="nn">init</span><span class="p">::</span><span class="n">LateResources</span> <span class="p">{</span> <span class="n">led</span><span class="p">,</span> <span class="n">timer</span> <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>(* If we don’t have late resources, we don’t need to return anything.)</p>

<p>The resources can be safely accessed in tasks. Let’s look at our TIM2 interrupt handler.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">#[task(binds</span> <span class="nd">=</span> <span class="nd">TIM2,</span> <span class="nd">resources</span> <span class="nd">=</span> <span class="err">[</span><span class="nd">timer,</span> <span class="nd">led]</span><span class="p">)]</span>
<span class="k">fn</span> <span class="nf">tim2</span><span class="p">(</span><span class="n">cx</span><span class="p">:</span> <span class="nn">tim2</span><span class="p">::</span><span class="n">Context</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">cx</span><span class="py">.resources.timer</span><span class="nf">.clear_interrupt</span><span class="p">(</span><span class="nn">Event</span><span class="p">::</span><span class="n">TimeOut</span><span class="p">);</span>
    <span class="n">cx</span><span class="py">.resources.led</span><span class="nf">.toggle</span><span class="p">()</span><span class="nf">.unwrap</span><span class="p">();</span>
<span class="p">}</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">resources = [timer, led])</code> defines which resources we want to use in this context. We can access them by following a path from context to resources: <code class="language-plaintext highlighter-rouge">cx.resources.timer</code>, <code class="language-plaintext highlighter-rouge">cx.resources.led</code>.</p>

<p>In this interrupt handler, we, using the shared resources, clear the interrupt flag and toggle the LED just like non RTFM version.</p>

<p>That’s it. Our first experiment with RTFM. I am liking this framework. I will explore more in future projects.</p>]]></content><author><name>lonesometraveler</name><email>lonesometraveler@mac.com</email></author><category term="Rust" /><category term="embedded" /><summary type="html"><![CDATA[In this post, I will talk about my first experiment with Real Time For the Masses (RTFM) Framework. My understanding is that RTFM finds itself between bare metal and Real Time OS. Bare metal’s small footprint is great for a resource-constrained platform. But managing resources and tasks can be very difficult. Real Time OS provides rich features. However, it comes with so much overhead. RTFM provides an ability to easily schedule tasks and guarantees safe access to shared resources without much runtime overhead.]]></summary></entry><entry><title type="html">ADC: Injected Conversion Mode</title><link href="https://lonesometraveler.github.io/2020/05/15/ADC-Injected-Conversion.html" rel="alternate" type="text/html" title="ADC: Injected Conversion Mode" /><published>2020-05-15T15:15:41+00:00</published><updated>2020-05-15T15:15:41+00:00</updated><id>https://lonesometraveler.github.io/2020/05/15/ADC-Injected-Conversion</id><content type="html" xml:base="https://lonesometraveler.github.io/2020/05/15/ADC-Injected-Conversion.html"><![CDATA[<p>Our embedded Rust experiments on STM32 platform continues. This week, we explore ADC’s injected conversion mode. The application note <a href="https://www.st.com/resource/en/application_note/cd00258017-stm32s-adc-modes-and-their-applications-stmicroelectronics.pdf">AN3116</a> explains what injected conversion mode is.</p>

<blockquote>
  <p>This mode is intended for use when conversion is triggered by an external event or by software.
The injected group has priority over the regular channel group. It interrupts the conversion of the current channel in the regular channel group.</p>
</blockquote>

<p><img src="https://lonesometraveler.github.io/assets/injected-conversion-mode.png" alt="" /></p>

<p>Injected conversions can be triggered by software or by hardware (timers or external pins). Injected conversions have higher priority and they can interrupt regular conversions immediately. A use case I can think of is that we run regular sequence conversion in a loop or something and interrupt that when needed.</p>

<h2 id="components">Components</h2>

<p>Hardware</p>
<ul>
  <li><a href="https://www.st.com/en/evaluation-tools/nucleo-f429zi.html">Nucleo-F429ZI</a></li>
  <li>Potentiometer</li>
</ul>

<p>Crates</p>
<ul>
  <li><a href="https://crates.io/crates/stm32f4xx-hal"><code class="language-plaintext highlighter-rouge">stm32f4xx-hal</code></a> A Rust embedded-hal HAL for all MCUs in the STM32 F4 family</li>
</ul>

<p>Code</p>
<ul>
  <li><a href="https://github.com/lonesometraveler/stm32f4xx-examples/blob/master/examples/adc_interrupt_2.rs">The code is available on GitHub</a></li>
</ul>

<h2 id="implementation">Implementation</h2>

<p>This week’s experiment demonstrates injected conversion mode using a timer as an external trigger source. Here are the things this post covers:</p>

<ul>
  <li>Configure Timer (the trigger source) in PWM mode</li>
  <li>Configure ADC
    <ul>
      <li>Configure External Trigger source</li>
      <li>Set up an analog input pin</li>
      <li>Configure ADC channel with ADC peripheral and the analog pin</li>
    </ul>
  </li>
  <li>Enable ADC interrupt</li>
  <li>Read ADC value in ISR</li>
</ul>

<h3 id="configure-pwm">Configure PWM</h3>

<p>One way to configure a timer in PWM mode is to use <code class="language-plaintext highlighter-rouge">stm32f4xx-hal</code>’s <code class="language-plaintext highlighter-rouge">pwm</code> module. <code class="language-plaintext highlighter-rouge">pwm</code> module routes a timer’s output to an output pin. Although output from a pin is not required to use a timer as an external trigger, being able to see the pulse may be helpful for debugging/troubleshooting.</p>

<p>In the code below, we create a <code class="language-plaintext highlighter-rouge">pwm</code> instance with <code class="language-plaintext highlighter-rouge">TIM1</code> and set its frequency to 10Hz. This will generate 0.1 seconds pulse.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="n">pa8</span> <span class="o">=</span> <span class="n">gpioa</span><span class="py">.pa8</span><span class="nf">.into_alternate_af1</span><span class="p">();</span>
<span class="k">let</span> <span class="k">mut</span> <span class="n">pwm</span> <span class="o">=</span> <span class="nn">pwm</span><span class="p">::</span><span class="nf">tim1</span><span class="p">(</span><span class="n">dp</span><span class="py">.TIM1</span><span class="p">,</span> <span class="n">pa8</span><span class="p">,</span> <span class="n">clocks</span><span class="p">,</span> <span class="mi">10</span><span class="nf">.hz</span><span class="p">());</span>
<span class="k">let</span> <span class="n">max_duty</span> <span class="o">=</span> <span class="n">pwm</span><span class="nf">.get_max_duty</span><span class="p">();</span>
<span class="n">pwm</span><span class="nf">.set_duty</span><span class="p">(</span><span class="n">max_duty</span> <span class="o">/</span> <span class="mi">2</span><span class="p">);</span>
<span class="n">pwm</span><span class="nf">.enable</span><span class="p">();</span>
</code></pre></div></div>

<p>If you don’t want to use <code class="language-plaintext highlighter-rouge">stm32f4xx-hal</code>’s <code class="language-plaintext highlighter-rouge">pwm</code> module, it is also possible to directly configure a timer in output mode. The code below shows how to select PWM mode 1, set duty, enable the channel, and enable the timer’s main output.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="n">_tim</span> <span class="o">=</span> <span class="nn">Timer</span><span class="p">::</span><span class="nf">tim1</span><span class="p">(</span><span class="n">dp</span><span class="py">.TIM1</span><span class="p">,</span> <span class="mi">10</span><span class="nf">.hz</span><span class="p">(),</span> <span class="n">clocks</span><span class="p">);</span>
<span class="nf">configure_timer1</span><span class="p">();</span>

<span class="c1">// ----</span>

<span class="k">fn</span> <span class="nf">configure_timer1</span><span class="p">()</span> <span class="p">{</span>
    <span class="k">unsafe</span> <span class="p">{</span>
        <span class="k">let</span> <span class="n">tim</span> <span class="o">=</span> <span class="o">&amp;</span><span class="p">(</span><span class="o">*</span><span class="nn">TIM1</span><span class="p">::</span><span class="nf">ptr</span><span class="p">());</span>
        <span class="n">tim</span><span class="nf">.ccmr1_output</span><span class="p">()</span>
            <span class="nf">.modify</span><span class="p">(|</span><span class="n">_</span><span class="p">,</span> <span class="n">w</span><span class="p">|</span> <span class="n">w</span><span class="nf">.oc1pe</span><span class="p">()</span><span class="nf">.set_bit</span><span class="p">()</span><span class="nf">.oc1m</span><span class="p">()</span><span class="nf">.pwm_mode1</span><span class="p">());</span>

        <span class="c1">// Set the duty cycle</span>
        <span class="n">tim</span><span class="py">.ccr1</span><span class="nf">.modify</span><span class="p">(|</span><span class="n">_</span><span class="p">,</span> <span class="n">w</span><span class="p">|</span> <span class="n">w</span><span class="nf">.ccr</span><span class="p">()</span><span class="nf">.bits</span><span class="p">(</span><span class="mi">1</span><span class="p">));</span>
        <span class="c1">// Enable the channel</span>
        <span class="n">tim</span><span class="py">.ccer</span><span class="nf">.modify</span><span class="p">(|</span><span class="n">_</span><span class="p">,</span> <span class="n">w</span><span class="p">|</span> <span class="n">w</span><span class="nf">.cc1e</span><span class="p">()</span><span class="nf">.set_bit</span><span class="p">());</span>
        <span class="c1">// Enable the TIM main Output</span>
        <span class="n">tim</span><span class="py">.bdtr</span><span class="nf">.modify</span><span class="p">(|</span><span class="n">_</span><span class="p">,</span> <span class="n">w</span><span class="p">|</span> <span class="n">w</span><span class="nf">.moe</span><span class="p">()</span><span class="nf">.set_bit</span><span class="p">());</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="configure-adc">Configure ADC</h3>

<p>Next, we configure our ADC in a way it -</p>
<ul>
  <li>starts a conversion when triggered by <code class="language-plaintext highlighter-rouge">TIM1</code></li>
  <li>generates an interrupt request upon the end of conversion</li>
</ul>

<p>We use <code class="language-plaintext highlighter-rouge">AdcConfig</code> to do that. Here, we specify the rising edge of <code class="language-plaintext highlighter-rouge">TIM1</code>’s signal to be the external trigger source.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="n">config</span> <span class="o">=</span> <span class="nn">AdcConfig</span><span class="p">::</span><span class="nf">default</span><span class="p">()</span>
    <span class="nf">.end_of_conversion_interrupt</span><span class="p">(</span><span class="nn">Eoc</span><span class="p">::</span><span class="n">Conversion</span><span class="p">)</span>
    <span class="nf">.external_trigger</span><span class="p">(</span><span class="nn">TriggerMode</span><span class="p">::</span><span class="n">RisingEdge</span><span class="p">,</span> <span class="nn">ExternalTrigger</span><span class="p">::</span><span class="n">Tim_1_cc_1</span><span class="p">);</span>
    
<span class="k">let</span> <span class="k">mut</span> <span class="n">adc</span> <span class="o">=</span> <span class="nn">Adc</span><span class="p">::</span><span class="nf">adc1</span><span class="p">(</span><span class="n">dp</span><span class="py">.ADC1</span><span class="p">,</span> <span class="k">true</span><span class="p">,</span> <span class="n">config</span><span class="p">);</span>
</code></pre></div></div>
<p>We now set up an analog pin and configure ADC channel.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="n">gpioa</span> <span class="o">=</span> <span class="n">dp</span><span class="py">.GPIOA</span><span class="nf">.split</span><span class="p">();</span>
<span class="k">let</span> <span class="n">pa3</span> <span class="o">=</span> <span class="n">gpioa</span><span class="py">.pa3</span><span class="nf">.into_analog</span><span class="p">();</span>
<span class="n">adc</span><span class="nf">.configure_channel</span><span class="p">(</span><span class="o">&amp;</span><span class="n">pa3</span><span class="p">,</span> <span class="nn">Sequence</span><span class="p">::</span><span class="n">One</span><span class="p">,</span> <span class="nn">SampleTime</span><span class="p">::</span><span class="n">Cycles_112</span><span class="p">);</span>
<span class="n">adc</span><span class="nf">.enable</span><span class="p">();</span>
</code></pre></div></div>
<h3 id="enable-adc-interrupt">Enable ADC Interrupt</h3>

<p>Since we need to access our ADC instance in ISR contexts, we declare a <code class="language-plaintext highlighter-rouge">Mutex</code> and move our ADC instance to it after initialization.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">static</span> <span class="n">ADC</span><span class="p">:</span> <span class="n">Mutex</span><span class="o">&lt;</span><span class="n">RefCell</span><span class="o">&lt;</span><span class="nb">Option</span><span class="o">&lt;</span><span class="n">Adc</span><span class="o">&lt;</span><span class="nn">stm32</span><span class="p">::</span><span class="n">ADC1</span><span class="o">&gt;&gt;&gt;&gt;</span> 
    <span class="o">=</span> <span class="nn">Mutex</span><span class="p">::</span><span class="nf">new</span><span class="p">(</span><span class="nn">RefCell</span><span class="p">::</span><span class="nf">new</span><span class="p">(</span><span class="nb">None</span><span class="p">));</span>

<span class="c1">// ----</span>

<span class="c1">// Move the shared resource to Mutex</span>
<span class="nf">free</span><span class="p">(|</span><span class="n">cs</span><span class="p">|</span> <span class="p">{</span>
    <span class="n">ADC</span><span class="nf">.borrow</span><span class="p">(</span><span class="n">cs</span><span class="p">)</span><span class="nf">.replace</span><span class="p">(</span><span class="nf">Some</span><span class="p">(</span><span class="n">adc</span><span class="p">));</span>
<span class="p">});</span>
</code></pre></div></div>

<p>Finally, enable ADC interrupt with the NVIC.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">unsafe</span> <span class="p">{</span>
    <span class="nn">stm32</span><span class="p">::</span><span class="nn">NVIC</span><span class="p">::</span><span class="nf">unmask</span><span class="p">(</span><span class="nn">stm32</span><span class="p">::</span><span class="nn">interrupt</span><span class="p">::</span><span class="n">ADC</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="interrupt-handler">Interrupt Handler</h3>

<p>That is it. Injected conversion should be triggered on the rising edge of the signal.</p>

<p>The rest is pretty much the same as <a href="https://lonesometraveler.github.io/2020/05/08/ADC-Interrupt.html">last week’s ADC experiment</a>. When a conversion is done, EOC end of conversion bit is set and an interrupt request is generated.</p>

<p>In the interrupt handler below, we read the currently available ADC value and print it out.  <code class="language-plaintext highlighter-rouge">current_sample()</code> reads the result from ADC’s DR register and clears the EOC flag automatically. There is no need to call <code class="language-plaintext highlighter-rouge">clear_end_of_conversion_flag()</code>.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">#[interrupt]</span>
<span class="k">fn</span> <span class="nf">ADC</span><span class="p">()</span> <span class="p">{</span>
    <span class="nf">free</span><span class="p">(|</span><span class="n">cs</span><span class="p">|</span> <span class="p">{</span>
        <span class="k">if</span> <span class="k">let</span> <span class="nf">Some</span><span class="p">(</span><span class="k">ref</span> <span class="k">mut</span> <span class="n">adc</span><span class="p">)</span> <span class="o">=</span> <span class="n">ADC</span><span class="nf">.borrow</span><span class="p">(</span><span class="n">cs</span><span class="p">)</span><span class="nf">.borrow_mut</span><span class="p">()</span><span class="nf">.deref_mut</span><span class="p">()</span> <span class="p">{</span>
            <span class="k">let</span> <span class="n">sample</span> <span class="o">=</span> <span class="n">adc</span><span class="nf">.current_sample</span><span class="p">();</span>
            <span class="nd">iprintln!</span><span class="p">(</span><span class="nf">itm</span><span class="p">(),</span> <span class="s">"PA3: {}"</span><span class="p">,</span> <span class="n">sample</span><span class="p">);</span>
        <span class="p">}</span>
    <span class="p">});</span>
<span class="p">}</span>
</code></pre></div></div>]]></content><author><name>lonesometraveler</name><email>lonesometraveler@mac.com</email></author><category term="Rust" /><category term="embedded" /><summary type="html"><![CDATA[Our embedded Rust experiments on STM32 platform continues. This week, we explore ADC’s injected conversion mode. The application note AN3116 explains what injected conversion mode is.]]></summary></entry><entry><title type="html">Interrupt Based ADC</title><link href="https://lonesometraveler.github.io/2020/05/08/ADC-Interrupt.html" rel="alternate" type="text/html" title="Interrupt Based ADC" /><published>2020-05-08T21:11:21+00:00</published><updated>2020-05-08T21:11:21+00:00</updated><id>https://lonesometraveler.github.io/2020/05/08/ADC-Interrupt</id><content type="html" xml:base="https://lonesometraveler.github.io/2020/05/08/ADC-Interrupt.html"><![CDATA[<p><a href="https://lonesometraveler.github.io/2020/05/01/ADC-PWM.html">Polling in a loop is the simplest way to use the ADC</a>. But it makes it difficult to run other codes while the ADC is running. It would be nice if we can make it interrupt-based. This post will show how to do a simple interrupt based ADC in embedded Rust.</p>

<h2 id="ingredients">Ingredients</h2>

<p><img src="https://lonesometraveler.github.io/assets/adc_pwm.jpeg" alt="" /></p>

<p>Hardware</p>

<ul>
  <li><a href="https://www.st.com/en/evaluation-tools/nucleo-f429zi.html">Nucleo-F429ZI</a></li>
  <li>Potentiometer</li>
</ul>

<p>Crates</p>
<ul>
  <li><a href="https://crates.io/crates/stm32f4xx-hal"><code class="language-plaintext highlighter-rouge">stm32f4xx-hal</code></a> A Rust embedded-hal HAL for all MCUs in the STM32 F4 family</li>
</ul>

<p>Code</p>

<ul>
  <li><a href="https://github.com/lonesometraveler/stm32f4xx-examples/blob/master/examples/adc_interrupt_1.rs">The code is available on GitHub</a></li>
</ul>

<h2 id="eoc-interrupt">EOC Interrupt</h2>

<p>Each time ADC completes a conversion, the EOC (End of Conversion) flag is set and the ADC_DR register (the register that holds ADC value) can be read. For this week’s little experiment, we use  the EOC flag for interrupts. Just like <a href="https://lonesometraveler.github.io/2020/05/01/ADC-PWM.html">last week’s ADC project</a>, our output will be PWM. This time, we will adjust the PWM duty cycle in the ISR context instead of the user context.</p>

<p>In <code class="language-plaintext highlighter-rouge">stm32f4xx-hal</code>’s <code class="language-plaintext highlighter-rouge">adc.rs</code>, the EOC interrupt is disabled by default. We explicitly enable the interrupt using <code class="language-plaintext highlighter-rouge">AdcConfig</code> like this.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="n">config</span> <span class="o">=</span> <span class="nn">AdcConfig</span><span class="p">::</span><span class="nf">default</span><span class="p">()</span>
    <span class="nf">.end_of_conversion_interrupt</span><span class="p">(</span><span class="nn">Eoc</span><span class="p">::</span><span class="n">Conversion</span><span class="p">);</span>
    
<span class="k">let</span> <span class="k">mut</span> <span class="n">adc</span> <span class="o">=</span> <span class="nn">Adc</span><span class="p">::</span><span class="nf">adc1</span><span class="p">(</span><span class="n">dp</span><span class="py">.ADC1</span><span class="p">,</span> <span class="k">true</span><span class="p">,</span> <span class="n">config</span><span class="p">);</span>
</code></pre></div></div>

<p>Next, we configure an analog pin and ADC channels. We use only one channel for this example project.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="n">pa3</span> <span class="o">=</span> <span class="n">gpioa</span><span class="py">.pa3</span><span class="nf">.into_analog</span><span class="p">();</span>
<span class="n">adc</span><span class="nf">.configure_channel</span><span class="p">(</span><span class="o">&amp;</span><span class="n">pa3</span><span class="p">,</span> <span class="nn">Sequence</span><span class="p">::</span><span class="n">One</span><span class="p">,</span> <span class="nn">SampleTime</span><span class="p">::</span><span class="n">Cycles_112</span><span class="p">);</span>
</code></pre></div></div>
<p>We are ready to go. Let’s start ADC. The method below does the following:</p>

<ul>
  <li>Enable ADC</li>
  <li>Clear the EOC flag</li>
  <li>Set SWSTART bit (which triggers conversion)</li>
  <li>Wait until conversion starts.</li>
</ul>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">adc</span><span class="nf">.start_conversion</span><span class="p">();</span>
</code></pre></div></div>

<p>Since we want to access ADC module in the interrupt handler, we move <code class="language-plaintext highlighter-rouge">adc</code> to <code class="language-plaintext highlighter-rouge">Mutex</code>.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nf">free</span><span class="p">(|</span><span class="n">cs</span><span class="p">|</span> <span class="p">{</span>
    <span class="n">ADC</span><span class="nf">.borrow</span><span class="p">(</span><span class="n">cs</span><span class="p">)</span><span class="nf">.replace</span><span class="p">(</span><span class="nf">Some</span><span class="p">(</span><span class="n">adc</span><span class="p">));</span>
<span class="p">});</span>
</code></pre></div></div>

<p>Don’t forget to enable the ADC interrupt in the NVIC (Nested Vector Interrupt Controller).</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">unsafe</span> <span class="p">{</span>
    <span class="nn">stm32</span><span class="p">::</span><span class="nn">NVIC</span><span class="p">::</span><span class="nf">unmask</span><span class="p">(</span><span class="nn">stm32</span><span class="p">::</span><span class="nn">interrupt</span><span class="p">::</span><span class="n">ADC</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<h2 id="interrupt-handler">Interrupt Handler</h2>

<p>The ADC interrupt is now enabled. Whenever the EOC flag is set, it generates an interrupt request and calls up this interrupt handler.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">#[interrupt]</span>
<span class="k">fn</span> <span class="nf">ADC</span><span class="p">()</span> <span class="p">{</span>
    <span class="nf">free</span><span class="p">(|</span><span class="n">cs</span><span class="p">|</span> <span class="p">{</span>
        <span class="k">if</span> <span class="k">let</span> <span class="p">(</span><span class="nf">Some</span><span class="p">(</span><span class="k">ref</span> <span class="k">mut</span> <span class="n">adc</span><span class="p">),</span> <span class="nf">Some</span><span class="p">(</span><span class="k">ref</span> <span class="k">mut</span> <span class="n">pwm</span><span class="p">))</span> <span class="o">=</span> <span class="p">(</span>
            <span class="n">ADC</span><span class="nf">.borrow</span><span class="p">(</span><span class="n">cs</span><span class="p">)</span><span class="nf">.borrow_mut</span><span class="p">()</span><span class="nf">.deref_mut</span><span class="p">(),</span>
            <span class="n">PWM</span><span class="nf">.borrow</span><span class="p">(</span><span class="n">cs</span><span class="p">)</span><span class="nf">.borrow_mut</span><span class="p">()</span><span class="nf">.deref_mut</span><span class="p">(),</span>
        <span class="p">)</span> <span class="p">{</span>
            <span class="c1">// Reading the result from the ADC_DR clears the EOC flag automatically.</span>
            <span class="k">let</span> <span class="n">sample</span> <span class="o">=</span> <span class="n">adc</span><span class="nf">.current_sample</span><span class="p">();</span>
            <span class="k">let</span> <span class="n">scale</span> <span class="o">=</span> <span class="n">sample</span> <span class="k">as</span> <span class="nb">f32</span> <span class="o">/</span> <span class="mi">0x0FFF</span> <span class="k">as</span> <span class="nb">f32</span><span class="p">;</span>
            <span class="n">pwm</span><span class="nf">.set_duty</span><span class="p">((</span><span class="n">scale</span> <span class="o">*</span> <span class="n">pwm</span><span class="nf">.get_max_duty</span><span class="p">()</span> <span class="k">as</span> <span class="nb">f32</span><span class="p">)</span> <span class="k">as</span> <span class="nb">u16</span><span class="p">);</span>
            <span class="c1">// restart ADC conversion</span>
            <span class="n">adc</span><span class="nf">.start_conversion</span><span class="p">();</span>
        <span class="p">}</span>
    <span class="p">});</span>
<span class="p">}</span>
</code></pre></div></div>

<p>In the handler, we take the ADC module out of Mutex and call <code class="language-plaintext highlighter-rouge">current_sample()</code>. This method reads from the ADC_DR register and clears the EOC flag. We update the PWM duty cycle based on the ADC value, and finally, restart the conversion by calling <code class="language-plaintext highlighter-rouge">start_conversion()</code> before we move out of the ISR.</p>

<p>That’s it! Now our main looks like the code below. There is nothing in the loop. ADC reading and PWM adjustment are all happening in the ISR.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">#[entry]</span>
<span class="k">fn</span> <span class="nf">main</span><span class="p">()</span> <span class="k">-&gt;</span> <span class="o">!</span> <span class="p">{</span>
    <span class="k">let</span> <span class="n">dp</span> <span class="o">=</span> <span class="nn">stm32</span><span class="p">::</span><span class="nn">Peripherals</span><span class="p">::</span><span class="nf">take</span><span class="p">()</span><span class="nf">.unwrap</span><span class="p">();</span>
    <span class="k">let</span> <span class="n">rcc</span> <span class="o">=</span> <span class="n">dp</span><span class="py">.RCC</span><span class="nf">.constrain</span><span class="p">();</span>
    <span class="k">let</span> <span class="n">clocks</span> <span class="o">=</span> <span class="n">rcc</span><span class="py">.cfgr</span><span class="nf">.freeze</span><span class="p">();</span>
    <span class="k">let</span> <span class="n">gpioa</span> <span class="o">=</span> <span class="n">dp</span><span class="py">.GPIOA</span><span class="nf">.split</span><span class="p">();</span>

    <span class="c1">// Configure PWM</span>
    <span class="k">let</span> <span class="n">pa8</span> <span class="o">=</span> <span class="n">gpioa</span><span class="py">.pa8</span><span class="nf">.into_alternate_af1</span><span class="p">();</span>
    <span class="k">let</span> <span class="k">mut</span> <span class="n">pwm</span> <span class="o">=</span> <span class="nn">pwm</span><span class="p">::</span><span class="nf">tim1</span><span class="p">(</span><span class="n">dp</span><span class="py">.TIM1</span><span class="p">,</span> <span class="n">pa8</span><span class="p">,</span> <span class="n">clocks</span><span class="p">,</span> <span class="mi">50</span><span class="nf">.hz</span><span class="p">());</span>
    <span class="n">pwm</span><span class="nf">.enable</span><span class="p">();</span>

    <span class="c1">// Configure ADC</span>
    <span class="k">let</span> <span class="n">config</span> <span class="o">=</span> <span class="nn">AdcConfig</span><span class="p">::</span><span class="nf">default</span><span class="p">()</span><span class="nf">.end_of_conversion_interrupt</span><span class="p">(</span><span class="nn">Eoc</span><span class="p">::</span><span class="n">Conversion</span><span class="p">);</span>
    <span class="k">let</span> <span class="k">mut</span> <span class="n">adc</span> <span class="o">=</span> <span class="nn">Adc</span><span class="p">::</span><span class="nf">adc1</span><span class="p">(</span><span class="n">dp</span><span class="py">.ADC1</span><span class="p">,</span> <span class="k">true</span><span class="p">,</span> <span class="n">config</span><span class="p">);</span>
    <span class="k">let</span> <span class="n">pa3</span> <span class="o">=</span> <span class="n">gpioa</span><span class="py">.pa3</span><span class="nf">.into_analog</span><span class="p">();</span>
    <span class="n">adc</span><span class="nf">.configure_channel</span><span class="p">(</span><span class="o">&amp;</span><span class="n">pa3</span><span class="p">,</span> <span class="nn">Sequence</span><span class="p">::</span><span class="n">One</span><span class="p">,</span> <span class="nn">SampleTime</span><span class="p">::</span><span class="n">Cycles_112</span><span class="p">);</span>
    <span class="n">adc</span><span class="nf">.start_conversion</span><span class="p">();</span>

    <span class="c1">// Move shared resources to Mutex</span>
    <span class="nf">free</span><span class="p">(|</span><span class="n">cs</span><span class="p">|</span> <span class="p">{</span>
        <span class="n">ADC</span><span class="nf">.borrow</span><span class="p">(</span><span class="n">cs</span><span class="p">)</span><span class="nf">.replace</span><span class="p">(</span><span class="nf">Some</span><span class="p">(</span><span class="n">adc</span><span class="p">));</span>
        <span class="n">PWM</span><span class="nf">.borrow</span><span class="p">(</span><span class="n">cs</span><span class="p">)</span><span class="nf">.replace</span><span class="p">(</span><span class="nf">Some</span><span class="p">(</span><span class="n">pwm</span><span class="p">));</span>
    <span class="p">});</span>

    <span class="c1">// Enable interrupt</span>
    <span class="k">unsafe</span> <span class="p">{</span>
        <span class="nn">stm32</span><span class="p">::</span><span class="nn">NVIC</span><span class="p">::</span><span class="nf">unmask</span><span class="p">(</span><span class="nn">stm32</span><span class="p">::</span><span class="nn">interrupt</span><span class="p">::</span><span class="n">ADC</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="k">loop</span> <span class="p">{}</span>
<span class="p">}</span>
</code></pre></div></div>]]></content><author><name>lonesometraveler</name><email>lonesometraveler@mac.com</email></author><category term="Rust" /><category term="embedded" /><summary type="html"><![CDATA[Polling in a loop is the simplest way to use the ADC. But it makes it difficult to run other codes while the ADC is running. It would be nice if we can make it interrupt-based. This post will show how to do a simple interrupt based ADC in embedded Rust.]]></summary></entry><entry><title type="html">ADC to PWM: The World Beyond ON/OFF</title><link href="https://lonesometraveler.github.io/2020/05/01/ADC-PWM.html" rel="alternate" type="text/html" title="ADC to PWM: The World Beyond ON/OFF" /><published>2020-05-01T22:11:21+00:00</published><updated>2020-05-01T22:11:21+00:00</updated><id>https://lonesometraveler.github.io/2020/05/01/ADC-PWM</id><content type="html" xml:base="https://lonesometraveler.github.io/2020/05/01/ADC-PWM.html"><![CDATA[<p><img src="https://lonesometraveler.github.io/assets/adc_pwm.gif" alt="" /></p>

<p>After playing around with <a href="https://lonesometraveler.github.io/2020/04/17/GPIO_interrupt.html">DigitalIO</a>, <a href="https://lonesometraveler.github.io/2020/04/22/Maxbotix-Ultrasonic.html">Timer Counter</a>, <a href="https://lonesometraveler.github.io/2020/04/04/timer-interrupt.html">Interrupt</a>, <a href="https://lonesometraveler.github.io/2020/03/20/max6955.html">I2C</a>, and <a href="https://lonesometraveler.github.io/2020/04/10/lsm9ds1-trait.html">SPI</a>, I thought it was time to work on Analog Digital Conversion.</p>

<p>To experiment with embedded Rust ADC, I did a quick project that adjusted PWM duty cycle based on ADC values. There were no fancy analog sensors in my toy box. I used a potentiometer and monitored PWM outputs on my oscilloscope.</p>

<p>Although it was such a simple project, I found it really satisfying to see pulses respond to my turning the potentiometer. It was quite a different experience from toggling an LED. As my sensei <a href="https://www.tigoe.com/pcomp/code/controllers/input-output/analog-input/">Tom Igoe says</a>, knowing whether a cat is on or off a mat is not always enough. Sometimes, we want to know how fat the cat is.</p>

<blockquote>
  <p>While a digital input to a microcontroller can tell you about discrete changes in the physical world, such as whether the cat is on the mat, or the cat is off the mat, there are times when this is not enough. Sometimes you want to know how fat the cat on the mat is.  - Tom Igoe</p>
</blockquote>

<h2 id="ingredients">Ingredients</h2>

<p><img src="https://lonesometraveler.github.io/assets/adc_pwm.jpeg" alt="" /></p>

<p>Hardware</p>

<ul>
  <li><a href="https://www.st.com/en/evaluation-tools/nucleo-f429zi.html">Nucleo-F429ZI</a></li>
  <li>Potentiometer</li>
</ul>

<p>Crates</p>
<ul>
  <li><a href="https://crates.io/crates/stm32f4xx-hal"><code class="language-plaintext highlighter-rouge">stm32f4xx-hal</code></a> A Rust embedded-hal HAL for all MCUs in the STM32 F4 family</li>
</ul>

<p>Code</p>

<ul>
  <li><a href="https://github.com/lonesometraveler/stm32f4xx-examples/blob/master/examples/adc_1.rs">The code is available on GitHub</a></li>
</ul>

<h2 id="implementation">Implementation</h2>

<h3 id="adc">ADC</h3>

<p>In order to use ADC on STM32 devices, we need to do the followings:</p>

<ol>
  <li>Enable the ADC clock</li>
  <li>Enable the GPIO clock</li>
  <li>Configure the GPIO pin as an analog input</li>
  <li>Configure the ADC (clock, resolution, data alignment, etc.)</li>
</ol>

<p>It sounded like a lot of work. But it turned out that ADC was as easy as ABC thanks to <code class="language-plaintext highlighter-rouge">stm32f4xx-hal</code>. After importing all the required modules, below was all I needed to enable and configure ADC.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="k">mut</span> <span class="n">adc</span> <span class="o">=</span> <span class="nn">Adc</span><span class="p">::</span><span class="nf">adc1</span><span class="p">(</span><span class="n">dp</span><span class="py">.ADC1</span><span class="p">,</span> <span class="k">true</span><span class="p">,</span> <span class="nn">AdcConfig</span><span class="p">::</span><span class="nf">default</span><span class="p">());</span>
</code></pre></div></div>

<p>I was curious to know what <code class="language-plaintext highlighter-rouge">AdcConfig</code>’s <code class="language-plaintext highlighter-rouge">Default</code> was. I looked up the doc and found this.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">impl</span> <span class="nb">Default</span> <span class="k">for</span> <span class="n">AdcConfig</span> <span class="p">{</span>
    <span class="k">fn</span> <span class="nf">default</span><span class="p">()</span> <span class="k">-&gt;</span> <span class="k">Self</span> <span class="p">{</span>
        <span class="k">Self</span> <span class="p">{</span>
            <span class="n">clock</span><span class="p">:</span> <span class="nn">Clock</span><span class="p">::</span><span class="n">Pclk2_div_2</span><span class="p">,</span>
            <span class="n">resolution</span><span class="p">:</span> <span class="nn">Resolution</span><span class="p">::</span><span class="n">Twelve</span><span class="p">,</span>
            <span class="n">align</span><span class="p">:</span> <span class="nn">Align</span><span class="p">::</span><span class="nb">Right</span><span class="p">,</span>
            <span class="n">scan</span><span class="p">:</span> <span class="nn">Scan</span><span class="p">::</span><span class="n">Disabled</span><span class="p">,</span>
            <span class="n">external_trigger</span><span class="p">:</span> <span class="p">(</span><span class="nn">TriggerMode</span><span class="p">::</span><span class="n">Disabled</span><span class="p">,</span> <span class="nn">ExternalTrigger</span><span class="p">::</span><span class="n">Tim_1_cc_1</span><span class="p">),</span>
            <span class="n">continuous</span><span class="p">:</span> <span class="nn">Continuous</span><span class="p">::</span><span class="n">Single</span><span class="p">,</span>
            <span class="n">dma</span><span class="p">:</span> <span class="nn">Dma</span><span class="p">::</span><span class="n">Disabled</span><span class="p">,</span>
            <span class="n">end_of_conversion_interrupt</span><span class="p">:</span> <span class="nn">Eoc</span><span class="p">::</span><span class="n">Disabled</span><span class="p">,</span>
            <span class="n">default_sample_time</span><span class="p">:</span> <span class="nn">SampleTime</span><span class="p">::</span><span class="n">Cycles_480</span><span class="p">,</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>You can, of course, customize <code class="language-plaintext highlighter-rouge">AdcConfig</code>. But for this simple experiment, I only wanted to do one-shot conversion. No scanning, no external triggers, no DMA… I didn’t change anything.</p>

<p>After enabling ADC, I configured an analog input pin, PA3.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="n">gpioa</span> <span class="o">=</span> <span class="n">dp</span><span class="py">.GPIOA</span><span class="nf">.split</span><span class="p">();</span>
<span class="k">let</span> <span class="n">pa3</span> <span class="o">=</span> <span class="n">gpioa</span><span class="py">.pa3</span><span class="nf">.into_analog</span><span class="p">();</span>
</code></pre></div></div>
<p>I passed my pin <code class="language-plaintext highlighter-rouge">pa3</code> to <code class="language-plaintext highlighter-rouge">read()</code> method to read a value on the pin.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="n">sample</span> <span class="o">=</span> <span class="n">adc</span><span class="nf">.read</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="n">pa3</span><span class="p">)</span><span class="nf">.unwrap</span><span class="p">();</span>
<span class="nd">iprintln!</span><span class="p">(</span><span class="nf">itm</span><span class="p">(),</span> <span class="s">"PA3: {}"</span><span class="p">,</span> <span class="n">sample</span><span class="p">);</span>
</code></pre></div></div>
<p>Nucleo-F429ZI has 12 bit ADCs. So, a returned value from <code class="language-plaintext highlighter-rouge">read()</code> can be <code class="language-plaintext highlighter-rouge">0</code> ~ <code class="language-plaintext highlighter-rouge">4095</code>. If you want to convert that to voltage, <code class="language-plaintext highlighter-rouge">stm32f4xx-hal</code> has a convenient method for that. Just pass the read value to <code class="language-plaintext highlighter-rouge">fn sample_to_millivolts(&amp;self, sample: u16) -&gt; u16</code>.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="n">millivolts</span> <span class="o">=</span> <span class="n">adc</span><span class="nf">.sample_to_millivolts</span><span class="p">(</span><span class="n">sample</span><span class="p">);</span>
<span class="nd">iprintln!</span><span class="p">(</span><span class="nf">itm</span><span class="p">(),</span> <span class="s">"PA3: {}mV"</span><span class="p">,</span> <span class="n">millivolts</span><span class="p">);</span>
</code></pre></div></div>

<h3 id="pwm">PWM</h3>

<p>I have to say I got lucky. A couple of days ago, the <code class="language-plaintext highlighter-rouge">stm32f4xx-hal</code> team released a new version, v0.8.0, and added PWM support. Without this update, it would have been difficult for me to do PWM.</p>

<p>I haven’t taken a close look at the PWM API yet. But it seems like we just need to pass a Timer, a pin (or pins), clocks, and desired frequency to create a PWM instance.</p>

<p>I initialized my PWM instance with PA8 pin and enabled it like this:</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="n">pa8</span> <span class="o">=</span> <span class="n">gpioa</span><span class="py">.pa8</span><span class="nf">.into_alternate_af1</span><span class="p">();</span>
<span class="k">let</span> <span class="k">mut</span> <span class="n">pwm</span> <span class="o">=</span> <span class="nn">pwm</span><span class="p">::</span><span class="nf">tim1</span><span class="p">(</span><span class="n">dp</span><span class="py">.TIM1</span><span class="p">,</span> <span class="n">pa8</span><span class="p">,</span> <span class="n">clocks</span><span class="p">,</span> <span class="mi">50</span><span class="nf">.hz</span><span class="p">());</span>
<span class="n">pwm</span><span class="nf">.enable</span><span class="p">();</span>
</code></pre></div></div>

<p>My understanding is that the PWM period is determined based on clock configuration. <code class="language-plaintext highlighter-rouge">get_max_duty()</code> returns the maximum value you can pass to <code class="language-plaintext highlighter-rouge">set_duty()</code> method.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="n">max_duty</span> <span class="o">=</span> <span class="n">pwm</span><span class="nf">.get_max_duty</span><span class="p">();</span>
<span class="n">pwm</span><span class="nf">.set_duty</span><span class="p">(</span><span class="n">max_duty</span><span class="p">);</span> <span class="c1">// 100% duty cycle</span>
<span class="n">pwm</span><span class="nf">.set_duty</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span> <span class="c1">// 0% duty cycle</span>
</code></pre></div></div>

<h3 id="adc---pwm">ADC -&gt; PWM</h3>

<p>After configuring ADC and PWM, I repeated the followings in the infinite loop.</p>

<ol>
  <li>Read an ADC value</li>
  <li>Scale the 12 bit ADC value to the range of <code class="language-plaintext highlighter-rouge">0</code> to <code class="language-plaintext highlighter-rouge">max_duty</code></li>
  <li>Set PWM duty</li>
</ol>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">loop</span> <span class="p">{</span>
    <span class="k">let</span> <span class="n">sample</span> <span class="o">=</span> <span class="k">match</span> <span class="n">adc</span><span class="nf">.read</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="n">pa3</span><span class="p">)</span> <span class="p">{</span>
        <span class="nf">Ok</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> <span class="k">=&gt;</span> <span class="n">x</span><span class="p">,</span>
        <span class="nf">Err</span><span class="p">(</span><span class="n">_</span><span class="p">)</span> <span class="k">=&gt;</span> <span class="k">continue</span><span class="p">,</span>
    <span class="p">};</span>
    <span class="k">let</span> <span class="n">scale</span> <span class="o">=</span> <span class="n">sample</span> <span class="k">as</span> <span class="nb">f32</span> <span class="o">/</span> <span class="mi">0x0FFF</span> <span class="k">as</span> <span class="nb">f32</span><span class="p">;</span>
    <span class="n">pwm</span><span class="nf">.set_duty</span><span class="p">((</span><span class="n">scale</span> <span class="o">*</span> <span class="n">max_duty</span> <span class="k">as</span> <span class="nb">f32</span><span class="p">)</span> <span class="k">as</span> <span class="nb">u16</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>That was it. Simple ADC and PWM with <code class="language-plaintext highlighter-rouge">stm32f4xx-hal</code>. I will explore other ADC features in future projects.</p>]]></content><author><name>lonesometraveler</name><email>lonesometraveler@mac.com</email></author><category term="Rust" /><category term="embedded" /><summary type="html"><![CDATA[]]></summary></entry><entry><title type="html">How to Measure Distance With Maxbotix Ultrasonic Sensor</title><link href="https://lonesometraveler.github.io/2020/04/23/Maxbotix-Ultrasonic.html" rel="alternate" type="text/html" title="How to Measure Distance With Maxbotix Ultrasonic Sensor" /><published>2020-04-23T00:11:21+00:00</published><updated>2020-04-23T00:11:21+00:00</updated><id>https://lonesometraveler.github.io/2020/04/23/Maxbotix-Ultrasonic</id><content type="html" xml:base="https://lonesometraveler.github.io/2020/04/23/Maxbotix-Ultrasonic.html"><![CDATA[<p><img src="https://lonesometraveler.github.io/assets/maxbotix_demo_1.gif" alt="" /></p>

<p>This week, I played around with an ultrasonic range finder and wrote a little library for it in Rust. The outcome is shown in the image above. This system measures the distance between myself and Ferris.</p>

<p>I used an ultrasonic sensor from <a href="https://www.maxbotix.com">Maxbotix</a> to measure distance. This project monitors the sensor’s output and shows the measured distance on a LED display.</p>

<p>Here are two new things I learned from this project:</p>

<ul>
  <li>How to read microcontroller’s timer counter value</li>
  <li>How to convert <code class="language-plaintext highlighter-rouge">u32</code> (sensor reading) to <code class="language-plaintext highlighter-rouge">&amp;str</code> (for the display) in a <code class="language-plaintext highlighter-rouge">no-std</code> environment where <code class="language-plaintext highlighter-rouge">format!</code> macro is not available</li>
</ul>

<h2 id="ingredients">Ingredients</h2>

<h3 id="hardware">Hardware</h3>

<ul>
  <li><a href="https://www.st.com/en/evaluation-tools/nucleo-f429zi.html">Nucleo-F429ZI</a></li>
  <li><a href="https://www.maxbotix.com/Ultrasonic_Sensors/MB1010.htm">Maxbotix RangeFinder LV-EZ1</a></li>
  <li>LED display (custom made)</li>
  <li><a href="https://devswag.com/products/rust-ferris">Ferris Plushie</a> 🦀</li>
</ul>

<p><img src="https://lonesometraveler.github.io/assets/distance_ingredients.jpeg" alt="" /></p>

<h3 id="crates">Crates</h3>

<ul>
  <li><a href="https://crates.io/crates/stm32f4xx-hal"><code class="language-plaintext highlighter-rouge">stm32f4xx-hal</code></a> A Rust embedded-hal HAL for all MCUs in the STM32 F4 family</li>
  <li><a href="https://crates.io/crates/max6955"><code class="language-plaintext highlighter-rouge">max6955</code></a> A platform agnostic driver to interface with MAX6955 LED Display Driver (<a href="https://lonesometraveler.github.io/2020/03/20/max6955.html">See my post about this driver</a>.)</li>
  <li><a href="https://crates.io/crates/heapless"><code class="language-plaintext highlighter-rouge">heapless</code></a> Heapless, <code class="language-plaintext highlighter-rouge">static</code> friendly data structures</li>
</ul>

<h2 id="ultrasonic-sensor">Ultrasonic Sensor</h2>

<p>Maxbotix ultrasonic sensor measures distance and outputs the reading through PWM or Analog. For this project, I read pulse width with a timer.</p>

<p>The output from the sensor looks like the screenshot below. The pulse width represents distance. You can learn more about pulse width based distance calculation at <a href="https://www.maxbotix.com/033-using-pulse-width-pin-2.htm">Maxbotix website</a>.</p>

<p><img src="https://lonesometraveler.github.io/assets/maxbotix_pulse.JPG" alt="" /></p>

<p>Reading the pulse width is straightforward. Basically, I observe the state of the input pin and read the timer counter value. 
When <code class="language-plaintext highlighter-rouge">read</code> method is called, it goes like this:</p>
<ul>
  <li>Wait while the pin is low</li>
  <li>Reset the counter</li>
  <li>Wait while the pin is high</li>
  <li>Read the counter value and return it to the caller</li>
</ul>

<h2 id="implementation">Implementation</h2>

<h3 id="three-sensor-models">Three Sensor Models</h3>

<p>The sensor comes in 3 models: LV, XL, and HR. They all work the same way. Just different resolutions.  To calculate the distance, we use the model-specific scale factor.</p>

<ul>
  <li>LV: 147uS/inch</li>
  <li>XL: 58uS/cm</li>
  <li>HR: 1uS/mm</li>
</ul>

<p>I define an enum called <code class="language-plaintext highlighter-rouge">Model</code> like this:</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">impl</span> <span class="n">Model</span> <span class="p">{</span>
    <span class="cd">/// scale factor</span>
    <span class="k">fn</span> <span class="nf">factor</span><span class="p">(</span><span class="k">self</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="nb">u32</span> <span class="p">{</span>
        <span class="k">match</span> <span class="k">self</span> <span class="p">{</span>
            <span class="nn">Model</span><span class="p">::</span><span class="n">LV</span> <span class="k">=&gt;</span> <span class="mi">147</span><span class="p">,</span>
            <span class="nn">Model</span><span class="p">::</span><span class="n">XL</span> <span class="k">=&gt;</span> <span class="mi">58</span><span class="p">,</span>
            <span class="nn">Model</span><span class="p">::</span><span class="n">HR</span> <span class="k">=&gt;</span> <span class="mi">1</span><span class="p">,</span>
        <span class="p">}</span>
    <span class="p">}</span>
    <span class="cd">/// unit</span>
    <span class="k">fn</span> <span class="nf">unit</span><span class="p">(</span><span class="k">self</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="o">&amp;</span><span class="nb">str</span> <span class="p">{</span>
        <span class="k">match</span> <span class="k">self</span> <span class="p">{</span>
            <span class="nn">Model</span><span class="p">::</span><span class="n">LV</span> <span class="k">=&gt;</span> <span class="s">"</span><span class="se">\"</span><span class="s">"</span><span class="p">,</span>
            <span class="nn">Model</span><span class="p">::</span><span class="n">XL</span> <span class="k">=&gt;</span> <span class="s">"cm"</span><span class="p">,</span>
            <span class="nn">Model</span><span class="p">::</span><span class="n">HR</span> <span class="k">=&gt;</span> <span class="s">"mm"</span><span class="p">,</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="distance-measurement-using-timer-counter">Distance measurement using timer counter</h3>

<p>I wrote a module called <code class="language-plaintext highlighter-rouge">maxsonar</code> to measure the pulse width by reading a timer’s counter value.</p>

<p>Here is the <code class="language-plaintext highlighter-rouge">struct</code> for the sensor. It takes a Timer (concrete <code class="language-plaintext highlighter-rouge">TIM2</code> of the HAL crate), <code class="language-plaintext highlighter-rouge">Model</code>, and generic <code class="language-plaintext highlighter-rouge">T: InputPin</code>.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">pub</span> <span class="k">struct</span> <span class="n">MaxSonar</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span> <span class="p">{</span>
    <span class="n">timer</span><span class="p">:</span> <span class="n">TIM2</span><span class="p">,</span>
    <span class="n">model</span><span class="p">:</span> <span class="n">Model</span><span class="p">,</span>
    <span class="n">pin</span><span class="p">:</span> <span class="n">T</span><span class="p">,</span>
<span class="p">}</span>

<span class="k">impl</span><span class="o">&lt;</span><span class="n">T</span><span class="p">,</span> <span class="n">E</span><span class="o">&gt;</span> <span class="n">MaxSonar</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span>
<span class="k">where</span>
    <span class="n">T</span><span class="p">:</span> <span class="n">InputPin</span><span class="o">&lt;</span><span class="n">Error</span> <span class="o">=</span> <span class="n">E</span><span class="o">&gt;</span><span class="p">,</span>
    <span class="n">E</span><span class="p">:</span> <span class="nn">core</span><span class="p">::</span><span class="nn">fmt</span><span class="p">::</span><span class="n">Debug</span><span class="p">,</span>
<span class="p">{</span>
    <span class="k">pub</span> <span class="k">fn</span> <span class="nf">new</span><span class="p">(</span><span class="n">timer</span><span class="p">:</span> <span class="n">TIM2</span><span class="p">,</span> <span class="n">model</span><span class="p">:</span> <span class="n">Model</span><span class="p">,</span> <span class="n">pin</span><span class="p">:</span> <span class="n">T</span><span class="p">,</span> <span class="n">sysclk</span><span class="p">:</span> <span class="n">Hertz</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="k">Self</span> <span class="p">{</span>
        <span class="c1">// Configure timer for 1Mhz</span>
        <span class="k">let</span> <span class="n">rcc</span> <span class="o">=</span> <span class="k">unsafe</span> <span class="p">{</span> <span class="o">&amp;</span><span class="p">(</span><span class="o">*</span><span class="nn">RCC</span><span class="p">::</span><span class="nf">ptr</span><span class="p">())</span> <span class="p">};</span>
        <span class="n">rcc</span><span class="py">.apb1enr</span><span class="nf">.modify</span><span class="p">(|</span><span class="n">_</span><span class="p">,</span> <span class="n">w</span><span class="p">|</span> <span class="n">w</span><span class="nf">.tim2en</span><span class="p">()</span><span class="nf">.set_bit</span><span class="p">());</span>
        <span class="k">let</span> <span class="n">psc</span> <span class="o">=</span> <span class="p">(</span><span class="n">sysclk</span><span class="na">.0</span> <span class="o">/</span> <span class="mi">1_000_000</span><span class="p">)</span> <span class="k">as</span> <span class="nb">u16</span><span class="p">;</span>
        <span class="n">timer</span><span class="py">.psc</span><span class="nf">.write</span><span class="p">(|</span><span class="n">w</span><span class="p">|</span> <span class="n">w</span><span class="nf">.psc</span><span class="p">()</span><span class="nf">.bits</span><span class="p">(</span><span class="n">psc</span> <span class="o">-</span> <span class="mi">1</span><span class="p">));</span>
        <span class="n">timer</span><span class="py">.egr</span><span class="nf">.write</span><span class="p">(|</span><span class="n">w</span><span class="p">|</span> <span class="n">w</span><span class="nf">.ug</span><span class="p">()</span><span class="nf">.set_bit</span><span class="p">());</span>
        <span class="c1">// Start MaxSonar</span>
        <span class="k">let</span> <span class="k">mut</span> <span class="n">sonar</span> <span class="o">=</span> <span class="n">MaxSonar</span> <span class="p">{</span> <span class="n">timer</span><span class="p">,</span> <span class="n">model</span><span class="p">,</span> <span class="n">pin</span> <span class="p">};</span>
        <span class="n">sonar</span><span class="nf">.start</span><span class="p">();</span>
        <span class="n">sonar</span>
    <span class="p">}</span>

    <span class="k">fn</span> <span class="nf">start</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">self</span><span class="py">.timer.cnt</span><span class="nf">.reset</span><span class="p">();</span>
        <span class="k">self</span><span class="py">.timer.cr1</span><span class="nf">.write</span><span class="p">(|</span><span class="n">w</span><span class="p">|</span> <span class="n">w</span><span class="nf">.cen</span><span class="p">()</span><span class="nf">.set_bit</span><span class="p">());</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>It looks like <code class="language-plaintext highlighter-rouge">stm32f4xx-hal</code> doesn’t implement a method to read the current timer value. So, I directly access <code class="language-plaintext highlighter-rouge">TIM2</code>’s <code class="language-plaintext highlighter-rouge">cnt</code> register in my <code class="language-plaintext highlighter-rouge">read</code> method.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">pub</span> <span class="k">fn</span> <span class="nf">read</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="nb">u32</span> <span class="p">{</span>
    <span class="k">while</span> <span class="k">self</span><span class="py">.pin</span><span class="nf">.is_low</span><span class="p">()</span><span class="nf">.unwrap</span><span class="p">()</span> <span class="p">{}</span>
    <span class="k">self</span><span class="py">.timer.cnt</span><span class="nf">.reset</span><span class="p">();</span>
    <span class="k">while</span> <span class="k">self</span><span class="py">.pin</span><span class="nf">.is_high</span><span class="p">()</span><span class="nf">.unwrap</span><span class="p">()</span> <span class="p">{}</span>
    <span class="k">self</span><span class="py">.timer.cnt</span><span class="nf">.read</span><span class="p">()</span><span class="nf">.bits</span><span class="p">()</span> <span class="o">/</span> <span class="k">self</span><span class="py">.model</span><span class="nf">.factor</span><span class="p">()</span>
<span class="p">}</span>
</code></pre></div></div>

<p>As you can see, I do these:</p>

<ul>
  <li>Wait while the pin is low</li>
  <li>Reset the counter</li>
  <li>Wait while the pin is high</li>
  <li>Read the counter value</li>
</ul>

<p>I then calculate the distance by dividing the counter value by the scale factor. <code class="language-plaintext highlighter-rouge">self.model.factor()</code> returns the scale factor of the chosen model. In this project, I use <code class="language-plaintext highlighter-rouge">Model::LV</code>. So, the factor is <code class="language-plaintext highlighter-rouge">147</code>.</p>

<h3 id="format-in-a-no-std-environment">format! in a no-std environment</h3>

<p>Great. I now have the distance as <code class="language-plaintext highlighter-rouge">u32</code>. I just need to convert it to <code class="language-plaintext highlighter-rouge">&amp;str</code> to show it on my LED display. Here is the definition of the display driver’s <code class="language-plaintext highlighter-rouge">write_str</code> method:</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">pub</span> <span class="k">fn</span> <span class="nf">write_str</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">,</span> <span class="n">text</span><span class="p">:</span> <span class="o">&amp;</span><span class="nb">str</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="nb">Result</span><span class="o">&lt;</span><span class="p">(),</span> <span class="n">E</span><span class="o">&gt;</span> 
</code></pre></div></div>

<p>In a <code class="language-plaintext highlighter-rouge">std</code> environment, I would just call <code class="language-plaintext highlighter-rouge">format!</code> to make a <code class="language-plaintext highlighter-rouge">&amp;str</code>. But, apparently I cannot do that in a <code class="language-plaintext highlighter-rouge">no-std</code> environment. After a struggle to find a way to convert <code class="language-plaintext highlighter-rouge">u32</code> to <code class="language-plaintext highlighter-rouge">&amp;str</code>, I managed to achieve that with <a href="https://crates.io/crates/heapless"><code class="language-plaintext highlighter-rouge">heapless</code></a> crate. With <code class="language-plaintext highlighter-rouge">heapless::String</code> and <code class="language-plaintext highlighter-rouge">write!</code> macro, I can create formatted texts.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">use</span> <span class="nn">core</span><span class="p">::</span><span class="nn">fmt</span><span class="p">::</span><span class="n">Write</span><span class="p">;</span>
<span class="k">use</span> <span class="nn">heapless</span><span class="p">::</span><span class="nn">consts</span><span class="p">::</span><span class="o">*</span><span class="p">;</span>
<span class="k">use</span> <span class="nn">heapless</span><span class="p">::</span><span class="nb">String</span><span class="p">;</span>

<span class="k">let</span> <span class="k">mut</span> <span class="n">data</span> <span class="o">=</span> <span class="nn">String</span><span class="p">::</span><span class="o">&lt;</span><span class="n">U8</span><span class="o">&gt;</span><span class="p">::</span><span class="nf">new</span><span class="p">();</span>

<span class="k">loop</span> <span class="p">{</span>
    <span class="k">let</span> <span class="n">distance</span> <span class="o">=</span> <span class="n">sonar</span><span class="nf">.read</span><span class="p">();</span>
    <span class="k">let</span> <span class="n">_</span> <span class="o">=</span> <span class="nd">write!</span><span class="p">(</span><span class="n">data</span><span class="p">,</span> <span class="s">"{:7}{}"</span><span class="p">,</span> <span class="n">distance</span><span class="p">,</span> <span class="n">sonar</span><span class="nf">.unit</span><span class="p">());</span>
    <span class="n">max6955</span><span class="nf">.write_str</span><span class="p">(</span><span class="o">&amp;</span><span class="n">data</span><span class="p">)</span><span class="nf">.unwrap</span><span class="p">();</span>
    <span class="n">data</span><span class="nf">.clear</span><span class="p">();</span>
<span class="p">}</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">sonar.unit()</code> returns the unit for the chosen model. So, it is <code class="language-plaintext highlighter-rouge">"</code> here.</p>

<ul>
  <li>The code is <a href="https://github.com/lonesometraveler/maxbotix">available on GitHub</a></li>
</ul>]]></content><author><name>lonesometraveler</name><email>lonesometraveler@mac.com</email></author><category term="Rust" /><category term="embedded" /><summary type="html"><![CDATA[]]></summary></entry><entry><title type="html">GPIO Interrupt: Let Me Know When You Need Me</title><link href="https://lonesometraveler.github.io/2020/04/17/GPIO_interrupt.html" rel="alternate" type="text/html" title="GPIO Interrupt: Let Me Know When You Need Me" /><published>2020-04-17T12:16:21+00:00</published><updated>2020-04-17T12:16:21+00:00</updated><id>https://lonesometraveler.github.io/2020/04/17/GPIO_interrupt</id><content type="html" xml:base="https://lonesometraveler.github.io/2020/04/17/GPIO_interrupt.html"><![CDATA[<p>After <a href="https://lonesometraveler.github.io/2020/04/04/timer-interrupt.html">the successful timer interrupt experiments</a>, I worked on GPIO interrupts this week.</p>

<p>For STM32 microcontrollers, we use EXTI (external interrupt controller) and do these to configure GPIO interrupts:</p>

<ul>
  <li>Enable peripheral clocks.</li>
  <li>Configure an input pin and set the edge detection.</li>
  <li>Unmask the interrupt mask register.</li>
</ul>

<p>Once properly configured, an interrupt request is generated when the selected edge occurs on the external interrupt line.</p>

<p>In this post, I will show 3 example programs that demonstrate GPIO interrupt.</p>

<ol>
  <li>GPIO interrupt with one button</li>
  <li>GPIO interrupt with two buttons and how to tell which one triggers an interrupt</li>
  <li>Interrupt with two buttons in a different way</li>
</ol>

<p>The goal is to control LEDs when buttons are pressed. I used Nucleo-F429ZI and <a href="https://github.com/stm32-rs/stm32f4xx-hal">stm32f4xx-hal</a> for all three of them.</p>

<h2 id="example-1-interrupt-with-one-button">Example 1: Interrupt with One Button</h2>

<h3 id="enable-peripheral-clocks">Enable peripheral clocks</h3>

<p>First, we need to turn on <code class="language-plaintext highlighter-rouge">SYSCFG</code> (System Configuration) peripheral.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="k">mut</span> <span class="n">dp</span> <span class="o">=</span> <span class="nn">stm32</span><span class="p">::</span><span class="nn">Peripherals</span><span class="p">::</span><span class="nf">take</span><span class="p">()</span><span class="nf">.unwrap</span><span class="p">();</span>
<span class="n">dp</span><span class="py">.RCC.apb2enr</span><span class="nf">.write</span><span class="p">(|</span><span class="n">w</span><span class="p">|</span> <span class="n">w</span><span class="nf">.syscfgen</span><span class="p">()</span><span class="nf">.enabled</span><span class="p">());</span>
</code></pre></div></div>

<h3 id="configure-a-led-and-a-button">Configure a LED and a button</h3>

<p>I need to access my button and LED in both ISR and user contexts. So, I wrap them with <code class="language-plaintext highlighter-rouge">Mutex</code>. Note that the initial values are <code class="language-plaintext highlighter-rouge">None</code> here. I will replace them with initialized instances later.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">static</span> <span class="n">BUTTON</span><span class="p">:</span> <span class="n">Mutex</span><span class="o">&lt;</span><span class="n">RefCell</span><span class="o">&lt;</span><span class="nb">Option</span><span class="o">&lt;</span><span class="n">PC13</span><span class="o">&lt;</span><span class="n">Input</span><span class="o">&lt;</span><span class="n">PullDown</span><span class="o">&gt;&gt;&gt;&gt;&gt;</span> <span class="o">=</span> <span class="nn">Mutex</span><span class="p">::</span><span class="nf">new</span><span class="p">(</span><span class="nn">RefCell</span><span class="p">::</span><span class="nf">new</span><span class="p">(</span><span class="nb">None</span><span class="p">));</span>
<span class="k">static</span> <span class="n">LED</span><span class="p">:</span> <span class="n">Mutex</span><span class="o">&lt;</span><span class="n">RefCell</span><span class="o">&lt;</span><span class="nb">Option</span><span class="o">&lt;</span><span class="n">PB7</span><span class="o">&lt;</span><span class="n">Output</span><span class="o">&lt;</span><span class="n">PushPull</span><span class="o">&gt;&gt;&gt;&gt;&gt;</span> <span class="o">=</span> <span class="nn">Mutex</span><span class="p">::</span><span class="nf">new</span><span class="p">(</span><span class="nn">RefCell</span><span class="p">::</span><span class="nf">new</span><span class="p">(</span><span class="nb">None</span><span class="p">));</span>
</code></pre></div></div>

<p>Nucleo-F429ZI’s pin <code class="language-plaintext highlighter-rouge">pc13</code> is connected to the user button. After setting it up as a pull down input, I set the edge detection to <code class="language-plaintext highlighter-rouge">RISING</code>.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="n">gpioc</span> <span class="o">=</span> <span class="n">dp</span><span class="py">.GPIOC</span><span class="nf">.split</span><span class="p">();</span>
<span class="k">let</span> <span class="k">mut</span> <span class="n">user_button</span> <span class="o">=</span> <span class="n">gpioc</span><span class="py">.pc13</span><span class="nf">.into_pull_down_input</span><span class="p">();</span>
<span class="n">user_button</span><span class="nf">.make_interrupt_source</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="n">dp</span><span class="py">.SYSCFG</span><span class="p">);</span>
<span class="n">user_button</span><span class="nf">.enable_interrupt</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="n">dp</span><span class="py">.EXTI</span><span class="p">);</span>
<span class="n">user_button</span><span class="nf">.trigger_on_edge</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="n">dp</span><span class="py">.EXTI</span><span class="p">,</span> <span class="nn">Edge</span><span class="p">::</span><span class="n">RISING</span><span class="p">);</span>
</code></pre></div></div>

<p>I also set up my LED.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="n">gpiob</span> <span class="o">=</span> <span class="n">dp</span><span class="py">.GPIOB</span><span class="nf">.split</span><span class="p">();</span>
<span class="k">let</span> <span class="n">led</span> <span class="o">=</span> <span class="n">gpiob</span><span class="py">.pb7</span><span class="nf">.into_push_pull_output</span><span class="p">();</span>
</code></pre></div></div>

<p>I now move my initialized button and LED to Mutex. Moving the shared resources to Mutex makes it possible to access the LED and the button in both ISR and user contexts. I use critical section with <code class="language-plaintext highlighter-rouge">cortex_m::interrupt::free</code> and replace the shared resources’ content (<code class="language-plaintext highlighter-rouge">None</code>) with <code class="language-plaintext highlighter-rouge">user_button</code> and <code class="language-plaintext highlighter-rouge">led</code>.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nf">free</span><span class="p">(|</span><span class="n">cs</span><span class="p">|</span> <span class="p">{</span>
    <span class="n">BUTTON</span><span class="nf">.borrow</span><span class="p">(</span><span class="n">cs</span><span class="p">)</span><span class="nf">.replace</span><span class="p">(</span><span class="nf">Some</span><span class="p">(</span><span class="n">user_button</span><span class="p">));</span>
    <span class="n">LED</span><span class="nf">.borrow</span><span class="p">(</span><span class="n">cs</span><span class="p">)</span><span class="nf">.replace</span><span class="p">(</span><span class="nf">Some</span><span class="p">(</span><span class="n">led</span><span class="p">));</span>
<span class="p">});</span>
</code></pre></div></div>

<h3 id="unmask-and-enable-interrupt">Unmask and enable interrupt</h3>

<p>Interrupt can be enabled by unmasking NVIC’s register.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">unsafe</span> <span class="p">{</span>
    <span class="nn">stm32</span><span class="p">::</span><span class="nn">NVIC</span><span class="p">::</span><span class="nf">unmask</span><span class="p">(</span><span class="nn">stm32</span><span class="p">::</span><span class="nn">interrupt</span><span class="p">::</span><span class="n">EXTI15_10</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">EXTI15_10</code> means interrupt lines from 10 - 15. Whenever an interrupt is triggered on these lines (my button <code class="language-plaintext highlighter-rouge">pc13</code> is on line 13), EXTI calls this handler.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">#[interrupt]</span>
<span class="k">fn</span> <span class="nf">EXTI15_10</span><span class="p">()</span> <span class="p">{</span>
    <span class="nf">free</span><span class="p">(|</span><span class="n">cs</span><span class="p">|</span> <span class="p">{</span>
        <span class="k">if</span> <span class="k">let</span> <span class="nf">Some</span><span class="p">(</span><span class="k">ref</span> <span class="k">mut</span> <span class="n">btn</span><span class="p">)</span> <span class="o">=</span> <span class="n">BUTTON</span><span class="nf">.borrow</span><span class="p">(</span><span class="n">cs</span><span class="p">)</span><span class="nf">.borrow_mut</span><span class="p">()</span><span class="nf">.deref_mut</span><span class="p">()</span> <span class="p">{</span>
            <span class="n">btn</span><span class="nf">.clear_interrupt_pending_bit</span><span class="p">();</span>

            <span class="k">if</span> <span class="k">let</span> <span class="nf">Some</span><span class="p">(</span><span class="k">ref</span> <span class="k">mut</span> <span class="n">led</span><span class="p">)</span> <span class="o">=</span> <span class="n">LED</span><span class="nf">.borrow</span><span class="p">(</span><span class="n">cs</span><span class="p">)</span><span class="nf">.borrow_mut</span><span class="p">()</span><span class="nf">.deref_mut</span><span class="p">()</span> <span class="p">{</span>
                <span class="n">led</span><span class="nf">.toggle</span><span class="p">()</span><span class="nf">.unwrap</span><span class="p">();</span>
            <span class="p">}</span>
        <span class="p">}</span>
    <span class="p">});</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Here, I clear the interrupt flag by calling <code class="language-plaintext highlighter-rouge">btn.clear_interrupt_pending_bit()</code> and toggle the LED. (If I don’t clear the flag, it keeps calling the interrupt handler.)</p>

<ul>
  <li><a href="https://github.com/lonesometraveler/stm32f4xx-examples/blob/master/examples/gpio_interrupt_1.rs">Example 1 full code</a></li>
</ul>

<h2 id="example-2-interrupt-with-two-buttons">Example 2: Interrupt with Two Buttons</h2>

<p>Ok, that was pretty easy. But, as I said, <code class="language-plaintext highlighter-rouge">EXTI15_10</code> means interrupt requests can be generated from any of six lines. In the example above, we know it is <code class="language-plaintext highlighter-rouge">BUTTON</code> that triggers an interrupt because there are no other buttons. But, what if we have two buttons and want to call different functions depending on which button is pressed? My second example handles interrupt requests from two buttons.</p>

<h3 id="configure-resources">Configure resources</h3>

<p>This time, I declare two sets of button/LED.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">static</span> <span class="n">BUTTON</span><span class="p">:</span> <span class="n">Mutex</span><span class="o">&lt;</span><span class="n">RefCell</span><span class="o">&lt;</span><span class="nb">Option</span><span class="o">&lt;</span><span class="n">PC13</span><span class="o">&lt;</span><span class="n">Input</span><span class="o">&lt;</span><span class="n">PullDown</span><span class="o">&gt;&gt;&gt;&gt;&gt;</span> <span class="o">=</span> <span class="nn">Mutex</span><span class="p">::</span><span class="nf">new</span><span class="p">(</span><span class="nn">RefCell</span><span class="p">::</span><span class="nf">new</span><span class="p">(</span><span class="nb">None</span><span class="p">));</span>
<span class="k">static</span> <span class="n">LED</span><span class="p">:</span> <span class="n">Mutex</span><span class="o">&lt;</span><span class="n">RefCell</span><span class="o">&lt;</span><span class="nb">Option</span><span class="o">&lt;</span><span class="n">PB7</span><span class="o">&lt;</span><span class="n">Output</span><span class="o">&lt;</span><span class="n">PushPull</span><span class="o">&gt;&gt;&gt;&gt;&gt;</span> <span class="o">=</span> <span class="nn">Mutex</span><span class="p">::</span><span class="nf">new</span><span class="p">(</span><span class="nn">RefCell</span><span class="p">::</span><span class="nf">new</span><span class="p">(</span><span class="nb">None</span><span class="p">));</span>
<span class="k">static</span> <span class="n">ANOTHER_BUTTON</span><span class="p">:</span> <span class="n">Mutex</span><span class="o">&lt;</span><span class="n">RefCell</span><span class="o">&lt;</span><span class="nb">Option</span><span class="o">&lt;</span><span class="n">PC10</span><span class="o">&lt;</span><span class="n">Input</span><span class="o">&lt;</span><span class="n">PullUp</span><span class="o">&gt;&gt;&gt;&gt;&gt;</span> <span class="o">=</span> <span class="nn">Mutex</span><span class="p">::</span><span class="nf">new</span><span class="p">(</span><span class="nn">RefCell</span><span class="p">::</span><span class="nf">new</span><span class="p">(</span><span class="nb">None</span><span class="p">));</span>
<span class="k">static</span> <span class="n">ANOTHER_LED</span><span class="p">:</span> <span class="n">Mutex</span><span class="o">&lt;</span><span class="n">RefCell</span><span class="o">&lt;</span><span class="nb">Option</span><span class="o">&lt;</span><span class="n">PB14</span><span class="o">&lt;</span><span class="n">Output</span><span class="o">&lt;</span><span class="n">PushPull</span><span class="o">&gt;&gt;&gt;&gt;&gt;</span> <span class="o">=</span> <span class="nn">Mutex</span><span class="p">::</span><span class="nf">new</span><span class="p">(</span><span class="nn">RefCell</span><span class="p">::</span><span class="nf">new</span><span class="p">(</span><span class="nb">None</span><span class="p">));</span>
</code></pre></div></div>

<p>I also declare a Mutex for the external interrupt controller.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">static</span> <span class="n">EXTI</span><span class="p">:</span> <span class="n">Mutex</span><span class="o">&lt;</span><span class="n">RefCell</span><span class="o">&lt;</span><span class="nb">Option</span><span class="o">&lt;</span><span class="nn">stm32</span><span class="p">::</span><span class="n">EXTI</span><span class="o">&gt;&gt;&gt;</span> <span class="o">=</span> <span class="nn">Mutex</span><span class="p">::</span><span class="nf">new</span><span class="p">(</span><span class="nn">RefCell</span><span class="p">::</span><span class="nf">new</span><span class="p">(</span><span class="nb">None</span><span class="p">));</span>
</code></pre></div></div>

<p>Just like the first example, I configure buttons and LEDs. I then wrap my resources with <code class="language-plaintext highlighter-rouge">Mutex</code>. This time, I wrap an instance of the external interrupt controller as well. I need <code class="language-plaintext highlighter-rouge">EXTI</code> to determine where an interrupt request is generated in the ISR.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="n">exti</span> <span class="o">=</span> <span class="n">dp</span><span class="py">.EXTI</span><span class="p">;</span> <span class="c1">// External Interrupt Controller</span>

<span class="nf">free</span><span class="p">(|</span><span class="n">cs</span><span class="p">|</span> <span class="p">{</span>
    <span class="n">BUTTON</span><span class="nf">.borrow</span><span class="p">(</span><span class="n">cs</span><span class="p">)</span><span class="nf">.replace</span><span class="p">(</span><span class="nf">Some</span><span class="p">(</span><span class="n">user_button</span><span class="p">));</span>
    <span class="n">LED</span><span class="nf">.borrow</span><span class="p">(</span><span class="n">cs</span><span class="p">)</span><span class="nf">.replace</span><span class="p">(</span><span class="nf">Some</span><span class="p">(</span><span class="n">led</span><span class="p">));</span>
    <span class="n">ANOTHER_BUTTON</span><span class="nf">.borrow</span><span class="p">(</span><span class="n">cs</span><span class="p">)</span><span class="nf">.replace</span><span class="p">(</span><span class="nf">Some</span><span class="p">(</span><span class="n">another_button</span><span class="p">));</span>
    <span class="n">ANOTHER_LED</span><span class="nf">.borrow</span><span class="p">(</span><span class="n">cs</span><span class="p">)</span><span class="nf">.replace</span><span class="p">(</span><span class="nf">Some</span><span class="p">(</span><span class="n">another_led</span><span class="p">));</span>
    <span class="n">EXTI</span><span class="nf">.borrow</span><span class="p">(</span><span class="n">cs</span><span class="p">)</span><span class="nf">.replace</span><span class="p">(</span><span class="nf">Some</span><span class="p">(</span><span class="n">exti</span><span class="p">));</span>
<span class="p">});</span>
</code></pre></div></div>

<h3 id="find-out-where-the-interrupt-comes-from">Find out where the interrupt comes from</h3>

<p>I now have two buttons: one on line 10 and the other on line 13. I want to find out which button is pressed and call a corresponding callback function. Here are my two callback functions.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">fn</span> <span class="nf">user_button_cb</span><span class="p">()</span> <span class="p">{</span>
    <span class="nf">free</span><span class="p">(|</span><span class="n">cs</span><span class="p">|</span> <span class="p">{</span>
        <span class="k">if</span> <span class="k">let</span> <span class="nf">Some</span><span class="p">(</span><span class="k">ref</span> <span class="k">mut</span> <span class="n">btn</span><span class="p">)</span> <span class="o">=</span> <span class="n">BUTTON</span><span class="nf">.borrow</span><span class="p">(</span><span class="n">cs</span><span class="p">)</span><span class="nf">.borrow_mut</span><span class="p">()</span><span class="nf">.deref_mut</span><span class="p">()</span> <span class="p">{</span>
            <span class="c1">// Clear the interrupt flag</span>
            <span class="n">btn</span><span class="nf">.clear_interrupt_pending_bit</span><span class="p">();</span>

            <span class="k">if</span> <span class="k">let</span> <span class="nf">Some</span><span class="p">(</span><span class="k">ref</span> <span class="k">mut</span> <span class="n">led</span><span class="p">)</span> <span class="o">=</span> <span class="n">LED</span><span class="nf">.borrow</span><span class="p">(</span><span class="n">cs</span><span class="p">)</span><span class="nf">.borrow_mut</span><span class="p">()</span><span class="nf">.deref_mut</span><span class="p">()</span> <span class="p">{</span>
                <span class="n">led</span><span class="nf">.toggle</span><span class="p">()</span><span class="nf">.unwrap</span><span class="p">();</span>
            <span class="p">}</span>
        <span class="p">}</span>
    <span class="p">});</span>
<span class="p">}</span>

<span class="k">fn</span> <span class="nf">another_button_cb</span><span class="p">()</span> <span class="p">{</span>
    <span class="nf">free</span><span class="p">(|</span><span class="n">cs</span><span class="p">|</span> <span class="p">{</span>
        <span class="k">if</span> <span class="k">let</span> <span class="nf">Some</span><span class="p">(</span><span class="k">ref</span> <span class="k">mut</span> <span class="n">btn</span><span class="p">)</span> <span class="o">=</span> <span class="n">ANOTHER_BUTTON</span><span class="nf">.borrow</span><span class="p">(</span><span class="n">cs</span><span class="p">)</span><span class="nf">.borrow_mut</span><span class="p">()</span><span class="nf">.deref_mut</span><span class="p">()</span> <span class="p">{</span>
            <span class="c1">// Clear the interrupt flag</span>
            <span class="n">btn</span><span class="nf">.clear_interrupt_pending_bit</span><span class="p">();</span>

            <span class="k">if</span> <span class="k">let</span> <span class="nf">Some</span><span class="p">(</span><span class="k">ref</span> <span class="k">mut</span> <span class="n">led</span><span class="p">)</span> <span class="o">=</span> <span class="n">ANOTHER_LED</span><span class="nf">.borrow</span><span class="p">(</span><span class="n">cs</span><span class="p">)</span><span class="nf">.borrow_mut</span><span class="p">()</span><span class="nf">.deref_mut</span><span class="p">()</span> <span class="p">{</span>
                <span class="n">led</span><span class="nf">.toggle</span><span class="p">()</span><span class="nf">.unwrap</span><span class="p">();</span>
            <span class="p">}</span>
        <span class="p">}</span>
    <span class="p">});</span>
<span class="p">}</span>
</code></pre></div></div>

<p>And this is how my interrupt handler tells which button is pressed.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">#[interrupt]</span>
<span class="k">fn</span> <span class="nf">EXTI15_10</span><span class="p">()</span> <span class="p">{</span>
    <span class="nf">free</span><span class="p">(|</span><span class="n">cs</span><span class="p">|</span> <span class="p">{</span>
        <span class="k">if</span> <span class="k">let</span> <span class="nf">Some</span><span class="p">(</span><span class="k">ref</span> <span class="k">mut</span> <span class="n">exti</span><span class="p">)</span> <span class="o">=</span> <span class="n">EXTI</span><span class="nf">.borrow</span><span class="p">(</span><span class="n">cs</span><span class="p">)</span><span class="nf">.borrow_mut</span><span class="p">()</span><span class="nf">.deref_mut</span><span class="p">()</span> <span class="p">{</span>
            <span class="k">let</span> <span class="n">pr</span> <span class="o">=</span> <span class="n">exti</span><span class="py">.pr</span><span class="nf">.read</span><span class="p">();</span>
            <span class="c1">// Interrupt on line 13?</span>
            <span class="k">if</span> <span class="n">pr</span><span class="nf">.pr13</span><span class="p">()</span><span class="nf">.bit_is_set</span><span class="p">()</span> <span class="p">{</span>
                <span class="nf">user_button_cb</span><span class="p">();</span>
            <span class="p">}</span>
            <span class="c1">// Interrupt on line 10?</span>
            <span class="k">if</span> <span class="n">pr</span><span class="nf">.pr10</span><span class="p">()</span><span class="nf">.bit_is_set</span><span class="p">()</span> <span class="p">{</span>
                <span class="nf">another_button_cb</span><span class="p">();</span>
            <span class="p">}</span>
        <span class="p">}</span>
    <span class="p">});</span>
<span class="p">}</span>
</code></pre></div></div>

<p>When an interrupt is triggered, the pending bit corresponding to the interrupt line is set. In the interrupt handler, I evaluate the external interrupt controller’s PR register and call a corresponding callback.</p>

<ul>
  <li><a href="https://github.com/lonesometraveler/stm32f4xx-examples/blob/master/examples/gpio_interrupt_2.rs">Example 2 full code</a></li>
</ul>

<h2 id="example-3-another-way-of-two-buttons">Example 3: Another Way of Two Buttons</h2>

<p>Example 2 works fine. But, if I touch <code class="language-plaintext highlighter-rouge">EXTI</code>’s PR register, I can easily clear interrupt flags by directly writing to it. As we see in example 2, when an interrupt is triggered, the pending bit corresponding to the interrupt line is set. This request can be reset by writing a <code class="language-plaintext highlighter-rouge">1</code> in the pending register. Actually, <code class="language-plaintext highlighter-rouge">stm32f4xx-hal</code>’s <code class="language-plaintext highlighter-rouge">clear_interrupt_pending_bit()</code> method does exactly that:</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">fn</span> <span class="nf">clear_interrupt_pending_bit</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">unsafe</span> <span class="p">{</span> <span class="p">(</span><span class="o">*</span><span class="nn">EXTI</span><span class="p">::</span><span class="nf">ptr</span><span class="p">())</span><span class="py">.pr</span><span class="nf">.write</span><span class="p">(|</span><span class="n">w</span><span class="p">|</span> <span class="n">w</span><span class="nf">.bits</span><span class="p">(</span><span class="mi">1</span> <span class="o">&lt;&lt;</span> <span class="k">self</span><span class="py">.i</span><span class="p">)</span> <span class="p">)</span> <span class="p">};</span>
<span class="p">}</span>
</code></pre></div></div>

<p>I am accessing EXTI anyway. Why don’t I clear the flag by directly writing to the PR register?</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">#[interrupt]</span>
<span class="k">fn</span> <span class="nf">EXTI15_10</span><span class="p">()</span> <span class="p">{</span>
    <span class="nf">free</span><span class="p">(|</span><span class="n">cs</span><span class="p">|</span> <span class="p">{</span>
        <span class="k">if</span> <span class="k">let</span> <span class="nf">Some</span><span class="p">(</span><span class="k">ref</span> <span class="k">mut</span> <span class="n">exti</span><span class="p">)</span> <span class="o">=</span> <span class="n">EXTI</span><span class="nf">.borrow</span><span class="p">(</span><span class="n">cs</span><span class="p">)</span><span class="nf">.borrow_mut</span><span class="p">()</span><span class="nf">.deref_mut</span><span class="p">()</span> <span class="p">{</span>
            <span class="k">let</span> <span class="n">pr</span> <span class="o">=</span> <span class="n">exti</span><span class="py">.pr</span><span class="nf">.read</span><span class="p">();</span>
            <span class="c1">// Interrupt on line 13?</span>
            <span class="k">if</span> <span class="n">pr</span><span class="nf">.pr13</span><span class="p">()</span><span class="nf">.bit_is_set</span><span class="p">()</span> <span class="p">{</span>
                <span class="c1">// Clear the interrupt flag</span>
                <span class="n">exti</span><span class="py">.pr</span><span class="nf">.write</span><span class="p">(|</span><span class="n">w</span><span class="p">|</span> <span class="n">w</span><span class="nf">.pr13</span><span class="p">()</span><span class="nf">.set_bit</span><span class="p">());</span>
                <span class="nf">user_button_cb</span><span class="p">();</span>
            <span class="p">}</span>
            <span class="c1">// Interrupt on line 10?</span>
            <span class="k">if</span> <span class="n">pr</span><span class="nf">.pr10</span><span class="p">()</span><span class="nf">.bit_is_set</span><span class="p">()</span> <span class="p">{</span>
                <span class="c1">// Clear the interrupt flag</span>
                <span class="n">exti</span><span class="py">.pr</span><span class="nf">.write</span><span class="p">(|</span><span class="n">w</span><span class="p">|</span> <span class="n">w</span><span class="nf">.pr10</span><span class="p">()</span><span class="nf">.set_bit</span><span class="p">());</span>
                <span class="nf">another_button_cb</span><span class="p">();</span>
            <span class="p">}</span>
        <span class="p">}</span>
    <span class="p">});</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Since <code class="language-plaintext highlighter-rouge">exti.pr.write(|w| w.pr13().set_bit());</code> clears the interrupt flag, I no longer need to call my button’s <code class="language-plaintext highlighter-rouge">clear_interrupt_pending_bit()</code> in my callbacks.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">fn</span> <span class="nf">user_button_cb</span><span class="p">()</span> <span class="p">{</span>
    <span class="nf">free</span><span class="p">(|</span><span class="n">cs</span><span class="p">|</span> <span class="p">{</span>
        <span class="k">if</span> <span class="k">let</span> <span class="nf">Some</span><span class="p">(</span><span class="k">ref</span> <span class="k">mut</span> <span class="n">led</span><span class="p">)</span> <span class="o">=</span> <span class="n">LED</span><span class="nf">.borrow</span><span class="p">(</span><span class="n">cs</span><span class="p">)</span><span class="nf">.borrow_mut</span><span class="p">()</span><span class="nf">.deref_mut</span><span class="p">()</span> <span class="p">{</span>
            <span class="n">led</span><span class="nf">.toggle</span><span class="p">()</span><span class="nf">.unwrap</span><span class="p">();</span>
        <span class="p">}</span>
    <span class="p">});</span>
<span class="p">}</span>

<span class="k">fn</span> <span class="nf">another_button_cb</span><span class="p">()</span> <span class="p">{</span>
    <span class="nf">free</span><span class="p">(|</span><span class="n">cs</span><span class="p">|</span> <span class="p">{</span>
        <span class="k">if</span> <span class="k">let</span> <span class="nf">Some</span><span class="p">(</span><span class="k">ref</span> <span class="k">mut</span> <span class="n">led</span><span class="p">)</span> <span class="o">=</span> <span class="n">ANOTHER_LED</span><span class="nf">.borrow</span><span class="p">(</span><span class="n">cs</span><span class="p">)</span><span class="nf">.borrow_mut</span><span class="p">()</span><span class="nf">.deref_mut</span><span class="p">()</span> <span class="p">{</span>
            <span class="n">led</span><span class="nf">.toggle</span><span class="p">()</span><span class="nf">.unwrap</span><span class="p">();</span>
        <span class="p">}</span>
    <span class="p">});</span>
<span class="p">}</span>
</code></pre></div></div>

<p>If I do it this way, I don’t even need Mutex for my buttons anymore. Once I configure the buttons and enable the interrupt, they generate interrupt requests and I can access them through EXTI. I don’t need my buttons in the interrupt handler. So, my shared resources are now just LEDs and EXTI.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">static</span> <span class="n">LED</span><span class="p">:</span> <span class="n">Mutex</span><span class="o">&lt;</span><span class="n">RefCell</span><span class="o">&lt;</span><span class="nb">Option</span><span class="o">&lt;</span><span class="n">PB7</span><span class="o">&lt;</span><span class="n">Output</span><span class="o">&lt;</span><span class="n">PushPull</span><span class="o">&gt;&gt;&gt;&gt;&gt;</span> <span class="o">=</span> <span class="nn">Mutex</span><span class="p">::</span><span class="nf">new</span><span class="p">(</span><span class="nn">RefCell</span><span class="p">::</span><span class="nf">new</span><span class="p">(</span><span class="nb">None</span><span class="p">));</span>
<span class="k">static</span> <span class="n">ANOTHER_LED</span><span class="p">:</span> <span class="n">Mutex</span><span class="o">&lt;</span><span class="n">RefCell</span><span class="o">&lt;</span><span class="nb">Option</span><span class="o">&lt;</span><span class="n">PB14</span><span class="o">&lt;</span><span class="n">Output</span><span class="o">&lt;</span><span class="n">PushPull</span><span class="o">&gt;&gt;&gt;&gt;&gt;</span> <span class="o">=</span> <span class="nn">Mutex</span><span class="p">::</span><span class="nf">new</span><span class="p">(</span><span class="nn">RefCell</span><span class="p">::</span><span class="nf">new</span><span class="p">(</span><span class="nb">None</span><span class="p">));</span>
<span class="k">static</span> <span class="n">EXTI</span><span class="p">:</span> <span class="n">Mutex</span><span class="o">&lt;</span><span class="n">RefCell</span><span class="o">&lt;</span><span class="nb">Option</span><span class="o">&lt;</span><span class="nn">stm32</span><span class="p">::</span><span class="n">EXTI</span><span class="o">&gt;&gt;&gt;</span> <span class="o">=</span> <span class="nn">Mutex</span><span class="p">::</span><span class="nf">new</span><span class="p">(</span><span class="nn">RefCell</span><span class="p">::</span><span class="nf">new</span><span class="p">(</span><span class="nb">None</span><span class="p">));</span>
</code></pre></div></div>

<ul>
  <li><a href="https://github.com/lonesometraveler/stm32f4xx-examples/blob/master/examples/gpio_interrupt_3.rs">Example 3 full code</a></li>
</ul>]]></content><author><name>lonesometraveler</name><email>lonesometraveler@mac.com</email></author><category term="Rust" /><category term="embedded" /><summary type="html"><![CDATA[After the successful timer interrupt experiments, I worked on GPIO interrupts this week.]]></summary></entry><entry><title type="html">LSM9DS1: Using a Trait to Support SPI and I2C Interfaces</title><link href="https://lonesometraveler.github.io/2020/04/10/lsm9ds1-trait.html" rel="alternate" type="text/html" title="LSM9DS1: Using a Trait to Support SPI and I2C Interfaces" /><published>2020-04-10T15:16:21+00:00</published><updated>2020-04-10T15:16:21+00:00</updated><id>https://lonesometraveler.github.io/2020/04/10/lsm9ds1-trait</id><content type="html" xml:base="https://lonesometraveler.github.io/2020/04/10/lsm9ds1-trait.html"><![CDATA[<p><a href="https://www.st.com/resource/en/datasheet/lsm9ds1.pdf">LSM9DS1</a> is a 9 axis motion sensor module that comes with accelerometer, gyroscope, magnetometer, and temperature sensor. A cool thing about this device is that it has I2C and SPI interfaces. In this post, I will show how I supported both interfaces with <code class="language-plaintext highlighter-rouge">trait</code>.</p>

<h2 id="supporting-spi-and-i2c-interfaces">Supporting SPI and I2C interfaces</h2>

<p>My first idea was to have two different constructors (one for SPI and the other for I2C) and implement the corresponding read and write methods like <code class="language-plaintext highlighter-rouge">spi_write()</code>, <code class="language-plaintext highlighter-rouge">i2c_write()</code> at the highest level. But, it didn’t sound right. There would be too many duplicates… So, I decided to solve the problem with a generic trait object.</p>

<h3 id="generic-interface">Generic interface</h3>

<p>First, I defined a trait named <code class="language-plaintext highlighter-rouge">Interface</code>.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cd">/// Interface Trait. `SpiInterface` and `I2cInterface` implement this.</span>
<span class="k">pub</span> <span class="k">trait</span> <span class="n">Interface</span> <span class="p">{</span>
    <span class="k">type</span> <span class="n">Error</span><span class="p">;</span>

    <span class="cd">/// Writes a byte to a sensor's specified register address.</span>
    <span class="cd">/// # Arguments</span>
    <span class="cd">/// * `sensor` - `Sensor` to talk to</span>
    <span class="cd">/// * `addr` - register address</span>
    <span class="cd">/// * `value` - value to write</span>
    <span class="k">fn</span> <span class="nf">write</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">,</span> <span class="n">sensor</span><span class="p">:</span> <span class="n">Sensor</span><span class="p">,</span> <span class="n">addr</span><span class="p">:</span> <span class="nb">u8</span><span class="p">,</span> <span class="n">value</span><span class="p">:</span> <span class="nb">u8</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="nb">Result</span><span class="o">&lt;</span><span class="p">(),</span> <span class="k">Self</span><span class="p">::</span><span class="n">Error</span><span class="o">&gt;</span><span class="p">;</span>
    <span class="cd">/// Reads multiple bytes from a sensor's specified register address.</span>
    <span class="cd">/// # Arguments</span>
    <span class="cd">/// * `sensor` - `Sensor` to talk to</span>
    <span class="cd">/// * `addr` - register address</span>
    <span class="cd">/// * `buffer` - buffer to store read data</span>
    <span class="k">fn</span> <span class="nf">read</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">,</span> <span class="n">sensor</span><span class="p">:</span> <span class="n">Sensor</span><span class="p">,</span> <span class="n">addr</span><span class="p">:</span> <span class="nb">u8</span><span class="p">,</span> <span class="n">buffer</span><span class="p">:</span> <span class="o">&amp;</span><span class="k">mut</span> <span class="p">[</span><span class="nb">u8</span><span class="p">])</span> <span class="k">-&gt;</span> <span class="nb">Result</span><span class="o">&lt;</span><span class="p">(),</span> <span class="k">Self</span><span class="p">::</span><span class="n">Error</span><span class="o">&gt;</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>As you can see, there is no real implementation here. This only defines shared behaviors that are meant to be implemented by SPI and I2C types.</p>

<h3 id="implementing-a-trait-on-a-type">Implementing a trait on a type</h3>

<p>Now let’s look at SPI and I2C <code class="language-plaintext highlighter-rouge">struct</code>s. SPI uses chip select pins to address a device to talk to while I2C communicates with a device by specifying its address. So, the <code class="language-plaintext highlighter-rouge">struct</code>s for SPI and I2C are very different. They take completely different arguments.</p>

<p>Here is how I defined <code class="language-plaintext highlighter-rouge">SpiInterface</code> type and its <code class="language-plaintext highlighter-rouge">init</code> method.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cd">/// This combines the SPI Interface and chip select pins</span>
<span class="k">pub</span> <span class="k">struct</span> <span class="n">SpiInterface</span><span class="o">&lt;</span><span class="n">SPI</span><span class="p">,</span> <span class="n">AG</span><span class="p">,</span> <span class="n">M</span><span class="o">&gt;</span> <span class="p">{</span>
    <span class="n">spi</span><span class="p">:</span> <span class="n">SPI</span><span class="p">,</span>
    <span class="n">ag_cs</span><span class="p">:</span> <span class="n">AG</span><span class="p">,</span>
    <span class="n">m_cs</span><span class="p">:</span> <span class="n">M</span><span class="p">,</span>
<span class="p">}</span>

<span class="k">impl</span><span class="o">&lt;</span><span class="n">SPI</span><span class="p">,</span> <span class="n">AG</span><span class="p">,</span> <span class="n">M</span><span class="p">,</span> <span class="n">CommE</span><span class="p">,</span> <span class="n">PinE</span><span class="o">&gt;</span> <span class="n">SpiInterface</span><span class="o">&lt;</span><span class="n">SPI</span><span class="p">,</span> <span class="n">AG</span><span class="p">,</span> <span class="n">M</span><span class="o">&gt;</span>
<span class="k">where</span>
    <span class="n">SPI</span><span class="p">:</span> <span class="n">Transfer</span><span class="o">&lt;</span><span class="nb">u8</span><span class="p">,</span> <span class="n">Error</span> <span class="o">=</span> <span class="n">CommE</span><span class="o">&gt;</span> <span class="o">+</span> <span class="n">Write</span><span class="o">&lt;</span><span class="nb">u8</span><span class="p">,</span> <span class="n">Error</span> <span class="o">=</span> <span class="n">CommE</span><span class="o">&gt;</span><span class="p">,</span>
    <span class="n">AG</span><span class="p">:</span> <span class="n">OutputPin</span><span class="o">&lt;</span><span class="n">Error</span> <span class="o">=</span> <span class="n">PinE</span><span class="o">&gt;</span><span class="p">,</span>
    <span class="n">M</span><span class="p">:</span> <span class="n">OutputPin</span><span class="o">&lt;</span><span class="n">Error</span> <span class="o">=</span> <span class="n">PinE</span><span class="o">&gt;</span><span class="p">,</span>
<span class="p">{</span>
    <span class="cd">/// Initializes an Interface with `SPI` instance and AG and M chip select `OutputPin`s</span>
    <span class="cd">/// # Arguments</span>
    <span class="cd">/// * `spi` - SPI instance</span>
    <span class="cd">/// * `ag_cs` - Chip Select pin for Accelerometer/Gyroscope</span>
    <span class="cd">/// * `m_cs` - Chip Select pin for Magnetometer</span>
    <span class="k">pub</span> <span class="k">fn</span> <span class="nf">init</span><span class="p">(</span><span class="n">spi</span><span class="p">:</span> <span class="n">SPI</span><span class="p">,</span> <span class="n">ag_cs</span><span class="p">:</span> <span class="n">AG</span><span class="p">,</span> <span class="n">m_cs</span><span class="p">:</span> <span class="n">M</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="k">Self</span> <span class="p">{</span>
        <span class="k">Self</span> <span class="p">{</span> <span class="n">spi</span><span class="p">,</span> <span class="n">ag_cs</span><span class="p">,</span> <span class="n">m_cs</span> <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>And here is <code class="language-plaintext highlighter-rouge">I2cInterface</code>. It takes I2C addresses.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cd">/// This holds `I2C` and AG and Mag addresses</span>
<span class="k">pub</span> <span class="k">struct</span> <span class="n">I2cInterface</span><span class="o">&lt;</span><span class="n">I2C</span><span class="o">&gt;</span> <span class="p">{</span>
    <span class="n">i2c</span><span class="p">:</span> <span class="n">I2C</span><span class="p">,</span>
    <span class="n">ag_addr</span><span class="p">:</span> <span class="nb">u8</span><span class="p">,</span>
    <span class="n">mag_addr</span><span class="p">:</span> <span class="nb">u8</span><span class="p">,</span>
<span class="p">}</span>

<span class="k">impl</span><span class="o">&lt;</span><span class="n">I2C</span><span class="o">&gt;</span> <span class="n">I2cInterface</span><span class="o">&lt;</span><span class="n">I2C</span><span class="o">&gt;</span> <span class="p">{</span>
    <span class="cd">/// Initializes an Interface with `I2C` instance and AG and Mag addresses</span>
    <span class="cd">/// # Arguments</span>
    <span class="cd">/// * `i2C` - I2C instance</span>
    <span class="cd">/// * `ag_addr` - `AgAddress`: register address for Accelerometer/Gyroscope</span>
    <span class="cd">/// * `mag_addr` - `MagAddress`: register address for Magnetometer</span>
    <span class="k">pub</span> <span class="k">fn</span> <span class="nf">init</span><span class="p">(</span><span class="n">i2c</span><span class="p">:</span> <span class="n">I2C</span><span class="p">,</span> <span class="n">ag_addr</span><span class="p">:</span> <span class="n">AgAddress</span><span class="p">,</span> <span class="n">mag_addr</span><span class="p">:</span> <span class="n">MagAddress</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="k">Self</span> <span class="p">{</span>
        <span class="k">Self</span> <span class="p">{</span>
            <span class="n">i2c</span><span class="p">,</span>
            <span class="n">ag_addr</span><span class="p">:</span> <span class="n">ag_addr</span><span class="nf">.addr</span><span class="p">(),</span>
            <span class="n">mag_addr</span><span class="p">:</span> <span class="n">mag_addr</span><span class="nf">.addr</span><span class="p">(),</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Although the two interfaces are very different, I can make them both <code class="language-plaintext highlighter-rouge">Interface</code> by implementing <code class="language-plaintext highlighter-rouge">Interface</code>’s <code class="language-plaintext highlighter-rouge">write</code> and <code class="language-plaintext highlighter-rouge">read</code> methods.</p>

<p>Here is the implementation of <code class="language-plaintext highlighter-rouge">Interface </code> on <code class="language-plaintext highlighter-rouge">SpiInterface</code>. You can see how it controls the chip select pins and communicates.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">impl</span><span class="o">&lt;</span><span class="n">SPI</span><span class="p">,</span> <span class="n">AG</span><span class="p">,</span> <span class="n">M</span><span class="p">,</span> <span class="n">CommE</span><span class="p">,</span> <span class="n">PinE</span><span class="o">&gt;</span> <span class="n">Interface</span> <span class="k">for</span> <span class="n">SpiInterface</span><span class="o">&lt;</span><span class="n">SPI</span><span class="p">,</span> <span class="n">AG</span><span class="p">,</span> <span class="n">M</span><span class="o">&gt;</span>
<span class="k">where</span>
    <span class="n">SPI</span><span class="p">:</span> <span class="n">Transfer</span><span class="o">&lt;</span><span class="nb">u8</span><span class="p">,</span> <span class="n">Error</span> <span class="o">=</span> <span class="n">CommE</span><span class="o">&gt;</span> <span class="o">+</span> <span class="n">Write</span><span class="o">&lt;</span><span class="nb">u8</span><span class="p">,</span> <span class="n">Error</span> <span class="o">=</span> <span class="n">CommE</span><span class="o">&gt;</span><span class="p">,</span>
    <span class="n">AG</span><span class="p">:</span> <span class="n">OutputPin</span><span class="o">&lt;</span><span class="n">Error</span> <span class="o">=</span> <span class="n">PinE</span><span class="o">&gt;</span><span class="p">,</span>
    <span class="n">M</span><span class="p">:</span> <span class="n">OutputPin</span><span class="o">&lt;</span><span class="n">Error</span> <span class="o">=</span> <span class="n">PinE</span><span class="o">&gt;</span><span class="p">,</span>
<span class="p">{</span>
    <span class="k">type</span> <span class="n">Error</span> <span class="o">=</span> <span class="n">Error</span><span class="o">&lt;</span><span class="n">CommE</span><span class="p">,</span> <span class="n">PinE</span><span class="o">&gt;</span><span class="p">;</span>

    <span class="k">fn</span> <span class="nf">write</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">,</span> <span class="n">sensor</span><span class="p">:</span> <span class="n">Sensor</span><span class="p">,</span> <span class="n">addr</span><span class="p">:</span> <span class="nb">u8</span><span class="p">,</span> <span class="n">value</span><span class="p">:</span> <span class="nb">u8</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="nb">Result</span><span class="o">&lt;</span><span class="p">(),</span> <span class="k">Self</span><span class="p">::</span><span class="n">Error</span><span class="o">&gt;</span> <span class="p">{</span>
        <span class="k">let</span> <span class="n">bytes</span> <span class="o">=</span> <span class="p">[</span><span class="n">addr</span><span class="p">,</span> <span class="n">value</span><span class="p">];</span>
        <span class="k">match</span> <span class="n">sensor</span> <span class="p">{</span>
            <span class="n">Accelerometer</span> <span class="p">|</span> <span class="n">Gyro</span> <span class="p">|</span> <span class="n">Temperature</span> <span class="k">=&gt;</span> <span class="p">{</span>
                <span class="k">self</span><span class="py">.ag_cs</span><span class="nf">.set_low</span><span class="p">()</span><span class="nf">.map_err</span><span class="p">(</span><span class="nn">Error</span><span class="p">::</span><span class="nb">Pin</span><span class="p">)</span><span class="o">?</span><span class="p">;</span>
                <span class="k">self</span><span class="py">.spi</span><span class="nf">.write</span><span class="p">(</span><span class="o">&amp;</span><span class="n">bytes</span><span class="p">)</span><span class="nf">.map_err</span><span class="p">(</span><span class="nn">Error</span><span class="p">::</span><span class="n">Comm</span><span class="p">)</span><span class="o">?</span><span class="p">;</span>
                <span class="k">self</span><span class="py">.ag_cs</span><span class="nf">.set_high</span><span class="p">()</span><span class="nf">.map_err</span><span class="p">(</span><span class="nn">Error</span><span class="p">::</span><span class="nb">Pin</span><span class="p">)</span><span class="o">?</span><span class="p">;</span>
            <span class="p">}</span>
            <span class="n">Magnetometer</span> <span class="k">=&gt;</span> <span class="p">{</span>
                <span class="k">self</span><span class="py">.m_cs</span><span class="nf">.set_low</span><span class="p">()</span><span class="nf">.map_err</span><span class="p">(</span><span class="nn">Error</span><span class="p">::</span><span class="nb">Pin</span><span class="p">)</span><span class="o">?</span><span class="p">;</span>
                <span class="k">self</span><span class="py">.spi</span><span class="nf">.write</span><span class="p">(</span><span class="o">&amp;</span><span class="n">bytes</span><span class="p">)</span><span class="nf">.map_err</span><span class="p">(</span><span class="nn">Error</span><span class="p">::</span><span class="n">Comm</span><span class="p">)</span><span class="o">?</span><span class="p">;</span>
                <span class="k">self</span><span class="py">.m_cs</span><span class="nf">.set_high</span><span class="p">()</span><span class="nf">.map_err</span><span class="p">(</span><span class="nn">Error</span><span class="p">::</span><span class="nb">Pin</span><span class="p">)</span><span class="o">?</span><span class="p">;</span>
            <span class="p">}</span>
        <span class="p">}</span>
        <span class="nf">Ok</span><span class="p">(())</span>
    <span class="p">}</span>

    <span class="k">fn</span> <span class="nf">read</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">,</span> <span class="n">sensor</span><span class="p">:</span> <span class="n">Sensor</span><span class="p">,</span> <span class="n">addr</span><span class="p">:</span> <span class="nb">u8</span><span class="p">,</span> <span class="n">buffer</span><span class="p">:</span> <span class="o">&amp;</span><span class="k">mut</span> <span class="p">[</span><span class="nb">u8</span><span class="p">])</span> <span class="k">-&gt;</span> <span class="nb">Result</span><span class="o">&lt;</span><span class="p">(),</span> <span class="k">Self</span><span class="p">::</span><span class="n">Error</span><span class="o">&gt;</span> <span class="p">{</span>
        <span class="k">match</span> <span class="n">sensor</span> <span class="p">{</span>
            <span class="n">Accelerometer</span> <span class="p">|</span> <span class="n">Gyro</span> <span class="p">|</span> <span class="n">Temperature</span> <span class="k">=&gt;</span> <span class="p">{</span>
                <span class="k">self</span><span class="py">.ag_cs</span><span class="nf">.set_low</span><span class="p">()</span><span class="nf">.map_err</span><span class="p">(</span><span class="nn">Error</span><span class="p">::</span><span class="nb">Pin</span><span class="p">)</span><span class="o">?</span><span class="p">;</span>
                <span class="k">self</span><span class="py">.spi</span><span class="nf">.write</span><span class="p">(</span><span class="o">&amp;</span><span class="p">[</span><span class="n">SPI_READ</span> <span class="p">|</span> <span class="n">addr</span><span class="p">])</span><span class="nf">.map_err</span><span class="p">(</span><span class="nn">Error</span><span class="p">::</span><span class="n">Comm</span><span class="p">)</span><span class="o">?</span><span class="p">;</span>
                <span class="k">self</span><span class="py">.spi</span><span class="nf">.transfer</span><span class="p">(</span><span class="n">buffer</span><span class="p">)</span><span class="nf">.map_err</span><span class="p">(</span><span class="nn">Error</span><span class="p">::</span><span class="n">Comm</span><span class="p">)</span><span class="o">?</span><span class="p">;</span>
                <span class="k">self</span><span class="py">.ag_cs</span><span class="nf">.set_high</span><span class="p">()</span><span class="nf">.map_err</span><span class="p">(</span><span class="nn">Error</span><span class="p">::</span><span class="nb">Pin</span><span class="p">)</span><span class="o">?</span><span class="p">;</span>
            <span class="p">}</span>
            <span class="n">Magnetometer</span> <span class="k">=&gt;</span> <span class="p">{</span>
                <span class="k">self</span><span class="py">.m_cs</span><span class="nf">.set_low</span><span class="p">()</span><span class="nf">.map_err</span><span class="p">(</span><span class="nn">Error</span><span class="p">::</span><span class="nb">Pin</span><span class="p">)</span><span class="o">?</span><span class="p">;</span>
                <span class="k">self</span><span class="py">.spi</span>
                    <span class="nf">.write</span><span class="p">(</span><span class="o">&amp;</span><span class="p">[</span><span class="n">SPI_READ</span> <span class="p">|</span> <span class="n">MS_BIT</span> <span class="p">|</span> <span class="n">addr</span><span class="p">])</span>
                    <span class="nf">.map_err</span><span class="p">(</span><span class="nn">Error</span><span class="p">::</span><span class="n">Comm</span><span class="p">)</span><span class="o">?</span><span class="p">;</span>
                <span class="k">self</span><span class="py">.spi</span><span class="nf">.transfer</span><span class="p">(</span><span class="n">buffer</span><span class="p">)</span><span class="nf">.map_err</span><span class="p">(</span><span class="nn">Error</span><span class="p">::</span><span class="n">Comm</span><span class="p">)</span><span class="o">?</span><span class="p">;</span>
                <span class="k">self</span><span class="py">.m_cs</span><span class="nf">.set_high</span><span class="p">()</span><span class="nf">.map_err</span><span class="p">(</span><span class="nn">Error</span><span class="p">::</span><span class="nb">Pin</span><span class="p">)</span><span class="o">?</span><span class="p">;</span>
            <span class="p">}</span>
        <span class="p">}</span>
        <span class="nf">Ok</span><span class="p">(())</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>And here is the implementation on <code class="language-plaintext highlighter-rouge">I2cInterface</code>. No chip select pins here. This uses an I2C address to specify a sensor.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">impl</span><span class="o">&lt;</span><span class="n">I2C</span><span class="p">,</span> <span class="n">CommE</span><span class="o">&gt;</span> <span class="n">Interface</span> <span class="k">for</span> <span class="n">I2cInterface</span><span class="o">&lt;</span><span class="n">I2C</span><span class="o">&gt;</span>
<span class="k">where</span>
    <span class="n">I2C</span><span class="p">:</span> <span class="n">WriteRead</span><span class="o">&lt;</span><span class="n">Error</span> <span class="o">=</span> <span class="n">CommE</span><span class="o">&gt;</span> <span class="o">+</span> <span class="n">Write</span><span class="o">&lt;</span><span class="n">Error</span> <span class="o">=</span> <span class="n">CommE</span><span class="o">&gt;</span><span class="p">,</span>
<span class="p">{</span>
    <span class="k">type</span> <span class="n">Error</span> <span class="o">=</span> <span class="n">Error</span><span class="o">&lt;</span><span class="n">CommE</span><span class="o">&gt;</span><span class="p">;</span>

    <span class="k">fn</span> <span class="nf">write</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">,</span> <span class="n">sensor</span><span class="p">:</span> <span class="n">Sensor</span><span class="p">,</span> <span class="n">addr</span><span class="p">:</span> <span class="nb">u8</span><span class="p">,</span> <span class="n">value</span><span class="p">:</span> <span class="nb">u8</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="nb">Result</span><span class="o">&lt;</span><span class="p">(),</span> <span class="k">Self</span><span class="p">::</span><span class="n">Error</span><span class="o">&gt;</span> <span class="p">{</span>
        <span class="k">let</span> <span class="n">sensor_addr</span> <span class="o">=</span> <span class="k">match</span> <span class="n">sensor</span> <span class="p">{</span>
            <span class="n">Accelerometer</span> <span class="p">|</span> <span class="n">Gyro</span> <span class="p">|</span> <span class="n">Temperature</span> <span class="k">=&gt;</span> <span class="k">self</span><span class="py">.ag_addr</span><span class="p">,</span>
            <span class="n">Magnetometer</span> <span class="k">=&gt;</span> <span class="k">self</span><span class="py">.mag_addr</span><span class="p">,</span>
        <span class="p">};</span>
        <span class="nn">core</span><span class="p">::</span><span class="nn">prelude</span><span class="p">::</span><span class="nn">v1</span><span class="p">::</span><span class="nf">Ok</span><span class="p">(</span>
            <span class="k">self</span><span class="py">.i2c</span>
                <span class="nf">.write</span><span class="p">(</span><span class="n">sensor_addr</span><span class="p">,</span> <span class="o">&amp;</span><span class="p">[</span><span class="n">addr</span><span class="p">,</span> <span class="n">value</span><span class="p">])</span>
                <span class="nf">.map_err</span><span class="p">(</span><span class="nn">Error</span><span class="p">::</span><span class="n">Comm</span><span class="p">)</span><span class="o">?</span><span class="p">,</span>
        <span class="p">)</span>
    <span class="p">}</span>

    <span class="k">fn</span> <span class="nf">read</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">,</span> <span class="n">sensor</span><span class="p">:</span> <span class="n">Sensor</span><span class="p">,</span> <span class="n">addr</span><span class="p">:</span> <span class="nb">u8</span><span class="p">,</span> <span class="n">buffer</span><span class="p">:</span> <span class="o">&amp;</span><span class="k">mut</span> <span class="p">[</span><span class="nb">u8</span><span class="p">])</span> <span class="k">-&gt;</span> <span class="nb">Result</span><span class="o">&lt;</span><span class="p">(),</span> <span class="k">Self</span><span class="p">::</span><span class="n">Error</span><span class="o">&gt;</span> <span class="p">{</span>
        <span class="k">let</span> <span class="n">sensor_addr</span> <span class="o">=</span> <span class="k">match</span> <span class="n">sensor</span> <span class="p">{</span>
            <span class="n">Accelerometer</span> <span class="p">|</span> <span class="n">Gyro</span> <span class="p">|</span> <span class="n">Temperature</span> <span class="k">=&gt;</span> <span class="k">self</span><span class="py">.ag_addr</span><span class="p">,</span>
            <span class="n">Magnetometer</span> <span class="k">=&gt;</span> <span class="k">self</span><span class="py">.mag_addr</span><span class="p">,</span>
        <span class="p">};</span>
        <span class="nn">core</span><span class="p">::</span><span class="nn">prelude</span><span class="p">::</span><span class="nn">v1</span><span class="p">::</span><span class="nf">Ok</span><span class="p">(</span>
            <span class="k">self</span><span class="py">.i2c</span>
                <span class="nf">.write_read</span><span class="p">(</span><span class="n">sensor_addr</span><span class="p">,</span> <span class="o">&amp;</span><span class="p">[</span><span class="n">addr</span><span class="p">],</span> <span class="n">buffer</span><span class="p">)</span>
                <span class="nf">.map_err</span><span class="p">(</span><span class="nn">Error</span><span class="p">::</span><span class="n">Comm</span><span class="p">)</span><span class="o">?</span><span class="p">,</span>
        <span class="p">)</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="init-lsm9ds1-driver-with-generic">Init LSM9DS1 driver with generic</h3>

<p>Because both <code class="language-plaintext highlighter-rouge">SpiInterface</code> and <code class="language-plaintext highlighter-rouge">I2cinterface</code> are now <code class="language-plaintext highlighter-rouge">Interface</code>, I can init my driver with generic <code class="language-plaintext highlighter-rouge">T: Interface</code> instead of a concrete SPI/I2C type.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">pub</span> <span class="k">struct</span> <span class="n">LSM9DS1</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span>
<span class="k">where</span>
    <span class="n">T</span><span class="p">:</span> <span class="n">Interface</span><span class="p">,</span>
<span class="p">{</span>
    <span class="n">interface</span><span class="p">:</span> <span class="n">T</span><span class="p">,</span>
    <span class="n">accel</span><span class="p">:</span> <span class="n">AccelSettings</span><span class="p">,</span>
    <span class="n">gyro</span><span class="p">:</span> <span class="n">GyroSettings</span><span class="p">,</span>
    <span class="n">mag</span><span class="p">:</span> <span class="n">MagSettings</span><span class="p">,</span>
<span class="p">}</span>
</code></pre></div></div>

<p>The fact that it takes <code class="language-plaintext highlighter-rouge">Interface</code> means that I can pass either <code class="language-plaintext highlighter-rouge">SpiInterface</code> or <code class="language-plaintext highlighter-rouge">I2cInterface</code> to instantiate the driver.
This way, when I talk to a sensor, I can simply call <code class="language-plaintext highlighter-rouge">self.interface.write()</code> or <code class="language-plaintext highlighter-rouge">self.interface.read()</code>.</p>

<p>For example, here is how to get a temperature measurement. It uses a chosen interface to communicate.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">pub</span> <span class="k">fn</span> <span class="nf">read_temp</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="nb">Result</span><span class="o">&lt;</span><span class="nb">f32</span><span class="p">,</span> <span class="nn">T</span><span class="p">::</span><span class="n">Error</span><span class="o">&gt;</span> <span class="p">{</span>
    <span class="k">let</span> <span class="k">mut</span> <span class="n">bytes</span> <span class="o">=</span> <span class="p">[</span><span class="mi">0u8</span><span class="p">;</span> <span class="mi">2</span><span class="p">];</span>
    <span class="k">self</span><span class="py">.interface</span><span class="nf">.read</span><span class="p">(</span>
        <span class="nn">Sensor</span><span class="p">::</span><span class="n">Accelerometer</span><span class="p">,</span>
        <span class="nn">register</span><span class="p">::</span><span class="nn">AG</span><span class="p">::</span><span class="n">OUT_TEMP_L</span><span class="nf">.addr</span><span class="p">(),</span>
        <span class="o">&amp;</span><span class="k">mut</span> <span class="n">bytes</span><span class="p">,</span>
    <span class="p">)</span><span class="o">?</span><span class="p">;</span>
    <span class="k">let</span> <span class="n">result</span><span class="p">:</span> <span class="nb">i16</span> <span class="o">=</span> <span class="p">(</span><span class="n">bytes</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="k">as</span> <span class="nb">i16</span><span class="p">)</span> <span class="o">&lt;&lt;</span> <span class="mi">8</span> <span class="p">|</span> <span class="n">bytes</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="k">as</span> <span class="nb">i16</span><span class="p">;</span>
    <span class="nf">Ok</span><span class="p">((</span><span class="n">result</span> <span class="k">as</span> <span class="nb">f32</span><span class="p">)</span> <span class="o">/</span> <span class="n">TEMP_SCALE</span> <span class="o">+</span> <span class="n">TEMP_BIAS</span><span class="p">)</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Once I pass the interface to <code class="language-plaintext highlighter-rouge">LSM9DS1</code> driver, I don’t need to worry about if uses SPI or I2C. There is no need to implement separate methods for SPI and I2C. Pretty cool.</p>

<p>Here is the <a href="https://github.com/lonesometraveler/lsm9ds1">GitHub repo</a> if you are interested.</p>

<h2 id="one-more-thing">One more thing…</h2>

<p>I found this trait technique really powerful. As an experiment, I also made a fake interface that could be used for testing. This struct implements <code class="language-plaintext highlighter-rouge">Interface</code> and has arrays that mimic registers. I can read and write these fake registers through the APIs.</p>

<p>In the end, I did testing at lower levels and didn’t really need this interface. But, I learned a lot in the process. I feel much more comfortable with <code class="language-plaintext highlighter-rouge">trait</code> now.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cd">//! Fake Interface for unit tests</span>
<span class="k">use</span> <span class="k">super</span><span class="p">::</span><span class="n">Interface</span><span class="p">;</span>
<span class="k">use</span> <span class="k">super</span><span class="p">::</span><span class="n">Sensor</span><span class="p">;</span>
<span class="k">use</span> <span class="nn">Sensor</span><span class="p">::</span><span class="o">*</span><span class="p">;</span>

<span class="cd">/// Errors in this crate</span>
<span class="nd">#[derive(Debug)]</span>
<span class="k">pub</span> <span class="k">enum</span> <span class="n">Error</span> <span class="p">{</span>
    <span class="cd">/// Communication error</span>
    <span class="n">Invalid</span><span class="p">,</span>
<span class="p">}</span>

<span class="cd">/// This holds fake registers</span>
<span class="k">pub</span> <span class="k">struct</span> <span class="n">FakeInterface</span> <span class="p">{</span>
    <span class="n">ag_registers</span><span class="p">:</span> <span class="p">[</span><span class="nb">u8</span><span class="p">;</span> <span class="mi">256</span><span class="p">],</span>
    <span class="n">mag_registers</span><span class="p">:</span> <span class="p">[</span><span class="nb">u8</span><span class="p">;</span> <span class="mi">256</span><span class="p">],</span>
<span class="p">}</span>

<span class="k">impl</span> <span class="nb">Default</span> <span class="k">for</span> <span class="n">FakeInterface</span> <span class="p">{</span>
    <span class="k">fn</span> <span class="nf">default</span><span class="p">()</span> <span class="k">-&gt;</span> <span class="k">Self</span> <span class="p">{</span>
        <span class="n">FakeInterface</span> <span class="p">{</span>
            <span class="n">ag_registers</span><span class="p">:</span> <span class="p">[</span><span class="mi">0u8</span><span class="p">;</span> <span class="mi">256</span><span class="p">],</span>
            <span class="n">mag_registers</span><span class="p">:</span> <span class="p">[</span><span class="mi">0u8</span><span class="p">;</span> <span class="mi">256</span><span class="p">],</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="k">impl</span> <span class="n">FakeInterface</span> <span class="p">{</span>
    <span class="cd">/// create a fake interface</span>
    <span class="k">pub</span> <span class="k">fn</span> <span class="nf">new</span><span class="p">()</span> <span class="k">-&gt;</span> <span class="k">Self</span> <span class="p">{</span>
        <span class="nn">Default</span><span class="p">::</span><span class="nf">default</span><span class="p">()</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="cd">/// Implementation of `Interface`</span>
<span class="k">impl</span> <span class="n">Interface</span> <span class="k">for</span> <span class="n">FakeInterface</span> <span class="p">{</span>
    <span class="k">type</span> <span class="n">Error</span> <span class="o">=</span> <span class="n">Error</span><span class="p">;</span>

    <span class="k">fn</span> <span class="nf">write</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">,</span> <span class="n">sensor</span><span class="p">:</span> <span class="n">Sensor</span><span class="p">,</span> <span class="n">addr</span><span class="p">:</span> <span class="nb">u8</span><span class="p">,</span> <span class="n">value</span><span class="p">:</span> <span class="nb">u8</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="nb">Result</span><span class="o">&lt;</span><span class="p">(),</span> <span class="k">Self</span><span class="p">::</span><span class="n">Error</span><span class="o">&gt;</span> <span class="p">{</span>
        <span class="k">match</span> <span class="n">sensor</span> <span class="p">{</span>
            <span class="n">Accelerometer</span> <span class="p">|</span> <span class="n">Gyro</span> <span class="p">|</span> <span class="n">Temperature</span> <span class="k">=&gt;</span> <span class="k">self</span><span class="py">.ag_registers</span><span class="p">[</span><span class="n">addr</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">]</span> <span class="o">=</span> <span class="n">value</span><span class="p">,</span>
            <span class="n">Magnetometer</span> <span class="k">=&gt;</span> <span class="k">self</span><span class="py">.mag_registers</span><span class="p">[</span><span class="n">addr</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">]</span> <span class="o">=</span> <span class="n">value</span><span class="p">,</span>
        <span class="p">}</span>
        <span class="nf">Ok</span><span class="p">(())</span>
    <span class="p">}</span>

    <span class="k">fn</span> <span class="nf">read</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">,</span> <span class="n">sensor</span><span class="p">:</span> <span class="n">Sensor</span><span class="p">,</span> <span class="n">addr</span><span class="p">:</span> <span class="nb">u8</span><span class="p">,</span> <span class="n">buffer</span><span class="p">:</span> <span class="o">&amp;</span><span class="k">mut</span> <span class="p">[</span><span class="nb">u8</span><span class="p">])</span> <span class="k">-&gt;</span> <span class="nb">Result</span><span class="o">&lt;</span><span class="p">(),</span> <span class="k">Self</span><span class="p">::</span><span class="n">Error</span><span class="o">&gt;</span> <span class="p">{</span>
        <span class="k">let</span> <span class="n">registers</span> <span class="o">=</span> <span class="k">match</span> <span class="n">sensor</span> <span class="p">{</span>
            <span class="n">Accelerometer</span> <span class="p">|</span> <span class="n">Gyro</span> <span class="p">|</span> <span class="n">Temperature</span> <span class="k">=&gt;</span> <span class="k">self</span><span class="py">.ag_registers</span><span class="p">,</span>
            <span class="n">Magnetometer</span> <span class="k">=&gt;</span> <span class="k">self</span><span class="py">.mag_registers</span><span class="p">,</span>
        <span class="p">};</span>
        <span class="k">for</span> <span class="n">i</span> <span class="k">in</span> <span class="mi">0</span><span class="o">..</span><span class="n">buffer</span><span class="nf">.len</span><span class="p">()</span> <span class="p">{</span>
            <span class="n">buffer</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">registers</span><span class="p">[(</span><span class="n">addr</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">)</span> <span class="o">+</span> <span class="n">i</span><span class="p">];</span>
        <span class="p">}</span>
        <span class="nf">Ok</span><span class="p">(())</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>]]></content><author><name>lonesometraveler</name><email>lonesometraveler@mac.com</email></author><category term="Rust" /><category term="embedded" /><summary type="html"><![CDATA[LSM9DS1 is a 9 axis motion sensor module that comes with accelerometer, gyroscope, magnetometer, and temperature sensor. A cool thing about this device is that it has I2C and SPI interfaces. In this post, I will show how I supported both interfaces with trait.]]></summary></entry><entry><title type="html">Timer Interrupt: In the Blink of an Eye</title><link href="https://lonesometraveler.github.io/2020/04/04/timer-interrupt.html" rel="alternate" type="text/html" title="Timer Interrupt: In the Blink of an Eye" /><published>2020-04-04T11:07:21+00:00</published><updated>2020-04-04T11:07:21+00:00</updated><id>https://lonesometraveler.github.io/2020/04/04/timer-interrupt</id><content type="html" xml:base="https://lonesometraveler.github.io/2020/04/04/timer-interrupt.html"><![CDATA[<p>As my daily routine was interrupted by COVID-19, I stayed home and played around with embedded Rust’s interrupt this week.</p>

<p>Interrupt can be dangerous if you don’t do it right. I read <a href="https://docs.rust-embedded.org/book/concurrency/index.html">the concurrency section of the book</a> and learned Rust’s safe way to share resources between the main and ISR contexts.</p>

<h2 id="how-to-use-timer-interrupt">How to use timer interrupt</h2>
<p>In this post, I will show how I did a blinking LED application using a timer interrupt.</p>

<p><img src="https://lonesometraveler.github.io/assets/blinking_led.gif" alt="" /></p>

<blockquote>
  <p>“It’s amazing in the blink of an eye, you finally see the light.” - Steven Tyler</p>
</blockquote>

<h3 id="1-wrap-shared-resources">1. Wrap shared resources</h3>

<p>The goal is to flip the desired state of a LED in an interrupt handler and turn on/off the LED accordingly in the main. So, it is necessary to share the state of LED and a timer peripheral between ISR and the main code.</p>

<p>In embedded Rust, we use statically allocated <code class="language-plaintext highlighter-rouge">Mutex</code> to share peripherals and variables between different contexts.</p>

<p>Here is how I wrap <code class="language-plaintext highlighter-rouge">bool</code> that represents the state of my LED.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">static</span> <span class="n">LED_STATE</span><span class="p">:</span> <span class="n">Mutex</span><span class="o">&lt;</span><span class="n">Cell</span><span class="o">&lt;</span><span class="nb">bool</span><span class="o">&gt;&gt;</span> <span class="o">=</span> <span class="nn">Mutex</span><span class="p">::</span><span class="nf">new</span><span class="p">(</span><span class="nn">Cell</span><span class="p">::</span><span class="nf">new</span><span class="p">(</span><span class="k">false</span><span class="p">));</span>
</code></pre></div></div>

<p>And a line below shows how I wrap my <code class="language-plaintext highlighter-rouge">TIM2</code>, timer 2 module. Note that <code class="language-plaintext highlighter-rouge">TIMER_TIM2</code>’s <code class="language-plaintext highlighter-rouge">RefCell</code> has an initial value of <code class="language-plaintext highlighter-rouge">None</code>. It will be replaced with a timer peripheral later.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">static</span> <span class="n">TIMER_TIM2</span><span class="p">:</span> <span class="n">Mutex</span><span class="o">&lt;</span><span class="n">RefCell</span><span class="o">&lt;</span><span class="nb">Option</span><span class="o">&lt;</span><span class="n">Timer</span><span class="o">&lt;</span><span class="nn">stm32</span><span class="p">::</span><span class="n">TIM2</span><span class="o">&gt;&gt;&gt;&gt;</span> <span class="o">=</span> <span class="nn">Mutex</span><span class="p">::</span><span class="nf">new</span><span class="p">(</span><span class="nn">RefCell</span><span class="p">::</span><span class="nf">new</span><span class="p">(</span><span class="nb">None</span><span class="p">));</span>
</code></pre></div></div>

<p>Next, I set up an interrupt timer. I am setting it up as a 5Hz timer and wrapping it with <code class="language-plaintext highlighter-rouge">Mutex</code>.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="k">mut</span> <span class="n">timer</span> <span class="o">=</span> <span class="nn">Timer</span><span class="p">::</span><span class="nf">tim2</span><span class="p">(</span><span class="n">dp</span><span class="py">.TIM2</span><span class="p">,</span> <span class="mi">5</span><span class="nf">.hz</span><span class="p">(),</span> <span class="n">clocks</span><span class="p">,</span> <span class="o">&amp;</span><span class="k">mut</span> <span class="n">rcc</span><span class="py">.apb1</span><span class="p">);</span>
<span class="n">timer</span><span class="nf">.listen</span><span class="p">(</span><span class="nn">Event</span><span class="p">::</span><span class="n">Update</span><span class="p">);</span>
</code></pre></div></div>

<p>I then use <a href="https://docs.rust-embedded.org/book/concurrency/#critical-sections">critical section</a> with <code class="language-plaintext highlighter-rouge">cortex_m::interrupt::free</code> and replace <code class="language-plaintext highlighter-rouge">TIMER_TIM2</code>’s content (<code class="language-plaintext highlighter-rouge">None</code>) with my instantiated <code class="language-plaintext highlighter-rouge">timer</code>.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nf">free</span><span class="p">(|</span><span class="n">cs</span><span class="p">|</span> <span class="p">{</span>
    <span class="n">TIMER_TIM2</span><span class="nf">.borrow</span><span class="p">(</span><span class="n">cs</span><span class="p">)</span><span class="nf">.replace</span><span class="p">(</span><span class="nf">Some</span><span class="p">(</span><span class="n">timer</span><span class="p">));</span>
<span class="p">});</span>
</code></pre></div></div>

<h3 id="2-handle-interrupts">2. Handle interrupts</h3>
<p>Enabling the <code class="language-plaintext highlighter-rouge">TIM2</code> interrupt is very easy with NVIC (Nested vector interrupt control).</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nn">stm32</span><span class="p">::</span><span class="nn">NVIC</span><span class="p">::</span><span class="nf">unpend</span><span class="p">(</span><span class="nn">Interrupt</span><span class="p">::</span><span class="n">TIM2</span><span class="p">);</span>
<span class="k">unsafe</span> <span class="p">{</span>
    <span class="nn">stm32</span><span class="p">::</span><span class="nn">NVIC</span><span class="p">::</span><span class="nf">unmask</span><span class="p">(</span><span class="nn">Interrupt</span><span class="p">::</span><span class="n">TIM2</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>That’s it. The timer is now running. When the interrupt is triggered, it goes to the interrupt handler defined like this:</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">#[interrupt]</span>
<span class="k">fn</span> <span class="nf">TIM2</span><span class="p">()</span> <span class="p">{</span>
    <span class="nf">free</span><span class="p">(|</span><span class="n">cs</span><span class="p">|</span> <span class="p">{</span>
        <span class="k">if</span> <span class="k">let</span> <span class="nf">Some</span><span class="p">(</span><span class="k">ref</span> <span class="k">mut</span> <span class="n">tim2</span><span class="p">)</span> <span class="o">=</span> <span class="n">TIMER_TIM2</span><span class="nf">.borrow</span><span class="p">(</span><span class="n">cs</span><span class="p">)</span><span class="nf">.borrow_mut</span><span class="p">()</span><span class="nf">.deref_mut</span><span class="p">()</span> <span class="p">{</span>
            <span class="n">tim2</span><span class="nf">.clear_update_interrupt_flag</span><span class="p">();</span>
        <span class="p">}</span>
        <span class="k">let</span> <span class="n">led_state</span> <span class="o">=</span> <span class="n">LED_STATE</span><span class="nf">.borrow</span><span class="p">(</span><span class="n">cs</span><span class="p">);</span>
        <span class="n">led_state</span><span class="nf">.replace</span><span class="p">(</span><span class="o">!</span><span class="n">led_state</span><span class="nf">.get</span><span class="p">());</span>
    <span class="p">});</span>
<span class="p">}</span>
</code></pre></div></div>

<p>The first thing to do in the ISR is to clear the interrupt flag. <code class="language-plaintext highlighter-rouge">stm32f3xx_hal</code> has <code class="language-plaintext highlighter-rouge">clear_update_interrupt_flag()</code>. This method clears the status register’s UIF bit. This bit is set by the hardware and must be cleared by the software. If this bit is not cleared, the program repeats the ISR forever.
After clearing the flag, I flip the state of <code class="language-plaintext highlighter-rouge">LED_STATE</code> and replace the old value with a new one.</p>

<h3 id="3-reflect-the-change-in-the-main">3. Reflect the change in the main</h3>
<p>In the main, I evaluate <code class="language-plaintext highlighter-rouge">LED_STATE</code> like this:</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">loop</span> <span class="p">{</span>
    <span class="k">if</span> <span class="nf">free</span><span class="p">(|</span><span class="n">cs</span><span class="p">|</span> <span class="n">LED_STATE</span><span class="nf">.borrow</span><span class="p">(</span><span class="n">cs</span><span class="p">)</span><span class="nf">.get</span><span class="p">())</span> <span class="p">{</span>
        <span class="n">led</span><span class="nf">.set_high</span><span class="p">()</span><span class="nf">.unwrap</span><span class="p">();</span>
    <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
        <span class="n">led</span><span class="nf">.set_low</span><span class="p">()</span><span class="nf">.unwrap</span><span class="p">();</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>See how I use critical section by calling <code class="language-plaintext highlighter-rouge">cortex_m::interrupt::free</code> to access <code class="language-plaintext highlighter-rouge">LED_STATE</code>. This and <code class="language-plaintext highlighter-rouge">Mutex</code> ensure exclusive access to the shared resource.</p>

<h2 id="code-blink-blink">Code: Blink Blink</h2>
<p>Here are two codes for the blinking LED. One for <a href="https://www.st.com/en/evaluation-tools/stm32f3discovery.html">STM32F3DISCOVERY board</a> and the other for <a href="https://www.st.com/en/evaluation-tools/nucleo-f429zi.html">Nucleo-F429ZI</a>. I used <code class="language-plaintext highlighter-rouge">stm32f3xx_hal</code> for DISCOVERY and <code class="language-plaintext highlighter-rouge">stm32f4xx_hal</code> for Nucleo. The basic concept is the same between the two implementations. Only differences are the way to instantiate the timer peripheral and the call to clear the interrupt flag by using HAL specific methods.</p>

<h3 id="stm32f3discovery">STM32F3DISCOVERY</h3>

<p>Here is the code for <a href="https://www.st.com/en/evaluation-tools/stm32f3discovery.html">STM32F3DISCOVERY board</a> board. This is built with <code class="language-plaintext highlighter-rouge">stm32f3xx_hal</code>.</p>

<ul>
  <li><a href="https://github.com/lonesometraveler/stm32f3xx-examples">GitHub repo</a></li>
</ul>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">#![no_main]</span>
<span class="nd">#![no_std]</span>

<span class="k">extern</span> <span class="k">crate</span> <span class="n">panic_halt</span><span class="p">;</span>

<span class="k">use</span> <span class="nn">core</span><span class="p">::</span><span class="nn">cell</span><span class="p">::{</span><span class="n">Cell</span><span class="p">,</span> <span class="n">RefCell</span><span class="p">};</span>
<span class="k">use</span> <span class="nn">core</span><span class="p">::</span><span class="nn">ops</span><span class="p">::</span><span class="n">DerefMut</span><span class="p">;</span>
<span class="k">use</span> <span class="n">cortex_m</span><span class="p">;</span>
<span class="k">use</span> <span class="nn">cortex_m</span><span class="p">::</span><span class="nn">interrupt</span><span class="p">::{</span><span class="n">free</span><span class="p">,</span> <span class="n">Mutex</span><span class="p">};</span>
<span class="k">use</span> <span class="nn">cortex_m_rt</span><span class="p">::</span><span class="n">entry</span><span class="p">;</span>
<span class="k">use</span> <span class="nn">stm32f3xx_hal</span><span class="p">::{</span>
    <span class="nn">prelude</span><span class="p">::</span><span class="o">*</span><span class="p">,</span>
    <span class="n">stm32</span><span class="p">,</span>
    <span class="nn">stm32</span><span class="p">::{</span><span class="n">interrupt</span><span class="p">,</span> <span class="n">Interrupt</span><span class="p">},</span>
    <span class="nn">timer</span><span class="p">::{</span><span class="n">Event</span><span class="p">,</span> <span class="n">Timer</span><span class="p">},</span>
<span class="p">};</span>

<span class="k">static</span> <span class="n">LED_STATE</span><span class="p">:</span> <span class="n">Mutex</span><span class="o">&lt;</span><span class="n">Cell</span><span class="o">&lt;</span><span class="nb">bool</span><span class="o">&gt;&gt;</span> <span class="o">=</span> <span class="nn">Mutex</span><span class="p">::</span><span class="nf">new</span><span class="p">(</span><span class="nn">Cell</span><span class="p">::</span><span class="nf">new</span><span class="p">(</span><span class="k">false</span><span class="p">));</span>
<span class="k">static</span> <span class="n">TIMER_TIM2</span><span class="p">:</span> <span class="n">Mutex</span><span class="o">&lt;</span><span class="n">RefCell</span><span class="o">&lt;</span><span class="nb">Option</span><span class="o">&lt;</span><span class="n">Timer</span><span class="o">&lt;</span><span class="nn">stm32</span><span class="p">::</span><span class="n">TIM2</span><span class="o">&gt;&gt;&gt;&gt;</span> <span class="o">=</span> <span class="nn">Mutex</span><span class="p">::</span><span class="nf">new</span><span class="p">(</span><span class="nn">RefCell</span><span class="p">::</span><span class="nf">new</span><span class="p">(</span><span class="nb">None</span><span class="p">));</span>

<span class="nd">#[interrupt]</span>
<span class="k">fn</span> <span class="nf">TIM2</span><span class="p">()</span> <span class="p">{</span>
    <span class="nf">free</span><span class="p">(|</span><span class="n">cs</span><span class="p">|</span> <span class="p">{</span>
        <span class="k">if</span> <span class="k">let</span> <span class="nf">Some</span><span class="p">(</span><span class="k">ref</span> <span class="k">mut</span> <span class="n">tim2</span><span class="p">)</span> <span class="o">=</span> <span class="n">TIMER_TIM2</span><span class="nf">.borrow</span><span class="p">(</span><span class="n">cs</span><span class="p">)</span><span class="nf">.borrow_mut</span><span class="p">()</span><span class="nf">.deref_mut</span><span class="p">()</span> <span class="p">{</span>
            <span class="n">tim2</span><span class="nf">.clear_update_interrupt_flag</span><span class="p">();</span>
        <span class="p">}</span>
        <span class="k">let</span> <span class="n">led_state</span> <span class="o">=</span> <span class="n">LED_STATE</span><span class="nf">.borrow</span><span class="p">(</span><span class="n">cs</span><span class="p">);</span>
        <span class="n">led_state</span><span class="nf">.replace</span><span class="p">(</span><span class="o">!</span><span class="n">led_state</span><span class="nf">.get</span><span class="p">());</span>
    <span class="p">});</span>
<span class="p">}</span>

<span class="nd">#[entry]</span>
<span class="k">fn</span> <span class="nf">main</span><span class="p">()</span> <span class="k">-&gt;</span> <span class="o">!</span> <span class="p">{</span>
    <span class="k">let</span> <span class="n">dp</span> <span class="o">=</span> <span class="nn">stm32</span><span class="p">::</span><span class="nn">Peripherals</span><span class="p">::</span><span class="nf">take</span><span class="p">()</span><span class="nf">.unwrap</span><span class="p">();</span>
    <span class="c1">// Set up the system clock</span>
    <span class="k">let</span> <span class="k">mut</span> <span class="n">flash</span> <span class="o">=</span> <span class="n">dp</span><span class="py">.FLASH</span><span class="nf">.constrain</span><span class="p">();</span>
    <span class="k">let</span> <span class="k">mut</span> <span class="n">rcc</span> <span class="o">=</span> <span class="n">dp</span><span class="py">.RCC</span><span class="nf">.constrain</span><span class="p">();</span>
    <span class="k">let</span> <span class="n">clocks</span> <span class="o">=</span> <span class="n">rcc</span><span class="py">.cfgr</span><span class="nf">.freeze</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="n">flash</span><span class="py">.acr</span><span class="p">);</span>

    <span class="c1">// Set up the LED</span>
    <span class="k">let</span> <span class="k">mut</span> <span class="n">gpioe</span> <span class="o">=</span> <span class="n">dp</span><span class="py">.GPIOE</span><span class="nf">.split</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="n">rcc</span><span class="py">.ahb</span><span class="p">);</span>
    <span class="k">let</span> <span class="k">mut</span> <span class="n">led</span> <span class="o">=</span> <span class="n">gpioe</span>
        <span class="py">.pe9</span>
        <span class="nf">.into_push_pull_output</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="n">gpioe</span><span class="py">.moder</span><span class="p">,</span> <span class="o">&amp;</span><span class="k">mut</span> <span class="n">gpioe</span><span class="py">.otyper</span><span class="p">);</span>

    <span class="c1">// Set up the interrupt timer</span>
    <span class="k">let</span> <span class="k">mut</span> <span class="n">timer</span> <span class="o">=</span> <span class="nn">Timer</span><span class="p">::</span><span class="nf">tim2</span><span class="p">(</span><span class="n">dp</span><span class="py">.TIM2</span><span class="p">,</span> <span class="mi">5</span><span class="nf">.hz</span><span class="p">(),</span> <span class="n">clocks</span><span class="p">,</span> <span class="o">&amp;</span><span class="k">mut</span> <span class="n">rcc</span><span class="py">.apb1</span><span class="p">);</span>
    <span class="n">timer</span><span class="nf">.listen</span><span class="p">(</span><span class="nn">Event</span><span class="p">::</span><span class="n">Update</span><span class="p">);</span>

    <span class="c1">// Move shared resources to Mutex</span>
    <span class="nf">free</span><span class="p">(|</span><span class="n">cs</span><span class="p">|</span> <span class="p">{</span>
        <span class="n">TIMER_TIM2</span><span class="nf">.borrow</span><span class="p">(</span><span class="n">cs</span><span class="p">)</span><span class="nf">.replace</span><span class="p">(</span><span class="nf">Some</span><span class="p">(</span><span class="n">timer</span><span class="p">));</span>
    <span class="p">});</span>

    <span class="c1">// Enable interrupt</span>
    <span class="nn">stm32</span><span class="p">::</span><span class="nn">NVIC</span><span class="p">::</span><span class="nf">unpend</span><span class="p">(</span><span class="nn">Interrupt</span><span class="p">::</span><span class="n">TIM2</span><span class="p">);</span>
    <span class="k">unsafe</span> <span class="p">{</span>
        <span class="nn">stm32</span><span class="p">::</span><span class="nn">NVIC</span><span class="p">::</span><span class="nf">unmask</span><span class="p">(</span><span class="nn">Interrupt</span><span class="p">::</span><span class="n">TIM2</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="k">loop</span> <span class="p">{</span>
        <span class="k">if</span> <span class="nf">free</span><span class="p">(|</span><span class="n">cs</span><span class="p">|</span> <span class="n">LED_STATE</span><span class="nf">.borrow</span><span class="p">(</span><span class="n">cs</span><span class="p">)</span><span class="nf">.get</span><span class="p">())</span> <span class="p">{</span>
            <span class="n">led</span><span class="nf">.set_high</span><span class="p">()</span><span class="nf">.unwrap</span><span class="p">();</span>
        <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
            <span class="n">led</span><span class="nf">.set_low</span><span class="p">()</span><span class="nf">.unwrap</span><span class="p">();</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>

</code></pre></div></div>

<h3 id="nucleo-f429zi">Nucleo-F429ZI</h3>

<p><a href="https://www.st.com/en/evaluation-tools/nucleo-f429zi.html">Nucleo-F429ZI board</a> has STM32F429 microcontroller. I use <code class="language-plaintext highlighter-rouge">stm32f4xx_hal</code> for this.</p>

<ul>
  <li><a href="https://github.com/lonesometraveler/stm32f4xx-examples">GitHub repo</a></li>
</ul>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">#![no_main]</span>
<span class="nd">#![no_std]</span>

<span class="k">extern</span> <span class="k">crate</span> <span class="n">panic_halt</span><span class="p">;</span>

<span class="k">use</span> <span class="nn">core</span><span class="p">::</span><span class="nn">cell</span><span class="p">::{</span><span class="n">Cell</span><span class="p">,</span> <span class="n">RefCell</span><span class="p">};</span>
<span class="k">use</span> <span class="nn">core</span><span class="p">::</span><span class="nn">ops</span><span class="p">::</span><span class="n">DerefMut</span><span class="p">;</span>
<span class="k">use</span> <span class="n">cortex_m</span><span class="p">;</span>
<span class="k">use</span> <span class="nn">cortex_m</span><span class="p">::</span><span class="nn">interrupt</span><span class="p">::{</span><span class="n">free</span><span class="p">,</span> <span class="n">Mutex</span><span class="p">};</span>
<span class="k">use</span> <span class="nn">cortex_m_rt</span><span class="p">::</span><span class="n">entry</span><span class="p">;</span>
<span class="k">use</span> <span class="nn">stm32f4xx_hal</span><span class="p">::{</span>
    <span class="nn">prelude</span><span class="p">::</span><span class="o">*</span><span class="p">,</span>
    <span class="n">stm32</span><span class="p">,</span>
    <span class="nn">stm32</span><span class="p">::</span><span class="n">interrupt</span><span class="p">,</span>
    <span class="nn">timer</span><span class="p">::{</span><span class="n">Event</span><span class="p">,</span> <span class="n">Timer</span><span class="p">},</span>
<span class="p">};</span>

<span class="k">static</span> <span class="n">LED_STATE</span><span class="p">:</span> <span class="n">Mutex</span><span class="o">&lt;</span><span class="n">Cell</span><span class="o">&lt;</span><span class="nb">bool</span><span class="o">&gt;&gt;</span> <span class="o">=</span> <span class="nn">Mutex</span><span class="p">::</span><span class="nf">new</span><span class="p">(</span><span class="nn">Cell</span><span class="p">::</span><span class="nf">new</span><span class="p">(</span><span class="k">false</span><span class="p">));</span>
<span class="k">static</span> <span class="n">TIMER_TIM2</span><span class="p">:</span> <span class="n">Mutex</span><span class="o">&lt;</span><span class="n">RefCell</span><span class="o">&lt;</span><span class="nb">Option</span><span class="o">&lt;</span><span class="n">Timer</span><span class="o">&lt;</span><span class="nn">stm32</span><span class="p">::</span><span class="n">TIM2</span><span class="o">&gt;&gt;&gt;&gt;</span> <span class="o">=</span> <span class="nn">Mutex</span><span class="p">::</span><span class="nf">new</span><span class="p">(</span><span class="nn">RefCell</span><span class="p">::</span><span class="nf">new</span><span class="p">(</span><span class="nb">None</span><span class="p">));</span>

<span class="nd">#[interrupt]</span>
<span class="k">fn</span> <span class="nf">TIM2</span><span class="p">()</span> <span class="p">{</span>
    <span class="nf">free</span><span class="p">(|</span><span class="n">cs</span><span class="p">|</span> <span class="p">{</span>
        <span class="k">if</span> <span class="k">let</span> <span class="nf">Some</span><span class="p">(</span><span class="k">ref</span> <span class="k">mut</span> <span class="n">tim2</span><span class="p">)</span> <span class="o">=</span> <span class="n">TIMER_TIM2</span><span class="nf">.borrow</span><span class="p">(</span><span class="n">cs</span><span class="p">)</span><span class="nf">.borrow_mut</span><span class="p">()</span><span class="nf">.deref_mut</span><span class="p">()</span> <span class="p">{</span>
            <span class="n">tim2</span><span class="nf">.clear_interrupt</span><span class="p">(</span><span class="nn">Event</span><span class="p">::</span><span class="n">TimeOut</span><span class="p">);</span>
        <span class="p">}</span>
        <span class="k">let</span> <span class="n">led_state</span> <span class="o">=</span> <span class="n">LED_STATE</span><span class="nf">.borrow</span><span class="p">(</span><span class="n">cs</span><span class="p">);</span>
        <span class="n">led_state</span><span class="nf">.replace</span><span class="p">(</span><span class="o">!</span><span class="n">led_state</span><span class="nf">.get</span><span class="p">());</span>
    <span class="p">});</span>
<span class="p">}</span>

<span class="nd">#[entry]</span>
<span class="k">fn</span> <span class="nf">main</span><span class="p">()</span> <span class="k">-&gt;</span> <span class="o">!</span> <span class="p">{</span>
    <span class="k">let</span> <span class="n">dp</span> <span class="o">=</span> <span class="nn">stm32</span><span class="p">::</span><span class="nn">Peripherals</span><span class="p">::</span><span class="nf">take</span><span class="p">()</span><span class="nf">.unwrap</span><span class="p">();</span>
    <span class="c1">// Set up the LED</span>
    <span class="k">let</span> <span class="n">gpiob</span> <span class="o">=</span> <span class="n">dp</span><span class="py">.GPIOB</span><span class="nf">.split</span><span class="p">();</span>
    <span class="k">let</span> <span class="k">mut</span> <span class="n">led</span> <span class="o">=</span> <span class="n">gpiob</span><span class="py">.pb7</span><span class="nf">.into_push_pull_output</span><span class="p">();</span>

    <span class="c1">// Set up the system clock</span>
    <span class="k">let</span> <span class="n">rcc</span> <span class="o">=</span> <span class="n">dp</span><span class="py">.RCC</span><span class="nf">.constrain</span><span class="p">();</span>
    <span class="k">let</span> <span class="n">clocks</span> <span class="o">=</span> <span class="n">rcc</span><span class="py">.cfgr</span><span class="nf">.sysclk</span><span class="p">(</span><span class="mi">48</span><span class="nf">.mhz</span><span class="p">())</span><span class="nf">.freeze</span><span class="p">();</span>

    <span class="c1">// Set up the interrupt timer</span>
    <span class="k">let</span> <span class="k">mut</span> <span class="n">timer</span> <span class="o">=</span> <span class="nn">Timer</span><span class="p">::</span><span class="nf">tim2</span><span class="p">(</span><span class="n">dp</span><span class="py">.TIM2</span><span class="p">,</span> <span class="mi">5</span><span class="nf">.hz</span><span class="p">(),</span> <span class="n">clocks</span><span class="p">);</span>
    <span class="n">timer</span><span class="nf">.listen</span><span class="p">(</span><span class="nn">Event</span><span class="p">::</span><span class="n">TimeOut</span><span class="p">);</span>

    <span class="nf">free</span><span class="p">(|</span><span class="n">cs</span><span class="p">|</span> <span class="p">{</span>
        <span class="n">TIMER_TIM2</span><span class="nf">.borrow</span><span class="p">(</span><span class="n">cs</span><span class="p">)</span><span class="nf">.replace</span><span class="p">(</span><span class="nf">Some</span><span class="p">(</span><span class="n">timer</span><span class="p">));</span>
    <span class="p">});</span>

    <span class="c1">// Enable interrupt</span>
    <span class="nn">stm32</span><span class="p">::</span><span class="nn">NVIC</span><span class="p">::</span><span class="nf">unpend</span><span class="p">(</span><span class="nn">stm32</span><span class="p">::</span><span class="nn">Interrupt</span><span class="p">::</span><span class="n">TIM2</span><span class="p">);</span>
    <span class="k">unsafe</span> <span class="p">{</span>
        <span class="nn">stm32</span><span class="p">::</span><span class="nn">NVIC</span><span class="p">::</span><span class="nf">unmask</span><span class="p">(</span><span class="nn">stm32</span><span class="p">::</span><span class="nn">Interrupt</span><span class="p">::</span><span class="n">TIM2</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="k">loop</span> <span class="p">{</span>
        <span class="k">if</span> <span class="nf">free</span><span class="p">(|</span><span class="n">cs</span><span class="p">|</span> <span class="n">LED_STATE</span><span class="nf">.borrow</span><span class="p">(</span><span class="n">cs</span><span class="p">)</span><span class="nf">.get</span><span class="p">())</span> <span class="p">{</span>
            <span class="n">led</span><span class="nf">.set_high</span><span class="p">()</span><span class="nf">.unwrap</span><span class="p">();</span>
        <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
            <span class="n">led</span><span class="nf">.set_low</span><span class="p">()</span><span class="nf">.unwrap</span><span class="p">();</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>]]></content><author><name>lonesometraveler</name><email>lonesometraveler@mac.com</email></author><category term="Rust" /><category term="embedded" /><summary type="html"><![CDATA[As my daily routine was interrupted by COVID-19, I stayed home and played around with embedded Rust’s interrupt this week.]]></summary></entry></feed>