From 2cf110dff423b81c35d108ed81cdd31d46836a22 Mon Sep 17 00:00:00 2001 From: Joseph Coffland Date: Fri, 30 Mar 2018 11:22:20 -0700 Subject: [PATCH] More work on modbus VFDs --- CHANGELOG.md | 1 + package.json | 2 +- src/avr/Makefile | 6 +- src/avr/src/main.c | 2 - src/avr/src/modbus.c | 118 +++++++++++++++++++------- src/avr/src/modbus.h | 11 ++- src/avr/src/pwm_spindle.c | 21 ++--- src/avr/src/pwm_spindle.h | 1 + src/avr/src/spindle.c | 78 +++++++++++++----- src/avr/src/spindle.def | 30 +++++++ src/avr/src/spindle.h | 2 +- src/avr/src/usart.c | 124 +++++++++++++++++++--------- src/avr/src/usart.h | 37 ++++++++- src/avr/src/vars.def | 27 +++--- src/avr/src/{ => vfd}/huanyang.c | 36 ++++---- src/avr/src/{ => vfd}/huanyang.h | 11 ++- src/avr/src/vfd/yl600.c | 128 +++++++++++++++++++++++++++++ src/jade/templates/indicators.jade | 6 +- src/jade/templates/tool-view.jade | 12 +-- src/js/tool-view.js | 2 - src/resources/config-template.json | 56 +++++++------ 21 files changed, 514 insertions(+), 197 deletions(-) create mode 100644 src/avr/src/spindle.def rename src/avr/src/{ => vfd}/huanyang.c (91%) rename src/avr/src/{ => vfd}/huanyang.h (98%) create mode 100644 src/avr/src/vfd/yl600.c diff --git a/CHANGELOG.md b/CHANGELOG.md index 7e15bb5..b68f7e5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ Buildbotics CNC Controller Firmware Changelog ## v0.3.21 - Implemented M70-M73 modal state save/restore. - Added support for modbus VFDs. + - Start Huanyang spindle with out first pressing Start button on VFD. ## v0.3.20 - Eliminated drift caused by miscounting half microsteps. diff --git a/package.json b/package.json index d5e7a28..674f55c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "bbctrl", - "version": "0.3.21", + "version": "0.3.21.1", "homepage": "http://buildbotics.com/", "repository": "https://github.com/buildbotics/bbctrl-firmware", "license": "GPL-3.0+", diff --git a/src/avr/Makefile b/src/avr/Makefile index 2c00a07..122921d 100644 --- a/src/avr/Makefile +++ b/src/avr/Makefile @@ -4,8 +4,10 @@ MCU = atxmega192a3u CLOCK = 32000000 # SRC -SRC = $(wildcard src/*.c) $(wildcard src/*.cpp) -OBJ = $(patsubst src/%.cpp,build/%.o,$(patsubst src/%.c,build/%.o,$(SRC))) +SRC = $(wildcard src/*.c) $(wildcard src/*.cpp) $(wildcard src/vfd/*.c) +OBJ := $(patsubst src/%.c,build/%.o,$(SRC)) +OBJ := $(patsubst src/%.cpp,build/%.o,$(OBJ)) +OBJ := $(patsubst src/vfd/%.c,build/vfd/%.o,$(OBJ)) JSON = vars command messages JSON := $(patsubst %,build/%.json,$(JSON)) diff --git a/src/avr/src/main.c b/src/avr/src/main.c index 5877224..94b3da7 100644 --- a/src/avr/src/main.c +++ b/src/avr/src/main.c @@ -29,7 +29,6 @@ #include "stepper.h" #include "motor.h" #include "switch.h" -#include "spindle.h" #include "usart.h" #include "drv8711.h" #include "vars.h" @@ -65,7 +64,6 @@ int main() { stepper_init(); // steppers motor_init(); // motors switch_init(); // switches - spindle_init(); // spindles exec_init(); // motion exec vars_init(); // configuration variables estop_init(); // emergency stop handler diff --git a/src/avr/src/modbus.c b/src/avr/src/modbus.c index 1d76f51..9921770 100644 --- a/src/avr/src/modbus.c +++ b/src/avr/src/modbus.c @@ -42,7 +42,10 @@ static struct { bool debug; - uint8_t baud; + uint8_t id; + baud_t baud; + parity_t parity; + stop_t stop; uint8_t bytes; uint8_t command[MODBUS_BUF_SIZE]; @@ -52,11 +55,15 @@ static struct { modbus_cb_t receive_cb; + uint16_t addr; + modbus_read_cb_t read_cb; + modbus_write_cb_t write_cb; + uint32_t last; uint8_t retry; bool connected; bool busy; -} mb = {false, USART_BAUD_9600}; +} mb = {false, 1, USART_BAUD_9600, USART_NONE, USART_1STOP}; static uint16_t _crc16(const uint8_t *buffer, unsigned length) { @@ -138,13 +145,11 @@ static void _handle_response() { mb.last = 0; // Clear timeout timer mb.retry = 0; // Reset retry counter - - if (mb.receive_cb) - mb.receive_cb(mb.response[0], mb.response[1], mb.response_length - 4, - mb.response + 2); - mb.connected = true; mb.busy = false; + + if (mb.receive_cb) + mb.receive_cb(mb.response[1], mb.response_length - 4, mb.response + 2); } @@ -182,6 +187,31 @@ ISR(RS485_RXC_vect) { } +void _read_cb(uint8_t func, uint8_t bytes, const uint8_t *data) { + if (func == MODBUS_READ_OUTPUT_REG && bytes == 3 && data[0] == 2) { + uint16_t value = (uint16_t)data[1] << 8 | data[2]; + if (mb.read_cb) mb.read_cb(true, mb.addr, value); + return; + } + + if (mb.read_cb) mb.read_cb(false, mb.addr, 0); +} + + +void _write_cb(uint8_t func, uint8_t bytes, const uint8_t *data) { + if (func == MODBUS_WRITE_OUTPUT_REG && bytes == 4) { + uint16_t addr = (uint16_t)data[0] << 8 | data[1]; + + if (addr == mb.addr) { + if (mb.write_cb) mb.write_cb(true, mb.addr); + return; + } + } + + if (mb.write_cb) mb.write_cb(false, mb.addr); +} + + static void _reset() { _set_dre_interrupt(false); _set_txc_interrupt(false); @@ -195,14 +225,20 @@ static void _reset() { // Save settings bool debug = mb.debug; - uint8_t baud = mb.baud; + uint8_t id = mb.id; + baud_t baud = mb.baud; + parity_t parity = mb.parity; + stop_t stop = mb.stop; // Clear state memset(&mb, 0, sizeof(mb)); // Restore settings mb.debug = debug; + mb.id = id; mb.baud = baud; + mb.parity = parity; + mb.stop = stop; } @@ -231,13 +267,12 @@ static void _timeout() { if (mb.debug) STATUS_DEBUG("modbus: timedout"); modbus_cb_t cb = mb.receive_cb; - uint8_t id = mb.command[0]; uint8_t func = mb.command[1]; _reset(); // Notify caller - if (cb) cb(id, func, 0, 0); + if (cb) cb(func, 0, 0); } @@ -250,18 +285,7 @@ void modbus_init() { OUTSET_PIN(RS485_RW_PIN); // High DIRSET_PIN(RS485_RW_PIN); // Output - usart_set_port_baud(&RS485_PORT, mb.baud); - - // No parity, 8 data bits, 1 stop bit - RS485_PORT.CTRLC = USART_CMODE_ASYNCHRONOUS_gc | USART_PMODE_DISABLED_gc | - USART_CHSIZE_8BIT_gc; - - // Enable receiver and transmitter - RS485_PORT.CTRLB |= USART_RXEN_bm | USART_TXEN_bm; - - // TODO remove this - PINCTRL_PIN(RS485_RO_PIN) ^= PORT_INVEN_bm; - PINCTRL_PIN(RS485_DI_PIN) ^= PORT_INVEN_bm; + usart_init_port(&RS485_PORT, mb.baud, mb.parity, USART_8BITS, mb.stop); _reset(); } @@ -282,28 +306,46 @@ void modbus_deinit() { bool modbus_busy() {return mb.busy;} -void modbus_func(uint8_t slave, uint8_t func, uint8_t send, const uint8_t *data, +void modbus_func(uint8_t func, uint8_t send, const uint8_t *data, uint8_t receive, modbus_cb_t receive_cb) { ASSERT(send + 4 <= MODBUS_BUF_SIZE); ASSERT(receive + 4 <= MODBUS_BUF_SIZE); - _reset(); - - mb.command[0] = slave; + mb.command[0] = mb.id; mb.command[1] = func; memcpy(mb.command + 2, data, send); uint16_t crc = _crc16(mb.command, send + 2); mb.command[send + 2] = crc; mb.command[send + 3] = crc >> 8; + mb.bytes = 0; mb.command_length = send + 4; mb.response_length = receive + 4; mb.receive_cb = receive_cb; + mb.last = 0; + mb.retry = 0; _set_dre_interrupt(true); } +void modbus_read(uint16_t addr, modbus_read_cb_t cb) { + mb.read_cb = cb; + mb.addr = addr; + uint8_t cmd[4] = {(uint8_t)(addr >> 8), (uint8_t)addr, 0, 1}; + modbus_func(MODBUS_READ_OUTPUT_REG, 4, cmd, 3, _read_cb); +} + + +void modbus_write(uint16_t addr, uint16_t value, modbus_write_cb_t cb) { + mb.write_cb = cb; + mb.addr = addr; + uint8_t cmd[4] = {(uint8_t)(addr >> 8), (uint8_t)addr, (uint8_t)(value >> 8), + (uint8_t)value}; + modbus_func(MODBUS_WRITE_OUTPUT_REG, 4, cmd, 4, _write_cb); +} + + void modbus_rtc_callback() { if (!mb.last || !rtc_expired(mb.last + MODBUS_TIMEOUT)) return; @@ -327,12 +369,32 @@ void modbus_rtc_callback() { // Variable callbacks bool get_modbus_debug() {return mb.debug;} void set_modbus_debug(bool value) {mb.debug = value;} +uint8_t get_modbus_id() {return mb.id;} +void set_modbus_id(uint8_t id) {mb.id = id;} uint8_t get_modbus_baud() {return mb.baud;} void set_modbus_baud(uint8_t baud) { - mb.baud = baud; - usart_set_port_baud(&RS485_PORT, baud); + mb.baud = (baud_t)baud; + usart_set_baud(&RS485_PORT, mb.baud); +} + + +uint8_t get_modbus_parity() {return mb.parity;} + + +void set_modbus_parity(uint8_t parity) { + mb.parity = (parity_t)parity; + usart_set_parity(&RS485_PORT, mb.parity); +} + + +uint8_t get_modbus_stop() {return mb.stop;} + + +void set_modbus_stop(uint8_t stop) { + mb.stop = (stop_t)stop; + usart_set_stop(&RS485_PORT, mb.stop); } diff --git a/src/avr/src/modbus.h b/src/avr/src/modbus.h index 802791e..0a36d32 100644 --- a/src/avr/src/modbus.h +++ b/src/avr/src/modbus.h @@ -98,12 +98,15 @@ typedef enum { } modbus_base_addrs_t; -typedef void (*modbus_cb_t)(uint8_t slave, uint8_t func, uint8_t bytes, - const uint8_t *data); +typedef void (*modbus_cb_t)(uint8_t func, uint8_t bytes, const uint8_t *data); +typedef void (*modbus_read_cb_t)(bool ok, uint16_t addr, uint16_t value); +typedef void (*modbus_write_cb_t)(bool ok, uint16_t addr); void modbus_init(); void modbus_deinit(); bool modbus_busy(); -void modbus_func(uint8_t slave, uint8_t func, uint8_t send, const uint8_t *data, - uint8_t receive, modbus_cb_t receive_cb); +void modbus_func(uint8_t func, uint8_t send, const uint8_t *data, + uint8_t receive, modbus_cb_t cb); +void modbus_read(uint16_t addr, modbus_read_cb_t cb); +void modbus_write(uint16_t addr, uint16_t value, modbus_write_cb_t cb); void modbus_rtc_callback(); diff --git a/src/avr/src/pwm_spindle.c b/src/avr/src/pwm_spindle.c index f93a9cf..80d2d8a 100644 --- a/src/avr/src/pwm_spindle.c +++ b/src/avr/src/pwm_spindle.c @@ -36,8 +36,6 @@ typedef struct { uint16_t freq; // base frequency for PWM driver, in Hz - float min_rpm; - float max_rpm; float min_duty; float max_duty; float duty; @@ -62,7 +60,7 @@ static void _update_pwm() { float speed = spindle.speed; // Disable - if (speed <= spindle.min_rpm || estop_triggered()) { + if (!speed || estop_triggered()) { TIMER_PWM.CTRLA = 0; OUTCLR_PIN(SPIN_PWM_PIN); _set_enable(false); @@ -71,15 +69,12 @@ static void _update_pwm() { _set_enable(true); // 100% duty - if (spindle.max_rpm <= speed && spindle.max_duty == 1) { + if (speed == 1 && spindle.max_duty == 1) { TIMER_PWM.CTRLB = 0; OUTSET_PIN(SPIN_PWM_PIN); return; } - // Clamp speed - if (spindle.max_rpm < speed) speed = spindle.max_rpm; - // Set clock period and optimal prescaler value float prescale = (float)(F_CPU >> 16) / spindle.freq; if (prescale <= 1) { @@ -104,10 +99,9 @@ static void _update_pwm() { } else TIMER_PWM.CTRLA = 0; - // Map RPM to duty cycle + // Compute duty cycle spindle.duty = - (speed - spindle.min_rpm) / (spindle.max_rpm - spindle.min_rpm) * - (spindle.max_duty - spindle.min_duty) + spindle.min_duty; + speed * (spindle.max_duty - spindle.min_duty) + spindle.min_duty; // Configure clock TIMER_PWM.CTRLB = TC1_CCAEN_bm | TC_WGMODE_SINGLESLOPE_gc; @@ -144,14 +138,11 @@ void pwm_spindle_set(float speed) { } +float pwm_spindle_get() {return spindle.speed;} void pwm_spindle_stop() {pwm_spindle_set(0);} -// TODO these need more effort and should work with the huanyang spindle too -float get_max_spin() {return spindle.max_rpm;} -void set_max_spin(float value) {spindle.max_rpm = value; _update_pwm();} -float get_min_spin() {return spindle.min_rpm;} -void set_min_spin(float value) {spindle.min_rpm = value; _update_pwm();} +// Var callbacks float get_pwm_min_duty() {return spindle.min_duty * 100;} diff --git a/src/avr/src/pwm_spindle.h b/src/avr/src/pwm_spindle.h index fe29f28..996020d 100644 --- a/src/avr/src/pwm_spindle.h +++ b/src/avr/src/pwm_spindle.h @@ -31,4 +31,5 @@ void pwm_spindle_init(); void pwm_spindle_deinit(); void pwm_spindle_set(float speed); +float pwm_spindle_get(); void pwm_spindle_stop(); diff --git a/src/avr/src/spindle.c b/src/avr/src/spindle.c index bc931ad..0af9ccb 100644 --- a/src/avr/src/spindle.c +++ b/src/avr/src/spindle.c @@ -28,56 +28,90 @@ #include "spindle.h" #include "config.h" -#include "pwm_spindle.h" -#include "huanyang.h" #include "pgmspace.h" +#include + typedef enum { SPINDLE_TYPE_DISABLED, - SPINDLE_TYPE_PWM, - SPINDLE_TYPE_HUANYANG, +#define SPINDLE(NAME) SPINDLE_TYPE_##NAME, +#include "spindle.def" +#undef SPINDLE } spindle_type_t; +// Function decls +#define SPINDLE(NAME) \ + void NAME##_init(); \ + void NAME##_deinit(); \ + void NAME##_set(float speed); \ + float NAME##_get(); \ + void NAME##_stop(); +#include "spindle.def" +#undef SPINDLE + + typedef struct { spindle_type_t type; float speed; bool reversed; + float min_rpm; + float max_rpm; } spindle_t; static spindle_t spindle = {SPINDLE_TYPE_DISABLED,}; -void spindle_init() {} - - void spindle_set_speed(float speed) { spindle.speed = speed; + bool negative = speed < 0; + if (spindle.max_rpm <= fabs(speed)) speed = negative ? -1 : 1; + else if (fabs(speed) < spindle.min_rpm) speed = 0; + else speed /= spindle.max_rpm; + if (spindle.reversed) speed = -speed; switch (spindle.type) { case SPINDLE_TYPE_DISABLED: break; - case SPINDLE_TYPE_PWM: pwm_spindle_set(speed); break; - case SPINDLE_TYPE_HUANYANG: hy_set(speed); break; +#define SPINDLE(NAME) case SPINDLE_TYPE_##NAME: NAME##_set(speed); break; +#include "spindle.def" +#undef SPINDLE } } -float spindle_get_speed() {return spindle.speed;} +float spindle_get_speed() { + float speed = 0; + + switch (spindle.type) { + case SPINDLE_TYPE_DISABLED: break; +#define SPINDLE(NAME) case SPINDLE_TYPE_##NAME: speed = NAME##_get(); break; +#include "spindle.def" +#undef SPINDLE + } + + return speed * spindle.max_rpm; +} void spindle_stop() { switch (spindle.type) { case SPINDLE_TYPE_DISABLED: break; - case SPINDLE_TYPE_PWM: pwm_spindle_stop(); break; - case SPINDLE_TYPE_HUANYANG: hy_stop(); break; +#define SPINDLE(NAME) case SPINDLE_TYPE_##NAME: NAME##_stop(); break; +#include "spindle.def" +#undef SPINDLE } } +bool spindle_is_reversed() {return spindle.reversed;} +static void _update_speed() {spindle_set_speed(spindle.speed);} + + +// Var callbacks uint8_t get_spindle_type() {return spindle.type;} @@ -87,16 +121,18 @@ void set_spindle_type(uint8_t value) { switch (spindle.type) { case SPINDLE_TYPE_DISABLED: break; - case SPINDLE_TYPE_PWM: pwm_spindle_deinit(); break; - case SPINDLE_TYPE_HUANYANG: hy_deinit(); break; +#define SPINDLE(NAME) case SPINDLE_TYPE_##NAME: NAME##_deinit(); break; +#include "spindle.def" +#undef SPINDLE } spindle.type = (spindle_type_t)value; switch (spindle.type) { case SPINDLE_TYPE_DISABLED: break; - case SPINDLE_TYPE_PWM: pwm_spindle_init(); break; - case SPINDLE_TYPE_HUANYANG: hy_init(); break; +#define SPINDLE(NAME) case SPINDLE_TYPE_##NAME: NAME##_init(); break; +#include "spindle.def" +#undef SPINDLE } spindle_set_speed(speed); @@ -104,7 +140,8 @@ void set_spindle_type(uint8_t value) { } -bool spindle_is_reversed() {return spindle.reversed;} +void set_speed(float speed) {spindle_set_speed(speed);} +float get_speed() {return spindle_get_speed();} bool get_spin_reversed() {return spindle.reversed;} @@ -116,6 +153,7 @@ void set_spin_reversed(bool reversed) { } -// Var callbacks -void set_speed(float speed) {spindle_set_speed(speed);} -float get_speed() {return spindle_get_speed();} +float get_max_spin() {return spindle.max_rpm;} +void set_max_spin(float value) {spindle.max_rpm = value; _update_speed();} +float get_min_spin() {return spindle.min_rpm;} +void set_min_spin(float value) {spindle.min_rpm = value; _update_speed();} diff --git a/src/avr/src/spindle.def b/src/avr/src/spindle.def new file mode 100644 index 0000000..1022568 --- /dev/null +++ b/src/avr/src/spindle.def @@ -0,0 +1,30 @@ +/******************************************************************************\ + + This file is part of the Buildbotics firmware. + + Copyright (c) 2015 - 2018, Buildbotics LLC + All rights reserved. + + This file ("the software") is free software: you can redistribute it + and/or modify it under the terms of the GNU General Public License, + version 2 as published by the Free Software Foundation. You should + have received a copy of the GNU General Public License, version 2 + along with the software. If not, see . + + The software is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the software. If not, see + . + + For information regarding this software email: + "Joseph Coffland" + +\******************************************************************************/ + +SPINDLE(pwm_spindle) +SPINDLE(huanyang) +SPINDLE(yl600) diff --git a/src/avr/src/spindle.h b/src/avr/src/spindle.h index 5473877..b15eb00 100644 --- a/src/avr/src/spindle.h +++ b/src/avr/src/spindle.h @@ -29,7 +29,7 @@ #include -void spindle_init(); + void spindle_set_speed(float speed); float spindle_get_speed(); void spindle_stop(); diff --git a/src/avr/src/usart.c b/src/avr/src/usart.c index 55876a6..a8e4658 100644 --- a/src/avr/src/usart.c +++ b/src/avr/src/usart.c @@ -95,7 +95,86 @@ static int _usart_putchar(char c, FILE *f) { } -void usart_init(void) { +static void _set_baud(USART_t *port, uint16_t bsel, uint8_t bscale) { + port->BAUDCTRLB = (uint8_t)((bscale << 4) | (bsel >> 8)); + port->BAUDCTRLA = bsel; + port->CTRLB |= USART_CLK2X_bm; +} + + +void usart_set_baud(USART_t *port, baud_t baud) { + // The BSEL / BSCALE values provided below assume a 32 Mhz clock + // With CTRLB CLK2X is set + // See http://www.avrcalc.elektronik-projekt.de/xmega/baud_rate_calculator + + switch (baud) { + case USART_BAUD_9600: _set_baud(port, 3325, 0b1101); break; + case USART_BAUD_19200: _set_baud(port, 3317, 0b1100); break; + case USART_BAUD_38400: _set_baud(port, 3301, 0b1011); break; + case USART_BAUD_57600: _set_baud(port, 1095, 0b1100); break; + case USART_BAUD_115200: _set_baud(port, 1079, 0b1011); break; + case USART_BAUD_230400: _set_baud(port, 1047, 0b1010); break; + case USART_BAUD_460800: _set_baud(port, 983, 0b1001); break; + case USART_BAUD_921600: _set_baud(port, 107, 0b1011); break; + case USART_BAUD_500000: _set_baud(port, 1, 0b0010); break; + case USART_BAUD_1000000: _set_baud(port, 1, 0b0001); break; + } +} + + +void usart_set_parity(USART_t *port, parity_t parity) { + uint8_t reg = port->CTRLC & ~USART_PMODE_gm; + + switch (parity) { + case USART_NONE: reg |= USART_PMODE_DISABLED_gc; break; + case USART_EVEN: reg |= USART_PMODE_EVEN_gc; break; + case USART_ODD: reg |= USART_PMODE_ODD_gc; break; + } + + port->CTRLC = reg; +} + + +void usart_set_stop(USART_t *port, stop_t stop) { + switch (stop) { + case USART_1STOP: port->CTRLC &= ~USART_SBMODE_bm; break; + case USART_2STOP: port->CTRLC |= USART_SBMODE_bm; break; + } +} + + +void usart_set_bits(USART_t *port, bits_t bits) { + uint8_t reg = port->CTRLC & ~USART_CHSIZE_gm; + + switch (bits) { + case USART_5BITS: reg |= USART_CHSIZE_5BIT_gc; break; + case USART_6BITS: reg |= USART_CHSIZE_6BIT_gc; break; + case USART_7BITS: reg |= USART_CHSIZE_7BIT_gc; break; + case USART_8BITS: reg |= USART_CHSIZE_8BIT_gc; break; + case USART_9BITS: reg |= USART_CHSIZE_9BIT_gc; break; + } + + port->CTRLC = reg; +} + + +void usart_init_port(USART_t *port, baud_t baud, parity_t parity, bits_t bits, + stop_t stop) { + // Set baud rate + usart_set_baud(port, baud); + + // Async, no parity, 8 data bits, 1 stop bit + port->CTRLC = USART_CMODE_ASYNCHRONOUS_gc; + usart_set_parity(port, parity); + usart_set_bits(port, bits); + usart_set_stop(port, stop); + + // Configure receiver and transmitter + port->CTRLB |= USART_RXEN_bm | USART_TXEN_bm; +} + + +void usart_init() { // Setup ring buffer tx_buf_init(); rx_buf_init(); @@ -109,15 +188,9 @@ void usart_init(void) { DIRSET_PIN(SERIAL_TX_PIN); // Tx Output DIRCLR_PIN(SERIAL_RX_PIN); // Rx Input - // Set baud rate - usart_set_baud(SERIAL_BAUD); - - // No parity, 8 data bits, 1 stop bit - SERIAL_PORT.CTRLC = USART_CMODE_ASYNCHRONOUS_gc | USART_PMODE_DISABLED_gc | - USART_CHSIZE_8BIT_gc; - - // Configure receiver and transmitter - SERIAL_PORT.CTRLB |= USART_RXEN_bm | USART_TXEN_bm; + // Configure port + usart_init_port(&SERIAL_PORT, SERIAL_BAUD, USART_NONE, USART_8BITS, + USART_1STOP); PMIC.CTRL |= PMIC_HILVLEN_bm; // Interrupt level on @@ -135,37 +208,6 @@ void usart_init(void) { } -static void _set_baud(USART_t *port, uint16_t bsel, uint8_t bscale) { - port->BAUDCTRLB = (uint8_t)((bscale << 4) | (bsel >> 8)); - port->BAUDCTRLA = bsel; - port->CTRLB |= USART_CLK2X_bm; -} - - -void usart_set_port_baud(USART_t *port, int baud) { - // The BSEL / BSCALE values provided below assume a 32 Mhz clock - // With CTRLB CLK2X is set - // See http://www.avrcalc.elektronik-projekt.de/xmega/baud_rate_calculator - - switch (baud) { - case USART_BAUD_9600: _set_baud(port, 3325, 0b1101); break; - case USART_BAUD_19200: _set_baud(port, 3317, 0b1100); break; - case USART_BAUD_38400: _set_baud(port, 3301, 0b1011); break; - case USART_BAUD_57600: _set_baud(port, 1095, 0b1100); break; - case USART_BAUD_115200: _set_baud(port, 1079, 0b1011); break; - case USART_BAUD_230400: _set_baud(port, 1047, 0b1010); break; - case USART_BAUD_460800: _set_baud(port, 983, 0b1001); break; - case USART_BAUD_921600: _set_baud(port, 107, 0b1011); break; - case USART_BAUD_500000: _set_baud(port, 1, 0b0010); break; - case USART_BAUD_1000000: _set_baud(port, 1, 0b0001); break; - } -} - - -void usart_set_baud(int baud) { - usart_set_port_baud(&SERIAL_PORT, baud); -} - void usart_set(int flag, bool enable) { if (enable) usart_flags |= flag; diff --git a/src/avr/src/usart.h b/src/avr/src/usart.h index 77a6349..b61bc42 100644 --- a/src/avr/src/usart.h +++ b/src/avr/src/usart.h @@ -37,7 +37,7 @@ #define USART_RX_RING_BUF_SIZE 256 -enum { +typedef enum { USART_BAUD_9600, USART_BAUD_19200, USART_BAUD_38400, @@ -48,7 +48,8 @@ enum { USART_BAUD_921600, USART_BAUD_500000, USART_BAUD_1000000 -}; +} baud_t; + enum { USART_CRLF = 1 << 0, @@ -57,9 +58,37 @@ enum { USART_FLUSH = 1 << 3, }; + +typedef enum { + USART_NONE, + USART_EVEN, + USART_ODD, +} parity_t; + + +typedef enum { + USART_1STOP, + USART_2STOP, +} stop_t; + + +typedef enum { + USART_5BITS, + USART_6BITS, + USART_7BITS, + USART_8BITS, + USART_9BITS, +} bits_t; + + +void usart_set_baud(USART_t *port, baud_t baud); +void usart_set_parity(USART_t *port, parity_t parity); +void usart_set_stop(USART_t *port, stop_t stop); +void usart_set_bits(USART_t *port, bits_t bits); +void usart_init_port(USART_t *port, baud_t baud, parity_t parity, bits_t bits, + stop_t stop); + void usart_init(); -void usart_set_port_baud(USART_t *port, int baud); -void usart_set_baud(int baud); void usart_set(int flag, bool enable); bool usart_is_set(int flags); void usart_putc(char c); diff --git a/src/avr/src/vars.def b/src/avr/src/vars.def index c2d3246..91a8b95 100644 --- a/src/avr/src/vars.def +++ b/src/avr/src/vars.def @@ -83,36 +83,37 @@ VAR(analog_input, ai, f32, ANALOG, 0, 0, "Analog input pins") // Spindle VAR(spindle_type, st, u8, 0, 1, 1, "DISABLED=0, PWM=1 or HUANYANG=2") +VAR(speed, s, f32, 0, 1, 1, "Current spindle speed") VAR(spin_reversed, sr, b8, 0, 1, 1, "Reverse spin") VAR(max_spin, sx, f32, 0, 1, 1, "Maximum spindle speed") VAR(min_spin, sm, f32, 0, 1, 1, "Minimum spindle speed") + +// PWM spindle +VAR(pwm_invert, pi, b8, 0, 1, 1, "Inverted spindle PWM") VAR(pwm_min_duty, nd, f32, 0, 1, 1, "Minimum PWM duty cycle") VAR(pwm_max_duty, md, f32, 0, 1, 1, "Maximum PWM duty cycle") VAR(pwm_duty, pd, f32, 0, 0, 1, "Current PWM duty cycle") VAR(pwm_freq, sf, u16, 0, 1, 1, "Spindle PWM frequency in Hz") -// PWM spindle -VAR(pwm_invert, pi, b8, 0, 1, 1, "Inverted spindle PWM") - // Modbus spindle VAR(modbus_debug, hb, b8, 0, 1, 1, "Modbus debugging") +VAR(modbus_id, hi, u8, 0, 1, 1, "Modbus ID") VAR(modbus_baud, mb, u8, 0, 1, 1, "Modbus BAUD rate") +VAR(modbus_parity, ma, u8, 0, 1, 1, "Modbus parity") +VAR(modbus_stop, ms, u8, 0, 1, 1, "Modbus stop bits") VAR(modbus_connected, he, b8, 0, 0, 1, "Modbus connected") // Huanyang spindle -VAR(hy_id, hi, u8, 0, 1, 1, "Modbus ID") -VAR(hy_freq, hz, f32, 0, 0, 1, "Modbus actual freq") -VAR(hy_current, hc, f32, 0, 0, 1, "Modbus actual current") -VAR(hy_rpm, hr, u16, 0, 0, 1, "Modbus actual RPM") -VAR(hy_temp, ht, u16, 0, 0, 1, "Modbus temperature") -VAR(hy_max_freq, hx, f32, 0, 0, 1, "Modbus max freq") -VAR(hy_min_freq, hm, f32, 0, 0, 1, "Modbus min freq") -VAR(hy_rated_rpm, hq, u16, 0, 0, 1, "Modbus rated RPM") -VAR(hy_status, hs, u8, 0, 0, 1, "Modbus status flags") +VAR(hy_freq, hz, f32, 0, 0, 1, "Huanyang actual freq") +VAR(hy_current, hc, f32, 0, 0, 1, "Huanyang actual current") +VAR(hy_temp, ht, u16, 0, 0, 1, "Huanyang temperature") +VAR(hy_max_freq, hx, f32, 0, 0, 1, "Huanyang max freq") +VAR(hy_min_freq, hm, f32, 0, 0, 1, "Huanyang min freq") +VAR(hy_rated_rpm, hq, u16, 0, 0, 1, "Huanyang rated RPM") +VAR(hy_status, hs, u8, 0, 0, 1, "Huanyang status flags") // Machine state VAR(id, id, u32, 0, 1, 1, "Last executed command ID") -VAR(speed, s, f32, 0, 1, 1, "Current spindle speed") VAR(feed_override, fo, f32, 0, 1, 1, "Feed rate override") VAR(speed_override, so, f32, 0, 1, 1, "Spindle speed override") VAR(optional_pause, op, b8, 0, 1, 1, "Optional pause state") diff --git a/src/avr/src/huanyang.c b/src/avr/src/vfd/huanyang.c similarity index 91% rename from src/avr/src/huanyang.c rename to src/avr/src/vfd/huanyang.c index 6d96abc..259c006 100644 --- a/src/avr/src/huanyang.c +++ b/src/avr/src/vfd/huanyang.c @@ -107,8 +107,6 @@ typedef enum { static struct { - uint8_t id; - uint8_t state; hy_func_t func; uint8_t data[4]; @@ -129,7 +127,7 @@ static struct { uint16_t rated_rpm; uint8_t status; -} hy = {1}; // Default ID +} hy = {0}; static void _func_read(hy_addr_t addr) { @@ -219,14 +217,12 @@ static void _next_command(); static void _reset(bool halt) { // Save settings - uint8_t id = hy.id; float speed = hy.speed; // Clear state memset(&hy, 0, sizeof(hy)); // Restore settings - hy.id = id; hy.speed = speed; hy.changed = true; @@ -234,8 +230,7 @@ static void _reset(bool halt) { } -static void _modbus_cb(uint8_t slave, uint8_t func, uint8_t bytes, - const uint8_t *data) { +static void _modbus_cb(uint8_t func, uint8_t bytes, const uint8_t *data) { if (!data) _reset(true); else if (bytes == *data + 1) { @@ -266,7 +261,8 @@ static void _next_command() { case 0: { // Update direction hy_ctrl_state_t state = HUANYANG_STOP; if (!hy.shutdown) { - if (0 < hy.speed) state = HUANYANG_RUN; + if (0 < hy.speed) + state = (hy_ctrl_state_t)(HUANYANG_RUN | HUANYANG_FORWARD); else if (hy.speed < 0) state = (hy_ctrl_state_t)(HUANYANG_RUN | HUANYANG_REV_FWD); } @@ -281,11 +277,7 @@ static void _next_command() { case 4: { // Update freqency // Compute frequency in Hz - float freq = fabs(hy.speed * 50 / hy.rated_rpm); - - // Clamp frequency - if (hy.max_freq < freq) freq = hy.max_freq; - if (freq < hy.min_freq) freq = hy.min_freq; + float freq = fabs(hy.speed * hy.max_freq); // Frequency write command _freq_write(freq * 100); @@ -300,20 +292,20 @@ static void _next_command() { } // Send command - modbus_func(hy.id, hy.func, hy.bytes, hy.data, hy.response, _modbus_cb); + modbus_func(hy.func, hy.bytes, hy.data, hy.response, _modbus_cb); } -void hy_init() { +void huanyang_init() { modbus_init(); _reset(false); } -void hy_deinit() {hy.shutdown = true;} +void huanyang_deinit() {hy.shutdown = true;} -void hy_set(float speed) { +void huanyang_set(float speed) { if (hy.speed != speed) { hy.speed = speed; hy.changed = true; @@ -321,17 +313,17 @@ void hy_set(float speed) { } -void hy_stop() { - hy_set(0); +float huanyang_get() {return hy.actual_freq / hy.max_freq;} + + +void huanyang_stop() { + huanyang_set(0); _reset(false); } -uint8_t get_hy_id() {return hy.id;} -void set_hy_id(uint8_t value) {hy.id = value;} float get_hy_freq() {return hy.actual_freq;} float get_hy_current() {return hy.actual_current;} -uint16_t get_hy_rpm() {return hy.actual_rpm;} uint16_t get_hy_temp() {return hy.temperature;} float get_hy_max_freq() {return hy.max_freq;} float get_hy_min_freq() {return hy.min_freq;} diff --git a/src/avr/src/huanyang.h b/src/avr/src/vfd/huanyang.h similarity index 98% rename from src/avr/src/huanyang.h rename to src/avr/src/vfd/huanyang.h index 739199d..c5b88af 100644 --- a/src/avr/src/huanyang.h +++ b/src/avr/src/vfd/huanyang.h @@ -27,13 +27,12 @@ #pragma once -#include "spindle.h" - -void hy_init(); -void hy_deinit(); -void hy_set(float speed); -void hy_stop(); +void huanyang_init(); +void huanyang_deinit(); +void huanyang_set(float speed); +float huanyang_get(); +void huanyang_stop(); /// See Huanyang VFD user manual diff --git a/src/avr/src/vfd/yl600.c b/src/avr/src/vfd/yl600.c new file mode 100644 index 0000000..e91e901 --- /dev/null +++ b/src/avr/src/vfd/yl600.c @@ -0,0 +1,128 @@ +/******************************************************************************\ + + This file is part of the Buildbotics firmware. + + Copyright (c) 2015 - 2018, Buildbotics LLC + All rights reserved. + + This file ("the software") is free software: you can redistribute it + and/or modify it under the terms of the GNU General Public License, + version 2 as published by the Free Software Foundation. You should + have received a copy of the GNU General Public License, version 2 + along with the software. If not, see . + + The software is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the software. If not, see + . + + For information regarding this software email: + "Joseph Coffland" + +\******************************************************************************/ + + +#include "modbus.h" + +#include + + +#define P(H, L) ((H) << 8 | (L)) + + +enum { + P00_00_MAIN_FREQ = P(0, 0), + P00_01_START_STOP_SOURCE = P(0, 1), + P00_04_HIGEST_OUTPUT_FREQ = P(0, 4), + P01_00_DIRECTION = P(1, 0), + P07_00_FREQ_1 = P(7, 0), + P07_08_FREQ_SOURCE_1 = P(7, 8), +}; + + +static struct { + uint8_t state; + bool changed; + bool shutdown; + + float speed; + uint16_t max_freq; + float actual_speed; +} s = {0}; + + +static void _next_command(); + + +static uint16_t _speed2freq(float speed) {return fabs(speed) * s.max_freq;} +static float _freq2speed(uint16_t freq) {return (float)freq / s.max_freq;} + + +static void _next_state(bool ok) { + if (!ok) s.state = 0; + + else if (s.changed) { + s.changed = false; + s.state = 0; + + } else if (++s.state == 5) s.state = 4; + + _next_command(); +} + + +static void _read_cb(bool ok, uint16_t addr, uint16_t value) { + if (ok) + switch (addr) { + case P00_04_HIGEST_OUTPUT_FREQ: s.max_freq = value; break; + case P07_00_FREQ_1: s.actual_speed = _freq2speed(value); break; + } + + _next_state(ok); +} + + +static void _write_cb(bool ok, uint16_t addr) {_next_state(ok);} + + +static void _next_command() { + if (s.shutdown) { + modbus_deinit(); + return; + } + + // TODO spin direction + switch (s.state) { + case 0: modbus_read(P00_04_HIGEST_OUTPUT_FREQ, _read_cb); break; + case 1: modbus_write(P00_01_START_STOP_SOURCE, 1, _write_cb); break; + case 2: modbus_write(P07_08_FREQ_SOURCE_1, 1, _write_cb); break; + case 3: modbus_write(P07_00_FREQ_1, _speed2freq(s.speed), _write_cb); break; + case 4: modbus_read(P07_00_FREQ_1, _read_cb); break; + } +} + + +void yl600_init() { + modbus_init(); + s.shutdown = false; + _next_command(); +} + + +void yl600_deinit() {s.shutdown = true;} + + +void yl600_set(float speed) { + if (s.speed != speed) { + s.speed = speed; + s.changed = true; + } +} + + +float yl600_get() {return s.actual_speed;} +void yl600_stop() {yl600_set(0);} diff --git a/src/jade/templates/indicators.jade b/src/jade/templates/indicators.jade index b3d1163..17a4c90 100644 --- a/src/jade/templates/indicators.jade +++ b/src/jade/templates/indicators.jade @@ -182,11 +182,11 @@ script#indicators-template(type="text/x-template") th Current tr - td {{state['hr']}} RPM + td {{state['s']}} RPM th Speed th.separator - td {{state['ht']}} ℃ - th Temp + td + th table.legend tr diff --git a/src/jade/templates/tool-view.jade b/src/jade/templates/tool-view.jade index d22e5d3..8be586f 100644 --- a/src/jade/templates/tool-view.jade +++ b/src/jade/templates/tool-view.jade @@ -41,16 +41,8 @@ script#tool-view-template(type="text/x-template") templated-input(v-for="templ in template['pwm-spindle']", :name="$key", :model.sync="pwmSpindle[$key]", :template="templ") - div(v-if="get_type() == 'HUANYANG'") - h2 Huanyang VFD - form.pure-form.pure-form-aligned - fieldset - templated-input(v-for="templ in template['huanyang-spindle']", - :name="$key", :model.sync="huanyangSpindle[$key]", - :template="templ") - - div(v-if="get_type() == 'MODBUS'") - h2 Modbus Compatiable VFD + div(v-if="get_type() != 'DISABLED' && get_type() != 'PWM'") + h2 Modbus Configuration form.pure-form.pure-form-aligned fieldset templated-input(v-for="templ in template['modbus-spindle']", diff --git a/src/js/tool-view.js b/src/js/tool-view.js index 731942b..498fe3c 100644 --- a/src/js/tool-view.js +++ b/src/js/tool-view.js @@ -37,7 +37,6 @@ module.exports = { return { tool: {}, pwmSpindle: {}, - huanyangSpindle: {}, modbusSpindle: {} } }, @@ -82,7 +81,6 @@ module.exports = { this.$set('tool["' + key + '"]', template[key].default); this.update_tool('pwm'); - this.update_tool('huanyang'); this.update_tool('modbus'); }.bind(this)); } diff --git a/src/resources/config-template.json b/src/resources/config-template.json index c1bf508..412698e 100644 --- a/src/resources/config-template.json +++ b/src/resources/config-template.json @@ -153,7 +153,7 @@ "tool": { "spindle-type": { "type": "enum", - "values": ["Disabled", "PWM", "Huanyang", "Modbus"], + "values": ["Disabled", "PWM", "Huanyang", "YL600"], "default": "Disabled", "code": "st" }, @@ -162,6 +162,20 @@ "default": "false", "code": "sr" }, + "max-spin": { + "type": "float", + "unit": "RPM", + "min": 0, + "default": 10000, + "code": "sx" + }, + "min-spin": { + "type": "float", + "unit": "RPM", + "min": 0, + "default": 0, + "code": "sm" + }, "tool-enable-mode": { "type": "enum", "values": ["disabled", "lo-hi", "hi-lo", "tri-lo", "tri-hi", "lo-tri", @@ -178,37 +192,33 @@ } }, - "huanyang-spindle": { + "modbus-spindle": { "bus-id": { "type": "int", "default": "1", "code": "hi" - } - }, - - "modbus-spindle": { - "modbus-id": { - "type": "int", + }, + "baud": { + "type": "enum", + "values": ["9600", "19200", "38400", "57600", "115200"], + "default": "9600", + "code": "mb" + }, + "parity": { + "type": "enum", + "values": ["None", "Even", "Odd"], + "default": "None", + "code": "ma" + }, + "stop-bits": { + "type": "enum", + "values": ["1", "2"], "default": "1", - "code": "bi" + "code": "ms" } }, "pwm-spindle": { - "max-spin": { - "type": "float", - "unit": "RPM", - "min": 0, - "default": 10000, - "code": "sx" - }, - "min-spin": { - "type": "float", - "unit": "RPM", - "min": 0, - "default": 0, - "code": "sm" - }, "pwm-inverted": { "type": "bool", "default": "false", -- 2.27.0