diff --git a/CMake/CMakeLists.txt b/CMake/CMakeLists.txt index a869dba..ef38f98 100644 --- a/CMake/CMakeLists.txt +++ b/CMake/CMakeLists.txt @@ -201,8 +201,6 @@ file(GLOB example_list "${CMAKE_CURRENT_SOURCE_DIR}/../examples/*.cpp" ) -list(REMOVE_ITEM example_list "../examples/example91.cpp") - foreach(file_path ${example_list}) string(REPLACE "../examples/" "" file_name ${file_path}) string(REPLACE ".cpp" "" base_name ${file_name}) @@ -212,19 +210,6 @@ foreach(file_path ${example_list}) add_test(NAME ${base_name} COMMAND ${base_name}) endforeach(file_path) -add_executable(example91 - ../examples/example91.cpp - ../examples/motor.h - ../examples/18F252.h -) -set_source_files_properties(motor1.c motor.h 18F252.h PROPERTIES LANGUAGE CXX ) - -target_include_directories(example91 PUBLIC - $ - $ # /include/mylib -) -message(STATUS "example91" ) - set_target_properties(test_z example84 PROPERTIES EXCLUDE_FROM_ALL TRUE EXCLUDE_FROM_DEFAULT_BUILD TRUE diff --git a/doc/boostbook/automatic.xml b/doc/boostbook/automatic.xml index 4141536..0d664b4 100644 --- a/doc/boostbook/automatic.xml +++ b/doc/boostbook/automatic.xml @@ -14,12 +14,7 @@
Model of -<<<<<<< HEAD - PromotionPolicy -======= PromotionPolicy ->>>>>>> develop
@@ -34,7 +29,7 @@ The following example illustrates the automatic type being passed as a template parameter for the type - safe<int>. + safe<int>. #include <boost/safe_numerics/safe_integer.hpp> #include <boost/safe_numerics/automatic.hpp> diff --git a/doc/boostbook/eliminate_runtime_penalty.xml b/doc/boostbook/eliminate_runtime_penalty.xml index 721753e..37bd065 100644 --- a/doc/boostbook/eliminate_runtime_penalty.xml +++ b/doc/boostbook/eliminate_runtime_penalty.xml @@ -5,11 +5,11 @@ Eliminating Runtime Penalty Up until now, we've focused on detecting when incorrect results are - produced and handling these occurances either by throwing an exception or + produced and handling these occurrences either by throwing an exception or invoking some designated function. We've achieved our goal of enforcing - arithmetically correct behavior - but at what cost. For many C++ programers + arithmetically correct behavior - but at what cost. For many C++ programmers any runtime penalty is unacceptable. Whether or not one agrees with this - tradeoff, its a fact that many C++ programmers feel this way. So the + trade off, its a fact that many C++ programmers feel this way. So the question arises as to how we alter our program to minimize or eliminate any runtime penalty. @@ -116,7 +116,7 @@ long z = (long)x + (long)y; // can never overflow Since the result type is guaranteed to hold the result, there is no need to check for errors - they can't happen !!! The usage of "trap_exception" - exception policy enforces this guarentee + exception policy enforces this guarantee @@ -285,7 +285,7 @@ z = (x + y) = <int>[-48,164] = 4 When variables are read from the console and assigned to safe_t variables x and y, they are checked for legal values. We need at hoc code to do this, as these types are guaranteed to contain - legal values and will throw an exception when this guarentee is + legal values and will throw an exception when this guarantee is violated. In other words, we automatically get checking of input variables with no additional programming. diff --git a/doc/boostbook/motor.xml b/doc/boostbook/motor.xml new file mode 100644 index 0000000..5c4bbed --- /dev/null +++ b/doc/boostbook/motor.xml @@ -0,0 +1,68 @@ + + +
+ Case Study: Safety Critical Embedded Controller + + Suppose we are given the task of creating stepper motor driver + software to drive a robotic hand to be used in micro surgery. The processor + that has been selected by the engineers is the PIC18F252 manufactured by + Microchip Corporation. On a processor this small, it's common to use a + mixture of 8, 16, and 32 bit data types in order to conserve memory space + and minimize memory footprint and runtime penalty. + + Requirements: + + Algorithm must be verifiable. + + + + Code must match the algorithm. + + + + No user interface available. + + + + No user input available. + + + + No exceptional conditions such as interrupts permitted. + + + + The system has no i/o other than a few pins to control the + stepper motor. + + + + Actually this is a pretty common scenario. The only difference in this + case are the extreme consequences associated with violations of the above + requirements. We will start making a basic working prototype. This we will + enhance in a stepwise fashion until all the above requirements are + met. + +
+ First Prototype + + 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. Searching around the net, we find a + popular article + on the operation of stepper motors using simple micro controllers. The + algorithm is very well explains and it includes a complete code example we can test. Starting + with the original code we make the following changes: + + We create a new file " + + + + + + +
+
diff --git a/doc/boostbook/safe_numerics.xml b/doc/boostbook/safe_numerics.xml index 94df15b..eaa2e98 100644 --- a/doc/boostbook/safe_numerics.xml +++ b/doc/boostbook/safe_numerics.xml @@ -302,6 +302,32 @@ replacement for T so it has to implement all the operations. + + + + According to C/C++ standards, unsigned integers cannot + overflow - they are modular integers which "warp around". Yet the + safe numerics library detects and traps this behavior as errors. Why + is that? + + + + The guiding purpose of the library is to trap incorrect + arithmetic behavior - not just undefined behavior. Although a savvy + user may understand and keep present in his mind that an unsigned + integer is really modular type, the plain reading of an arithmetic + expression conveys the idea that all operands are plain integers. + Also in many cases, unsigned integers are used in cases where + modular arithmetic is not intended, such as array indexes. Finally, + the modulus for such an integer would vary depending upon the + machine architecture. For these reasons, in the context of this + library, an unsigned integer is considered to a representation of a + subset of integers which is expected to provide correct integer + results. Note that this decision is consistent with INT30-C, “Ensure + that unsigned integer operations do not wrap” in the CERT C Secure + Coding Standard [Seacord 2008].. + +
@@ -660,5 +686,93 @@ to C++ standard libraries + + + + + + Jad Mouawad + + + + <ulink url="http://www.cert.org/secure-coding/publications/books/secure-coding-c-c-second-edition.cfm?"> + <ulink + url="http://www.nytimes.com/2015/05/01/business/faa-orders-fix-for-possible-power-loss-in-boeing-787.html?_r=0">F.A.A + Orders Fix for Possible Power Loss in Boeing 787</ulink> + </ulink> + + + New York Times + + April 30, 2015 + + + Federal regulators will order operators of Boeing 787 + Dreamliners to shut down the plane’s electrical power periodically + after Boeing discovered a software error that could result in a total + loss of power. + + + + + + + David + + Keaton + + + + Thomas + + Plum + + + + Robert + + C. + + Seacord + + + + David + + Svoboda + + + + Alex + + Volkovitsky + + + + Timothy + + Wilson + + + + + <ulink url="http://www.cert.org/secure-coding/publications/books/secure-coding-c-c-second-edition.cfm?"> + <ulink + url="http://resources.sei.cmu.edu/asset_files/TechnicalNote/2009_004_001_15074.pdf">As-if + Infinitely Ranged Integer Model</ulink> + </ulink> + + + + Software Engineering + Institute + + + CMU/SEI-2009-TN-023 + + + Presents a model for addressing integer overflow errors. + + diff --git a/examples/18F252.h b/examples/18F252.h index f954ab9..c26bb48 100644 --- a/examples/18F252.h +++ b/examples/18F252.h @@ -15,54 +15,6 @@ // any program which uses this is destined to be run on // the desk top for debugging. So set indicator here -#define DESKTOP - -/* -#include -#include - -#include "../include/cpp.hpp" -#include "../include/automatic.hpp" -#include "../include/exception.hpp" -#include "../include/safe_integer.hpp" -#include "../include/safe_range.hpp" -#include "../include/safe_literal.hpp" - -// use same type promotion as used by the pic compiler -// see the following comment in motor.c -// Types: int8,int16,int32=8,16,32bit integers, unsigned by default - -using pic16_promotion = boost::numeric::cpp< - 8, // char - 8, // short - 8, // int - 16, // long - 32 // long long ->; - -// define safe types used desktop version of the program. In conjunction -// with the promotion policy above, this will permit us to guarantee that -// the resulting program will be free of arithmetic errors introduced by -// C expression syntax and type promotion with no runtime penalty -template // T is char, int, etc data type -using safe_t = boost::numeric::safe< - T, - pic16_promotion, - boost::numeric::throw_exception // use for compiling and running tests ->; -using safe_bool_t = boost::numeric::safe_unsigned_range< - 0, - 1, - pic16_promotion, - boost::numeric::throw_exception // use for compiling and running tests ->; - -// define a macro for literal types. This may not be strictly necessary -// but it provides more information at compile time to the safe numerics -// library which may result in faster code. -#define literal(x) boost::numeric::safe_literal{} -*/ - // define alias the same as used by the pic compiler as safe types for // the desktop // see the following comment in motor.c diff --git a/examples/18F252_desktop.h b/examples/18F252_desktop.h new file mode 100644 index 0000000..bb531fb --- /dev/null +++ b/examples/18F252_desktop.h @@ -0,0 +1,87 @@ +#ifndef PIC18F252_H +#define PIC18F252_H + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +// 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) + +// any program which uses this is destined to be run on +// the desk top for debugging. So set indicator here + +// define alias the same as used by the pic compiler as safe types for +// the desktop +// see the following comment in motor.c +// Types: int8,int16,int32=8,16,32bit integers, unsigned by default +using int8 = safe_t; +using int16 = safe_t; +using int32 = safe_t; +using uint8 = safe_t; +using uint16 = safe_t; +using uint32 = safe_t; +using signed_int8 = safe_t; +using signed_int16 = safe_t; +using signed_int32 = safe_t; + +// define special type for unsigned modulo N integers +using mod16 = boost::uint_t<16>::exact; +using mod8 = boost::uint_t<8>::exact; + +// implement equivalent to #bit in C++ + +// this types is meant to implement operations of naming bits +// which are part of a larger word. +// example +// unsigned int x. +// bit switch; // switch now refers to the +// second bit from the right of the variable x. So now can use: +// +// switch = 1; +// if(switch) +// ... + +template +struct bit { + T & m_word; + bit(T & rhs) : + m_word(rhs) + {} + bit & operator=(const safe_bool_t & b){ + if(b) + m_word |= (1 << N); + else + m_word &= ~(1 << N); + return *this; + } + bit & operator=(const boost::numeric::safe_literal<0>){ + m_word &= ~(1 << N); + return *this; + } + bit & operator=(const boost::numeric::safe_literal<1>){ + m_word |= (1 << N); + return *this; + } + operator safe_bool_t () const { + return m_word >> N & 1; + } +}; + +// make a 16 bit value from two 8 bit ones +int16 inline make16(int8 h, int8 l){ + return (h << literal(8)) | l; +} + +#define disable_interrupts(x) +#define enable_interrupts(x) +#define output_c(x) +#define set_tris_c(x) +#define TRUE literal(1) +#define FALSE literal(0) + +#endif // PIC18F252_H diff --git a/examples/Motor1.c b/examples/Motor1.c index 52fcadc..4f199c8 100644 --- a/examples/Motor1.c +++ b/examples/Motor1.c @@ -1,198 +1,188 @@ -////////////////////////////////////////////////////////////////// -// motor.c -// 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 - -////////////////////////////////////////////////////////////////// -// Note: -// changes to original source code to permit desktop compile, test -// and debug while remaining compatible with pic compiler. These -// changes to the original code are marked with RR below - -// Robert Ramey, 2015 - -// note changes to original source code -// -// signed int16 <- signed_int16 note '-' added -// commented out the #byte and #bit statements -// commented out the #INT_CCP1 -// changed instances of x = 0 to x = literal(0) - -// *********** -// RR factor out motor.c so motor code can be separated from tests -// and other user code. -#include "motor.h" - -#if !defined(DESKTOP) - #include "picsfr.h" -#else - // define a memory map to emulate the on in the pic. This permits all - // same pic code to work on the desktop with no alteration - std::uint8_t base[0xfff]; - // now we can render - //#bit TMR1ON = T1CON.0 as - bit TMR1ON(T1CON); - // and use expressions such as TMR1ON = 0 -#endif - -// 1st step=50ms; max speed=120rpm (based on 1MHz timer, 1.8deg steps) -#define C0 literal(50000) -#define C_MIN literal(2500) - -// ramp state-machine states -#define ramp_idle literal(0) -#define ramp_up literal(1) -#define ramp_max literal(2) -#define ramp_down literal(3) -#define ramp_last literal(4) - -// Types: int8,int16,int32=8,16,32bit integers, unsigned by default -int8 ramp_sts=ramp_idle; -signed_int16 motor_pos = literal(0); // absolute step number -signed_int16 pos_inc = literal(0); // motor_pos increment -int16 phase=literal(0); // ccpPhase[phase_ix] -int8 phase_ix=literal(0); // index to ccpPhase[] -int8 phase_inc; // phase_ix increment -int8 run_flg; // true while motor is running -int16 ccpr; // copy of CCPR1&2 -int16 c; // integer delay count -int16 step_no; // progress of move -int16 step_down; // start of down-ramp -int16 move; // total steps to move -int16 midpt; // midpoint of move -int32 c32; // 24.8 fixed point delay count -signed_int16 denom; // 4.n+1 in ramp algo - -// Config data to make CCP1&2 generate quadrature sequence on PHASE pins -// Action on CCP match: 8=set+irq; 9=clear+irq -int16 const ccpPhase[] = { - literal(0x909), - literal(0x908), - literal(0x808), - literal(0x809) -}; // 00,01,11,10 - -void current_on(){/* code as needed */} // motor drive current -void current_off(){/* code as needed */} // reduce to holding value - -// RR compiler-specific ISR declaration -// #if ! defined(DESKTOP) -// #INT_CCP1 -// #endif -void isr_motor_step() -{ // CCP1 match -> step pulse + IRQ - ccpr += c; // next comparator value: add step delay count - switch (ramp_sts) - { - case ramp_up: // accel - if (step_no==midpt) - { // midpoint: decel - ramp_sts = ramp_down; - denom = ((step_no - move) << literal(2) )+literal(1); - - if (!(move & literal(1))) - { // even move: repeat last delay before decel - denom +=literal(4); - break; - } - } - // no break: share code for ramp algo - case ramp_down: // decel - if (step_no == move-literal(1)) - { // next irq is cleanup (no step) - ramp_sts = ramp_last; - break; - } - denom+=4; - c32 -= (c32 << literal(1)) / denom; // ramp algorithm - // beware confict with foreground code if long div not reentrant - c = (c32+literal(128))>>literal(8); // round 24.8format->int16 - if (c <= C_MIN) - { // go to constant speed - ramp_sts = ramp_max; - step_down = move - step_no; - c = C_MIN; - break; - } - break; - case ramp_max: // constant speed - if (step_no == step_down) - { // start decel - ramp_sts = ramp_down; - denom = ((step_no - move)<> literal(8)); // timer value at next CCP match - CCPR2L = CCPR1L = (ccpr & literal(0xff)); - if (ramp_sts!=ramp_last) // else repeat last action: no step - phase_ix = (phase_ix + phase_inc) & literal(3); - phase = ccpPhase[phase_ix]; - CCP1CON = phase & literal(0xff); // set CCP action on next match - CCP2CON = phase >> literal(8); - } // if (ramp_sts != ramp_idle) -} // isr_motor_step() - -void motor_run(signed_int16 pos_new) -{ // set up to drive motor to pos_new (absolute step#) - if (pos_new < motor_pos) // get direction & #steps - { - move = motor_pos-pos_new; - pos_inc = literal(-1); - phase_inc = literal(0xff); - } - else if (pos_new != motor_pos) - { - move = pos_new-motor_pos; - pos_inc = literal(1); - phase_inc = literal(1); - } - else return; // already there - midpt = (move-1)>>1; - c = C0; - c32 = c<> literal(8)); - CCPR2L = CCPR1L = (ccpr & literal(0xff)); - phase_ix = (phase_ix + phase_inc) & literal(3); - phase = ccpPhase[phase_ix]; - CCP1CON = phase & literal(0xff); // sets action on match - CCP2CON = phase >> literal(8); - current_on(); // current in motor windings - enable_interrupts(INT_CCP1); - TMR1ON = literal(0); // restart timer1; -} // motor_run() - -void initialize() -{ - disable_interrupts(GLOBAL); - disable_interrupts(INT_CCP1); - disable_interrupts(INT_CCP2); - output_c(0); - set_tris_c(0); - T3CON = 0; - T1CON = 0x35; - enable_interrupts(GLOBAL); -} - -// end of file motor.c +////////////////////////////////////////////////////////////////// +// motor.c +// 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 + +////////////////////////////////////////////////////////////////// +// Note: +// changes to original source code to permit desktop compile, test +// and debug while remaining compatible with pic compiler. These +// changes to the original code are marked with RR below + +// Robert Ramey, 2015 + +// note changes to original source code +// +// signed int16 <- signed_int16 note '-' added +// commented out the #byte and #bit statements +// commented out the #INT_CCP1 + +// *********** +// RR factor out motor.c so motor code can be separated from tests +// and other user code. +#include "motor.h" + +#if !defined(DESKTOP) + #include "picsfr.h" +#else + // define a memory map to emulate the on in the pic. This permits all + // same pic code to work on the desktop with no alteration + std::uint8_t base[0xfff]; + // now we can render + //#bit TMR1ON = T1CON.0 as + bit TMR1ON(T1CON); + // and use expressions such as TMR1ON = 0 +#endif + +// 1st step=50ms; max speed=120rpm (based on 1MHz timer, 1.8deg steps) +#define C0 50000 +#define C_MIN 2500 + +// ramp state-machine states +#define ramp_idle 0 +#define ramp_up 1 +#define ramp_max 2 +#define ramp_down 3 +#define ramp_last 4 + +// Types: int8,int16,int32=8,16,32bit integers, unsigned by default +int8 ramp_sts=ramp_idle; +signed_int16 motor_pos = 0; // absolute step number +signed_int16 pos_inc=0; // motor_pos increment +int16 phase=0; // ccpPhase[phase_ix] +int8 phase_ix=0; // index to ccpPhase[] +int8 phase_inc; // phase_ix increment +int8 run_flg; // true while motor is running +int16 ccpr; // copy of CCPR1&2 +int16 c; // integer delay count +int16 step_no; // progress of move +int16 step_down; // start of down-ramp +int16 move; // total steps to move +int16 midpt; // midpoint of move +int32 c32; // 24.8 fixed point delay count +signed_int16 denom; // 4.n+1 in ramp algo + +// Config data to make CCP1&2 generate quadrature sequence on PHASE pins +// Action on CCP match: 8=set+irq; 9=clear+irq +int16 const ccpPhase[] = {0x909, 0x908, 0x808, 0x809}; // 00,01,11,10 + +void current_on(){/* code as needed */} // motor drive current +void current_off(){/* code as needed */} // reduce to holding value + +// compiler-specific ISR declaration +// #INT_CCP1 +void isr_motor_step() +{ // CCP1 match -> step pulse + IRQ + ccpr += c; // next comparator value: add step delay count + switch (ramp_sts) + { + case ramp_up: // accel + if (step_no==midpt) + { // midpoint: decel + ramp_sts = ramp_down; + denom = ((step_no - move)<<2)+1; + if (!(move & 1)) + { // even move: repeat last delay before decel + denom +=4; + break; + } + } + // no break: share code for ramp algo + case ramp_down: // decel + if (step_no == move-1) + { // next irq is cleanup (no step) + ramp_sts = ramp_last; + break; + } + denom+=4; + c32 -= (c32<<1)/denom; // ramp algorithm + // beware confict with foreground code if long div not reentrant + c = (c32+128)>>8; // round 24.8format->int16 + if (c <= C_MIN) + { // go to constant speed + ramp_sts = ramp_max; + step_down = move - step_no; + c = C_MIN; + break; + } + break; + case ramp_max: // constant speed + if (step_no == step_down) + { // start decel + ramp_sts = ramp_down; + denom = ((step_no - move)<<2)+5; + } + break; + default: // last step: cleanup + ramp_sts = ramp_idle; + current_off(); // reduce motor current to holding value + disable_interrupts(INT_CCP1); + run_flg = FALSE; // move complete + break; + } // switch (ramp_sts) + if (ramp_sts!=ramp_idle) + { + motor_pos += pos_inc; + ++step_no; + CCPR2H = CCPR1H = (ccpr >> 8); // timer value at next CCP match + CCPR2L = CCPR1L = (ccpr & 0xff); + if (ramp_sts!=ramp_last) // else repeat last action: no step + phase_ix = (phase_ix + phase_inc) & 3; + phase = ccpPhase[phase_ix]; + CCP1CON = phase & 0xff; // set CCP action on next match + CCP2CON = phase >> 8; + } // if (ramp_sts != ramp_idle) +} // isr_motor_step() + +void motor_run(short pos_new) +{ // set up to drive motor to pos_new (absolute step#) + if (pos_new < motor_pos) // get direction & #steps + { + move = motor_pos-pos_new; + pos_inc = -1; + phase_inc = 0xff; + } + else if (pos_new != motor_pos) + { + move = pos_new-motor_pos; + pos_inc = 1; + phase_inc = 1; + } + else return; // already there + midpt = (move-1)>>1; + c = C0; + c32 = c<<8; // keep c in 24.8 fixed-point format for ramp calcs + step_no = 0; // step counter + denom = 1; // 4.n+1, n=0 + ramp_sts = ramp_up; // start ramp state-machine + run_flg = TRUE; + TMR1ON = 0; // stop timer1; + ccpr = make16(TMR1H,TMR1L); // 16bit value of Timer1 + ccpr += 1000; // 1st step + irq 1ms after timer1 restart + CCPR2H = CCPR1H = (ccpr >> 8); + CCPR2L = CCPR1L = (ccpr & 0xff); + phase_ix = (phase_ix + phase_inc) & 3; + phase = ccpPhase[phase_ix]; + CCP1CON = phase & 0xff; // sets action on match + CCP2CON = phase >> 8; + current_on(); // current in motor windings + enable_interrupts(INT_CCP1); + TMR1ON=1; // restart timer1; +} // motor_run() + +void initialize() +{ + disable_interrupts(GLOBAL); + disable_interrupts(INT_CCP1); + disable_interrupts(INT_CCP2); + output_c(0); + set_tris_c(0); + T3CON = 0; + T1CON = 0x35; + enable_interrupts(GLOBAL); +} // initialize() + diff --git a/examples/example91.cpp b/examples/example91.cpp index aa88692..3efc920 100644 --- a/examples/example91.cpp +++ b/examples/example91.cpp @@ -52,6 +52,7 @@ using safe_bool_t = boost::numeric::safe_unsigned_range< //#define literal(x) boost::numeric::safe_literal{} #define literal(x) x +#define DESKTOP #include "motor1.c" #include diff --git a/examples/example92.cpp b/examples/example92.cpp new file mode 100644 index 0000000..f2c8dbe --- /dev/null +++ b/examples/example92.cpp @@ -0,0 +1,85 @@ +////////////////////////////////////////////////////////////////// +// example91.cpp +// +// 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) + +#include +#include +#include + +#include "../include/cpp.hpp" +#include "../include/automatic.hpp" +#include "../include/exception.hpp" +#include "../include/safe_integer.hpp" +#include "../include/safe_range.hpp" +#include "../include/safe_literal.hpp" + +// use same type promotion as used by the pic compiler +// see the following comment in motor.c +// Types: int8,int16,int32=8,16,32bit integers, unsigned by default + +using pic16_promotion = boost::numeric::cpp< + 8, // char + 8, // short + 8, // int + 16, // long + 32 // long long +>; + +// define safe types used desktop version of the program. In conjunction +// with the promotion policy above, this will permit us to guarantee that +// the resulting program will be free of arithmetic errors introduced by +// C expression syntax and type promotion with no runtime penalty +template // T is char, int, etc data type +using safe_t = boost::numeric::safe< + T, + pic16_promotion, + boost::numeric::throw_exception // use for compiling and running tests +>; +using safe_bool_t = boost::numeric::safe_unsigned_range< + 0, + 1, + pic16_promotion, + boost::numeric::throw_exception // use for compiling and running tests +>; + +#define DESKTOP +#include "motor2.c" + +#include +#include + +void test(int16 m){ + std::cout << "move motor to " << m << '\n'; + int i = 0; + motor_run(m); + do{ + isr_motor_step(); + std::cout << ++i << ' ' << c32 << ' ' << c << '\n'; + std::this_thread::sleep_for(std::chrono::microseconds(ccpr)); + }while(run_flg); +} + +int main() +{ + std::cout << "start test\n"; + try{ + initialize(); + // move motor to position 100 + test(100); + // move motor to position 1000 + //test(1000); + // move back to position 0 + test(0); + } + catch(...){ + std::cout << "test interrupted\n"; + return 1; + } + std::cout << "end test\n"; + return 0; +} \ No newline at end of file diff --git a/examples/example93.cpp b/examples/example93.cpp new file mode 100644 index 0000000..623fbcf --- /dev/null +++ b/examples/example93.cpp @@ -0,0 +1,100 @@ +////////////////////////////////////////////////////////////////// +// example91.cpp +// +// 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) + +#include +#include +#include + +#include "../include/cpp.hpp" +#include "../include/automatic.hpp" +#include "../include/exception.hpp" +#include "../include/safe_integer.hpp" +#include "../include/safe_range.hpp" +#include "../include/safe_literal.hpp" + +// use same type promotion as used by the pic compiler +// see the following comment in motor.c +// Types: int8,int16,int32=8,16,32bit integers, unsigned by default + +using pic16_promotion = boost::numeric::cpp< + 8, // char + 8, // short + 8, // int + 16, // long + 32 // long long +>; + +// define safe types used desktop version of the program. In conjunction +// with the promotion policy above, this will permit us to guarantee that +// the resulting program will be free of arithmetic errors introduced by +// C expression syntax and type promotion with no runtime penalty +template // T is char, int, etc data type +using safe_t = boost::numeric::safe< + T, + boost::numeric::automatic, + boost::numeric::trap_exception // use for compiling and running tests +>; +using safe_bool_t = boost::numeric::safe_unsigned_range< + 0, + 1, + pic16_promotion, + boost::numeric::trap_exception // use for compiling and running tests +>; + +using step_t = boost::numeric::safe_signed_range< + 0, + 1000, + boost::numeric::automatic, + boost::numeric::trap_exception +>; +using denom_t = boost::numeric::safe_signed_range< + 1, + 4001, + boost::numeric::automatic, + boost::numeric::trap_exception +>; + +#define literal(x) boost::numeric::safe_literal{} + +#define DESKTOP +#include "motor3.c" + +#include +#include + +void test(int16 m){ + std::cout << "move motor to " << m << '\n'; + int i = 0; + motor_run(m); + do{ + isr_motor_step(); + std::cout << ++i << ' ' << c32 << ' ' << c << '\n'; + std::this_thread::sleep_for(std::chrono::microseconds(ccpr)); + }while(run_flg); +} + +int main() +{ + std::cout << "start test\n"; + try{ + initialize(); + // move motor to position 100 + test(100); + // move motor to position 1000 + //test(1000); + // move back to position 0 + test(0); + } + catch(...){ + std::cout << "test interrupted\n"; + return 1; + } + std::cout << "end test\n"; + return 0; +} \ No newline at end of file diff --git a/examples/motor.h b/examples/motor.h index ba285e7..90a1446 100644 --- a/examples/motor.h +++ b/examples/motor.h @@ -11,14 +11,16 @@ // RR on desktop - this resolves to special file for usage in that // environment -#include "18F252.h" #if ! defined(DESKTOP) + #include "18F252.h" // include pic sfr map only on pic compilers which support the // #byte preprocessor statement. In other environments, this // provokes unsuppressable syntax error. #include "picsfr.h" #else + #include "18F252_desktop.h" + extern std::uint8_t base[0xfff]; extern bit TMR1ON; @@ -36,7 +38,7 @@ #endif extern "C" void isr_motor_step(); -extern "C" void motor_run(signed_int16 pos_new); +extern "C" void motor_run(int16 pos_new); extern "C" void initialize(); int8 get_run_flg(); diff --git a/examples/motor2.c b/examples/motor2.c new file mode 100644 index 0000000..f5a5596 --- /dev/null +++ b/examples/motor2.c @@ -0,0 +1,211 @@ +////////////////////////////////////////////////////////////////// +// motor.c +// 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 + +////////////////////////////////////////////////////////////////// +// Note: +// changes to original source code to permit desktop compile, test +// and debug while remaining compatible with pic compiler. These +// changes to the original code are marked with RR below + +// Robert Ramey, 2015 + +// note changes to original source code +// +// signed int16 <- signed_int16 note '-' added +// commented out the #byte and #bit statements +// commented out the #INT_CCP1 + +// *********** +// RR factor out motor.c so motor code can be separated from tests +// and other user code. + +// a) changed step_no and move to signed 16 bit integer types +// b) replaced bit shifts by multiplications. bit shifts are not +// guaranteed portable. Decent compilers should implements +// const multiplications by powers of 2 as bit shifts anyway +// c) changed c32 to 32 bit signed integer type +// d) changed phase_inc to 8 bit signed type +// e) factored phase index into phase_bump in order to have +// standard conforming code + +#include "motor.h" + +#if !defined(DESKTOP) + #include "picsfr.h" + #define mod16 int16 +#else + // define a memory map to emulate the on in the pic. This permits all + // same pic code to work on the desktop with no alteration + std::uint8_t base[0xfff]; + // now we can render + //#bit TMR1ON = T1CON.0 as + bit TMR1ON(T1CON); + // and use expressions such as TMR1ON = 0 +#endif + +// 1st step=50ms; max speed=120rpm (based on 1MHz timer, 1.8deg steps) +#define C0 50000 +#define C_MIN 2500 + +// ramp state-machine states +#define ramp_idle 0 +#define ramp_up 1 +#define ramp_max 2 +#define ramp_down 3 +#define ramp_last 4 + +// Types: int8,int16,int32=8,16,32bit integers, unsigned by default +int8 ramp_sts=ramp_idle; +signed_int16 motor_pos = 0; // absolute step number +signed_int16 pos_inc=0; // motor_pos increment +int16 phase=0; // ccpPhase[phase_ix] +int8 phase_ix=0; // index to ccpPhase[] +int8 phase_inc; // phase_ix increment +int8 run_flg; // true while motor is running +mod16 ccpr; // copy of CCPR1&2 +mod16 c; // integer delay count +signed_int16 step_no; // progress of move +int16 step_down; // start of down-ramp +signed_int16 move; // total steps to move +int16 midpt; // midpoint of move +signed_int32 c32; // 24.8 fixed point delay count +signed_int16 denom; // 4.n+1 in ramp algo + +// Config data to make CCP1&2 generate quadrature sequence on PHASE pins +// Action on CCP match: 8=set+irq; 9=clear+irq +int16 const ccpPhase[] = {0x909, 0x908, 0x808, 0x809}; // 00,01,11,10 + +void current_on(){/* code as needed */} // motor drive current +void current_off(){/* code as needed */} // reduce to holding value + +void phase_bump() +{ + if(phase_inc > 0) + if(phase_ix == 3) + phase_ix = 0; + else + ++phase_ix; + else + // phase_inc < 0 + if(phase_ix == 0) + phase_ix = 3; + else + --phase_ix; + phase = ccpPhase[phase_ix]; + CCP1CON = phase & 0xff; // set CCP action on next match + CCP2CON = phase >> 8; +} +// compiler-specific ISR declaration +// #INT_CCP1 +void isr_motor_step() +{ // CCP1 match -> step pulse + IRQ + ccpr += c; // next comparator value: add step delay count + switch (ramp_sts) + { + case ramp_up: // accel + if (step_no==midpt) + { // midpoint: decel + ramp_sts = ramp_down; + denom = ((step_no - move) * 4) + 1; + if (!(move & 1)) + { // even move: repeat last delay before decel + denom +=4; + break; + } + } + // no break: share code for ramp algo + case ramp_down: // decel + if (step_no == move-1) + { // next irq is cleanup (no step) + ramp_sts = ramp_last; + break; + } + denom+=4; + c32 -= (c32 * 2) / denom; // ramp algorithm + // beware confict with foreground code if long div not reentrant + c = (c32 + 128) / 256; // round 24.8format->int16 + if (c <= C_MIN) + { // go to constant speed + ramp_sts = ramp_max; + step_down = move - step_no; + c = C_MIN; + break; + } + break; + case ramp_max: // constant speed + if (step_no == step_down) + { // start decel + ramp_sts = ramp_down; + denom = ((step_no - move) * 4) + 5; + } + break; + default: // last step: cleanup + ramp_sts = ramp_idle; + current_off(); // reduce motor current to holding value + disable_interrupts(INT_CCP1); + run_flg = FALSE; // move complete + break; + } // switch (ramp_sts) + if (ramp_sts!=ramp_idle) + { + motor_pos += pos_inc; + ++step_no; + CCPR2H = CCPR1H = (ccpr >> 8); // timer value at next CCP match + CCPR2L = CCPR1L = (ccpr & 0xff); + + if (ramp_sts!=ramp_last) // else repeat last action: no step + phase_bump(); + } // if (ramp_sts != ramp_idle) +} // isr_motor_step() + +void motor_run(int16 pos_new) +{ // set up to drive motor to pos_new (absolute step#) + if (pos_new < motor_pos) // get direction & #steps + { + move = motor_pos-pos_new; + pos_inc = -1; + phase_inc = -1; + } + else if (pos_new != motor_pos) + { + move = pos_new-motor_pos; + pos_inc = 1; + phase_inc = 1; + } + else return; // already there + midpt = (move-1)>>1; + c = C0; + c32 = c * 256; // keep c in 24.8 fixed-point format for ramp calcs + step_no = 0; // step counter + denom = 1; // 4.n+1, n=0 + ramp_sts = ramp_up; // start ramp state-machine + run_flg = TRUE; + TMR1ON = 0; // stop timer1; + ccpr = make16(TMR1H,TMR1L); // 16bit value of Timer1 + ccpr += 1000; // 1st step + irq 1ms after timer1 restart + CCPR2H = CCPR1H = (ccpr >> 8); + CCPR2L = CCPR1L = (ccpr & 0xff); + phase_bump(); + current_on(); // current in motor windings + enable_interrupts(INT_CCP1); + TMR1ON=1; // restart timer1; +} // motor_run() + +void initialize() +{ + disable_interrupts(GLOBAL); + disable_interrupts(INT_CCP1); + disable_interrupts(INT_CCP2); + output_c(0); + set_tris_c(0); + T3CON = 0; + T1CON = 0x35; + enable_interrupts(GLOBAL); +} // initialize() + diff --git a/examples/motor3.c b/examples/motor3.c new file mode 100644 index 0000000..eb50cd7 --- /dev/null +++ b/examples/motor3.c @@ -0,0 +1,219 @@ +////////////////////////////////////////////////////////////////// +// motor.c +// 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 + +////////////////////////////////////////////////////////////////// +// Note: +// changes to original source code to permit desktop compile, test +// and debug while remaining compatible with pic compiler. These +// changes to the original code are marked with RR below + +// Robert Ramey, 2015 + +// note changes to original source code +// +// signed int16 <- signed_int16 note '-' added +// commented out the #byte and #bit statements +// commented out the #INT_CCP1 + +// *********** +// RR factor out motor.c so motor code can be separated from tests +// and other user code. + +// a) changed step_no and move to signed 16 bit integer types +// b) replaced bit shifts by multiplications. bit shifts are not +// guaranteed portable. Decent compilers should implements +// const multiplications by powers of 2 as bit shifts anyway +// c) changed c32 to 32 bit signed integer type +// d) changed phase_inc to 8 bit signed type +// e) factored phase index into phase_bump in order to have +// standard conforming code + +#include "motor3.h" + +#if !defined(DESKTOP) + #include "picsfr.h" + #define mod16 int16 + #define literal(x) +#else + // define a memory map to emulate the on in the pic. This permits all + // same pic code to work on the desktop with no alteration + std::uint8_t base[0xfff]; + // now we can render + //#bit TMR1ON = T1CON.0 as + bit TMR1ON(T1CON); + // and use expressions such as TMR1ON = 0 +#endif + +// 1st step=50ms; max speed=120rpm (based on 1MHz timer, 1.8deg steps) +#define C0 50000 +#define C_MIN 2500 + +// ramp state-machine states +#define ramp_idle literal(0) +#define ramp_up literal(1) +#define ramp_max literal(2) +#define ramp_down literal(3) +#define ramp_last literal(4) + + + +// Types: int8,int16,int32=8,16,32bit integers, unsigned by default +int8 ramp_sts=ramp_idle; +step_t motor_pos = literal(0); // absolute step number +step_t pos_inc = literal(0); // motor_pos increment +int16 phase = literal(0); // ccpPhase[phase_ix] +int8 phase_ix = literal(0); // index to ccpPhase[] +int8 phase_inc; // phase_ix increment +int8 run_flg; // true while motor is running +mod16 ccpr; // copy of CCPR1&2 +mod16 c; // integer delay count +step_t step_no; // progress of move +step_t step_down; // start of down-ramp +step_t move; // total steps to move +step_t midpt; // midpoint of move +signed_int32 c32; // 24.8 fixed point delay count +denom_t denom; // 4.n+1 in ramp algo + +// Config data to make CCP1&2 generate quadrature sequence on PHASE pins +// Action on CCP match: 8=set+irq; 9=clear+irq +int16 const ccpPhase[] = { + literal(0x909), + literal(0x908), + literal(0x808), + literal(0x809) +}; // 00,01,11,10 + +void current_on(){/* code as needed */} // motor drive current +void current_off(){/* code as needed */} // reduce to holding value + +void phase_bump() +{ + if(phase_inc > 0) + if(phase_ix == 3) + phase_ix = literal(0); + else + ++phase_ix; + else + // phase_inc < 0 + if(phase_ix == 0) + phase_ix = literal(3); + else + --phase_ix; + phase = ccpPhase[phase_ix]; + CCP1CON = phase & literal(0xff); // set CCP action on next match + CCP2CON = phase >> literal(8); +} +// compiler-specific ISR declaration +// #INT_CCP1 +void isr_motor_step() +{ // CCP1 match -> step pulse + IRQ + ccpr += c; // next comparator value: add step delay count + switch (ramp_sts) + { + case ramp_up: // accel + if (step_no==midpt) + { // midpoint: decel + ramp_sts = ramp_down; + denom = ((step_no - move) * literal(4)) + literal(1); + if (!(move & literal(1))) + { // even move: repeat last delay before decel + denom += literal(4); + break; + } + } + // no break: share code for ramp algo + case ramp_down: // decel + if (step_no == move - literal(1)) + { // next irq is cleanup (no step) + ramp_sts = ramp_last; + break; + } + denom += literal(4); + c32 -= (c32 * 2) / denom; // ramp algorithm + // beware confict with foreground code if long div not reentrant + c = (c32 + 128) / 256; // round 24.8format->int16 + if (c <= C_MIN) + { // go to constant speed + ramp_sts = ramp_max; + step_down = move - step_no; + c = C_MIN; + break; + } + break; + case ramp_max: // constant speed + if (step_no == step_down) + { // start decel + ramp_sts = ramp_down; + denom = ((step_no - move) * literal(4)) + literal(5); + } + break; + default: // last step: cleanup + ramp_sts = ramp_idle; + current_off(); // reduce motor current to holding value + disable_interrupts(INT_CCP1); + run_flg = FALSE; // move complete + break; + } // switch (ramp_sts) + if (ramp_sts!=ramp_idle) + { + motor_pos += pos_inc; + ++step_no; + CCPR2H = CCPR1H = (ccpr >> 8); // timer value at next CCP match + CCPR2L = CCPR1L = (ccpr & 0xff); + + if (ramp_sts!=ramp_last) // else repeat last action: no step + phase_bump(); + } // if (ramp_sts != ramp_idle) +} // isr_motor_step() + +void motor_run(step_t pos_new) +{ // set up to drive motor to pos_new (absolute step#) + if (pos_new < motor_pos) // get direction & #steps + { + move = motor_pos - pos_new; + pos_inc = literal(-1); + phase_inc = literal(-1); + } + else if (pos_new != motor_pos) + { + move = pos_new-motor_pos; + pos_inc = literal(1); + phase_inc = literal(1); + } + else return; // already there + midpt = (move - literal(1))>> literal(1); + c = C0; + c32 = c * 256; // keep c in 24.8 fixed-point format for ramp calcs + step_no = literal(0); // step counter + denom = literal(1); // 4.n+1, n=0 + ramp_sts = ramp_up; // start ramp state-machine + run_flg = literal(TRUE); + TMR1ON = 0; // stop timer1; + ccpr = make16(TMR1H,TMR1L); // 16bit value of Timer1 + ccpr += 1000; // 1st step + irq 1ms after timer1 restart + CCPR2H = CCPR1H = (ccpr >> 8); + CCPR2L = CCPR1L = (ccpr & 0xff); + phase_bump(); + current_on(); // current in motor windings + enable_interrupts(INT_CCP1); + TMR1ON=1; // restart timer1; +} // motor_run() + +void initialize() +{ + disable_interrupts(GLOBAL); + disable_interrupts(INT_CCP1); + disable_interrupts(INT_CCP2); + output_c(0); + set_tris_c(0); + T3CON = 0; + T1CON = 0x35; + enable_interrupts(GLOBAL); +} // initialize() + diff --git a/examples/motor3.h b/examples/motor3.h new file mode 100644 index 0000000..90a1446 --- /dev/null +++ b/examples/motor3.h @@ -0,0 +1,45 @@ +////////////////////////////////////////////////////////////////// +// motor.h +// 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) + +#ifndef MOTOR_H +#define MOTOR_H + +// RR on desktop - this resolves to special file for usage in that +// environment + +#if ! defined(DESKTOP) + #include "18F252.h" + // include pic sfr map only on pic compilers which support the + // #byte preprocessor statement. In other environments, this + // provokes unsuppressable syntax error. + #include "picsfr.h" +#else + #include "18F252_desktop.h" + + extern std::uint8_t base[0xfff]; + extern bit TMR1ON; + + #define TRISC base[0xf94] + #define T3CON base[0xfb1] + #define CCP2CON base[0xfba] + #define CCPR2L base[0xfbb] + #define CCPR2H base[0xfbc] + #define CCP1CON base[0xfbd] + #define CCPR1L base[0xfbe] + #define CCPR1H base[0xfbf] + #define T1CON base[0xfcd] + #define TMR1L base[0xfce] + #define TMR1H base[0xfcf] +#endif + +extern "C" void isr_motor_step(); +extern "C" void motor_run(int16 pos_new); +extern "C" void initialize(); +int8 get_run_flg(); + +#endif // MOTOR_H diff --git a/examples/motor4.c b/examples/motor4.c new file mode 100644 index 0000000..52fcadc --- /dev/null +++ b/examples/motor4.c @@ -0,0 +1,198 @@ +////////////////////////////////////////////////////////////////// +// motor.c +// 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 + +////////////////////////////////////////////////////////////////// +// Note: +// changes to original source code to permit desktop compile, test +// and debug while remaining compatible with pic compiler. These +// changes to the original code are marked with RR below + +// Robert Ramey, 2015 + +// note changes to original source code +// +// signed int16 <- signed_int16 note '-' added +// commented out the #byte and #bit statements +// commented out the #INT_CCP1 +// changed instances of x = 0 to x = literal(0) + +// *********** +// RR factor out motor.c so motor code can be separated from tests +// and other user code. +#include "motor.h" + +#if !defined(DESKTOP) + #include "picsfr.h" +#else + // define a memory map to emulate the on in the pic. This permits all + // same pic code to work on the desktop with no alteration + std::uint8_t base[0xfff]; + // now we can render + //#bit TMR1ON = T1CON.0 as + bit TMR1ON(T1CON); + // and use expressions such as TMR1ON = 0 +#endif + +// 1st step=50ms; max speed=120rpm (based on 1MHz timer, 1.8deg steps) +#define C0 literal(50000) +#define C_MIN literal(2500) + +// ramp state-machine states +#define ramp_idle literal(0) +#define ramp_up literal(1) +#define ramp_max literal(2) +#define ramp_down literal(3) +#define ramp_last literal(4) + +// Types: int8,int16,int32=8,16,32bit integers, unsigned by default +int8 ramp_sts=ramp_idle; +signed_int16 motor_pos = literal(0); // absolute step number +signed_int16 pos_inc = literal(0); // motor_pos increment +int16 phase=literal(0); // ccpPhase[phase_ix] +int8 phase_ix=literal(0); // index to ccpPhase[] +int8 phase_inc; // phase_ix increment +int8 run_flg; // true while motor is running +int16 ccpr; // copy of CCPR1&2 +int16 c; // integer delay count +int16 step_no; // progress of move +int16 step_down; // start of down-ramp +int16 move; // total steps to move +int16 midpt; // midpoint of move +int32 c32; // 24.8 fixed point delay count +signed_int16 denom; // 4.n+1 in ramp algo + +// Config data to make CCP1&2 generate quadrature sequence on PHASE pins +// Action on CCP match: 8=set+irq; 9=clear+irq +int16 const ccpPhase[] = { + literal(0x909), + literal(0x908), + literal(0x808), + literal(0x809) +}; // 00,01,11,10 + +void current_on(){/* code as needed */} // motor drive current +void current_off(){/* code as needed */} // reduce to holding value + +// RR compiler-specific ISR declaration +// #if ! defined(DESKTOP) +// #INT_CCP1 +// #endif +void isr_motor_step() +{ // CCP1 match -> step pulse + IRQ + ccpr += c; // next comparator value: add step delay count + switch (ramp_sts) + { + case ramp_up: // accel + if (step_no==midpt) + { // midpoint: decel + ramp_sts = ramp_down; + denom = ((step_no - move) << literal(2) )+literal(1); + + if (!(move & literal(1))) + { // even move: repeat last delay before decel + denom +=literal(4); + break; + } + } + // no break: share code for ramp algo + case ramp_down: // decel + if (step_no == move-literal(1)) + { // next irq is cleanup (no step) + ramp_sts = ramp_last; + break; + } + denom+=4; + c32 -= (c32 << literal(1)) / denom; // ramp algorithm + // beware confict with foreground code if long div not reentrant + c = (c32+literal(128))>>literal(8); // round 24.8format->int16 + if (c <= C_MIN) + { // go to constant speed + ramp_sts = ramp_max; + step_down = move - step_no; + c = C_MIN; + break; + } + break; + case ramp_max: // constant speed + if (step_no == step_down) + { // start decel + ramp_sts = ramp_down; + denom = ((step_no - move)<> literal(8)); // timer value at next CCP match + CCPR2L = CCPR1L = (ccpr & literal(0xff)); + if (ramp_sts!=ramp_last) // else repeat last action: no step + phase_ix = (phase_ix + phase_inc) & literal(3); + phase = ccpPhase[phase_ix]; + CCP1CON = phase & literal(0xff); // set CCP action on next match + CCP2CON = phase >> literal(8); + } // if (ramp_sts != ramp_idle) +} // isr_motor_step() + +void motor_run(signed_int16 pos_new) +{ // set up to drive motor to pos_new (absolute step#) + if (pos_new < motor_pos) // get direction & #steps + { + move = motor_pos-pos_new; + pos_inc = literal(-1); + phase_inc = literal(0xff); + } + else if (pos_new != motor_pos) + { + move = pos_new-motor_pos; + pos_inc = literal(1); + phase_inc = literal(1); + } + else return; // already there + midpt = (move-1)>>1; + c = C0; + c32 = c<> literal(8)); + CCPR2L = CCPR1L = (ccpr & literal(0xff)); + phase_ix = (phase_ix + phase_inc) & literal(3); + phase = ccpPhase[phase_ix]; + CCP1CON = phase & literal(0xff); // sets action on match + CCP2CON = phase >> literal(8); + current_on(); // current in motor windings + enable_interrupts(INT_CCP1); + TMR1ON = literal(0); // restart timer1; +} // motor_run() + +void initialize() +{ + disable_interrupts(GLOBAL); + disable_interrupts(INT_CCP1); + disable_interrupts(INT_CCP2); + output_c(0); + set_tris_c(0); + T3CON = 0; + T1CON = 0x35; + enable_interrupts(GLOBAL); +} + +// end of file motor.c diff --git a/include/checked.hpp b/include/checked.hpp index e30ad05..a421ef9 100644 --- a/include/checked.hpp +++ b/include/checked.hpp @@ -40,6 +40,9 @@ constexpr checked_result cast( const T & t ) { + // INT31-C requires that integer conversions, both implicit + // and explicit (using a cast),must be guaranteed not to result + // in lost or misinterpreted data [Seacord 2008]. return std::numeric_limits::is_signed ? // T is signed @@ -606,6 +609,7 @@ constexpr left_shift( const R & r, const U & u ){ + // INT13-C. Use bitwise operators only on unsigned operands // cannot shift negative values to the left return (r < 0) ? checked_result( diff --git a/include/interval.hpp b/include/interval.hpp index f0ab94c..db23d30 100644 --- a/include/interval.hpp +++ b/include/interval.hpp @@ -317,6 +317,23 @@ constexpr checked_result> right_shift_positive( }); } +template +constexpr checked_result> intersection( + const interval & t, + const interval & u +){ + + const R rl = std::max(std::initializer_list{t.l, u.l}); + const R ru = std::min(std::initializer_list{t.u, u.u}); + + if(rl > ru) + return checked_result>( + exception_type::uninitialized, + "null intersection" + ); + return interval(rl, ru); +} + template constexpr boost::logic::tribool operator<( const interval & t, diff --git a/include/safe_base_operations.hpp b/include/safe_base_operations.hpp index 1eaacb2..eb0d6b4 100644 --- a/include/safe_base_operations.hpp +++ b/include/safe_base_operations.hpp @@ -20,6 +20,7 @@ #include #include #include +#include #include #include // lazy_enable_if @@ -65,11 +66,12 @@ template template constexpr Stored safe_base:: validated_cast(const T & t) const { - constexpr const interval::type> t_interval( + using t_base_type = typename base_type::type; + constexpr const interval t_interval{ base_value(std::numeric_limits::min()), base_value(std::numeric_limits::max()) - ); - constexpr const interval this_interval{}; + }; + constexpr const interval this_interval(Min, Max); // if static values don't overlap, the program can never function static_assert( indeterminate(t_interval < this_interval), @@ -126,7 +128,6 @@ operator=(const safe_base & rhs){ ///////////////////////////////////////////////////////////////// // casting operators - template struct cast_detail { struct exception_possible { @@ -295,8 +296,7 @@ struct addition_result { // when we add the temporary intervals above, we'll get a new interval // with the correct range for the sum ! - constexpr static const checked_result> r_interval - = add(t_interval, u_interval); + constexpr static const checked_result> r_interval = add(t_interval, u_interval); constexpr static bool exception_possible() { return ! r_interval.no_exception(); @@ -1267,22 +1267,25 @@ struct bitwise_and_result { u_base_type >::type; - using xtype = - typename boost::mpl::if_c< - sizeof(t_base_type) < sizeof(u_base_type), - T, - U - >::type; - - constexpr static const interval result_interval { - base_value(std::numeric_limits::min()), - base_value(std::numeric_limits::max()) + constexpr static const interval t_interval{ + base_value(std::numeric_limits::min()), + base_value(std::numeric_limits::max()) }; + constexpr static const interval u_interval{ + base_value(std::numeric_limits::min()), + base_value(std::numeric_limits::max()) + }; + + constexpr static const checked_result> + result_interval = intersection(t_interval, u_interval); + + static_assert(result_interval.no_exception(), "null intersection"); + using type = safe_base< result_base_type, - result_interval.l, - result_interval.u, + result_interval.m_r.l, + result_interval.m_r.u, promotion_policy, exception_policy >;