void enqueue_home(TARGET *t, uint8_t endstop_check, uint8_t endstop_stop_cond) { // don't call this function when the queue is full, but just in case, wait for a move to complete and free up the space for the passed target while (queue_full()) delay(WAITING_DELAY); uint8_t h = mb_head + 1; h &= (MOVEBUFFER_SIZE - 1); DDA* new_movebuffer = &(movebuffer[h]); if (t != NULL) { dda_create(new_movebuffer, t); new_movebuffer->endstop_check = endstop_check; new_movebuffer->endstop_stop_cond = endstop_stop_cond; } else { // it's a wait for temp new_movebuffer->waitfor_temp = 1; new_movebuffer->nullmove = 0; } // make certain all writes to global memory // are flushed before modifying mb_head. MEMORY_BARRIER(); mb_head = h; uint8_t save_reg = SREG; cli(); CLI_SEI_BUG_MEMORY_BARRIER(); uint8_t isdead = (movebuffer[mb_tail].live == 0); MEMORY_BARRIER(); SREG = save_reg; if (isdead) { timer1_compa_deferred_enable = 0; next_move(); if (timer1_compa_deferred_enable) { uint8_t save_reg = SREG; cli(); CLI_SEI_BUG_MEMORY_BARRIER(); TIMSK1 |= MASK(OCIE1A); MEMORY_BARRIER(); SREG = save_reg; } } }
uint8_t queue_empty(){ uint8_t save_reg = SREG; cli(); CLI_SEI_BUG_MEMORY_BARRIER(); uint8_t result = ((mb_tail == mb_head) && (movebuffer[mb_tail].live = 0))?255:0; MEMORY_BARRIER(); SREG = save_reg; return result; }
/// dump queue for emergency stop. /// \todo effect on startpoint is undefined! void queue_flush() { // Since the timer interrupt is disabled before this function // is called it is not strictly necessary to write the variables // inside an interrupt disabled block... uint8_t save_reg = SREG; cli(); CLI_SEI_BUG_MEMORY_BARRIER(); // flush queue mb_tail = mb_head; movebuffer[mb_head].live = 0; // disable timer setTimer(0); MEMORY_BARRIER(); SREG = save_reg; }
/*! do stuff every 1/4 second called from clock_10ms(), do not call directly */ void clock_250ms() { #ifndef NO_AUTO_IDLE if (temp_all_zero()) { if (steptimeout > (30 * 4)) { power_off(); } else { uint8_t save_reg = SREG; cli(); CLI_SEI_BUG_MEMORY_BARRIER(); steptimeout++; MEMORY_BARRIER(); SREG = save_reg; } } #endif ifclock(clock_flag_1s) { if (DEBUG_POSITION && (debug_flags & DEBUG_POSITION)) { // current position sersendf_P(PSTR("Pos: %ld,%ld,%ld,%ld,%lu\n"), current_position.X, current_position.Y, current_position.Z, current_position.E, current_position.F); // target position sersendf_P(PSTR("Dst: %ld,%ld,%ld,%ld,%lu\n"), movebuffer[mb_tail].endpoint.X, movebuffer[mb_tail].endpoint.Y, movebuffer[mb_tail].endpoint.Z, movebuffer[mb_tail].endpoint.E, movebuffer[mb_tail].endpoint.F); // Queue print_queue(); // newline serial_writechar('\n'); } // temperature /* if (temp_get_target()) temp_print();*/ } #ifdef TEMP_INTERCOM start_send(); #endif }
void clock_250ms() { debug_led_step(); if (steptimeout > (30 * 4)) { power_off(); } else if (heaters_all_off()) { uint8_t save_reg = SREG; cli(); CLI_SEI_BUG_MEMORY_BARRIER(); steptimeout++; MEMORY_BARRIER(); SREG = save_reg; } #ifdef TEMP_INTERCOM start_send(); #endif ifclock(clock_flag_1s) { if (DEBUG_POSITION && (debug_flags & DEBUG_CLOCK)) sersendf_P(PSTR("1s")); if (DEBUG_POSITION && (debug_flags & DEBUG_POSITION)) { // current position sersendf_P(PSTR("Pos: %ld,%ld,%ld,%ld,%lu\n"), current_position.X, current_position.Y, current_position.Z, current_position.E, current_position.F); // target position sersendf_P(PSTR("Dst: %ld,%ld,%ld,%ld,%lu\n"), movebuffer[mb_tail].endpoint.X, movebuffer[mb_tail].endpoint.Y, movebuffer[mb_tail].endpoint.Z, movebuffer[mb_tail].endpoint.E, movebuffer[mb_tail].endpoint.F); // Queue print_queue(); // newline serial_writechar('\n'); } check_temp_achieved(); if (DEBUG_POSITION && (debug_flags & DEBUG_CLOCK)) sersendf_P(PSTR("t")); ++seconds_counter; if (++idle_seconds>60) working_seconds=0; else ++working_seconds; #ifdef OK_WHEN_IDLE if (idle_seconds>OK_WHEN_IDLE && seconds_counter-last_ok_time>OK_WHEN_IDLE) { sersendf_P(PSTR("ok (idle)\n")); last_ok_time=seconds_counter; } #endif if (DEBUG_POSITION && (debug_flags & DEBUG_CLOCK)) sersendf_P(PSTR("r\n")); #if defined ALWAYS_CHECK_Z_MIN && defined Z_MIN_PIN if (z_min_pushed_flag) { sersendf_P(PSTR("ALERT!! PUSHING UNDERGROUND!!\n")); z_min_pushed_flag=0; } #endif } }
/*! Specify how long until the step timer should fire. \param delay in CPU ticks This enables the step interrupt, but also disables interrupts globally. So, if you use it from inside the step interrupt, make sure to do so as late as possible. If you use it from outside the step interrupt, do a sei() after it to make the interrupt actually fire. */ void setTimer(uint32_t delay) { uint16_t step_start = 0; #ifdef ACCELERATION_TEMPORAL uint16_t current_time; uint32_t earliest_time, actual_time; #endif /* ACCELERATION_TEMPORAL */ // re-enable clock interrupt in case we're recovering from emergency stop TIMSK1 |= MASK(OCIE1B); // An interrupt would make all our timing calculations invalid, // so stop that here. cli(); CLI_SEI_BUG_MEMORY_BARRIER(); // Assume all steps belong to one move. Within one move the delay is // from one step to the next one, which should be more or less the same // as from one step interrupt to the next one. The last step interrupt happend // at OCR1A, so start delay from there. step_start = OCR1A; if (next_step_time == 0) { // new move, take current time as start value step_start = TCNT1; } next_step_time = delay; #ifdef ACCELERATION_TEMPORAL // 300 = safe number of cpu cycles until the interrupt actually happens current_time = TCNT1; earliest_time = (uint32_t)current_time + 300; if (current_time < step_start) // timer counter did overflow recently earliest_time += 0x00010000; actual_time = (uint32_t)step_start + next_step_time; // Setting the interrupt earlier than it can happen obviously doesn't // make sense. To keep the "belongs to one move" idea, add an extra, // remember this extra and compensate the extra if a longer delay comes in. if (earliest_time > actual_time) { step_extra_time += (earliest_time - actual_time); next_step_time = earliest_time - (uint32_t)step_start; } else if (step_extra_time) { if (step_extra_time < actual_time - earliest_time) { next_step_time -= step_extra_time; step_extra_time = 0; } else { step_extra_time -= (actual_time - earliest_time); next_step_time -= (actual_time - earliest_time); } } #endif /* ACCELERATION_TEMPORAL */ // Now we know how long we actually want to delay, so set the timer. if (next_step_time < 65536) { // set the comparator directly to the next real step OCR1A = (next_step_time + step_start) & 0xFFFF; } else if (next_step_time < 75536) { // Next comparator interrupt would have to trigger another // interrupt within a short time (possibly within 1 cycle). // Avoid the impossible by firing the interrupt earlier. OCR1A = (step_start - 10000) & 0xFFFF; next_step_time += 10000; } else { OCR1A = step_start; } // Enable this interrupt, but only do it after disabling // global interrupts (see above). This will cause push any possible // timer1a interrupt to the far side of the return, protecting the // stack from recursively clobbering memory. TIMSK1 |= MASK(OCIE1A); }
/// specify how long until the step timer should fire void setTimer(uint32_t delay) { // save interrupt flag uint8_t sreg = SREG; uint16_t step_start = 0; // disable interrupts cli(); CLI_SEI_BUG_MEMORY_BARRIER(); // re-enable clock interrupt in case we're recovering from emergency stop TIMSK1 |= MASK(OCIE1B); if (delay > 0) { // if the delay is too small use a minimum delay so that there is time // to set everything up before the timer expires. if (delay < 17 ) delay = 17; // Assume all steps belong to one move. Within one move the delay is // from one step to the next one, which should be more or less the same // as from one step interrupt to the next one. The last step interrupt happend // at OCR1A, so start delay from there. step_start = OCR1A; if (next_step_time == 0) { // new move, take current time as start value step_start = TCNT1; } next_step_time = delay; if (next_step_time < 65536) { // set the comparator directly to the next real step OCR1A = (next_step_time + step_start) & 0xFFFF; } else if (next_step_time < 75536) { // Next comparator interrupt would have to trigger another // interrupt within a short time (possibly within 1 cycle). // Avoid the impossible by firing the interrupt earlier. OCR1A = (step_start - 10000) & 0xFFFF; next_step_time += 10000; } else { OCR1A = step_start; } // Defer the enabling of the timer1_CompA interrupts. timer1_compa_deferred_enable = 1; } else { // flag: move has ended next_step_time = 0; TIMSK1 &= ~MASK(OCIE1A); timer1_compa_deferred_enable = 0; } // restore interrupt flag MEMORY_BARRIER(); SREG = sreg; }