1139 lines
129 KiB
HTML
1139 lines
129 KiB
HTML
<html>
|
||
<head>
|
||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||
<title>Safety Critical Embedded Controller</title>
|
||
<link rel="stylesheet" href="boostbook.css" type="text/css">
|
||
<meta name="generator" content="DocBook XSL Stylesheets V1.79.1">
|
||
<link rel="home" href="index.html" title="Safe Numerics">
|
||
<link rel="up" href="case_studies.html" title="Case Studies">
|
||
<link rel="prev" href="composition_with_other_libraries.html" title="Composition with Other Libraries">
|
||
<link rel="next" href="notes.html" title="Background">
|
||
</head>
|
||
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
|
||
<table cellpadding="2" width="100%"><tr>
|
||
<td valign="top"><img href="index.html" height="164px" src="pre-boost.jpg" alt="Library Documentation Index"></td>
|
||
<td><h2>Safe Numerics</h2></td>
|
||
</tr></table>
|
||
<div class="spirit-nav">
|
||
<a accesskey="p" href="composition_with_other_libraries.html"><img src="images/prev.png" alt="Prev"></a><a accesskey="u" href="case_studies.html"><img src="images/up.png" alt="Up"></a><a accesskey="h" href="index.html"><img src="images/home.png" alt="Home"></a><a accesskey="n" href="notes.html"><img src="images/next.png" alt="Next"></a>
|
||
</div>
|
||
<div class="section">
|
||
<div class="titlepage"><div><div><h3 class="title">
|
||
<a name="safe_numerics.safety_critical_embedded_controller"></a>Safety Critical Embedded Controller</h3></div></div></div>
|
||
<div class="toc"><dl class="toc">
|
||
<dt><span class="section"><a href="safety_critical_embedded_controller.html#idm488721963072">How a Stepper Motor Works</a></span></dt>
|
||
<dt><span class="section"><a href="safety_critical_embedded_controller.html#idm488721950912">Updating the Code</a></span></dt>
|
||
<dt><span class="section"><a href="safety_critical_embedded_controller.html#idm488725879184">Refactor for Testing</a></span></dt>
|
||
<dt><span class="section"><a href="safety_critical_embedded_controller.html#idm488728731120">Compiling on the Desktop</a></span></dt>
|
||
<dt><span class="section"><a href="safety_critical_embedded_controller.html#idm488728235264">Trapping Errors at Compile Time</a></span></dt>
|
||
<dt><span class="section"><a href="safety_critical_embedded_controller.html#idm488720805184">Summary</a></span></dt>
|
||
</dl></div>
|
||
<p>Suppose we are given the task of creating stepper motor driver
|
||
software to drive a robotic hand to be used in robotic micro surgery. The
|
||
processor that has been selected by the engineers is the <a href="http://www.microchip.com/wwwproducts/en/PIC18F2520" target="_top">PIC18F2520</a>
|
||
manufactured by <a href="http://www.microchip.com" target="_top">Microchip
|
||
Corporation</a>. This processor has 32KB of program memory. On a
|
||
processor this small, it's common to use a mixture of 8, 16, and 32 bit data
|
||
types in order to minimize memory footprint and program run time. The type
|
||
<code class="computeroutput">int</code> has 16 bits. It's programmed in C. Since this program is
|
||
going to be running life critical function, it must be demonstrably correct.
|
||
This implies that it needs to be verifiable and testable. Since the target
|
||
micro processor is inconvenient for accomplishing these goals, we will build
|
||
and test the code on the desktop.</p>
|
||
<div class="section">
|
||
<div class="titlepage"><div><div><h4 class="title">
|
||
<a name="idm488721963072"></a>How a Stepper Motor Works</h4></div></div></div>
|
||
<div class="figure">
|
||
<a name="idm488721962432"></a><p class="title"><b>Figure 1. Stepper Motor</b></p>
|
||
<div class="figure-contents"><div class="mediaobject" align="left"><table border="0" summary="manufactured viewport for HTML img" style="cellpadding: 0; cellspacing: 0;" width="50%"><tr><td align="left"><img src="StepperMotor.gif" align="left" width="216" alt="Stepper Motor"></td></tr></table></div></div>
|
||
</div>
|
||
<br class="figure-break"><p>A stepper motor controller emits a pulse which causes the motor to
|
||
move one step. It seems simple, but in practice it turns out to be quite
|
||
intricate to get right as one has to time the pulses individually to
|
||
smoothly accelerate the rotation of the motor from a standing start until
|
||
it reaches the some maximum velocity. Failure to do this will either limit
|
||
the stepper motor to very low speed or result in skipped steps when the
|
||
motor is under load. Similarly, a loaded motor must be slowly decelerated
|
||
down to a stop.</p>
|
||
<div class="figure">
|
||
<a name="idm488721958112"></a><p class="title"><b>Figure 2. Motion Profile</b></p>
|
||
<div class="figure-contents"><div class="mediaobject"><table border="0" summary="manufactured viewport for HTML img" style="cellpadding: 0; cellspacing: 0;" width="100%"><tr><td><img src="stepper_profile.png" width="100%" alt="Motion Profile"></td></tr></table></div></div>
|
||
</div>
|
||
<p><br class="figure-break"></p>
|
||
<p>This implies the the width of the pulses must decrease as the motor
|
||
accelerates. That is the pulse with has to be computed while the motor is
|
||
in motion. This is illustrated in the above drawing. A program to
|
||
accomplish this might look something like the following:</p>
|
||
<div class="literallayout"><p>setup registers and step to zero position<br>
|
||
<br>
|
||
specify target position<br>
|
||
set initial time to interrupt<br>
|
||
enable interrupts<br>
|
||
<br>
|
||
On interrupt<br>
|
||
if at target position<br>
|
||
disable interrupts and return<br>
|
||
calculate width of next step<br>
|
||
change current winding according to motor direction<br>
|
||
set delay time to next interrupt to width of next step</p></div>
|
||
<p>Already, this is turning it to a much more complex project than it
|
||
first seemed. Searching around the net, we find a popular <a href="../../example/stepper-motor.pdf" target="_top">article</a> on the operation of
|
||
stepper motors using simple micro controllers. The algorithm is very well
|
||
explained and it includes complete <a href="../../example/motor.c" target="_top">code
|
||
we can test</a>. The engineers are still debugging the prototype
|
||
boards and hope to have them ready before the product actually ships. But
|
||
this doesn't have to keep us from working on our code.</p>
|
||
</div>
|
||
<div class="section">
|
||
<div class="titlepage"><div><div><h4 class="title">
|
||
<a name="idm488721950912"></a>Updating the Code</h4></div></div></div>
|
||
<p>Inspecting this <a href="../../example/motor.c" target="_top">code</a>, we
|
||
find that it is written in a dialect of C rather than C itself. At the
|
||
time this code was written, conforming versions of the C compiler were not
|
||
available for PIC processors. We want to compile this code on the <a href="http://ww1.microchip.com/downloads/en/DeviceDoc/50002053G.pdf" target="_top">Microchip
|
||
XC8 compiler</a> which, for the most part, is standards conforming. So
|
||
we made the following minimal changes:</p>
|
||
<div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; ">
|
||
<li class="listitem"><p>Factor into <a href="../../example/motor1.c" target="_top">motor1.c</a> which contains the
|
||
motor driving code and <a href="../../example/motor_test1.c" target="_top">motor_test1.c</a> which tests
|
||
that code.</p></li>
|
||
<li class="listitem"><p>Include header <code class="computeroutput"><xc.h></code> which contains
|
||
constants for the <a href="http://www.microchip.com/wwwproducts/en/PIC18F2520" target="_top">PIC18F2520</a>
|
||
processor</p></li>
|
||
<li class="listitem"><p>Include header <code class="computeroutput"><stdint.h></code> to include
|
||
standard Fixed width integer types.</p></li>
|
||
<li class="listitem"><p>Include header <code class="computeroutput"><stdbool.h></code> to include
|
||
keywords true and false in a C program.</p></li>
|
||
<li class="listitem"><p>The original has some anomalies in the names of types. For
|
||
example, int16 is assumed to be unsigned. This is an artifact of the
|
||
original C compiler being used. So type names in the code were
|
||
altered to standard ones while retaining the intent of the original
|
||
code.</p></li>
|
||
<li class="listitem"><p>Add in missing <code class="computeroutput">make16</code> function.</p></li>
|
||
<li class="listitem"><p>Format code to personal taste.</p></li>
|
||
<li class="listitem"><p>Replaced enable_interrupts and disable_interrupts functions
|
||
with appropriate PIC commands.</p></li>
|
||
</ul></div>
|
||
<p>The resulting program can be checked to be identical to the original
|
||
but compiles on with the Microchip XC8 compiler. Given a development
|
||
board, we could hook it up to a stepper motor, download and boot the code
|
||
and verify that the motor rotates 5 revolutions in each direction with
|
||
smooth acceleration and deceleration. We don't have such a board yet, but
|
||
the engineers have promised a working board real soon now.</p>
|
||
</div>
|
||
<div class="section">
|
||
<div class="titlepage"><div><div><h4 class="title">
|
||
<a name="idm488725879184"></a>Refactor for Testing</h4></div></div></div>
|
||
<p>In order to develop our test suite and execute the same code on the
|
||
desktop and the target system we factor out the shared code as a separate
|
||
module which will used in both environments without change. The shared
|
||
module <a href="../../example/motor2.c" target="_top"><code class="computeroutput"><a href="../../example/motor1.c" target="_top">motor2.c</a></code></a> contains the
|
||
algorithm for handling the interrupts in such a way as to create the
|
||
smooth acceleration we require.</p>
|
||
<div class="literallayout"><p> <a href="../../example/motor2.c" target="_top"><code class="computeroutput"><a href="../../example/motor_test2.c" target="_top">motor_test2.c</a></code></a> <a href="../../example/motor2.c" target="_top"><code class="computeroutput"><a href="../../example/example92.cpp" target="_top">example92.cpp</a></code></a><br>
|
||
<br>
|
||
#include ... #include ...<br>
|
||
PIC typedefs ... desktop types ...<br>
|
||
\ /<br>
|
||
\ /<br>
|
||
#include <a href="../../example/motor2.c" target="_top"><code class="computeroutput"><a href="../../example/motor2.c" target="_top">motor2.c</a></code></a><br>
|
||
/ \<br>
|
||
/ \<br>
|
||
PIC test code desktop test code</p></div>
|
||
</div>
|
||
<div class="section">
|
||
<div class="titlepage"><div><div><h4 class="title">
|
||
<a name="idm488728731120"></a>Compiling on the Desktop</h4></div></div></div>
|
||
<p>Using the target environment to run tests is often very difficult or
|
||
impossible due to limited resources. So software unit testing for embedded
|
||
systems is very problematic and often skipped. The C language on our
|
||
desktop is the same used by the <a href="http://www.microchip.com/wwwproducts/en/PIC18F2520" target="_top">PIC18F2520</a>.
|
||
So now we can also run and debug the code on our desktop machine. Once our
|
||
code passes all our tests, we can download the code to the embedded
|
||
hardware and run the code natively. Here is a program we use on the
|
||
desktop to do that:</p>
|
||
<pre class="programlisting"><span class="comment">//////////////////////////////////////////////////////////////////</span>
|
||
<span class="comment">// example92.cpp</span>
|
||
<span class="comment">//</span>
|
||
<span class="comment">// Copyright (c) 2015 Robert Ramey</span>
|
||
<span class="comment">//</span>
|
||
<span class="comment">// Distributed under the Boost Software License, Version 1.0. (See</span>
|
||
<span class="comment">// accompanying file LICENSE_1_0.txt or copy at</span>
|
||
<span class="comment">// http://www.boost.org/LICENSE_1_0.txt)</span>
|
||
|
||
<span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">iostream</span><span class="special">></span>
|
||
|
||
<span class="comment">// *************************** </span>
|
||
<span class="comment">// 1. include headers to support safe integers</span>
|
||
<span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">safe_numerics</span><span class="special">/</span><span class="identifier">cpp</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span>
|
||
<span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">safe_numerics</span><span class="special">/</span><span class="identifier">exception</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span>
|
||
<span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">safe_numerics</span><span class="special">/</span><span class="identifier">safe_integer</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span>
|
||
|
||
<span class="comment">// *************************** </span>
|
||
<span class="comment">// 2. specify a promotion policy to support proper emulation of </span>
|
||
<span class="comment">// PIC types on the desktop</span>
|
||
<span class="keyword">using</span> <span class="identifier">pic16_promotion</span> <span class="special">=</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">safe_numerics</span><span class="special">::</span><span class="identifier">cpp</span><span class="special"><</span>
|
||
<span class="number">8</span><span class="special">,</span> <span class="comment">// char 8 bits</span>
|
||
<span class="number">16</span><span class="special">,</span> <span class="comment">// short 16 bits</span>
|
||
<span class="number">16</span><span class="special">,</span> <span class="comment">// int 16 bits</span>
|
||
<span class="number">16</span><span class="special">,</span> <span class="comment">// long 16 bits</span>
|
||
<span class="number">32</span> <span class="comment">// long long 32 bits</span>
|
||
<span class="special">></span><span class="special">;</span>
|
||
|
||
<span class="comment">// 1st step=50ms; max speed=120rpm (based on 1MHz timer, 1.8deg steps)</span>
|
||
<span class="preprocessor">#define</span> <span class="identifier">C0</span> <span class="special">(</span><span class="number">50000</span> <span class="special"><<</span> <span class="number">8</span><span class="special">)</span>
|
||
<span class="preprocessor">#define</span> <span class="identifier">C_MIN</span> <span class="special">(</span><span class="number">2500</span> <span class="special"><<</span> <span class="number">8</span><span class="special">)</span>
|
||
|
||
<span class="identifier">static_assert</span><span class="special">(</span><span class="identifier">C0</span> <span class="special"><</span> <span class="number">0xffffff</span><span class="special">,</span> <span class="string">"Largest step too long"</span><span class="special">)</span><span class="special">;</span>
|
||
<span class="identifier">static_assert</span><span class="special">(</span><span class="identifier">C_MIN</span> <span class="special">></span> <span class="number">0</span><span class="special">,</span> <span class="string">"Smallest step must be greater than zero"</span><span class="special">)</span><span class="special">;</span>
|
||
<span class="identifier">static_assert</span><span class="special">(</span><span class="identifier">C_MIN</span> <span class="special"><</span> <span class="identifier">C0</span><span class="special">,</span> <span class="string">"Smallest step must be smaller than largest step"</span><span class="special">)</span><span class="special">;</span>
|
||
|
||
<span class="comment">// *************************** </span>
|
||
<span class="comment">// 3. define PIC integer type names to be safe integer types of he same size.</span>
|
||
|
||
<span class="keyword">template</span> <span class="special"><</span><span class="keyword">typename</span> <span class="identifier">T</span><span class="special">></span> <span class="comment">// T is char, int, etc data type</span>
|
||
<span class="keyword">using</span> <span class="identifier">safe_t</span> <span class="special">=</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">safe_numerics</span><span class="special">::</span><span class="identifier">safe</span><span class="special"><</span>
|
||
<span class="identifier">T</span><span class="special">,</span>
|
||
<span class="identifier">pic16_promotion</span>
|
||
<span class="special">></span><span class="special">;</span>
|
||
|
||
<span class="comment">// alias original program's integer types to corresponding PIC safe types</span>
|
||
<span class="comment">// In conjunction with the promotion policy above, this will permit us to </span>
|
||
<span class="comment">// guarantee that the resulting program will be free of arithmetic errors </span>
|
||
<span class="comment">// introduced by C expression syntax and type promotion with no runtime penalty</span>
|
||
|
||
<span class="keyword">typedef</span> <span class="identifier">safe_t</span><span class="special"><</span><span class="identifier">int8_t</span><span class="special">></span> <span class="identifier">int8</span><span class="special">;</span>
|
||
<span class="keyword">typedef</span> <span class="identifier">safe_t</span><span class="special"><</span><span class="identifier">int16_t</span><span class="special">></span> <span class="identifier">int16</span><span class="special">;</span>
|
||
<span class="keyword">typedef</span> <span class="identifier">safe_t</span><span class="special"><</span><span class="identifier">int32_t</span><span class="special">></span> <span class="identifier">int32</span><span class="special">;</span>
|
||
<span class="keyword">typedef</span> <span class="identifier">safe_t</span><span class="special"><</span><span class="identifier">uint8_t</span><span class="special">></span> <span class="identifier">uint8</span><span class="special">;</span>
|
||
<span class="keyword">typedef</span> <span class="identifier">safe_t</span><span class="special"><</span><span class="identifier">uint16_t</span><span class="special">></span> <span class="identifier">uint16</span><span class="special">;</span>
|
||
<span class="keyword">typedef</span> <span class="identifier">safe_t</span><span class="special"><</span><span class="identifier">uint32_t</span><span class="special">></span> <span class="identifier">uint32</span><span class="special">;</span>
|
||
|
||
<span class="comment">// *************************** </span>
|
||
<span class="comment">// 4. emulate PIC features on the desktop</span>
|
||
|
||
<span class="comment">// filter out special keyword used only by XC8 compiler</span>
|
||
<span class="preprocessor">#define</span> <span class="identifier">__interrupt</span>
|
||
<span class="comment">// filter out XC8 enable/disable global interrupts</span>
|
||
<span class="preprocessor">#define</span> <span class="identifier">ei</span><span class="special">(</span><span class="special">)</span>
|
||
<span class="preprocessor">#define</span> <span class="identifier">di</span><span class="special">(</span><span class="special">)</span>
|
||
|
||
<span class="comment">// emulate PIC special registers</span>
|
||
<span class="identifier">uint8</span> <span class="identifier">RCON</span><span class="special">;</span>
|
||
<span class="identifier">uint8</span> <span class="identifier">INTCON</span><span class="special">;</span>
|
||
<span class="identifier">uint8</span> <span class="identifier">CCP1IE</span><span class="special">;</span>
|
||
<span class="identifier">uint8</span> <span class="identifier">CCP2IE</span><span class="special">;</span>
|
||
<span class="identifier">uint8</span> <span class="identifier">PORTC</span><span class="special">;</span>
|
||
<span class="identifier">uint8</span> <span class="identifier">TRISC</span><span class="special">;</span>
|
||
<span class="identifier">uint8</span> <span class="identifier">T3CON</span><span class="special">;</span>
|
||
<span class="identifier">uint8</span> <span class="identifier">T1CON</span><span class="special">;</span>
|
||
|
||
<span class="identifier">uint8</span> <span class="identifier">CCPR2H</span><span class="special">;</span>
|
||
<span class="identifier">uint8</span> <span class="identifier">CCPR2L</span><span class="special">;</span>
|
||
<span class="identifier">uint8</span> <span class="identifier">CCPR1H</span><span class="special">;</span>
|
||
<span class="identifier">uint8</span> <span class="identifier">CCPR1L</span><span class="special">;</span>
|
||
<span class="identifier">uint8</span> <span class="identifier">CCP1CON</span><span class="special">;</span>
|
||
<span class="identifier">uint8</span> <span class="identifier">CCP2CON</span><span class="special">;</span>
|
||
<span class="identifier">uint8</span> <span class="identifier">TMR1H</span><span class="special">;</span>
|
||
<span class="identifier">uint8</span> <span class="identifier">TMR1L</span><span class="special">;</span>
|
||
|
||
<span class="comment">// create type used to map PIC bit names to</span>
|
||
<span class="comment">// correct bit in PIC register</span>
|
||
<span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">T</span><span class="special">,</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">int8_t</span> <span class="identifier">N</span><span class="special">></span>
|
||
<span class="keyword">struct</span> <span class="identifier">bit</span> <span class="special">{</span>
|
||
<span class="identifier">T</span> <span class="special">&</span> <span class="identifier">m_word</span><span class="special">;</span>
|
||
<span class="keyword">constexpr</span> <span class="keyword">explicit</span> <span class="identifier">bit</span><span class="special">(</span><span class="identifier">T</span> <span class="special">&</span> <span class="identifier">rhs</span><span class="special">)</span> <span class="special">:</span>
|
||
<span class="identifier">m_word</span><span class="special">(</span><span class="identifier">rhs</span><span class="special">)</span>
|
||
<span class="special">{</span><span class="special">}</span>
|
||
<span class="keyword">constexpr</span> <span class="identifier">bit</span> <span class="special">&</span> <span class="keyword">operator</span><span class="special">=</span><span class="special">(</span><span class="keyword">int</span> <span class="identifier">b</span><span class="special">)</span><span class="special">{</span>
|
||
<span class="keyword">if</span><span class="special">(</span><span class="identifier">b</span> <span class="special">!=</span> <span class="number">0</span><span class="special">)</span>
|
||
<span class="identifier">m_word</span> <span class="special">|=</span> <span class="special">(</span><span class="number">1</span> <span class="special"><<</span> <span class="identifier">N</span><span class="special">)</span><span class="special">;</span>
|
||
<span class="keyword">else</span>
|
||
<span class="identifier">m_word</span> <span class="special">&=</span> <span class="special">~</span><span class="special">(</span><span class="number">1</span> <span class="special"><<</span> <span class="identifier">N</span><span class="special">)</span><span class="special">;</span>
|
||
<span class="keyword">return</span> <span class="special">*</span><span class="keyword">this</span><span class="special">;</span>
|
||
<span class="special">}</span>
|
||
<span class="keyword">constexpr</span> <span class="keyword">operator</span> <span class="keyword">int</span> <span class="special">(</span><span class="special">)</span> <span class="keyword">const</span> <span class="special">{</span>
|
||
<span class="keyword">return</span> <span class="identifier">m_word</span> <span class="special">>></span> <span class="identifier">N</span> <span class="special">&</span> <span class="number">1</span><span class="special">;</span>
|
||
<span class="special">}</span>
|
||
<span class="special">}</span><span class="special">;</span>
|
||
|
||
<span class="comment">// define bits for T1CON register</span>
|
||
<span class="keyword">struct</span> <span class="special">{</span>
|
||
<span class="identifier">bit</span><span class="special"><</span><span class="identifier">uint8</span><span class="special">,</span> <span class="number">7</span><span class="special">></span> <span class="identifier">RD16</span><span class="special">{</span><span class="identifier">T1CON</span><span class="special">}</span><span class="special">;</span>
|
||
<span class="identifier">bit</span><span class="special"><</span><span class="identifier">uint8</span><span class="special">,</span> <span class="number">5</span><span class="special">></span> <span class="identifier">T1CKPS1</span><span class="special">{</span><span class="identifier">T1CON</span><span class="special">}</span><span class="special">;</span>
|
||
<span class="identifier">bit</span><span class="special"><</span><span class="identifier">uint8</span><span class="special">,</span> <span class="number">4</span><span class="special">></span> <span class="identifier">T1CKPS0</span><span class="special">{</span><span class="identifier">T1CON</span><span class="special">}</span><span class="special">;</span>
|
||
<span class="identifier">bit</span><span class="special"><</span><span class="identifier">uint8</span><span class="special">,</span> <span class="number">3</span><span class="special">></span> <span class="identifier">T1OSCEN</span><span class="special">{</span><span class="identifier">T1CON</span><span class="special">}</span><span class="special">;</span>
|
||
<span class="identifier">bit</span><span class="special"><</span><span class="identifier">uint8</span><span class="special">,</span> <span class="number">2</span><span class="special">></span> <span class="identifier">T1SYNC</span><span class="special">{</span><span class="identifier">T1CON</span><span class="special">}</span><span class="special">;</span>
|
||
<span class="identifier">bit</span><span class="special"><</span><span class="identifier">uint8</span><span class="special">,</span> <span class="number">1</span><span class="special">></span> <span class="identifier">TMR1CS</span><span class="special">{</span><span class="identifier">T1CON</span><span class="special">}</span><span class="special">;</span>
|
||
<span class="identifier">bit</span><span class="special"><</span><span class="identifier">uint8</span><span class="special">,</span> <span class="number">0</span><span class="special">></span> <span class="identifier">TMR1ON</span><span class="special">{</span><span class="identifier">T1CON</span><span class="special">}</span><span class="special">;</span>
|
||
<span class="special">}</span> <span class="identifier">T1CONbits</span><span class="special">;</span>
|
||
|
||
<span class="comment">// define bits for T1CON register</span>
|
||
<span class="keyword">struct</span> <span class="special">{</span>
|
||
<span class="identifier">bit</span><span class="special"><</span><span class="identifier">uint8</span><span class="special">,</span> <span class="number">7</span><span class="special">></span> <span class="identifier">GEI</span><span class="special">{</span><span class="identifier">INTCON</span><span class="special">}</span><span class="special">;</span>
|
||
<span class="identifier">bit</span><span class="special"><</span><span class="identifier">uint8</span><span class="special">,</span> <span class="number">5</span><span class="special">></span> <span class="identifier">PEIE</span><span class="special">{</span><span class="identifier">INTCON</span><span class="special">}</span><span class="special">;</span>
|
||
<span class="identifier">bit</span><span class="special"><</span><span class="identifier">uint8</span><span class="special">,</span> <span class="number">4</span><span class="special">></span> <span class="identifier">TMR0IE</span><span class="special">{</span><span class="identifier">INTCON</span><span class="special">}</span><span class="special">;</span>
|
||
<span class="identifier">bit</span><span class="special"><</span><span class="identifier">uint8</span><span class="special">,</span> <span class="number">3</span><span class="special">></span> <span class="identifier">RBIE</span><span class="special">{</span><span class="identifier">INTCON</span><span class="special">}</span><span class="special">;</span>
|
||
<span class="identifier">bit</span><span class="special"><</span><span class="identifier">uint8</span><span class="special">,</span> <span class="number">2</span><span class="special">></span> <span class="identifier">TMR0IF</span><span class="special">{</span><span class="identifier">INTCON</span><span class="special">}</span><span class="special">;</span>
|
||
<span class="identifier">bit</span><span class="special"><</span><span class="identifier">uint8</span><span class="special">,</span> <span class="number">1</span><span class="special">></span> <span class="identifier">INT0IF</span><span class="special">{</span><span class="identifier">INTCON</span><span class="special">}</span><span class="special">;</span>
|
||
<span class="identifier">bit</span><span class="special"><</span><span class="identifier">uint8</span><span class="special">,</span> <span class="number">0</span><span class="special">></span> <span class="identifier">RBIF</span><span class="special">{</span><span class="identifier">INTCON</span><span class="special">}</span><span class="special">;</span>
|
||
<span class="special">}</span> <span class="identifier">INTCONbits</span><span class="special">;</span>
|
||
|
||
<span class="comment">// ***************************</span>
|
||
<span class="comment">// 5. include the environment independent code we want to test</span>
|
||
<span class="preprocessor">#include</span> <span class="string">"motor2.c"</span>
|
||
|
||
<span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">chrono</span><span class="special">></span>
|
||
<span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">thread</span><span class="special">></span>
|
||
|
||
<span class="comment">// round 24.8 format to microseconds</span>
|
||
<span class="identifier">int32</span> <span class="identifier">to_microseconds</span><span class="special">(</span><span class="identifier">uint32</span> <span class="identifier">t</span><span class="special">)</span><span class="special">{</span>
|
||
<span class="keyword">return</span> <span class="special">(</span><span class="identifier">t</span> <span class="special">+</span> <span class="number">128</span><span class="special">)</span> <span class="special">/</span> <span class="number">256</span><span class="special">;</span>
|
||
<span class="special">}</span>
|
||
|
||
<span class="keyword">using</span> <span class="identifier">result_t</span> <span class="special">=</span> <span class="identifier">uint8_t</span><span class="special">;</span>
|
||
<span class="keyword">const</span> <span class="identifier">result_t</span> <span class="identifier">success</span> <span class="special">=</span> <span class="number">1</span><span class="special">;</span>
|
||
<span class="keyword">const</span> <span class="identifier">result_t</span> <span class="identifier">fail</span> <span class="special">=</span> <span class="number">0</span><span class="special">;</span>
|
||
|
||
<span class="comment">// move motor to the indicated target position in steps</span>
|
||
<span class="identifier">result_t</span> <span class="identifier">test</span><span class="special">(</span><span class="identifier">int32</span> <span class="identifier">m</span><span class="special">)</span><span class="special">{</span>
|
||
<span class="keyword">try</span> <span class="special">{</span>
|
||
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="string">"move motor to "</span> <span class="special"><<</span> <span class="identifier">m</span> <span class="special"><<</span> <span class="char">'\n'</span><span class="special">;</span>
|
||
<span class="identifier">motor_run</span><span class="special">(</span><span class="identifier">m</span><span class="special">)</span><span class="special">;</span>
|
||
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span>
|
||
<span class="special"><<</span> <span class="string">"step #"</span> <span class="special"><<</span> <span class="char">' '</span>
|
||
<span class="special"><<</span> <span class="string">"delay(us)(24.8)"</span> <span class="special"><<</span> <span class="char">' '</span>
|
||
<span class="special"><<</span> <span class="string">"delay(us)"</span> <span class="special"><<</span> <span class="char">' '</span>
|
||
<span class="special"><<</span> <span class="string">"CCPR"</span> <span class="special"><<</span> <span class="char">' '</span>
|
||
<span class="special"><<</span> <span class="string">"motor position"</span> <span class="special"><<</span> <span class="char">'\n'</span><span class="special">;</span>
|
||
<span class="keyword">do</span><span class="special">{</span>
|
||
<span class="identifier">std</span><span class="special">::</span><span class="identifier">this_thread</span><span class="special">::</span><span class="identifier">sleep_for</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">chrono</span><span class="special">::</span><span class="identifier">microseconds</span><span class="special">(</span><span class="identifier">to_microseconds</span><span class="special">(</span><span class="identifier">c</span><span class="special">)</span><span class="special">)</span><span class="special">)</span><span class="special">;</span>
|
||
<span class="identifier">uint32</span> <span class="identifier">last_c</span> <span class="special">=</span> <span class="identifier">c</span><span class="special">;</span>
|
||
<span class="identifier">uint32</span> <span class="identifier">last_ccpr</span> <span class="special">=</span> <span class="identifier">ccpr</span><span class="special">;</span>
|
||
<span class="identifier">isr_motor_step</span><span class="special">(</span><span class="special">)</span><span class="special">;</span>
|
||
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span>
|
||
<span class="special"><<</span> <span class="identifier">step_no</span> <span class="special"><<</span> <span class="char">' '</span>
|
||
<span class="special"><<</span> <span class="identifier">last_c</span> <span class="special"><<</span> <span class="char">' '</span>
|
||
<span class="special"><<</span> <span class="identifier">to_microseconds</span><span class="special">(</span><span class="identifier">last_c</span><span class="special">)</span> <span class="special"><<</span> <span class="char">' '</span>
|
||
<span class="special"><<</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">hex</span> <span class="special"><<</span> <span class="identifier">last_ccpr</span> <span class="special"><<</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">dec</span> <span class="special"><<</span> <span class="char">' '</span>
|
||
<span class="special"><<</span> <span class="identifier">motor_pos</span> <span class="special"><<</span> <span class="char">'\n'</span><span class="special">;</span>
|
||
<span class="special">}</span><span class="keyword">while</span><span class="special">(</span><span class="identifier">run_flg</span><span class="special">)</span><span class="special">;</span>
|
||
<span class="special">}</span>
|
||
<span class="keyword">catch</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">exception</span> <span class="special">&</span> <span class="identifier">e</span><span class="special">)</span><span class="special">{</span>
|
||
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="identifier">e</span><span class="special">.</span><span class="identifier">what</span><span class="special">(</span><span class="special">)</span> <span class="special"><<</span> <span class="char">'\n'</span><span class="special">;</span>
|
||
<span class="keyword">return</span> <span class="identifier">fail</span><span class="special">;</span>
|
||
<span class="special">}</span>
|
||
<span class="keyword">return</span> <span class="identifier">success</span><span class="special">;</span>
|
||
<span class="special">}</span>
|
||
|
||
<span class="keyword">int</span> <span class="identifier">main</span><span class="special">(</span><span class="special">)</span><span class="special">{</span>
|
||
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="string">"start test\n"</span><span class="special">;</span>
|
||
<span class="identifier">result_t</span> <span class="identifier">result</span> <span class="special">=</span> <span class="identifier">success</span><span class="special">;</span>
|
||
<span class="keyword">try</span><span class="special">{</span>
|
||
<span class="identifier">initialize</span><span class="special">(</span><span class="special">)</span><span class="special">;</span>
|
||
<span class="comment">// move motor to position 1000</span>
|
||
<span class="identifier">result</span> <span class="special">&=</span> <span class="identifier">test</span><span class="special">(</span><span class="number">1000</span><span class="special">)</span><span class="special">;</span>
|
||
<span class="comment">// move motor to position 200</span>
|
||
<span class="identifier">result</span> <span class="special">&=</span> <span class="identifier">test</span><span class="special">(</span><span class="number">200</span><span class="special">)</span><span class="special">;</span>
|
||
<span class="comment">// move motor to position 200 again! Should result in no movement.</span>
|
||
<span class="identifier">result</span> <span class="special">&=</span> <span class="identifier">test</span><span class="special">(</span><span class="number">200</span><span class="special">)</span><span class="special">;</span>
|
||
<span class="comment">// move back to position 0</span>
|
||
<span class="identifier">result</span> <span class="special">&=</span> <span class="identifier">test</span><span class="special">(</span><span class="number">0</span><span class="special">)</span><span class="special">;</span>
|
||
<span class="comment">// ***************************</span>
|
||
<span class="comment">// 6. error detected here! data types can't handle enough</span>
|
||
<span class="comment">// steps to move the carriage from end to end! Suppress this</span>
|
||
<span class="comment">// test for now.</span>
|
||
<span class="comment">// move motor to position 50000.</span>
|
||
<span class="comment">// result &= test(50000);</span>
|
||
<span class="comment">// move motor back to position 0.</span>
|
||
<span class="identifier">result</span> <span class="special">&=</span> <span class="identifier">test</span><span class="special">(</span><span class="number">0</span><span class="special">)</span><span class="special">;</span>
|
||
<span class="special">}</span>
|
||
<span class="keyword">catch</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">exception</span> <span class="special">&</span> <span class="identifier">e</span><span class="special">)</span><span class="special">{</span>
|
||
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="identifier">e</span><span class="special">.</span><span class="identifier">what</span><span class="special">(</span><span class="special">)</span> <span class="special"><<</span> <span class="char">'\n'</span><span class="special">;</span>
|
||
<span class="keyword">return</span> <span class="number">1</span><span class="special">;</span>
|
||
<span class="special">}</span>
|
||
<span class="keyword">catch</span><span class="special">(</span><span class="special">...</span><span class="special">)</span><span class="special">{</span>
|
||
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="string">"test interrupted\n"</span><span class="special">;</span>
|
||
<span class="keyword">return</span> <span class="identifier">EXIT_FAILURE</span><span class="special">;</span>
|
||
<span class="special">}</span>
|
||
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="string">"end test\n"</span><span class="special">;</span>
|
||
<span class="keyword">return</span> <span class="identifier">result</span> <span class="special">==</span> <span class="identifier">success</span> <span class="special">?</span> <span class="identifier">EXIT_SUCCESS</span> <span class="special">:</span> <span class="identifier">EXIT_FAILURE</span><span class="special">;</span>
|
||
<span class="special">}</span>
|
||
</pre>
|
||
<p>Here are the essential features of the desktop version of the test
|
||
program.</p>
|
||
<div class="orderedlist"><ol class="orderedlist" type="1">
|
||
<li class="listitem"><p>Include headers required to support safe integers.</p></li>
|
||
<li class="listitem">
|
||
<p>Specify a <a class="link" href="promotion_policy.html" title="PromotionPolicy<PP>">promotion policy</a> to
|
||
support proper emulation of PIC types on the desktop.</p>
|
||
<p>The C language standard doesn't specify sizes for primitive
|
||
data types like <code class="computeroutput">int</code>. They can and do differ between
|
||
environments. Hence, the characterization of C/C++ as "portable"
|
||
languages is not strictly true. Here we choose aliases for data
|
||
types so that they can be defined to be the same in both
|
||
environments. But this is not enough to emulate the <a href="http://www.microchip.com/wwwproducts/en/PIC18F2520" target="_top">PIC18F2520</a>
|
||
on the desktop. The problem is that compilers implicitly convert
|
||
arguments of C expressions to some common type before performing
|
||
arithmetic operations. Often, this common type is the native
|
||
<code class="computeroutput">int</code> and the size of this native type is different in
|
||
the desktop and embedded environment. Thus, many arithmetic results
|
||
would be different in the two environments.</p>
|
||
<p>But now we can specify our own implicit promotion rules for
|
||
test programs on the development platform that are identical to
|
||
those on the target environment! So unit testing executed in the
|
||
development environment can now provide results relevant to the
|
||
target environment.</p>
|
||
</li>
|
||
<li class="listitem">
|
||
<p>Define PIC integer type aliases to be safe integer types of he
|
||
same size.</p>
|
||
<p>Code tested in the development environment will use safe
|
||
numerics to detect errors. We need these aliases to permit the code
|
||
in <a href="../../example/motor2.c" target="_top">motor2.c</a> to be tested
|
||
in the desktop environment. The same code run in the target system
|
||
without change.</p>
|
||
</li>
|
||
<li class="listitem">
|
||
<p>Emulate PIC features on the desktop.</p>
|
||
<p>The PIC processor, in common with most micro controllers these
|
||
days, includes a myriad of special purpose peripherals to handle
|
||
things like interrupts, USB, timers, SPI bus, I^2C bus, etc.. These
|
||
peripherals are configured using special 8 bit words in reserved
|
||
memory locations. Configuration consists of setting particular bits
|
||
in these words. To facilitate configuration operations, the XC8
|
||
compiler includes a special syntax for setting and accessing bits in
|
||
these locations. One of our goals is to permit the testing of the
|
||
identical code with our desktop C++ compiler as will run on the
|
||
micro controller. To realize this goal, we create some C++ code
|
||
which implements the XC8 C syntax for setting bits in particular
|
||
memory locations.</p>
|
||
</li>
|
||
<li class="listitem"><p>include <a href="../../example/motor1.c" target="_top">motor1.c</a></p></li>
|
||
<li class="listitem"><p>Add test to verify that the motor will be able to keep track
|
||
of a position from 0 to 50000 steps. This will be needed to maintain
|
||
the position of out linear stage across a range from 0 to 500
|
||
mm.</p></li>
|
||
</ol></div>
|
||
<p>Our first attempt to run this program fails by throwing an exception
|
||
from <a href="../../example/motor1.c" target="_top">motor1.c</a> indicating that
|
||
the code attempts to left shift a negative number at the
|
||
statements:</p>
|
||
<pre class="programlisting"><span class="identifier">denom</span> <span class="special">=</span> <span class="special">(</span><span class="special">(</span><span class="identifier">step_no</span> <span class="special">-</span> <span class="identifier">move</span><span class="special">)</span> <span class="special"><<</span> <span class="number">2</span><span class="special">)</span> <span class="special">+</span> <span class="number">1</span><span class="special">;</span></pre>
|
||
<p>According to the C/C++ standards this is implementation defined
|
||
behavior. But in practice with all modern platforms (as far as I know),
|
||
this will be equivalent to a multiplication by 4. Clearly the intent of
|
||
the original author is to "micro optimize" the operation by substituting a
|
||
cheap left shift for a potentially expensive integer multiplication. But
|
||
on all modern compilers, this substitution will be performed automatically
|
||
by the compiler's optimizer. So we have two alternatives here:</p>
|
||
<div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; ">
|
||
<li class="listitem">
|
||
<p>Just ignore the issue.</p>
|
||
<p>This will work when the code is run on the PIC. But, in order to
|
||
permit testing on the desktop, we need to inhibit the error detection
|
||
in that environment. With safe numerics, error handling is determined
|
||
by specifying an <a class="link" href="exception_policy.html" title="ExceptionPolicy<EP>">exception policy</a>. In
|
||
this example, we've used the default exception policy which traps
|
||
implementation defined behavior. To ignore this kind of behavior we
|
||
could define our own custom <a class="link" href="exception_policy.html" title="ExceptionPolicy<EP>">exception
|
||
policy</a>.</p>
|
||
</li>
|
||
<li class="listitem"><p>change the <code class="computeroutput"><< 2</code> to <code class="computeroutput">* 4</code>. This
|
||
will produce the intended result in an unambiguous, portable way. For
|
||
all known compilers, this change should not affect runtime performance
|
||
in any way. It will result in unambiguously portable code.</p></li>
|
||
<li class="listitem"><p>Alter the code so that the expression in question is never
|
||
negative. Depending on sizes of the operands and the size of the
|
||
native integer, this expression might return convert the operands to
|
||
int or result in an invalid result.</p></li>
|
||
</ul></div>
|
||
<p>Of these alternatives, the third seems the more definitive fix so
|
||
we'll choose that one. We also decide to make a couple of minor changes to
|
||
simplify the code and make mapping of the algorithm in the article to the
|
||
code more transparent. With these changes, our test program runs to the
|
||
end with no errors or exceptions. In addition, I made a minor change which
|
||
simplifies the handling of floating point values in format of 24.8. This
|
||
results in <a href="../../example/motor2.c" target="_top">motor2.c</a> which
|
||
makes the above changes. It should be easy to see that these two versions
|
||
are otherwise identical.</p>
|
||
<p>Finally our range test fails. In order to handle the full range we
|
||
need, we'll have to change some data types used for holding step count and
|
||
position. We won't do that here as it would make our example too complex.
|
||
We'll deal with this on the next version.</p>
|
||
</div>
|
||
<div class="section">
|
||
<div class="titlepage"><div><div><h4 class="title">
|
||
<a name="idm488728235264"></a>Trapping Errors at Compile Time</h4></div></div></div>
|
||
<p>We can test the same code we're going to load into our target system
|
||
on the desktop. We could build and execute a complete unit test suite. We
|
||
could capture the output and graph it. We have the ability to make are
|
||
code much more likely to be bug free. But:</p>
|
||
<div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; ">
|
||
<li class="listitem"><p>This system detects errors and exceptions on the test machine -
|
||
but it fails to address and detect such problems on the target system.
|
||
Since the target system is compiles only C code, we can't use the
|
||
exception/error facilities of this library at runtime.</p></li>
|
||
<li class="listitem"><p><a href="https://en.wikiquote.org/wiki/Edsger_W._Dijkstra" target="_top">Testing shows
|
||
the presence, not the absence of bugs</a>. Can we not prove that
|
||
all integer arithmetic is correct?</p></li>
|
||
<li class="listitem"><p>For at least some operations on safe integers there is runtime
|
||
cost in checking for errors. In this example, this is not really a
|
||
problem as the safe integer code is not included when the code is run
|
||
on the target - it's only a C compiler after all. But more generally,
|
||
using safe integers might incur an undesired runtime cost.</p></li>
|
||
</ul></div>
|
||
<p>Can we catch all potential problems at compiler time and therefore
|
||
eliminate all runtime cost?</p>
|
||
<p>Our first attempt consists of simply changing default exception
|
||
policy from the default runtime checking to the compile time trapping one.
|
||
Then we redefine the aliases for the types used by the PIC to use this
|
||
exception policy.</p>
|
||
<pre class="programlisting"><span class="comment">// generate compile time errors if operation could fail </span>
|
||
<span class="keyword">using</span> <span class="identifier">trap_policy</span> <span class="special">=</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">numeric</span><span class="special">::</span><span class="identifier">loose_trap_policy</span><span class="special">;</span>
|
||
<span class="special">...</span>
|
||
<span class="keyword">typedef</span> <span class="identifier">safe_t</span><span class="special"><</span><span class="identifier">int8_t</span><span class="special">,</span> <span class="identifier">trap_policy</span><span class="special">></span> <span class="identifier">int8</span><span class="special">;</span>
|
||
<span class="special">...</span>
|
||
</pre>
|
||
<p>When we compile now, any expressions which could possibly fail will
|
||
be flagged as syntax errors. This occurs 11 times when compiling the
|
||
<a href="../../example/motor2.c" target="_top">motor2.c</a> program. This is
|
||
fewer than one might expect. To understand why, consider the following
|
||
example:</p>
|
||
<pre class="programlisting"><span class="identifier">safe</span><span class="special"><</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">int8_t</span><span class="special">></span> <span class="identifier">x</span><span class="special">,</span> <span class="identifier">y</span><span class="special">;</span>
|
||
<span class="special">...</span>
|
||
<span class="identifier">safe</span><span class="special"><</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">int16_t</span><span class="special">></span> <span class="identifier">z</span> <span class="special">=</span> <span class="identifier">x</span> <span class="special">+</span> <span class="identifier">y</span><span class="special">;</span>
|
||
</pre>
|
||
<p>C promotion rules and arithmetic are such that the z will
|
||
always contain an arithmetically correct result regardless of what values
|
||
are assigned to x and y. Hence there is no need for any kind of checking
|
||
of the arithmetic or result. The Safe Numerics library uses compile time
|
||
range arithmetic, C++ template multiprogramming and other techniques to
|
||
restrict invocation of checking code to only those operations which could
|
||
possible fail. So the above code incurs no runtime overhead.</p>
|
||
<p>Now we have 11 cases to consider. Our goal is to modify the program
|
||
so that this number of cases is reduced - hopefully to zero. Initially I
|
||
wanted to just make a few tweaks in the versions of
|
||
<code class="computeroutput">example92.c</code>, <code class="computeroutput">motor2.c</code> and
|
||
<code class="computeroutput">motor_test2.c</code> above without actually having to understand the
|
||
code. It turns out that one needs to carefully consider what various types
|
||
and variables are used for. This can be a good thing or a bad thing
|
||
depending on one's circumstances, goals and personality. The programs
|
||
above evolved into <a href="../../example/example93.c" target="_top"><code class="computeroutput">example93.c</code></a>,
|
||
<code class="computeroutput"><a href="../../example/motor3.c" target="_top">motor3.c</a></code> and
|
||
<a href="../../example/motor_test3.c" target="_top"><code class="computeroutput">motor_test3.c</code></a>.
|
||
First we'll look at <code class="computeroutput">example93.c</code>:</p>
|
||
<pre class="programlisting"><span class="comment">//////////////////////////////////////////////////////////////////</span>
|
||
<span class="comment">// example93.cpp</span>
|
||
<span class="comment">//</span>
|
||
<span class="comment">// Copyright (c) 2015 Robert Ramey</span>
|
||
<span class="comment">//</span>
|
||
<span class="comment">// Distributed under the Boost Software License, Version 1.0. (See</span>
|
||
<span class="comment">// accompanying file LICENSE_1_0.txt or copy at</span>
|
||
<span class="comment">// http://www.boost.org/LICENSE_1_0.txt)</span>
|
||
|
||
<span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">iostream</span><span class="special">></span>
|
||
|
||
<span class="comment">// include headers to support safe integers</span>
|
||
<span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">safe_numerics</span><span class="special">/</span><span class="identifier">cpp</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span>
|
||
<span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">safe_numerics</span><span class="special">/</span><span class="identifier">exception</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span>
|
||
<span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">safe_numerics</span><span class="special">/</span><span class="identifier">safe_integer</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span>
|
||
<span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">safe_numerics</span><span class="special">/</span><span class="identifier">safe_integer_range</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span>
|
||
<span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">safe_numerics</span><span class="special">/</span><span class="identifier">safe_integer_literal</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span>
|
||
|
||
<span class="comment">// use same type promotion as used by the pic compiler</span>
|
||
<span class="comment">// target compiler XC8 supports:</span>
|
||
<span class="keyword">using</span> <span class="identifier">pic16_promotion</span> <span class="special">=</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">safe_numerics</span><span class="special">::</span><span class="identifier">cpp</span><span class="special"><</span>
|
||
<span class="number">8</span><span class="special">,</span> <span class="comment">// char 8 bits</span>
|
||
<span class="number">16</span><span class="special">,</span> <span class="comment">// short 16 bits</span>
|
||
<span class="number">16</span><span class="special">,</span> <span class="comment">// int 16 bits</span>
|
||
<span class="number">16</span><span class="special">,</span> <span class="comment">// long 16 bits</span>
|
||
<span class="number">32</span> <span class="comment">// long long 32 bits</span>
|
||
<span class="special">></span><span class="special">;</span>
|
||
|
||
<span class="comment">// ***************************</span>
|
||
<span class="comment">// 1. Specify exception policies so we will generate a</span>
|
||
<span class="comment">// compile time error whenever an operation MIGHT fail.</span>
|
||
|
||
<span class="comment">// ***************************</span>
|
||
<span class="comment">// generate runtime errors if operation could fail</span>
|
||
<span class="keyword">using</span> <span class="identifier">exception_policy</span> <span class="special">=</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">safe_numerics</span><span class="special">::</span><span class="identifier">default_exception_policy</span><span class="special">;</span>
|
||
|
||
<span class="comment">// generate compile time errors if operation could fail</span>
|
||
<span class="keyword">using</span> <span class="identifier">trap_policy</span> <span class="special">=</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">safe_numerics</span><span class="special">::</span><span class="identifier">loose_trap_policy</span><span class="special">;</span>
|
||
|
||
<span class="comment">// ***************************</span>
|
||
<span class="comment">// 2. Create a macro named literal an integral value</span>
|
||
<span class="comment">// that can be evaluated at compile time.</span>
|
||
<span class="preprocessor">#define</span> <span class="identifier">literal</span><span class="special">(</span><span class="identifier">n</span><span class="special">)</span> <span class="identifier">make_safe_literal</span><span class="special">(</span><span class="identifier">n</span><span class="special">,</span> <span class="identifier">pic16_promotion</span><span class="special">,</span> <span class="keyword">void</span><span class="special">)</span>
|
||
|
||
<span class="comment">// For min speed of 2 mm / sec (24.8 format)</span>
|
||
<span class="comment">// sec / step = sec / 2 mm * 2 mm / rotation * rotation / 200 steps</span>
|
||
<span class="preprocessor">#define</span> <span class="identifier">C0</span> <span class="identifier">literal</span><span class="special">(</span><span class="number">5000</span> <span class="special"><<</span> <span class="number">8</span><span class="special">)</span>
|
||
|
||
<span class="comment">// For max speed of 400 mm / sec</span>
|
||
<span class="comment">// sec / step = sec / 400 mm * 2 mm / rotation * rotation / 200 steps</span>
|
||
<span class="preprocessor">#define</span> <span class="identifier">C_MIN</span> <span class="identifier">literal</span><span class="special">(</span><span class="number">25</span> <span class="special"><<</span> <span class="number">8</span><span class="special">)</span>
|
||
|
||
<span class="identifier">static_assert</span><span class="special">(</span>
|
||
<span class="identifier">C0</span> <span class="special"><</span> <span class="identifier">make_safe_literal</span><span class="special">(</span><span class="number">0xffffff</span><span class="special">,</span> <span class="identifier">pic16_promotion</span><span class="special">,</span><span class="identifier">trap_policy</span><span class="special">)</span><span class="special">,</span>
|
||
<span class="string">"Largest step too long"</span>
|
||
<span class="special">)</span><span class="special">;</span>
|
||
<span class="identifier">static_assert</span><span class="special">(</span>
|
||
<span class="identifier">C_MIN</span> <span class="special">></span> <span class="identifier">make_safe_literal</span><span class="special">(</span><span class="number">0</span><span class="special">,</span> <span class="identifier">pic16_promotion</span><span class="special">,</span><span class="identifier">trap_policy</span><span class="special">)</span><span class="special">,</span>
|
||
<span class="string">"Smallest step must be greater than zero"</span>
|
||
<span class="special">)</span><span class="special">;</span>
|
||
|
||
<span class="comment">// ***************************</span>
|
||
<span class="comment">// 3. Create special ranged types for the motor program</span>
|
||
<span class="comment">// These wiil guarantee that values are in the expected</span>
|
||
<span class="comment">// ranges and permit compile time determination of when</span>
|
||
<span class="comment">// exceptional conditions might occur.</span>
|
||
|
||
<span class="keyword">using</span> <span class="identifier">pic_register_t</span> <span class="special">=</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">safe_numerics</span><span class="special">::</span><span class="identifier">safe</span><span class="special"><</span>
|
||
<span class="identifier">uint8_t</span><span class="special">,</span>
|
||
<span class="identifier">pic16_promotion</span><span class="special">,</span>
|
||
<span class="identifier">trap_policy</span> <span class="comment">// use for compiling and running tests</span>
|
||
<span class="special">></span><span class="special">;</span>
|
||
|
||
<span class="comment">// note: the maximum value of step_t would be:</span>
|
||
<span class="comment">// 50000 = 500 mm / 2 mm/rotation * 200 steps/rotation.</span>
|
||
<span class="comment">// But in one expression the value of number of steps * 4 is</span>
|
||
<span class="comment">// used. To prevent introduction of error, permit this</span>
|
||
<span class="comment">// type to hold the larger value.</span>
|
||
<span class="keyword">using</span> <span class="identifier">step_t</span> <span class="special">=</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">safe_numerics</span><span class="special">::</span><span class="identifier">safe_unsigned_range</span><span class="special"><</span>
|
||
<span class="number">0</span><span class="special">,</span>
|
||
<span class="number">200000</span><span class="special">,</span>
|
||
<span class="identifier">pic16_promotion</span><span class="special">,</span>
|
||
<span class="identifier">exception_policy</span>
|
||
<span class="special">></span><span class="special">;</span>
|
||
|
||
<span class="comment">// position</span>
|
||
<span class="keyword">using</span> <span class="identifier">position_t</span> <span class="special">=</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">safe_numerics</span><span class="special">::</span><span class="identifier">safe_unsigned_range</span><span class="special"><</span>
|
||
<span class="number">0</span><span class="special">,</span>
|
||
<span class="number">50000</span><span class="special">,</span> <span class="comment">// 500 mm / 2 mm/rotation * 200 steps/rotation</span>
|
||
<span class="identifier">pic16_promotion</span><span class="special">,</span>
|
||
<span class="identifier">exception_policy</span>
|
||
<span class="special">></span><span class="special">;</span>
|
||
|
||
<span class="comment">// next end of step timer value in format 24.8</span>
|
||
<span class="comment">// where the .8 is the number of bits in the fractional part.</span>
|
||
<span class="keyword">using</span> <span class="identifier">ccpr_t</span> <span class="special">=</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">safe_numerics</span><span class="special">::</span><span class="identifier">safe</span><span class="special"><</span>
|
||
<span class="identifier">uint32_t</span><span class="special">,</span>
|
||
<span class="identifier">pic16_promotion</span><span class="special">,</span>
|
||
<span class="identifier">exception_policy</span>
|
||
<span class="special">></span><span class="special">;</span>
|
||
|
||
<span class="comment">// pulse length in format 24.8</span>
|
||
<span class="comment">// note: this value is constrainted to be a positive value. But</span>
|
||
<span class="comment">// we still need to make it a signed type. We get an arithmetic</span>
|
||
<span class="comment">// error when moving to a negative step number.</span>
|
||
<span class="keyword">using</span> <span class="identifier">c_t</span> <span class="special">=</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">safe_numerics</span><span class="special">::</span><span class="identifier">safe_unsigned_range</span><span class="special"><</span>
|
||
<span class="identifier">C_MIN</span><span class="special">,</span>
|
||
<span class="identifier">C0</span><span class="special">,</span>
|
||
<span class="identifier">pic16_promotion</span><span class="special">,</span>
|
||
<span class="identifier">exception_policy</span>
|
||
<span class="special">></span><span class="special">;</span>
|
||
|
||
<span class="comment">// 32 bit unsigned integer used for temporary purposes</span>
|
||
<span class="keyword">using</span> <span class="identifier">temp_t</span> <span class="special">=</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">safe_numerics</span><span class="special">::</span><span class="identifier">safe_unsigned_range</span><span class="special"><</span>
|
||
<span class="number">0</span><span class="special">,</span> <span class="number">0xffffffff</span><span class="special">,</span>
|
||
<span class="identifier">pic16_promotion</span><span class="special">,</span>
|
||
<span class="identifier">exception_policy</span>
|
||
<span class="special">></span><span class="special">;</span>
|
||
|
||
<span class="comment">// index into phase table</span>
|
||
<span class="comment">// note: The legal values are 0-3. So why must this be a signed</span>
|
||
<span class="comment">// type? Turns out that expressions like phase_ix + d</span>
|
||
<span class="comment">// will convert both operands to unsigned. This in turn will</span>
|
||
<span class="comment">// create an exception. So leave it signed even though the</span>
|
||
<span class="comment">// value is greater than zero.</span>
|
||
<span class="keyword">using</span> <span class="identifier">phase_ix_t</span> <span class="special">=</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">safe_numerics</span><span class="special">::</span><span class="identifier">safe_signed_range</span><span class="special"><</span>
|
||
<span class="number">0</span><span class="special">,</span>
|
||
<span class="number">3</span><span class="special">,</span>
|
||
<span class="identifier">pic16_promotion</span><span class="special">,</span>
|
||
<span class="identifier">trap_policy</span>
|
||
<span class="special">></span><span class="special">;</span>
|
||
|
||
<span class="comment">// settings for control value output</span>
|
||
|
||
<span class="keyword">using</span> <span class="identifier">phase_t</span> <span class="special">=</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">safe_numerics</span><span class="special">::</span><span class="identifier">safe</span><span class="special"><</span>
|
||
<span class="identifier">uint16_t</span><span class="special">,</span>
|
||
<span class="identifier">pic16_promotion</span><span class="special">,</span>
|
||
<span class="identifier">trap_policy</span>
|
||
<span class="special">></span><span class="special">;</span>
|
||
|
||
<span class="comment">// direction of rotation</span>
|
||
<span class="keyword">using</span> <span class="identifier">direction_t</span> <span class="special">=</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">safe_numerics</span><span class="special">::</span><span class="identifier">safe_signed_range</span><span class="special"><</span>
|
||
<span class="special">-</span><span class="number">1</span><span class="special">,</span>
|
||
<span class="special">+</span><span class="number">1</span><span class="special">,</span>
|
||
<span class="identifier">pic16_promotion</span><span class="special">,</span>
|
||
<span class="identifier">trap_policy</span>
|
||
<span class="special">></span><span class="special">;</span>
|
||
|
||
<span class="comment">// some number of microseconds</span>
|
||
<span class="keyword">using</span> <span class="identifier">microseconds</span> <span class="special">=</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">safe_numerics</span><span class="special">::</span><span class="identifier">safe</span><span class="special"><</span>
|
||
<span class="identifier">uint32_t</span><span class="special">,</span>
|
||
<span class="identifier">pic16_promotion</span><span class="special">,</span>
|
||
<span class="identifier">trap_policy</span>
|
||
<span class="special">></span><span class="special">;</span>
|
||
|
||
<span class="comment">// *************************** </span>
|
||
<span class="comment">// emulate PIC features on the desktop</span>
|
||
|
||
<span class="comment">// filter out special keyword used only by XC8 compiler</span>
|
||
<span class="preprocessor">#define</span> <span class="identifier">__interrupt</span>
|
||
<span class="comment">// filter out XC8 enable/disable global interrupts</span>
|
||
<span class="preprocessor">#define</span> <span class="identifier">ei</span><span class="special">(</span><span class="special">)</span>
|
||
<span class="preprocessor">#define</span> <span class="identifier">di</span><span class="special">(</span><span class="special">)</span>
|
||
|
||
<span class="comment">// emulate PIC special registers</span>
|
||
<span class="identifier">pic_register_t</span> <span class="identifier">RCON</span><span class="special">;</span>
|
||
<span class="identifier">pic_register_t</span> <span class="identifier">INTCON</span><span class="special">;</span>
|
||
<span class="identifier">pic_register_t</span> <span class="identifier">CCP1IE</span><span class="special">;</span>
|
||
<span class="identifier">pic_register_t</span> <span class="identifier">CCP2IE</span><span class="special">;</span>
|
||
<span class="identifier">pic_register_t</span> <span class="identifier">PORTC</span><span class="special">;</span>
|
||
<span class="identifier">pic_register_t</span> <span class="identifier">TRISC</span><span class="special">;</span>
|
||
<span class="identifier">pic_register_t</span> <span class="identifier">T3CON</span><span class="special">;</span>
|
||
<span class="identifier">pic_register_t</span> <span class="identifier">T1CON</span><span class="special">;</span>
|
||
|
||
<span class="identifier">pic_register_t</span> <span class="identifier">CCPR2H</span><span class="special">;</span>
|
||
<span class="identifier">pic_register_t</span> <span class="identifier">CCPR2L</span><span class="special">;</span>
|
||
<span class="identifier">pic_register_t</span> <span class="identifier">CCPR1H</span><span class="special">;</span>
|
||
<span class="identifier">pic_register_t</span> <span class="identifier">CCPR1L</span><span class="special">;</span>
|
||
<span class="identifier">pic_register_t</span> <span class="identifier">CCP1CON</span><span class="special">;</span>
|
||
<span class="identifier">pic_register_t</span> <span class="identifier">CCP2CON</span><span class="special">;</span>
|
||
<span class="identifier">pic_register_t</span> <span class="identifier">TMR1H</span><span class="special">;</span>
|
||
<span class="identifier">pic_register_t</span> <span class="identifier">TMR1L</span><span class="special">;</span>
|
||
|
||
<span class="comment">// ***************************</span>
|
||
<span class="comment">// special checked type for bits - values restricted to 0 or 1</span>
|
||
<span class="keyword">using</span> <span class="identifier">safe_bit_t</span> <span class="special">=</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">safe_numerics</span><span class="special">::</span><span class="identifier">safe_unsigned_range</span><span class="special"><</span>
|
||
<span class="number">0</span><span class="special">,</span>
|
||
<span class="number">1</span><span class="special">,</span>
|
||
<span class="identifier">pic16_promotion</span><span class="special">,</span>
|
||
<span class="identifier">trap_policy</span>
|
||
<span class="special">></span><span class="special">;</span>
|
||
|
||
<span class="comment">// create type used to map PIC bit names to</span>
|
||
<span class="comment">// correct bit in PIC register</span>
|
||
<span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">T</span><span class="special">,</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">int8_t</span> <span class="identifier">N</span><span class="special">></span>
|
||
<span class="keyword">struct</span> <span class="identifier">bit</span> <span class="special">{</span>
|
||
<span class="identifier">T</span> <span class="special">&</span> <span class="identifier">m_word</span><span class="special">;</span>
|
||
<span class="keyword">constexpr</span> <span class="keyword">explicit</span> <span class="identifier">bit</span><span class="special">(</span><span class="identifier">T</span> <span class="special">&</span> <span class="identifier">rhs</span><span class="special">)</span> <span class="special">:</span>
|
||
<span class="identifier">m_word</span><span class="special">(</span><span class="identifier">rhs</span><span class="special">)</span>
|
||
<span class="special">{</span><span class="special">}</span>
|
||
<span class="comment">// special functions for assignment of literal</span>
|
||
<span class="keyword">constexpr</span> <span class="identifier">bit</span> <span class="special">&</span> <span class="keyword">operator</span><span class="special">=</span><span class="special">(</span><span class="keyword">decltype</span><span class="special">(</span><span class="identifier">literal</span><span class="special">(</span><span class="number">1</span><span class="special">)</span><span class="special">)</span><span class="special">)</span><span class="special">{</span>
|
||
<span class="identifier">m_word</span> <span class="special">|=</span> <span class="identifier">literal</span><span class="special">(</span><span class="number">1</span> <span class="special"><<</span> <span class="identifier">N</span><span class="special">)</span><span class="special">;</span>
|
||
<span class="keyword">return</span> <span class="special">*</span><span class="keyword">this</span><span class="special">;</span>
|
||
<span class="special">}</span>
|
||
<span class="keyword">constexpr</span> <span class="identifier">bit</span> <span class="special">&</span> <span class="keyword">operator</span><span class="special">=</span><span class="special">(</span><span class="keyword">decltype</span><span class="special">(</span><span class="identifier">literal</span><span class="special">(</span><span class="number">0</span><span class="special">)</span><span class="special">)</span><span class="special">)</span><span class="special">{</span>
|
||
<span class="identifier">m_word</span> <span class="special">&=</span> <span class="special">~</span><span class="identifier">literal</span><span class="special">(</span><span class="number">1</span> <span class="special"><<</span> <span class="identifier">N</span><span class="special">)</span><span class="special">;</span>
|
||
<span class="keyword">return</span> <span class="special">*</span><span class="keyword">this</span><span class="special">;</span>
|
||
<span class="special">}</span>
|
||
<span class="comment">// operator to convert to 0 or 1</span>
|
||
<span class="keyword">constexpr</span> <span class="keyword">operator</span> <span class="identifier">safe_bit_t</span> <span class="special">(</span><span class="special">)</span> <span class="keyword">const</span> <span class="special">{</span>
|
||
<span class="keyword">return</span> <span class="identifier">m_word</span> <span class="special">>></span> <span class="identifier">literal</span><span class="special">(</span><span class="identifier">N</span><span class="special">)</span> <span class="special">&</span> <span class="identifier">literal</span><span class="special">(</span><span class="number">1</span><span class="special">)</span><span class="special">;</span>
|
||
<span class="special">}</span>
|
||
<span class="special">}</span><span class="special">;</span>
|
||
|
||
<span class="comment">// define bits for T1CON register</span>
|
||
<span class="keyword">struct</span> <span class="special">{</span>
|
||
<span class="identifier">bit</span><span class="special"><</span><span class="identifier">pic_register_t</span><span class="special">,</span> <span class="number">7</span><span class="special">></span> <span class="identifier">RD16</span><span class="special">{</span><span class="identifier">T1CON</span><span class="special">}</span><span class="special">;</span>
|
||
<span class="identifier">bit</span><span class="special"><</span><span class="identifier">pic_register_t</span><span class="special">,</span> <span class="number">5</span><span class="special">></span> <span class="identifier">T1CKPS1</span><span class="special">{</span><span class="identifier">T1CON</span><span class="special">}</span><span class="special">;</span>
|
||
<span class="identifier">bit</span><span class="special"><</span><span class="identifier">pic_register_t</span><span class="special">,</span> <span class="number">4</span><span class="special">></span> <span class="identifier">T1CKPS0</span><span class="special">{</span><span class="identifier">T1CON</span><span class="special">}</span><span class="special">;</span>
|
||
<span class="identifier">bit</span><span class="special"><</span><span class="identifier">pic_register_t</span><span class="special">,</span> <span class="number">3</span><span class="special">></span> <span class="identifier">T1OSCEN</span><span class="special">{</span><span class="identifier">T1CON</span><span class="special">}</span><span class="special">;</span>
|
||
<span class="identifier">bit</span><span class="special"><</span><span class="identifier">pic_register_t</span><span class="special">,</span> <span class="number">2</span><span class="special">></span> <span class="identifier">T1SYNC</span><span class="special">{</span><span class="identifier">T1CON</span><span class="special">}</span><span class="special">;</span>
|
||
<span class="identifier">bit</span><span class="special"><</span><span class="identifier">pic_register_t</span><span class="special">,</span> <span class="number">1</span><span class="special">></span> <span class="identifier">TMR1CS</span><span class="special">{</span><span class="identifier">T1CON</span><span class="special">}</span><span class="special">;</span>
|
||
<span class="identifier">bit</span><span class="special"><</span><span class="identifier">pic_register_t</span><span class="special">,</span> <span class="number">0</span><span class="special">></span> <span class="identifier">TMR1ON</span><span class="special">{</span><span class="identifier">T1CON</span><span class="special">}</span><span class="special">;</span>
|
||
<span class="special">}</span> <span class="identifier">T1CONbits</span><span class="special">;</span>
|
||
|
||
<span class="comment">// define bits for T1CON register</span>
|
||
<span class="keyword">struct</span> <span class="special">{</span>
|
||
<span class="identifier">bit</span><span class="special"><</span><span class="identifier">pic_register_t</span><span class="special">,</span> <span class="number">7</span><span class="special">></span> <span class="identifier">GEI</span><span class="special">{</span><span class="identifier">INTCON</span><span class="special">}</span><span class="special">;</span>
|
||
<span class="identifier">bit</span><span class="special"><</span><span class="identifier">pic_register_t</span><span class="special">,</span> <span class="number">5</span><span class="special">></span> <span class="identifier">PEIE</span><span class="special">{</span><span class="identifier">INTCON</span><span class="special">}</span><span class="special">;</span>
|
||
<span class="identifier">bit</span><span class="special"><</span><span class="identifier">pic_register_t</span><span class="special">,</span> <span class="number">4</span><span class="special">></span> <span class="identifier">TMR0IE</span><span class="special">{</span><span class="identifier">INTCON</span><span class="special">}</span><span class="special">;</span>
|
||
<span class="identifier">bit</span><span class="special"><</span><span class="identifier">pic_register_t</span><span class="special">,</span> <span class="number">3</span><span class="special">></span> <span class="identifier">RBIE</span><span class="special">{</span><span class="identifier">INTCON</span><span class="special">}</span><span class="special">;</span>
|
||
<span class="identifier">bit</span><span class="special"><</span><span class="identifier">pic_register_t</span><span class="special">,</span> <span class="number">2</span><span class="special">></span> <span class="identifier">TMR0IF</span><span class="special">{</span><span class="identifier">INTCON</span><span class="special">}</span><span class="special">;</span>
|
||
<span class="identifier">bit</span><span class="special"><</span><span class="identifier">pic_register_t</span><span class="special">,</span> <span class="number">1</span><span class="special">></span> <span class="identifier">INT0IF</span><span class="special">{</span><span class="identifier">INTCON</span><span class="special">}</span><span class="special">;</span>
|
||
<span class="identifier">bit</span><span class="special"><</span><span class="identifier">pic_register_t</span><span class="special">,</span> <span class="number">0</span><span class="special">></span> <span class="identifier">RBIF</span><span class="special">{</span><span class="identifier">INTCON</span><span class="special">}</span><span class="special">;</span>
|
||
<span class="special">}</span> <span class="identifier">INTCONbits</span><span class="special">;</span>
|
||
|
||
<span class="preprocessor">#include</span> <span class="string">"motor3.c"</span>
|
||
|
||
<span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">chrono</span><span class="special">></span>
|
||
<span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">thread</span><span class="special">></span>
|
||
|
||
<span class="comment">// round 24.8 format to microseconds</span>
|
||
<span class="identifier">microseconds</span> <span class="identifier">to_microseconds</span><span class="special">(</span><span class="identifier">ccpr_t</span> <span class="identifier">t</span><span class="special">)</span><span class="special">{</span>
|
||
<span class="keyword">return</span> <span class="special">(</span><span class="identifier">t</span> <span class="special">+</span> <span class="identifier">literal</span><span class="special">(</span><span class="number">128</span><span class="special">)</span><span class="special">)</span> <span class="special">/</span> <span class="identifier">literal</span><span class="special">(</span><span class="number">256</span><span class="special">)</span><span class="special">;</span>
|
||
<span class="special">}</span>
|
||
|
||
<span class="keyword">using</span> <span class="identifier">result_t</span> <span class="special">=</span> <span class="identifier">uint8_t</span><span class="special">;</span>
|
||
<span class="keyword">const</span> <span class="identifier">result_t</span> <span class="identifier">success</span> <span class="special">=</span> <span class="number">1</span><span class="special">;</span>
|
||
<span class="keyword">const</span> <span class="identifier">result_t</span> <span class="identifier">fail</span> <span class="special">=</span> <span class="number">0</span><span class="special">;</span>
|
||
|
||
<span class="comment">// move motor to the indicated target position in steps</span>
|
||
<span class="identifier">result_t</span> <span class="identifier">test</span><span class="special">(</span><span class="identifier">position_t</span> <span class="identifier">new_position</span><span class="special">)</span><span class="special">{</span>
|
||
<span class="keyword">try</span> <span class="special">{</span>
|
||
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="string">"move motor to "</span> <span class="special"><<</span> <span class="identifier">new_position</span> <span class="special"><<</span> <span class="char">'\n'</span><span class="special">;</span>
|
||
<span class="identifier">motor_run</span><span class="special">(</span><span class="identifier">new_position</span><span class="special">)</span><span class="special">;</span>
|
||
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span>
|
||
<span class="special"><<</span> <span class="string">"step #"</span> <span class="special"><<</span> <span class="char">' '</span>
|
||
<span class="special"><<</span> <span class="string">"delay(us)(24.8)"</span> <span class="special"><<</span> <span class="char">' '</span>
|
||
<span class="special"><<</span> <span class="string">"delay(us)"</span> <span class="special"><<</span> <span class="char">' '</span>
|
||
<span class="special"><<</span> <span class="string">"CCPR"</span> <span class="special"><<</span> <span class="char">' '</span>
|
||
<span class="special"><<</span> <span class="string">"motor position"</span> <span class="special"><<</span> <span class="char">'\n'</span><span class="special">;</span>
|
||
<span class="keyword">while</span><span class="special">(</span><span class="identifier">busy</span><span class="special">(</span><span class="special">)</span><span class="special">)</span><span class="special">{</span>
|
||
<span class="identifier">std</span><span class="special">::</span><span class="identifier">this_thread</span><span class="special">::</span><span class="identifier">sleep_for</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">chrono</span><span class="special">::</span><span class="identifier">microseconds</span><span class="special">(</span><span class="identifier">to_microseconds</span><span class="special">(</span><span class="identifier">c</span><span class="special">)</span><span class="special">)</span><span class="special">)</span><span class="special">;</span>
|
||
<span class="identifier">c_t</span> <span class="identifier">last_c</span> <span class="special">=</span> <span class="identifier">c</span><span class="special">;</span>
|
||
<span class="identifier">ccpr_t</span> <span class="identifier">last_ccpr</span> <span class="special">=</span> <span class="identifier">ccpr</span><span class="special">;</span>
|
||
<span class="identifier">isr_motor_step</span><span class="special">(</span><span class="special">)</span><span class="special">;</span>
|
||
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="identifier">i</span> <span class="special"><<</span> <span class="char">' '</span>
|
||
<span class="special"><<</span> <span class="identifier">last_c</span> <span class="special"><<</span> <span class="char">' '</span>
|
||
<span class="special"><<</span> <span class="identifier">to_microseconds</span><span class="special">(</span><span class="identifier">last_c</span><span class="special">)</span> <span class="special"><<</span> <span class="char">' '</span>
|
||
<span class="special"><<</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">hex</span> <span class="special"><<</span> <span class="identifier">last_ccpr</span> <span class="special"><<</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">dec</span> <span class="special"><<</span> <span class="char">' '</span>
|
||
<span class="special"><<</span> <span class="identifier">motor_position</span> <span class="special"><<</span> <span class="char">'\n'</span><span class="special">;</span>
|
||
<span class="special">}</span><span class="special">;</span>
|
||
<span class="special">}</span>
|
||
<span class="keyword">catch</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">exception</span> <span class="special">&</span> <span class="identifier">e</span><span class="special">)</span><span class="special">{</span>
|
||
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="identifier">e</span><span class="special">.</span><span class="identifier">what</span><span class="special">(</span><span class="special">)</span> <span class="special"><<</span> <span class="char">'\n'</span><span class="special">;</span>
|
||
<span class="keyword">return</span> <span class="identifier">fail</span><span class="special">;</span>
|
||
<span class="special">}</span>
|
||
<span class="keyword">return</span> <span class="identifier">success</span><span class="special">;</span>
|
||
<span class="special">}</span>
|
||
|
||
<span class="keyword">int</span> <span class="identifier">main</span><span class="special">(</span><span class="special">)</span><span class="special">{</span>
|
||
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="string">"start test\n"</span><span class="special">;</span>
|
||
<span class="identifier">result_t</span> <span class="identifier">result</span> <span class="special">=</span> <span class="identifier">success</span><span class="special">;</span>
|
||
<span class="keyword">try</span> <span class="special">{</span>
|
||
<span class="identifier">initialize</span><span class="special">(</span><span class="special">)</span><span class="special">;</span>
|
||
<span class="comment">// move motor to position 1000</span>
|
||
<span class="identifier">result</span> <span class="special">&=</span> <span class="identifier">test</span><span class="special">(</span><span class="identifier">literal</span><span class="special">(</span><span class="number">9000</span><span class="special">)</span><span class="special">)</span><span class="special">;</span>
|
||
<span class="comment">// move to the left before zero position</span>
|
||
<span class="comment">// fails to compile !</span>
|
||
<span class="comment">// result &= ! test(-10);</span>
|
||
<span class="comment">// move motor to position 200</span>
|
||
<span class="identifier">result</span> <span class="special">&=</span> <span class="identifier">test</span><span class="special">(</span><span class="identifier">literal</span><span class="special">(</span><span class="number">200</span><span class="special">)</span><span class="special">)</span><span class="special">;</span>
|
||
<span class="comment">// move motor to position 200 again! Should result in no movement.</span>
|
||
<span class="identifier">result</span> <span class="special">&=</span> <span class="identifier">test</span><span class="special">(</span><span class="identifier">literal</span><span class="special">(</span><span class="number">200</span><span class="special">)</span><span class="special">)</span><span class="special">;</span>
|
||
<span class="comment">// move motor to position 50000.</span>
|
||
<span class="identifier">result</span> <span class="special">&=</span> <span class="identifier">test</span><span class="special">(</span><span class="identifier">literal</span><span class="special">(</span><span class="number">50000</span><span class="special">)</span><span class="special">)</span><span class="special">;</span>
|
||
<span class="comment">// move motor back to position 0.</span>
|
||
<span class="identifier">result</span> <span class="special">&=</span> <span class="identifier">test</span><span class="special">(</span><span class="identifier">literal</span><span class="special">(</span><span class="number">0</span><span class="special">)</span><span class="special">)</span><span class="special">;</span>
|
||
<span class="special">}</span>
|
||
<span class="keyword">catch</span><span class="special">(</span><span class="special">...</span><span class="special">)</span><span class="special">{</span>
|
||
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="string">"test interrupted\n"</span><span class="special">;</span>
|
||
<span class="keyword">return</span> <span class="identifier">EXIT_FAILURE</span><span class="special">;</span>
|
||
<span class="special">}</span>
|
||
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="string">"end test\n"</span><span class="special">;</span>
|
||
<span class="keyword">return</span> <span class="identifier">result</span> <span class="special">==</span> <span class="identifier">success</span> <span class="special">?</span> <span class="identifier">EXIT_SUCCESS</span> <span class="special">:</span> <span class="identifier">EXIT_FAILURE</span><span class="special">;</span>
|
||
<span class="special">}</span>
|
||
</pre>
|
||
<p>Here are the changes we've made int the desktop test
|
||
program</p>
|
||
<div class="orderedlist"><ol class="orderedlist" type="1">
|
||
<li class="listitem"><p>Specify exception policies so we can generate a compile time
|
||
error whenever an operation MIGHT fail. We've aliased this policy
|
||
with the name <code class="computeroutput">trap_policy</code>. The default policy of which
|
||
throws a runtime exception when an error is countered is aliased as
|
||
<code class="computeroutput">exception_policy</code>. When creating safe types, we'll now
|
||
specify which type of checking, compile time or runtime, we want
|
||
done.</p></li>
|
||
<li class="listitem">
|
||
<p>Create a macro named "literal" an integral value that can be
|
||
evaluated at compile time.</p>
|
||
<p>"literal" values are instances of safe numeric types which are
|
||
determined at compile time. They are <code class="computeroutput">constexpr</code> values.
|
||
When used along with other instances of safe numeric types, the
|
||
compiler can calculate the range of the result and verify whether or
|
||
not it can be contained in the result type. To create "literal"
|
||
types we use the macro <code class="computeroutput"><a class="link" href="safe_literal.html#safe_numerics.safe_literal.make_safe_literal" title="make_safe_literal(n, PP, EP)">make_safe_literal</a>(n,
|
||
p, e)</code> where n is the value, p is the <a class="link" href="promotion_policy.html" title="PromotionPolicy<PP>">promotion policy</a> and
|
||
e is the <a class="link" href="exception_policy.html" title="ExceptionPolicy<EP>">exception
|
||
policy</a>.</p>
|
||
<p>When all the values in an expression are safe numeric values,
|
||
the compiler can calculate the narrowest range of the result. If all
|
||
the values in this range can be represented by the result type, then
|
||
it can be guaranteed that an invalid result cannot be produced at
|
||
runtime and no runtime checking is required.</p>
|
||
<p>Make sure that all literal values are x are replaced with the
|
||
macro invocation "literal(x)".</p>
|
||
<p>It's unfortunate that the "literal" macro is required as it
|
||
clutters the code. The good news is that is some future version of
|
||
C++, expansion of <code class="computeroutput">constexpr</code> facilities may result in
|
||
elimination of this requirement.</p>
|
||
</li>
|
||
<li class="listitem">
|
||
<p>Create special types for the motor program. These will
|
||
guarantee that values are in the expected ranges and permit compile
|
||
time determination of when exceptional conditions might occur. In
|
||
this example we create a special type c_t to the width of the pulse
|
||
applied to the motor. Engineering constraints (motor load inertia)
|
||
limit this value to the range of C0 to C_MIN. So we create a type
|
||
with those limits. By using limits no larger than necessary, we
|
||
supply enough information for the compiler to determine that the
|
||
result of a calculation cannot fall outside the range of the result
|
||
type. So less runtime checking is required. In addition, we get
|
||
extra verification at compile time that values are in reasonable
|
||
ranges for the quantity being modeled.</p>
|
||
<p>We call these types "strong types".</p>
|
||
</li>
|
||
</ol></div>
|
||
<p>And we've made changes consistent with the above to <a href="../../example/motor3.c" target="_top">motor3.c</a> as well</p>
|
||
<pre class="programlisting"><span class="comment">/*
|
||
* david austin
|
||
* http://www.embedded.com/design/mcus-processors-and-socs/4006438/Generate-stepper-motor-speed-profiles-in-real-time
|
||
* DECEMBER 30, 2004
|
||
*
|
||
* Demo program for stepper motor control with linear ramps
|
||
* Hardware: PIC18F252, L6219
|
||
*
|
||
* Copyright (c) 2015 Robert Ramey
|
||
*
|
||
* Distributed under the Boost Software License, Version 1.0. (See
|
||
* accompanying file LICENSE_1_0.txt or copy at
|
||
* http://www.boost.org/LICENSE_1_0.txt)
|
||
*/</span>
|
||
|
||
<span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">assert</span><span class="special">.</span><span class="identifier">h</span><span class="special">></span>
|
||
|
||
<span class="comment">// ramp state-machine states</span>
|
||
<span class="keyword">enum</span> <span class="identifier">ramp_state</span> <span class="special">{</span>
|
||
<span class="identifier">ramp_idle</span> <span class="special">=</span> <span class="number">0</span><span class="special">,</span>
|
||
<span class="identifier">ramp_up</span> <span class="special">=</span> <span class="number">1</span><span class="special">,</span>
|
||
<span class="identifier">ramp_const</span> <span class="special">=</span> <span class="number">2</span><span class="special">,</span>
|
||
<span class="identifier">ramp_down</span> <span class="special">=</span> <span class="number">3</span><span class="special">,</span>
|
||
<span class="special">}</span><span class="special">;</span>
|
||
|
||
<span class="comment">// ***************************</span>
|
||
<span class="comment">// 1. Define state variables using custom strong types</span>
|
||
|
||
<span class="comment">// initial setup</span>
|
||
<span class="keyword">enum</span> <span class="identifier">ramp_state</span> <span class="identifier">ramp_sts</span><span class="special">;</span>
|
||
<span class="identifier">position_t</span> <span class="identifier">motor_position</span><span class="special">;</span>
|
||
<span class="identifier">position_t</span> <span class="identifier">m</span><span class="special">;</span> <span class="comment">// target position</span>
|
||
<span class="identifier">position_t</span> <span class="identifier">m2</span><span class="special">;</span> <span class="comment">// midpoint or point where acceleration changes</span>
|
||
<span class="identifier">direction_t</span> <span class="identifier">d</span><span class="special">;</span> <span class="comment">// direction of traval -1 or +1</span>
|
||
|
||
<span class="comment">// curent state along travel</span>
|
||
<span class="identifier">step_t</span> <span class="identifier">i</span><span class="special">;</span> <span class="comment">// step number</span>
|
||
<span class="identifier">c_t</span> <span class="identifier">c</span><span class="special">;</span> <span class="comment">// 24.8 fixed point delay count increment</span>
|
||
<span class="identifier">ccpr_t</span> <span class="identifier">ccpr</span><span class="special">;</span> <span class="comment">// 24.8 fixed point delay count</span>
|
||
<span class="identifier">phase_ix_t</span> <span class="identifier">phase_ix</span><span class="special">;</span> <span class="comment">// motor phase index</span>
|
||
|
||
<span class="comment">// ***************************</span>
|
||
<span class="comment">// 2. Surround all literal values with the "literal" keyword</span>
|
||
|
||
<span class="comment">// Config data to make CCP1&2 generate quadrature sequence on PHASE pins</span>
|
||
<span class="comment">// Action on CCP match: 8=set+irq; 9=clear+irq</span>
|
||
<span class="identifier">phase_t</span> <span class="keyword">const</span> <span class="identifier">ccpPhase</span><span class="special">[</span><span class="special">]</span> <span class="special">=</span> <span class="special">{</span>
|
||
<span class="identifier">literal</span><span class="special">(</span><span class="number">0x909</span><span class="special">)</span><span class="special">,</span>
|
||
<span class="identifier">literal</span><span class="special">(</span><span class="number">0x908</span><span class="special">)</span><span class="special">,</span>
|
||
<span class="identifier">literal</span><span class="special">(</span><span class="number">0x808</span><span class="special">)</span><span class="special">,</span>
|
||
<span class="identifier">literal</span><span class="special">(</span><span class="number">0x809</span><span class="special">)</span>
|
||
<span class="special">}</span><span class="special">;</span> <span class="comment">// 00,01,11,10</span>
|
||
|
||
<span class="keyword">void</span> <span class="identifier">current_on</span><span class="special">(</span><span class="special">)</span><span class="special">{</span><span class="comment">/* code as needed */</span><span class="special">}</span> <span class="comment">// motor drive current</span>
|
||
<span class="keyword">void</span> <span class="identifier">current_off</span><span class="special">(</span><span class="special">)</span><span class="special">{</span><span class="comment">/* code as needed */</span><span class="special">}</span> <span class="comment">// reduce to holding value</span>
|
||
|
||
<span class="comment">// ***************************</span>
|
||
<span class="comment">// 3. Refactor code to make it easier to understand</span>
|
||
<span class="comment">// and relate to the documentation</span>
|
||
|
||
<span class="keyword">bool</span> <span class="identifier">busy</span><span class="special">(</span><span class="special">)</span><span class="special">{</span>
|
||
<span class="keyword">return</span> <span class="identifier">ramp_idle</span> <span class="special">!=</span> <span class="identifier">ramp_sts</span><span class="special">;</span>
|
||
<span class="special">}</span>
|
||
|
||
<span class="comment">// set outputs to energize motor coils</span>
|
||
<span class="keyword">void</span> <span class="identifier">update</span><span class="special">(</span><span class="identifier">ccpr_t</span> <span class="identifier">ccpr_arg</span><span class="special">,</span> <span class="identifier">phase_ix_t</span> <span class="identifier">phase_ix_arg</span><span class="special">)</span><span class="special">{</span>
|
||
<span class="comment">// energize correct windings</span>
|
||
<span class="keyword">const</span> <span class="identifier">phase_t</span> <span class="identifier">phase</span> <span class="special">=</span> <span class="identifier">ccpPhase</span><span class="special">[</span><span class="identifier">phase_ix_arg</span><span class="special">]</span><span class="special">;</span>
|
||
<span class="identifier">CCP1CON</span> <span class="special">=</span> <span class="identifier">phase</span> <span class="special">&</span> <span class="identifier">literal</span><span class="special">(</span><span class="number">0xff</span><span class="special">)</span><span class="special">;</span> <span class="comment">// set CCP action on next match</span>
|
||
<span class="identifier">CCP2CON</span> <span class="special">=</span> <span class="identifier">phase</span> <span class="special">>></span> <span class="identifier">literal</span><span class="special">(</span><span class="number">8</span><span class="special">)</span><span class="special">;</span>
|
||
<span class="comment">// timer value at next CCP match</span>
|
||
<span class="identifier">CCPR1H</span> <span class="special">=</span> <span class="identifier">literal</span><span class="special">(</span><span class="number">0xff</span><span class="special">)</span> <span class="special">&</span> <span class="special">(</span><span class="identifier">ccpr_arg</span> <span class="special">>></span> <span class="identifier">literal</span><span class="special">(</span><span class="number">8</span><span class="special">)</span><span class="special">)</span><span class="special">;</span>
|
||
<span class="identifier">CCPR1L</span> <span class="special">=</span> <span class="identifier">literal</span><span class="special">(</span><span class="number">0xff</span><span class="special">)</span> <span class="special">&</span> <span class="identifier">ccpr_arg</span><span class="special">;</span>
|
||
<span class="special">}</span>
|
||
|
||
<span class="comment">// compiler-specific ISR declaration</span>
|
||
<span class="comment">// ***************************</span>
|
||
<span class="comment">// 4. Rewrite interrupt handler in a way which mirrors the orginal</span>
|
||
<span class="comment">// description of the algorithm and minimizes usage of state variable,</span>
|
||
<span class="comment">// accumulated values, etc.</span>
|
||
<span class="keyword">void</span> <span class="identifier">__interrupt</span> <span class="identifier">isr_motor_step</span><span class="special">(</span><span class="keyword">void</span><span class="special">)</span> <span class="special">{</span> <span class="comment">// CCP1 match -> step pulse + IRQ</span>
|
||
<span class="comment">// *** possible exception</span>
|
||
<span class="comment">// motor_position += d;</span>
|
||
<span class="comment">// use the following to avoid mixing exception policies which is an error</span>
|
||
<span class="keyword">if</span><span class="special">(</span><span class="identifier">d</span> <span class="special"><</span> <span class="number">0</span><span class="special">)</span>
|
||
<span class="special">--</span><span class="identifier">motor_position</span><span class="special">;</span>
|
||
<span class="keyword">else</span>
|
||
<span class="special">++</span><span class="identifier">motor_position</span><span class="special">;</span>
|
||
<span class="comment">// *** possible exception</span>
|
||
<span class="special">++</span><span class="identifier">i</span><span class="special">;</span>
|
||
<span class="comment">// calculate next difference in time</span>
|
||
<span class="keyword">for</span><span class="special">(</span><span class="special">;</span><span class="special">;</span><span class="special">)</span><span class="special">{</span>
|
||
<span class="keyword">switch</span> <span class="special">(</span><span class="identifier">ramp_sts</span><span class="special">)</span> <span class="special">{</span>
|
||
<span class="keyword">case</span> <span class="identifier">ramp_up</span><span class="special">:</span> <span class="comment">// acceleration</span>
|
||
<span class="keyword">if</span> <span class="special">(</span><span class="identifier">i</span> <span class="special">==</span> <span class="identifier">m2</span><span class="special">)</span> <span class="special">{</span>
|
||
<span class="identifier">ramp_sts</span> <span class="special">=</span> <span class="identifier">ramp_down</span><span class="special">;</span>
|
||
<span class="keyword">continue</span><span class="special">;</span>
|
||
<span class="special">}</span>
|
||
<span class="comment">// equation 13</span>
|
||
<span class="comment">// *** possible negative overflow on update of c</span>
|
||
<span class="identifier">c</span> <span class="special">-=</span> <span class="identifier">literal</span><span class="special">(</span><span class="number">2</span><span class="special">)</span> <span class="special">*</span> <span class="identifier">c</span> <span class="special">/</span> <span class="special">(</span><span class="identifier">literal</span><span class="special">(</span><span class="number">4</span><span class="special">)</span> <span class="special">*</span> <span class="identifier">i</span> <span class="special">+</span> <span class="identifier">literal</span><span class="special">(</span><span class="number">1</span><span class="special">)</span><span class="special">)</span><span class="special">;</span>
|
||
<span class="keyword">if</span><span class="special">(</span><span class="identifier">c</span> <span class="special"><</span> <span class="identifier">C_MIN</span><span class="special">)</span><span class="special">{</span>
|
||
<span class="identifier">c</span> <span class="special">=</span> <span class="identifier">C_MIN</span><span class="special">;</span>
|
||
<span class="identifier">ramp_sts</span> <span class="special">=</span> <span class="identifier">ramp_const</span><span class="special">;</span>
|
||
<span class="comment">// *** possible exception</span>
|
||
<span class="identifier">m2</span> <span class="special">=</span> <span class="identifier">m</span> <span class="special">-</span> <span class="identifier">i</span><span class="special">;</span> <span class="comment">// new inflection point</span>
|
||
<span class="keyword">continue</span><span class="special">;</span>
|
||
<span class="special">}</span>
|
||
<span class="keyword">break</span><span class="special">;</span>
|
||
<span class="keyword">case</span> <span class="identifier">ramp_const</span><span class="special">:</span> <span class="comment">// constant speed</span>
|
||
<span class="keyword">if</span><span class="special">(</span><span class="identifier">i</span> <span class="special">></span> <span class="identifier">m2</span><span class="special">)</span> <span class="special">{</span>
|
||
<span class="identifier">ramp_sts</span> <span class="special">=</span> <span class="identifier">ramp_down</span><span class="special">;</span>
|
||
<span class="keyword">continue</span><span class="special">;</span>
|
||
<span class="special">}</span>
|
||
<span class="keyword">break</span><span class="special">;</span>
|
||
<span class="keyword">case</span> <span class="identifier">ramp_down</span><span class="special">:</span> <span class="comment">// deceleration</span>
|
||
<span class="keyword">if</span> <span class="special">(</span><span class="identifier">i</span> <span class="special">==</span> <span class="identifier">m</span><span class="special">)</span> <span class="special">{</span>
|
||
<span class="identifier">ramp_sts</span> <span class="special">=</span> <span class="identifier">ramp_idle</span><span class="special">;</span>
|
||
<span class="identifier">current_off</span><span class="special">(</span><span class="special">)</span><span class="special">;</span> <span class="comment">// reduce motor current to holding value</span>
|
||
<span class="identifier">CCP1IE</span> <span class="special">=</span> <span class="identifier">literal</span><span class="special">(</span><span class="number">0</span><span class="special">)</span><span class="special">;</span> <span class="comment">// disable_interrupts(INT_CCP1);</span>
|
||
<span class="keyword">return</span><span class="special">;</span>
|
||
<span class="special">}</span>
|
||
<span class="comment">// equation 14</span>
|
||
<span class="comment">// *** possible positive overflow on update of c</span>
|
||
<span class="comment">// note: re-arrange expression to avoid negative result</span>
|
||
<span class="comment">// from difference of two unsigned values</span>
|
||
<span class="special">{</span>
|
||
<span class="comment">// testing discovered that this can overflow. It's not easy to</span>
|
||
<span class="comment">// avoid so we'll use a temporary unsigned variable 32 bits wide</span>
|
||
<span class="keyword">const</span> <span class="identifier">temp_t</span> <span class="identifier">x</span> <span class="special">=</span> <span class="identifier">c</span> <span class="special">+</span> <span class="identifier">literal</span><span class="special">(</span><span class="number">2</span><span class="special">)</span> <span class="special">*</span> <span class="identifier">c</span> <span class="special">/</span> <span class="special">(</span><span class="identifier">literal</span><span class="special">(</span><span class="number">4</span><span class="special">)</span> <span class="special">*</span> <span class="special">(</span><span class="identifier">m</span> <span class="special">-</span> <span class="identifier">i</span><span class="special">)</span> <span class="special">-</span> <span class="identifier">literal</span><span class="special">(</span><span class="number">1</span><span class="special">)</span><span class="special">)</span><span class="special">;</span>
|
||
<span class="identifier">c</span> <span class="special">=</span> <span class="identifier">x</span> <span class="special">></span> <span class="identifier">C0</span> <span class="special">?</span> <span class="identifier">C0</span> <span class="special">:</span> <span class="identifier">x</span><span class="special">;</span>
|
||
<span class="special">}</span>
|
||
<span class="keyword">break</span><span class="special">;</span>
|
||
<span class="keyword">default</span><span class="special">:</span>
|
||
<span class="comment">// should never arrive here!</span>
|
||
<span class="identifier">assert</span><span class="special">(</span><span class="keyword">false</span><span class="special">)</span><span class="special">;</span>
|
||
<span class="special">}</span> <span class="comment">// switch (ramp_sts)</span>
|
||
<span class="keyword">break</span><span class="special">;</span>
|
||
<span class="special">}</span>
|
||
<span class="identifier">assert</span><span class="special">(</span><span class="identifier">c</span> <span class="special"><=</span> <span class="identifier">C0</span> <span class="special">&&</span> <span class="identifier">c</span> <span class="special">>=</span> <span class="identifier">C_MIN</span><span class="special">)</span><span class="special">;</span>
|
||
<span class="comment">// *** possible exception</span>
|
||
<span class="identifier">ccpr</span> <span class="special">=</span> <span class="identifier">literal</span><span class="special">(</span><span class="number">0xffffff</span><span class="special">)</span> <span class="special">&</span> <span class="special">(</span><span class="identifier">ccpr</span> <span class="special">+</span> <span class="identifier">c</span><span class="special">)</span><span class="special">;</span>
|
||
<span class="identifier">phase_ix</span> <span class="special">=</span> <span class="special">(</span><span class="identifier">phase_ix</span> <span class="special">+</span> <span class="identifier">d</span><span class="special">)</span> <span class="special">&</span> <span class="identifier">literal</span><span class="special">(</span><span class="number">3</span><span class="special">)</span><span class="special">;</span>
|
||
<span class="identifier">update</span><span class="special">(</span><span class="identifier">ccpr</span><span class="special">,</span> <span class="identifier">phase_ix</span><span class="special">)</span><span class="special">;</span>
|
||
<span class="special">}</span> <span class="comment">// isr_motor_step()</span>
|
||
|
||
<span class="comment">// set up to drive motor to pos_new (absolute step#)</span>
|
||
<span class="keyword">void</span> <span class="identifier">motor_run</span><span class="special">(</span><span class="identifier">position_t</span> <span class="identifier">new_position</span><span class="special">)</span> <span class="special">{</span>
|
||
<span class="keyword">if</span><span class="special">(</span><span class="identifier">new_position</span> <span class="special">></span> <span class="identifier">motor_position</span><span class="special">)</span><span class="special">{</span>
|
||
<span class="identifier">d</span> <span class="special">=</span> <span class="identifier">literal</span><span class="special">(</span><span class="number">1</span><span class="special">)</span><span class="special">;</span>
|
||
<span class="comment">// *** possible exception</span>
|
||
<span class="identifier">m</span> <span class="special">=</span> <span class="identifier">new_position</span> <span class="special">-</span> <span class="identifier">motor_position</span><span class="special">;</span>
|
||
<span class="special">}</span>
|
||
<span class="keyword">else</span>
|
||
<span class="keyword">if</span><span class="special">(</span><span class="identifier">motor_position</span> <span class="special">></span> <span class="identifier">new_position</span><span class="special">)</span><span class="special">{</span>
|
||
<span class="identifier">d</span> <span class="special">=</span> <span class="identifier">literal</span><span class="special">(</span><span class="special">-</span><span class="number">1</span><span class="special">)</span><span class="special">;</span>
|
||
<span class="comment">// *** possible exception</span>
|
||
<span class="identifier">m</span> <span class="special">=</span> <span class="identifier">motor_position</span> <span class="special">-</span> <span class="identifier">new_position</span><span class="special">;</span>
|
||
<span class="special">}</span>
|
||
<span class="keyword">else</span><span class="special">{</span>
|
||
<span class="identifier">d</span> <span class="special">=</span> <span class="identifier">literal</span><span class="special">(</span><span class="number">0</span><span class="special">)</span><span class="special">;</span>
|
||
<span class="identifier">m</span> <span class="special">=</span> <span class="identifier">literal</span><span class="special">(</span><span class="number">0</span><span class="special">)</span><span class="special">;</span>
|
||
<span class="identifier">ramp_sts</span> <span class="special">=</span> <span class="identifier">ramp_idle</span><span class="special">;</span> <span class="comment">// start ramp state-machine</span>
|
||
<span class="keyword">return</span><span class="special">;</span>
|
||
<span class="special">}</span>
|
||
|
||
<span class="identifier">i</span> <span class="special">=</span> <span class="identifier">literal</span><span class="special">(</span><span class="number">0</span><span class="special">)</span><span class="special">;</span>
|
||
<span class="identifier">m2</span> <span class="special">=</span> <span class="identifier">m</span> <span class="special">/</span> <span class="identifier">literal</span><span class="special">(</span><span class="number">2</span><span class="special">)</span><span class="special">;</span>
|
||
|
||
<span class="identifier">ramp_sts</span> <span class="special">=</span> <span class="identifier">ramp_up</span><span class="special">;</span> <span class="comment">// start ramp state-machine</span>
|
||
|
||
<span class="identifier">T1CONbits</span><span class="special">.</span><span class="identifier">TMR1ON</span> <span class="special">=</span> <span class="identifier">literal</span><span class="special">(</span><span class="number">0</span><span class="special">)</span><span class="special">;</span> <span class="comment">// stop timer1;</span>
|
||
|
||
<span class="identifier">current_on</span><span class="special">(</span><span class="special">)</span><span class="special">;</span> <span class="comment">// current in motor windings</span>
|
||
|
||
<span class="identifier">c</span> <span class="special">=</span> <span class="identifier">C0</span><span class="special">;</span>
|
||
<span class="identifier">ccpr</span> <span class="special">=</span> <span class="special">(</span><span class="identifier">TMR1H</span> <span class="special"><<</span> <span class="identifier">literal</span><span class="special">(</span><span class="number">8</span><span class="special">)</span> <span class="special">|</span> <span class="identifier">TMR1L</span><span class="special">)</span> <span class="special">+</span> <span class="identifier">C0</span> <span class="special">+</span> <span class="identifier">literal</span><span class="special">(</span><span class="number">1000</span><span class="special">)</span><span class="special">;</span>
|
||
<span class="identifier">phase_ix</span> <span class="special">=</span> <span class="identifier">d</span> <span class="special">&</span> <span class="identifier">literal</span><span class="special">(</span><span class="number">3</span><span class="special">)</span><span class="special">;</span>
|
||
<span class="identifier">update</span><span class="special">(</span><span class="identifier">ccpr</span><span class="special">,</span> <span class="identifier">phase_ix</span><span class="special">)</span><span class="special">;</span>
|
||
|
||
<span class="identifier">CCP1IE</span> <span class="special">=</span> <span class="identifier">literal</span><span class="special">(</span><span class="number">1</span><span class="special">)</span><span class="special">;</span> <span class="comment">// enable_interrupts(INT_CCP1);</span>
|
||
<span class="identifier">T1CONbits</span><span class="special">.</span><span class="identifier">TMR1ON</span> <span class="special">=</span> <span class="identifier">literal</span><span class="special">(</span><span class="number">1</span><span class="special">)</span><span class="special">;</span> <span class="comment">// restart timer1;</span>
|
||
<span class="special">}</span> <span class="comment">// motor_run()</span>
|
||
|
||
<span class="keyword">void</span> <span class="identifier">initialize</span><span class="special">(</span><span class="special">)</span> <span class="special">{</span>
|
||
<span class="identifier">di</span><span class="special">(</span><span class="special">)</span><span class="special">;</span> <span class="comment">// disable_interrupts(GLOBAL);</span>
|
||
<span class="identifier">motor_position</span> <span class="special">=</span> <span class="identifier">literal</span><span class="special">(</span><span class="number">0</span><span class="special">)</span><span class="special">;</span>
|
||
<span class="identifier">CCP1IE</span> <span class="special">=</span> <span class="identifier">literal</span><span class="special">(</span><span class="number">0</span><span class="special">)</span><span class="special">;</span> <span class="comment">// disable_interrupts(INT_CCP1);</span>
|
||
<span class="identifier">CCP2IE</span> <span class="special">=</span> <span class="identifier">literal</span><span class="special">(</span><span class="number">0</span><span class="special">)</span><span class="special">;</span> <span class="comment">// disable_interrupts(INT_CCP2);</span>
|
||
<span class="identifier">PORTC</span> <span class="special">=</span> <span class="identifier">literal</span><span class="special">(</span><span class="number">0</span><span class="special">)</span><span class="special">;</span> <span class="comment">// output_c(0);</span>
|
||
<span class="identifier">TRISC</span> <span class="special">=</span> <span class="identifier">literal</span><span class="special">(</span><span class="number">0</span><span class="special">)</span><span class="special">;</span> <span class="comment">// set_tris_c(0);</span>
|
||
<span class="identifier">T3CON</span> <span class="special">=</span> <span class="identifier">literal</span><span class="special">(</span><span class="number">0</span><span class="special">)</span><span class="special">;</span>
|
||
<span class="identifier">T1CON</span> <span class="special">=</span> <span class="identifier">literal</span><span class="special">(</span><span class="number">0x35</span><span class="special">)</span><span class="special">;</span>
|
||
<span class="identifier">INTCONbits</span><span class="special">.</span><span class="identifier">PEIE</span> <span class="special">=</span> <span class="identifier">literal</span><span class="special">(</span><span class="number">1</span><span class="special">)</span><span class="special">;</span>
|
||
<span class="identifier">INTCONbits</span><span class="special">.</span><span class="identifier">RBIF</span> <span class="special">=</span> <span class="identifier">literal</span><span class="special">(</span><span class="number">0</span><span class="special">)</span><span class="special">;</span>
|
||
<span class="identifier">ei</span><span class="special">(</span><span class="special">)</span><span class="special">;</span> <span class="comment">// enable_interrupts(GLOBAL);</span>
|
||
<span class="special">}</span> <span class="comment">// initialize()</span>
|
||
</pre>
|
||
<div class="orderedlist"><ol class="orderedlist" type="1">
|
||
<li class="listitem"><p>Define variables using strong types</p></li>
|
||
<li class="listitem"><p>Surround all literal values with the "literal" keyword</p></li>
|
||
<li class="listitem"><p>Re-factor code to make it easier to understand and compare
|
||
with the algorithm as described in the original <a href="../../example/stepper-motor.pdf" target="_top">article</a>.</p></li>
|
||
<li class="listitem"><p>Rewrite interrupt handler in a way which mirrors the original
|
||
description of the algorithm and minimizes usage of state variable,
|
||
accumulated values, etc.</p></li>
|
||
<li class="listitem"><p>Distinguish all the statements which might invoke a runtime
|
||
exception with a comment. There are 12 such instances.</p></li>
|
||
</ol></div>
|
||
<p>Finally we make a couple minor changes in <a href="../../example/motor_test3.c" target="_top">motor_test3.c</a> to verify that we
|
||
can compile the exact same version of motor3.c on the PIC as well as on
|
||
the desktop.</p>
|
||
</div>
|
||
<div class="section">
|
||
<div class="titlepage"><div><div><h4 class="title">
|
||
<a name="idm488720805184"></a>Summary</h4></div></div></div>
|
||
<p>The intent of this case study is to show that the Safe Numerics
|
||
Library can be an essential tool in validating the correctness of C/C++
|
||
programs in all environments - including the most restricted.</p>
|
||
<div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; ">
|
||
<li class="listitem"><p>We started with a program written for a tiny micro controller
|
||
for controlling the acceleration and deceleration of a stepper
|
||
motor. The algorithm for doing this is very non-trivial and
|
||
difficult prove that it is correct.</p></li>
|
||
<li class="listitem"><p>We used the type promotion policies of the Safe Numerics
|
||
Library to test and validate this algorithm on the desk top. The
|
||
tested code is also compiled for the target micro controller.</p></li>
|
||
<li class="listitem"><p>We used <span class="emphasis"><em>strong typing</em></span> features of Safe
|
||
Numerics to check that all types hold the values expected and invoke
|
||
no invalid implicit conversions. Again the tested code is compiled
|
||
for the target processor.</p></li>
|
||
</ul></div>
|
||
<p>What we failed to do is to create a version of the program which
|
||
uses the type system to prove that no results can be invalid. I turns out
|
||
that states such as</p>
|
||
<pre class="programlisting"><span class="special">++</span><span class="identifier">i</span><span class="special">;</span>
|
||
<span class="identifier">c</span> <span class="special">=</span> <span class="identifier">f</span><span class="special">(</span><span class="identifier">c</span><span class="special">)</span><span class="special">;</span></pre>
|
||
<p>can't be proved not to overflow with this system. So we're left with
|
||
having to depend upon exhaustive testing. It's not what we hoped, but it's
|
||
the best we can do.</p>
|
||
</div>
|
||
</div>
|
||
<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
|
||
<td align="left"></td>
|
||
<td align="right"><div class="copyright-footer">Copyright © 2012-2018 Robert Ramey<p><a href="http://www.boost.org/LICENSE_1_0.txt" target="_top">Subject to Boost
|
||
Software License</a></p>
|
||
</div></td>
|
||
</tr></table>
|
||
<hr>
|
||
<div class="spirit-nav">
|
||
<a accesskey="p" href="composition_with_other_libraries.html"><img src="images/prev.png" alt="Prev"></a><a accesskey="u" href="case_studies.html"><img src="images/up.png" alt="Up"></a><a accesskey="h" href="index.html"><img src="images/home.png" alt="Home"></a><a accesskey="n" href="notes.html"><img src="images/next.png" alt="Next"></a>
|
||
</div>
|
||
</body>
|
||
</html>
|