example93.cpp 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. //////////////////////////////////////////////////////////////////
  2. // example93.cpp
  3. //
  4. // Copyright (c) 2015 Robert Ramey
  5. //
  6. // Distributed under the Boost Software License, Version 1.0. (See
  7. // accompanying file LICENSE_1_0.txt or copy at
  8. // http://www.boost.org/LICENSE_1_0.txt)
  9. #include <iostream>
  10. // include headers to support safe integers
  11. #include <boost/safe_numerics/cpp.hpp>
  12. #include <boost/safe_numerics/exception.hpp>
  13. #include <boost/safe_numerics/safe_integer.hpp>
  14. #include <boost/safe_numerics/safe_integer_range.hpp>
  15. #include <boost/safe_numerics/safe_integer_literal.hpp>
  16. // use same type promotion as used by the pic compiler
  17. // target compiler XC8 supports:
  18. using pic16_promotion = boost::safe_numerics::cpp<
  19. 8, // char 8 bits
  20. 16, // short 16 bits
  21. 16, // int 16 bits
  22. 16, // long 16 bits
  23. 32 // long long 32 bits
  24. >;
  25. // ***************************
  26. // 1. Specify exception policies so we will generate a
  27. // compile time error whenever an operation MIGHT fail.
  28. // ***************************
  29. // generate runtime errors if operation could fail
  30. using exception_policy = boost::safe_numerics::default_exception_policy;
  31. // generate compile time errors if operation could fail
  32. using trap_policy = boost::safe_numerics::loose_trap_policy;
  33. // ***************************
  34. // 2. Create a macro named literal an integral value
  35. // that can be evaluated at compile time.
  36. #define literal(n) make_safe_literal(n, pic16_promotion, void)
  37. // For min speed of 2 mm / sec (24.8 format)
  38. // sec / step = sec / 2 mm * 2 mm / rotation * rotation / 200 steps
  39. #define C0 literal(5000 << 8)
  40. // For max speed of 400 mm / sec
  41. // sec / step = sec / 400 mm * 2 mm / rotation * rotation / 200 steps
  42. #define C_MIN literal(25 << 8)
  43. static_assert(
  44. C0 < make_safe_literal(0xffffff, pic16_promotion,trap_policy),
  45. "Largest step too long"
  46. );
  47. static_assert(
  48. C_MIN > make_safe_literal(0, pic16_promotion,trap_policy),
  49. "Smallest step must be greater than zero"
  50. );
  51. // ***************************
  52. // 3. Create special ranged types for the motor program
  53. // These wiil guarantee that values are in the expected
  54. // ranges and permit compile time determination of when
  55. // exceptional conditions might occur.
  56. using pic_register_t = boost::safe_numerics::safe<
  57. uint8_t,
  58. pic16_promotion,
  59. trap_policy // use for compiling and running tests
  60. >;
  61. // note: the maximum value of step_t would be:
  62. // 50000 = 500 mm / 2 mm/rotation * 200 steps/rotation.
  63. // But in one expression the value of number of steps * 4 is
  64. // used. To prevent introduction of error, permit this
  65. // type to hold the larger value.
  66. using step_t = boost::safe_numerics::safe_unsigned_range<
  67. 0,
  68. 200000,
  69. pic16_promotion,
  70. exception_policy
  71. >;
  72. // position
  73. using position_t = boost::safe_numerics::safe_unsigned_range<
  74. 0,
  75. 50000, // 500 mm / 2 mm/rotation * 200 steps/rotation
  76. pic16_promotion,
  77. exception_policy
  78. >;
  79. // next end of step timer value in format 24.8
  80. // where the .8 is the number of bits in the fractional part.
  81. using ccpr_t = boost::safe_numerics::safe<
  82. uint32_t,
  83. pic16_promotion,
  84. exception_policy
  85. >;
  86. // pulse length in format 24.8
  87. // note: this value is constrainted to be a positive value. But
  88. // we still need to make it a signed type. We get an arithmetic
  89. // error when moving to a negative step number.
  90. using c_t = boost::safe_numerics::safe_unsigned_range<
  91. C_MIN,
  92. C0,
  93. pic16_promotion,
  94. exception_policy
  95. >;
  96. // index into phase table
  97. // note: The legal values are 0-3. So why must this be a signed
  98. // type? Turns out that expressions like phase_ix + d
  99. // will convert both operands to unsigned. This in turn will
  100. // create an exception. So leave it signed even though the
  101. // value is greater than zero.
  102. using phase_ix_t = boost::safe_numerics::safe_signed_range<
  103. 0,
  104. 3,
  105. pic16_promotion,
  106. trap_policy
  107. >;
  108. // settings for control value output
  109. using phase_t = boost::safe_numerics::safe<
  110. uint16_t,
  111. pic16_promotion,
  112. trap_policy
  113. >;
  114. // direction of rotation
  115. using direction_t = boost::safe_numerics::safe_signed_range<
  116. -1,
  117. +1,
  118. pic16_promotion,
  119. trap_policy
  120. >;
  121. // some number of microseconds
  122. using microseconds = boost::safe_numerics::safe<
  123. uint32_t,
  124. pic16_promotion,
  125. trap_policy
  126. >;
  127. // ***************************
  128. // emulate PIC features on the desktop
  129. // filter out special keyword used only by XC8 compiler
  130. #define __interrupt
  131. // filter out XC8 enable/disable global interrupts
  132. #define ei()
  133. #define di()
  134. // emulate PIC special registers
  135. pic_register_t RCON;
  136. pic_register_t INTCON;
  137. pic_register_t CCP1IE;
  138. pic_register_t CCP2IE;
  139. pic_register_t PORTC;
  140. pic_register_t TRISC;
  141. pic_register_t T3CON;
  142. pic_register_t T1CON;
  143. pic_register_t CCPR2H;
  144. pic_register_t CCPR2L;
  145. pic_register_t CCPR1H;
  146. pic_register_t CCPR1L;
  147. pic_register_t CCP1CON;
  148. pic_register_t CCP2CON;
  149. pic_register_t TMR1H;
  150. pic_register_t TMR1L;
  151. // ***************************
  152. // special checked type for bits - values restricted to 0 or 1
  153. using safe_bit_t = boost::safe_numerics::safe_unsigned_range<
  154. 0,
  155. 1,
  156. pic16_promotion,
  157. trap_policy
  158. >;
  159. // create type used to map PIC bit names to
  160. // correct bit in PIC register
  161. template<typename T, std::int8_t N>
  162. struct bit {
  163. T & m_word;
  164. constexpr explicit bit(T & rhs) :
  165. m_word(rhs)
  166. {}
  167. // special functions for assignment of literal
  168. constexpr bit & operator=(decltype(literal(1))){
  169. m_word |= literal(1 << N);
  170. return *this;
  171. }
  172. constexpr bit & operator=(decltype(literal(0))){
  173. m_word &= ~literal(1 << N);
  174. return *this;
  175. }
  176. // operator to convert to 0 or 1
  177. constexpr operator safe_bit_t () const {
  178. return m_word >> literal(N) & literal(1);
  179. }
  180. };
  181. // define bits for T1CON register
  182. struct {
  183. bit<pic_register_t, 7> RD16{T1CON};
  184. bit<pic_register_t, 5> T1CKPS1{T1CON};
  185. bit<pic_register_t, 4> T1CKPS0{T1CON};
  186. bit<pic_register_t, 3> T1OSCEN{T1CON};
  187. bit<pic_register_t, 2> T1SYNC{T1CON};
  188. bit<pic_register_t, 1> TMR1CS{T1CON};
  189. bit<pic_register_t, 0> TMR1ON{T1CON};
  190. } T1CONbits;
  191. // define bits for T1CON register
  192. struct {
  193. bit<pic_register_t, 7> GEI{INTCON};
  194. bit<pic_register_t, 5> PEIE{INTCON};
  195. bit<pic_register_t, 4> TMR0IE{INTCON};
  196. bit<pic_register_t, 3> RBIE{INTCON};
  197. bit<pic_register_t, 2> TMR0IF{INTCON};
  198. bit<pic_register_t, 1> INT0IF{INTCON};
  199. bit<pic_register_t, 0> RBIF{INTCON};
  200. } INTCONbits;
  201. #include "motor3.c"
  202. #include <chrono>
  203. #include <thread>
  204. // round 24.8 format to microseconds
  205. microseconds to_microseconds(ccpr_t t){
  206. return (t + literal(128)) / literal(256);
  207. }
  208. using result_t = uint8_t;
  209. const result_t success = 1;
  210. const result_t fail = 0;
  211. // move motor to the indicated target position in steps
  212. result_t test(position_t new_position){
  213. try {
  214. std::cout << "move motor to " << new_position << '\n';
  215. motor_run(new_position);
  216. std::cout
  217. << "step #" << ' '
  218. << "delay(us)(24.8)" << ' '
  219. << "delay(us)" << ' '
  220. << "CCPR" << ' '
  221. << "motor position" << '\n';
  222. while(busy()){
  223. std::this_thread::sleep_for(std::chrono::microseconds(to_microseconds(c)));
  224. c_t last_c = c;
  225. ccpr_t last_ccpr = ccpr;
  226. isr_motor_step();
  227. std::cout << i << ' '
  228. << last_c << ' '
  229. << to_microseconds(last_c) << ' '
  230. << std::hex << last_ccpr << std::dec << ' '
  231. << motor_position << '\n';
  232. };
  233. }
  234. catch(const std::exception & e){
  235. std::cout << e.what() << '\n';
  236. return fail;
  237. }
  238. return success;
  239. }
  240. int main(){
  241. std::cout << "start test\n";
  242. result_t result = success;
  243. try {
  244. initialize();
  245. // move motor to position 1000
  246. result &= test(literal(1000));
  247. // move to the left before zero position
  248. // fails to compile !
  249. // result &= ! test(-10);
  250. // move motor to position 200
  251. result &= test(literal(200));
  252. // move motor to position 200 again! Should result in no movement.
  253. result &= test(literal(200));
  254. // move motor to position 50000.
  255. result &= test(literal(50000));
  256. // move motor back to position 0.
  257. result &= test(literal(0));
  258. }
  259. catch(...){
  260. std::cout << "test interrupted\n";
  261. return EXIT_FAILURE;
  262. }
  263. std::cout << "end test\n";
  264. return result == success ? EXIT_SUCCESS : EXIT_FAILURE;
  265. }