Buildbotics CNC Controller Firmware Changelog
==============================================
-## v0.3.29
+## v0.4.0
- Increased display precision of position and motor config.
- Added support for 256 microstepping.
- Smoother operation at 250k step rate by doubling clock as needed.
- Major improvements for LASER raster GCodes.
- Fixed major bug in command queuing.
- Ignore Program Number O-Codes.
- - Improved planning of colinear line segments.
+ - Improved planning of collinear line segments.
- Allow PWM output up to 320kHz and no slower than 8Hz.
## v0.3.28
{
"name": "bbctrl",
- "version": "0.3.29",
+ "version": "0.4.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
{
"name": "bbctrl",
- "version": "0.3.29",
+ "version": "0.4.0",
"homepage": "http://buildbotics.com/",
"repository": "https://github.com/buildbotics/bbctrl-firmware",
"license": "GPL-3.0+",
// Serial settings
-#define SERIAL_BAUD USART_BAUD_115200
+#define SERIAL_BAUD USART_BAUD_230400 // 115200
#define SERIAL_PORT USARTC0
#define SERIAL_DRE_vect USARTC0_DRE_vect
#define SERIAL_RXC_vect USARTC0_RXC_vect
#define SERIAL_CTS_THRESH 4
+// Spindle settings
+#define SPEED_QUEUE_SIZE 64
+#define SPEED_OFFSET 6 // ms
+
// Input
#define INPUT_BUFFER_LEN 128 // text buffer size (255 max)
if (l.speed.time < 0 || endT < l.speed.time) break;
// Queue speed
- spindle_queue_speed(round(l.speed.time - startT), l.speed.speed);
+ spindle_set_speed(round(l.speed.time - startT), l.speed.speed);
l.speed.time = -1; // Mark done
}
}
l.lineT += t;
} else {
- spindle_new_segment();
exec_set_cb(0);
// Last segment of last section
void command_sync_speed_exec(void *data) {
speed_t s = *(speed_t *)data;
- spindle_queue_speed(0, s.speed);
+ spindle_set_speed(0, s.speed);
}
#include "analog.h"
#include "exec.h"
#include "state.h"
-#include "spindle.h"
#include <avr/wdt.h>
vars_init(); // configuration variables
estop_init(); // emergency stop handler
command_init(); // command queue
- spindle_init(); // spindle
sei(); // enable interrupts
#include <math.h>
+typedef struct {
+ uint8_t time;
+ uint16_t period;
+ bool clockwise;
+} update_t;
+
+
+#define RING_BUF_NAME update_q
+#define RING_BUF_TYPE update_t
+#define RING_BUF_INDEX_TYPE volatile uint8_t
+#define RING_BUF_SIZE SPEED_QUEUE_SIZE
+#include "ringbuf.def"
+
+
typedef struct {
float freq; // base frequency for PWM driver, in Hz
float min_duty;
float max_duty;
float duty;
float speed;
+ uint8_t time;
} pwm_spindle_t;
}
-static void _update_pwm() {
- float speed = spindle.speed;
+static void _update_clock(uint16_t period) {
+ if (estop_triggered()) period = 0;
// Disable
- if (!speed || estop_triggered()) {
- spindle.duty = 0;
+ if (!period) {
TIMER_PWM.CTRLB = 0; // Disable clock control of pin
OUTCLR_PIN(SPIN_PWM_PIN);
_set_enable(false);
_set_enable(true);
// 100% duty
- if (speed == 1 && spindle.max_duty == 1) {
- spindle.duty = 1;
+ if (period == 0xffff) {
TIMER_PWM.CTRLB = 0; // Disable clock control of pin
OUTSET_PIN(SPIN_PWM_PIN);
return;
}
- // Compute duty cycle
- spindle.duty =
- speed * (spindle.max_duty - spindle.min_duty) + spindle.min_duty;
-
// Configure clock
TIMER_PWM.CTRLB = TC1_CCAEN_bm | TC_WGMODE_SINGLESLOPE_gc;
- TIMER_PWM.CCA = TIMER_PWM.PER * spindle.duty;
+ TIMER_PWM.CCA = period;
+}
+
+
+static float _compute_duty(float speed) {
+ if (!speed) return 0; // 0% duty
+ if (speed == 1 && spindle.max_duty == 1) return 1; // 100% duty
+ return speed * (spindle.max_duty - spindle.min_duty) + spindle.min_duty;
}
+static uint16_t _compute_period(float speed) {
+ spindle.speed = speed;
+ spindle.duty = _compute_duty(speed);
+
+ if (!spindle.duty) return 0;
+ if (spindle.duty == 1) return 0xffff;
+ return TIMER_PWM.PER * spindle.duty;
+}
+
+
+static void _update_pwm() {_update_clock(_compute_period(spindle.speed));}
+
+
static void _update_freq() {
// Set clock period and optimal prescaler value
float prescale = (F_CPU >> 16) / spindle.freq;
void pwm_spindle_init() {
+ update_q_init();
+
// Configure IO
_set_dir(true);
_set_enable(false);
}
-void pwm_spindle_set(float speed) {
- if (speed) _set_dir(0 < speed);
- spindle.speed = fabs(speed);
- _update_pwm();
+void pwm_spindle_set(uint8_t time, float speed) {
+ if (update_q_full()) update_q_init();
+
+ update_t d = {
+ (uint8_t)(spindle.time + time + SPEED_OFFSET),
+ _compute_period(fabsf(speed)),
+ 0 < speed
+ };
+
+ update_q_push(d);
}
float pwm_spindle_get() {return spindle.speed;}
+void pwm_spindle_update() {
+ bool set = false;
+ uint16_t period;
+ bool clockwise;
+
+ while (!update_q_empty()) {
+ update_t d = update_q_peek();
+ if (spindle.time != d.time) break;
+ update_q_pop();
+ set = true;
+ period = d.period;
+ clockwise = d.clockwise;
+ }
+
+ if (set) {
+ _update_clock(period);
+ if (period) _set_dir(clockwise);
+ }
+
+ spindle.time++;
+}
+
+
// Var callbacks
float get_pwm_min_duty() {return spindle.min_duty * 100;}
void pwm_spindle_init();
void pwm_spindle_deinit(deinit_cb_t cb);
-void pwm_spindle_set(float speed);
+void pwm_spindle_set(uint8_t time, float speed);
float pwm_spindle_get();
+void pwm_spindle_update();
#include <math.h>
-#define SPEED_QUEUE_SIZE 32
-
-typedef struct {
- int8_t time;
- float speed;
-} speed_t;
-
-
-#define RING_BUF_NAME speed_q
-#define RING_BUF_TYPE speed_t
-#define RING_BUF_INDEX_TYPE volatile uint8_t
-#define RING_BUF_SIZE SPEED_QUEUE_SIZE
-#include "ringbuf.def"
-
-
static struct {
spindle_type_t type;
float override;
float min_rpm;
float max_rpm;
- int8_t time;
spindle_type_t next_type;
} spindle = {
};
-void spindle_init() {
- speed_q_init();
- spindle_new_segment();
-}
-
-
spindle_type_t spindle_get_type() {return spindle.type;}
-void _set_speed(float speed) {
+void spindle_set_speed(uint8_t time, float speed) {
spindle.speed = speed;
speed *= spindle.override;
switch (spindle.type) {
case SPINDLE_TYPE_DISABLED: break;
- case SPINDLE_TYPE_PWM: pwm_spindle_set(speed); break;
+ case SPINDLE_TYPE_PWM: pwm_spindle_set(time, speed); break;
case SPINDLE_TYPE_HUANYANG: huanyang_set(speed); break;
default: vfd_spindle_set(speed); break;
}
}
-void spindle_stop() {_set_speed(0);}
+void spindle_stop() {spindle_set_speed(0, 0);}
bool spindle_is_reversed() {return spindle.reversed;}
void spindle_update() {
- while (!speed_q_empty()) {
- speed_t s = speed_q_peek();
- if (s.time == -1 || spindle.time < s.time) break;
- speed_q_pop();
- _set_speed(s.speed);
- }
-
- spindle.time++;
-}
-
-
-void spindle_next_segment() {
- while (!speed_q_empty()) {
- speed_t s = speed_q_next();
- if (s.time == -1) break;
- _set_speed(s.speed);
- }
-
- spindle.time = 0;
- spindle_update();
-}
-
-
-void spindle_new_segment() {
- speed_t s = {-1, 0};
- if (!speed_q_full()) speed_q_push(s);
-}
-
-
-void spindle_queue_speed(int8_t time, float speed) {
- if (speed_q_empty()) spindle_new_segment();
-
- speed_t s = {time, speed};
-
-#if 1
- if (!speed_q_full()) speed_q_push(s);
-
-#else
- speed_t *last = speed_q_back();
-
- if ((speed_q_empty() || last->time != time) && !speed_q_full())
- speed_q_push(s);
- else if (last->time == time) last->speed = speed;
-#endif
+ if (spindle.type == SPINDLE_TYPE_PWM) pwm_spindle_update();
}
-static void _update_speed() {_set_speed(spindle.speed);}
+static void _update_speed() {spindle_set_speed(0, spindle.speed);}
static void _deinit_cb() {
default: vfd_spindle_init(); break;
}
- _set_speed(spindle.speed);
+ spindle_set_speed(0, spindle.speed);
}
float get_speed() {return _get_speed();}
-void set_speed(float speed) {spindle_queue_speed(0, speed);}
+void set_speed(float speed) {spindle_set_speed(0, speed);}
bool get_tool_reversed() {return spindle.reversed;}
typedef void (*deinit_cb_t)();
-void spindle_init();
spindle_type_t spindle_get_type();
void spindle_stop();
bool spindle_is_reversed();
void spindle_update();
-void spindle_next_segment();
-void spindle_new_segment();
-void spindle_queue_speed(int8_t time, float speed);
+void spindle_set_speed(uint8_t time, float speed);
return;
}
- spindle_next_segment();
-
// Start move
if (st.move_type == MOVE_TYPE_LINE)
for (int motor = 0; motor < MOTORS; motor++)
help = 'HTTP address to bind')
parser.add_argument('-s', '--serial', default = '/dev/ttyAMA0',
help = 'Serial device')
- parser.add_argument('-b', '--baud', default = 115200, type = int,
+ parser.add_argument('-b', '--baud', default = 230400, type = int,
help = 'Serial baud rate')
parser.add_argument('--i2c-port', default = 1, type = int,
help = 'I2C port')