Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Expo] Direct stepper chunk support #7012

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Marlin/Marlin.h
Original file line number Diff line number Diff line change
Expand Up @@ -417,6 +417,8 @@ extern uint8_t active_extruder;

void calculate_volumetric_multipliers();

void send_chunk_ok();

/**
* Blocking movement and shorthand functions
*/
Expand Down
97 changes: 85 additions & 12 deletions Marlin/MarlinSerial.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,17 @@

// Disable HardwareSerial.cpp to support chips without a UART (Attiny, etc.)

unsigned char chunk_buffer[NUM_CHUNK_BUFFERS][CHUNK_BUFFER_SIZE] = { { 0 } };
uint8_t chunk_buffer_idx = 0;
uint8_t chunk_response[NUM_CHUNK_BUFFERS] = { CHUNK_RESPONSE_NONE };
volatile uint8_t chunk_respond_busy = 0;
volatile uint32_t check_sum_failures = 0;
volatile uint32_t chunks_done = 0;

uint8_t chunk_stage = CHUNK_STAGE_WAIT;
uint8_t chunk_buffer_iter = 0;
unsigned char chunk_checksum = 0;

#if !defined(USBCON) && (defined(UBRRH) || defined(UBRR0H) || defined(UBRR1H) || defined(UBRR2H) || defined(UBRR3H))

#if UART_PRESENT(SERIAL_PORT)
Expand Down Expand Up @@ -136,18 +147,79 @@

#endif // EMERGENCY_PARSER

//CHUNK RESPONSE

FORCE_INLINE void store_char(unsigned char c) {
CRITICAL_SECTION_START;
const uint8_t h = rx_buffer.head,
i = (uint8_t)(h + 1) & (RX_BUFFER_SIZE - 1);

// if we should be storing the received character into the location
// just before the tail (meaning that the head would advance to the
// current location of the tail), we're about to overflow the buffer
// and so we don't write the character or advance the head.
if (i != rx_buffer.tail) {
rx_buffer.buffer[h] = c;
rx_buffer.head = i;
switch(chunk_stage) {
case CHUNK_STAGE_COLLECT:
chunk_buffer[chunk_buffer_idx][chunk_buffer_iter++] = c;
chunk_checksum ^= c;

//has not rolled back to 0, buffer still filling
if(chunk_buffer_iter)
break;

chunk_stage = CHUNK_STAGE_CHECKSUM;

break;
case CHUNK_STAGE_CHECKSUM:
chunk_stage = CHUNK_STAGE_WAIT;
chunks_done++;

chunk_response[chunk_buffer_idx] = CHUNK_RESPONSE_OK;

if(chunk_checksum == c)
break;

chunk_response[chunk_buffer_idx] = CHUNK_RESPONSE_FAIL;

check_sum_failures++;

break;
case CHUNK_STAGE_DRAIN:
chunk_buffer_iter++;

//has not rolled back to 0, buffer still filling
if(chunk_buffer_iter)
break;

chunk_stage = CHUNK_STAGE_DRAIN_POST;

break;
case CHUNK_STAGE_DRAIN_POST:
chunk_stage = CHUNK_STAGE_WAIT;
chunk_respond_busy++;

break;
case CHUNK_STAGE_WAIT:
default:
if(c == CHUNK_START_CHAR) {
uint8_t oldIndex = chunk_buffer_idx;

chunk_stage = CHUNK_STAGE_COLLECT;
chunk_buffer_iter = 0;
chunk_checksum = 0;
chunk_buffer_idx = (uint8_t)(chunk_buffer_idx + 1) % (NUM_CHUNK_BUFFERS - 1);

//if chunk is still busy, drain data and respond with a busy response
if(chunk_response[chunk_buffer_idx] != CHUNK_RESPONSE_NONE) {
chunk_buffer_idx = oldIndex;
chunk_stage = CHUNK_STAGE_DRAIN;
}
} else {
const uint8_t h = rx_buffer.head,
i = (uint8_t)(h + 1) & (RX_BUFFER_SIZE - 1);

// if we should be storing the received character into the location
// just before the tail (meaning that the head would advance to the
// current location of the tail), we're about to overflow the buffer
// and so we don't write the character or advance the head.
if (i != rx_buffer.tail) {
rx_buffer.buffer[h] = c;
rx_buffer.head = i;
}
}
}
CRITICAL_SECTION_END;

Expand Down Expand Up @@ -355,9 +427,10 @@
}

#else

void MarlinSerial::write(uint8_t c) {
while (!TEST(M_UCSRxA, M_UDREx))
;
while (!TEST(M_UCSRxA, M_UDREx));

M_UDRx = c;
}
#endif
Expand Down
22 changes: 22 additions & 0 deletions Marlin/MarlinSerial.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,21 @@
#define SERIAL_PORT 0
#endif

#define CHUNK_BUFFER_SIZE 256
#define NUM_CHUNK_BUFFERS 16
#define CHUNK_START_CHAR '!'

#define CHUNK_STAGE_COLLECT 0
#define CHUNK_STAGE_CHECKSUM 1
#define CHUNK_STAGE_DRAIN 2
#define CHUNK_STAGE_DRAIN_POST 3
#define CHUNK_STAGE_WAIT 4

#define CHUNK_RESPONSE_NONE 0
#define CHUNK_RESPONSE_PENDING 1
#define CHUNK_RESPONSE_OK 2
#define CHUNK_RESPONSE_FAIL 3

// The presence of the UBRRH register is used to detect a UART.
#define UART_PRESENT(port) ((port == 0 && (defined(UBRRH) || defined(UBRR0H))) || \
(port == 1 && defined(UBRR1H)) || (port == 2 && defined(UBRR2H)) || \
Expand Down Expand Up @@ -75,6 +90,13 @@
#define BIN 2
#define BYTE 0

extern unsigned char chunk_buffer[NUM_CHUNK_BUFFERS][CHUNK_BUFFER_SIZE];
extern uint8_t chunk_buffer_idx;
extern uint8_t chunk_response[NUM_CHUNK_BUFFERS];
extern volatile uint8_t chunk_respond_busy;
extern volatile uint32_t check_sum_failures;
extern volatile uint32_t chunks_done;

#ifndef USBCON
// Define constants and variables for buffering incoming serial data. We're
// using a ring buffer (I think), in which rx_buffer_head is the index of the
Expand Down
40 changes: 38 additions & 2 deletions Marlin/Marlin_main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@
*
* -----------------
*
* "C" Codes
*
* C0 - Execute buffered step chunk(s)
*
* "G" Codes
*
* G0 -> G1
Expand Down Expand Up @@ -3259,6 +3263,27 @@ bool position_is_reachable(const float target[XYZ]
***************** GCode Handlers *****************
**************************************************/

inline void gcode_C0() {
static uint32_t step_speed = 0;

uint8_t chunk_idx = 0;
uint8_t chunk_num = 1;

if (code_seen('S'))
step_speed = code_value_linear_units();

if (code_seen('I'))
chunk_idx = code_value_linear_units();
else
return;

if (code_seen('R'))
chunk_num = code_value_linear_units();

if(step_speed)
Planner::buffer_chunk(chunk_idx, chunk_num, active_extruder, step_speed);
}

/**
* G0, G1: Coordinated movement of X Y Z E axes
*/
Expand Down Expand Up @@ -5578,7 +5603,7 @@ inline void gcode_G92() {
else if (didE)
sync_plan_position_e();

report_current_position();
//report_current_position();
}

#if HAS_RESUME_CONTINUE
Expand Down Expand Up @@ -9803,8 +9828,14 @@ void process_next_command() {

KEEPALIVE_STATE(IN_HANDLER);

// Handle a known G, M, or T
// Handle a known C, G, M, or T
switch (command_code) {
case 'C': switch (codenum) {
case 0:
gcode_C0();
break;
}
break;
case 'G': switch (codenum) {

// G0, G1
Expand Down Expand Up @@ -12058,6 +12089,8 @@ void idle(
bool no_stepper_sleep/*=false*/
#endif
) {
send_chunk_ok();

lcd_update();

host_keepalive();
Expand Down Expand Up @@ -12320,6 +12353,9 @@ void setup() {
#if ENABLED(ENDSTOP_INTERRUPTS_FEATURE)
setup_endstop_interrupts();
#endif

SERIAL_PROTOCOLPGM("setup_done");
SERIAL_EOL;
}

/**
Expand Down
68 changes: 68 additions & 0 deletions Marlin/chunk_support.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
#include "Arduino.h"
#include "Macros.h"
#include "Configuration.h"
#include "serial.h"
#include "temperature.h"

#define BLINK_LED LED_BUILTIN

//wave tables, 4 bit move, +/- 7
uint8_t block_moves[16][8] = {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

wave tables for each step frequency, done by hand. this is my third version for this encoding, it seems to be the least annoying noise wise.

{ 1, 1, 1, 1, 1, 1, 1, 0 },//14 = 7
{ 1, 1, 1, 0, 1, 1, 1, 0 },//13 = 6
{ 0, 1, 1, 0, 1, 0, 1, 1 },//12 = 5
{ 0, 1, 0, 1, 0, 1, 0, 1 },//11 = 4
{ 0, 1, 0, 0, 1, 0, 0, 1 },//10 = 3
{ 0, 0, 1, 0, 0, 0, 1, 0 },//9 = 2
{ 0, 0, 0, 0, 1, 0, 0, 0 },//8 = 1

{ 0, 0, 0, 0, 0, 0, 0, 0 },//7 = 0

{ 0, 0, 0, 0, 1, 0, 0, 0 },//8 = 1
{ 0, 0, 1, 0, 0, 0, 1, 0 },//9 = 2
{ 0, 1, 0, 0, 1, 0, 0, 1 },//10 = 3
{ 0, 1, 0, 1, 0, 1, 0, 1 },//11 = 4
{ 0, 1, 1, 0, 1, 0, 1, 1 },//12 = 5
{ 1, 1, 1, 0, 1, 1, 1, 0 },//13 = 6
{ 1, 1, 1, 1, 1, 1, 1, 0 },//14 = 7
{ 0 }
};

void send_chunk_ok() {
static uint8_t chunk_respond_busy_done = 0;

//concurrently keep up with response counter, should auto roll over
while(chunk_respond_busy_done != chunk_respond_busy) {
SERIAL_PROTOCOLPGM("!busy");
SERIAL_EOL;
chunk_respond_busy_done++;
}

//TODO: this needs to somehow respect ordering. Should we start from the current index?
for(int n = 0 ; n < NUM_CHUNK_BUFFERS ; n++) {
const int i = (uint8_t)(chunk_buffer_idx + n) % (NUM_CHUNK_BUFFERS - 1);

switch(chunk_response[i]) {
case CHUNK_RESPONSE_NONE:
case CHUNK_RESPONSE_PENDING:
break;
case CHUNK_RESPONSE_OK:
SERIAL_PROTOCOLPGM("!ok ");
SERIAL_ECHO(i);
SERIAL_EOL;

chunk_response[i] = CHUNK_RESPONSE_PENDING;

break;
case CHUNK_RESPONSE_FAIL:
SERIAL_PROTOCOLPGM("!fail");
SERIAL_EOL;

chunk_response[i] = CHUNK_RESPONSE_NONE;

break;
}
}
}


2 changes: 2 additions & 0 deletions Marlin/language_es.h
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,8 @@
#define MSG_FILAMENT_CHANGE_RESUME_1 _UxGT("Esperando imp.")
#define MSG_FILAMENT_CHANGE_RESUME_2 _UxGT("para resumir")
#define MSG_FILAMENT_CHANGE_HEAT_1 _UxGT("Oprima boton para")
#define MSG_FILAMENT_CHANGE_HEAT_2 _UxGT("Calentar la boquilla")
#define MSG_FILAMENT_CHANGE_HEATING_1 _UxGT("Calentando boquilla")
#define MSG_FILAMENT_CHANGE_HEATING_2 _UxGT("Espere por favor")

#endif // LANGUAGE_ES_H
36 changes: 36 additions & 0 deletions Marlin/planner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -633,6 +633,42 @@ void Planner::check_axes_activity() {

#endif // PLANNER_LEVELING

void Planner::buffer_chunk(const uint8_t chunk_idx, const uint8_t chunk_num,
const uint8_t extruder, const uint32_t step_speed) {
// Calculate the buffer head after we push this byte
const uint8_t next_buffer_head = next_block_index(block_buffer_head);

// If the buffer is full: good! That means we are well ahead of the robot.
// Rest here until there is room in the buffer.
while (block_buffer_tail == next_buffer_head) idle();

// Prepare to set up new block
block_t* block = &block_buffer[block_buffer_head];

block->flag = BLOCK_FLAG_IS_CHUNK;

#if FAN_COUNT > 0
for (uint8_t i = 0; i < FAN_COUNT; i++) block->fan_speed[i] = fanSpeeds[i];
#endif

block->active_extruder = extruder;

block->initial_rate =
block->final_rate =
block->nominal_rate = step_speed; //steps/s
block->chunk_idx = chunk_idx;
//blocks per chunk * 8 steps per block
block->step_event_count = (256 / 2 * 8) * chunk_num;
block->accelerate_until = 0;
block->decelerate_after = block->step_event_count;

// Move buffer head
block_buffer_head = next_buffer_head;

enable_all_steppers();
stepper.wake_up();
}

/**
* Planner::_buffer_line
*
Expand Down
Loading