Skip to content

Commit

Permalink
Pipeline sdcard reads
Browse files Browse the repository at this point in the history
Sdcard reads are very inefficient, although we fill the command buffer, we
only read a single move command at a time. When printing with high detail
this is often not fast enough to keep the move command ring full, which
results in planner badness in addition to slowing down the print. So, if we
encounter a stream of move commands, pipeline those reads into the planner.
Additionally, if we still haven't filled the buffer blocks, read more from
the sdcard, and continue doing so until we do. This effectively prioritizes
reading of sdcard data during prints over everything else, except interrupts
of course. If a very long area of high detail is encountered, we can be in
that loop for a long time, since st_interrupt basically 100% cpu and is
draining the block buffer continuously. Therefore we break out after we've
done a bunch of work so that the menu and other slices are still responsive.
  • Loading branch information
dbavatar committed Aug 2, 2016
1 parent f32c70a commit 9b746ba
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 13 deletions.
56 changes: 48 additions & 8 deletions firmware/src/MightyBoard/Motherboard/Command.cc
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@
#include "Pin.hh"
#include <util/delay.h>
#include "Piezo.hh"
#include <avr/wdt.h>
#include <avr/cpufunc.h>

#ifdef HAS_RGB_LED
#include "RGB_LED.hh"
Expand All @@ -49,7 +51,6 @@
namespace command {

static bool sdCardError;

#if defined(PSTOP_SUPPORT)
// When non-zero, a P-Stop has been requested
bool pstop_triggered = 0;
Expand Down Expand Up @@ -1414,17 +1415,59 @@ void runCommandSlice() {
}

if ( mode == READY ) {
if ( st_empty() )
//For movement commands attempt to fill the pipeline as long as the next command is a move
//Technically, this algorithm reduces the need for command_buffer while using SD, in case
//memory is needed later.
//Primary mode is to keep the pipeline full, secondary mode is refill the entire pipeline if
//The steppers have already stopped moving, this allows a movement plan to be computed once.

uint8_t count = 0;
uint8_t command = command_buffer[0];

if ( st_empty() ) {
if ((command == HOST_CMD_QUEUE_POINT_EXT || command == HOST_CMD_QUEUE_POINT_NEW ||
command == HOST_CMD_QUEUE_POINT_NEW_EXT) ) {
pipeline_ready = false;
_MemoryBarrier();
}

disable_slowdown = true;
}

while ( command_buffer.getLength() > 0 && movesplanned() < (BLOCK_BUFFER_SIZE - 2) &&
(command == HOST_CMD_QUEUE_POINT_EXT || command == HOST_CMD_QUEUE_POINT_NEW ||
command == HOST_CMD_QUEUE_POINT_NEW_EXT)) {

//If we get a very detailed spot, allow for up to BLOCK_BUFFER_SIZE*2 commands before leaving.
//Otherwise, st_interrupt could be consuming blocks forever leaving us unresponsive to input.
if ( ++count == BLOCK_BUFFER_SIZE*2 ) {
Motherboard::getBoard().resetUserInputTimeout();
return;
}

handleMovementCommand(command);

while ( command_buffer.getRemainingCapacity() > 0 && sdcard::isPlaying() && sdcard::playbackHasNext())
command_buffer.push(sdcard::playbackNext());

command = command_buffer[0];

//Since we might stay here for a while, make sure the watchdog doesn't fire.
wdt_reset();
}

if ( !pipeline_ready ) {
planner_recalculate();
_MemoryBarrier();
pipeline_ready = true;
}

//
// process next command on the queue.
//
if ((command_buffer.getLength() > 0)){
Motherboard::getBoard().resetUserInputTimeout();

uint8_t command = command_buffer[0];

//If we're running acceleration, we want to populate the pipeline buffer,
//but we also need to sync (wait for the pipeline buffer to clear) on certain
//commands, we do that here
Expand All @@ -1446,10 +1489,7 @@ void runCommandSlice() {
if ( ! st_empty() ) return;
}

if (command == HOST_CMD_QUEUE_POINT_EXT || command == HOST_CMD_QUEUE_POINT_NEW ||
command == HOST_CMD_QUEUE_POINT_NEW_EXT ) {
handleMovementCommand(command);
} else if (command == HOST_CMD_CHANGE_TOOL) {
if (command == HOST_CMD_CHANGE_TOOL) {
if (command_buffer.getLength() >= 2) {
pop8(); // remove the command code
#if EXTRUDERS > 1
Expand Down
4 changes: 2 additions & 2 deletions firmware/src/MightyBoard/Motherboard/StepperAccel.cc
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@
#include "StepperAxis.hh"
#include "Steppers.hh"


block_t *current_block; // A pointer to the block currently being traced
bool extruder_deprime_travel; // When false, only deprime on pauses
bool extrude_when_negative[EXTRUDERS]; // True if negative values cause an extruder to extrude material
Expand Down Expand Up @@ -470,7 +469,8 @@ bool st_interrupt() {
// If there is no current block, attempt to pop one from the buffer
if (current_block == NULL) {
// Anything in the buffer?
current_block = plan_get_current_block();
if (pipeline_ready)
current_block = plan_get_current_block();

if (current_block != NULL) {
setup_next_block();
Expand Down
2 changes: 1 addition & 1 deletion firmware/src/MightyBoard/Motherboard/StepperAccel.hh
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ void st_extruder_interrupt();

void quickStop();


extern volatile bool pipeline_ready;
extern block_t *current_block; // A pointer to the block currently being traced
extern bool extruder_deprime_travel;
extern int16_t extruder_deprime_steps[EXTRUDERS];
Expand Down
5 changes: 3 additions & 2 deletions firmware/src/MightyBoard/Motherboard/StepperAccelPlanner.cc
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@
#define VLT(v1,v2) (((v1) + VEPSILON) < (v2))
#endif


volatile bool pipeline_ready = true;
uint32_t max_acceleration_units_per_sq_second[STEPPER_COUNT]; // Use M201 to override by software
FPTYPE smallest_max_speed_change;
FPTYPE max_speed_change[STEPPER_COUNT]; //The speed between junctions in the planner, reduces blobbing
Expand Down Expand Up @@ -1642,7 +1642,8 @@ void plan_buffer_line(FPTYPE feed_rate, const uint32_t &dda_rate, const uint8_t
// #endif
//#endif

planner_recalculate();
if (pipeline_ready)
planner_recalculate();

#ifdef SIMULATOR
sblock = NULL;
Expand Down
2 changes: 2 additions & 0 deletions firmware/src/MightyBoard/Motherboard/StepperAccelPlanner.hh
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,8 @@ void plan_init(FPTYPE extruderAdvanceK, FPTYPE extruderAdvanceK2, bool zhold);
// Add a new linear movement to the buffer.
void plan_buffer_line(FPTYPE feed_rate, const uint32_t &dda_rate, const uint8_t &extruder, bool use_accel, uint8_t active_toolhead);

void planner_recalculate();

// Set position. Used for G92 instructions.
#if EXTRUDERS > 1
void plan_set_position(const int32_t &x, const int32_t &y, const int32_t &z,
Expand Down

3 comments on commit 9b746ba

@caall99
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am enjoying tracking your changes. Is there anyway you could share a .hex for the most recent replicator 1 with atmega2560 firmware version that includes your changes? I cannot figure out how to build the firmware... Thanks!

@dbavatar
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this is ready for non-dev consumption yet. I have a good idea of how much more work needs to be done in the planner so that I can be confident that it actually works right for anyone, it's just a matter of getting around to it. Before that it will be hard to tell if a trajectory planning bug already existed or I inserted a new one.

@caall99
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One last concurrence: The hammering problem has been evident in EVERY Sailfish-loaded printer I have worked with. The issue is present in stable release v7.7 r1432.

Please sign in to comment.