stepper_at91.c

Go to the documentation of this file.
00001 
00056 #include "stepper_at91.h"
00057 
00058 #include <cfg/macros.h>
00059 #include <cfg/debug.h>
00060 
00061 #include <cpu/types.h>
00062 #include <cpu/irq.h>
00063 
00064 #include <io/arm.h>
00065 
00066 #include "appconfig.h"
00067 
00068 /*
00069  * Delay to set C compare to clear output
00070  * on select TIO output
00071  */
00072 #define STEPPER_DELAY_ON_COMPARE_C 20
00073 
00074 /*
00075  * Forward declaration for interrupt handler
00076  */
00077 static void stepper_tc0_irq(void);
00078 static void stepper_tc1_irq(void);
00079 static void stepper_tc2_irq(void);
00080 
00082 static struct TimerCounter stepper_timers[CONFIG_TC_STEPPER_MAX_NUM] =
00083 {
00084     { //Timer Counter settings for TIOA0 output pin
00085         .timer_id = TC0_ID,
00086         .blk_ctrl_set = TC_NONEXC0,
00087         .chl_mode_reg = &TC0_CMR,
00088         .chl_ctrl_reg = &TC0_CCR,
00089         .comp_effect_mask = TC_ACPA_MASK,
00090         .comp_effect_set = TC_ACPA_SET_OUTPUT,
00091         .comp_effect_clear = TC_ACPA_CLEAR_OUTPUT,
00092         .comp_effect_c_mask = TC_ACPC_MASK,
00093         .comp_effect_c_clear = TC_ACPC_CLEAR_OUTPUT,
00094         .ext_event_set = TC_EEVT_XC0,
00095         .comp_reg = &TC0_RA,
00096         .comp_c_reg = &TC0_RC,
00097         .count_val_reg = &TC0_CV,
00098         .irq_enable_reg = &TC0_IER,
00099         .irq_disable_reg = &TC0_IDR,
00100         .irq_set_mask = BV(TC_CPAS),
00101         .irq_mask_reg = &TC0_IMR,
00102         .isr = stepper_tc0_irq,
00103         .status_reg = &TC0_SR,
00104         .tio_pin = TIOA0,
00105         .callback = NULL,
00106         .motor = NULL,
00107     },
00108     { //Timer Counter settings for TIOB0 output pin
00109         .timer_id = TC0_ID,
00110         .blk_ctrl_set = TC_NONEXC0,
00111         .chl_mode_reg = &TC0_CMR,
00112         .chl_ctrl_reg = &TC0_CCR,
00113         .comp_reg = &TC0_RB,
00114         .comp_c_reg = &TC0_RC,
00115         .count_val_reg = &TC0_CV,
00116         .comp_effect_mask = TC_BCPB_MASK,
00117         .comp_effect_set = TC_BCPB_SET_OUTPUT,
00118         .comp_effect_clear = TC_BCPB_CLEAR_OUTPUT,
00119         .comp_effect_c_mask = TC_BCPC_MASK,
00120         .comp_effect_c_clear = TC_BCPC_CLEAR_OUTPUT,
00121         .ext_event_set = TC_EEVT_XC0,
00122         .irq_enable_reg = &TC0_IER,
00123         .irq_disable_reg = &TC0_IDR,
00124         .irq_set_mask = BV(TC_CPBS),
00125         .irq_mask_reg = &TC0_IMR,
00126         .isr = stepper_tc0_irq,
00127         .status_reg = &TC0_SR,
00128         .tio_pin = TIOB0,
00129         .callback = NULL,
00130         .motor = NULL,
00131     },
00132     { //Timer Counter settings for TIOA1 output pin
00133         .timer_id = TC1_ID,
00134         .blk_ctrl_set = TC_NONEXC1,
00135         .chl_mode_reg = &TC1_CMR,
00136         .chl_ctrl_reg = &TC1_CCR,
00137         .comp_reg = &TC1_RA,
00138         .comp_c_reg = &TC1_RC,
00139         .count_val_reg = &TC1_CV,
00140         .comp_effect_mask = TC_ACPA_MASK,
00141         .comp_effect_set = TC_ACPA_SET_OUTPUT,
00142         .comp_effect_clear = TC_ACPA_CLEAR_OUTPUT,
00143         .comp_effect_c_mask = TC_ACPC_MASK,
00144         .comp_effect_c_clear = TC_ACPC_CLEAR_OUTPUT,
00145         .ext_event_set = TC_EEVT_XC1,
00146         .irq_enable_reg = &TC1_IER,
00147         .irq_disable_reg = &TC1_IDR,
00148         .irq_set_mask = BV(TC_CPAS),
00149         .irq_mask_reg = &TC1_IMR,
00150         .isr = stepper_tc1_irq,
00151         .status_reg = &TC1_SR,
00152         .tio_pin = TIOA1,
00153         .callback = NULL,
00154         .motor = NULL,
00155     },
00156     { //Timer Counter settings for TIOB1 output pin
00157         .timer_id = TC1_ID,
00158         .blk_ctrl_set = TC_NONEXC1,
00159         .chl_mode_reg = &TC1_CMR,
00160         .chl_ctrl_reg = &TC1_CCR,
00161         .comp_reg = &TC1_RB,
00162         .comp_c_reg = &TC1_RC,
00163         .count_val_reg = &TC1_CV,
00164         .comp_effect_mask = TC_BCPB_MASK,
00165         .comp_effect_set = TC_BCPB_SET_OUTPUT,
00166         .comp_effect_clear = TC_BCPB_CLEAR_OUTPUT,
00167         .comp_effect_c_mask = TC_BCPC_MASK,
00168         .comp_effect_c_clear = TC_BCPC_CLEAR_OUTPUT,
00169         .ext_event_set = TC_EEVT_XC1,
00170         .irq_enable_reg = &TC1_IER,
00171         .irq_disable_reg = &TC1_IDR,
00172         .irq_set_mask = BV(TC_CPBS),
00173         .irq_mask_reg = &TC1_IMR,
00174         .isr = stepper_tc1_irq,
00175         .status_reg = &TC1_SR,
00176         .tio_pin = TIOB1,
00177         .callback = NULL,
00178         .motor = NULL,
00179     },
00180     { //Timer Counter settings for TIOA2 output pin
00181         .timer_id = TC2_ID,
00182         .blk_ctrl_set = TC_NONEXC2,
00183         .chl_mode_reg = &TC2_CMR,
00184         .chl_ctrl_reg = &TC2_CCR,
00185         .comp_reg = &TC2_RA,
00186         .comp_c_reg = &TC2_RC,
00187         .count_val_reg = &TC2_CV,
00188         .comp_effect_mask = TC_ACPA_MASK,
00189         .comp_effect_set = TC_ACPA_SET_OUTPUT,
00190         .comp_effect_clear = TC_ACPA_CLEAR_OUTPUT,
00191         .comp_effect_c_mask = TC_ACPC_MASK,
00192         .comp_effect_c_clear = TC_ACPC_CLEAR_OUTPUT,
00193         .ext_event_set = TC_EEVT_XC2,
00194         .irq_enable_reg = &TC2_IER,
00195         .irq_disable_reg = &TC2_IDR,
00196         .irq_set_mask = BV(TC_CPAS),
00197         .irq_mask_reg = &TC2_IMR,
00198         .isr = stepper_tc2_irq,
00199         .status_reg = &TC2_SR,
00200         .tio_pin = TIOA2,
00201         .callback = NULL,
00202         .motor = NULL,
00203     },
00204     { //Timer Counter settings for TIOB2 output pin
00205         .timer_id = TC2_ID,
00206         .blk_ctrl_set = TC_NONEXC2,
00207         .chl_mode_reg = &TC2_CMR,
00208         .chl_ctrl_reg = &TC2_CCR,
00209         .comp_reg = &TC2_RB,
00210         .comp_c_reg = &TC2_RC,
00211         .count_val_reg = &TC2_CV,
00212         .comp_effect_mask = TC_BCPB_MASK,
00213         .comp_effect_set = TC_BCPB_SET_OUTPUT,
00214         .comp_effect_clear = TC_BCPB_CLEAR_OUTPUT,
00215         .comp_effect_c_mask = TC_BCPC_MASK,
00216         .comp_effect_c_clear = TC_BCPC_CLEAR_OUTPUT,
00217         .ext_event_set = TC_EEVT_XC2,
00218         .irq_enable_reg = &TC2_IER,
00219         .irq_disable_reg = &TC2_IDR,
00220         .irq_set_mask = BV(TC_CPBS),
00221         .irq_mask_reg = &TC2_IMR,
00222         .isr = stepper_tc2_irq,
00223         .status_reg = &TC2_SR,
00224         .tio_pin = TIOB2,
00225         .callback = NULL,
00226         .motor = NULL,
00227     }
00228 };
00229 
00233 INLINE void stepper_tc_tio_irq(struct TimerCounter * t)
00234 {
00235     //
00236     *t->chl_mode_reg &= ~t->comp_effect_c_mask;
00237     *t->chl_mode_reg |= t->comp_effect_c_clear;
00238 
00239     /*
00240      * Cleat TIO output on c register compare.
00241      * This generate an pulse with variable lenght, this
00242      * depend to delay that interrupt is realy service.
00243      */
00244     *t->comp_c_reg = *t->count_val_reg + STEPPER_DELAY_ON_COMPARE_C;
00245 
00246     //Call the associate callback
00247     t->callback(t->motor);
00248 
00249     *t->chl_mode_reg &= ~t->comp_effect_c_mask;
00250 }
00251 
00252 
00253 /*
00254  * Interrupt handler for timer counter TCKL0
00255  */
00256 static void ISR_FUNC stepper_tc0_irq(void)
00257 {
00258     /*
00259      * Warning: when we read the status_reg register, we reset it.
00260      * That mean if is occur an interrupt event we can read only
00261      * the last that has been occur. To not miss an interrupt event
00262      * we save the status_reg register and then we read it.
00263      */
00264     uint32_t  status_reg = TC0_SR & TC0_IMR;
00265 
00266     if ((status_reg & BV(TC_CPBS)) && (status_reg & BV(TC_CPAS)))
00267         STEPPER_STROBE_ON;
00268 
00269     if (status_reg & BV(TC_CPAS))
00270         stepper_tc_tio_irq(&stepper_timers[TC_TIOA0]);
00271 
00272     if (status_reg & BV(TC_CPBS))
00273         stepper_tc_tio_irq(&stepper_timers[TC_TIOB0]);
00274 
00275     STEPPER_STROBE_OFF;
00276     /* Inform hw that we have served the IRQ */
00277     AIC_EOICR = 0;
00278 
00279 }
00280 
00281 /*
00282  * Interrupt handler for timer counter TCKL1
00283  */
00284 static void ISR_FUNC stepper_tc1_irq(void)
00285 {
00286     STEPPER_STROBE_ON_1;
00287     /*
00288      * Warning: when we read the status_reg register, we reset it.
00289      * That mean if is occur an interrupt event we can read only
00290      * the last that has been occur. To not miss an interrupt event
00291      * we save the status_reg register and then we read it.
00292      */
00293     uint32_t  status_reg = TC1_SR & TC1_IMR;
00294 
00295     if (status_reg & BV(TC_CPAS))
00296         stepper_tc_tio_irq(&stepper_timers[TC_TIOA1]);
00297 
00298     if (status_reg & BV(TC_CPBS))
00299         stepper_tc_tio_irq(&stepper_timers[TC_TIOB1]);
00300 
00301 
00302     /* Inform hw that we have served the IRQ */
00303     AIC_EOICR = 0;
00304     STEPPER_STROBE_OFF_1;
00305 }
00306 
00307 
00308 /*
00309  * Interrupt handler for timer counter TCKL2
00310  */
00311 static void ISR_FUNC stepper_tc2_irq(void)
00312 {
00313 
00314     /*
00315      * Warning: when we read the status_reg register, we reset it.
00316      * That mean if is occur an interrupt event we can read only
00317      * the last that has been occur. To not miss an interrupt event
00318      * we save the status_reg register and then we read it.
00319      */
00320     uint32_t  status_reg = TC2_SR & TC2_IMR;
00321 
00322     STEPPER_STROBE_ON_2;
00323     if (status_reg & BV(TC_CPAS))
00324         stepper_tc_tio_irq(&stepper_timers[TC_TIOA2]);
00325 
00326     if (status_reg & BV(TC_CPBS))
00327         stepper_tc_tio_irq(&stepper_timers[TC_TIOB2]);
00328 
00329     STEPPER_STROBE_OFF_2;
00330     /* Inform hw that we have served the IRQ */
00331     AIC_EOICR = 0;
00332 
00333 }
00334 
00341 void stepper_tc_setup(int index, stepper_isr_t callback, struct Stepper *motor)
00342 {
00343     ASSERT(index < CONFIG_TC_STEPPER_MAX_NUM);
00344 
00345     motor->timer = &stepper_timers[index];
00346 
00347     //Disable PIO controller and enable TIO function
00348     TIO_PIO_PDR = BV(motor->timer->tio_pin);
00349     TIO_PIO_ABSR = BV(motor->timer->tio_pin);
00350 
00351     /*
00352      * Sets timer counter in waveform mode.
00353      * We set as default:
00354      * - Waveform mode 00 (see datasheet for more detail.)
00355      * - Master clock prescaler to STEPPER_MCK_PRESCALER
00356      * - Set none external event
00357      * - Clear pin output on comp_reg
00358      * - None effect on reg C compare
00359      */
00360     *motor->timer->chl_mode_reg = BV(TC_WAVE);
00361     *motor->timer->chl_mode_reg |= motor->timer->ext_event_set;
00362     *motor->timer->chl_mode_reg &= ~TC_WAVSEL_MASK;
00363     *motor->timer->chl_mode_reg |= TC_WAVSEL_UP;
00364     *motor->timer->chl_mode_reg |= STEPPER_MCK_PRESCALER;
00365     *motor->timer->chl_mode_reg |= motor->timer->comp_effect_clear;
00366     *motor->timer->chl_mode_reg &= ~motor->timer->comp_effect_c_mask;
00367 
00368     //Reset comp_reg and C compare register
00369     *motor->timer->comp_reg = 0;
00370     *motor->timer->comp_c_reg = 0;
00371 
00372     //Register interrupt vector
00373     cpuflags_t flags;
00374     IRQ_SAVE_DISABLE(flags);
00375 
00376     /*
00377      * Warning: To guarantee a correct management of interrupt event, we must
00378      * trig the interrupt on level sensitive. This becouse, we have only a common
00379      * line for interrupt request, and if we have at the same time two interrupt
00380      * request could be that the is service normaly but the second will never
00381      *  been detected and interrupt will stay active but never serviced.
00382      */
00383     AIC_SVR(motor->timer->timer_id) = motor->timer->isr;
00384     AIC_SMR(motor->timer->timer_id) = AIC_SRCTYPE_INT_LEVEL_SENSITIVE;
00385     AIC_IECR = BV(motor->timer->timer_id);
00386 
00387     // Disable interrupt on select timer counter
00388     stepper_tc_irq_disable(motor->timer);
00389 
00390     IRQ_RESTORE(flags);
00391 
00392     //Register callback
00393     motor->timer->callback = callback;
00394     motor->timer->motor = motor;
00395 }
00396 
00400 void stepper_tc_init(void)
00401 {
00402     STEPPER_STROBE_INIT;
00403 
00404     ASSERT(CONFIG_NUM_STEPPER_MOTORS <= CONFIG_TC_STEPPER_MAX_NUM);
00405 
00406     /*
00407      * Enable timer counter:
00408      * - power on all timer counter
00409      * - disable all interrupt
00410      * - disable all external event/timer source
00411      */
00412     for (int i = 0; i < CONFIG_TC_STEPPER_MAX_NUM; i++)
00413     {
00414         PMC_PCER = BV(stepper_timers[i].timer_id);
00415         *stepper_timers[i].irq_disable_reg = 0xFFFFFFFF;
00416         TC_BMR = stepper_timers[i].blk_ctrl_set;
00417     }
00418 
00419     /*
00420      * Enable timer counter and start it.
00421      */
00422     for (int i = 0; i < CONFIG_TC_STEPPER_MAX_NUM; i++)
00423         *stepper_timers[i].chl_ctrl_reg = (BV(TC_CLKEN) | BV(TC_SWTRG));
00424 
00425 }
00426