More work on modbus VFDs
authorJoseph Coffland <joseph@cauldrondevelopment.com>
Fri, 30 Mar 2018 18:22:20 +0000 (11:22 -0700)
committerJoseph Coffland <joseph@cauldrondevelopment.com>
Fri, 30 Mar 2018 18:22:20 +0000 (11:22 -0700)
23 files changed:
CHANGELOG.md
package.json
src/avr/Makefile
src/avr/src/huanyang.c [deleted file]
src/avr/src/huanyang.h [deleted file]
src/avr/src/main.c
src/avr/src/modbus.c
src/avr/src/modbus.h
src/avr/src/pwm_spindle.c
src/avr/src/pwm_spindle.h
src/avr/src/spindle.c
src/avr/src/spindle.def [new file with mode: 0644]
src/avr/src/spindle.h
src/avr/src/usart.c
src/avr/src/usart.h
src/avr/src/vars.def
src/avr/src/vfd/huanyang.c [new file with mode: 0644]
src/avr/src/vfd/huanyang.h [new file with mode: 0644]
src/avr/src/vfd/yl600.c [new file with mode: 0644]
src/jade/templates/indicators.jade
src/jade/templates/tool-view.jade
src/js/tool-view.js
src/resources/config-template.json

index 7e15bb52c555734aecdaebc835618b8979594cf1..b68f7e57f17dcd880532dbf98be5ddb1d6532d4e 100644 (file)
@@ -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.
index d5e7a28bba47fa228d91ba304ca2dc3fe21bbbf1..674f55c98de04f3d581be40f46c0c617263fb51a 100644 (file)
@@ -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+",
index 2c00a07d4abe67a8165b51d530dedb6dac8373ae..122921dce2ad18ee88f8ca1d6babff1029a3b84b 100644 (file)
@@ -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/huanyang.c b/src/avr/src/huanyang.c
deleted file mode 100644 (file)
index 6d96abc..0000000
+++ /dev/null
@@ -1,339 +0,0 @@
-/******************************************************************************\
-
-                 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 <http://www.gnu.org/licenses/>.
-
-      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
-                        <http://www.gnu.org/licenses/>.
-
-                 For information regarding this software email:
-                   "Joseph Coffland" <joseph@buildbotics.com>
-
-\******************************************************************************/
-
-#include "huanyang.h"
-#include "config.h"
-#include "modbus.h"
-#include "report.h"
-
-#include <string.h>
-#include <math.h>
-
-
-/*
-  Huanyang is not quite Modbus compliant.
-
-  Message format is:
-
-    [id][func][length][data][checksum]
-
-  Where:
-
-     id       - 1-byte Peer ID
-     func     - 1-byte One of hy_func_t
-     length   - 1-byte Length data in bytes
-     data     - length bytes - Command arguments
-     checksum - 16-bit CRC: x^16 + x^15 + x^2 + 1 (0xa001) initial: 0xffff
-*/
-
-
-// See VFD manual pg56 3.1.3
-typedef enum {
-  HUANYANG_FUNC_READ = 1, // [len=1][hy_addr_t]
-  HUANYANG_FUNC_WRITE,    // [len=3][hy_addr_t][data]
-  HUANYANG_CTRL_WRITE,    // [len=1][hy_ctrl_state_t]
-  HUANYANG_CTRL_READ,     // [len=1][hy_ctrl_addr_t]
-  HUANYANG_FREQ_WRITE,    // [len=2][freq]
-  HUANYANG_RESERVED_1,
-  HUANYANG_RESERVED_2,
-  HUANYANG_LOOP_TEST,
-} hy_func_t;
-
-
-// Sent in HUANYANG_CTRL_WRITE
-// See VFD manual pg57 3.1.3.c
-typedef enum {
-  HUANYANG_RUN         = 1 << 0,
-  HUANYANG_FORWARD     = 1 << 1,
-  HUANYANG_REVERSE     = 1 << 2,
-  HUANYANG_STOP        = 1 << 3,
-  HUANYANG_REV_FWD     = 1 << 4,
-  HUANYANG_JOG         = 1 << 5,
-  HUANYANG_JOG_FORWARD = 1 << 6,
-  HUANYANG_JOG_REVERSE = 1 << 7,
-} hy_ctrl_state_t;
-
-
-// Returned by HUANYANG_CTRL_WRITE
-// See VFD manual pg57 3.1.3.c
-typedef enum {
-  HUANYANG_STATUS_RUN         = 1 << 0,
-  HUANYANG_STATUS_JOG         = 1 << 1,
-  HUANYANG_STATUS_COMMAND_REV = 1 << 2,
-  HUANYANG_STATUS_RUNNING     = 1 << 3,
-  HUANYANG_STATUS_JOGGING     = 1 << 4,
-  HUANYANG_STATUS_JOGGING_REV = 1 << 5,
-  HUANYANG_STATUS_BRAKING     = 1 << 6,
-  HUANYANG_STATUS_TRACK_START = 1 << 7,
-} hy_ctrl_status_t;
-
-
-// Sent in HUANYANG_CTRL_READ
-// See VFD manual pg57 3.1.3.d
-typedef enum {
-  HUANYANG_TARGET_FREQ,
-  HUANYANG_ACTUAL_FREQ,
-  HUANYANG_ACTUAL_CURRENT,
-  HUANYANG_ACTUAL_RPM,
-  HUANYANG_DCV,
-  HUANYANG_ACV,
-  HUANYANG_COUNTER,
-  HUANYANG_TEMPERATURE,
-} hy_ctrl_addr_t;
-
-
-static struct {
-  uint8_t id;
-
-  uint8_t state;
-  hy_func_t func;
-  uint8_t data[4];
-  uint8_t bytes;
-  uint8_t response;
-
-  bool shutdown;
-  bool changed;
-  float speed;
-
-  float actual_freq;
-  float actual_current;
-  uint16_t actual_rpm;
-  uint16_t temperature;
-
-  float max_freq;
-  float min_freq;
-  uint16_t rated_rpm;
-
-  uint8_t status;
-} hy = {1}; // Default ID
-
-
-static void _func_read(hy_addr_t addr) {
-  hy.func     = HUANYANG_FUNC_READ;
-  hy.bytes    = 2;
-  hy.response = 4;
-  hy.data[0]  = 1;
-  hy.data[1]  = addr;
-}
-
-
-static void _ctrl_write(hy_ctrl_state_t state) {
-  hy.func     = HUANYANG_CTRL_WRITE;
-  hy.bytes    = 2;
-  hy.response = 2;
-  hy.data[0]  = 1;
-  hy.data[1]  = state;
-}
-
-
-static void _ctrl_read(hy_ctrl_addr_t addr) {
-  hy.func     = HUANYANG_CTRL_READ;
-  hy.bytes    = 2;
-  hy.response = 4;
-  hy.data[0]  = 1;
-  hy.data[1]  = addr;
-}
-
-
-static void _freq_write(uint16_t freq) {
-  hy.func     = HUANYANG_FREQ_WRITE;
-  hy.bytes    = 3;
-  hy.response = 3;
-  hy.data[0]  = 2;
-  hy.data[1]  = freq >> 8;
-  hy.data[2]  = freq;
-}
-
-
-static void _func_read_response(hy_addr_t addr, uint16_t value) {
-  switch (addr) {
-  case HY_PD005_MAX_FREQUENCY:         hy.max_freq  = value * 0.01; break;
-  case HY_PD011_FREQUENCY_LOWER_LIMIT: hy.min_freq  = value * 0.01; break;
-  case HY_PD144_RATED_MOTOR_RPM:       hy.rated_rpm = value;        break;
-  default: break;
-  }
-}
-
-
-static void _ctrl_read_response(hy_ctrl_addr_t addr, uint16_t value) {
-  switch (addr) {
-  case HUANYANG_ACTUAL_FREQ:    hy.actual_freq    = value * 0.01; break;
-  case HUANYANG_ACTUAL_CURRENT: hy.actual_current = value * 0.01; break;
-  case HUANYANG_ACTUAL_RPM:     hy.actual_rpm     = value;        break;
-  case HUANYANG_TEMPERATURE:    hy.temperature    = value;        break;
-  default: break;
-  }
-}
-
-
-static uint16_t _read_word(const uint8_t *data) {
-  return (uint16_t)data[0] << 8 | data[1];
-}
-
-
-static void _handle_response(hy_func_t func, const uint8_t *data) {
-  switch (func) {
-  case HUANYANG_FUNC_READ:
-    _func_read_response((hy_addr_t)*data, _read_word(data + 1));
-    break;
-
-  case HUANYANG_FUNC_WRITE: break;
-  case HUANYANG_CTRL_WRITE: hy.status = *data; break;
-
-  case HUANYANG_CTRL_READ:
-    _ctrl_read_response((hy_ctrl_addr_t)*data, _read_word(data + 1));
-    break;
-
-  case HUANYANG_FREQ_WRITE: break;
-  default: break;
-  }
-}
-
-
-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;
-
-  if (!halt) _next_command();
-}
-
-
-static void _modbus_cb(uint8_t slave, uint8_t func, uint8_t bytes,
-                       const uint8_t *data) {
-  if (!data) _reset(true);
-
-  else if (bytes == *data + 1) {
-    _handle_response((hy_func_t)func, data + 1);
-
-    if (func == HUANYANG_CTRL_WRITE && hy.shutdown) {
-      _reset(true);
-      modbus_deinit();
-      return;
-    }
-
-    // Next command
-    if (++hy.state == 9) {
-      hy.state = 5;
-      report_request();
-    }
-
-    // Update freq
-    if (hy.shutdown || (hy.changed && 4 < hy.state)) hy.state = 0;
-  }
-
-  _next_command();
-}
-
-
-static void _next_command() {
-  switch (hy.state) {
-  case 0: { // Update direction
-    hy_ctrl_state_t state = HUANYANG_STOP;
-    if (!hy.shutdown) {
-      if (0 < hy.speed) state = HUANYANG_RUN;
-      else if (hy.speed < 0)
-        state = (hy_ctrl_state_t)(HUANYANG_RUN | HUANYANG_REV_FWD);
-    }
-
-    _ctrl_write(state);
-    break;
-  }
-
-  case 1: _func_read(HY_PD005_MAX_FREQUENCY); break;
-  case 2: _func_read(HY_PD011_FREQUENCY_LOWER_LIMIT); break;
-  case 3: _func_read(HY_PD144_RATED_MOTOR_RPM); break;
-
-  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;
-
-    // Frequency write command
-    _freq_write(freq * 100);
-    hy.changed = false;
-    break;
-  }
-
-  case 5: _ctrl_read(HUANYANG_ACTUAL_FREQ);    break;
-  case 6: _ctrl_read(HUANYANG_ACTUAL_CURRENT); break;
-  case 7: _ctrl_read(HUANYANG_ACTUAL_RPM);     break;
-  case 8: _ctrl_read(HUANYANG_TEMPERATURE);    break;
-  }
-
-  // Send command
-  modbus_func(hy.id, hy.func, hy.bytes, hy.data, hy.response, _modbus_cb);
-}
-
-
-void hy_init() {
-  modbus_init();
-  _reset(false);
-}
-
-
-void hy_deinit() {hy.shutdown = true;}
-
-
-void hy_set(float speed) {
-  if (hy.speed != speed) {
-    hy.speed = speed;
-    hy.changed = true;
-  }
-}
-
-
-void hy_stop() {
-  hy_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;}
-uint16_t get_hy_rated_rpm() {return hy.rated_rpm;}
-float get_hy_status() {return hy.status;}
diff --git a/src/avr/src/huanyang.h b/src/avr/src/huanyang.h
deleted file mode 100644 (file)
index 739199d..0000000
+++ /dev/null
@@ -1,225 +0,0 @@
-/******************************************************************************\
-
-                 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 <http://www.gnu.org/licenses/>.
-
-      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
-                        <http://www.gnu.org/licenses/>.
-
-                 For information regarding this software email:
-                   "Joseph Coffland" <joseph@buildbotics.com>
-
-\******************************************************************************/
-
-#pragma once
-
-#include "spindle.h"
-
-
-void hy_init();
-void hy_deinit();
-void hy_set(float speed);
-void hy_stop();
-
-
-/// See Huanyang VFD user manual
-typedef enum {
-  HY_PD000_PARAMETER_LOCK,
-  HY_PD001_SOURCE_OF_OPERATION_COMMANDS,
-  HY_PD002_SOURCE_OF_OPERATING_FREQUENCY,
-  HY_PD003_MAIN_FREQUENCY,
-  HY_PD004_BASE_FREQUENCY,
-  HY_PD005_MAX_FREQUENCY,
-  HY_PD006_INTERMEDIATE_FREQUENCY,
-  HY_PD007_MIN_FREQUENCY,
-  HY_PD008_MAX_VOLTAGE,
-  HY_PD009_INTERMEDIATE_VOLTAGE,
-  HY_PD010_MIN_VOLTAGE,
-  HY_PD011_FREQUENCY_LOWER_LIMIT,
-  HY_PD012_RESERVED,
-  HY_PD013_PARAMETER_RESET,
-  HY_PD014_ACCEL_TIME_1,
-  HY_PD015_DECEL_TIME_1,
-  HY_PD016_ACCEL_TIME_2,
-  HY_PD017_DECEL_TIME_2,
-  HY_PD018_ACCEL_TIME_3,
-  HY_PD019_DECEL_TIME_3,
-  HY_PD020_ACCEL_TIME_4,
-  HY_PD021_DECEL_TIME_4,
-  HY_PD022_FACTORY_RESERVED,
-  HY_PD023_REV_ROTATION_SELECT,
-  HY_PD024_STOP_KEY,
-  HY_PD025_STARTING_MODE,
-  HY_PD026_STOPPING_MODE,
-  HY_PD027_STARTING_FREQUENCY,
-  HY_PD028_STOPPING_FREQUENCY,
-  HY_PD029_DC_BRAKING_TIME_AT_START,
-  HY_PD030_DC_BRAKING_TIME_AT_STOP,
-  HY_PD031_DC_BRAKING_VOLTAGE_LEVEL,
-  HY_PD032_FREQUENCY_TRACK_TIME,
-  HY_PD033_CURRENT_LEVEL_FOR_FREQUENCY_TRACK,
-  HY_PD034_VOLTAGE_RISE_TIME_FOR_FREQUENCY_TRACK,
-  HY_PD035_FREQUENCY_STEP_LENGTH,
-  HY_PD036,
-  HY_PD037,
-  HY_PD038,
-  HY_PD039,
-  HY_PD040,
-  HY_PD041_CARRIER_FREQUENCY,
-  HY_PD042_JOGGING_FREQUENCY,
-  HY_PD043_S_CURVE_TIME,
-  HY_PD044_MULTI_INPUT_FOR,
-  HY_PD045_MULTI_INPUT_REV,
-  HY_PD046_MULTI_INPUT_RST,
-  HY_PD047_MULTI_INPUT_SPH,
-  HY_PD048_MULTI_INPUT_SPM,
-  HY_PD049_MULTI_INPUT_SPL,
-  HY_PD050_MULTI_OUTPUT_DRV,
-  HY_PD051_MULTI_OUTPUT_UPF,
-  HY_PD052_MULTI_OUTPUT_FA_FB_FC,
-  HY_PD053_MULTI_OUTPUT_KA_KB,
-  HY_PD054_MULTI_OUTPUT_AM,
-  HY_PD055_AM_ANALOG_OUTPUT_GAIN,
-  HY_PD056_SKIP_FREQUENCY_1,
-  HY_PD057_SKIP_FREQUENCY_2,
-  HY_PD058_SKIP_FREQUENCY_3,
-  HY_PD059_SKIP_FREQUENCY_RANGE,
-  HY_PD060_UNIFORM_FREQUENCY_1,
-  HY_PD061_UNIFORM_FREQUENCY_2,
-  HY_PD062_UNIFORM_FREQUENCY_RANGE,
-  HY_PD063_TIMER_1_TIME,
-  HY_PD064_TIMER_2_TIME,
-  HY_PD065_COUNTING_VALUE,
-  HY_PD066_INTERMEDIATE_COUNTER,
-  HY_PD067,
-  HY_PD068,
-  HY_PD069,
-  HY_PD070_ANALOG_INPUT,
-  HY_PD071_ANALOG_FILTERING_CONSTANT,
-  HY_PD072_HIGHER_ANALOG_FREQUENCY,
-  HY_PD073_LOWER_ANALOG_FREQUENCY,
-  HY_PD074_BIAS_DIRECTION_AT_HIGHER_FREQUENCY,
-  HY_PD075_BIAS_DIRECTION_AT_LOWER_FREQUENCY,
-  HY_PD076_ANALOG_NEGATIVE_BIAS_REVERSE,
-  HY_PD077_UP_DOWN_FUNCTION,
-  HY_PD078_UP_DOWN_SPEED,
-  HY_PD079,
-  HY_PD080_PLC_OPERATION,
-  HY_PD081_AUTO_PLC,
-  HY_PD082_PLC_RUNNING_DIRECTION,
-  HY_PD083,
-  HY_PD084_PLC_RAMP_TIME,
-  HY_PD085,
-  HY_PD086_FREQUENCY_2,
-  HY_PD087_FREQUENCY_3,
-  HY_PD088_FREQUENCY_4,
-  HY_PD089_FREQUENCY_5,
-  HY_PD090_FREQUENCY_6,
-  HY_PD091_FREQUENCY_7,
-  HY_PD092_FREQUENCY_8,
-  HY_PD093,
-  HY_PD094,
-  HY_PD095,
-  HY_PD096,
-  HY_PD097,
-  HY_PD098,
-  HY_PD099,
-  HY_PD100,
-  HY_PD101_TIMER_1,
-  HY_PD102_TIMER_2,
-  HY_PD103_TIMER_3,
-  HY_PD104_TIMER_4,
-  HY_PD105_TIMER_5,
-  HY_PD106_TIMER_6,
-  HY_PD107_TIMER_7,
-  HY_PD108_TIMER_8,
-  HY_PD109,
-  HY_PD110,
-  HY_PD111,
-  HY_PD112,
-  HY_PD113,
-  HY_PD114,
-  HY_PD115,
-  HY_PD116,
-  HY_PD117_AUTOPLC_MEMORY_FUNCTION,
-  HY_PD118_OVER_VOLTAGE_STALL_PREVENTION,
-  HY_PD119_STALL_PREVENTION_LEVEL_AT_RAMP_UP,
-  HY_PD120_STALL_PREVENTION_LEVEL_AT_CONSTANT_SPEED,
-  HY_PD121_DECEL_TIME_FOR_STALL_PREVENTION_AT_CONSTANT_SPEED,
-  HY_PD122_STALL_PREVENTION_LEVEL_AT_DECELERATION,
-  HY_PD123_OVER_TORQUE_DETECT_MODE,
-  HY_PD124_OVER_TORQUE_DETECT_LEVEL,
-  HY_PD125_OVER_TORQUE_DETECT_TIME,
-  HY_PD126,
-  HY_PD127,
-  HY_PD128,
-  HY_PD129,
-  HY_PD130_NUMBER_OF_AUXILIARY_PUMP,
-  HY_PD131_CONTINUOUS_RUNNING_TIME_OF_AUXILIARY_PUMPS,
-  HY_PD132_INTERLOCKING_TIME_OF_AUXILIARY_PUMP,
-  HY_PD133_HIGH_SPEED_RUNNING_TIME,
-  HY_PD134_LOW_SPEED_RUNNING_TIME,
-  HY_PD135_STOPPING_VOLTAGE_LEVEL,
-  HY_PD136_LASTING_TIME_OF_STOPPING_VOLTAGE_LEVEL,
-  HY_PD137_WAKEUP_VOLTAGE_LEVEL,
-  HY_PD138_SLEEP_FREQUENCY,
-  HY_PD139_LASTING_TIME_OF_SLEEP_FREQUENCY,
-  HY_PD140,
-  HY_PD141_RATED_MOTOR_VOLTAGE,
-  HY_PD142_RATED_MOTOR_CURRENT,
-  HY_PD143_MOTOR_POLE_NUMBER,
-  HY_PD144_RATED_MOTOR_RPM,
-  HY_PD145_AUTO_TORQUE_COMPENSATION,
-  HY_PD146_MOTOR_NO_LOAD_CURRENT,
-  HY_PD147_MOTOR_SLIP_COMPENSATION,
-  HY_PD148,
-  HY_PD149,
-  HY_PD150_AUTO_VOLTAGE_REGULATION,
-  HY_PD151_AUTO_ENERGY_SAVING,
-  HY_PD152_FAULT_RESTART_TIME,
-  HY_PD153_RESTART_AFTER_INSTANTANEOUS_STOP,
-  HY_PD154_ALLOWABLE_POWER_BREAKDOWN_TIME,
-  HY_PD155_NUMBER_OF_ABNORMAL_RESTART,
-  HY_PD156_PROPORTIONAL_CONSTANT,
-  HY_PD157_INTEGRAL_TIME,
-  HY_PD158_DIFFERENTIAL_TIME,
-  HY_PD159_TARGET_VALUE,
-  HY_PD160_PID_TARGET_VALUE,
-  HY_PD161_PID_UPPER_LIMIT,
-  HY_PD162_PID_LOWER_LIMIT,
-  HY_PD163_COMMUNICATION_ADDRESSES,
-  HY_PD164_COMMUNICATION_BAUD_RATE,
-  HY_PD165_COMMUNICATION_DATA_METHOD,
-  HY_PD166,
-  HY_PD167,
-  HY_PD168,
-  HY_PD169,
-  HY_PD170_DISPLAY_ITEMS,
-  HY_PD171_DISPLAY_ITEMS_OPEN,
-  HY_PD172_FAULT_CLEAR,
-  HY_PD173,
-  HY_PD174_RATED_CURRENT_OF_INVERTER,
-  HY_PD175_INVERTER_MODEL,
-  HY_PD176_INVERTER_FREQUENCY_STANDARD,
-  HY_PD177_FAULT_RECORD_1,
-  HY_PD178_FAULT_RECORD_2,
-  HY_PD179_FAULT_RECORD_3,
-  HY_PD180_FAULT_RECORD_4,
-  HY_PD181_SOFTWARE_VERSION,
-  HY_PD182_MANUFACTURE_DATE,
-  HY_PD183_SERIAL_NO,
-} hy_addr_t;
index 5877224ee952d312c21c4eeff1f258271f87d215..94b3da72ab21662d912c60443cd7ebf0f643b2ed 100644 (file)
@@ -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
index 1d76f512fdcddd130fda2782df326bb826277e54..99217707a7e301b66b92f231f45fc27d59088993 100644 (file)
 
 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);
 }
 
 
index 802791ea7f4ae761731522ae151aa8455d9ed9c6..0a36d32dde344e71433200542fc98ead10a07ce7 100644 (file)
@@ -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();
index f93a9cf32f64c1abbc9d1d6acb594e4d8b8394cf..80d2d8a62e67ffee6ee8520b5498d93d6d5166b6 100644 (file)
@@ -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;}
 
 
index fe29f2812256c1169b6e825a162842c6f07a46ef..996020db1429e4aa837ee978728845b66d1507d4 100644 (file)
@@ -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();
index bc931ad36b73530e9e89c28708029ab566dc9331..0af9ccb01074fbba3b19ea55736ea58d49215e8d 100644 (file)
 #include "spindle.h"
 
 #include "config.h"
-#include "pwm_spindle.h"
-#include "huanyang.h"
 #include "pgmspace.h"
 
+#include <math.h>
+
 
 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 (file)
index 0000000..1022568
--- /dev/null
@@ -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 <http://www.gnu.org/licenses/>.
+
+      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
+                        <http://www.gnu.org/licenses/>.
+
+                 For information regarding this software email:
+                   "Joseph Coffland" <joseph@buildbotics.com>
+
+\******************************************************************************/
+
+SPINDLE(pwm_spindle)
+SPINDLE(huanyang)
+SPINDLE(yl600)
index 5473877c6e64d342e8a89cc5e6095119444f7c83..b15eb00ab3b00c16b571ce364abe15a56cdc976a 100644 (file)
@@ -29,7 +29,7 @@
 
 #include <stdbool.h>
 
-void spindle_init();
+
 void spindle_set_speed(float speed);
 float spindle_get_speed();
 void spindle_stop();
index 55876a66d70fbf1d40ea798071e4cfc442c9536f..a8e465841320814f65796102652e53e7a02060ca 100644 (file)
@@ -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;
index 77a63494caf02365abc69fec215ce740b9a96ded..b61bc421f21b75d64d4302ce82bb332c1b9c8922 100644 (file)
@@ -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);
index c2d324612069cb7751d2b0594e7c017b8a260b31..91a8b95705e935b58a2d6ddf79fa509c19f086b6 100644 (file)
@@ -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/vfd/huanyang.c b/src/avr/src/vfd/huanyang.c
new file mode 100644 (file)
index 0000000..259c006
--- /dev/null
@@ -0,0 +1,331 @@
+/******************************************************************************\
+
+                 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 <http://www.gnu.org/licenses/>.
+
+      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
+                        <http://www.gnu.org/licenses/>.
+
+                 For information regarding this software email:
+                   "Joseph Coffland" <joseph@buildbotics.com>
+
+\******************************************************************************/
+
+#include "huanyang.h"
+#include "config.h"
+#include "modbus.h"
+#include "report.h"
+
+#include <string.h>
+#include <math.h>
+
+
+/*
+  Huanyang is not quite Modbus compliant.
+
+  Message format is:
+
+    [id][func][length][data][checksum]
+
+  Where:
+
+     id       - 1-byte Peer ID
+     func     - 1-byte One of hy_func_t
+     length   - 1-byte Length data in bytes
+     data     - length bytes - Command arguments
+     checksum - 16-bit CRC: x^16 + x^15 + x^2 + 1 (0xa001) initial: 0xffff
+*/
+
+
+// See VFD manual pg56 3.1.3
+typedef enum {
+  HUANYANG_FUNC_READ = 1, // [len=1][hy_addr_t]
+  HUANYANG_FUNC_WRITE,    // [len=3][hy_addr_t][data]
+  HUANYANG_CTRL_WRITE,    // [len=1][hy_ctrl_state_t]
+  HUANYANG_CTRL_READ,     // [len=1][hy_ctrl_addr_t]
+  HUANYANG_FREQ_WRITE,    // [len=2][freq]
+  HUANYANG_RESERVED_1,
+  HUANYANG_RESERVED_2,
+  HUANYANG_LOOP_TEST,
+} hy_func_t;
+
+
+// Sent in HUANYANG_CTRL_WRITE
+// See VFD manual pg57 3.1.3.c
+typedef enum {
+  HUANYANG_RUN         = 1 << 0,
+  HUANYANG_FORWARD     = 1 << 1,
+  HUANYANG_REVERSE     = 1 << 2,
+  HUANYANG_STOP        = 1 << 3,
+  HUANYANG_REV_FWD     = 1 << 4,
+  HUANYANG_JOG         = 1 << 5,
+  HUANYANG_JOG_FORWARD = 1 << 6,
+  HUANYANG_JOG_REVERSE = 1 << 7,
+} hy_ctrl_state_t;
+
+
+// Returned by HUANYANG_CTRL_WRITE
+// See VFD manual pg57 3.1.3.c
+typedef enum {
+  HUANYANG_STATUS_RUN         = 1 << 0,
+  HUANYANG_STATUS_JOG         = 1 << 1,
+  HUANYANG_STATUS_COMMAND_REV = 1 << 2,
+  HUANYANG_STATUS_RUNNING     = 1 << 3,
+  HUANYANG_STATUS_JOGGING     = 1 << 4,
+  HUANYANG_STATUS_JOGGING_REV = 1 << 5,
+  HUANYANG_STATUS_BRAKING     = 1 << 6,
+  HUANYANG_STATUS_TRACK_START = 1 << 7,
+} hy_ctrl_status_t;
+
+
+// Sent in HUANYANG_CTRL_READ
+// See VFD manual pg57 3.1.3.d
+typedef enum {
+  HUANYANG_TARGET_FREQ,
+  HUANYANG_ACTUAL_FREQ,
+  HUANYANG_ACTUAL_CURRENT,
+  HUANYANG_ACTUAL_RPM,
+  HUANYANG_DCV,
+  HUANYANG_ACV,
+  HUANYANG_COUNTER,
+  HUANYANG_TEMPERATURE,
+} hy_ctrl_addr_t;
+
+
+static struct {
+  uint8_t state;
+  hy_func_t func;
+  uint8_t data[4];
+  uint8_t bytes;
+  uint8_t response;
+
+  bool shutdown;
+  bool changed;
+  float speed;
+
+  float actual_freq;
+  float actual_current;
+  uint16_t actual_rpm;
+  uint16_t temperature;
+
+  float max_freq;
+  float min_freq;
+  uint16_t rated_rpm;
+
+  uint8_t status;
+} hy = {0};
+
+
+static void _func_read(hy_addr_t addr) {
+  hy.func     = HUANYANG_FUNC_READ;
+  hy.bytes    = 2;
+  hy.response = 4;
+  hy.data[0]  = 1;
+  hy.data[1]  = addr;
+}
+
+
+static void _ctrl_write(hy_ctrl_state_t state) {
+  hy.func     = HUANYANG_CTRL_WRITE;
+  hy.bytes    = 2;
+  hy.response = 2;
+  hy.data[0]  = 1;
+  hy.data[1]  = state;
+}
+
+
+static void _ctrl_read(hy_ctrl_addr_t addr) {
+  hy.func     = HUANYANG_CTRL_READ;
+  hy.bytes    = 2;
+  hy.response = 4;
+  hy.data[0]  = 1;
+  hy.data[1]  = addr;
+}
+
+
+static void _freq_write(uint16_t freq) {
+  hy.func     = HUANYANG_FREQ_WRITE;
+  hy.bytes    = 3;
+  hy.response = 3;
+  hy.data[0]  = 2;
+  hy.data[1]  = freq >> 8;
+  hy.data[2]  = freq;
+}
+
+
+static void _func_read_response(hy_addr_t addr, uint16_t value) {
+  switch (addr) {
+  case HY_PD005_MAX_FREQUENCY:         hy.max_freq  = value * 0.01; break;
+  case HY_PD011_FREQUENCY_LOWER_LIMIT: hy.min_freq  = value * 0.01; break;
+  case HY_PD144_RATED_MOTOR_RPM:       hy.rated_rpm = value;        break;
+  default: break;
+  }
+}
+
+
+static void _ctrl_read_response(hy_ctrl_addr_t addr, uint16_t value) {
+  switch (addr) {
+  case HUANYANG_ACTUAL_FREQ:    hy.actual_freq    = value * 0.01; break;
+  case HUANYANG_ACTUAL_CURRENT: hy.actual_current = value * 0.01; break;
+  case HUANYANG_ACTUAL_RPM:     hy.actual_rpm     = value;        break;
+  case HUANYANG_TEMPERATURE:    hy.temperature    = value;        break;
+  default: break;
+  }
+}
+
+
+static uint16_t _read_word(const uint8_t *data) {
+  return (uint16_t)data[0] << 8 | data[1];
+}
+
+
+static void _handle_response(hy_func_t func, const uint8_t *data) {
+  switch (func) {
+  case HUANYANG_FUNC_READ:
+    _func_read_response((hy_addr_t)*data, _read_word(data + 1));
+    break;
+
+  case HUANYANG_FUNC_WRITE: break;
+  case HUANYANG_CTRL_WRITE: hy.status = *data; break;
+
+  case HUANYANG_CTRL_READ:
+    _ctrl_read_response((hy_ctrl_addr_t)*data, _read_word(data + 1));
+    break;
+
+  case HUANYANG_FREQ_WRITE: break;
+  default: break;
+  }
+}
+
+
+static void _next_command();
+
+
+static void _reset(bool halt) {
+  // Save settings
+  float speed = hy.speed;
+
+  // Clear state
+  memset(&hy, 0, sizeof(hy));
+
+  // Restore settings
+  hy.speed = speed;
+  hy.changed = true;
+
+  if (!halt) _next_command();
+}
+
+
+static void _modbus_cb(uint8_t func, uint8_t bytes, const uint8_t *data) {
+  if (!data) _reset(true);
+
+  else if (bytes == *data + 1) {
+    _handle_response((hy_func_t)func, data + 1);
+
+    if (func == HUANYANG_CTRL_WRITE && hy.shutdown) {
+      _reset(true);
+      modbus_deinit();
+      return;
+    }
+
+    // Next command
+    if (++hy.state == 9) {
+      hy.state = 5;
+      report_request();
+    }
+
+    // Update freq
+    if (hy.shutdown || (hy.changed && 4 < hy.state)) hy.state = 0;
+  }
+
+  _next_command();
+}
+
+
+static void _next_command() {
+  switch (hy.state) {
+  case 0: { // Update direction
+    hy_ctrl_state_t state = HUANYANG_STOP;
+    if (!hy.shutdown) {
+      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);
+    }
+
+    _ctrl_write(state);
+    break;
+  }
+
+  case 1: _func_read(HY_PD005_MAX_FREQUENCY); break;
+  case 2: _func_read(HY_PD011_FREQUENCY_LOWER_LIMIT); break;
+  case 3: _func_read(HY_PD144_RATED_MOTOR_RPM); break;
+
+  case 4: { // Update freqency
+    // Compute frequency in Hz
+    float freq = fabs(hy.speed * hy.max_freq);
+
+    // Frequency write command
+    _freq_write(freq * 100);
+    hy.changed = false;
+    break;
+  }
+
+  case 5: _ctrl_read(HUANYANG_ACTUAL_FREQ);    break;
+  case 6: _ctrl_read(HUANYANG_ACTUAL_CURRENT); break;
+  case 7: _ctrl_read(HUANYANG_ACTUAL_RPM);     break;
+  case 8: _ctrl_read(HUANYANG_TEMPERATURE);    break;
+  }
+
+  // Send command
+  modbus_func(hy.func, hy.bytes, hy.data, hy.response, _modbus_cb);
+}
+
+
+void huanyang_init() {
+  modbus_init();
+  _reset(false);
+}
+
+
+void huanyang_deinit() {hy.shutdown = true;}
+
+
+void huanyang_set(float speed) {
+  if (hy.speed != speed) {
+    hy.speed = speed;
+    hy.changed = true;
+  }
+}
+
+
+float huanyang_get() {return hy.actual_freq / hy.max_freq;}
+
+
+void huanyang_stop() {
+  huanyang_set(0);
+  _reset(false);
+}
+
+
+float get_hy_freq() {return hy.actual_freq;}
+float get_hy_current() {return hy.actual_current;}
+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;}
+uint16_t get_hy_rated_rpm() {return hy.rated_rpm;}
+float get_hy_status() {return hy.status;}
diff --git a/src/avr/src/vfd/huanyang.h b/src/avr/src/vfd/huanyang.h
new file mode 100644 (file)
index 0000000..c5b88af
--- /dev/null
@@ -0,0 +1,224 @@
+/******************************************************************************\
+
+                 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 <http://www.gnu.org/licenses/>.
+
+      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
+                        <http://www.gnu.org/licenses/>.
+
+                 For information regarding this software email:
+                   "Joseph Coffland" <joseph@buildbotics.com>
+
+\******************************************************************************/
+
+#pragma once
+
+
+void huanyang_init();
+void huanyang_deinit();
+void huanyang_set(float speed);
+float huanyang_get();
+void huanyang_stop();
+
+
+/// See Huanyang VFD user manual
+typedef enum {
+  HY_PD000_PARAMETER_LOCK,
+  HY_PD001_SOURCE_OF_OPERATION_COMMANDS,
+  HY_PD002_SOURCE_OF_OPERATING_FREQUENCY,
+  HY_PD003_MAIN_FREQUENCY,
+  HY_PD004_BASE_FREQUENCY,
+  HY_PD005_MAX_FREQUENCY,
+  HY_PD006_INTERMEDIATE_FREQUENCY,
+  HY_PD007_MIN_FREQUENCY,
+  HY_PD008_MAX_VOLTAGE,
+  HY_PD009_INTERMEDIATE_VOLTAGE,
+  HY_PD010_MIN_VOLTAGE,
+  HY_PD011_FREQUENCY_LOWER_LIMIT,
+  HY_PD012_RESERVED,
+  HY_PD013_PARAMETER_RESET,
+  HY_PD014_ACCEL_TIME_1,
+  HY_PD015_DECEL_TIME_1,
+  HY_PD016_ACCEL_TIME_2,
+  HY_PD017_DECEL_TIME_2,
+  HY_PD018_ACCEL_TIME_3,
+  HY_PD019_DECEL_TIME_3,
+  HY_PD020_ACCEL_TIME_4,
+  HY_PD021_DECEL_TIME_4,
+  HY_PD022_FACTORY_RESERVED,
+  HY_PD023_REV_ROTATION_SELECT,
+  HY_PD024_STOP_KEY,
+  HY_PD025_STARTING_MODE,
+  HY_PD026_STOPPING_MODE,
+  HY_PD027_STARTING_FREQUENCY,
+  HY_PD028_STOPPING_FREQUENCY,
+  HY_PD029_DC_BRAKING_TIME_AT_START,
+  HY_PD030_DC_BRAKING_TIME_AT_STOP,
+  HY_PD031_DC_BRAKING_VOLTAGE_LEVEL,
+  HY_PD032_FREQUENCY_TRACK_TIME,
+  HY_PD033_CURRENT_LEVEL_FOR_FREQUENCY_TRACK,
+  HY_PD034_VOLTAGE_RISE_TIME_FOR_FREQUENCY_TRACK,
+  HY_PD035_FREQUENCY_STEP_LENGTH,
+  HY_PD036,
+  HY_PD037,
+  HY_PD038,
+  HY_PD039,
+  HY_PD040,
+  HY_PD041_CARRIER_FREQUENCY,
+  HY_PD042_JOGGING_FREQUENCY,
+  HY_PD043_S_CURVE_TIME,
+  HY_PD044_MULTI_INPUT_FOR,
+  HY_PD045_MULTI_INPUT_REV,
+  HY_PD046_MULTI_INPUT_RST,
+  HY_PD047_MULTI_INPUT_SPH,
+  HY_PD048_MULTI_INPUT_SPM,
+  HY_PD049_MULTI_INPUT_SPL,
+  HY_PD050_MULTI_OUTPUT_DRV,
+  HY_PD051_MULTI_OUTPUT_UPF,
+  HY_PD052_MULTI_OUTPUT_FA_FB_FC,
+  HY_PD053_MULTI_OUTPUT_KA_KB,
+  HY_PD054_MULTI_OUTPUT_AM,
+  HY_PD055_AM_ANALOG_OUTPUT_GAIN,
+  HY_PD056_SKIP_FREQUENCY_1,
+  HY_PD057_SKIP_FREQUENCY_2,
+  HY_PD058_SKIP_FREQUENCY_3,
+  HY_PD059_SKIP_FREQUENCY_RANGE,
+  HY_PD060_UNIFORM_FREQUENCY_1,
+  HY_PD061_UNIFORM_FREQUENCY_2,
+  HY_PD062_UNIFORM_FREQUENCY_RANGE,
+  HY_PD063_TIMER_1_TIME,
+  HY_PD064_TIMER_2_TIME,
+  HY_PD065_COUNTING_VALUE,
+  HY_PD066_INTERMEDIATE_COUNTER,
+  HY_PD067,
+  HY_PD068,
+  HY_PD069,
+  HY_PD070_ANALOG_INPUT,
+  HY_PD071_ANALOG_FILTERING_CONSTANT,
+  HY_PD072_HIGHER_ANALOG_FREQUENCY,
+  HY_PD073_LOWER_ANALOG_FREQUENCY,
+  HY_PD074_BIAS_DIRECTION_AT_HIGHER_FREQUENCY,
+  HY_PD075_BIAS_DIRECTION_AT_LOWER_FREQUENCY,
+  HY_PD076_ANALOG_NEGATIVE_BIAS_REVERSE,
+  HY_PD077_UP_DOWN_FUNCTION,
+  HY_PD078_UP_DOWN_SPEED,
+  HY_PD079,
+  HY_PD080_PLC_OPERATION,
+  HY_PD081_AUTO_PLC,
+  HY_PD082_PLC_RUNNING_DIRECTION,
+  HY_PD083,
+  HY_PD084_PLC_RAMP_TIME,
+  HY_PD085,
+  HY_PD086_FREQUENCY_2,
+  HY_PD087_FREQUENCY_3,
+  HY_PD088_FREQUENCY_4,
+  HY_PD089_FREQUENCY_5,
+  HY_PD090_FREQUENCY_6,
+  HY_PD091_FREQUENCY_7,
+  HY_PD092_FREQUENCY_8,
+  HY_PD093,
+  HY_PD094,
+  HY_PD095,
+  HY_PD096,
+  HY_PD097,
+  HY_PD098,
+  HY_PD099,
+  HY_PD100,
+  HY_PD101_TIMER_1,
+  HY_PD102_TIMER_2,
+  HY_PD103_TIMER_3,
+  HY_PD104_TIMER_4,
+  HY_PD105_TIMER_5,
+  HY_PD106_TIMER_6,
+  HY_PD107_TIMER_7,
+  HY_PD108_TIMER_8,
+  HY_PD109,
+  HY_PD110,
+  HY_PD111,
+  HY_PD112,
+  HY_PD113,
+  HY_PD114,
+  HY_PD115,
+  HY_PD116,
+  HY_PD117_AUTOPLC_MEMORY_FUNCTION,
+  HY_PD118_OVER_VOLTAGE_STALL_PREVENTION,
+  HY_PD119_STALL_PREVENTION_LEVEL_AT_RAMP_UP,
+  HY_PD120_STALL_PREVENTION_LEVEL_AT_CONSTANT_SPEED,
+  HY_PD121_DECEL_TIME_FOR_STALL_PREVENTION_AT_CONSTANT_SPEED,
+  HY_PD122_STALL_PREVENTION_LEVEL_AT_DECELERATION,
+  HY_PD123_OVER_TORQUE_DETECT_MODE,
+  HY_PD124_OVER_TORQUE_DETECT_LEVEL,
+  HY_PD125_OVER_TORQUE_DETECT_TIME,
+  HY_PD126,
+  HY_PD127,
+  HY_PD128,
+  HY_PD129,
+  HY_PD130_NUMBER_OF_AUXILIARY_PUMP,
+  HY_PD131_CONTINUOUS_RUNNING_TIME_OF_AUXILIARY_PUMPS,
+  HY_PD132_INTERLOCKING_TIME_OF_AUXILIARY_PUMP,
+  HY_PD133_HIGH_SPEED_RUNNING_TIME,
+  HY_PD134_LOW_SPEED_RUNNING_TIME,
+  HY_PD135_STOPPING_VOLTAGE_LEVEL,
+  HY_PD136_LASTING_TIME_OF_STOPPING_VOLTAGE_LEVEL,
+  HY_PD137_WAKEUP_VOLTAGE_LEVEL,
+  HY_PD138_SLEEP_FREQUENCY,
+  HY_PD139_LASTING_TIME_OF_SLEEP_FREQUENCY,
+  HY_PD140,
+  HY_PD141_RATED_MOTOR_VOLTAGE,
+  HY_PD142_RATED_MOTOR_CURRENT,
+  HY_PD143_MOTOR_POLE_NUMBER,
+  HY_PD144_RATED_MOTOR_RPM,
+  HY_PD145_AUTO_TORQUE_COMPENSATION,
+  HY_PD146_MOTOR_NO_LOAD_CURRENT,
+  HY_PD147_MOTOR_SLIP_COMPENSATION,
+  HY_PD148,
+  HY_PD149,
+  HY_PD150_AUTO_VOLTAGE_REGULATION,
+  HY_PD151_AUTO_ENERGY_SAVING,
+  HY_PD152_FAULT_RESTART_TIME,
+  HY_PD153_RESTART_AFTER_INSTANTANEOUS_STOP,
+  HY_PD154_ALLOWABLE_POWER_BREAKDOWN_TIME,
+  HY_PD155_NUMBER_OF_ABNORMAL_RESTART,
+  HY_PD156_PROPORTIONAL_CONSTANT,
+  HY_PD157_INTEGRAL_TIME,
+  HY_PD158_DIFFERENTIAL_TIME,
+  HY_PD159_TARGET_VALUE,
+  HY_PD160_PID_TARGET_VALUE,
+  HY_PD161_PID_UPPER_LIMIT,
+  HY_PD162_PID_LOWER_LIMIT,
+  HY_PD163_COMMUNICATION_ADDRESSES,
+  HY_PD164_COMMUNICATION_BAUD_RATE,
+  HY_PD165_COMMUNICATION_DATA_METHOD,
+  HY_PD166,
+  HY_PD167,
+  HY_PD168,
+  HY_PD169,
+  HY_PD170_DISPLAY_ITEMS,
+  HY_PD171_DISPLAY_ITEMS_OPEN,
+  HY_PD172_FAULT_CLEAR,
+  HY_PD173,
+  HY_PD174_RATED_CURRENT_OF_INVERTER,
+  HY_PD175_INVERTER_MODEL,
+  HY_PD176_INVERTER_FREQUENCY_STANDARD,
+  HY_PD177_FAULT_RECORD_1,
+  HY_PD178_FAULT_RECORD_2,
+  HY_PD179_FAULT_RECORD_3,
+  HY_PD180_FAULT_RECORD_4,
+  HY_PD181_SOFTWARE_VERSION,
+  HY_PD182_MANUFACTURE_DATE,
+  HY_PD183_SERIAL_NO,
+} hy_addr_t;
diff --git a/src/avr/src/vfd/yl600.c b/src/avr/src/vfd/yl600.c
new file mode 100644 (file)
index 0000000..e91e901
--- /dev/null
@@ -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 <http://www.gnu.org/licenses/>.
+
+      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
+                        <http://www.gnu.org/licenses/>.
+
+                 For information regarding this software email:
+                   "Joseph Coffland" <joseph@buildbotics.com>
+
+\******************************************************************************/
+
+
+#include "modbus.h"
+
+#include <math.h>
+
+
+#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);}
index b3d1163176f32515004382cbad3e71d8a96069b2..17a4c900a7b18af30b599a9637b3a0ea1b7321de 100644 (file)
@@ -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
index d22e5d33ddc923e7ed36c6c2ed0f1b76a2044c57..8be586fa3621013f34ef72a8cd304c9e38acfb55 100644 (file)
@@ -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']",
index 731942b671516a90d87b9574b8846489cb3c83fe..498fe3cac563a1ef6b864d008113572bf460da04 100644 (file)
@@ -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));
     }
index c1bf508ba86e61e313e7785d4e43cb3be07443b7..412698e5bb04390a6f2a0e3def644cda64e9a516 100644 (file)
   "tool": {
     "spindle-type": {
       "type": "enum",
-      "values": ["Disabled", "PWM", "Huanyang", "Modbus"],
+      "values": ["Disabled", "PWM", "Huanyang", "YL600"],
       "default": "Disabled",
       "code": "st"
     },
       "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",
     }
   },
 
-  "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",