Jekyll2018-10-25T20:49:06+00:00https://branan.github.io/teensy/Exploring Rust on TeensyWalking through building a rust-based project on a Teensy. From project setup through building safe abstractions for the underlying hardware.
Part 3: Improving Safety2017-05-09T04:00:00+00:002017-05-09T04:00:00+00:00https://branan.github.io/teensy/2017/05/09/safety<h2 id="overview">Overview</h2>
<p>Our goal in this post is to eliminate as much unsafe code from <code class="highlighter-rouge">main</code>
as possible. We will do this by using Rust’s type and lifetime systems
to enforce hardware invariants. This is similar to what we did in the
previous post for clock modes, but across all of our code.</p>
<p>We’re not going to end up with any new behaviors by the end of this
post. We’re just laying a foundation of ways to think about using
Rust’s safety features for hardware.</p>
<h3 id="hardware-allocation">Hardware Allocation</h3>
<p>The overall idea behind this post is that hardware should be
<em>allocated</em> before a bit of code can use it. This implies the same
things as a memory allocation in Rust:</p>
<ul>
<li>
<p>The allocation itself is unsafe, but creation of a wrapper that
handles deallocation is safe.</p>
</li>
<li>
<p>If user code attempts to allocation a resource that is unavailable,
we must fail in some way.</p>
</li>
</ul>
<p>Rust, of course, responds to a failure of memory allocation by
aborting. In this blog series, we’ll typically panic. I prefer panics
to an <code class="highlighter-rouge">Option</code> or <code class="highlighter-rouge">Error</code> type since they allow the example code to
follow the happy path without getting bogged down in
unwrapping. Panics also make it possible for us to include a useful
message indicating which hardware unit was incorrectly allocated.</p>
<h2 id="the-mcg-and-osc">The MCG and OSC</h2>
<p>We will start with the easiest structs to update. The hardware modules
for the MCG and OSC are not dependant on any other modules, so they do
not reqire the complexity that some of our other structs will.</p>
<p>The update to the OSC looks like this:</p>
<figure class="highlight"><pre><code class="language-rust" data-lang="rust"><span class="k">use</span> <span class="nn">volatile</span><span class="p">::</span><span class="n">Volatile</span><span class="p">;</span>
<span class="k">use</span> <span class="nn">bit_field</span><span class="p">::</span><span class="n">BitField</span><span class="p">;</span>
<span class="k">use</span> <span class="nn">core</span><span class="p">::</span><span class="nn">sync</span><span class="p">::</span><span class="nn">atomic</span><span class="p">::{</span><span class="n">AtomicBool</span><span class="p">,</span><span class="n">ATOMIC_BOOL_INIT</span><span class="p">,</span><span class="n">Ordering</span><span class="p">};</span>
<span class="nd">#[repr(C,packed)]</span>
<span class="k">struct</span> <span class="n">OscRegs</span> <span class="p">{</span>
<span class="n">cr</span><span class="p">:</span> <span class="n">Volatile</span><span class="o"><</span><span class="nb">u8</span><span class="o">></span>
<span class="p">}</span>
<span class="k">pub</span> <span class="k">struct</span> <span class="n">Osc</span> <span class="p">{</span>
<span class="n">reg</span><span class="p">:</span> <span class="o">&</span><span class="nv">'static</span> <span class="k">mut</span> <span class="n">OscRegs</span>
<span class="p">}</span>
<span class="k">static</span> <span class="n">OSC_INIT</span><span class="p">:</span> <span class="n">AtomicBool</span> <span class="o">=</span> <span class="n">ATOMIC_BOOL_INIT</span><span class="p">;</span>
<span class="k">impl</span> <span class="n">Osc</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="k">-></span> <span class="n">Osc</span> <span class="p">{</span>
<span class="k">let</span> <span class="n">was_init</span> <span class="o">=</span> <span class="n">OSC_INIT</span><span class="nf">.swap</span><span class="p">(</span><span class="k">true</span><span class="p">,</span> <span class="nn">Ordering</span><span class="p">::</span><span class="n">Relaxed</span><span class="p">);</span>
<span class="k">if</span> <span class="n">was_init</span> <span class="p">{</span>
<span class="nd">panic!</span><span class="p">(</span><span class="s">"Cannot initialize OSC: It's already active"</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">let</span> <span class="n">reg</span> <span class="o">=</span> <span class="k">unsafe</span> <span class="p">{</span> <span class="o">&</span><span class="k">mut</span> <span class="o">*</span><span class="p">(</span><span class="mi">0x40065000</span> <span class="k">as</span> <span class="o">*</span><span class="k">mut</span> <span class="n">OscRegs</span><span class="p">)</span> <span class="p">};</span>
<span class="n">Osc</span> <span class="p">{</span><span class="n">reg</span><span class="p">:</span> <span class="n">reg</span><span class="p">}</span>
<span class="p">}</span>
<span class="k">pub</span> <span class="k">fn</span> <span class="nf">enable</span><span class="p">(</span><span class="o">&</span><span class="k">mut</span> <span class="k">self</span><span class="p">,</span> <span class="n">capacitance</span><span class="p">:</span> <span class="nb">u8</span><span class="p">)</span> <span class="p">{</span>
<span class="o">...</span>
<span class="k">self</span><span class="py">.reg.cr</span><span class="nf">.write</span><span class="p">(</span><span class="n">cr</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="k">impl</span> <span class="n">Drop</span> <span class="k">for</span> <span class="n">Osc</span> <span class="p">{</span>
<span class="k">fn</span> <span class="k">drop</span><span class="p">(</span><span class="o">&</span><span class="k">mut</span> <span class="k">self</span><span class="p">)</span> <span class="p">{</span>
<span class="n">OSC_INIT</span><span class="nf">.store</span><span class="p">(</span><span class="k">false</span><span class="p">,</span> <span class="nn">Ordering</span><span class="p">::</span><span class="n">Relaxed</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span></code></pre></figure>
<p>There are lots of changes here. Let’s go through them all:</p>
<ol>
<li>We have a new import for <code class="highlighter-rouge">AtomicBool</code>, and some related bits.</li>
<li>The old <code class="highlighter-rouge">Osc</code> struct is now called <code class="highlighter-rouge">OscRegs</code></li>
<li>There is a new struct called <code class="highlighter-rouge">Osc</code>, which holds a reference to the
registers</li>
<li>There is a new global <code class="highlighter-rouge">AtomicBool</code> acting as a flag to indicate
when there is an outstanding reference to the <code class="highlighter-rouge">Osc</code>.</li>
<li>The <code class="highlighter-rouge">::new</code> function now returns an owned struct, instead of a
reference. It will also panic if there is already an instance of
<code class="highlighter-rouge">Osc</code> in use.</li>
<li>We implement <code class="highlighter-rouge">Drop</code> for <code class="highlighter-rouge">Osc</code>, to indicate when there is no longer
an active instance, and it is safe to create a new one.</li>
</ol>
<p>It is important that we use an atomic boolean for this flag. Besides
being friendly to Rust’s rules for global variables,an atomic protects
us from race conditions when accessing the OSC.</p>
<p>The MCG struct is updated similarly, and uses an identical allocation
pattern. An important addition with the MCG is that each of the clock
state structs now <em>own</em> the MCG instance, and pass that ownership down
the chain as the clock state is changed. Here’s all of the MCG
code. I’ve left out the change to indirect all register accesses
through the <code class="highlighter-rouge">regs</code> member, since that would balloon this example.</p>
<figure class="highlight"><pre><code class="language-rust" data-lang="rust"><span class="k">use</span> <span class="nn">core</span><span class="p">::</span><span class="n">mem</span><span class="p">;</span>
<span class="k">use</span> <span class="nn">volatile</span><span class="p">::</span><span class="n">Volatile</span><span class="p">;</span>
<span class="k">use</span> <span class="nn">bit_field</span><span class="p">::</span><span class="n">BitField</span><span class="p">;</span>
<span class="k">use</span> <span class="nn">super</span><span class="p">::</span><span class="n">OscToken</span><span class="p">;</span>
<span class="k">use</span> <span class="nn">core</span><span class="p">::</span><span class="nn">sync</span><span class="p">::</span><span class="nn">atomic</span><span class="p">::{</span><span class="n">AtomicBool</span><span class="p">,</span><span class="n">ATOMIC_BOOL_INIT</span><span class="p">,</span><span class="n">Ordering</span><span class="p">};</span>
<span class="nd">#[repr(C,packed)]</span>
<span class="k">struct</span> <span class="n">McgRegs</span> <span class="p">{</span>
<span class="o">...</span>
<span class="p">}</span>
<span class="k">pub</span> <span class="k">struct</span> <span class="n">Mcg</span> <span class="p">{</span>
<span class="n">reg</span><span class="p">:</span> <span class="o">&</span><span class="nv">'static</span> <span class="k">mut</span> <span class="n">McgRegs</span>
<span class="p">}</span>
<span class="k">pub</span> <span class="k">struct</span> <span class="n">Fei</span> <span class="p">{</span>
<span class="n">mcg</span><span class="p">:</span> <span class="n">Mcg</span>
<span class="p">}</span>
<span class="k">pub</span> <span class="k">struct</span> <span class="n">Fbe</span> <span class="p">{</span>
<span class="n">mcg</span><span class="p">:</span> <span class="n">Mcg</span>
<span class="p">}</span>
<span class="k">pub</span> <span class="k">struct</span> <span class="n">Pbe</span> <span class="p">{</span>
<span class="n">mcg</span><span class="p">:</span> <span class="n">Mcg</span>
<span class="p">}</span>
<span class="k">pub</span> <span class="k">enum</span> <span class="n">Clock</span> <span class="p">{</span>
<span class="nf">Fei</span><span class="p">(</span><span class="n">Fei</span><span class="p">),</span>
<span class="nf">Fbe</span><span class="p">(</span><span class="n">Fbe</span><span class="p">),</span>
<span class="nf">Pbe</span><span class="p">(</span><span class="n">Pbe</span><span class="p">)</span>
<span class="p">}</span>
<span class="k">static</span> <span class="n">MCG_INIT</span><span class="p">:</span> <span class="n">AtomicBool</span> <span class="o">=</span> <span class="n">ATOMIC_BOOL_INIT</span><span class="p">;</span>
<span class="k">impl</span> <span class="n">Mcg</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="k">-></span> <span class="n">Mcg</span> <span class="p">{</span>
<span class="k">let</span> <span class="n">was_init</span> <span class="o">=</span> <span class="n">MCG_INIT</span><span class="nf">.swap</span><span class="p">(</span><span class="k">true</span><span class="p">,</span> <span class="nn">Ordering</span><span class="p">::</span><span class="n">Relaxed</span><span class="p">);</span>
<span class="k">if</span> <span class="n">was_init</span> <span class="p">{</span>
<span class="nd">panic!</span><span class="p">(</span><span class="s">"Cannot initialize MCG: It's already active"</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">let</span> <span class="n">reg</span> <span class="o">=</span> <span class="k">unsafe</span> <span class="p">{</span> <span class="o">&</span><span class="k">mut</span> <span class="o">*</span><span class="p">(</span><span class="mi">0x40064000</span> <span class="k">as</span> <span class="o">*</span><span class="k">mut</span> <span class="n">McgRegs</span><span class="p">)</span> <span class="p">};</span>
<span class="n">Mcg</span> <span class="p">{</span><span class="n">reg</span><span class="p">:</span> <span class="n">reg</span><span class="p">}</span>
<span class="p">}{</span>
<span class="k">pub</span> <span class="k">fn</span> <span class="nf">clock</span><span class="p">(</span><span class="k">self</span><span class="p">)</span> <span class="k">-></span> <span class="n">Clock</span> <span class="p">{</span>
<span class="o">...</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="k">impl</span> <span class="n">Drop</span> <span class="k">for</span> <span class="n">Mcg</span> <span class="p">{</span>
<span class="k">fn</span> <span class="k">drop</span><span class="p">(</span><span class="o">&</span><span class="k">mut</span> <span class="k">self</span><span class="p">)</span> <span class="p">{</span>
<span class="n">MCG_INIT</span><span class="nf">.store</span><span class="p">(</span><span class="k">false</span><span class="p">,</span> <span class="nn">Ordering</span><span class="p">::</span><span class="n">Relaxed</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span></code></pre></figure>
<h3 id="remember-your-invariants">Remember Your Invariants</h3>
<p>There is one more lingering piece of unsoundness in this code: The way
we configure the MCG requires the OSC to be initialized, but nothing
currently enforces this. We can fix this with a simple token type that
indicates that the OSC is configured:</p>
<figure class="highlight"><pre><code class="language-rust" data-lang="rust"><span class="k">pub</span> <span class="k">struct</span> <span class="n">OscToken</span> <span class="p">{</span>
<span class="n">_private</span><span class="p">:</span> <span class="p">()</span>
<span class="p">}</span>
<span class="k">impl</span> <span class="n">Osc</span> <span class="p">{</span>
<span class="k">pub</span> <span class="k">fn</span> <span class="nf">enable</span><span class="p">(</span><span class="o">&</span><span class="k">mut</span> <span class="k">self</span><span class="p">,</span> <span class="n">capacitance</span><span class="p">:</span> <span class="nb">u8</span><span class="p">)</span> <span class="k">-></span> <span class="n">OscToken</span> <span class="p">{</span>
<span class="o">...</span>
<span class="k">return</span> <span class="nn">OscToken</span><span class="p">::</span><span class="nf">new</span><span class="p">()</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="k">impl</span> <span class="n">OscToken</span> <span class="p">{</span>
<span class="k">fn</span> <span class="nf">new</span><span class="p">()</span> <span class="k">-></span> <span class="n">OscToken</span> <span class="p">{</span>
<span class="n">OscToken</span> <span class="p">{</span> <span class="n">_private</span><span class="p">:</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">Fei</span> <span class="p">{</span>
<span class="k">pub</span> <span class="k">fn</span> <span class="nf">enable_xtal</span><span class="p">(</span><span class="o">&</span><span class="k">mut</span> <span class="k">self</span><span class="p">,</span> <span class="n">range</span><span class="p">:</span> <span class="n">OscRange</span><span class="p">,</span> <span class="n">_token</span><span class="p">:</span> <span class="n">OscToken</span><span class="p">)</span> <span class="p">{</span>
<span class="o">...</span>
<span class="p">}</span>
<span class="p">}</span></code></pre></figure>
<h2 id="the-sim">The SIM</h2>
<p>Allocation for a <code class="highlighter-rouge">Sim</code> instance can be handled in the same way as for
the MCG and OSC. We add an <code class="highlighter-rouge">AtomicBool</code> to act as a lock, and
implement <code class="highlighter-rouge">Drop</code> to clear that lock when the <code class="highlighter-rouge">Sim</code> goes out of
scope. I trust you can do this on your own at this point.</p>
<h3 id="clock-gates">Clock Gates</h3>
<p>The next problem we face with the SIM is clock gates. Ideally, we want
clock gating to be tied to the allocation of a hardware unit - it
should be impossible to have an outstanding reference to a piece of
hardware without its clock gate being enabled, and vice-versa. The
first is necessary for safety reasons - accessing hardware that is
disabled will cause a hardware fault. The second is for
power-efficiency reasons. Any hardware we’re not using should be
turned off if possible.</p>
<p>We’ll handle this by moving allocation of most hardware units to the
SIM. Let’s start with Ports:</p>
<figure class="highlight"><pre><code class="language-rust" data-lang="rust"><span class="k">pub</span> <span class="k">struct</span> <span class="n">ClockGate</span> <span class="p">{</span>
<span class="n">gate</span><span class="p">:</span> <span class="o">&</span><span class="nv">'static</span> <span class="k">mut</span> <span class="n">Volatile</span><span class="o"><</span><span class="nb">u32</span><span class="o">></span>
<span class="p">}</span>
<span class="k">impl</span> <span class="n">ClockGate</span> <span class="p">{</span>
<span class="k">fn</span> <span class="nf">new</span><span class="p">(</span><span class="n">reg</span><span class="p">:</span> <span class="nb">usize</span><span class="p">,</span> <span class="n">bit</span><span class="p">:</span> <span class="nb">usize</span><span class="p">)</span> <span class="k">-></span> <span class="n">ClockGate</span> <span class="p">{</span>
<span class="k">assert</span><span class="o">!</span><span class="p">(</span><span class="n">reg</span> <span class="o"><=</span> <span class="mi">7</span><span class="p">);</span>
<span class="k">assert</span><span class="o">!</span><span class="p">(</span><span class="n">bit</span> <span class="o"><=</span> <span class="mi">31</span><span class="p">);</span>
<span class="k">let</span> <span class="n">base</span><span class="p">:</span> <span class="nb">usize</span> <span class="o">=</span> <span class="mi">0x42900500</span><span class="p">;</span>
<span class="k">let</span> <span class="n">reg_offset</span> <span class="o">=</span> <span class="mi">128</span> <span class="o">*</span> <span class="p">(</span><span class="n">reg</span> <span class="err">-</span> <span class="mi">1</span><span class="p">);</span>
<span class="k">let</span> <span class="n">bit_offset</span> <span class="o">=</span> <span class="mi">4</span> <span class="o">*</span> <span class="n">bit</span><span class="p">;</span>
<span class="k">let</span> <span class="n">ptr</span> <span class="o">=</span> <span class="p">(</span><span class="n">base</span> <span class="o">+</span> <span class="n">reg_offset</span> <span class="o">+</span> <span class="n">bit_offset</span><span class="p">)</span> <span class="k">as</span> <span class="o">*</span><span class="k">mut</span> <span class="n">Volatile</span><span class="o"><</span><span class="nb">u32</span><span class="o">></span><span class="p">;</span>
<span class="k">unsafe</span> <span class="p">{</span>
<span class="n">ClockGate</span> <span class="p">{</span> <span class="n">gate</span><span class="p">:</span> <span class="o">&</span><span class="k">mut</span> <span class="o">*</span><span class="n">ptr</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">Drop</span> <span class="k">for</span> <span class="n">ClockGate</span> <span class="p">{</span>
<span class="k">fn</span> <span class="k">drop</span><span class="p">(</span><span class="o">&</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">.gate</span><span class="nf">.write</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="k">impl</span> <span class="n">Sim</span> <span class="p">{</span>
<span class="k">pub</span> <span class="k">fn</span> <span class="nf">port</span><span class="p">(</span><span class="o">&</span><span class="k">mut</span> <span class="k">self</span><span class="p">,</span> <span class="n">port</span><span class="p">:</span> <span class="n">PortName</span><span class="p">)</span> <span class="k">-></span> <span class="n">Port</span> <span class="p">{</span>
<span class="k">let</span> <span class="n">gate</span> <span class="o">=</span> <span class="k">match</span> <span class="n">port</span> <span class="p">{</span>
<span class="nn">PortName</span><span class="p">::</span><span class="n">B</span> <span class="k">=></span> <span class="nn">ClockGate</span><span class="p">::</span><span class="nf">new</span><span class="p">(</span><span class="mi">5</span><span class="p">,</span> <span class="mi">10</span><span class="p">),</span>
<span class="nn">PortName</span><span class="p">::</span><span class="n">C</span> <span class="k">=></span> <span class="nn">ClockGate</span><span class="p">::</span><span class="nf">new</span><span class="p">(</span><span class="mi">5</span><span class="p">,</span> <span class="mi">11</span><span class="p">),</span>
<span class="p">};</span>
<span class="k">if</span> <span class="n">gate</span><span class="py">.gate</span><span class="nf">.read</span><span class="p">()</span> <span class="o">!=</span> <span class="mi">0</span> <span class="p">{</span>
<span class="nd">panic!</span><span class="p">(</span><span class="s">"Cannot create Port instance; it is already in use"</span><span class="p">);</span>
<span class="p">}</span>
<span class="n">gate</span><span class="py">.gate</span><span class="nf">.write</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span>
<span class="k">unsafe</span> <span class="p">{</span>
<span class="nn">Port</span><span class="p">::</span><span class="nf">new</span><span class="p">(</span><span class="n">port</span><span class="p">,</span> <span class="n">gate</span><span class="p">)</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span></code></pre></figure>
<p>The new <code class="highlighter-rouge">ClockGate</code> struct uses the bitband to enable or disable a
clock gate when it is created or dropped. The port allocation function
passes ownership of the <code class="highlighter-rouge">ClockGate</code> to the <code class="highlighter-rouge">Port</code> instance. Let’s take
a look at that now:</p>
<figure class="highlight"><pre><code class="language-rust" data-lang="rust"><span class="k">pub</span> <span class="k">struct</span> <span class="n">Port</span> <span class="p">{</span>
<span class="n">reg</span><span class="p">:</span> <span class="n">UnsafeCell</span><span class="o"><&</span><span class="nv">'static</span> <span class="k">mut</span> <span class="n">PortRegs</span><span class="o">></span><span class="p">,</span>
<span class="n">locks</span><span class="p">:</span> <span class="p">[</span><span class="n">AtomicBool</span><span class="p">;</span> <span class="mi">32</span><span class="p">],</span>
<span class="n">_gate</span><span class="p">:</span> <span class="n">ClockGate</span><span class="p">,</span>
<span class="p">}</span>
<span class="k">impl</span> <span class="n">Port</span> <span class="p">{</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">name</span><span class="p">:</span> <span class="n">PortName</span><span class="p">,</span> <span class="n">gate</span><span class="p">:</span> <span class="n">ClockGate</span><span class="p">)</span> <span class="k">-></span> <span class="n">Port</span> <span class="p">{</span>
<span class="k">let</span> <span class="n">myself</span> <span class="o">=</span> <span class="o">&</span><span class="k">mut</span> <span class="o">*</span> <span class="k">match</span> <span class="n">name</span> <span class="p">{</span>
<span class="nn">PortName</span><span class="p">::</span><span class="n">B</span> <span class="k">=></span> <span class="mi">0x4004A000</span> <span class="k">as</span> <span class="o">*</span><span class="k">mut</span> <span class="n">PortRegs</span><span class="p">,</span>
<span class="nn">PortName</span><span class="p">::</span><span class="n">C</span> <span class="k">=></span> <span class="mi">0x4004B000</span> <span class="k">as</span> <span class="o">*</span><span class="k">mut</span> <span class="n">PortRegs</span>
<span class="p">};</span>
<span class="n">Port</span> <span class="p">{</span> <span class="n">reg</span><span class="p">:</span> <span class="nn">UnsafeCell</span><span class="p">::</span><span class="nf">new</span><span class="p">(</span><span class="n">myself</span><span class="p">),</span> <span class="n">locks</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="n">_gate</span><span class="p">:</span> <span class="n">gate</span> <span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span></code></pre></figure>
<p>The move to a <code class="highlighter-rouge">PortRegs</code> struct is the same pattern we’ve seen for
other hardware units so far. Wrapping the reference in <code class="highlighter-rouge">UnsafeCell</code> is
due to how pins are handled - we’ll cover that shortly. The <code class="highlighter-rouge">locks</code>
member is also for safe pin handling. The <code class="highlighter-rouge">_gate</code> member keeps the
appropriate clock gate enabled for as long as this <code class="highlighter-rouge">Port</code> instance
exists. The <code class="highlighter-rouge">ClockGate</code> will be dropped when the <code class="highlighter-rouge">Port</code> is - precisely
what we want.</p>
<h2 id="safe-pins">Safe Pins</h2>
<p>Making pins safe requires some additional reasoning. Since a <code class="highlighter-rouge">Port</code>
being dropped will cause the associated clock gate to be disabled, we
know that a <code class="highlighter-rouge">Port</code> must outlive any associated <code class="highlighter-rouge">Pin</code>. This means that
each <code class="highlighter-rouge">Pin</code> struct must borrow its parent <code class="highlighter-rouge">Port</code>. In order for multiple
<code class="highlighter-rouge">Pins</code> to borrow a single <code class="highlighter-rouge">Port</code>, these must be immutable borrows.</p>
<p>This has an important implication: It must be possible to allocate a
<code class="highlighter-rouge">Pin</code> from a borrowed <code class="highlighter-rouge">Port</code> - possibly even simultaneously in
separate tasks or interrupt handlers. This is a form of <em>internal
mutability</em>, and is why the <code class="highlighter-rouge">PortRegs</code> reference is wrapped in an
<code class="highlighter-rouge">UnsafeCell</code>. Internal mutability often requires a bit more attention
to detail in order to ensure safety. I believe that this
implementation is safe, although I welcome any suggestions.</p>
<figure class="highlight"><pre><code class="language-rust" data-lang="rust"><span class="k">pub</span> <span class="k">struct</span> <span class="n">Pin</span><span class="o"><</span><span class="nv">'a</span><span class="o">></span> <span class="p">{</span>
<span class="n">port</span><span class="p">:</span> <span class="o">&</span><span class="nv">'a</span> <span class="n">Port</span><span class="p">,</span>
<span class="n">pin</span><span class="p">:</span> <span class="nb">usize</span>
<span class="p">}</span>
<span class="k">pub</span> <span class="k">struct</span> <span class="n">Tx</span><span class="o"><</span><span class="nv">'a</span><span class="o">></span> <span class="p">{</span>
<span class="n">uart</span><span class="p">:</span> <span class="nb">u8</span><span class="p">,</span>
<span class="n">_pin</span><span class="p">:</span> <span class="n">Pin</span><span class="o"><</span><span class="nv">'a</span><span class="o">></span>
<span class="p">}</span>
<span class="k">pub</span> <span class="k">struct</span> <span class="n">Rx</span><span class="o"><</span><span class="nv">'a</span><span class="o">></span> <span class="p">{</span>
<span class="n">uart</span><span class="p">:</span> <span class="nb">u8</span><span class="p">,</span>
<span class="n">_pin</span><span class="p">:</span> <span class="n">Pin</span><span class="o"><</span><span class="nv">'a</span><span class="o">></span>
<span class="p">}</span>
<span class="nd">#[repr(C,packed)]</span>
<span class="k">struct</span> <span class="n">GpioBitband</span> <span class="p">{</span>
<span class="n">pdor</span><span class="p">:</span> <span class="p">[</span><span class="n">Volatile</span><span class="o"><</span><span class="nb">u32</span><span class="o">></span><span class="p">;</span> <span class="mi">32</span><span class="p">],</span>
<span class="n">psor</span><span class="p">:</span> <span class="p">[</span><span class="n">Volatile</span><span class="o"><</span><span class="nb">u32</span><span class="o">></span><span class="p">;</span> <span class="mi">32</span><span class="p">],</span>
<span class="n">pcor</span><span class="p">:</span> <span class="p">[</span><span class="n">Volatile</span><span class="o"><</span><span class="nb">u32</span><span class="o">></span><span class="p">;</span> <span class="mi">32</span><span class="p">],</span>
<span class="n">ptor</span><span class="p">:</span> <span class="p">[</span><span class="n">Volatile</span><span class="o"><</span><span class="nb">u32</span><span class="o">></span><span class="p">;</span> <span class="mi">32</span><span class="p">],</span>
<span class="n">pdir</span><span class="p">:</span> <span class="p">[</span><span class="n">Volatile</span><span class="o"><</span><span class="nb">u32</span><span class="o">></span><span class="p">;</span> <span class="mi">32</span><span class="p">],</span>
<span class="n">pddr</span><span class="p">:</span> <span class="p">[</span><span class="n">Volatile</span><span class="o"><</span><span class="nb">u32</span><span class="o">></span><span class="p">;</span> <span class="mi">32</span><span class="p">]</span>
<span class="p">}</span>
<span class="k">pub</span> <span class="k">struct</span> <span class="n">Gpio</span><span class="o"><</span><span class="nv">'a</span><span class="o">></span> <span class="p">{</span>
<span class="n">gpio</span><span class="p">:</span> <span class="o">*</span><span class="k">mut</span> <span class="n">GpioBitband</span><span class="p">,</span>
<span class="n">pin</span><span class="p">:</span> <span class="n">Pin</span><span class="o"><</span><span class="nv">'a</span><span class="o">></span>
<span class="p">}</span>
<span class="k">impl</span> <span class="n">Port</span> <span class="p">{</span>
<span class="k">pub</span> <span class="k">fn</span> <span class="nf">pin</span><span class="p">(</span><span class="o">&</span><span class="k">self</span><span class="p">,</span> <span class="n">p</span><span class="p">:</span> <span class="nb">usize</span><span class="p">)</span> <span class="k">-></span> <span class="n">Pin</span> <span class="p">{</span>
<span class="k">assert</span><span class="o">!</span><span class="p">(</span><span class="n">p</span> <span class="o"><</span> <span class="mi">32</span><span class="p">);</span>
<span class="k">let</span> <span class="n">was_init</span> <span class="o">=</span> <span class="k">self</span><span class="py">.locks</span><span class="p">[</span><span class="n">p</span><span class="p">]</span><span class="nf">.swap</span><span class="p">(</span><span class="k">true</span><span class="p">,</span> <span class="nn">Ordering</span><span class="p">::</span><span class="n">Relaxed</span><span class="p">);</span>
<span class="k">if</span> <span class="n">was_init</span> <span class="p">{</span>
<span class="nd">panic!</span><span class="p">(</span><span class="s">"Pin {} is already in use"</span><span class="p">,</span> <span class="n">p</span><span class="p">);</span>
<span class="p">}</span>
<span class="n">Pin</span> <span class="p">{</span> <span class="n">port</span><span class="p">:</span> <span class="k">self</span><span class="p">,</span> <span class="n">pin</span><span class="p">:</span> <span class="n">p</span> <span class="p">}</span>
<span class="p">}</span>
<span class="k">unsafe</span> <span class="k">fn</span> <span class="nf">set_pin_mode</span><span class="p">(</span><span class="o">&</span><span class="k">self</span><span class="p">,</span> <span class="n">p</span><span class="p">:</span> <span class="nb">usize</span><span class="p">,</span> <span class="n">mode</span><span class="p">:</span> <span class="nb">u32</span><span class="p">)</span> <span class="p">{</span>
<span class="k">assert</span><span class="o">!</span><span class="p">(</span><span class="n">p</span> <span class="o"><</span> <span class="mi">32</span><span class="p">);</span>
<span class="k">self</span><span class="nf">.reg</span><span class="p">()</span><span class="py">.pcr</span><span class="p">[</span><span class="n">p</span><span class="p">]</span><span class="nf">.update</span><span class="p">(|</span><span class="n">pcr</span><span class="p">|</span> <span class="p">{</span>
<span class="n">pcr</span><span class="nf">.set_bits</span><span class="p">(</span><span class="mi">8</span><span class="o">..</span><span class="mi">11</span><span class="p">,</span> <span class="n">mode</span><span class="p">);</span>
<span class="p">});</span>
<span class="p">}</span>
<span class="k">unsafe</span> <span class="k">fn</span> <span class="nf">drop_pin</span><span class="p">(</span><span class="o">&</span><span class="k">self</span><span class="p">,</span> <span class="n">p</span><span class="p">:</span> <span class="nb">usize</span><span class="p">)</span> <span class="p">{</span>
<span class="k">assert</span><span class="o">!</span><span class="p">(</span><span class="n">p</span> <span class="o"><</span> <span class="mi">32</span><span class="p">);</span>
<span class="k">self</span><span class="py">.locks</span><span class="p">[</span><span class="n">p</span><span class="p">]</span><span class="nf">.store</span><span class="p">(</span><span class="k">false</span><span class="p">,</span> <span class="nn">Ordering</span><span class="p">::</span><span class="n">Relaxed</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">fn</span> <span class="nf">reg</span><span class="p">(</span><span class="o">&</span><span class="k">self</span><span class="p">)</span> <span class="k">-></span> <span class="o">&</span><span class="nv">'static</span> <span class="k">mut</span> <span class="n">PortRegs</span> <span class="p">{</span>
<span class="c">// NOTE: This does no validation. It's on the calling</span>
<span class="c">// functions to ensure they're not accessing the same</span>
<span class="c">// registers from multiple codepaths. If they can't make those</span>
<span class="c">// guarantees, they should be marked as `unsafe` (See</span>
<span class="c">// `set_pin_mode` as an example).</span>
<span class="k">unsafe</span> <span class="p">{</span>
<span class="o">*</span><span class="k">self</span><span class="py">.reg</span><span class="nf">.get</span><span class="p">()</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="k">impl</span> <span class="o"><</span><span class="nv">'a</span><span class="o">></span> <span class="n">Drop</span> <span class="k">for</span> <span class="n">Pin</span><span class="o"><</span><span class="nv">'a</span><span class="o">></span> <span class="p">{</span>
<span class="k">fn</span> <span class="k">drop</span><span class="p">(</span><span class="o">&</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="k">self</span><span class="py">.port</span><span class="nf">.drop_pin</span><span class="p">(</span><span class="k">self</span><span class="py">.pin</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span></code></pre></figure>
<p>As before, each <code class="highlighter-rouge">Pin</code> is really referencing only a subset of the
<code class="highlighter-rouge">Port</code> struct - the particular <code class="highlighter-rouge">pcr</code> register for that pin. This makes
our usage of <code class="highlighter-rouge">UnsafeCell</code> in the <code class="highlighter-rouge">set_pin_mode</code> function safe, as long
as the correct pin number is passed in. The various <code class="highlighter-rouge">Pin::make_*</code>
functions enforce this invariant, wrapping the unsafe <code class="highlighter-rouge">set_pin_mode</code>
in safe functions.</p>
<p>The <code class="highlighter-rouge">Gpio</code>, <code class="highlighter-rouge">Tx</code>, and <code class="highlighter-rouge">Rx</code> structs now also hold on to their
associated <code class="highlighter-rouge">Pin</code> struct. This is simply to ensure that the correct
<code class="highlighter-rouge">Port</code> remains borrowed for as long as these structs are in scope.</p>
<h2 id="cleaning-up-the-uart">Cleaning up the UART</h2>
<p>We’re almost there! The UART has the most complex requirements, but
they build off of everything we’ve done so far. Just like a <code class="highlighter-rouge">Port</code>, a
<code class="highlighter-rouge">Uart</code> instance must hold on to a <code class="highlighter-rouge">ClockGate</code>. It also must keep track
of the pins it is using, both to prevent the associated <code class="highlighter-rouge">Port</code> from
being dropped, and to keep the pins themselves from being used
elsewhere.</p>
<p>We’ll start by adding a <code class="highlighter-rouge">::uart</code> method to the <code class="highlighter-rouge">Sim</code>, to do the
allocation, and go from there by updating the <code class="highlighter-rouge">Uart</code> struct itself to
own the various necessary structs. These are actually simpler changes
than were necessary for the <code class="highlighter-rouge">Port</code> struct - we already did most of the
heavy lifting when we made that safe!</p>
<figure class="highlight"><pre><code class="language-rust" data-lang="rust"><span class="k">impl</span> <span class="n">Sim</span>
<span class="k">pub</span> <span class="k">fn</span> <span class="n">uart</span><span class="o"><</span><span class="nv">'a</span><span class="p">,</span> <span class="nv">'b</span><span class="o">></span><span class="p">(</span><span class="o">&</span><span class="k">mut</span> <span class="k">self</span><span class="p">,</span> <span class="n">uart</span><span class="p">:</span> <span class="nb">u8</span><span class="p">,</span> <span class="n">rx</span><span class="p">:</span> <span class="nb">Option</span><span class="o"><</span><span class="n">Rx</span><span class="o"><</span><span class="nv">'a</span><span class="o">>></span><span class="p">,</span> <span class="n">tx</span><span class="p">:</span> <span class="nb">Option</span><span class="o"><</span><span class="n">Tx</span><span class="o"><</span><span class="nv">'b</span><span class="o">>></span><span class="p">,</span> <span class="n">clkdiv</span><span class="p">:</span> <span class="p">(</span><span class="nb">u16</span><span class="p">,</span> <span class="nb">u8</span><span class="p">))</span> <span class="k">-></span> <span class="n">Uart</span><span class="o"><</span><span class="nv">'a</span><span class="p">,</span> <span class="nv">'b</span><span class="o">></span> <span class="p">{</span>
<span class="k">let</span> <span class="n">gate</span> <span class="o">=</span> <span class="k">match</span> <span class="n">uart</span> <span class="p">{</span>
<span class="mi">0</span> <span class="k">=></span> <span class="nn">ClockGate</span><span class="p">::</span><span class="nf">new</span><span class="p">(</span><span class="mi">4</span><span class="p">,</span> <span class="mi">10</span><span class="p">),</span>
<span class="n">_</span> <span class="k">=></span> <span class="nd">panic!</span><span class="p">(</span><span class="s">"Cannot enable clock for UART {}"</span><span class="p">,</span> <span class="n">uart</span><span class="p">)</span>
<span class="p">};</span>
<span class="k">if</span> <span class="n">gate</span><span class="py">.gate</span><span class="nf">.read</span><span class="p">()</span> <span class="o">!=</span> <span class="mi">0</span> <span class="p">{</span>
<span class="nd">panic!</span><span class="p">(</span><span class="s">"Cannot create Uart instance; it is already in use"</span><span class="p">);</span>
<span class="p">}</span>
<span class="n">gate</span><span class="py">.gate</span><span class="nf">.write</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span>
<span class="k">unsafe</span> <span class="p">{</span>
<span class="nn">Uart</span><span class="p">::</span><span class="nf">new</span><span class="p">(</span><span class="n">uart</span><span class="p">,</span> <span class="n">rx</span><span class="p">,</span> <span class="n">tx</span><span class="p">,</span> <span class="n">clkdiv</span><span class="p">,</span> <span class="n">gate</span><span class="p">)</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="k">use</span> <span class="nn">volatile</span><span class="p">::</span><span class="n">Volatile</span><span class="p">;</span>
<span class="k">use</span> <span class="nn">bit_field</span><span class="p">::</span><span class="n">BitField</span><span class="p">;</span>
<span class="k">use</span> <span class="n">core</span><span class="p">;</span>
<span class="k">use</span> <span class="nn">super</span><span class="p">::{</span><span class="n">ClockGate</span><span class="p">,</span><span class="n">Rx</span><span class="p">,</span><span class="n">Tx</span><span class="p">};</span>
<span class="nd">#[repr(C,packed)]</span>
<span class="k">struct</span> <span class="n">UartRegs</span> <span class="p">{</span>
<span class="o">...</span>
<span class="p">}</span>
<span class="k">pub</span> <span class="k">struct</span> <span class="n">Uart</span><span class="o"><</span><span class="nv">'a</span><span class="p">,</span> <span class="nv">'b</span><span class="o">></span> <span class="p">{</span>
<span class="n">reg</span><span class="p">:</span> <span class="o">&</span><span class="nv">'static</span> <span class="k">mut</span> <span class="n">UartRegs</span><span class="p">,</span>
<span class="n">_rx</span><span class="p">:</span> <span class="nb">Option</span><span class="o"><</span><span class="n">Rx</span><span class="o"><</span><span class="nv">'a</span><span class="o">>></span><span class="p">,</span>
<span class="n">_tx</span><span class="p">:</span> <span class="nb">Option</span><span class="o"><</span><span class="n">Tx</span><span class="o"><</span><span class="nv">'b</span><span class="o">>></span><span class="p">,</span>
<span class="n">_gate</span><span class="p">:</span> <span class="n">ClockGate</span>
<span class="p">}</span>
<span class="k">impl</span> <span class="o"><</span><span class="nv">'a</span><span class="p">,</span> <span class="nv">'b</span><span class="o">></span> <span class="n">Uart</span><span class="o"><</span><span class="nv">'a</span><span class="p">,</span> <span class="nv">'b</span><span class="o">></span> <span class="p">{</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">id</span><span class="p">:</span> <span class="nb">u8</span><span class="p">,</span> <span class="n">rx</span><span class="p">:</span> <span class="nb">Option</span><span class="o"><</span><span class="n">Rx</span><span class="o"><</span><span class="nv">'a</span><span class="o">>></span><span class="p">,</span> <span class="n">tx</span><span class="p">:</span> <span class="nb">Option</span><span class="o"><</span><span class="n">Tx</span><span class="o"><</span><span class="nv">'b</span><span class="o">>></span><span class="p">,</span> <span class="n">clkdiv</span><span class="p">:</span> <span class="p">(</span><span class="nb">u16</span><span class="p">,</span><span class="nb">u8</span><span class="p">),</span> <span class="n">gate</span><span class="p">:</span> <span class="n">ClockGate</span><span class="p">)</span> <span class="k">-></span> <span class="n">Uart</span><span class="o"><</span><span class="nv">'a</span><span class="p">,</span> <span class="nv">'b</span><span class="o">></span> <span class="p">{</span>
<span class="o">...</span>
<span class="n">Uart</span> <span class="p">{</span><span class="n">reg</span><span class="p">:</span> <span class="n">uart</span><span class="p">,</span> <span class="n">_tx</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">rx</span><span class="p">,</span> <span class="n">_gate</span><span class="p">:</span> <span class="n">gate</span><span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span></code></pre></figure>
<h2 id="a-new-segment">A New Segment</h2>
<p>Several of the updated structs above use global <code class="highlighter-rouge">AtomicBool</code> instances
to keep track of whether they are in use. These booleans are stored in
a new executable section called <code class="highlighter-rouge">.bss</code>. We must initialize all data in
this section to zero at program startup.</p>
<p>We’ll add the new section to our linker script, then write a simple
function to zero the data at startup.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>SECTIONS
{
...
.bss : {
. = ORIGIN(RAM);
_bss_start = .;
*(.bss*)
_bss_end = .;
} > RAM
...
}
</code></pre></div></div>
<figure class="highlight"><pre><code class="language-rust" data-lang="rust"><span class="err">#</span><span class="o">!</span><span class="p">[</span><span class="n">no_builtins</span><span class="p">]</span>
<span class="k">extern</span> <span class="p">{</span>
<span class="k">static</span> <span class="k">mut</span> <span class="n">_bss_start</span><span class="p">:</span> <span class="nb">u8</span><span class="p">;</span>
<span class="k">static</span> <span class="k">mut</span> <span class="n">_bss_end</span><span class="p">:</span> <span class="nb">u8</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">unsafe</span> <span class="k">fn</span> <span class="nf">setup_bss</span><span class="p">()</span> <span class="p">{</span>
<span class="k">let</span> <span class="n">bss_start</span> <span class="o">=</span> <span class="o">&</span><span class="k">mut</span> <span class="n">_bss_start</span> <span class="k">as</span> <span class="o">*</span><span class="k">mut</span> <span class="nb">u8</span><span class="p">;</span>
<span class="k">let</span> <span class="n">bss_end</span> <span class="o">=</span> <span class="o">&</span><span class="k">mut</span> <span class="n">_bss_end</span> <span class="k">as</span> <span class="o">*</span><span class="k">mut</span> <span class="nb">u8</span><span class="p">;</span>
<span class="k">let</span> <span class="n">bss_len</span> <span class="o">=</span> <span class="n">bss_end</span> <span class="k">as</span> <span class="nb">usize</span> <span class="err">-</span> <span class="n">bss_start</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">;</span>
<span class="k">let</span> <span class="n">bss</span> <span class="o">=</span> <span class="nn">slice</span><span class="p">::</span><span class="nf">from_raw_parts_mut</span><span class="p">(</span><span class="n">bss_start</span><span class="p">,</span> <span class="n">bss_len</span><span class="p">);</span>
<span class="k">for</span> <span class="n">b</span> <span class="n">in</span> <span class="o">&</span><span class="k">mut</span> <span class="n">bss</span><span class="nf">.iter_mut</span><span class="p">()</span> <span class="p">{</span>
<span class="o">*</span><span class="n">b</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span></code></pre></figure>
<p>The new <code class="highlighter-rouge">no_builtins</code> crate attribute prevents the compiler from
trying to convert our loop in <code class="highlighter-rouge">setup_bss</code> into a call to <code class="highlighter-rouge">memclr</code>,
which does not exist in our embedded world. The new <code class="highlighter-rouge">setup_bss</code>
function is also unsafe, since it directly manipulates memory that is
in use by other parts of the program.</p>
<h2 id="printing-panics">Printing Panics</h2>
<p>Our new code relies on panics quite frequently to indicate when
something has gone wrong. Nothing should panic if you’re following
this series closely, but in the future we’ll rely on panics in more
complex code. We can use our UART to send panic messages back to a
host computer, making it easier for us to track when something has
gone wrong:</p>
<figure class="highlight"><pre><code class="language-rust" data-lang="rust"><span class="k">static</span> <span class="k">mut</span> <span class="n">PORT</span><span class="p">:</span> <span class="nb">Option</span><span class="o"><</span><span class="n">Port</span><span class="o">></span> <span class="o">=</span> <span class="nb">None</span><span class="p">;</span>
<span class="k">static</span> <span class="k">mut</span> <span class="n">WRITER</span><span class="p">:</span> <span class="nb">Option</span><span class="o"><</span><span class="n">Uart</span><span class="o"><</span><span class="nv">'static</span><span class="p">,</span> <span class="nv">'static</span><span class="o">>></span> <span class="o">=</span> <span class="nb">None</span><span class="p">;</span>
<span class="nd">#[panic_handler]</span>
<span class="k">fn</span> <span class="nf">teensy_panic</span><span class="p">(</span><span class="n">pi</span><span class="p">:</span> <span class="o">&</span><span class="nn">core</span><span class="p">::</span><span class="nn">panic</span><span class="p">::</span><span class="n">PanicInfo</span><span class="p">)</span> <span class="k">-></span> <span class="o">!</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="n">uart</span><span class="p">)</span> <span class="o">=</span> <span class="k">unsafe</span> <span class="p">{</span> <span class="n">WRITER</span><span class="nf">.as_mut</span><span class="p">()</span> <span class="p">}</span> <span class="p">{</span>
<span class="nd">write!</span><span class="p">(</span><span class="n">uart</span><span class="p">,</span> <span class="s">"Panic occured! "</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="n">format_args</span><span class="p">)</span> <span class="o">=</span> <span class="n">pi</span><span class="nf">.message</span><span class="p">()</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="nf">write</span><span class="p">(</span><span class="n">uart</span><span class="p">,</span> <span class="o">*</span><span class="n">format_args</span><span class="p">)</span><span class="nf">.unwrap</span><span class="p">();</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="c">// Reset the MCU after we've printed our panic.</span>
<span class="k">let</span> <span class="n">aircr</span> <span class="o">=</span> <span class="k">unsafe</span> <span class="p">{</span>
<span class="o">&</span><span class="k">mut</span> <span class="o">*</span><span class="p">(</span><span class="mi">0xE000ED0C</span> <span class="k">as</span> <span class="o">*</span><span class="k">mut</span> <span class="n">Volatile</span><span class="o"><</span><span class="nb">u32</span><span class="o">></span><span class="p">)</span>
<span class="p">};</span>
<span class="n">aircr</span><span class="nf">.write</span><span class="p">(</span><span class="mi">0x05FA0004</span><span class="p">);</span>
<span class="nd">unreachable!</span><span class="p">();</span>
<span class="p">}</span></code></pre></figure>
<p>This code uses a couple of global variables to make a UART available
to the panic printer. The printer also now resets the microcontroller,
instead of hanging. This requires accessing a register we don’t have a
struct for yet, so we cheat and write to its address directly.</p>
<h2 id="putting-it-together">Putting it Together</h2>
<p>We’ve now expanded our types to use more of Rust’s features to ensure
safety. Let’s put it all together with a new <code class="highlighter-rouge">main</code> that uses less
unsafe code:</p>
<figure class="highlight"><pre><code class="language-rust" data-lang="rust"><span class="err">#</span><span class="p">[</span><span class="nf">allow</span><span class="p">(</span><span class="n">empty_loop</span><span class="p">)]</span>
<span class="k">extern</span> <span class="k">fn</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
<span class="k">unsafe</span> <span class="p">{</span>
<span class="nn">Watchdog</span><span class="p">::</span><span class="nf">new</span><span class="p">()</span><span class="nf">.disable</span><span class="p">();</span>
<span class="nf">setup_bss</span><span class="p">();</span>
<span class="p">}</span>
<span class="c">// Enable the crystal oscillator with 10pf of capacitance</span>
<span class="k">let</span> <span class="n">osc_token</span> <span class="o">=</span> <span class="nn">Osc</span><span class="p">::</span><span class="nf">new</span><span class="p">()</span><span class="nf">.enable</span><span class="p">(</span><span class="mi">10</span><span class="p">);</span>
<span class="c">// Set our clocks:</span>
<span class="c">// core: 72Mhz</span>
<span class="c">// peripheral: 36MHz</span>
<span class="c">// flash: 24MHz</span>
<span class="k">let</span> <span class="k">mut</span> <span class="n">sim</span> <span class="o">=</span> <span class="nn">Sim</span><span class="p">::</span><span class="nf">new</span><span class="p">();</span>
<span class="n">sim</span><span class="nf">.set_dividers</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">);</span>
<span class="c">// We would also set the USB divider here if we wanted to use it.</span>
<span class="c">// Now we can start setting up the MCG for our needs.</span>
<span class="k">let</span> <span class="n">mcg</span> <span class="o">=</span> <span class="nn">Mcg</span><span class="p">::</span><span class="nf">new</span><span class="p">();</span>
<span class="k">if</span> <span class="k">let</span> <span class="nn">Clock</span><span class="p">::</span><span class="nf">Fei</span><span class="p">(</span><span class="k">mut</span> <span class="n">fei</span><span class="p">)</span> <span class="o">=</span> <span class="n">mcg</span><span class="nf">.clock</span><span class="p">()</span> <span class="p">{</span>
<span class="c">// Our 16MHz xtal is "very fast", and needs to be divided</span>
<span class="c">// by 512 to be in the acceptable FLL range.</span>
<span class="n">fei</span><span class="nf">.enable_xtal</span><span class="p">(</span><span class="nn">OscRange</span><span class="p">::</span><span class="n">VeryHigh</span><span class="p">,</span> <span class="n">osc_token</span><span class="p">);</span>
<span class="k">let</span> <span class="n">fbe</span> <span class="o">=</span> <span class="n">fei</span><span class="nf">.use_external</span><span class="p">(</span><span class="mi">512</span><span class="p">);</span>
<span class="c">// PLL is 27/6 * xtal == 72MHz</span>
<span class="k">let</span> <span class="n">pbe</span> <span class="o">=</span> <span class="n">fbe</span><span class="nf">.enable_pll</span><span class="p">(</span><span class="mi">27</span><span class="p">,</span> <span class="mi">6</span><span class="p">);</span>
<span class="n">pbe</span><span class="nf">.use_pll</span><span class="p">();</span>
<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
<span class="nd">panic!</span><span class="p">(</span><span class="s">"Somehow the clock wasn't in FEI mode"</span><span class="p">);</span>
<span class="p">}</span>
<span class="c">// Initialize the UART as our panic writer. This is unsafe because</span>
<span class="c">// we are modifying a global variable.</span>
<span class="k">unsafe</span> <span class="p">{</span>
<span class="n">PORT</span> <span class="o">=</span> <span class="nf">Some</span><span class="p">(</span><span class="n">sim</span><span class="nf">.port</span><span class="p">(</span><span class="nn">PortName</span><span class="p">::</span><span class="n">B</span><span class="p">));</span>
<span class="k">let</span> <span class="n">rx</span> <span class="o">=</span> <span class="n">PORT</span><span class="nf">.as_ref</span><span class="p">()</span><span class="nf">.unwrap</span><span class="p">()</span><span class="nf">.pin</span><span class="p">(</span><span class="mi">16</span><span class="p">)</span><span class="nf">.make_rx</span><span class="p">();</span>
<span class="k">let</span> <span class="n">tx</span> <span class="o">=</span> <span class="n">PORT</span><span class="nf">.as_ref</span><span class="p">()</span><span class="nf">.unwrap</span><span class="p">()</span><span class="nf">.pin</span><span class="p">(</span><span class="mi">17</span><span class="p">)</span><span class="nf">.make_tx</span><span class="p">();</span>
<span class="n">WRITER</span> <span class="o">=</span> <span class="nf">Some</span><span class="p">(</span><span class="n">sim</span><span class="nf">.uart</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="nf">Some</span><span class="p">(</span><span class="n">rx</span><span class="p">),</span> <span class="nf">Some</span><span class="p">(</span><span class="n">tx</span><span class="p">),</span> <span class="p">(</span><span class="mi">468</span><span class="p">,</span> <span class="mi">24</span><span class="p">)));</span>
<span class="p">};</span>
<span class="k">let</span> <span class="n">portc</span> <span class="o">=</span> <span class="n">sim</span><span class="nf">.port</span><span class="p">(</span><span class="nn">PortName</span><span class="p">::</span><span class="n">C</span><span class="p">);</span>
<span class="k">let</span> <span class="k">mut</span> <span class="n">gpio</span> <span class="o">=</span> <span class="n">portc</span><span class="nf">.pin</span><span class="p">(</span><span class="mi">5</span><span class="p">)</span><span class="nf">.make_gpio</span><span class="p">();</span>
<span class="n">gpio</span><span class="nf">.output</span><span class="p">();</span>
<span class="n">gpio</span><span class="nf">.high</span><span class="p">();</span>
<span class="k">loop</span> <span class="p">{};</span>
<span class="p">}</span></code></pre></figure>
<p>Two of our remaining uses of <code class="highlighter-rouge">unsafe</code> are clear: Clearing the <code class="highlighter-rouge">.bss</code>
segment, as we discussed earlier, writes to memory that is used by
other parts of the code. It must be unsafe. Modifying the globals used
by the panic printer is also unsafe.</p>
<p>But what about the watchdog? Any modification to the watchdog settings
requires knowledge of how the program itself is structured. A
misconfigured watchdog will reset the microcontroller at unexpected
times - or fail to reset it when a program has failed. Since it is
impossible to handle the coordination between watchdog settings and
software design programmatically, it is better to leave it unsafe, to
indicate that extreme caution is needed.</p>
<h2 id="next-time">Next Time</h2>
<p>Now that we have patterns for allocating hardware units, we’ll
continue to expand our toolbox of hardware units. We’ll configure
interrupts and a timer to interact with some external hardware - a
WS2812B RGB LED strip.</p>OverviewPart 2: Sending a Message2017-01-28T22:00:00+00:002017-01-28T22:00:00+00:00https://branan.github.io/teensy/2017/01/28/uart<h2 id="overview">Overview</h2>
<p>In this post, we’re going to set up the Teensy for serial
communication with the outside world. We’ll be able to use this serial
connection to send debug information back to our computers.</p>
<p>Serial communication is very timing-sensitive. Because of this, we
can’t use a serial connection until we have a very stable clock source
configured.</p>
<h3 id="a-serial-interface">A serial interface</h3>
<p>To connect the serial pins of the Teensy to our computer, we will need
some sort of USB serial interface. I’ll be using an Arduino Leonardo
for this. Any arduino-compatible device with at least one hardware
serial port will work, including a second Teensy. You may also be able
to find an FTDI breakout board or cable - but they’re pricey enough
that a second development board is probably a better investment. Trust
me, you can never have too many development boards!</p>
<p>The Teensy 3.2 and 3.5 are 5V tolerant, meaning they can be safely
used with just about any USB to serial converter (including the
Arduino Leonardo that I’m using). The 3.1 and 3.6 require an adapter
running at 3.3V. For them, you’ll likely want to either use another
Teensy, or a dedicated 3.3v serial adapter. Be careful about USB to
RS232 adapters. They run at much higher volatages than the
microcontroller, and <em>will</em> fry your teensy if you try to use one. You
want an adapter that has pin headers, not one with a DE-9 plug.</p>
<p>If you’re using an Arduino or Teensy as your adapter, check out the
<a href="https://github.com/branan/teensy/tree/master/serial_forward">serial_forward</a> Arduino sketch in the code
repository. Running this sketch will cause any output from our Teensy
to be forwarded through our Arduino to the IDE’s console.</p>
<h2 id="cleaner-register-handling">Cleaner Register Handling</h2>
<p>In the first post, we hand-coded all of our volatile register accesses
and bit manipulations. This is useful for understanding how the MCU
works, but has a few problems:</p>
<ul>
<li>
<p>Complex bit manipulations become “write-only” - it is hard to read
the code and understand what’s happening</p>
</li>
<li>
<p>We skipped some types of bounds checking, because it would have made
the code even harder to read. It would be nice to have this.</p>
</li>
<li>
<p>Volatile accesses introduce lots of extra “unsafe” blocks, making it
hard for us to see when we have code (like the Port and Gpio) that
actually does weird things with memory.</p>
</li>
</ul>
<p>To solve these, we will use a pair of crates from Philipp Oppermann:
<code class="highlighter-rouge">volatile</code> and <code class="highlighter-rouge">bit_field</code>. The <code class="highlighter-rouge">volatile</code> crate provides safe
wrappers for accessing volatile integers, like our hardware
registers. This is paired with <code class="highlighter-rouge">bit_field</code> to streamline our
manipulation of those registers.</p>
<h3 id="rewriting-the-watchdog">Rewriting the Watchdog</h3>
<p>The Watchdog provides a good demonstration for how these crates are
used. The updated code is shown below:</p>
<figure class="highlight"><pre><code class="language-rust" data-lang="rust"><span class="k">use</span> <span class="nn">volatile</span><span class="p">::</span><span class="n">Volatile</span><span class="p">;</span>
<span class="k">use</span> <span class="nn">bit_field</span><span class="p">::</span><span class="n">BitField</span><span class="p">;</span>
<span class="k">use</span> <span class="nn">core</span><span class="p">::</span><span class="nn">arch</span><span class="p">::</span><span class="nn">arm</span><span class="p">::</span><span class="n">__NOP</span><span class="p">;</span>
<span class="nd">#[repr(C,packed)]</span>
<span class="k">pub</span> <span class="k">struct</span> <span class="n">Watchdog</span> <span class="p">{</span>
<span class="n">stctrlh</span><span class="p">:</span> <span class="n">Volatile</span><span class="o"><</span><span class="nb">u16</span><span class="o">></span><span class="p">,</span>
<span class="n">stctrll</span><span class="p">:</span> <span class="n">Volatile</span><span class="o"><</span><span class="nb">u16</span><span class="o">></span><span class="p">,</span>
<span class="n">tovalh</span><span class="p">:</span> <span class="n">Volatile</span><span class="o"><</span><span class="nb">u16</span><span class="o">></span><span class="p">,</span>
<span class="n">tovall</span><span class="p">:</span> <span class="n">Volatile</span><span class="o"><</span><span class="nb">u16</span><span class="o">></span><span class="p">,</span>
<span class="n">winh</span><span class="p">:</span> <span class="n">Volatile</span><span class="o"><</span><span class="nb">u16</span><span class="o">></span><span class="p">,</span>
<span class="n">winl</span><span class="p">:</span> <span class="n">Volatile</span><span class="o"><</span><span class="nb">u16</span><span class="o">></span><span class="p">,</span>
<span class="n">refresh</span><span class="p">:</span> <span class="n">Volatile</span><span class="o"><</span><span class="nb">u16</span><span class="o">></span><span class="p">,</span>
<span class="n">unlock</span><span class="p">:</span> <span class="n">Volatile</span><span class="o"><</span><span class="nb">u16</span><span class="o">></span><span class="p">,</span>
<span class="n">tmrouth</span><span class="p">:</span> <span class="n">Volatile</span><span class="o"><</span><span class="nb">u16</span><span class="o">></span><span class="p">,</span>
<span class="n">tmroutl</span><span class="p">:</span> <span class="n">Volatile</span><span class="o"><</span><span class="nb">u16</span><span class="o">></span><span class="p">,</span>
<span class="n">rstcnt</span><span class="p">:</span> <span class="n">Volatile</span><span class="o"><</span><span class="nb">u16</span><span class="o">></span><span class="p">,</span>
<span class="n">presc</span><span class="p">:</span> <span class="n">Volatile</span><span class="o"><</span><span class="nb">u16</span><span class="o">></span>
<span class="p">}</span>
<span class="k">impl</span> <span class="n">Watchdog</span> <span class="p">{</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="k">-></span> <span class="o">&</span><span class="nv">'static</span> <span class="k">mut</span> <span class="n">Watchdog</span> <span class="p">{</span>
<span class="o">&</span><span class="k">mut</span> <span class="o">*</span><span class="p">(</span><span class="mi">0x40052000</span> <span class="k">as</span> <span class="o">*</span><span class="k">mut</span> <span class="n">Watchdog</span><span class="p">)</span>
<span class="p">}</span>
<span class="k">pub</span> <span class="k">fn</span> <span class="nf">disable</span><span class="p">(</span><span class="o">&</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="k">self</span><span class="py">.unlock</span><span class="nf">.write</span><span class="p">(</span><span class="mi">0xC520</span><span class="p">);</span>
<span class="k">self</span><span class="py">.unlock</span><span class="nf">.write</span><span class="p">(</span><span class="mi">0xD928</span><span class="p">);</span>
<span class="nf">__NOP</span><span class="p">();</span>
<span class="nf">__NOP</span><span class="p">();</span>
<span class="k">self</span><span class="py">.stctrlh</span><span class="nf">.update</span><span class="p">(|</span><span class="n">ctrl</span><span class="p">|</span> <span class="p">{</span>
<span class="n">ctrl</span><span class="nf">.set_bit</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="k">false</span><span class="p">);</span>
<span class="p">});</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span></code></pre></figure>
<p>All of the struct fields are now <code class="highlighter-rouge">Volatile</code>. This type is always the
same size as the integer it wraps, so it can be dropped in like this
without requiring any changes to our struct layout. The <code class="highlighter-rouge">new</code> function
is unchanged, and is still unafe. Most of the change comes in the
<code class="highlighter-rouge">disable</code> method.</p>
<p>Even though updating these <code class="highlighter-rouge">Volatile</code> values is no longer unsafe, we
still need to keep this function marked as <code class="highlighter-rouge">unsafe</code>. Rust considers
certain interactions with packed structs to be <code class="highlighter-rouge">unsafe</code> since they can
violate platform alignment constraints. This should never happen when
doing register accesses like this, but unfortunately the compiler does
not know that.</p>
<h3 id="other-structs">Other Structs</h3>
<p>The changes to the SIM are very similar to those for the watchdog -
switching to <code class="highlighter-rouge">update</code> and <code class="highlighter-rouge">set_bit</code>, instead of raw volatile
operations and bit manipulations. The Port and Gpio structs have some
special considerations:</p>
<ul>
<li>
<p>Since <code class="highlighter-rouge">Port::set_pin_mode</code> can affect other objects (Pin or Gpio
instances) it needs to stay unsafe, even though it now only uses
safe functions.</p>
</li>
<li>
<p>The GPIO methods all still need unsafe blocks to deal with the raw
pointer to the GPIO struct.</p>
</li>
</ul>
<p>Both of these are fine, though - we’re actually doing weird things
with memory in the Port and Gpio structs, so they <em>should</em> be flagged
as unsafe. Now that we aren’t forced to use unsafe for all register
accesses, it becomes more obvious that this code requires special
care.</p>
<p>All of these changes can be seen [on github][branan].</p>
<h2 id="a-more-stable-clock">A more stable clock</h2>
<p>When the MK20DX256 boots, it runs off of an internal reference
clock. This is more than fast enough for our needs - The processor
runs somewhere between 20MHz and 25MHz - but it is not accurate
enough. In order to connect to another device over a serial interface,
we need a clock error below about 3%.</p>
<p>Fortunately, the Teensy is equipped with an accurate 16MHz crystal
oscillator. We will use this crystal as a reference to establish a
very stable 72MHz frequency for the MCU.</p>
<p>If you’re using a Teensy 3.6, you’re on your own here - the clock
generator in the MK66FX1M0 chip has very different parameters than the
one in the earlier chips. If you’re well-versed in reading data
sheets, you should be able to sort out the differences. Feel free to
email me if you need help here.</p>
<p>If you’re using a Teensy 3.0, the maximum rated clock speed is
slower. You’ll need to update some of the parameters used to stay
within the manufacturer’s rated speeds, but the overall register
layout is the same.</p>
<h3 id="clock-modes">Clock Modes</h3>
<p>There are a number of modes that the MK20DX256’s clock system can be
in. They control which basic oscillator (the very accurate external
crystal or a less-accurate internal reference) is used, and how that
reference is multiplied to produce the final clock speed.</p>
<p>The procesor starts in FEI mode - “FLL enabled, internal
(reference)”. This means that the clock is generated by the “Frequency
Locked Loop”, based on the internal 32KHz reference. Our goal is to
transition the clock generator to “PEE” mode, which means the clock is
generated by the “Phase Locked Loop”, based on the external 16MHz
crystal reference. The difference between frequency- and
phase-locked-loops is outside the scope of this post, but in general a
PLL creates a more stable output frequency.</p>
<p>From FEI mode, we will transition the processor through FBE and PBE
modes, before arriving in PEE mode. We will rely on Rust’s type system
to ensure that our transitions between these modes are safe and
correct.</p>
<h3 id="the-clock-registers">The Clock Registers.</h3>
<p>Before we dive into the clock’s state machine, we’ll look at the basic
clock registers. Like all the other functional units of the MK20DX256,
the MCG (Multipurpose Clock Generator) is represented by a block of
registers at a known address:</p>
<figure class="highlight"><pre><code class="language-rust" data-lang="rust"><span class="k">use</span> <span class="nn">volatile</span><span class="p">::</span><span class="n">Volatile</span><span class="p">;</span>
<span class="k">use</span> <span class="nn">bit_field</span><span class="p">::</span><span class="n">BitField</span><span class="p">;</span>
<span class="nd">#[repr(C,packed)]</span>
<span class="k">pub</span> <span class="k">struct</span> <span class="n">Mcg</span> <span class="p">{</span>
<span class="n">c1</span><span class="p">:</span> <span class="n">Volatile</span><span class="o"><</span><span class="nb">u8</span><span class="o">></span><span class="p">,</span>
<span class="n">c2</span><span class="p">:</span> <span class="n">Volatile</span><span class="o"><</span><span class="nb">u8</span><span class="o">></span><span class="p">,</span>
<span class="n">c3</span><span class="p">:</span> <span class="n">Volatile</span><span class="o"><</span><span class="nb">u8</span><span class="o">></span><span class="p">,</span>
<span class="n">c4</span><span class="p">:</span> <span class="n">Volatile</span><span class="o"><</span><span class="nb">u8</span><span class="o">></span><span class="p">,</span>
<span class="n">c5</span><span class="p">:</span> <span class="n">Volatile</span><span class="o"><</span><span class="nb">u8</span><span class="o">></span><span class="p">,</span>
<span class="n">c6</span><span class="p">:</span> <span class="n">Volatile</span><span class="o"><</span><span class="nb">u8</span><span class="o">></span><span class="p">,</span>
<span class="n">s</span><span class="p">:</span> <span class="n">Volatile</span><span class="o"><</span><span class="nb">u8</span><span class="o">></span><span class="p">,</span>
<span class="n">_pad0</span><span class="p">:</span> <span class="nb">u8</span><span class="p">,</span>
<span class="n">sc</span><span class="p">:</span> <span class="n">Volatile</span><span class="o"><</span><span class="nb">u8</span><span class="o">></span><span class="p">,</span>
<span class="n">_pad1</span><span class="p">:</span> <span class="nb">u8</span><span class="p">,</span>
<span class="n">atcvh</span><span class="p">:</span> <span class="n">Volatile</span><span class="o"><</span><span class="nb">u8</span><span class="o">></span><span class="p">,</span>
<span class="n">atcvl</span><span class="p">:</span> <span class="n">Volatile</span><span class="o"><</span><span class="nb">u8</span><span class="o">></span><span class="p">,</span>
<span class="n">c7</span><span class="p">:</span> <span class="n">Volatile</span><span class="o"><</span><span class="nb">u8</span><span class="o">></span><span class="p">,</span>
<span class="n">c8</span><span class="p">:</span> <span class="n">Volatile</span><span class="o"><</span><span class="nb">u8</span><span class="o">></span><span class="p">,</span>
<span class="p">}</span>
<span class="k">impl</span> <span class="n">Mcg</span> <span class="p">{</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="k">-></span> <span class="o">&</span><span class="nv">'static</span> <span class="k">mut</span> <span class="n">Mcg</span> <span class="p">{</span>
<span class="o">&</span><span class="k">mut</span> <span class="o">*</span><span class="p">(</span><span class="mi">0x40064000</span> <span class="k">as</span> <span class="o">*</span><span class="k">mut</span> <span class="n">Mcg</span><span class="p">)</span>
<span class="p">}</span>
<span class="p">}</span></code></pre></figure>
<p>This is the familiar pattern of defining the memory layout as a packed
struct, with our <code class="highlighter-rouge">new</code> method being an unsafe way to create that
struct at the appropriate hardware address for these registers.</p>
<h3 id="the-clock-state-machine">The Clock State Machine</h3>
<p>Each of the clock mode transitions represents small modifications to
the MCG - typically just a few bits changed in a
register. Unfortunately, the set of valid modifications changes with
the mode. Invalid modifications can cause the processor itself to fail
in unexpected ways (all CPUs rely on a stable clock, after all). We
<em>could</em> just rely on ourselves to only program the MCG properly, but
we would be better served by building tools to ensure we do it safely
and correctly.</p>
<p>We’ll start by defining each of our possible states as a struct
holding a mutable reference to the MCG. Each of these structs will
have methods impl’d on them that allow only the changes to the MCG
which are safe in that state. There is no struct for PEE mode, since
we have no need to modify the MCG at that point. A more complete
impmlementation would include PEE mode, as well as the other states
that we aren’t using.</p>
<figure class="highlight"><pre><code class="language-rust" data-lang="rust"><span class="k">pub</span> <span class="k">struct</span> <span class="n">Fei</span> <span class="p">{</span>
<span class="n">mcg</span><span class="p">:</span> <span class="o">&</span><span class="nv">'static</span> <span class="k">mut</span> <span class="n">Mcg</span>
<span class="p">}</span>
<span class="k">pub</span> <span class="k">struct</span> <span class="n">Fbe</span> <span class="p">{</span>
<span class="n">mcg</span><span class="p">:</span> <span class="o">&</span><span class="nv">'static</span> <span class="k">mut</span> <span class="n">Mcg</span>
<span class="p">}</span>
<span class="k">pub</span> <span class="k">struct</span> <span class="n">Pbe</span> <span class="p">{</span>
<span class="n">mcg</span><span class="p">:</span> <span class="o">&</span><span class="nv">'static</span> <span class="k">mut</span> <span class="n">Mcg</span>
<span class="p">}</span></code></pre></figure>
<p>Now, for each struct, we will need to define the functions that
transition the clock to the next state. We will start with the FEI to
FBE transition. For this, we need to enable the crystal oscillator,
and then switch our output to it. This second operation will also
consume the Fei instance, returning an Fbe instance. This represents
the transition of the MCG from using the FLL based on the internal
reference (FEI mode), to being clocked directly from the external
crystal (FBE mode).</p>
<p>Even though we’re transitioning away from using the FLL, we want to be
sure that we continue to operate it within its normal parameters. This
is why we must pass in a clock divider for it - our 16MHz crystal is
far too fast to be used as a reference for the FLL without this
divider. Making sure that we do things right will also make it easier
to expand this code to support FEE and other modes in the future.</p>
<p>In both functions, we must wait for our changes to take effect before
we continue. We read the status register in a loop until the MCG
reports that it is in the expected state.</p>
<figure class="highlight"><pre><code class="language-rust" data-lang="rust"><span class="k">pub</span> <span class="k">enum</span> <span class="n">OscRange</span> <span class="p">{</span>
<span class="n">Low</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span>
<span class="n">High</span> <span class="o">=</span> <span class="mi">1</span><span class="p">,</span>
<span class="n">VeryHigh</span> <span class="o">=</span> <span class="mi">2</span>
<span class="p">}</span>
<span class="k">enum</span> <span class="n">OscSource</span> <span class="p">{</span>
<span class="n">LockedLoop</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span>
<span class="n">Internal</span> <span class="o">=</span> <span class="mi">1</span><span class="p">,</span>
<span class="n">External</span> <span class="o">=</span> <span class="mi">2</span>
<span class="p">}</span>
<span class="k">impl</span> <span class="n">Fei</span> <span class="p">{</span>
<span class="k">pub</span> <span class="k">fn</span> <span class="nf">enable_xtal</span><span class="p">(</span><span class="o">&</span><span class="k">mut</span> <span class="k">self</span><span class="p">,</span> <span class="n">range</span><span class="p">:</span> <span class="n">OscRange</span><span class="p">)</span> <span class="p">{</span>
<span class="k">self</span><span class="py">.mcg.c2</span><span class="nf">.update</span><span class="p">(|</span><span class="n">c2</span><span class="p">|</span> <span class="p">{</span>
<span class="n">c2</span><span class="nf">.set_bits</span><span class="p">(</span><span class="mi">4</span><span class="o">..</span><span class="mi">6</span><span class="p">,</span> <span class="n">range</span> <span class="k">as</span> <span class="nb">u8</span><span class="p">);</span>
<span class="n">c2</span><span class="nf">.set_bit</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="k">true</span><span class="p">);</span>
<span class="p">});</span>
<span class="c">// Wait for the crystal oscillator to become enabled.</span>
<span class="k">while</span> <span class="o">!</span><span class="k">self</span><span class="py">.mcg.s</span><span class="nf">.read</span><span class="p">()</span><span class="nf">.get_bit</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="p">{}</span>
<span class="p">}</span>
<span class="k">pub</span> <span class="k">fn</span> <span class="nf">use_external</span><span class="p">(</span><span class="k">self</span><span class="p">,</span> <span class="n">divide</span><span class="p">:</span> <span class="nb">u32</span><span class="p">)</span> <span class="k">-></span> <span class="n">Fbe</span> <span class="p">{</span>
<span class="k">let</span> <span class="n">osc</span> <span class="o">=</span> <span class="k">self</span><span class="py">.mcg.c2</span><span class="nf">.read</span><span class="p">()</span><span class="nf">.get_bits</span><span class="p">(</span><span class="mi">4</span><span class="o">..</span><span class="mi">6</span><span class="p">);</span>
<span class="k">let</span> <span class="n">frdiv</span> <span class="o">=</span> <span class="k">if</span> <span class="n">osc</span> <span class="o">==</span> <span class="nn">OscRange</span><span class="p">::</span><span class="n">Low</span> <span class="k">as</span> <span class="nb">u8</span> <span class="p">{</span>
<span class="k">match</span> <span class="n">divide</span> <span class="p">{</span>
<span class="mi">1</span> <span class="k">=></span> <span class="mi">0</span><span class="p">,</span>
<span class="mi">2</span> <span class="k">=></span> <span class="mi">1</span><span class="p">,</span>
<span class="mi">4</span> <span class="k">=></span> <span class="mi">2</span><span class="p">,</span>
<span class="mi">8</span> <span class="k">=></span> <span class="mi">3</span><span class="p">,</span>
<span class="mi">16</span> <span class="k">=></span> <span class="mi">4</span><span class="p">,</span>
<span class="mi">32</span> <span class="k">=></span> <span class="mi">5</span><span class="p">,</span>
<span class="mi">64</span> <span class="k">=></span> <span class="mi">6</span><span class="p">,</span>
<span class="mi">128</span> <span class="k">=></span> <span class="mi">7</span><span class="p">,</span>
<span class="n">_</span> <span class="k">=></span> <span class="nd">panic!</span><span class="p">(</span><span class="s">"Invalid external clock divider: {}"</span><span class="p">,</span> <span class="n">divide</span><span class="p">)</span>
<span class="p">}</span>
<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
<span class="k">match</span> <span class="n">divide</span> <span class="p">{</span>
<span class="mi">32</span> <span class="k">=></span> <span class="mi">0</span><span class="p">,</span>
<span class="mi">64</span> <span class="k">=></span> <span class="mi">1</span><span class="p">,</span>
<span class="mi">128</span> <span class="k">=></span> <span class="mi">2</span><span class="p">,</span>
<span class="mi">256</span> <span class="k">=></span> <span class="mi">3</span><span class="p">,</span>
<span class="mi">512</span> <span class="k">=></span> <span class="mi">4</span><span class="p">,</span>
<span class="mi">1024</span> <span class="k">=></span> <span class="mi">5</span><span class="p">,</span>
<span class="mi">1280</span> <span class="k">=></span> <span class="mi">6</span><span class="p">,</span>
<span class="mi">1536</span> <span class="k">=></span> <span class="mi">7</span><span class="p">,</span>
<span class="n">_</span> <span class="k">=></span> <span class="nd">panic!</span><span class="p">(</span><span class="s">"Invalid external clock divider: {}"</span><span class="p">,</span> <span class="n">divide</span><span class="p">)</span>
<span class="p">}</span>
<span class="p">};</span>
<span class="k">self</span><span class="py">.mcg.c1</span><span class="nf">.update</span><span class="p">(|</span><span class="n">c1</span><span class="p">|</span> <span class="p">{</span>
<span class="n">c1</span><span class="nf">.set_bits</span><span class="p">(</span><span class="mi">6</span><span class="o">..</span><span class="mi">8</span><span class="p">,</span> <span class="nn">OscSource</span><span class="p">::</span><span class="n">External</span> <span class="k">as</span> <span class="nb">u8</span><span class="p">);</span>
<span class="n">c1</span><span class="nf">.set_bits</span><span class="p">(</span><span class="mi">3</span><span class="o">..</span><span class="mi">6</span><span class="p">,</span> <span class="n">frdiv</span><span class="p">);</span>
<span class="n">c1</span><span class="nf">.set_bit</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="k">false</span><span class="p">);</span>
<span class="p">});</span>
<span class="c">// Once we write to the control register, we need to wait for</span>
<span class="c">// the new clock to stabilize before we move on.</span>
<span class="c">// First: Wait for the FLL to be pointed at the crystal</span>
<span class="c">// Then: Wait for our clock source to be the crystal osc</span>
<span class="k">while</span> <span class="k">self</span><span class="py">.mcg.s</span><span class="nf">.read</span><span class="p">()</span><span class="nf">.get_bit</span><span class="p">(</span><span class="mi">4</span><span class="p">)</span> <span class="p">{}</span>
<span class="k">while</span> <span class="k">self</span><span class="py">.mcg.s</span><span class="nf">.read</span><span class="p">()</span><span class="nf">.get_bits</span><span class="p">(</span><span class="mi">2</span><span class="o">..</span><span class="mi">4</span><span class="p">)</span> <span class="o">!=</span> <span class="nn">OscSource</span><span class="p">::</span><span class="n">External</span> <span class="k">as</span> <span class="nb">u8</span> <span class="p">{}</span>
<span class="n">Fbe</span> <span class="p">{</span> <span class="n">mcg</span><span class="p">:</span> <span class="k">self</span><span class="py">.mcg</span> <span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span></code></pre></figure>
<p>From FBE mode, we transition to PBE mode by enabling the PLL. This
will be done as a single function, which takes the PLL divider
parameters. Our output frequency will be the crystal frequency
(16MHz) multiplied by the fraction numerator/denominator.</p>
<figure class="highlight"><pre><code class="language-rust" data-lang="rust"><span class="k">impl</span> <span class="n">Fbe</span> <span class="p">{</span>
<span class="k">pub</span> <span class="k">fn</span> <span class="nf">enable_pll</span><span class="p">(</span><span class="k">self</span><span class="p">,</span> <span class="n">numerator</span><span class="p">:</span> <span class="nb">u8</span><span class="p">,</span> <span class="n">denominator</span><span class="p">:</span> <span class="nb">u8</span><span class="p">)</span> <span class="k">-></span> <span class="n">Pbe</span> <span class="p">{</span>
<span class="k">if</span> <span class="n">numerator</span> <span class="o"><</span> <span class="mi">24</span> <span class="p">||</span> <span class="n">numerator</span> <span class="o">></span> <span class="mi">55</span> <span class="p">{</span>
<span class="nd">panic!</span><span class="p">(</span><span class="s">"Invalid PLL VCO divide factor: {}"</span><span class="p">,</span> <span class="n">numerator</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">if</span> <span class="n">denominator</span> <span class="o"><</span> <span class="mi">1</span> <span class="p">||</span> <span class="n">denominator</span> <span class="o">></span> <span class="mi">25</span> <span class="p">{</span>
<span class="nd">panic!</span><span class="p">(</span><span class="s">"Invalid PLL reference divide factor: {}"</span><span class="p">,</span> <span class="n">denominator</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">self</span><span class="py">.mcg.c5</span><span class="nf">.update</span><span class="p">(|</span><span class="n">c5</span><span class="p">|</span> <span class="p">{</span>
<span class="n">c5</span><span class="nf">.set_bits</span><span class="p">(</span><span class="mi">0</span><span class="o">..</span><span class="mi">5</span><span class="p">,</span> <span class="n">denominator</span> <span class="err">-</span> <span class="mi">1</span><span class="p">);</span>
<span class="p">});</span>
<span class="k">self</span><span class="py">.mcg.c6</span><span class="nf">.update</span><span class="p">(|</span><span class="n">c6</span><span class="p">|</span> <span class="p">{</span>
<span class="n">c6</span><span class="nf">.set_bits</span><span class="p">(</span><span class="mi">0</span><span class="o">..</span><span class="mi">5</span><span class="p">,</span> <span class="n">numerator</span> <span class="err">-</span> <span class="mi">24</span><span class="p">);</span>
<span class="n">c6</span><span class="nf">.set_bit</span><span class="p">(</span><span class="mi">6</span><span class="p">,</span> <span class="k">true</span><span class="p">);</span>
<span class="p">});</span>
<span class="c">// Wait for PLL to be enabled</span>
<span class="k">while</span> <span class="o">!</span><span class="k">self</span><span class="py">.mcg.s</span><span class="nf">.read</span><span class="p">()</span><span class="nf">.get_bit</span><span class="p">(</span><span class="mi">5</span><span class="p">)</span> <span class="p">{}</span>
<span class="c">// Wait for the PLL to be "locked" and stable</span>
<span class="k">while</span> <span class="o">!</span><span class="k">self</span><span class="py">.mcg.s</span><span class="nf">.read</span><span class="p">()</span><span class="nf">.get_bit</span><span class="p">(</span><span class="mi">6</span><span class="p">)</span> <span class="p">{}</span>
<span class="n">Pbe</span> <span class="p">{</span> <span class="n">mcg</span><span class="p">:</span> <span class="k">self</span><span class="py">.mcg</span> <span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span></code></pre></figure>
<p>This gets us to PBE mode, or “PLL Bypassed, based on the External
oscillator”. The PLL will be running at our desired frequency here,
but not selected as the main clock source. The last step is to engage
the PLL, making it our actual clock source. There’s a little bit of
weirdness in our wait loop here, due to how the MCG reports which of
the FLL or PLL is in use.</p>
<p>This function consumes the Pbe instance, but does not return
anything. This is because we are “done” with clock setup here. If you
wanted to potentially transition out of PEE mode, you would return
some sort of value here to allow continued modification of the clock
state.</p>
<figure class="highlight"><pre><code class="language-rust" data-lang="rust"><span class="k">impl</span> <span class="n">Pbe</span> <span class="p">{</span>
<span class="k">pub</span> <span class="k">fn</span> <span class="nf">use_pll</span><span class="p">(</span><span class="k">self</span><span class="p">)</span> <span class="p">{</span>
<span class="k">self</span><span class="py">.mcg.c1</span><span class="nf">.update</span><span class="p">(|</span><span class="n">c1</span><span class="p">|</span> <span class="p">{</span>
<span class="n">c1</span><span class="nf">.set_bits</span><span class="p">(</span><span class="mi">6</span><span class="o">..</span><span class="mi">8</span><span class="p">,</span> <span class="nn">OscSource</span><span class="p">::</span><span class="n">LockedLoop</span> <span class="k">as</span> <span class="nb">u8</span><span class="p">);</span>
<span class="p">});</span>
<span class="c">// mcg.c1 and mcg.s have slightly different behaviors. In c1,</span>
<span class="c">// we use one value to indicate "Use whichever LL is</span>
<span class="c">// enabled". In s, it is differentiated between the FLL at 0,</span>
<span class="c">// and the PLL at 3. Instead of adding a value to OscSource</span>
<span class="c">// which would be invalid to set, we just check for the known</span>
<span class="c">// value "3" here.</span>
<span class="k">while</span> <span class="k">self</span><span class="py">.mcg.s</span><span class="nf">.read</span><span class="p">()</span><span class="nf">.get_bits</span><span class="p">(</span><span class="mi">2</span><span class="o">..</span><span class="mi">4</span><span class="p">)</span> <span class="o">!=</span> <span class="mi">3</span> <span class="p">{}</span>
<span class="p">}</span>
<span class="p">}</span></code></pre></figure>
<p>That’s it for the clock mode transitions! When we update main, we’ll
work through each of these clock modes, starting from FEI, to move the
MCG to the state we want it in. At each step, we know that we can only
make the modifications that are safe.</p>
<p>The last part of clock setup is getting our initial Fei instance from
the MCG. The MCG, however, doesn’t know that it’s in FEI mode. We need
to query the various control registers to determine which state it is
actually in, and return the appropriate struct. For the purposes of
this blog post, we’ll panic if the clock is in an unknown state. In
production code, you’d want to implement the full set of clock states
so that this function would always return a valid value.</p>
<figure class="highlight"><pre><code class="language-rust" data-lang="rust"><span class="k">pub</span> <span class="k">enum</span> <span class="n">Clock</span> <span class="p">{</span>
<span class="nf">Fei</span><span class="p">(</span><span class="n">Fei</span><span class="p">),</span>
<span class="nf">Fbe</span><span class="p">(</span><span class="n">Fbe</span><span class="p">),</span>
<span class="nf">Pbe</span><span class="p">(</span><span class="n">Pbe</span><span class="p">)</span>
<span class="p">}</span>
<span class="k">impl</span> <span class="n">mcg</span> <span class="p">{</span>
<span class="k">pub</span> <span class="k">fn</span> <span class="nf">clock</span><span class="p">(</span><span class="o">&</span><span class="nv">'static</span> <span class="k">mut</span> <span class="k">self</span><span class="p">)</span> <span class="k">-></span> <span class="n">Clock</span> <span class="p">{</span>
<span class="k">let</span> <span class="n">source</span><span class="p">:</span> <span class="n">OscSource</span> <span class="o">=</span> <span class="k">unsafe</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">self</span><span class="py">.c1</span><span class="nf">.read</span><span class="p">()</span><span class="nf">.get_bits</span><span class="p">(</span><span class="mi">6</span><span class="o">..</span><span class="mi">8</span><span class="p">))</span>
<span class="p">};</span>
<span class="k">let</span> <span class="n">fll_internal</span> <span class="o">=</span> <span class="k">self</span><span class="py">.c1</span><span class="nf">.read</span><span class="p">()</span><span class="nf">.get_bit</span><span class="p">(</span><span class="mi">2</span><span class="p">);</span>
<span class="k">let</span> <span class="n">pll_enabled</span> <span class="o">=</span> <span class="k">self</span><span class="py">.c6</span><span class="nf">.read</span><span class="p">()</span><span class="nf">.get_bit</span><span class="p">(</span><span class="mi">6</span><span class="p">);</span>
<span class="k">match</span> <span class="p">(</span><span class="n">fll_internal</span><span class="p">,</span> <span class="n">pll_enabled</span><span class="p">,</span> <span class="n">source</span><span class="p">)</span> <span class="p">{</span>
<span class="p">(</span><span class="k">true</span><span class="p">,</span> <span class="k">false</span><span class="p">,</span> <span class="nn">OscSource</span><span class="p">::</span><span class="n">LockedLoop</span><span class="p">)</span> <span class="k">=></span> <span class="nn">Clock</span><span class="p">::</span><span class="nf">Fei</span><span class="p">(</span><span class="n">Fei</span><span class="p">{</span> <span class="n">mcg</span><span class="p">:</span> <span class="k">self</span> <span class="p">}),</span>
<span class="p">(</span><span class="k">false</span><span class="p">,</span> <span class="k">false</span><span class="p">,</span> <span class="nn">OscSource</span><span class="p">::</span><span class="n">External</span><span class="p">)</span> <span class="k">=></span> <span class="nn">Clock</span><span class="p">::</span><span class="nf">Fbe</span><span class="p">(</span><span class="n">Fbe</span><span class="p">{</span> <span class="n">mcg</span><span class="p">:</span> <span class="k">self</span> <span class="p">}),</span>
<span class="p">(</span><span class="n">_</span><span class="p">,</span> <span class="k">true</span><span class="p">,</span> <span class="nn">OscSource</span><span class="p">::</span><span class="n">External</span><span class="p">)</span> <span class="k">=></span> <span class="nn">Clock</span><span class="p">::</span><span class="nf">Pbe</span><span class="p">(</span><span class="n">Pbe</span><span class="p">{</span> <span class="n">mcg</span><span class="p">:</span> <span class="k">self</span> <span class="p">}),</span>
<span class="n">_</span> <span class="k">=></span> <span class="nd">panic!</span><span class="p">(</span><span class="s">"The current clock mode cannot be represented as a known struct"</span><span class="p">)</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span></code></pre></figure>
<p>There is a bit of unsafety here, to coerce the oscillator selection
field to our enum type. We otherwise are simply comparing the set of
control registers to the expected values for each known mode.</p>
<h3 id="the-oscillator-unit">The Oscillator Unit</h3>
<p>I wasn’t entirely truthful when I said we were “enableing the crystal”
earlier. What we actually did was select the crystal as the clock
source for the PLL. The crystal oscillator itself needs to be enabled
and configured through its own set of registers. We’ll put the code
for this in a file called <code class="highlighter-rouge">osc.rs</code>.</p>
<figure class="highlight"><pre><code class="language-rust" data-lang="rust"><span class="k">use</span> <span class="nn">volatile</span><span class="p">::</span><span class="n">Volatile</span><span class="p">;</span>
<span class="k">use</span> <span class="nn">bit_field</span><span class="p">::</span><span class="n">BitField</span><span class="p">;</span>
<span class="k">pub</span> <span class="k">struct</span> <span class="n">Osc</span> <span class="p">{</span>
<span class="n">cr</span><span class="p">:</span> <span class="n">Volatile</span><span class="o"><</span><span class="nb">u8</span><span class="o">></span>
<span class="p">}</span>
<span class="k">impl</span> <span class="n">Osc</span> <span class="p">{</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="k">-></span> <span class="o">&</span><span class="nv">'static</span> <span class="k">mut</span> <span class="n">Osc</span> <span class="p">{</span>
<span class="o">&</span><span class="k">mut</span> <span class="o">*</span><span class="p">(</span><span class="mi">0x40065000</span> <span class="k">as</span> <span class="o">*</span><span class="k">mut</span> <span class="n">Osc</span><span class="p">)</span>
<span class="p">}</span>
<span class="k">pub</span> <span class="k">fn</span> <span class="nf">enable</span><span class="p">(</span><span class="o">&</span><span class="k">mut</span> <span class="k">self</span><span class="p">,</span> <span class="n">capacitance</span><span class="p">:</span> <span class="nb">u8</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span> <span class="n">capacitance</span> <span class="o">%</span> <span class="mi">2</span> <span class="o">==</span> <span class="mi">1</span> <span class="p">||</span> <span class="n">capacitance</span> <span class="o">></span> <span class="mi">30</span> <span class="p">{</span>
<span class="nd">panic!</span><span class="p">(</span><span class="s">"Invalid crystal capacitance value: {}"</span><span class="p">,</span> <span class="n">capacitance</span><span class="p">)</span>
<span class="p">}</span>
<span class="k">let</span> <span class="k">mut</span> <span class="n">cr</span><span class="p">:</span> <span class="nb">u8</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="c">// The capacitance control bits are backwards, and start at 2pf</span>
<span class="c">// We swizzle them all here</span>
<span class="n">cr</span><span class="nf">.set_bit</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="n">capacitance</span><span class="nf">.get_bit</span><span class="p">(</span><span class="mi">1</span><span class="p">));</span>
<span class="n">cr</span><span class="nf">.set_bit</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="n">capacitance</span><span class="nf">.get_bit</span><span class="p">(</span><span class="mi">2</span><span class="p">));</span>
<span class="n">cr</span><span class="nf">.set_bit</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="n">capacitance</span><span class="nf">.get_bit</span><span class="p">(</span><span class="mi">3</span><span class="p">));</span>
<span class="n">cr</span><span class="nf">.set_bit</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">capacitance</span><span class="nf">.get_bit</span><span class="p">(</span><span class="mi">4</span><span class="p">));</span>
<span class="c">// enable the crystal oscillator</span>
<span class="n">cr</span><span class="nf">.set_bit</span><span class="p">(</span><span class="mi">7</span><span class="p">,</span> <span class="k">true</span><span class="p">);</span>
<span class="k">self</span><span class="py">.cr</span><span class="nf">.write</span><span class="p">(</span><span class="n">cr</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span></code></pre></figure>
<p>The oscillator is very simple compared to some of the functional units
we’ve had to deal with. Most of the body of this function is setting
the capacitive load for the crystal (between 2pf and 30pf). It also
sets the enable bit, to turn on the oscillator.</p>
<h3 id="putting-it-together--updating-main">Putting it Together & Updating main</h3>
<p>We’ve created two new files for managing two new functional units of
the MCU: the MCG and the OSC. The OSC has a single function to enable
the unit, and set the capacitance needed for the external crystal. The
MCG has a series of structs that define a state machine for bringing
the clock machinery to the correct mode. We’ll update main to take
advantage of these. At the end we still just turn on the LED, but in
between we now set up the clock machinery to run the MCU at its rated
72MHz.</p>
<figure class="highlight"><pre><code class="language-rust" data-lang="rust"><span class="k">extern</span> <span class="k">fn</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
<span class="k">let</span> <span class="p">(</span><span class="n">wdog</span><span class="p">,</span><span class="n">sim</span><span class="p">,</span><span class="n">mcg</span><span class="p">,</span><span class="n">osc</span><span class="p">,</span><span class="n">pin</span><span class="p">)</span> <span class="o">=</span> <span class="k">unsafe</span> <span class="p">{</span>
<span class="p">(</span><span class="nn">watchdog</span><span class="p">::</span><span class="nn">Watchdog</span><span class="p">::</span><span class="nf">new</span><span class="p">(),</span>
<span class="nn">sim</span><span class="p">::</span><span class="nn">Sim</span><span class="p">::</span><span class="nf">new</span><span class="p">(),</span>
<span class="nn">mcg</span><span class="p">::</span><span class="nn">Mcg</span><span class="p">::</span><span class="nf">new</span><span class="p">(),</span>
<span class="nn">osc</span><span class="p">::</span><span class="nn">Osc</span><span class="p">::</span><span class="nf">new</span><span class="p">(),</span>
<span class="nn">port</span><span class="p">::</span><span class="nn">Port</span><span class="p">::</span><span class="nf">new</span><span class="p">(</span><span class="nn">port</span><span class="p">::</span><span class="nn">PortName</span><span class="p">::</span><span class="n">C</span><span class="p">)</span><span class="nf">.pin</span><span class="p">(</span><span class="mi">5</span><span class="p">))</span>
<span class="p">};</span>
<span class="n">wdog</span><span class="nf">.disable</span><span class="p">();</span>
<span class="c">// Enable the crystal oscillator with 10pf of capacitance</span>
<span class="n">osc</span><span class="nf">.enable</span><span class="p">(</span><span class="mi">10</span><span class="p">);</span>
<span class="c">// Turn on the Port C clock gate</span>
<span class="n">sim</span><span class="nf">.enable_clock</span><span class="p">(</span><span class="nn">sim</span><span class="p">::</span><span class="nn">Clock</span><span class="p">::</span><span class="n">PortC</span><span class="p">);</span>
<span class="c">// Set our clocks:</span>
<span class="c">// core: 72Mhz</span>
<span class="c">// peripheral: 36MHz</span>
<span class="c">// flash: 24MHz</span>
<span class="n">sim</span><span class="nf">.set_dividers</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">);</span>
<span class="c">// We would also set the USB divider here if we wanted to use it.</span>
<span class="c">// Now we can start setting up the MCG for our needs.</span>
<span class="k">if</span> <span class="k">let</span> <span class="nn">mcg</span><span class="p">::</span><span class="nn">Clock</span><span class="p">::</span><span class="nf">Fei</span><span class="p">(</span><span class="k">mut</span> <span class="n">fei</span><span class="p">)</span> <span class="o">=</span> <span class="n">mcg</span><span class="nf">.clock</span><span class="p">()</span> <span class="p">{</span>
<span class="c">// Our 16MHz xtal is "very fast", and needs to be divided</span>
<span class="c">// by 512 to be in the acceptable FLL range.</span>
<span class="n">fei</span><span class="nf">.enable_xtal</span><span class="p">(</span><span class="nn">mcg</span><span class="p">::</span><span class="nn">OscRange</span><span class="p">::</span><span class="n">VeryHigh</span><span class="p">);</span>
<span class="k">let</span> <span class="n">fbe</span> <span class="o">=</span> <span class="n">fei</span><span class="nf">.use_external</span><span class="p">(</span><span class="mi">512</span><span class="p">);</span>
<span class="c">// PLL is 27/6 * xtal == 72MHz</span>
<span class="k">let</span> <span class="n">pbe</span> <span class="o">=</span> <span class="n">fbe</span><span class="nf">.enable_pll</span><span class="p">(</span><span class="mi">27</span><span class="p">,</span> <span class="mi">6</span><span class="p">);</span>
<span class="n">pbe</span><span class="nf">.use_pll</span><span class="p">();</span>
<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
<span class="nd">panic!</span><span class="p">(</span><span class="s">"Somehow the clock wasn't in FEI mode"</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">let</span> <span class="k">mut</span> <span class="n">gpio</span> <span class="o">=</span> <span class="n">pin</span><span class="nf">.make_gpio</span><span class="p">();</span>
<span class="n">gpio</span><span class="nf">.output</span><span class="p">();</span>
<span class="n">gpio</span><span class="nf">.high</span><span class="p">();</span>
<span class="k">loop</span> <span class="p">{}</span>
<span class="p">}</span></code></pre></figure>
<p>This looks a lot more complicated, but is really only a few
changes. From the top:</p>
<ul>
<li>We add the OSC and MCG to the list functional units we want
references for.</li>
<li>After the watchdog is disabled, we enable the external oscillator,
with 10pf of capacitiance. This is the right amount for the cyrstal
on the Teensy. You might need a different number, if you have a
different board.</li>
<li>We set the “clock dividers” of the SIM. More on this below.</li>
<li>If the clock is in FEI mode, we transition it to PEE mode using the
set of functions we defined above. If it’s not in FEI mode we panic,
since it should always been in FEI mode at boot.</li>
</ul>
<p>The only thing we haven’t already covered is the new <code class="highlighter-rouge">set_dividers</code>
method of the SIM. We want to run the main CPU core at 72MHz, but not
all the parts of the chip can run that fast. We need to keep the
peripheral bus below 50MHz, and the Flash below 25MHz. This function
sets up the “clock dividers”, so that we can keep the bus and flash
running at the slower speeds that they are rated for.</p>
<figure class="highlight"><pre><code class="language-rust" data-lang="rust"><span class="k">impl</span> <span class="n">Sim</span>
<span class="k">pub</span> <span class="k">fn</span> <span class="nf">set_dividers</span><span class="p">(</span><span class="o">&</span><span class="k">mut</span> <span class="k">self</span><span class="p">,</span> <span class="n">core</span><span class="p">:</span> <span class="nb">u32</span><span class="p">,</span> <span class="n">bus</span><span class="p">:</span> <span class="nb">u32</span><span class="p">,</span> <span class="n">flash</span><span class="p">:</span> <span class="nb">u32</span><span class="p">)</span> <span class="p">{</span>
<span class="k">let</span> <span class="k">mut</span> <span class="n">clkdiv</span><span class="p">:</span> <span class="nb">u32</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="n">clkdiv</span><span class="nf">.set_bits</span><span class="p">(</span><span class="mi">28</span><span class="o">..</span><span class="mi">32</span><span class="p">,</span> <span class="n">core</span><span class="err">-</span><span class="mi">1</span><span class="p">);</span>
<span class="n">clkdiv</span><span class="nf">.set_bits</span><span class="p">(</span><span class="mi">24</span><span class="o">..</span><span class="mi">28</span><span class="p">,</span> <span class="n">bus</span><span class="err">-</span><span class="mi">1</span><span class="p">);</span>
<span class="n">clkdiv</span><span class="nf">.set_bits</span><span class="p">(</span><span class="mi">16</span><span class="o">..</span><span class="mi">20</span><span class="p">,</span> <span class="n">flash</span><span class="err">-</span><span class="mi">1</span><span class="p">);</span>
<span class="k">self</span><span class="py">.clkdiv1</span><span class="nf">.write</span><span class="p">(</span><span class="n">clkdiv</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span></code></pre></figure>
<h2 id="the-serial-port">The Serial Port</h2>
<p>Now that we have a stable clock, we can move on to configuring the
serial port, or <em>UART</em> (Universal Asynchronous
Reciever/Transmitter). For our needs the UART itself is fairly easy to
program. Most of the challenge here will be in expanding our pin
handling to support serial functionality.</p>
<h3 id="more-about-pins">More About Pins</h3>
<p>When we first set up a GPIO pin, we had a couple of advantages:</p>
<ol>
<li>All pins can act as GPIOs, so we didn’t need any validation logic.</li>
<li>All pins use the same mux value when configured as a GPIO.</li>
</ol>
<p>For the UART, neither of these shortcuts holds. Our setup code will
need to know both which pins can be used for serial communication, and
which mux value will appropriately connect those pins to the UART.</p>
<p>Just as for the GPIO, we will add functions to the Pin struct to
convert a pin to a serial-specific struct.</p>
<figure class="highlight"><pre><code class="language-rust" data-lang="rust"><span class="k">pub</span> <span class="k">struct</span> <span class="nf">Tx</span><span class="p">(</span><span class="nb">u8</span><span class="p">);</span>
<span class="k">pub</span> <span class="k">struct</span> <span class="nf">Rx</span><span class="p">(</span><span class="nb">u8</span><span class="p">);</span>
<span class="k">impl</span> <span class="n">Pin</span> <span class="p">{</span>
<span class="k">pub</span> <span class="k">fn</span> <span class="nf">make_rx</span><span class="p">(</span><span class="k">self</span><span class="p">)</span> <span class="k">-></span> <span class="n">Rx</span> <span class="p">{</span>
<span class="k">unsafe</span> <span class="p">{</span>
<span class="k">let</span> <span class="n">port</span> <span class="o">=</span> <span class="o">&</span><span class="k">mut</span> <span class="o">*</span><span class="k">self</span><span class="py">.port</span><span class="p">;</span>
<span class="k">match</span> <span class="p">(</span><span class="n">port</span><span class="nf">.name</span><span class="p">(),</span> <span class="k">self</span><span class="py">.pin</span><span class="p">)</span> <span class="p">{</span>
<span class="p">(</span><span class="nn">PortName</span><span class="p">::</span><span class="n">B</span><span class="p">,</span> <span class="mi">16</span><span class="p">)</span> <span class="k">=></span> <span class="p">{</span>
<span class="n">port</span><span class="nf">.set_pin_mode</span><span class="p">(</span><span class="k">self</span><span class="py">.pin</span><span class="p">,</span> <span class="mi">3</span><span class="p">);</span>
<span class="nf">Rx</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
<span class="p">},</span>
<span class="n">_</span> <span class="k">=></span> <span class="nd">panic!</span><span class="p">(</span><span class="s">"Invalid serial RX pin"</span><span class="p">)</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="k">pub</span> <span class="k">fn</span> <span class="nf">make_tx</span><span class="p">(</span><span class="k">self</span><span class="p">)</span> <span class="k">-></span> <span class="n">Tx</span> <span class="p">{</span>
<span class="k">unsafe</span> <span class="p">{</span>
<span class="k">let</span> <span class="n">port</span> <span class="o">=</span> <span class="o">&</span><span class="k">mut</span> <span class="o">*</span><span class="k">self</span><span class="py">.port</span><span class="p">;</span>
<span class="k">match</span> <span class="p">(</span><span class="n">port</span><span class="nf">.name</span><span class="p">(),</span> <span class="k">self</span><span class="py">.pin</span><span class="p">)</span> <span class="p">{</span>
<span class="p">(</span><span class="nn">PortName</span><span class="p">::</span><span class="n">B</span><span class="p">,</span> <span class="mi">17</span><span class="p">)</span> <span class="k">=></span> <span class="p">{</span>
<span class="n">port</span><span class="nf">.set_pin_mode</span><span class="p">(</span><span class="k">self</span><span class="py">.pin</span><span class="p">,</span> <span class="mi">3</span><span class="p">);</span>
<span class="nf">Tx</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
<span class="p">},</span>
<span class="n">_</span> <span class="k">=></span> <span class="nd">panic!</span><span class="p">(</span><span class="s">"Invalid serial TX pin"</span><span class="p">)</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span></code></pre></figure>
<p>Each Tx or Rx instance includes which UART it is valid for. We could
choose to encode this in the type system, but that sends us down a
road of a lot of complexity (possibly including separate Structs for
each UART). We still potentially panic when converting an invalid pin
to an Rx or Tx instance, so the tradeoff of avoiding another panic
when passing that pin to the wrong UART doesn’t seem worth it. Your
needs might be different.</p>
<p>This code also reference a new <code class="highlighter-rouge">PortName::B</code>. This is easy to add to
the existing Port and GPIO code. The Port lives at 0x4004A000, and the
GpioBitband is at 0x43FE0800.</p>
<p>We now have the code in place to set up pins B16 and B17 as UART
pins. These map to pins 0 and 1 on the Teensy, the same as <code class="highlighter-rouge">Serial1</code>
when programming the Teensy with the Arduino IDE.</p>
<h3 id="the-uart">The UART</h3>
<p>The UART is our first struct that will require a complex <code class="highlighter-rouge">::new</code>
implementation. In addition to selecting which UART unit we will use,
the method must handle several other parameters:</p>
<ul>
<li>An optional Rx pin, to enable recieve functionality</li>
<li>An optional Tx pin, to enable transmit functinality</li>
<li>The clock divider, as an A,B pair. This is interpreted as <code class="highlighter-rouge">A +
B/32</code>.</li>
</ul>
<p>On the Teensy 3.5 or 3.6, you could choose to use a float for the
third parameter. This would require you to then convert it to the
integers used by the hardware module itself. It’s up to you if this
extra work is worth the simpler interface.</p>
<figure class="highlight"><pre><code class="language-rust" data-lang="rust"><span class="k">use</span> <span class="nn">volatile</span><span class="p">::</span><span class="n">Volatile</span><span class="p">;</span>
<span class="k">use</span> <span class="nn">bit_field</span><span class="p">::</span><span class="n">BitField</span><span class="p">;</span>
<span class="k">use</span> <span class="n">core</span><span class="p">;</span>
<span class="k">use</span> <span class="nn">super</span><span class="p">::</span><span class="nn">port</span><span class="p">::{</span><span class="n">Rx</span><span class="p">,</span><span class="n">Tx</span><span class="p">};</span>
<span class="nd">#[repr(C,packed)]</span>
<span class="k">pub</span> <span class="k">struct</span> <span class="n">Uart</span> <span class="p">{</span>
<span class="n">bdh</span><span class="p">:</span> <span class="n">Volatile</span><span class="o"><</span><span class="nb">u8</span><span class="o">></span><span class="p">,</span>
<span class="n">bdl</span><span class="p">:</span> <span class="n">Volatile</span><span class="o"><</span><span class="nb">u8</span><span class="o">></span><span class="p">,</span>
<span class="n">c1</span><span class="p">:</span> <span class="n">Volatile</span><span class="o"><</span><span class="nb">u8</span><span class="o">></span><span class="p">,</span>
<span class="n">c2</span><span class="p">:</span> <span class="n">Volatile</span><span class="o"><</span><span class="nb">u8</span><span class="o">></span><span class="p">,</span>
<span class="n">s1</span><span class="p">:</span> <span class="n">Volatile</span><span class="o"><</span><span class="nb">u8</span><span class="o">></span><span class="p">,</span>
<span class="n">s2</span><span class="p">:</span> <span class="n">Volatile</span><span class="o"><</span><span class="nb">u8</span><span class="o">></span><span class="p">,</span>
<span class="n">c3</span><span class="p">:</span> <span class="n">Volatile</span><span class="o"><</span><span class="nb">u8</span><span class="o">></span><span class="p">,</span>
<span class="n">d</span><span class="p">:</span> <span class="n">Volatile</span><span class="o"><</span><span class="nb">u8</span><span class="o">></span><span class="p">,</span>
<span class="n">ma1</span><span class="p">:</span> <span class="n">Volatile</span><span class="o"><</span><span class="nb">u8</span><span class="o">></span><span class="p">,</span>
<span class="n">ma2</span><span class="p">:</span> <span class="n">Volatile</span><span class="o"><</span><span class="nb">u8</span><span class="o">></span><span class="p">,</span>
<span class="n">c4</span><span class="p">:</span> <span class="n">Volatile</span><span class="o"><</span><span class="nb">u8</span><span class="o">></span><span class="p">,</span>
<span class="n">c5</span><span class="p">:</span> <span class="n">Volatile</span><span class="o"><</span><span class="nb">u8</span><span class="o">></span><span class="p">,</span>
<span class="n">ed</span><span class="p">:</span> <span class="n">Volatile</span><span class="o"><</span><span class="nb">u8</span><span class="o">></span><span class="p">,</span>
<span class="n">modem</span><span class="p">:</span> <span class="n">Volatile</span><span class="o"><</span><span class="nb">u8</span><span class="o">></span><span class="p">,</span>
<span class="n">ir</span><span class="p">:</span> <span class="n">Volatile</span><span class="o"><</span><span class="nb">u8</span><span class="o">></span><span class="p">,</span>
<span class="p">}</span>
<span class="k">impl</span> <span class="n">Uart</span> <span class="p">{</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">id</span><span class="p">:</span> <span class="nb">u8</span><span class="p">,</span> <span class="n">rx</span><span class="p">:</span> <span class="nb">Option</span><span class="o"><</span><span class="n">Rx</span><span class="o">></span><span class="p">,</span> <span class="n">tx</span><span class="p">:</span> <span class="nb">Option</span><span class="o"><</span><span class="n">Tx</span><span class="o">></span><span class="p">,</span> <span class="n">clkdiv</span><span class="p">:</span> <span class="p">(</span><span class="nb">u16</span><span class="p">,</span><span class="nb">u8</span><span class="p">))</span> <span class="k">-></span> <span class="o">&</span><span class="nv">'static</span> <span class="k">mut</span> <span class="n">Uart</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="n">r</span><span class="p">)</span> <span class="o">=</span> <span class="n">rx</span><span class="nf">.as_ref</span><span class="p">()</span> <span class="p">{</span>
<span class="k">if</span> <span class="n">r</span><span class="nf">.uart</span><span class="p">()</span> <span class="o">!=</span> <span class="n">id</span> <span class="p">{</span>
<span class="nd">panic!</span><span class="p">(</span><span class="s">"Invalid RX pin for UART {}"</span><span class="p">,</span> <span class="n">id</span><span class="p">);</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="n">t</span><span class="p">)</span> <span class="o">=</span> <span class="n">tx</span><span class="nf">.as_ref</span><span class="p">()</span> <span class="p">{</span>
<span class="k">if</span> <span class="n">t</span><span class="nf">.uart</span><span class="p">()</span> <span class="o">!=</span> <span class="n">id</span> <span class="p">{</span>
<span class="nd">panic!</span><span class="p">(</span><span class="s">"Invalid TX pin for UART {}"</span><span class="p">,</span> <span class="n">id</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="k">if</span> <span class="n">clkdiv</span><span class="err">.</span><span class="mi">0</span> <span class="o">>=</span> <span class="mi">8192</span> <span class="p">{</span>
<span class="nd">panic!</span><span class="p">(</span><span class="s">"Invalid UART clock divider: {}"</span><span class="p">,</span> <span class="n">clkdiv</span>.<span class="mi">0</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">if</span> <span class="n">clkdiv</span><span class="err">.</span><span class="mi">1</span> <span class="o">>=</span> <span class="mi">32</span> <span class="p">{</span>
<span class="nd">panic!</span><span class="p">(</span><span class="s">"Invalid UART fractional divisor: {}"</span><span class="p">,</span> <span class="n">clkdiv</span>.<span class="mi">1</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">let</span> <span class="n">uart</span> <span class="o">=</span> <span class="k">match</span> <span class="n">id</span> <span class="p">{</span>
<span class="mi">0</span> <span class="k">=></span> <span class="o">&</span><span class="k">mut</span> <span class="o">*</span><span class="p">(</span><span class="mi">0x4006A000</span> <span class="k">as</span> <span class="o">*</span><span class="k">mut</span> <span class="n">Uart</span><span class="p">),</span>
<span class="n">_</span> <span class="k">=></span> <span class="nd">panic!</span><span class="p">(</span><span class="s">"Invalid UART id: {}"</span><span class="p">,</span> <span class="n">id</span><span class="p">)</span>
<span class="p">};</span>
<span class="n">uart</span><span class="py">.c4</span><span class="nf">.update</span><span class="p">(|</span><span class="n">c4</span><span class="p">|</span> <span class="p">{</span>
<span class="n">c4</span><span class="nf">.set_bits</span><span class="p">(</span><span class="mi">0</span><span class="o">..</span><span class="mi">5</span><span class="p">,</span> <span class="n">clkdiv</span><span class="err">.</span><span class="mi">1</span><span class="p">);</span>
<span class="p">});</span>
<span class="n">uart</span><span class="py">.bdh</span><span class="nf">.update</span><span class="p">(|</span><span class="n">bdh</span><span class="p">|</span> <span class="p">{</span>
<span class="n">bdh</span><span class="nf">.set_bits</span><span class="p">(</span><span class="mi">0</span><span class="o">..</span><span class="mi">5</span><span class="p">,</span> <span class="n">clkdiv</span><span class="err">.</span><span class="mi">0</span><span class="nf">.get_bits</span><span class="p">(</span><span class="mi">8</span><span class="o">..</span><span class="mi">13</span><span class="p">)</span> <span class="k">as</span> <span class="nb">u8</span><span class="p">);</span>
<span class="p">});</span>
<span class="n">uart</span><span class="py">.bdl</span><span class="nf">.write</span><span class="p">(</span><span class="n">clkdiv</span><span class="err">.</span><span class="mi">0</span><span class="nf">.get_bits</span><span class="p">(</span><span class="mi">0</span><span class="o">..</span><span class="mi">8</span><span class="p">)</span> <span class="k">as</span> <span class="nb">u8</span><span class="p">);</span>
<span class="n">uart</span><span class="py">.c2</span><span class="nf">.update</span><span class="p">(|</span><span class="n">c2</span><span class="p">|</span> <span class="p">{</span>
<span class="n">c2</span><span class="nf">.set_bit</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="n">rx</span><span class="nf">.is_some</span><span class="p">());</span>
<span class="n">c2</span><span class="nf">.set_bit</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="n">tx</span><span class="nf">.is_some</span><span class="p">());</span>
<span class="p">});</span>
<span class="n">uart</span>
<span class="p">}</span>
<span class="p">}</span></code></pre></figure>
<p>This starts with validating the parameters: The Rx and Tx pins must be
usable for this UART, and the clock dividers need to be in the
acceptable range. The clock dividers are passed to the
hardware. Lastly, recieve and transmit are enabled if appropriate pins
were passed in, and the Uart reference is returned.</p>
<h3 id="string-output">String Output</h3>
<p>To use the UART as an output device, we will implement the
<code class="highlighter-rouge">core::fmt::Write</code> trait for it. This will enable the <code class="highlighter-rouge">write!</code> macro,
and make it easy to use a UART for output from our panic handler.</p>
<p>Most of the functions in the <code class="highlighter-rouge">Write</code> trait have default
implementations, which we will rely on. The only one we must implement
is <code class="highlighter-rouge">write_str</code>. Our implementation writes each byte of the string in
sequeuence, waiting in between for the hardware to indicate that it is
ready for another byte. Once all the bytes are written, we wait for
the Transmit Complete (TC) flag to be set, indicating that the UART is
finished sending all the data.</p>
<figure class="highlight"><pre><code class="language-rust" data-lang="rust"><span class="k">impl</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="k">for</span> <span class="n">Uart</span> <span class="p">{</span>
<span class="k">fn</span> <span class="nf">write_str</span><span class="p">(</span><span class="o">&</span><span class="k">mut</span> <span class="k">self</span><span class="p">,</span> <span class="n">s</span><span class="p">:</span> <span class="o">&</span><span class="nb">str</span><span class="p">)</span> <span class="k">-></span> <span class="nn">core</span><span class="p">::</span><span class="nn">fmt</span><span class="p">::</span><span class="n">Result</span> <span class="p">{</span>
<span class="k">for</span> <span class="n">b</span> <span class="n">in</span> <span class="n">s</span><span class="nf">.bytes</span><span class="p">()</span> <span class="p">{</span>
<span class="k">while</span> <span class="o">!</span><span class="k">self</span><span class="py">.s1</span><span class="nf">.read</span><span class="p">()</span><span class="nf">.get_bit</span><span class="p">(</span><span class="mi">7</span><span class="p">)</span> <span class="p">{}</span>
<span class="k">self</span><span class="py">.d</span><span class="nf">.write</span><span class="p">(</span><span class="n">b</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">while</span> <span class="o">!</span><span class="k">self</span><span class="py">.s1</span><span class="nf">.read</span><span class="p">()</span><span class="nf">.get_bit</span><span class="p">(</span><span class="mi">6</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></figure>
<h2 id="hello-world">Hello, World!</h2>
<p>Adding serial output to our main is now just a few lines of
code. First, enable the Port B and UART clocks:</p>
<figure class="highlight"><pre><code class="language-rust" data-lang="rust"><span class="n">sim</span><span class="nf">.enable_clock</span><span class="p">(</span><span class="nn">sim</span><span class="p">::</span><span class="nn">Clock</span><span class="p">::</span><span class="n">PortB</span><span class="p">);</span>
<span class="n">sim</span><span class="nf">.enable_clock</span><span class="p">(</span><span class="nn">sim</span><span class="p">::</span><span class="nn">Clock</span><span class="p">::</span><span class="n">Uart0</span><span class="p">);</span></code></pre></figure>
<p>With those clocks enabled, we can grab a uart instance, and write a
message:</p>
<figure class="highlight"><pre><code class="language-rust" data-lang="rust"><span class="k">let</span> <span class="k">mut</span> <span class="n">uart</span> <span class="o">=</span> <span class="k">unsafe</span> <span class="p">{</span>
<span class="k">let</span> <span class="n">rx</span> <span class="o">=</span> <span class="nn">port</span><span class="p">::</span><span class="nn">Port</span><span class="p">::</span><span class="nf">new</span><span class="p">(</span><span class="nn">port</span><span class="p">::</span><span class="nn">PortName</span><span class="p">::</span><span class="n">B</span><span class="p">)</span><span class="nf">.pin</span><span class="p">(</span><span class="mi">16</span><span class="p">)</span><span class="nf">.make_rx</span><span class="p">();</span>
<span class="k">let</span> <span class="n">tx</span> <span class="o">=</span> <span class="nn">port</span><span class="p">::</span><span class="nn">Port</span><span class="p">::</span><span class="nf">new</span><span class="p">(</span><span class="nn">port</span><span class="p">::</span><span class="nn">PortName</span><span class="p">::</span><span class="n">B</span><span class="p">)</span><span class="nf">.pin</span><span class="p">(</span><span class="mi">17</span><span class="p">)</span><span class="nf">.make_tx</span><span class="p">();</span>
<span class="nn">uart</span><span class="p">::</span><span class="nn">Uart</span><span class="p">::</span><span class="nf">new</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="nf">Some</span><span class="p">(</span><span class="n">rx</span><span class="p">),</span> <span class="nf">Some</span><span class="p">(</span><span class="n">tx</span><span class="p">),</span> <span class="p">(</span><span class="mi">468</span><span class="p">,</span> <span class="mi">24</span><span class="p">))</span>
<span class="p">};</span>
<span class="nd">writeln!</span><span class="p">(</span><span class="n">uart</span><span class="p">,</span> <span class="s">"Hello, World"</span><span class="p">)</span><span class="nf">.unwrap</span><span class="p">();</span></code></pre></figure>
<p>This sets the UART clock divider as 468.75 (24/32). The baud rate will
be 72MHz/(16*468.75), or 9600. This is a pretty standard rate, and
will be easy to use with any serial adapter.</p>
<p>Finally, we send a message across the serial port. How you recieve
this message will depend on the specific adapter you’re using. If
you’re using an Arduino, open the serial console in the IDE and watch
for the message to appear when you reset the Teensy.</p>
<h2 id="next-time">Next Time</h2>
<p>Now that we have good output capabilities, we will use them to make
our panic handler useful. With good panics, we can then focus on
cleaning up our hardware setup to be safer and more robust. Our goal
will be to minimize the amount of unsafe code in <code class="highlighter-rouge">main</code>.</p>OverviewPart 1: Bootup to LED2017-01-12T21:00:00+00:002017-01-12T21:00:00+00:00https://branan.github.io/teensy/2017/01/12/bootup<h2 id="introduction">Introduction</h2>
<p>This post explains how to get a minimal application booting on a
Teensy 3.2. Further blog posts will explain how to access the various
hardware features of this chip. The goal of this tutorial series is to
explore building safe hardware abstractions in Rust. As such, existing
libraries for embedded devices will not be used.</p>
<p>The <a href="https://pjrc.com/teensy/">Teensy</a> family is a set inexpensive embedded
development boards, originally designed to be programmed using the
Arduino environment. The Teensy 3.2 that we’ll be targeting is based
on a Freescale (NXP) MK20DX256 ARM Cortex-M4 microcontroller.</p>
<p>The Teensy 3.x boards use microntrollers in the same family. Much of
what’s in this series will be applicable to all of them, and you can
probably follow along if you’re willing to read the datasheet for your
board. I’ll try to call out where things might be different for other
chips, but you’ll have the best luck using the Teensy 3.1 or 3.2 that
the tutorials are written for.</p>
<p>This tutorial is written mostly for Linux; specifically Arch. You may
have to adjust commands for other OSes, or even for other Linux
distros. If anything is broken for you, please feel free to <a href="https://github.com/branan/teensy/issues">file an
issue</a> on GitHub.</p>
<h3 id="target-audience">Target Audience</h3>
<p>This series of posts is aimed at someone who has done “lightweight”
embedded development on an Arduino (or similar). It does not rely on
you having existing knowledge of how microcontrollers are programmed
at the “low level”. You will be expected to already have a basic
knowledge of Rust, although I’ll cover some language details when we
get in to places where embedded work differs from desktop development.</p>
<h3 id="a-short-introduction-to-embedded-programming">A Short Introduction to Embedded Programming</h3>
<p>Unlike with typical desktop or server applications, embedded programs
do not have an operating system to provide them with hardware
control. Instead, they must access the hardware directly. The exact
process for hardware control varies depending on the type of processor
in use. For the ARM microcontroller that we’re using, we access the
hardware through <em>memory mapped registers</em>.</p>
<p>Memory mapping is assigning a special memory address which, when read
from or written to, interacts with a hardware device instead of
RAM. For example, address 0x4006A007 is the <em>UART Data
Register</em>. Writing a byte to this address will cause that data to be
sent across the serial port.</p>
<p>Writing to arbitrary memory addresses requires unsafe Rust. One of our
goals through this series will be to use Rust’s language features to
create safe interfaces for these unsafe memory accesses.</p>
<h2 id="development-environment">Development Environment</h2>
<p>Currently, embedded development requires the use of nightly Rust to be
practical. While many things can now be done with stable rust, we will
still need a nightly version to access some specific hardware
instructions. We’ll use <a href="https://rustup.rs/">Rustup</a> to install nightly Rust.</p>
<figure class="highlight"><pre><code class="language-shell" data-lang="shell"><span class="nv">$ </span>rustup toolchain install nightly
<span class="nv">$ </span>rustup component add <span class="nt">--target</span> thumbv7em-none-eabi rust-std <span class="nt">--toolchain</span><span class="o">=</span>nightly</code></pre></figure>
<p>We need to add the appropriate stdlib for the architecture we’re
targeting. For the Teensy 3.2, this is <code class="highlighter-rouge">thumbv7em-none-eabi</code>. This
provides the <code class="highlighter-rouge">core</code> crate that our embedded application will be linked
against.</p>
<p>Modern nightly versions of rust provide <code class="highlighter-rouge">lld</code>, the LLVM
linker. However, we still require <code class="highlighter-rouge">binutils</code> in order to convert our
binary to a format which can be loaded onto the teensy. For arch, we
install binutils like so:</p>
<figure class="highlight"><pre><code class="language-shell" data-lang="shell"><span class="nv">$ </span><span class="nb">sudo </span>pacman <span class="nt">-S</span> arm-none-eabi-binutils</code></pre></figure>
<p>Finally, you’ll want to get the <a href="https://www.pjrc.com/teensy/loader_cli.html">Teensy Loader</a>. This
is a small command line tool that handles flashing a program to the
Teensy. If you are on Linux, it may also be available through your
package manager.</p>
<h2 id="code-overview">Code Overview</h2>
<p>For this first post, we’ll be focused on the bootup procedure of the
MK20DX256. We’ll start by building up the skeleton of an embedded
application. Next, we’ll handle some basic hardware initialization
tasks. Lastly, we will add some code to turn on the Teensy’s LED. This
will let us see that our code is executing on the device.</p>
<h2 id="bootup-sequence">Bootup Sequence</h2>
<p>The MK20DX256 starts up by loading an <em>initial stack pointer</em> and
<em>reset vector</em> from the beginning of flash memory. The <em>reset vector</em>
is the equivalent of <code class="highlighter-rouge">main</code> in a normal desktop application - it is
the first bit of our code that will execute.</p>
<p>Once our main function has control, it will have to perform some basic
hardware setup - disabling the <em>watchdog</em> and enabling the <em>clock
gate</em> for any peripherals that the application needs.</p>
<p>The watchdog is a piece of hardware which will reset the
microcontroller unless the running application “checks in” in a
certain interval. It’s designed to restart crashed or hung
programs. For our needs in this tutorial it just adds complexity, so
we will disable it.</p>
<p>The other part of hardware initialization is <em>clock gating</em>. This term
comes from implementation details of how microcontrollers are
constructed. You should think of a clock gate as an on/off switch for
a piece of functionality. As we progress, we will need to enable the
clocks for a number of hardware features.</p>
<h2 id="application-setup">Application Setup</h2>
<p>We’ll start by creating a new application with cargo, and setting it
to use nightly Rust.</p>
<figure class="highlight"><pre><code class="language-shell" data-lang="shell"><span class="nv">$ </span>cargo new <span class="nt">--bin</span> teensy
<span class="nv">$ </span><span class="nb">cd </span>teensy
<span class="nv">$ </span>rustup override <span class="nb">set </span>nightly</code></pre></figure>
<p>The first thing to do is make our program embedded-friendly. There are
a few major changes to <code class="highlighter-rouge">src/main.rs</code> that we’ll need to make. Here’s the
new code, with explanations below:</p>
<figure class="highlight"><pre><code class="language-rust" data-lang="rust"><span class="err">#</span><span class="o">!</span><span class="p">[</span><span class="nf">feature</span><span class="p">(</span><span class="n">stdsimd</span><span class="p">)]</span>
<span class="err">#</span><span class="o">!</span><span class="p">[</span><span class="n">no_std</span><span class="p">]</span>
<span class="err">#</span><span class="o">!</span><span class="p">[</span><span class="n">no_main</span><span class="p">]</span>
<span class="nd">#[no_mangle]</span>
<span class="k">pub</span> <span class="k">extern</span> <span class="k">fn</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
<span class="k">loop</span><span class="p">{}</span>
<span class="p">}</span></code></pre></figure>
<p>The first line enables the use of <em>intrinsics</em>, and is the reason we
need nightly Rust. The next two lines actually disable features of the
Rust environment - the standard library, and the <code class="highlighter-rouge">main</code> wrapper. The
Rust standard library relies on a full operating system, and can’t
typically be used for embedded development. Instead, we will have
access to <em>libcore</em>, which is the subset of <code class="highlighter-rouge">std</code> that is available
without an OS. Similarly, the <code class="highlighter-rouge">main</code> wrapper is used for application
setup tasks that aren’t necessary in embedded programs.</p>
<p>Lastly, we’ve marked <code class="highlighter-rouge">main</code> as an <em>extern</em> function, and added an
infinite loop to it. <em>Extern</em> tells the Rust compiler that this
function follows the C calling convention. The details of what this
does vary by target, and are beyond the scope of this post. The
important effect of the change is that it’s now safe to use <code class="highlighter-rouge">main</code> as
our reset vector. Adding the infinite loop ensures that main will
never return. There’s no code for main to return to in this embedded
environment.</p>
<h3 id="language-items">Language Items</h3>
<p>The Rust compiler relies on certain functionality to be defined by the
standard library. Unfortunately for us, we just disabled it. This
means that we are responsible for providing these features.</p>
<p>For now, the only language feature we’re responsible for is the <em>panic
handler</em>. This is the function that gets called to display a message
when our code panics. We will eventually want to pass these messages
along to the user, but initially we will ignore them and hang the
program.</p>
<figure class="highlight"><pre><code class="language-rust" data-lang="rust"><span class="err">#</span><span class="p">[</span><span class="n">panic_handler</span><span class="p">]</span>
<span class="k">fn</span> <span class="nf">teensy_panic</span><span class="p">(</span><span class="n">_pi</span><span class="p">:</span> <span class="o">&</span><span class="nn">core</span><span class="p">::</span><span class="nn">panic</span><span class="p">::</span><span class="n">PanicInfo</span><span class="p">)</span> <span class="k">-></span> <span class="o">!</span> <span class="p">{</span>
<span class="k">loop</span> <span class="p">{};</span>
<span class="p">}</span></code></pre></figure>
<h3 id="static-data">Static Data</h3>
<p>There are two arrays of data the the hardware expects. The first is
the <em>interrupt table</em>. This contains the initial stack pointer and
reset vector that was mentioned earlier. The second is the <em>flash
configuration</em>. This is a block of 16 bytes which control how the
flash can be read and written. The Teensy bootloader makes assumptions
about these values, so we will use the same set of bytes as the
<a href="https://github.com/PaulStoffregen/cores/blob/master/teensy3/mk20dx128.c#L654-L658">Teensy Arduino tooling</a>. Specifically, we disable all
flash security through the <code class="highlighter-rouge">FSEC</code> field, and tell the processor to
boot into high-power mode with <code class="highlighter-rouge">FOPT</code>.</p>
<figure class="highlight"><pre><code class="language-rust" data-lang="rust"><span class="k">extern</span> <span class="p">{</span>
<span class="k">fn</span> <span class="nf">_stack_top</span><span class="p">();</span>
<span class="p">}</span>
<span class="nd">#[link_section</span> <span class="nd">=</span> <span class="s">".vectors"</span><span class="nd">]</span>
<span class="nd">#[no_mangle]</span>
<span class="k">pub</span> <span class="k">static</span> <span class="n">_VECTORS</span><span class="p">:</span> <span class="p">[</span><span class="k">unsafe</span> <span class="k">extern</span> <span class="k">fn</span><span class="p">();</span> <span class="mi">2</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span>
<span class="n">_stack_top</span><span class="p">,</span>
<span class="n">main</span><span class="p">,</span>
<span class="p">];</span>
<span class="nd">#[link_section</span> <span class="nd">=</span> <span class="s">".flashconfig"</span><span class="nd">]</span>
<span class="nd">#[no_mangle]</span>
<span class="k">pub</span> <span class="k">static</span> <span class="n">_FLASHCONFIG</span><span class="p">:</span> <span class="p">[</span><span class="nb">u8</span><span class="p">;</span> <span class="mi">16</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span>
<span class="mi">0xFF</span><span class="p">,</span> <span class="mi">0xFF</span><span class="p">,</span> <span class="mi">0xFF</span><span class="p">,</span> <span class="mi">0xFF</span><span class="p">,</span> <span class="mi">0xFF</span><span class="p">,</span> <span class="mi">0xFF</span><span class="p">,</span> <span class="mi">0xFF</span><span class="p">,</span> <span class="mi">0xFF</span><span class="p">,</span>
<span class="mi">0xFF</span><span class="p">,</span> <span class="mi">0xFF</span><span class="p">,</span> <span class="mi">0xFF</span><span class="p">,</span> <span class="mi">0xFF</span><span class="p">,</span> <span class="mi">0xDE</span><span class="p">,</span> <span class="mi">0xF9</span><span class="p">,</span> <span class="mi">0xFF</span><span class="p">,</span> <span class="mi">0xFF</span>
<span class="p">];</span></code></pre></figure>
<p>We will use the <code class="highlighter-rouge">link_section</code> attributes in a minute to control where
in the flash memory these arrays end up. The <code class="highlighter-rouge">no_mangle</code> attribute is
needed to tell Rust that these arrays have special meaning at link
time. Without it, the data will not appear in our final executable.</p>
<p><code class="highlighter-rouge">_stack_top</code> is not really a function. It is a memory address
representing the initial stack pointer. We pretend that it is a
function so that our _VECTORS array is easier to write. Fortunately
calling it from our own code is unsafe, so we can be pretty sure that
only the hardware will read these values.</p>
<h2 id="compiling-and-linking">Compiling and Linking</h2>
<p>Our program now contains the important data tables, as well as a
<code class="highlighter-rouge">main</code> that can be called by the microcontroller. We will now turn our
attention to building the project for the Teensy. We’ll use a Makefile
to handle the build process. Laying out the code and data in the
Teensy’s flash memory is done with a <em>linker script</em>.</p>
<h3 id="linker-scripts">Linker Scripts</h3>
<p>The linker script includes information on available memory regions,
and how program code and data are organized within those regions. Our
linker script will start out very simply, as we don’t have a lot going
on in our program. We’ll put our linker script in a new file called
<code class="highlighter-rouge">layout.ld</code>:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>MEMORY
{
FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 256K
RAM (rwx) : ORIGIN = 0x1FFF8000, LENGTH = 64K
}
SECTIONS
{
.text : {
. = 0;
KEEP(*(.vectors))
. = 0x400;
KEEP(*(.flashconfig*))
. = ALIGN(4);
*(.text*)
} > FLASH = 0xFF
.rodata : {
*(.rodata*)
} > FLASH
_stack_top = ORIGIN(RAM) + LENGTH(RAM);
/DISCARD/ : {
*(.ARM.*)
}
}
</code></pre></div></div>
<p>We begin by specifying the address ranges of both <code class="highlighter-rouge">FLASH</code> and
<code class="highlighter-rouge">RAM</code>. Next we lay out our program code at the beginning of the flash
memory. We start with the interrupt table in the first 1024
bytes. After that comes the flash configuration at address 0x0400. The
rest of flash can be laid out however we want. For now, we add our
program code and read-only data right after the flash configuration
block.</p>
<p>This file also specifies the address of <code class="highlighter-rouge">_stack_top</code> as the highest
available memory address. Since we currently have no other data in
RAM, this means that our stack can grow to fill up the entire memory
space. We’ll eventually constrain it by adding additional data to RAM.</p>
<p>Finally, we discard any sections in the executable that match the
pattern <code class="highlighter-rouge">.ARM.*</code>. This is all metadata that we don’t need in our
binary, and would waste space in our constrained environment.</p>
<h3 id="rust-linker-configuration">Rust Linker Configuration</h3>
<p>Rust will not use our linker script until we tell it to. This is done
with a cargo configuration file, which must be named
<code class="highlighter-rouge">.cargo/config</code>. While we’re here, we’ll also tell Cargo to target our
microcontroller.</p>
<figure class="highlight"><pre><code class="language-toml" data-lang="toml"><span class="nn">[build]</span>
<span class="py">target</span> <span class="p">=</span> <span class="s">"thumbv7em-none-eabi"</span>
<span class="nn">[target.thumbv7em-none-eabi]</span>
<span class="py">rustflags</span> <span class="p">=</span> <span class="p">[</span>
<span class="s">"-C"</span><span class="p">,</span> <span class="s">"link-arg=-Tlayout.ld"</span><span class="p">,</span>
<span class="p">]</span></code></pre></figure>
<h3 id="the-makefile">The Makefile</h3>
<p>Building our project is a three-step process:</p>
<ul>
<li>Use cargo to compile the rust code for the target processor</li>
<li>Convert the built program to the right format with objcopy</li>
<li>Flash our code to the Teensy with <code class="highlighter-rouge">teensy_loader_cli</code></li>
</ul>
<p>This sort of repetitive sequenced work is exactly what Makefiles were
designed for. Ours isn’t particularly complicated:</p>
<figure class="highlight"><pre><code class="language-make" data-lang="make"><span class="nv">BIN</span><span class="o">=</span>teensy
<span class="nv">OUTDIR</span><span class="o">=</span>target/thumbv7em-none-eabi/release
<span class="nv">HEX</span><span class="o">=</span><span class="nv">$(OUTDIR)</span>/<span class="nv">$(BIN)</span>.hex
<span class="nv">ELF</span><span class="o">=</span><span class="nv">$(OUTDIR)</span>/<span class="nv">$(BIN)</span>
<span class="nl">all</span><span class="o">::</span> <span class="nf">$(ELF)</span>
<span class="nl">.PHONY</span><span class="o">:</span> <span class="nf">$(ELF)</span>
<span class="nl">$(ELF)</span><span class="o">:</span>
cargo build <span class="nt">--release</span>
<span class="nl">$(HEX)</span><span class="o">:</span> <span class="nf">$(ELF)</span>
arm-none-eabi-objcopy <span class="nt">-O</span> ihex <span class="nv">$(ELF)</span> <span class="nv">$(HEX)</span>
<span class="nl">.PHONY</span><span class="o">:</span> <span class="nf">flash</span>
<span class="nl">flash</span><span class="o">:</span> <span class="nf">$(HEX)</span>
teensy_loader_cli <span class="nt">-w</span> <span class="nt">-mmcu</span><span class="o">=</span>mk20dx256 <span class="nv">$(HEX)</span> <span class="nt">-v</span></code></pre></figure>
<p>The targets marked <em>.PHONY</em> will always be built by make, even if it
thinks they are up-to-date. This is needed for the ELF target, since
its dependencies are managed by cargo. We also add it to the flash
target so that make will still flash our image even if someone creates
a file called “flash”.</p>
<p>Running <code class="highlighter-rouge">make</code> will build our project. <code class="highlighter-rouge">make flash</code> will install it to
a Teensy.</p>
<p>At this point, we can compile our project and flash it to a
Teensy. Sadly, it does nothing interesting - we wouldn’t even be able
to tell if it was running. In the next section we’ll expand our code
to do something more useful.</p>
<h2 id="accessing-the-hardware">Accessing The Hardware</h2>
<p>Our first steps here will be some basic hardware initialization
tasks. We’ll build accessors for the watchdog and for the <em>System
Integration Module</em>, or SIM. The SIM handles clock gating as well as
most other global configuration of the microcontroller. Once we have
those in place, we’ll turn to the I/O functions necessary to turn on
the LED.</p>
<h3 id="disabling-the-watchdog">Disabling the Watchdog</h3>
<p>The first bit of hardware setup we’ll do is disabling the
watchdog. The watchdog’s control is done through a series of 12 16-bit
registers at address 0x40052000. This can be represented in Rust as a
packed structure.</p>
<figure class="highlight"><pre><code class="language-rust" data-lang="rust"><span class="err">#</span><span class="p">[</span><span class="nf">repr</span><span class="p">(</span><span class="n">C</span><span class="p">,</span><span class="n">packed</span><span class="p">)]</span>
<span class="k">pub</span> <span class="k">struct</span> <span class="n">Watchdog</span> <span class="p">{</span>
<span class="n">stctrlh</span><span class="p">:</span> <span class="nb">u16</span><span class="p">,</span>
<span class="n">stctrll</span><span class="p">:</span> <span class="nb">u16</span><span class="p">,</span>
<span class="n">tovalh</span><span class="p">:</span> <span class="nb">u16</span><span class="p">,</span>
<span class="n">tovall</span><span class="p">:</span> <span class="nb">u16</span><span class="p">,</span>
<span class="n">winh</span><span class="p">:</span> <span class="nb">u16</span><span class="p">,</span>
<span class="n">winl</span><span class="p">:</span> <span class="nb">u16</span><span class="p">,</span>
<span class="n">refresh</span><span class="p">:</span> <span class="nb">u16</span><span class="p">,</span>
<span class="n">unlock</span><span class="p">:</span> <span class="nb">u16</span><span class="p">,</span>
<span class="n">tmrouth</span><span class="p">:</span> <span class="nb">u16</span><span class="p">,</span>
<span class="n">tmroutl</span><span class="p">:</span> <span class="nb">u16</span><span class="p">,</span>
<span class="n">rstcnt</span><span class="p">:</span> <span class="nb">u16</span><span class="p">,</span>
<span class="n">presc</span><span class="p">:</span> <span class="nb">u16</span>
<span class="p">}</span></code></pre></figure>
<p>We’ll add this struct to a new file - <code class="highlighter-rouge">src/watchdog.rs</code>. The fields of
this struct use the same names that the manufacturer does for these
registers. They’re hard to read here, but being consistent makes
searching for their documentation much easier.</p>
<p>Once we have a struct representing the hardware, we need to build our
functions to access it safely. To design this abstraction, we need to
think about the <em>invariants</em> of accessing these registers. An
invariant is any rule or condition that our unsafe code must take into
account, in order for it to be safely callable by safe
code. Fortunately the watchdog is pretty simple - it looks just like a
struct in memory, and can be treated as such. The biggest invariants
here are Rust’s rules about reference aliasing. There can only be one
mutable reference to the watchdog struct.</p>
<p>For now, we will say that acquiring a reference to the watchdog is an
unsafe operation. This puts the responsibility on the calling code to
verify there is only one mutable reference. Once we have that
reference, all the functions to update the watchdog will be safe -
after all, we’re just changing some fields in memory.</p>
<p>In reality, using the watchdog to its full potential could introduce
additional invariants. For example, requiring that a certain value be
written to a watchdog register during your main loop. This is not a
memory safety issue, and thus strictly falls outside of Rust’s idea of
safety. It could cause correctness issues, though, and good API design
will try to minimize correctness errors - even if they’re technically
“safe”.</p>
<p>The watchdog’s implementation looks like this. Note that <code class="highlighter-rouge">new</code> is
unsafe, but <code class="highlighter-rouge">disable</code> is safe.</p>
<figure class="highlight"><pre><code class="language-rust" data-lang="rust"><span class="k">use</span> <span class="nn">core</span><span class="p">::</span><span class="nn">arch</span><span class="p">::</span><span class="nn">arm</span><span class="p">::</span><span class="n">__NOP</span><span class="p">;</span>
<span class="k">impl</span> <span class="n">Watchdog</span> <span class="p">{</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="k">-></span> <span class="o">&</span><span class="nv">'static</span> <span class="k">mut</span> <span class="n">Watchdog</span> <span class="p">{</span>
<span class="o">&</span><span class="k">mut</span> <span class="o">*</span><span class="p">(</span><span class="mi">0x40052000</span> <span class="k">as</span> <span class="o">*</span><span class="k">mut</span> <span class="n">Watchdog</span><span class="p">)</span>
<span class="p">}</span>
<span class="k">pub</span> <span class="k">fn</span> <span class="nf">disable</span><span class="p">(</span><span class="o">&</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="nn">core</span><span class="p">::</span><span class="nn">ptr</span><span class="p">::</span><span class="nf">write_volatile</span><span class="p">(</span><span class="o">&</span><span class="k">mut</span> <span class="k">self</span><span class="py">.unlock</span><span class="p">,</span> <span class="mi">0xC520</span><span class="p">);</span>
<span class="nn">core</span><span class="p">::</span><span class="nn">ptr</span><span class="p">::</span><span class="nf">write_volatile</span><span class="p">(</span><span class="o">&</span><span class="k">mut</span> <span class="k">self</span><span class="py">.unlock</span><span class="p">,</span> <span class="mi">0xD928</span><span class="p">);</span>
<span class="nf">__NOP</span><span class="p">();</span>
<span class="nf">__NOP</span><span class="p">();</span>
<span class="k">let</span> <span class="k">mut</span> <span class="n">ctrl</span> <span class="o">=</span> <span class="nn">core</span><span class="p">::</span><span class="nn">ptr</span><span class="p">::</span><span class="nf">read_volatile</span><span class="p">(</span><span class="o">&</span><span class="k">self</span><span class="py">.stctrlh</span><span class="p">);</span>
<span class="n">ctrl</span> <span class="o">&=</span> <span class="o">!</span><span class="p">(</span><span class="mi">0x00000001</span><span class="p">);</span>
<span class="nn">core</span><span class="p">::</span><span class="nn">ptr</span><span class="p">::</span><span class="nf">write_volatile</span><span class="p">(</span><span class="o">&</span><span class="k">mut</span> <span class="k">self</span><span class="py">.stctrlh</span><span class="p">,</span> <span class="n">ctrl</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span></code></pre></figure>
<p>The disable function is following the procedure set forth in the
manufacturer’s data sheet. The watchdog is protected against being
accidentally disabled by a random write to memory, so our code must
“unlock” it first, by writing special values to the unlock
register. Once that’s done, we need to wait for the watchdog to
actually unlock itself. The <code class="highlighter-rouge">__NOP</code> intrinsic tells the processor to
briefly do nothing. This introduces our necessary 2-cycle
delay. Finally, we read the control register and un-set the “enable”
bit.</p>
<p>All of our memory access are <em>volatile</em>. This tells the Rust compiler
that the read (or write) has an effect that it can’t see from our
program code. In this case, that effect is a hardware access. Without
marking our memory accesses volatile, the Rust compiler would be free
to say “You never read from <code class="highlighter-rouge">unlock</code>, so I will optimize away the
unneeded write to it”. This would, naturally, cause our code to fail.</p>
<p>This disable process shows why we must have only one mutable reference
to the watchdog. If an interrupt were to occur partway through this
function and write to the watchdog, our attempt to disable it would
fail. Knowing that an interrupt cannot change watchdog settings gives
us confidence that this code will execute as we expect.</p>
<h3 id="clock-gating">Clock Gating</h3>
<p>The other piece of hardware involved in the microcontroller setup is
the System Integration Module. We’ll use this to enable the
appropriate clock gate to enable our I/O port. Just like the watchdog,
the SIM is controlled through a block of memory, which also will be
represent as a struct. It has the same basic memory safety rules as
the watchdog does, and for now has no extra memory-safety invariants.</p>
<p>There is a potential correctness issue involved with the SIM - it’s
possible to use a mutable reference to the SIM to disable a hardware
function that another section of code relies on. We can design an API
that keeps better track of which functional units are needed, but we
will save that for a future post. For now, we’ll just have to trust
ourselves.</p>
<p>The complete code for <code class="highlighter-rouge">src/sim.rs</code> is here:</p>
<figure class="highlight"><pre><code class="language-rust" data-lang="rust"><span class="k">use</span> <span class="n">core</span><span class="p">;</span>
<span class="nd">#[derive(Clone,Copy)]</span>
<span class="k">pub</span> <span class="k">enum</span> <span class="n">Clock</span> <span class="p">{</span>
<span class="n">PortC</span><span class="p">,</span>
<span class="p">}</span>
<span class="nd">#[repr(C,packed)]</span>
<span class="k">pub</span> <span class="k">struct</span> <span class="n">Sim</span> <span class="p">{</span>
<span class="n">sopt1</span><span class="p">:</span> <span class="nb">u32</span><span class="p">,</span>
<span class="n">sopt1_cfg</span><span class="p">:</span> <span class="nb">u32</span><span class="p">,</span>
<span class="n">_pad0</span><span class="p">:</span> <span class="p">[</span><span class="nb">u32</span><span class="p">;</span> <span class="mi">1023</span><span class="p">],</span>
<span class="n">sopt2</span><span class="p">:</span> <span class="nb">u32</span><span class="p">,</span>
<span class="n">_pad1</span><span class="p">:</span> <span class="nb">u32</span><span class="p">,</span>
<span class="n">sopt4</span><span class="p">:</span> <span class="nb">u32</span><span class="p">,</span>
<span class="n">sopt5</span><span class="p">:</span> <span class="nb">u32</span><span class="p">,</span>
<span class="n">_pad2</span><span class="p">:</span> <span class="nb">u32</span><span class="p">,</span>
<span class="n">sopt7</span><span class="p">:</span> <span class="nb">u32</span><span class="p">,</span>
<span class="n">_pad3</span><span class="p">:</span> <span class="p">[</span><span class="nb">u32</span><span class="p">;</span> <span class="mi">2</span><span class="p">],</span>
<span class="n">sdid</span><span class="p">:</span> <span class="nb">u32</span><span class="p">,</span>
<span class="n">_pad4</span><span class="p">:</span> <span class="p">[</span><span class="nb">u32</span><span class="p">;</span> <span class="mi">3</span><span class="p">],</span>
<span class="n">scgc4</span><span class="p">:</span> <span class="nb">u32</span><span class="p">,</span>
<span class="n">scgc5</span><span class="p">:</span> <span class="nb">u32</span><span class="p">,</span>
<span class="n">scgc6</span><span class="p">:</span> <span class="nb">u32</span><span class="p">,</span>
<span class="n">scgc7</span><span class="p">:</span> <span class="nb">u32</span><span class="p">,</span>
<span class="n">clkdiv1</span><span class="p">:</span> <span class="nb">u32</span><span class="p">,</span>
<span class="n">clkviv2</span><span class="p">:</span> <span class="nb">u32</span><span class="p">,</span>
<span class="n">fcfg1</span><span class="p">:</span> <span class="nb">u32</span><span class="p">,</span>
<span class="n">fcfg2</span><span class="p">:</span> <span class="nb">u32</span><span class="p">,</span>
<span class="n">uidh</span><span class="p">:</span> <span class="nb">u32</span><span class="p">,</span>
<span class="n">uidmh</span><span class="p">:</span> <span class="nb">u32</span><span class="p">,</span>
<span class="n">uidml</span><span class="p">:</span> <span class="nb">u32</span><span class="p">,</span>
<span class="n">uidl</span><span class="p">:</span> <span class="nb">u32</span>
<span class="p">}</span>
<span class="k">impl</span> <span class="n">Sim</span> <span class="p">{</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="k">-></span> <span class="o">&</span><span class="nv">'static</span> <span class="k">mut</span> <span class="n">Sim</span> <span class="p">{</span>
<span class="o">&</span><span class="k">mut</span> <span class="o">*</span><span class="p">(</span><span class="mi">0x40047000</span> <span class="k">as</span> <span class="o">*</span><span class="k">mut</span> <span class="n">Sim</span><span class="p">)</span>
<span class="p">}</span>
<span class="k">pub</span> <span class="k">fn</span> <span class="nf">enable_clock</span><span class="p">(</span><span class="o">&</span><span class="k">mut</span> <span class="k">self</span><span class="p">,</span> <span class="n">clock</span><span class="p">:</span> <span class="n">Clock</span><span class="p">)</span> <span class="p">{</span>
<span class="k">unsafe</span> <span class="p">{</span>
<span class="k">match</span> <span class="n">clock</span> <span class="p">{</span>
<span class="nn">Clock</span><span class="p">::</span><span class="n">PortC</span> <span class="k">=></span> <span class="p">{</span>
<span class="k">let</span> <span class="k">mut</span> <span class="n">scgc</span> <span class="o">=</span> <span class="nn">core</span><span class="p">::</span><span class="nn">ptr</span><span class="p">::</span><span class="nf">read_volatile</span><span class="p">(</span><span class="o">&</span><span class="k">self</span><span class="py">.scgc5</span><span class="p">);</span>
<span class="n">scgc</span> <span class="p">|</span><span class="o">=</span> <span class="mi">0x00000800</span><span class="p">;</span>
<span class="nn">core</span><span class="p">::</span><span class="nn">ptr</span><span class="p">::</span><span class="nf">write_volatile</span><span class="p">(</span><span class="o">&</span><span class="k">mut</span> <span class="k">self</span><span class="py">.scgc5</span><span class="p">,</span> <span class="n">scgc</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span></code></pre></figure>
<p>The simple match-based clock management we have here would get
unwieldy pretty quickly if we intended to use it to manage a large
number of hardware functions. We’ll get rid of it when we look in to
more robust ways to manage clock gates.</p>
<h3 id="io-ports">I/O Ports</h3>
<p>With the initial hardware setup out of the way, we can turn our
attention to achieving that bright orange<sup>1</sup> glow that we’ve
been working towards. We will put a pin into <em>GPIO</em> mode, and use it
to turn on the LED. GPIO stands for “General Purpose I/O”. When a pin
is in GPIO mode, software has control over the high/low state of an
output pin and direct read access to the state of an input pin. This
is in contrast to the pin being controlled by a dedicated hardware
function, such as a serial port.</p>
<p>Pins are grouped into ports, and all of a pin’s settings are
controlled from the port’s register block. This poses a bit of a
challenge for us. We’d like each pin to be a self-contained struct, so
that ownership of it can be passed from one software module to
another, and only the owning module can mutate its pins. This follows
Rust’s one-owner rule for pins, but would require that each pin be
able to mutate its settings in the Port register block. We all know
how Rust feels about shared mutable state.</p>
<p>Fortunately, each pin has a separate control register in the port’s
block. That means there’s no actual overlap of memory locations that
might be written. We’ll take advantage of this to write some very,
very careful unsafe code that allows each pin instance to modify its
own control settings.</p>
<p>We’ll start out with a port implementation in <code class="highlighter-rouge">src/port.rs</code>.</p>
<figure class="highlight"><pre><code class="language-rust" data-lang="rust"><span class="k">use</span> <span class="n">core</span><span class="p">;</span>
<span class="nd">#[derive(Clone,Copy)]</span>
<span class="k">pub</span> <span class="k">enum</span> <span class="n">PortName</span> <span class="p">{</span>
<span class="n">C</span>
<span class="p">}</span>
<span class="nd">#[repr(C,packed)]</span>
<span class="k">pub</span> <span class="k">struct</span> <span class="n">Port</span> <span class="p">{</span>
<span class="n">pcr</span><span class="p">:</span> <span class="p">[</span><span class="nb">u32</span><span class="p">;</span> <span class="mi">32</span><span class="p">],</span>
<span class="n">gpclr</span><span class="p">:</span> <span class="nb">u32</span><span class="p">,</span>
<span class="n">gpchr</span><span class="p">:</span> <span class="nb">u32</span><span class="p">,</span>
<span class="n">reserved_0</span><span class="p">:</span> <span class="p">[</span><span class="nb">u8</span><span class="p">;</span> <span class="mi">24</span><span class="p">],</span>
<span class="n">isfr</span><span class="p">:</span> <span class="nb">u32</span><span class="p">,</span>
<span class="p">}</span>
<span class="k">impl</span> <span class="n">Port</span> <span class="p">{</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">name</span><span class="p">:</span> <span class="n">PortName</span><span class="p">)</span> <span class="k">-></span> <span class="o">&</span><span class="nv">'static</span> <span class="k">mut</span> <span class="n">Port</span> <span class="p">{</span>
<span class="o">&</span><span class="k">mut</span> <span class="o">*</span> <span class="k">match</span> <span class="n">name</span> <span class="p">{</span>
<span class="nn">PortName</span><span class="p">::</span><span class="n">C</span> <span class="k">=></span> <span class="mi">0x4004B000</span> <span class="k">as</span> <span class="o">*</span><span class="k">mut</span> <span class="n">Port</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="k">pub</span> <span class="k">unsafe</span> <span class="k">fn</span> <span class="nf">set_pin_mode</span><span class="p">(</span><span class="o">&</span><span class="k">mut</span> <span class="k">self</span><span class="p">,</span> <span class="n">p</span><span class="p">:</span> <span class="nb">usize</span><span class="p">,</span> <span class="k">mut</span> <span class="n">mode</span><span class="p">:</span> <span class="nb">u32</span><span class="p">)</span> <span class="p">{</span>
<span class="k">let</span> <span class="k">mut</span> <span class="n">pcr</span> <span class="o">=</span> <span class="nn">core</span><span class="p">::</span><span class="nn">ptr</span><span class="p">::</span><span class="nf">read_volatile</span><span class="p">(</span><span class="o">&</span><span class="k">self</span><span class="py">.pcr</span><span class="p">[</span><span class="n">p</span><span class="p">]);</span>
<span class="n">pcr</span> <span class="o">&=</span> <span class="mi">0xFFFFF8FF</span><span class="p">;</span>
<span class="n">mode</span> <span class="o">&=</span> <span class="mi">0x00000007</span><span class="p">;</span>
<span class="n">mode</span> <span class="o"><<=</span> <span class="mi">8</span><span class="p">;</span>
<span class="n">pcr</span> <span class="p">|</span><span class="o">=</span> <span class="n">mode</span><span class="p">;</span>
<span class="nn">core</span><span class="p">::</span><span class="nn">ptr</span><span class="p">::</span><span class="nf">write_volatile</span><span class="p">(</span><span class="o">&</span><span class="k">mut</span> <span class="k">self</span><span class="py">.pcr</span><span class="p">[</span><span class="n">p</span><span class="p">],</span> <span class="n">pcr</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span></code></pre></figure>
<p>Note the array of 32 words called <em>pcr</em>; each of these is an
individual pin control register. The <code class="highlighter-rouge">set_pin_mode</code> function is
responsible for switching a single pin into GPIO (or any other)
mode. The only memory it touches is the PCR associated with a single
pin, and is unsafe to call. It’s unsafety is because calling it for a
pin that you do not own could cause a race condition. An interrupt
that changes a PCR between the read and write in this function could
have its changes overwritten.</p>
<p>The pin struct is next on our list. A pin is not a reference to any
particular register. Instead, it is a concept in our code that
represents a piece of a port. It will have a mutable reference to its
containing port, as well as an integer representing which index in the
PCR array it is associated with.</p>
<p>In order for this mutable port reference to be safe, Pin instances
must only call methods of Port that affect the correct PCR. We can’t
really enforce this, but to encourage it, Pin’s Port reference will
actually be a pointer. This makes it impossible to call Port methods
without an unsafe block, and reinforces the peculiarity of this
arrangement.</p>
<figure class="highlight"><pre><code class="language-rust" data-lang="rust"><span class="k">pub</span> <span class="k">struct</span> <span class="n">Pin</span> <span class="p">{</span>
<span class="n">port</span><span class="p">:</span> <span class="o">*</span><span class="k">mut</span> <span class="n">Port</span><span class="p">,</span>
<span class="n">pin</span><span class="p">:</span> <span class="nb">usize</span>
<span class="p">}</span>
<span class="k">impl</span> <span class="n">Port</span> <span class="p">{</span>
<span class="k">pub</span> <span class="k">unsafe</span> <span class="k">fn</span> <span class="nf">pin</span><span class="p">(</span><span class="o">&</span><span class="k">mut</span> <span class="k">self</span><span class="p">,</span> <span class="n">p</span><span class="p">:</span> <span class="nb">usize</span><span class="p">)</span> <span class="k">-></span> <span class="n">Pin</span> <span class="p">{</span>
<span class="n">Pin</span> <span class="p">{</span> <span class="n">port</span><span class="p">:</span> <span class="k">self</span><span class="p">,</span> <span class="n">pin</span><span class="p">:</span> <span class="n">p</span> <span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span></code></pre></figure>
<h3 id="gpio-and-the-bit-band">GPIO and the Bit-Band</h3>
<p>There are two ways to access the GPIO registers. The first is through
a block of 32-bit registers, associated with a port. It looks
something like this:</p>
<figure class="highlight"><pre><code class="language-rust" data-lang="rust"><span class="err">#</span><span class="p">[</span><span class="nf">repr</span><span class="p">(</span><span class="n">C</span><span class="p">,</span><span class="n">packed</span><span class="p">)]</span>
<span class="k">struct</span> <span class="n">Gpio</span> <span class="p">{</span>
<span class="n">pdor</span><span class="p">:</span> <span class="nb">u32</span><span class="p">,</span>
<span class="n">psor</span><span class="p">:</span> <span class="nb">u32</span><span class="p">,</span>
<span class="n">pcor</span><span class="p">:</span> <span class="nb">u32</span><span class="p">,</span>
<span class="n">ptor</span><span class="p">:</span> <span class="nb">u32</span><span class="p">,</span>
<span class="n">pdir</span><span class="p">:</span> <span class="nb">u32</span><span class="p">,</span>
<span class="n">pddr</span><span class="p">:</span> <span class="nb">u32</span>
<span class="p">}</span></code></pre></figure>
<p>This is very convenient to work with, but has an unfortunate
flaw. Each of the fields represents all 32 pins in a Port. This means
that any pin changes are subject to a race condition during our
read/modify/write process. Pins that are owned by a separate piece of
code can have an impact on how our pin behaves.</p>
<p>Fortunately, ARM has a solution to this. We will take advantage of the
<em>bit-band alias</em>. Bit-banding is a feature of certain ARM processors
that maps a memory region to one 32 times as large. Each 32-bit word
of this larger regions maps to a single <em>bit</em> of the original
region. This gives us the capability to set or clear a single bit at a
time, without risk of race conditions. If we visualized this as a rust
struct, the bit-band alias for the GPIO would look like this:</p>
<figure class="highlight"><pre><code class="language-rust" data-lang="rust"><span class="err">#</span><span class="p">[</span><span class="nf">repr</span><span class="p">(</span><span class="n">C</span><span class="p">,</span><span class="n">packed</span><span class="p">)]</span>
<span class="k">struct</span> <span class="n">GpioBitband</span> <span class="p">{</span>
<span class="n">pdor</span><span class="p">:</span> <span class="p">[</span><span class="nb">u32</span><span class="p">;</span> <span class="mi">32</span><span class="p">],</span>
<span class="n">psor</span><span class="p">:</span> <span class="p">[</span><span class="nb">u32</span><span class="p">;</span> <span class="mi">32</span><span class="p">],</span>
<span class="n">pcor</span><span class="p">:</span> <span class="p">[</span><span class="nb">u32</span><span class="p">;</span> <span class="mi">32</span><span class="p">],</span>
<span class="n">ptor</span><span class="p">:</span> <span class="p">[</span><span class="nb">u32</span><span class="p">;</span> <span class="mi">32</span><span class="p">],</span>
<span class="n">pdir</span><span class="p">:</span> <span class="p">[</span><span class="nb">u32</span><span class="p">;</span> <span class="mi">32</span><span class="p">],</span>
<span class="n">pddr</span><span class="p">:</span> <span class="p">[</span><span class="nb">u32</span><span class="p">;</span> <span class="mi">32</span><span class="p">]</span>
<span class="p">}</span></code></pre></figure>
<p>This is what we will use to control the GPIO. Just like with Pins and
the PCR registers, we will have individual GPIO structures that
represent a single GPIO pin. They will ensure safety by only writing
to the register words associated with their pin index. Let’s look at
all that code now, then walk through it.</p>
<figure class="highlight"><pre><code class="language-rust" data-lang="rust"><span class="k">pub</span> <span class="k">struct</span> <span class="n">Gpio</span> <span class="p">{</span>
<span class="n">gpio</span><span class="p">:</span> <span class="o">*</span><span class="k">mut</span> <span class="n">GpioBitband</span><span class="p">,</span>
<span class="n">pin</span><span class="p">:</span> <span class="nb">usize</span>
<span class="p">}</span>
<span class="k">impl</span> <span class="n">Port</span> <span class="p">{</span>
<span class="k">pub</span> <span class="k">fn</span> <span class="nf">name</span><span class="p">(</span><span class="o">&</span><span class="k">self</span><span class="p">)</span> <span class="k">-></span> <span class="n">PortName</span> <span class="p">{</span>
<span class="k">let</span> <span class="n">addr</span> <span class="o">=</span> <span class="p">(</span><span class="k">self</span> <span class="k">as</span> <span class="o">*</span><span class="k">const</span> <span class="n">Port</span><span class="p">)</span> <span class="k">as</span> <span class="nb">u32</span><span class="p">;</span>
<span class="k">match</span> <span class="n">addr</span> <span class="p">{</span>
<span class="mi">0x4004B000</span> <span class="k">=></span> <span class="nn">PortName</span><span class="p">::</span><span class="n">C</span><span class="p">,</span>
<span class="n">_</span> <span class="k">=></span> <span class="nd">unreachable!</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">Pin</span> <span class="p">{</span>
<span class="k">pub</span> <span class="k">fn</span> <span class="nf">make_gpio</span><span class="p">(</span><span class="k">self</span><span class="p">)</span> <span class="k">-></span> <span class="n">Gpio</span> <span class="p">{</span>
<span class="k">unsafe</span> <span class="p">{</span>
<span class="k">let</span> <span class="n">port</span> <span class="o">=</span> <span class="o">&</span><span class="k">mut</span> <span class="o">*</span><span class="k">self</span><span class="py">.port</span><span class="p">;</span>
<span class="n">port</span><span class="nf">.set_pin_mode</span><span class="p">(</span><span class="k">self</span><span class="py">.pin</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
<span class="nn">Gpio</span><span class="p">::</span><span class="nf">new</span><span class="p">(</span><span class="n">port</span><span class="nf">.name</span><span class="p">(),</span> <span class="k">self</span><span class="py">.pin</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">Gpio</span> <span class="p">{</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">port</span><span class="p">:</span> <span class="n">PortName</span><span class="p">,</span> <span class="n">pin</span><span class="p">:</span> <span class="nb">usize</span><span class="p">)</span> <span class="k">-></span> <span class="n">Gpio</span> <span class="p">{</span>
<span class="k">let</span> <span class="n">gpio</span> <span class="o">=</span> <span class="k">match</span> <span class="n">port</span> <span class="p">{</span>
<span class="nn">PortName</span><span class="p">::</span><span class="n">C</span> <span class="k">=></span> <span class="mi">0x43FE1000</span> <span class="k">as</span> <span class="o">*</span><span class="k">mut</span> <span class="n">GpioBitband</span>
<span class="p">};</span>
<span class="n">Gpio</span> <span class="p">{</span> <span class="n">gpio</span><span class="p">,</span> <span class="n">pin</span> <span class="p">}</span>
<span class="p">}</span>
<span class="k">pub</span> <span class="k">fn</span> <span class="nf">output</span><span class="p">(</span><span class="o">&</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="nn">core</span><span class="p">::</span><span class="nn">ptr</span><span class="p">::</span><span class="nf">write_volatile</span><span class="p">(</span><span class="o">&</span><span class="k">mut</span> <span class="p">(</span><span class="o">*</span><span class="k">self</span><span class="py">.gpio</span><span class="p">)</span><span class="py">.pddr</span><span class="p">[</span><span class="k">self</span><span class="py">.pin</span><span class="p">],</span> <span class="mi">1</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="k">pub</span> <span class="k">fn</span> <span class="nf">high</span><span class="p">(</span><span class="o">&</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="nn">core</span><span class="p">::</span><span class="nn">ptr</span><span class="p">::</span><span class="nf">write_volatile</span><span class="p">(</span><span class="o">&</span><span class="k">mut</span> <span class="p">(</span><span class="o">*</span><span class="k">self</span><span class="py">.gpio</span><span class="p">)</span><span class="py">.psor</span><span class="p">[</span><span class="k">self</span><span class="py">.pin</span><span class="p">],</span> <span class="mi">1</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span></code></pre></figure>
<p>The Gpio struct, just like the Port struct, holds a pointer to the
shared data block, as well as an index of its pin number. It has two
functions: one to set itself as an output, and one to set its output
value to high. Thanks to the bit-band, these functions can be
implemented with a single write, eliminating the potential race
condition that a read-modify-write of a shared memory address would
create.</p>
<p>Converting a Pin into a Gpio consumes the Pin. This prevents having
more than one reference to a single hardware pin. Getting another copy
of a pin from the port is unsafe, so we can be confident that safe
code will never make a second copy of a pin that is in use as a GPIO.</p>
<h2 id="putting-it-together">Putting it Together</h2>
<p>We now have all the pieces for our first program. Going back to the
beginning, our application will do the following:</p>
<ul>
<li>disable the watchdog</li>
<li>turn on the clock gate for Port C</li>
<li>grab pin 5 from that port, and make it a GPIO</li>
<li>set that GPIO high to light the LED</li>
</ul>
<p>This all ends up being surprisingly short in main:</p>
<figure class="highlight"><pre><code class="language-rust" data-lang="rust"><span class="k">mod</span> <span class="n">port</span><span class="p">;</span>
<span class="k">mod</span> <span class="n">sim</span><span class="p">;</span>
<span class="k">mod</span> <span class="n">watchdog</span><span class="p">;</span>
<span class="k">extern</span> <span class="k">fn</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
<span class="k">let</span> <span class="p">(</span><span class="n">wdog</span><span class="p">,</span><span class="n">sim</span><span class="p">,</span><span class="n">pin</span><span class="p">)</span> <span class="o">=</span> <span class="k">unsafe</span> <span class="p">{</span>
<span class="p">(</span><span class="nn">watchdog</span><span class="p">::</span><span class="nn">Watchdog</span><span class="p">::</span><span class="nf">new</span><span class="p">(),</span>
<span class="nn">sim</span><span class="p">::</span><span class="nn">Sim</span><span class="p">::</span><span class="nf">new</span><span class="p">(),</span>
<span class="nn">port</span><span class="p">::</span><span class="nn">Port</span><span class="p">::</span><span class="nf">new</span><span class="p">(</span><span class="nn">port</span><span class="p">::</span><span class="nn">PortName</span><span class="p">::</span><span class="n">C</span><span class="p">)</span><span class="nf">.pin</span><span class="p">(</span><span class="mi">5</span><span class="p">))</span>
<span class="p">};</span>
<span class="n">wdog</span><span class="nf">.disable</span><span class="p">();</span>
<span class="n">sim</span><span class="nf">.enable_clock</span><span class="p">(</span><span class="nn">sim</span><span class="p">::</span><span class="nn">Clock</span><span class="p">::</span><span class="n">PortC</span><span class="p">);</span>
<span class="k">let</span> <span class="k">mut</span> <span class="n">gpio</span> <span class="o">=</span> <span class="n">pin</span><span class="nf">.make_gpio</span><span class="p">();</span>
<span class="n">gpio</span><span class="nf">.output</span><span class="p">();</span>
<span class="n">gpio</span><span class="nf">.high</span><span class="p">();</span>
<span class="k">loop</span> <span class="p">{}</span>
<span class="p">}</span></code></pre></figure>
<p>Our only unsafe code in main is creating the mutable references to the
various register blocks. Creating these is always unsafe, since more
than one would violate Rust’s memory safety rules. The rest of the
code is 100% safe.</p>
<p>It’s finally time to send our first pure-rust embedded program to the
Teensy! Connect your Teensy to a USB port, then run <code class="highlighter-rouge">make flash</code>. You
should see the LED on the Teensy light up once the process is
complete. If it doesn’t, double-check your linker script, and the link
sections of the _VECTORS and _FLASHCONFIG arrays. You might also
double-check the addresses of the register blocks.</p>
<p>Our next post will look at enabling a UART for serial
communication. This will give us access to real panic messages. We’ll
take advantage of panics to enforce some of our rules about duplicate
pins, similar to how Rust’s <code class="highlighter-rouge">RefCell</code> panics on duplicate mutable
accesses.</p>
<p><sup>1</sup> All genuine Teensys have an orange LED. If yours has a
different color, I’m sad to say it’s a knockoff.</p>Introduction