1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207
|
//////////////////////////////////////////////////////////////////
// example92.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 <iostream>
// ***************************
// 1. include headers to support safe integers
#include <boost/safe_numerics/cpp.hpp>
#include <boost/safe_numerics/exception.hpp>
#include <boost/safe_numerics/safe_integer.hpp>
// ***************************
// 2. specify a promotion policy to support proper emulation of
// PIC types on the desktop
using pic16_promotion = boost::safe_numerics::cpp<
8, // char 8 bits
16, // short 16 bits
16, // int 16 bits
16, // long 16 bits
32 // long long 32 bits
>;
// 1st step=50ms; max speed=120rpm (based on 1MHz timer, 1.8deg steps)
#define C0 (50000 << 8)
#define C_MIN (2500 << 8)
static_assert(C0 < 0xffffff, "Largest step too long");
static_assert(C_MIN > 0, "Smallest step must be greater than zero");
static_assert(C_MIN < C0, "Smallest step must be smaller than largest step");
// ***************************
// 3. define PIC integer type names to be safe integer types of he same size.
template <typename T> // T is char, int, etc data type
using safe_t = boost::safe_numerics::safe<
T,
pic16_promotion
>;
// alias original program's integer types to corresponding PIC safe types
// 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
typedef safe_t<int8_t> int8;
typedef safe_t<int16_t> int16;
typedef safe_t<int32_t> int32;
typedef safe_t<uint8_t> uint8;
typedef safe_t<uint16_t> uint16;
typedef safe_t<uint32_t> uint32;
// ***************************
// 4. emulate PIC features on the desktop
// filter out special keyword used only by XC8 compiler
#define __interrupt
// filter out XC8 enable/disable global interrupts
#define ei()
#define di()
// emulate PIC special registers
uint8 RCON;
uint8 INTCON;
uint8 CCP1IE;
uint8 CCP2IE;
uint8 PORTC;
uint8 TRISC;
uint8 T3CON;
uint8 T1CON;
uint8 CCPR2H;
uint8 CCPR2L;
uint8 CCPR1H;
uint8 CCPR1L;
uint8 CCP1CON;
uint8 CCP2CON;
uint8 TMR1H;
uint8 TMR1L;
// create type used to map PIC bit names to
// correct bit in PIC register
template<typename T, std::int8_t N>
struct bit {
T & m_word;
constexpr explicit bit(T & rhs) :
m_word(rhs)
{}
constexpr bit & operator=(int b){
if(b != 0)
m_word |= (1 << N);
else
m_word &= ~(1 << N);
return *this;
}
constexpr operator int () const {
return m_word >> N & 1;
}
};
// define bits for T1CON register
struct {
bit<uint8, 7> RD16{T1CON};
bit<uint8, 5> T1CKPS1{T1CON};
bit<uint8, 4> T1CKPS0{T1CON};
bit<uint8, 3> T1OSCEN{T1CON};
bit<uint8, 2> T1SYNC{T1CON};
bit<uint8, 1> TMR1CS{T1CON};
bit<uint8, 0> TMR1ON{T1CON};
} T1CONbits;
// define bits for T1CON register
struct {
bit<uint8, 7> GEI{INTCON};
bit<uint8, 5> PEIE{INTCON};
bit<uint8, 4> TMR0IE{INTCON};
bit<uint8, 3> RBIE{INTCON};
bit<uint8, 2> TMR0IF{INTCON};
bit<uint8, 1> INT0IF{INTCON};
bit<uint8, 0> RBIF{INTCON};
} INTCONbits;
// ***************************
// 5. include the environment independent code we want to test
#include "motor2.c"
#include <chrono>
#include <thread>
// round 24.8 format to microseconds
int32 to_microseconds(uint32 t){
return (t + 128) / 256;
}
using result_t = uint8_t;
const result_t success = 1;
const result_t fail = 0;
// move motor to the indicated target position in steps
result_t test(int32 m){
try {
std::cout << "move motor to " << m << '\n';
motor_run(m);
std::cout
<< "step #" << ' '
<< "delay(us)(24.8)" << ' '
<< "delay(us)" << ' '
<< "CCPR" << ' '
<< "motor position" << '\n';
do{
std::this_thread::sleep_for(std::chrono::microseconds(to_microseconds(c)));
uint32 last_c = c;
uint32 last_ccpr = ccpr;
isr_motor_step();
std::cout
<< step_no << ' '
<< last_c << ' '
<< to_microseconds(last_c) << ' '
<< std::hex << last_ccpr << std::dec << ' '
<< motor_pos << '\n';
}while(run_flg);
}
catch(const std::exception & e){
std::cout << e.what() << '\n';
return fail;
}
return success;
}
int main(){
std::cout << "start test\n";
result_t result = success;
try{
initialize();
// move motor to position 1000
result &= test(1000);
// move motor to position 200
result &= test(200);
// move motor to position 200 again! Should result in no movement.
result &= test(200);
// move back to position 0
result &= test(0);
// ***************************
// 6. error detected here! data types can't handle enough
// steps to move the carriage from end to end! Suppress this
// test for now.
// move motor to position 50000.
// result &= test(50000);
// move motor back to position 0.
result &= test(0);
}
catch(const std::exception & e){
std::cout << e.what() << '\n';
return 1;
}
catch(...){
std::cout << "test interrupted\n";
return EXIT_FAILURE;
}
std::cout << "end test\n";
return result == success ? EXIT_SUCCESS : EXIT_FAILURE;
}
|