2 // Product: UCC Radiotelescope - Stepper Motor Controller
\r
4 // Date: 5 November 2010
\r
6 // +-----------------------+
\r
7 // | d e c i s i o n s |
\r
8 // +-----------------------+
\r
9 // | a n d d e s i g n s |
\r
10 // +-----------------------+
\r
12 // Copyright (C) 2010 Decisions and Designs Pty Ltd. All rights reserved.
\r
14 // This software may be distributed and modified under the terms of the GNU
\r
15 // General Public License version 2 (GPL) as published by the Free Software
\r
16 // Foundation and appearing in the file GPL.TXT included in the packaging of
\r
17 // this file. Please note that GPL Section 2[b] requires that all works based
\r
18 // on this software must also be made publicly available under the terms of
\r
19 // the GPL ("Copyleft").
\r
21 // Contact information:
\r
22 // Decisions and Designs Web site: http://www.decisions-and-designs.com.au
\r
26 #include "radiotelescope.h"
\r
27 #include "qpn_port.h"
\r
29 #include "signals.h"
\r
30 #include "stepper.h"
\r
34 * All comments containing ATmega1280 "Section number and description"
\r
35 * refer to the Atmel datasheet:
\r
36 * ATmega640/1280/1281/2560/2561 Rev. 2549M-09/10
\r
37 * available from (on 5 November 2010):
\r
38 * www.atmel.com/dyn/resources/prod_documents/doc2549.PDF
\r
40 * The following stepper driver code uses two hardware pins to drive both sides
\r
41 * of an opto-transistor LED for 10mA nominal LED current:
\r
43 * | LED (one half of optotransistor)
\r
44 * "OCB" pin |----------/\/\/\---->|-----
\r
45 * ATmega1280 MCU | 270R |
\r
46 * "OCA" pin |---------------------------
\r
49 * This takes advantage of the AVR timer output compare logic which can be
\r
50 * configured to set MCU pins high or low when the timer matches an output
\r
51 * compare (OC) register; each timer has three OCs: OCA, OCB, and OCC. This
\r
52 * driver uses OCA and OCB to adjust two pins so their difference is the
\r
53 * active (LED has current) period for the opto-transistor:
\r
55 * OCA pin ```````\_______________________/```````
\r
56 * OCB pin ````````````````````````\_______/``````
\r
57 * LED active ~~~~~XXXXXXXXXXXXXXXX~~~~~~~~~~~~~~~
\r
59 * There are two identical drivers using Timer 3 and Timer 4 respectively.
\r
60 * Each driver accepts a uint32_t step count argument from which the upper
\r
61 * 16 bits are consumed as rollovers of the 16 bit hardware counter before
\r
62 * the final (lower) 16 step count bits are consumed in the hardware counter.
\r
63 * In both the rollover and final count, the timer output compare register
\r
64 * OCA either generates interrupts on rollover or (for the final count)
\r
65 * confgures the OCA latch to drive the corresponding output pin (active)
\r
66 * low to initiate the step pulse. During the final count, the OCB latch
\r
67 * has also been configured to drive it's corresponding output pin (inactive)
\r
68 * low to complete the step pulse. Both pins are subsequently forced high to
\r
69 * prepare for the next step pulse. The advantage of this design is that
\r
70 * all the step pulse periods are fixed length (defined by the hardware
\r
71 * timer behaviour) and setup requirements for subsequent step periods are
\r
72 * easier to guarantee (less dependence on ISR delays). As the ATmega1280
\r
73 * datasheet notes however, there is significant CPU overhead to manage the
\r
74 * stepper signals in this way, see:
\r
75 * ATmega1280 "16.9.1 Normal Mode".
\r
77 * The following diagram shows the rollover periods, final count, the
\r
78 * step pulse output period, and output restoration ready for the next step
\r
81 * final rollover final count end pulse
\r
83 * ISR empty ISR call |--ISR--|
\r
85 * OCA pin ``````````````````````````````\_______________________/```````
\r
86 * OCB pin ```````````````````````````````````````````````\_______/``````
\r
87 * LED active ~~~~~~~~~~~~~~~~~~~~~~~~~~~~XXXXXXXXXXXXXXXX~~~~~~~~~~~~~~~
\r
89 * 1. After consuming all of the upper 16 bits of the counter, a final count
\r
90 * period remains in the lower 16 bits of the step count argument. Advance
\r
91 * OCA by the remaining step count. Also advance OCB beyond OCA by the
\r
92 * pulse period; all is ready for the hardware pulse between 2. and 3.
\r
93 * 2. The hardware pulse is initiated here but only the OCB interrupt is
\r
94 * enabled so OCA ISR does not get called.
\r
95 * 3. If another step pulse is queued for the driver, OCA is advanced (if
\r
96 * the step has no rollover component) or OCA interrupt is enabled for
\r
97 * rollovers. The main timer free runs so all rollovers and advancement
\r
98 * of OCA means each falling edge maintains the correct step period
\r
99 * regardless of when the ISR is called to set up the next step period.
\r
100 * The next step time set up occurs in OCB ISR so the ISR must respond
\r
101 * within MIN_SETUP_TIME-PULSE_TIME (see definitions below).
\r
102 * 4. The hardware pulse is de-activated when OCB pin goes inactive high.
\r
104 * Radiotelescope application:
\r
105 * ---------------------------
\r
106 * The RTA Pavia GMD 04 stepper driver board has a maximum step frequency
\r
107 * of 50KHz, clocks on the falling edge of the step input (when the opto
\r
108 * LED goes active) and suggests a 50% step clock duty cycle. See:
\r
109 * http://wiki.ucc.asn.au/RadioTelescope?action=AttachFile&do=view&target=GDMman.pdf
\r
110 * This implies that the minimum pulse period is 10 uSec so it should be
\r
111 * ok to use a 100 uSec pulse and allow for a maximum stepping period of
\r
112 * 1 mSec until further performance tests are conducted.
\r
113 * In order to achieve smooth (queued) stepping, the QP stepper tasks
\r
114 * need to respond to a signal from OCB ISR to request the next queued
\r
115 * step period before the OCA pin change on final OCA (see step 2 above).
\r
116 * Because the non-premptive QP kernel is being used, all RTC code in the
\r
117 * QP tasks must run within MIN_SETUP_TIME-PULSE_TIME; or 900 uSec which
\r
120 * For opto-isolated hardware connection to the GDM 04, AVR pins can
\r
121 * source and sink at least 10mA; see:
\r
122 * ATmega1280 "30.1 DC Characteristics" symbols V(OL), V(OH).
\r
123 * Choose an optotransistor which can operate with 10mA LED current for
\r
124 * the required optotransistor fall time. Connect the optotransistor
\r
125 * to the stepper drive module inputs (with [TBD] external pull-up resistor
\r
126 * if required). Thus the AVR pins drive the LED into an active (lit) state
\r
127 * at the start of the step pulse period and the phototransistor conducts
\r
128 * pulling the GDM 04 stepper driver tesp input low for a falling edge
\r
129 * stepper clock; see (from wiki link above):
\r
130 * GDMman.pdf, "4 - INPUT AND OUTPUT LOGIC SIGNALS", page 7.
\r
131 * TODO See schematic of interface in project file stepper_iface.pdf
\r
135 #define TIMER_MODE_NORMAL 0
\r
137 /* ATmega1280, "16.3 Accessing 16-bit Registers"
\r
139 "To do a 16-bit write, the high byte must be written before the low byte.
\r
140 For a 16-bit read, the low byte must be read before the high byte." */
\r
141 #define forwardOf(DEST, SRC, OSET) \
\r
144 temp = SRC ## L ; \
\r
145 temp += (SRC ## H) << 8 ; \
\r
147 DEST ## H = temp >> 8; \
\r
148 DEST ## L = temp & 0xff; \
\r
152 /*..........................................................................*/
\r
153 /* Timer globals */
\r
154 QActive *count3AO = (QActive *)0;
\r
155 uint32_t count3, nextCount3;
\r
157 QActive *count4AO = (QActive *)0;
\r
158 uint32_t count4, nextCount4;
\r
159 /*..........................................................................*/
\r
160 void BSP_initStepTimer3(QActive *me)
\r
165 /* Disable power reduction for timer3; see
\r
166 ATmega1280 "11.9.3 PRR1 - Power Reduction Register 1" */
\r
167 PRR1 &= ~(1 << PRTIM3);
\r
168 /* Disable (clocking of) the timer; see ATmega1280
\r
169 "17.11.8 TCCR5B - Timer/Counter 5 Control Register B" */
\r
171 /* Set COM3A and COM3B to drive both OC latches high; see
\r
172 ATmega1280 "Table 17-3. Compare Output Mode, non-PWM" */
\r
173 TCCR3A = (1 << COM3A1) | (1 << COM3A0)
\r
174 | (1 << COM3B1) | (1 << COM3B0)
\r
175 | TIMER_MODE_NORMAL;
\r
176 /* Force OC latches high; see ATmega1280
\r
177 "17.11.12 TCCR5C - Timer/Counter 5 Control Register C" */
\r
178 TCCR3C = (1 << FOC3A) | (1 << FOC3B);
\r
179 /* Disable OC as pin source and drive pins with PORT latch */
\r
180 TCCR3A = TIMER_MODE_NORMAL;
\r
181 /* Set OCA and OCB PORT bits high; OC3A is PE3 and OC3B is PE4 */
\r
182 PORTE |= (1 << PE3) | (1 << PE4);
\r
183 /* Set DDR to drive the PORT bits for OCA and OCB pins */
\r
184 DDRE |= (1 << DDE3) | (1 << DDE4);
\r
185 /* Reenable timer with clkI/O (no prescaling) */
\r
186 TCCR3B = 1 << CS30;
\r
189 /*..........................................................................*/
\r
190 uint8_t BSP_nextStepTimer3(uint32_t count)
\r
192 uint8_t register sreg;
\r
194 /* There is a minimum setup time so error on short counts */
\r
195 if (count < MIN_SETUP_TIME)
\r
197 /* A count is already queued so error */
\r
200 sreg = SREG; /* save interrupt and other status */
\r
201 cli(); /* and disable interrupts */
\r
202 /* If step timer is still running, leave it to the ISR to load
\r
203 the next step time */
\r
205 nextCount3 = count; /* queue the count for ISR to load */
\r
206 SREG = sreg; /* restore interrupts */
\r
209 SREG = sreg; /* restore interrupts */
\r
210 /* Request next step time from HSM */
\r
212 QActive_postISR(count3AO, NEXT_STEP_TIME_SIG, 0);
\r
214 /* If the last OCA period is too short, run "half" in the first OCA count
\r
215 so the final count is withing setup time limits */
\r
216 if ((count & 0x0000ffff) < MIN_SETUP_TIME) {
\r
217 count3 = count + 0x10000 - (MID_SET_TIME - MIN_SETUP_TIME);
\r
218 /* Set OCA3 forward of the current TCNT3 */
\r
219 forwardOf(OCR3A, TCNT3, (MID_SET_TIME - MIN_SETUP_TIME));
\r
221 /* If the last OCA period extends the OCB past rollover then
\r
222 run "half" in the first OCA count */
\r
223 else if ((count & 0x0000ffff) > MAX_SETUP_TIME) {
\r
224 count3 = count + 0x10000 - (MAX_SETUP_TIME - MID_SET_TIME);
\r
225 /* Set OCA3 forward of the current TCNT3 */
\r
226 forwardOf(OCR3A, TCNT3, (MAX_SETUP_TIME - MID_SET_TIME));
\r
228 /* Final count period */
\r
229 else if (!(count & 0xffff0000)) {
\r
230 /* Flag nextStepTimer3() that the last time is still running
\r
231 so nextCount3 is queued */
\r
233 /* Set up the last OCRA period and OCRB pulse period */
\r
234 forwardOf(OCR3A, TCNT3, (uint16_t)count);
\r
235 forwardOf(OCR3B, OCR3A, PULSE_TIME);
\r
236 /* Clear stale OC interrupt flags; see ATmega1280
\r
237 "17.11.40 TIFR5 - Timer/Counter5 Interrupt Flag Register" */
\r
238 TIFR3 = (1 << OCF3B) | (1 << OCF3A);
\r
239 /* Enable the OCA and OCB pin controls to clear (drive low) both pins;
\r
240 see ATmega1280 "Table 17-3. Compare Output Mode, non-PWM" */
\r
241 TCCR3A = (1 << COM3A1) | (1 << COM3B1) | TIMER_MODE_NORMAL;
\r
242 /* Enable the OCA interrupt to discard the interrupt during the final count.
\r
243 Enable OCB interrupt to reload at end of pulse */
\r
244 TIMSK3 = (1 << OCIE3A) | (1 << OCIE3B);
\r
247 /* Start rollover period */
\r
250 forwardOf(OCR3A, TCNT3, 0);
\r
252 /* Clear stale OCA interrupt flag; see ATmega1280
\r
253 "17.11.40 TIFR5 - Timer/Counter5 Interrupt Flag Register" */
\r
254 TIFR3 = 1 << OCF3A;
\r
255 /* For all non-FINAL timing, only enable OCA interrupt; see ATmega1280
\r
256 "17.11.36 TIMSK5 - Timer/Counter 5 Interrupt Mask Register" */
\r
257 TIMSK3 = 1 << OCIE3A;
\r
260 /*..........................................................................*/
\r
261 /* For information about AVR Interrupts see:
\r
262 http://www.nongnu.org/avr-libc/user-manual/group__avr__interrupts.html
\r
263 OC3A Interrupt handler */
\r
264 ISR(TIMER3_COMPA_vect) {
\r
265 /* Adjust timer based on time to run */
\r
266 if (count3 & 0xffff0000) {
\r
268 if (count3 & 0xffff0000) {
\r
269 /* More OCA rollovers yet */
\r
273 /* The OCA interrupt flag has been cleared on vector into here,
\r
274 ISR(TIMER3_COMPA_vect), see: ATmega1280
\r
275 "16.11.40 TIFR5 - Timer/Counter5 Interrupt Flag Register", but no
\r
276 further action is needed. This EMPTY_INTERRUPT behaviour is to
\r
277 avoid having to clear a stale OCA pending interrupt and potentially
\r
278 discard an OCA on the next step time setup in ISR(TIMER3_COMPB_vect)
\r
280 if (count3 == FINAL) {
\r
284 /* Last OCA time for this step. Setup to pulse opto using OCA and OCB */
\r
285 forwardOf(OCR3A, OCR3A, (uint16_t)count3);
\r
286 forwardOf(OCR3B, OCR3A, PULSE_TIME);
\r
287 /* Maintain flag for nextStepTimer3() to queue any request */
\r
289 /* Clear stale OCB interrupt flag; see ATmega1280
\r
290 "17.11.40 TIFR5 - Timer/Counter5 Interrupt Flag Register" */
\r
291 TIFR3 = 1 << OCF3B;
\r
292 /* Enable the OCA and OCB pin controls to clear (drive low) both pins;
\r
293 see ATmega1280 "Table 17-3. Compare Output Mode, non-PWM" */
\r
294 TCCR3A = (1 << COM3A1) | (1 << COM3B1) | TIMER_MODE_NORMAL;
\r
295 /* Enable the OCA interrupt to discard the interrupt during the final count.
\r
296 Enable OCB interrupt to reload at end of pulse; see
\r
297 ATmega1280 "17.11.36 TIMSK5 - Timer/Counter 5 Interrupt Mask Register". */
\r
298 TIMSK3 = (1 << OCIE3A) | (1 << OCIE3B);
\r
301 /*..........................................................................*/
\r
302 /* OC3B Interrupt handler */
\r
303 ISR(TIMER3_COMPB_vect) {
\r
304 /* Set COM3A and COM3B to drive both OC latches high; see
\r
305 ATmega1280 "Table 17-3. Compare Output Mode, non-PWM" */
\r
306 TCCR3A = (1 << COM3A1) | (1 << COM3A0)
\r
307 | (1 << COM3B1) | (1 << COM3B0)
\r
308 | TIMER_MODE_NORMAL;
\r
309 /* Force OC latches high; see
\r
310 ATmega1280 "17.11.12 TCCR5C - Timer/Counter 5 Control Register C"
\r
311 Force OCA first followed by OCB so the LED extinguishes "glitch-free"
\r
312 TODO Consider risk of reverse bias of the LED for the interval */
\r
313 TCCR3C = (1 << FOC3A);
\r
314 TCCR3C = (1 << FOC3B);
\r
315 /* Disable OC as pin source and drive pins with PORT latch */
\r
316 TCCR3A = TIMER_MODE_NORMAL;
\r
317 /* Disable OCA and OCB interrupt; see ATmega1280
\r
318 "17.11.36 TIMSK5 - Timer/Counter 5 Interrupt Mask Register" */
\r
320 /* If no queued step time, idle and restart timer from nextStepTimer3() */
\r
325 /* Else consume queued step time */
\r
326 count3 = nextCount3;
\r
328 /* Request next step time from HSM */
\r
330 QActive_postISR(count3AO, NEXT_STEP_TIME_SIG, 0);
\r
332 /* If the last OCA period is too short, run "half" in the first OCA count
\r
333 so the final count is withing setup time limits */
\r
334 if ((count3 & 0xffff) < MIN_SETUP_TIME) {
\r
335 count3 += 0x10000 - (MID_SET_TIME - MIN_SETUP_TIME);
\r
336 /* Set OCA3 forward of the current TCNT3 */
\r
337 forwardOf(OCR3A, OCR3A, (MID_SET_TIME - MIN_SETUP_TIME));
\r
339 /* If the last OCA period extends the OCB past rollover then
\r
340 run "half" in the first OCA count */
\r
341 else if ((count3 & 0xffff) > MAX_SETUP_TIME) {
\r
342 count3 += 0x10000 - (MAX_SETUP_TIME - MID_SET_TIME);
\r
343 /* Set OCA3 forward of the current TCNT3 */
\r
344 forwardOf(OCR3A, OCR3A, (MAX_SETUP_TIME - MID_SET_TIME));
\r
346 /* Final count period */
\r
347 else if (!(count3 & 0xffff0000)) {
\r
348 /* Set up the last OCA period and OCB pulse period */
\r
349 forwardOf(OCR3A, OCR3A, (uint16_t)count3);
\r
350 forwardOf(OCR3B, OCR3A, PULSE_TIME);
\r
351 /* Flag nextStepTimer3() that the last time is still running
\r
352 so nextCount3 is queued */
\r
354 /* Enable the OCA and OCB pin controls to clear (drive low) both pins;
\r
355 see ATmega1280 "Table 17-3. Compare Output Mode, non-PWM" */
\r
356 TCCR3A = (1 << COM3A1) | (1 << COM3B1) | TIMER_MODE_NORMAL;
\r
357 /* Enable the timer OCB interrupt to reload at end of pulse */
\r
358 TIMSK3 = 1 << OCIE3B;
\r
361 /* For all non-FINAL timing, only enable OCA interrupt; see ATmega1280
\r
362 "17.11.36 TIMSK5 - Timer/Counter 5 Interrupt Mask Register" */
\r
363 TIMSK3 = 1 << OCIE3A;
\r
366 /*..........................................................................*/
\r
367 void BSP_initStepTimer4(QActive *me)
\r
372 /* Disable power reduction for timer4; see
\r
373 ATmega1280 "11.9.3 PRR1 - Power Reduction Register 1" */
\r
374 PRR1 &= ~(1 << PRTIM4);
\r
375 /* Disable (clocking of) the timer; see ATmega1280
\r
376 "17.11.8 TCCR5B - Timer/Counter 5 Control Register B" */
\r
378 /* Set COM4A and COM4B to drive both OC latches high; see
\r
379 ATmega1280 "Table 17-3. Compare Output Mode, non-PWM" */
\r
380 TCCR4A = (1 << COM4A1) | (1 << COM4A0)
\r
381 | (1 << COM4B1) | (1 << COM4B0)
\r
382 | TIMER_MODE_NORMAL;
\r
383 /* Force OC latches high; see ATmega1280
\r
384 "17.11.12 TCCR5C - Timer/Counter 5 Control Register C" */
\r
385 TCCR4C = (1 << FOC4A) | (1 << FOC4B);
\r
386 /* Disable OC as pin source and drive pins with PORT latch */
\r
387 TCCR4A = TIMER_MODE_NORMAL;
\r
388 /* Set OCA and OCB PORT bits high; OC4A is PH3 and OC4B is PH4 */
\r
389 PORTH |= (1 << PH3) | (1 << PH4);
\r
390 /* Set DDR to drive the PORT bits for OCA and OCB pins */
\r
391 DDRH |= (1 << DDH3) | (1 << DDH4);
\r
392 /* Reenable timer with clkI/O (no prescaling) */
\r
393 TCCR4B = 1 << CS40;
\r
396 /*..........................................................................*/
\r
397 uint8_t BSP_nextStepTimer4(uint32_t count)
\r
399 uint8_t register sreg;
\r
401 /* There is a minimum setup time so error on short counts */
\r
402 if (count < MIN_SETUP_TIME)
\r
404 /* A count is already queued so error */
\r
407 sreg = SREG; /* save interrupt and other status */
\r
408 cli(); /* and disable interrupts */
\r
409 /* If step timer is still running, leave it to the ISR to load
\r
410 the next step time */
\r
412 nextCount4 = count; /* queue the count for ISR to load */
\r
413 SREG = sreg; /* restore interrupts */
\r
416 SREG = sreg; /* restore interrupts */
\r
417 /* Request next step time from HSM */
\r
419 QActive_postISR(count4AO, NEXT_STEP_TIME_SIG, 0);
\r
421 /* If the last OCA period is too short, run "half" in the first OCA count
\r
422 so the final count is withing setup time limits */
\r
423 if ((count & 0x0000ffff) < MIN_SETUP_TIME) {
\r
424 count4 = count + 0x10000 - (MID_SET_TIME - MIN_SETUP_TIME);
\r
425 /* Set OCA4 forward of the current TCNT4 */
\r
426 forwardOf(OCR4A, TCNT4, (MID_SET_TIME - MIN_SETUP_TIME));
\r
428 /* If the last OCA period extends the OCB past rollover then
\r
429 run "half" in the first OCA count */
\r
430 else if ((count & 0x0000ffff) > MAX_SETUP_TIME) {
\r
431 count4 = count + 0x10000 - (MAX_SETUP_TIME - MID_SET_TIME);
\r
432 /* Set OCA4 forward of the current TCNT4 */
\r
433 forwardOf(OCR4A, TCNT4, (MAX_SETUP_TIME - MID_SET_TIME));
\r
435 /* Final count period */
\r
436 else if (!(count & 0xffff0000)) {
\r
437 /* Flag nextStepTimer4() that the last time is still running
\r
438 so nextCount4 is queued */
\r
440 /* Set up the last OCRA period and OCRB pulse period */
\r
441 forwardOf(OCR4A, TCNT4, (uint16_t)count);
\r
442 forwardOf(OCR4B, OCR4A, PULSE_TIME);
\r
443 /* Clear stale OC interrupt flags; see ATmega1280
\r
444 "17.11.40 TIFR5 - Timer/Counter5 Interrupt Flag Register" */
\r
445 TIFR4 = (1 << OCF4B) | (1 << OCF4A);
\r
446 /* Enable the OCA and OCB pin controls to clear (drive low) both pins;
\r
447 see ATmega1280 "Table 17-3. Compare Output Mode, non-PWM" */
\r
448 TCCR4A = (1 << COM4A1) | (1 << COM4B1) | TIMER_MODE_NORMAL;
\r
449 /* Enable the OCA interrupt to discard the interrupt during the final count.
\r
450 Enable OCB interrupt to reload at end of pulse */
\r
451 TIMSK4 = (1 << OCIE4A) | (1 << OCIE4B);
\r
454 /* Start rollover period */
\r
457 forwardOf(OCR4A, TCNT4, 0);
\r
459 /* Clear stale OCA interrupt flag; see ATmega1280
\r
460 "17.11.40 TIFR5 - Timer/Counter5 Interrupt Flag Register" */
\r
461 TIFR4 = 1 << OCF4A;
\r
462 /* For all non-FINAL timing, only enable OCA interrupt; see ATmega1280
\r
463 "17.11.36 TIMSK5 - Timer/Counter 5 Interrupt Mask Register" */
\r
464 TIMSK4 = 1 << OCIE4A;
\r
467 /*..........................................................................*/
\r
468 /* For information about AVR Interrupts see:
\r
469 http://www.nongnu.org/avr-libc/user-manual/group__avr__interrupts.html
\r
470 OC4A Interrupt handler */
\r
471 ISR(TIMER4_COMPA_vect) {
\r
472 /* Adjust timer based on time to run */
\r
473 if (count4 & 0xffff0000) {
\r
475 if (count4 & 0xffff0000) {
\r
476 /* More OCA rollovers yet */
\r
480 /* The OCA interrupt flag has been cleared on vector into here,
\r
481 ISR(TIMER4_COMPA_vect), see: ATmega1280
\r
482 "16.11.40 TIFR5 - Timer/Counter5 Interrupt Flag Register", but no
\r
483 further action is needed. This EMPTY_INTERRUPT behaviour is to
\r
484 avoid having to clear a stale OCA pending interrupt and potentially
\r
485 discard an OCA on the next step time setup in ISR(TIMER4_COMPB_vect)
\r
487 if (count4 == FINAL) {
\r
491 /* Last OCA time for this step. Setup to pulse opto using OCA and OCB */
\r
492 forwardOf(OCR4A, OCR4A, (uint16_t)count4);
\r
493 forwardOf(OCR4B, OCR4A, PULSE_TIME);
\r
494 /* Maintain flag for nextStepTimer4() to queue any request */
\r
496 /* Clear stale OCB interrupt flag; see ATmega1280
\r
497 "17.11.40 TIFR5 - Timer/Counter5 Interrupt Flag Register" */
\r
498 TIFR4 = 1 << OCF4B;
\r
499 /* Enable the OCA and OCB pin controls to clear (drive low) both pins;
\r
500 see ATmega1280 "Table 17-3. Compare Output Mode, non-PWM" */
\r
501 TCCR4A = (1 << COM4A1) | (1 << COM4B1) | TIMER_MODE_NORMAL;
\r
502 /* Enable the OCA interrupt to discard the interrupt during the final count.
\r
503 Enable OCB interrupt to reload at end of pulse; see
\r
504 ATmega1280 "17.11.36 TIMSK5 - Timer/Counter 5 Interrupt Mask Register". */
\r
505 TIMSK4 = (1 << OCIE4A) | (1 << OCIE4B);
\r
508 /*..........................................................................*/
\r
509 /* OC4B Interrupt handler */
\r
510 ISR(TIMER4_COMPB_vect) {
\r
511 /* Set COM4A and COM4B to drive both OC latches high; see
\r
512 ATmega1280 "Table 17-3. Compare Output Mode, non-PWM" */
\r
513 TCCR4A = (1 << COM4A1) | (1 << COM4A0)
\r
514 | (1 << COM4B1) | (1 << COM4B0)
\r
515 | TIMER_MODE_NORMAL;
\r
516 /* Force OC latches high; see
\r
517 ATmega1280 "17.11.12 TCCR5C - Timer/Counter 5 Control Register C"
\r
518 Force OCA first followed by OCB so the LED extinguishes "glitch-free"
\r
519 TODO Consider risk of reverse bias of the LED for the interval */
\r
520 TCCR4C = (1 << FOC4A);
\r
521 TCCR4C = (1 << FOC4B);
\r
522 /* Disable OC as pin source and drive pins with PORT latch */
\r
523 TCCR4A = TIMER_MODE_NORMAL;
\r
524 /* Disable OCA and OCB interrupt; see ATmega1280
\r
525 "17.11.36 TIMSK5 - Timer/Counter 5 Interrupt Mask Register" */
\r
527 /* If no queued step time, idle and restart timer from nextStepTimer4() */
\r
532 /* Else consume queued step time */
\r
533 count4 = nextCount4;
\r
535 /* Request next step time from HSM */
\r
537 QActive_postISR(count4AO, NEXT_STEP_TIME_SIG, 0);
\r
539 /* If the last OCA period is too short, run "half" in the first OCA count
\r
540 so the final count is withing setup time limits */
\r
541 if ((count4 & 0xffff) < MIN_SETUP_TIME) {
\r
542 count4 += 0x10000 - (MID_SET_TIME - MIN_SETUP_TIME);
\r
543 /* Set OCA4 forward of the current TCNT4 */
\r
544 forwardOf(OCR4A, OCR4A, (MID_SET_TIME - MIN_SETUP_TIME));
\r
546 /* If the last OCA period extends the OCB past rollover then
\r
547 run "half" in the first OCA count */
\r
548 else if ((count4 & 0xffff) > MAX_SETUP_TIME) {
\r
549 count4 += 0x10000 - (MAX_SETUP_TIME - MID_SET_TIME);
\r
550 /* Set OCA4 forward of the current TCNT4 */
\r
551 forwardOf(OCR4A, OCR4A, (MAX_SETUP_TIME - MID_SET_TIME));
\r
553 /* Final count period */
\r
554 else if (!(count4 & 0xffff0000)) {
\r
555 /* Set up the last OCA period and OCB pulse period */
\r
556 forwardOf(OCR4A, OCR4A, (uint16_t)count4);
\r
557 forwardOf(OCR4B, OCR4A, PULSE_TIME);
\r
558 /* Flag nextStepTimer4() that the last time is still running
\r
559 so nextCount4 is queued */
\r
561 /* Enable the OCA and OCB pin controls to clear (drive low) both pins;
\r
562 see ATmega1280 "Table 17-3. Compare Output Mode, non-PWM" */
\r
563 TCCR4A = (1 << COM4A1) | (1 << COM4B1) | TIMER_MODE_NORMAL;
\r
564 /* Enable the timer OCB interrupt to reload at end of pulse */
\r
565 TIMSK4 = 1 << OCIE4B;
\r
568 /* For all non-FINAL timing, only enable OCA interrupt; see ATmega1280
\r
569 "17.11.36 TIMSK5 - Timer/Counter 5 Interrupt Mask Register" */
\r
570 TIMSK4 = 1 << OCIE4A;
\r
573 /*..........................................................................*/
\r
574 ISR(TIMER0_COMPA_vect)
\r
578 /*..........................................................................*/
\r
579 QActive *ADC15Sense = (QActive *)0;
\r
581 void BSP_initAzimuthFault(QActive *me)
\r
584 /* Arduino ADC15 pin generates PCINT23 interrupts */
\r
585 PCMSK2 |= 1 << PCINT23;
\r
586 PCICR |= 1 << PCIE2;
\r
591 if (PINK & (1 << PINK7)) {
\r
592 QActive_postISR(ADC15Sense, STEPPER_FAULT_SIG, 0);
\r
595 /*..........................................................................*/
\r
596 QActive *PWM12Sense = (QActive *)0;
\r
598 void BSP_initElevationFault(QActive *me)
\r
601 /* Arduino PWM12 pin generates PCINT6 interrupts */
\r
602 PCMSK0 |= 1 << PCINT6;
\r
603 PCICR |= 1 << PCIE0;
\r
608 if (PINB & (1 << PINB6)) {
\r
609 QActive_postISR(PWM12Sense, STEPPER_FAULT_SIG, 0);
\r
612 /*..........................................................................*/
\r
613 void BSP_azimuthDirection(int8_t direction)
\r
615 if (direction < 0) {
\r
616 PORTA &= ~(1 << AZ_DIR_PIN);
\r
619 PORTA |= 1 << AZ_DIR_PIN;
\r
621 /*..........................................................................*/
\r
622 void BSP_elevationDirection(int8_t direction)
\r
624 if (direction < 0) {
\r
625 PORTA &= ~(1 << EL_DIR_PIN);
\r
628 PORTA |= 1 << EL_DIR_PIN;
\r
630 /*..........................................................................*/
\r
631 /* Current reduction should be implemented automatically using FC jumper on
\r
632 the GDM stepper driver board. See warning, GDM Manual, 6.5 Bridges
\r
633 (Jumpers) function, page 11. The services and hardware are provided in
\r
634 case explicit current control is necessary or for Current Off control. */
\r
635 void BSP_azimuthCurrent(uint8_t full)
\r
638 PORTA &= ~(1 << AZ_CURR_PIN);
\r
641 PORTA |= 1 << AZ_CURR_PIN;
\r
643 /*..........................................................................*/
\r
644 void BSP_elevationCurrent(uint8_t full)
\r
647 PORTA &= ~(1 << EL_CURR_PIN);
\r
650 PORTA |= 1 << EL_CURR_PIN;
\r
652 /*..........................................................................*/
\r
653 void BSP_init(void)
\r
655 /* set the output compare value */
\r
656 OCR0A = (uint8_t)((F_CPU / BSP_TICKS_PER_SEC / 1024) - 1);
\r
658 /* enable the shield activity LED port pin and drive LED on */
\r
662 /* Drive output EL and AZ output pins and set inactive low */
\r
663 PORTA &= ~( (1 << EL_DIR_PIN) | (1 << AZ_DIR_PIN)
\r
664 | (1 << EL_CURR_PIN) | (1 << AZ_CURR_PIN));
\r
665 DDRA |= (1 << EL_DIR_PIN) | (1 << AZ_DIR_PIN)
\r
666 | (1 << EL_CURR_PIN) | (1 << AZ_CURR_PIN);
\r
668 /*..........................................................................*/
\r
669 void QF_onStartup(void) {
\r
670 cli(); /* make sure that all interrupts are disabled */
\r
672 /* set Timer0 in CTC mode, 1/1024 prescaler, start the timer ticking */
\r
673 TCCR0A = (1 << WGM01) | (0 << WGM00);
\r
674 TCCR0B = (0 << WGM02) | (5 << CS00);
\r
675 TIMSK0 = (1 << OCIE0A); /* Enable TIMER0 compare Interrupt */
\r
677 // start the serial port
\r
678 //serialReceiveStartup(USART0);
\r
679 //serialTransmitStartup(USART0);
\r
681 sei(); /* make sure that all interrupts are enabled */
\r
683 /*..........................................................................*/
\r
684 void QF_onIdle(void) {
\r
685 PORTB &= ~(1 << PB7);
\r
686 /* Power reduction on Timer1, SPI (both unused) */
\r
687 // PRR = (1 << PRTWI) | (1 << PRTIM2) | (1 << PRTIM1) | (1 << PRSPI);
\r
688 SMCR = (0 << SM0) | (1 << SE); /* Power save */
\r
689 __asm__ __volatile__ ("sei" "\n\t" :: ); /* Two instructions atomic */
\r
690 __asm__ __volatile__ ("sleep" "\n\t" :: );
\r
694 /*..........................................................................*/
\r
695 void Q_onAssert(char const Q_ROM * const Q_ROM_VAR file, int line) {
\r
696 for (;;) { /* NOTE: replace the loop with reset for final version */
\r
699 /*..........................................................................*/
\r