From d4cbac2a5c8cfab572784f52176b643c581a6894 Mon Sep 17 00:00:00 2001 From: Todd Fleming Date: Sun, 8 Jan 2017 16:12:24 -0500 Subject: [PATCH] Port stepper --- grbl/config.h | 14 +++++---- grbl/stepper.c | 76 ++++++++++++++++++++++++++++------------------- smoother/avr/io.h | 20 +------------ smoother/delay.h | 20 +++++++++---- 4 files changed, 70 insertions(+), 60 deletions(-) diff --git a/grbl/config.h b/grbl/config.h index 0510b36..b039de4 100644 --- a/grbl/config.h +++ b/grbl/config.h @@ -415,14 +415,18 @@ // NOTE: Uncomment to enable. The recommended delay must be > 3us, and, when added with the // user-supplied step pulse time, the total time must not exceed 127us. Reported successful // values for certain setups have ranged from 5 to 20us. -// #define STEP_PULSE_DELAY 10 // Step pulse delay in microseconds. Default disabled. +// not ported; don't use. #define STEP_PULSE_DELAY 10 // Step pulse delay in microseconds. Default disabled. + +// Creates a delay between setting the direction pin and pulsing the step pin. This delay +// lives inside the main Grbl interrupt. +#define STEP_PULSE_DELAY_NS 200 // Step pulse delay in nanoseconds. // The number of linear motions in the planner buffer to be planned at any give time. The vast // majority of RAM that Grbl uses is based on this buffer size. Only increase if there is extra // available RAM, like when re-compiling for a Mega2560. Or decrease if the Arduino begins to // crash due to the lack of available RAM or if the CPU is having trouble keeping up with planning // new incoming motions as they are executed. -// #define BLOCK_BUFFER_SIZE 16 // Uncomment to override default in planner.h. +#define BLOCK_BUFFER_SIZE 32 // Uncomment to override default in planner.h. // Governs the size of the intermediary step segment buffer between the step execution algorithm // and the planner blocks. Each segment is set of steps executed at a constant velocity over a @@ -617,9 +621,9 @@ #define Y_LIMIT_BIT 27 // Y-MIN=26, Y-MAX=27 #define Z_LIMIT_BIT 29 // Z-MIN=28, Z-MAX=29 #define LIMIT_MASK ((1<> 3); #else // Normal operation - // Set step pulse time. Ad hoc computation from oscilloscope. Uses two's complement. - st.step_pulse_time = -(((settings.pulse_microseconds-2)*TICKS_PER_MICROSECOND) >> 3); + st.step_setup_time = uint32_t(uint64_t(SystemCoreClock)*STEP_PULSE_DELAY_NS/1000'000'000); + st.step_pulse_time = settings.pulse_microseconds*TICKS_PER_MICROSECOND; #endif - // Enable Stepper Driver Interrupt - TIMSK1 |= (1<TCR = 0b10; // reset + LPC_TIM1->MR0 = 4000; // Generate first interrupt soon + LPC_TIM1->TCR = 0b01; // enable } @@ -233,8 +236,7 @@ void st_wake_up() void st_go_idle() { // Disable Stepper Driver Interrupt. Allow Stepper Port Reset Interrupt to finish, if active. - TIMSK1 &= ~(1<TCR = 0; // Disable Timer1 busy = false; // Set stepper driver idle state, disabled or enabled, depending on settings and circumstances. @@ -299,8 +301,9 @@ void st_go_idle() // TODO: Replace direct updating of the int32 position counters in the ISR somehow. Perhaps use smaller // int8 variables and update position counters only when a segment completes. This can get complicated // with probing and homing cycles that require true real-time positions. -ISR(TIMER1_COMPA_vect) +extern "C" void TIMER1_IRQHandler() { + LPC_TIM1->IR = LPC_TIM1->IR; // Clear interrupt if (busy) { return; } // The busy-flag is used to avoid reentering this interrupt // Set the direction pins a couple of nanoseconds before we step the steppers @@ -308,19 +311,26 @@ ISR(TIMER1_COMPA_vect) // Then pulse the stepping pins #ifdef STEP_PULSE_DELAY + #error not implemented st.step_bits = (STEP_PORT & ~STEP_MASK) | st.step_outbits; // Store out_bits to prevent overwriting. #else // Normal operation + delay_loop(get_time(), st.step_setup_time); STEP_PORT = (STEP_PORT & ~STEP_MASK) | st.step_outbits; + // Mark time step bits were set + uint32_t step_start_time = get_time(); #endif // Enable step pulse reset timer so that The Stepper Port Reset Interrupt can reset the signal after // exactly settings.pulse_microseconds microseconds, independent of the main Timer1 prescaler. - TCNT0 = st.step_pulse_time; // Reload Timer0 counter - TCCR0B = (1<prescaler<cycles_per_tick; + LPC_TIM1->MR0 = st.exec_segment->cycles_per_tick; st.step_count = st.exec_segment->n_step; // NOTE: Can sometimes be zero when moving slow. // If the new segment starts a new planner block, initialize stepper variables and counters. // NOTE: When the segment data index changes, this indicates a new planner block. @@ -368,6 +379,9 @@ ISR(TIMER1_COMPA_vect) if (st.exec_block->is_pwm_rate_adjusted) { spindle_set_speed(SPINDLE_PWM_OFF_VALUE); } #endif system_set_exec_state_flag(EXEC_CYCLE_STOP); // Flag main program for cycle end + // Reset stepping pins after delay + delay_loop(step_start_time, st.step_pulse_time); + STEP_PORT = (STEP_PORT & ~STEP_MASK) | (step_port_invert_mask & STEP_MASK); return; // Nothing to do but exit. } } @@ -425,6 +439,11 @@ ISR(TIMER1_COMPA_vect) } st.step_outbits ^= step_port_invert_mask; // Apply step port invert mask + + // Reset stepping pins after delay + delay_loop(step_start_time, st.step_pulse_time); + STEP_PORT = (STEP_PORT & ~STEP_MASK) | (step_port_invert_mask & STEP_MASK); + busy = false; } @@ -437,6 +456,8 @@ ISR(TIMER1_COMPA_vect) cause issues at high step rates if another high frequency asynchronous interrupt is added to Grbl. */ +/* Not ported; the main ISR assumes short pulse widths and handles it. Stepper drivers with + long pulse widths may need this instead if they cause the main ISR to consume too much time. // This interrupt is enabled by ISR_TIMER1_COMPAREA when it sets the motor port bits to execute // a step. This ISR resets the motor port after a short period (settings.pulse_microseconds) // completing one step cycle. @@ -457,6 +478,7 @@ ISR(TIMER0_OVF_vect) STEP_PORT = st.step_bits; // Begin step pulse. } #endif +*/ // Generates the step and direction port invert masks used in the Stepper Interrupt Driver. @@ -506,21 +528,13 @@ void stepper_init() DIRECTION_DDR |= DIRECTION_MASK; // Configure Timer 1: Stepper Driver Interrupt - TCCR1B &= ~(1<TCR = 0; // disable + LPC_TIM1->CTCR = 0; // timer mode + LPC_TIM1->PR = 0; // no prescale + LPC_TIM1->MCR = 0b011; // MR0: !stop, reset, interrupt + LPC_TIM1->CCR = 0; // no capture + LPC_TIM1->EMR = 0; // no external match + NVIC_EnableIRQ(TIMER1_IRQn); // Enable Stepper Driver Interrupt } @@ -948,9 +962,9 @@ void st_prep_buffer() cycles >>= prep_segment->amass_level; prep_segment->n_step <<= prep_segment->amass_level; } - if (cycles < (1UL << 16)) { prep_segment->cycles_per_tick = cycles; } // < 65536 (4.1ms @ 16MHz) - else { prep_segment->cycles_per_tick = 0xffff; } // Just set the slowest speed possible. + prep_segment->cycles_per_tick = cycles; #else + #error not ported; AMASS is required // Compute step timing and timer prescalar for normal step generation. if (cycles < (1UL << 16)) { // < 65536 (4.1ms @ 16MHz) prep_segment->prescaler = 1; // prescaler: 0 diff --git a/smoother/avr/io.h b/smoother/avr/io.h index 8925325..1e4e5ee 100644 --- a/smoother/avr/io.h +++ b/smoother/avr/io.h @@ -28,28 +28,14 @@ extern DummyReg EECR; extern DummyReg EEDR; extern DummyReg EEMPE; extern DummyReg EEPE; -extern DummyReg OCIE0A; -extern DummyReg OCIE0B; -extern DummyReg OCIE1A; -extern DummyReg OCR1A; extern DummyReg OCR2A; extern DummyReg PCICR; extern DummyReg PCIE0; extern DummyReg PCIE1; extern DummyReg PCMSK0; extern DummyReg PCMSK1; -extern DummyReg SREG; -extern DummyReg TCCR0A; -extern DummyReg TCCR0B; -extern DummyReg TCCR1A; -extern DummyReg TCCR1B; -extern DummyReg TCCRA; extern DummyReg TCCR2A; extern DummyReg TCCR2B; -extern DummyReg TCNT0; -extern DummyReg TIMSK0; -extern DummyReg TIMSK1; -extern DummyReg TOIE0; extern DummyReg UCSR0A; extern DummyReg UCSR0B; @@ -68,11 +54,7 @@ static const int COM2A1 = 0; static const int COM2B0 = 0; static const int COM2B1 = 0; -static const int CS01 = 0; -static const int CS10 = 0; -static const int CS11 = 0; -static const int CS12 = 0; -static const int CS22 = 0; + static const int CS22 = 0; static const int EEMWE = 0; static const int EERE = 0; static const int EEWE = 0; diff --git a/smoother/delay.h b/smoother/delay.h index 902f1b4..c08d216 100644 --- a/smoother/delay.h +++ b/smoother/delay.h @@ -24,15 +24,25 @@ void delay_init(); +// Get current time in clock cycles +inline uint32_t get_time() +{ + return LPC_TIM3->TC; +} + +// Wait until get_time() is numCycles past startTime. Handles timer wrap. +inline void delay_loop(uint32_t startTime, uint32_t numCycles) +{ + while (get_time() - startTime < numCycles) + ; +} + inline void delay_us(uint32_t us) { - uint32_t start = LPC_TIM3->TC; - uint32_t cycles = uint32_t(uint64_t(SystemCoreClock) * us / 1000000); - while (LPC_TIM3->TC - start < cycles) - ; + delay_loop(get_time(), uint32_t(uint64_t(SystemCoreClock) * us / 1'000'000)); } inline void delay_ms(uint32_t ms) { - return delay_us(ms * 1000); + delay_loop(get_time(), uint32_t(uint64_t(SystemCoreClock) * ms / 1000)); }