changed atomic access for updating the acceleration profile

the stepper interrupt is only halted when necessary and for the shortest
time possible (8% cycle time)
This commit is contained in:
Jens Geisler 2013-02-22 16:36:27 +01:00
parent 67608a5014
commit ea09ddba99
5 changed files with 47 additions and 24 deletions

View File

@ -42,7 +42,7 @@ FUSES = -U hfuse:w:0xd2:m -U lfuse:w:0xff:m
# Tune the lines below only if you know what you are doing: # Tune the lines below only if you know what you are doing:
AVRDUDE = avrdude $(PROGRAMMER) -p $(DEVICE) -B 10 -F AVRDUDE = avrdude $(PROGRAMMER) -p $(DEVICE) -B 10 -F
COMPILE = avr-gcc -Wall -Os -DF_CPU=$(CLOCK) -mmcu=$(DEVICE) -I. -ffunction-sections COMPILE = avr-gcc -Wall -Os -DF_CPU=$(CLOCK) -mmcu=$(DEVICE) -I. -ffunction-sections --std=c99
# symbolic targets: # symbolic targets:
all: grbl.hex all: grbl.hex

View File

@ -23,6 +23,7 @@
/* The ring buffer implementation gleaned from the wiring_serial library by David A. Mellis. */ /* The ring buffer implementation gleaned from the wiring_serial library by David A. Mellis. */
#include <avr/interrupt.h> #include <avr/interrupt.h>
#include <util/atomic.h>
#include <inttypes.h> #include <inttypes.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
@ -34,8 +35,6 @@
#include "protocol.h" #include "protocol.h"
#include "motion_control.h" #include "motion_control.h"
uint32_t planner_steps_counter;
#define SOME_LARGE_VALUE 1.0E+38 // Used by rapids and acceleration maximization calculations. Just needs #define SOME_LARGE_VALUE 1.0E+38 // Used by rapids and acceleration maximization calculations. Just needs
// to be larger than any feasible (mm/min)^2 or mm/sec^2 value. // to be larger than any feasible (mm/min)^2 or mm/sec^2 value.
@ -103,7 +102,8 @@ static uint8_t prev_block_index(uint8_t block_index)
static uint8_t calculate_trapezoid_for_block(block_t *block, uint8_t idx, float entry_speed_sqr, float exit_speed_sqr) static uint8_t calculate_trapezoid_for_block(block_t *block, uint8_t idx, float entry_speed_sqr, float exit_speed_sqr)
{ {
// Compute new initial rate for stepper algorithm // Compute new initial rate for stepper algorithm
uint32_t initial_rate = ceil(sqrt(entry_speed_sqr)*(RANADE_MULTIPLIER/(60*ISR_TICKS_PER_SECOND))); // (mult*mm/isr_tic) // volatile is necessary so that the optimizer doesn't move the calculation in the ATOMIC_BLOCK
volatile uint32_t initial_rate = ceil(sqrt(entry_speed_sqr)*(RANADE_MULTIPLIER/(60*ISR_TICKS_PER_SECOND))); // (mult*mm/isr_tic)
// TODO: Compute new nominal rate if a feedrate override occurs. // TODO: Compute new nominal rate if a feedrate override occurs.
// block->nominal_rate = ceil(feed_rate*(RANADE_MULTIPLIER/(60.0*ISR_TICKS_PER_SECOND))); // (mult*mm/isr_tic) // block->nominal_rate = ceil(feed_rate*(RANADE_MULTIPLIER/(60.0*ISR_TICKS_PER_SECOND))); // (mult*mm/isr_tic)
@ -132,23 +132,50 @@ static uint8_t calculate_trapezoid_for_block(block_t *block, uint8_t idx, float
if (decelerate_after > block->step_event_count) { decelerate_after = block->step_event_count; } if (decelerate_after > block->step_event_count) { decelerate_after = block->step_event_count; }
} }
// safe block adjustment uint8_t block_buffer_tail_hold= block_buffer_tail; // store to avoid rereading volatile
cli(); // check if we got overtaken by the stepper
uint8_t block_buffer_tail_hold= block_buffer_tail; // store to avoid reading volatile twice if(idx==prev_block_index(block_buffer_tail_hold)) {
uint8_t block_buffer_head_hold= block_buffer_head; // store to avoid reading volatile twice return false;
uint8_t idx_inside_queue; }
// is the current block inside the queue? if not: the stepper overtook us
if(block_buffer_head_hold>=block_buffer_tail_hold) idx_inside_queue= idx>=block_buffer_tail_hold && idx<=block_buffer_head_hold; // check where the stepper is currently working relative to the block we want to update
else idx_inside_queue= idx<=block_buffer_head_hold || idx>=block_buffer_tail_hold; uint8_t block_buffer_tail_next= next_block_index(block_buffer_tail_hold);
if(idx_inside_queue && (idx!=block_buffer_tail_hold || idx==block_buffer_head_hold || !st_is_decelerating())) { if(idx==block_buffer_tail_hold || idx==block_buffer_tail_next) {
// we are close to were the stepper is working, so we need to block it for a short time
// to safely adjust the block
// I counted the cycles in this block from the assembler code
// It's 42 cycles worst case including the call to st_is_decelerating
// @ 16MHz this is 2.6250e-06 seconds, 30kHz cycle duration is 3.3333e-05 seconds
// -> this block will delay the stepper timer by max 8%
// given that this occurs not very often, it should be ok
// but test will have to show
// ATOMIC_BLOCK only works with compiler parameter --std=c99
ATOMIC_BLOCK(ATOMIC_FORCEON) {
// reload block_buffer_tail in case it changed
uint8_t block_buffer_tail_hold2= block_buffer_tail;
if(idx!=block_buffer_tail_hold2) {
if(block_buffer_tail_hold2==block_buffer_tail_next)
return false; // the stepper didn't overtook in the meantime
} else {
if(st_is_decelerating())
return false; // we want to change the currently running block and it has already started to decelerate
}
block->decelerate_after= decelerate_after;
block->initial_rate= initial_rate;
return true;
}
} else {
// let's assume the stepper did not complete two blocks since we loaded block_buffer_tail to block_buffer_tail_hold
// so the block we want to change is not currently being run by the stepper and it's safe to touch it without precautions
block->decelerate_after= decelerate_after; block->decelerate_after= decelerate_after;
block->initial_rate= initial_rate; block->initial_rate= initial_rate;
sei(); return true;
return(true);
} else {
sei();
return(false); // this block is currently being processed by the stepper and it already finished accelerating or the stepper is already finished with this block: we can no longer change anything here
} }
return false;
} }
@ -212,7 +239,6 @@ static uint8_t planner_recalculate()
block_t *curr_block = &block_buffer[current_block_idx]; block_t *curr_block = &block_buffer[current_block_idx];
uint8_t plan_unchanged= 1; uint8_t plan_unchanged= 1;
planner_steps_counter= 0;
if(current_block_idx!=block_buffer_tail) { // we cannot do anything to only one block if(current_block_idx!=block_buffer_tail) { // we cannot do anything to only one block
float max_entry_speed_sqr; float max_entry_speed_sqr;
float next_entry_speed_sqr= 0.0; float next_entry_speed_sqr= 0.0;
@ -222,7 +248,6 @@ static uint8_t planner_recalculate()
planned_block_tail= current_block_idx; planned_block_tail= current_block_idx;
break; break;
} }
planner_steps_counter++;
// TODO: Determine maximum entry speed at junction for feedrate overrides, since they can alter // TODO: Determine maximum entry speed at junction for feedrate overrides, since they can alter
// the planner nominal speeds at any time. This calc could be done in the override handler, but // the planner nominal speeds at any time. This calc could be done in the override handler, but

View File

@ -22,8 +22,6 @@
#ifndef planner_h #ifndef planner_h
#define planner_h #define planner_h
extern uint32_t planner_steps_counter;
// The number of linear motions that can be in the plan at any give time // The number of linear motions that can be in the plan at any give time
#ifndef BLOCK_BUFFER_SIZE #ifndef BLOCK_BUFFER_SIZE
#define BLOCK_BUFFER_SIZE 18 #define BLOCK_BUFFER_SIZE 18

View File

@ -157,8 +157,7 @@ void printBlock() {
else block_position[2]+= b->steps_z; else block_position[2]+= b->steps_z;
fprintf(block_out_file,"%d, ", block_position[2]); fprintf(block_out_file,"%d, ", block_position[2]);
fprintf(block_out_file,"%f, ", b->entry_speed_sqr); fprintf(block_out_file,"%f", b->entry_speed_sqr);
fprintf(block_out_file,"%d", planner_steps_counter);
fprintf(block_out_file,"\n"); fprintf(block_out_file,"\n");
last_block= b; last_block= b;

View File

@ -45,6 +45,7 @@ void st_cycle_reinitialize();
// Initiates a feed hold of the running program // Initiates a feed hold of the running program
void st_feed_hold(); void st_feed_hold();
// Accessor function to query the acceleration state of the stepper
uint8_t st_is_decelerating(); uint8_t st_is_decelerating();
#endif #endif