motor.xml 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!DOCTYPE section PUBLIC "-//Boost//DTD BoostBook XML V1.1//EN"
  3. "http://www.boost.org/tools/boostbook/dtd/boostbook.dtd">
  4. <section id="safe_numerics.safety_critical_embedded_controller">
  5. <title>Safety Critical Embedded Controller</title>
  6. <?dbhtml stop-chunking?>
  7. <para>Suppose we are given the task of creating stepper motor driver
  8. software to drive a robotic hand to be used in robotic micro surgery. The
  9. processor that has been selected by the engineers is the <ulink
  10. url="http://www.microchip.com/wwwproducts/en/PIC18F2520">PIC18F2520</ulink>
  11. manufactured by <ulink url="http://www.microchip.com">Microchip
  12. Corporation</ulink>. This processor has 32KB of program memory. On a
  13. processor this small, it's common to use a mixture of 8, 16, and 32 bit data
  14. types in order to minimize memory footprint and program run time. The type
  15. <code>int</code> has 16 bits. It's programmed in C. Since this program is
  16. going to be running life critical function, it must be demonstrably correct.
  17. This implies that it needs to be verifiable and testable. Since the target
  18. micro processor is inconvenient for accomplishing these goals, we will build
  19. and test the code on the desktop.</para>
  20. <section>
  21. <title>How a Stepper Motor Works</title>
  22. <figure float="0">
  23. <title>Stepper Motor</title>
  24. <mediaobject>
  25. <imageobject>
  26. <imagedata align="left" contentwidth="216"
  27. fileref="StepperMotor.gif" format="GIF" width="50%"/>
  28. </imageobject>
  29. </mediaobject>
  30. </figure>
  31. <para>A stepper motor controller emits a pulse which causes the motor to
  32. move one step. It seems simple, but in practice it turns out to be quite
  33. intricate to get right as one has to time the pulses individually to
  34. smoothly accelerate the rotation of the motor from a standing start until
  35. it reaches the some maximum velocity. Failure to do this will either limit
  36. the stepper motor to very low speed or result in skipped steps when the
  37. motor is under load. Similarly, a loaded motor must be slowly decelerated
  38. down to a stop.</para>
  39. <para><figure>
  40. <title>Motion Profile</title>
  41. <mediaobject>
  42. <imageobject>
  43. <imagedata fileref="stepper_profile.png" format="PNG" width="100%"/>
  44. </imageobject>
  45. </mediaobject>
  46. </figure></para>
  47. <para>This implies the the width of the pulses must decrease as the motor
  48. accelerates. That is the pulse with has to be computed while the motor is
  49. in motion. This is illustrated in the above drawing. A program to
  50. accomplish this might look something like the following:</para>
  51. <literallayout class="normal" linenumbering="unnumbered">setup registers and step to zero position
  52. specify target position
  53. set initial time to interrupt
  54. enable interrupts
  55. On interrupt
  56. if at target position
  57. disable interrupts and return
  58. calculate width of next step
  59. change current winding according to motor direction
  60. set delay time to next interrupt to width of next step</literallayout>
  61. <para>Already, this is turning it to a much more complex project than it
  62. first seemed. Searching around the net, we find a popular <ulink
  63. url="../../example/stepper-motor.pdf">article</ulink> on the operation of
  64. stepper motors using simple micro controllers. The algorithm is very well
  65. explained and it includes complete <ulink url="../../example/motor.c">code
  66. we can test</ulink>. The engineers are still debugging the prototype
  67. boards and hope to have them ready before the product actually ships. But
  68. this doesn't have to keep us from working on our code.</para>
  69. </section>
  70. <section>
  71. <title>Updating the Code</title>
  72. <para>Inspecting this <ulink url="../../example/motor.c">code</ulink>, we
  73. find that it is written in a dialect of C rather than C itself. At the
  74. time this code was written, conforming versions of the C compiler were not
  75. available for PIC processors. We want to compile this code on the <ulink
  76. url="http://ww1.microchip.com/downloads/en/DeviceDoc/50002053G.pdf">Microchip
  77. XC8 compiler</ulink> which, for the most part, is standards conforming. So
  78. we made the following minimal changes:</para>
  79. <para><itemizedlist>
  80. <listitem>
  81. <para>Factor into <ulink
  82. url="../../example/motor1.c">motor1.c</ulink> which contains the
  83. motor driving code and <ulink
  84. url="../../example/motor_test1.c">motor_test1.c</ulink> which tests
  85. that code.</para>
  86. </listitem>
  87. <listitem>
  88. <para>Include header <code>&lt;xc.h&gt;</code> which contains
  89. constants for the <ulink
  90. url="http://www.microchip.com/wwwproducts/en/PIC18F2520">PIC18F2520</ulink>
  91. processor</para>
  92. </listitem>
  93. <listitem>
  94. <para>Include header <code>&lt;stdint.h&gt;</code> to include
  95. standard Fixed width integer types.</para>
  96. </listitem>
  97. <listitem>
  98. <para>Include header <code>&lt;stdbool.h&gt;</code> to include
  99. keywords true and false in a C program.</para>
  100. </listitem>
  101. <listitem>
  102. <para>The original has some anomalies in the names of types. For
  103. example, int16 is assumed to be unsigned. This is an artifact of the
  104. original C compiler being used. So type names in the code were
  105. altered to standard ones while retaining the intent of the original
  106. code.</para>
  107. </listitem>
  108. <listitem>
  109. <para>Add in missing <code>make16</code> function.</para>
  110. </listitem>
  111. <listitem>
  112. <para>Format code to personal taste.</para>
  113. </listitem>
  114. <listitem>
  115. <para>Replaced enable_interrupts and disable_interrupts functions
  116. with appropriate PIC commands.</para>
  117. </listitem>
  118. </itemizedlist></para>
  119. <para>The resulting program can be checked to be identical to the original
  120. but compiles on with the Microchip XC8 compiler. Given a development
  121. board, we could hook it up to a stepper motor, download and boot the code
  122. and verify that the motor rotates 5 revolutions in each direction with
  123. smooth acceleration and deceleration. We don't have such a board yet, but
  124. the engineers have promised a working board real soon now.</para>
  125. </section>
  126. <section>
  127. <title>Refactor for Testing</title>
  128. <para>In order to develop our test suite and execute the same code on the
  129. desktop and the target system we factor out the shared code as a separate
  130. module which will used in both environments without change. The shared
  131. module <ulink url="../../example/motor2.c"><code><ulink
  132. url="../../example/motor1.c">motor2.c</ulink></code></ulink> contains the
  133. algorithm for handling the interrupts in such a way as to create the
  134. smooth acceleration we require.</para>
  135. <literallayout> <ulink url="../../example/motor2.c"><code><ulink
  136. url="../../example/motor_test2.c">motor_test2.c</ulink></code></ulink> <ulink
  137. url="../../example/motor2.c"><code><ulink
  138. url="../../example/example92.cpp">example92.cpp</ulink></code></ulink>
  139. #include ... #include ...
  140. PIC typedefs ... desktop types ...
  141. \ /
  142. \ /
  143. #include <ulink url="../../example/motor2.c"><code><ulink
  144. url="../../example/motor2.c">motor2.c</ulink></code></ulink>
  145. / \
  146. / \
  147. PIC test code desktop test code</literallayout>
  148. </section>
  149. <section>
  150. <title>Compiling on the Desktop</title>
  151. <para>Using the target environment to run tests is often very difficult or
  152. impossible due to limited resources. So software unit testing for embedded
  153. systems is very problematic and often skipped. The C language on our
  154. desktop is the same used by the <ulink
  155. url="http://www.microchip.com/wwwproducts/en/PIC18F2520">PIC18F2520</ulink>.
  156. So now we can also run and debug the code on our desktop machine. Once our
  157. code passes all our tests, we can download the code to the embedded
  158. hardware and run the code natively. Here is a program we use on the
  159. desktop to do that:</para>
  160. <programlisting><xi:include href="../../example/example92.cpp"
  161. parse="text" xmlns:xi="http://www.w3.org/2001/XInclude"/></programlisting>
  162. <para>Here are the essential features of the desktop version of the test
  163. program.<orderedlist>
  164. <listitem>
  165. <para>Include headers required to support safe integers.</para>
  166. </listitem>
  167. <listitem>
  168. <para>Specify a <link
  169. linkend="safe_numerics.promotion_policy">promotion policy</link> to
  170. support proper emulation of PIC types on the desktop.</para>
  171. <para>The C language standard doesn't specify sizes for primitive
  172. data types like <code>int</code>. They can and do differ between
  173. environments. Hence, the characterization of C/C++ as "portable"
  174. languages is not strictly true. Here we choose aliases for data
  175. types so that they can be defined to be the same in both
  176. environments. But this is not enough to emulate the <ulink
  177. url="http://www.microchip.com/wwwproducts/en/PIC18F2520">PIC18F2520</ulink>
  178. on the desktop. The problem is that compilers implicitly convert
  179. arguments of C expressions to some common type before performing
  180. arithmetic operations. Often, this common type is the native
  181. <code>int</code> and the size of this native type is different in
  182. the desktop and embedded environment. Thus, many arithmetic results
  183. would be different in the two environments.</para>
  184. <para>But now we can specify our own implicit promotion rules for
  185. test programs on the development platform that are identical to
  186. those on the target environment! So unit testing executed in the
  187. development environment can now provide results relevant to the
  188. target environment.</para>
  189. </listitem>
  190. <listitem>
  191. <para>Define PIC integer type aliases to be safe integer types of he
  192. same size.</para>
  193. <para>Code tested in the development environment will use safe
  194. numerics to detect errors. We need these aliases to permit the code
  195. in <ulink url="../../example/motor2.c">motor2.c</ulink> to be tested
  196. in the desktop environment. The same code run in the target system
  197. without change.</para>
  198. </listitem>
  199. <listitem>
  200. <para>Emulate PIC features on the desktop.</para>
  201. <para>The PIC processor, in common with most micro controllers these
  202. days, includes a myriad of special purpose peripherals to handle
  203. things like interrupts, USB, timers, SPI bus, I^2C bus, etc.. These
  204. peripherals are configured using special 8 bit words in reserved
  205. memory locations. Configuration consists of setting particular bits
  206. in these words. To facilitate configuration operations, the XC8
  207. compiler includes a special syntax for setting and accessing bits in
  208. these locations. One of our goals is to permit the testing of the
  209. identical code with our desktop C++ compiler as will run on the
  210. micro controller. To realize this goal, we create some C++ code
  211. which implements the XC8 C syntax for setting bits in particular
  212. memory locations.</para>
  213. </listitem>
  214. <listitem>
  215. <para>include <ulink
  216. url="../../example/motor1.c">motor1.c</ulink></para>
  217. </listitem>
  218. <listitem>
  219. <para>Add test to verify that the motor will be able to keep track
  220. of a position from 0 to 50000 steps. This will be needed to maintain
  221. the position of out linear stage across a range from 0 to 500
  222. mm.</para>
  223. </listitem>
  224. </orderedlist></para>
  225. <para>Our first attempt to run this program fails by throwing an exception
  226. from <ulink url="../../example/motor1.c">motor1.c</ulink> indicating that
  227. the code attempts to left shift a negative number at the
  228. statements:</para>
  229. <programlisting>denom = ((step_no - move) &lt;&lt; 2) + 1;</programlisting>
  230. <para>According to the C/C++ standards this is implementation defined
  231. behavior. But in practice with all modern platforms (as far as I know),
  232. this will be equivalent to a multiplication by 4. Clearly the intent of
  233. the original author is to "micro optimize" the operation by substituting a
  234. cheap left shift for a potentially expensive integer multiplication. But
  235. on all modern compilers, this substitution will be performed automatically
  236. by the compiler's optimizer. So we have two alternatives here:</para>
  237. <itemizedlist>
  238. <listitem>
  239. <para>Just ignore the issue.</para>
  240. <para>This will work when the code is run on the PIC. But, in order to
  241. permit testing on the desktop, we need to inhibit the error detection
  242. in that environment. With safe numerics, error handling is determined
  243. by specifying an <link
  244. linkend="safe_numerics.exception_policy">exception policy</link>. In
  245. this example, we've used the default exception policy which traps
  246. implementation defined behavior. To ignore this kind of behavior we
  247. could define our own custom <link
  248. linkend="safe_numerics.exception_policy">exception
  249. policy</link>.</para>
  250. </listitem>
  251. <listitem>
  252. <para>change the <code>&lt;&lt; 2</code> to <code>* 4</code>. This
  253. will produce the intended result in an unambiguous, portable way. For
  254. all known compilers, this change should not affect runtime performance
  255. in any way. It will result in unambiguously portable code.</para>
  256. </listitem>
  257. <listitem>
  258. <para>Alter the code so that the expression in question is never
  259. negative. Depending on sizes of the operands and the size of the
  260. native integer, this expression might return convert the operands to
  261. int or result in an invalid result.</para>
  262. </listitem>
  263. </itemizedlist>
  264. <para>Of these alternatives, the third seems the more definitive fix so
  265. we'll choose that one. We also decide to make a couple of minor changes to
  266. simplify the code and make mapping of the algorithm in the article to the
  267. code more transparent. With these changes, our test program runs to the
  268. end with no errors or exceptions. In addition, I made a minor change which
  269. simplifies the handling of floating point values in format of 24.8. This
  270. results in <ulink url="../../example/motor2.c">motor2.c</ulink> which
  271. makes the above changes. It should be easy to see that these two versions
  272. are otherwise identical.</para>
  273. <para>Finally our range test fails. In order to handle the full range we
  274. need, we'll have to change some data types used for holding step count and
  275. position. We won't do that here as it would make our example too complex.
  276. We'll deal with this on the next version.</para>
  277. </section>
  278. <section>
  279. <title>Trapping Errors at Compile Time</title>
  280. <para>We can test the same code we're going to load into our target system
  281. on the desktop. We could build and execute a complete unit test suite. We
  282. could capture the output and graph it. We have the ability to make are
  283. code much more likely to be bug free. But:</para>
  284. <itemizedlist>
  285. <listitem>
  286. <para>This system detects errors and exceptions on the test machine -
  287. but it fails to address and detect such problems on the target system.
  288. Since the target system is compiles only C code, we can't use the
  289. exception/error facilities of this library at runtime.</para>
  290. </listitem>
  291. <listitem>
  292. <para><ulink
  293. url="https://en.wikiquote.org/wiki/Edsger_W._Dijkstra">Testing shows
  294. the presence, not the absence of bugs</ulink>. Can we not prove that
  295. all integer arithmetic is correct?</para>
  296. </listitem>
  297. <listitem>
  298. <para>For at least some operations on safe integers there is runtime
  299. cost in checking for errors. In this example, this is not really a
  300. problem as the safe integer code is not included when the code is run
  301. on the target - it's only a C compiler after all. But more generally,
  302. using safe integers might incur an undesired runtime cost.</para>
  303. </listitem>
  304. </itemizedlist>
  305. <para>Can we catch all potential problems at compiler time and therefore
  306. eliminate all runtime cost?</para>
  307. <para>Our first attempt consists of simply changing default exception
  308. policy from the default runtime checking to the compile time trapping one.
  309. Then we redefine the aliases for the types used by the PIC to use this
  310. exception policy.</para>
  311. <programlisting>// generate compile time errors if operation could fail
  312. using trap_policy = boost::numeric::loose_trap_policy;
  313. ...
  314. typedef safe_t&lt;int8_t, trap_policy&gt; int8;
  315. ...
  316. </programlisting>
  317. <para>When we compile now, any expressions which could possibly fail will
  318. be flagged as syntax errors. This occurs 11 times when compiling the
  319. <ulink url="../../example/motor2.c">motor2.c</ulink> program. This is
  320. fewer than one might expect. To understand why, consider the following
  321. example:</para>
  322. <para><programlisting>safe&lt;std::int8_t&gt; x, y;
  323. ...
  324. safe&lt;std::int16_t&gt; z = x + y;
  325. </programlisting>C promotion rules and arithmetic are such that the z will
  326. always contain an arithmetically correct result regardless of what values
  327. are assigned to x and y. Hence there is no need for any kind of checking
  328. of the arithmetic or result. The Safe Numerics library uses compile time
  329. range arithmetic, C++ template multiprogramming and other techniques to
  330. restrict invocation of checking code to only those operations which could
  331. possible fail. So the above code incurs no runtime overhead.</para>
  332. <para>Now we have 11 cases to consider. Our goal is to modify the program
  333. so that this number of cases is reduced - hopefully to zero. Initially I
  334. wanted to just make a few tweaks in the versions of
  335. <code>example92.c</code>, <code>motor2.c</code> and
  336. <code>motor_test2.c</code> above without actually having to understand the
  337. code. It turns out that one needs to carefully consider what various types
  338. and variables are used for. This can be a good thing or a bad thing
  339. depending on one's circumstances, goals and personality. The programs
  340. above evolved into <ulink
  341. url="../../example/example93.c"><code>example93.c</code></ulink>,
  342. <code><ulink url="../../example/motor3.c">motor3.c</ulink></code> and
  343. <ulink
  344. url="../../example/motor_test3.c"><code>motor_test3.c</code></ulink>.
  345. First we'll look at <code>example93.c</code>:</para>
  346. <programlisting><xi:include href="../../example/example93.cpp"
  347. parse="text" xmlns:xi="http://www.w3.org/2001/XInclude"/></programlisting>
  348. <para>Here are the changes we've made int the desktop test
  349. program<orderedlist>
  350. <listitem>
  351. <para>Specify exception policies so we can generate a compile time
  352. error whenever an operation MIGHT fail. We've aliased this policy
  353. with the name <code>trap_policy</code>. The default policy of which
  354. throws a runtime exception when an error is countered is aliased as
  355. <code>exception_policy</code>. When creating safe types, we'll now
  356. specify which type of checking, compile time or runtime, we want
  357. done.</para>
  358. </listitem>
  359. <listitem>
  360. <para>Create a macro named "literal" an integral value that can be
  361. evaluated at compile time.</para>
  362. <para>"literal" values are instances of safe numeric types which are
  363. determined at compile time. They are <code>constexpr</code> values.
  364. When used along with other instances of safe numeric types, the
  365. compiler can calculate the range of the result and verify whether or
  366. not it can be contained in the result type. To create "literal"
  367. types we use the macro <code><link
  368. linkend="safe_numerics.safe_literal.make_safe_literal">make_safe_literal</link>(n,
  369. p, e)</code> where n is the value, p is the <link
  370. linkend="safe_numerics.promotion_policy">promotion policy</link> and
  371. e is the <link linkend="safe_numerics.exception_policy">exception
  372. policy</link>.</para>
  373. <para>When all the values in an expression are safe numeric values,
  374. the compiler can calculate the narrowest range of the result. If all
  375. the values in this range can be represented by the result type, then
  376. it can be guaranteed that an invalid result cannot be produced at
  377. runtime and no runtime checking is required.</para>
  378. <para>Make sure that all literal values are x are replaced with the
  379. macro invocation "literal(x)".</para>
  380. <para>It's unfortunate that the "literal" macro is required as it
  381. clutters the code. The good news is that is some future version of
  382. C++, expansion of <code>constexpr</code> facilities may result in
  383. elimination of this requirement.</para>
  384. </listitem>
  385. <listitem>
  386. <para>Create special types for the motor program. These will
  387. guarantee that values are in the expected ranges and permit compile
  388. time determination of when exceptional conditions might occur. In
  389. this example we create a special type c_t to the width of the pulse
  390. applied to the motor. Engineering constraints (motor load inertia)
  391. limit this value to the range of C0 to C_MIN. So we create a type
  392. with those limits. By using limits no larger than necessary, we
  393. supply enough information for the compiler to determine that the
  394. result of a calculation cannot fall outside the range of the result
  395. type. So less runtime checking is required. In addition, we get
  396. extra verification at compile time that values are in reasonable
  397. ranges for the quantity being modeled.</para>
  398. <para>We call these types "strong types".</para>
  399. </listitem>
  400. </orderedlist></para>
  401. <para>And we've made changes consistent with the above to <ulink
  402. url="../../example/motor3.c">motor3.c</ulink> as well<programlisting><xi:include
  403. href="../../example/motor3.c" parse="text"
  404. xmlns:xi="http://www.w3.org/2001/XInclude"/></programlisting><orderedlist>
  405. <listitem>
  406. <para>Define variables using strong types</para>
  407. </listitem>
  408. <listitem>
  409. <para>Surround all literal values with the "literal" keyword</para>
  410. </listitem>
  411. <listitem>
  412. <para>Re-factor code to make it easier to understand and compare
  413. with the algorithm as described in the original <ulink
  414. url="../../example/stepper-motor.pdf">article</ulink>.</para>
  415. </listitem>
  416. <listitem>
  417. <para>Rewrite interrupt handler in a way which mirrors the original
  418. description of the algorithm and minimizes usage of state variable,
  419. accumulated values, etc.</para>
  420. </listitem>
  421. <listitem>
  422. <para>Distinguish all the statements which might invoke a runtime
  423. exception with a comment. There are 12 such instances.</para>
  424. </listitem>
  425. </orderedlist></para>
  426. <para>Finally we make a couple minor changes in <ulink
  427. url="../../example/motor_test3.c">motor_test3.c</ulink> to verify that we
  428. can compile the exact same version of motor3.c on the PIC as well as on
  429. the desktop.</para>
  430. </section>
  431. <section>
  432. <title>Summary</title>
  433. <para>The intent of this case study is to show that the Safe Numerics
  434. Library can be an essential tool in validating the correctness of C/C++
  435. programs in all environments - including the most restricted.<itemizedlist>
  436. <listitem>
  437. <para>We started with a program written for a tiny micro controller
  438. for controlling the acceleration and deceleration of a stepper
  439. motor. The algorithm for doing this is very non-trivial and
  440. difficult prove that it is correct.</para>
  441. </listitem>
  442. <listitem>
  443. <para>We used the type promotion policies of the Safe Numerics
  444. Library to test and validate this algorithm on the desk top. The
  445. tested code is also compiled for the target micro controller.</para>
  446. </listitem>
  447. <listitem>
  448. <para>We used <emphasis>strong typing</emphasis> features of Safe
  449. Numerics to check that all types hold the values expected and invoke
  450. no invalid implicit conversions. Again the tested code is compiled
  451. for the target processor.</para>
  452. </listitem>
  453. </itemizedlist></para>
  454. <para>What we failed to do is to create a version of the program which
  455. uses the type system to prove that no results can be invalid. I turns out
  456. that states such as</para>
  457. <programlisting>++i;
  458. c = f(c);</programlisting>
  459. <para>can't be proved not to overflow with this system. So we're left with
  460. having to depend upon exhaustive testing. It's not what we hoped, but it's
  461. the best we can do.</para>
  462. </section>
  463. </section>