Advertisement
dezulm

Period & DutyCycle Measurement

Mar 11th, 2012
91
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 7.23 KB | None | 0 0
  1. /*
  2. * *
  3. * This code is based on publicly available code available at the following sources:
  4. * http://pastebin.com/NQtbVCFh
  5. * http://forums.leaflabs.com/topic.php?id=1038
  6. *
  7. * The above sources provided period measurement guidance for generic timer
  8. * The following uses advanced timer capabilities such as timer with slave and PWM input mode to measure period and duty cycle
  9. */
  10.  
  11. #include <timer.h>
  12.  
  13.  
  14. // initialize global variables
  15. int periodvalue = 0;
  16. int dutycyclevalue = 0;
  17. int count = 0;
  18. int overflow_flag = 0;
  19.  
  20. HardwareTimer timer1 = HardwareTimer(1);
  21.  
  22. //quick method to return if there's anyone on the other end of the serialusb link yet.
  23. boolean isConnected(){
  24. return (SerialUSB.isConnected() && (SerialUSB.getDTR() || SerialUSB.getRTS()));
  25. }
  26.  
  27. void setup()
  28. {
  29.  
  30. SerialUSB.begin();
  31. while(!isConnected()); //wait till console attaches.
  32. SerialUSB.println("Hello!");
  33.  
  34. //Setup Timer1 Channel 1 (pin 6) as an input
  35. pinMode(6, INPUT);
  36.  
  37. //Configure pin 7 as an output (100 Hz 50% duty cycle with be genaerted and outputed pin 7. A jumper from pin 7 to pin 6 will be applied.
  38. pinMode(7, OUTPUT);
  39.  
  40. // set up advanced timer capabilities
  41. setup_timer();
  42.  
  43. }
  44.  
  45. void __measurePulse_irq()
  46. {
  47.  
  48. //For some reason, the interrupt is triggered as soon as
  49. //the device is turned on. This gets around that bug.
  50. // came with sample code - probably used because pulse may be in unknown state
  51. if( count == 0 )
  52. return;
  53. else {
  54.  
  55. if(~overflow_flag) {
  56.  
  57. periodvalue = TIMER1_BASE->CCR1; //read the captured value - period defined from pulse going up to next cycle where pulse goes high. CCR1 contains period count
  58.  
  59. }
  60.  
  61. else {
  62. periodvalue = 0;
  63. overflow_flag = 0;
  64. }
  65.  
  66.  
  67. timer1.setCount(0); //Zero timer
  68. }
  69. }
  70.  
  71. void __measureDutyCycle_irq()
  72. {
  73.  
  74. //For some reason, the interrupt is triggred as soon as
  75. //the device is turned on. This gets around that bug.
  76. if( count == 0 )
  77. return;
  78. else {
  79.  
  80. if(~overflow_flag) {
  81. dutycyclevalue = TIMER1_BASE->CCR2; //read the captured value - dutycycle count defined from pulse going up to pulse going down. CCR2 contains duty cycle count
  82.  
  83. }
  84.  
  85. else {
  86. dutycyclevalue = 0;
  87. overflow_flag = 0;
  88. }
  89.  
  90. }
  91. }
  92.  
  93. // overflow irq accounts for when the counter overflows. overflow is defined in this case as 65535 (2^16- 1). should not be getting overflow.
  94. void handle_overflow() {
  95.  
  96. overflow_flag = 1;
  97. }
  98.  
  99. void loop() {
  100.  
  101. //Display the counter values (period and duty cycle) very 500 mS
  102. if( count == 100 ) {
  103. //delay(500);
  104. SerialUSB.print("Period: ");
  105. SerialUSB.println(periodvalue);
  106. SerialUSB.print("Duty Cycle: ");
  107. SerialUSB.println(dutycyclevalue); //value = 0;
  108. count = 0;
  109. }
  110.  
  111.  
  112. //Pulse pin 7 at a rate of 100 Hz @ 50% DC - this is the PWM signal with 100Hz and 50% duty cycle.
  113. digitalWrite(7, HIGH);
  114. delay(5);
  115. digitalWrite(7, LOW);
  116. delay(5);
  117.  
  118. count++;
  119.  
  120. }
  121.  
  122.  
  123. //Halt processor and flash LED - used for debugging - code that calls this function is currently not used - can be removed.
  124. void HaltAll(void) {
  125.  
  126. //Timer1.pause();
  127. timer1.pause();
  128. pinMode(BOARD_LED_PIN, OUTPUT);
  129.  
  130. while(1) {
  131.  
  132. toggleLED();
  133. delay(1000);
  134.  
  135. }
  136.  
  137. }
  138.  
  139. // configure timer1 which is an advanced timer wuth a slave to measure period and duty cycle.
  140. void setup_timer(void) {
  141.  
  142. //Create a pointer to the timer (why?)
  143. timer_dev *t = TIMER1;
  144.  
  145. //Initialize timer
  146. timer1.pause();
  147.  
  148. /*
  149. A prescaler of 288 means that at 72MHz, I get the following:
  150. 100 Hz = 2510
  151. 10 Hz = 25084
  152. */
  153. timer1.setPrescaleFactor(288);
  154.  
  155. timer1.setOverflow(65535);
  156. timer1.setCount(0);
  157.  
  158. //New code to set overflow timer
  159. timer1.setMode(3, TIMER_OUTPUT_COMPARE); //Set this channel to compare
  160. timer1.setCompare(3, 65534); //Set the compare for the channel to the overflow value
  161. timer1.attachInterrupt(3, handle_overflow); //Assign the interrupt handler
  162.  
  163. timer1.refresh();
  164.  
  165. //Create a pointer to the timer registers (why?)
  166. timer_reg_map r = t->regs;
  167.  
  168.  
  169. //capture compare regs TIMx_CCRx used to hold val after a transition on corresponding ICx
  170.  
  171. //when cap occurs, flag CCXIF (TIMx_SR register) is set,
  172. //and interrupt, or dma req can be sent if they are enabled.
  173.  
  174. //if cap occurs while flag is already high CCxOF (overcapture) flag is set..
  175.  
  176. //CCIX can be cleared by writing 0, or by reading the capped data from TIMx_CCRx
  177. //CCxOF is cleared by writing 0 to it.
  178.  
  179. //Capture/Compare 1 Selection
  180. // set CC1S bits to 01 in the capture compare mode register.
  181. // 01 selects TI1 as the input to use. (page 336 stm32 reference)
  182. // (assuming here that TI1 is D6, according to maple master pin map)
  183. //CC1S bits are bits 0,1
  184. bitSet(r.adv->CCMR1, 0);
  185. bitClear(r.adv->CCMR1, 1);
  186.  
  187.  
  188. //Input Capture 1 Filter.
  189. // need to set IC1F bits according to a table saying how long
  190. // we should wait for a signal to be 'stable' to validate a transition
  191. // on the input.
  192. // (page 336 stm32 reference)
  193. //IC1F bits are bits 7,6,5,4
  194. bitClear(r.adv->CCMR1, 7);
  195. bitClear(r.adv->CCMR1, 6);
  196. bitSet(r.adv->CCMR1, 5);
  197. bitSet(r.adv->CCMR1, 4);
  198.  
  199. //sort out the input capture prescaler..
  200. //00 no prescaler.. capture is done as soon as edge is detected
  201. bitClear(r.adv->CCMR1, 3);
  202. bitClear(r.adv->CCMR1, 2);
  203.  
  204.  
  205. //select the edge for the transition on TI1 channel using CC1P in CCER
  206. //CC1P is bit 1 of CCER (page 339)
  207. // 0 = rising
  208. // 1 = falling
  209. bitClear(r.adv->CCER,1);
  210.  
  211. //Capture/Compare 1 Selection of down part of the pulse on TI1
  212. // set CC2S bits to 10 in the capture compare mode register.
  213. // 01 selects TI1 as the input to use. (page 336 stm32 reference)
  214. // (assuming here that TI1 is D6, according to maple master pin map)
  215. //CC2S bits are bits 8,9
  216. bitSet(r.adv->CCMR1, 9);
  217. bitClear(r.adv->CCMR1, 8);
  218.  
  219. //select the edge for the transition on TI1 channel using CC2P in CCER
  220. //CC2P is bit 5 of CCER (page 339)
  221. // 0 = active high
  222. // 1 = active low
  223. bitSet(r.adv->CCER,5);
  224.  
  225.  
  226. //select filtered trigger option: TS bits are set 101 in SMCR
  227. // seelects the trigger input to be used to synchronize counter
  228. // in this case a filtered TI1 (page 328)
  229. bitSet(r.adv->SMCR,6);
  230. bitClear(r.adv->SMCR,5);
  231. bitSet(r.adv->SMCR,4);
  232.  
  233. //select slave mode selection: SMS bits are set 100 in SMCR
  234. // configure slave mode in reset mode (page 329)
  235. bitSet(r.adv->SMCR,2);
  236. bitClear(r.adv->SMCR,1);
  237. bitClear(r.adv->SMCR,0);
  238.  
  239.  
  240. //set the CC1E bit to enable capture from the counter.
  241. //CCE1 is bit 0 of CCER (page 339)
  242. //Enable capture
  243. bitSet(r.adv->CCER,0);
  244.  
  245.  
  246. //set the CC2E bit to enable capture from the counter.
  247. //CCE2 is bit 4 of CCER (page 339)
  248. bitSet(r.adv->CCER,4);
  249.  
  250.  
  251. // attach interrupts for when pulse goes high for period measurement and pulse goes low for duty cycle measurement
  252. timer1.attachInterrupt(1, __measurePulse_irq);
  253. timer1.attachInterrupt(2, __measureDutyCycle_irq);
  254.  
  255. //timer_resume(TIMER4);
  256. timer1.resume();
  257.  
  258.  
  259. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement