From: Joseph Coffland Date: Sat, 2 Jan 2016 06:04:06 +0000 (-0800) Subject: Preliminary TMC2660 driver X-Git-Url: https://git.buildbotics.com/?a=commitdiff_plain;h=0c29237a2198dadd3ed0c3725d2dce468645953f;p=bbctrl-firmware Preliminary TMC2660 driver --- diff --git a/Makefile b/Makefile index b4d1208..1db20ee 100755 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ # Makefile for the project TinyG firmware PROJECT = tinyg -MCU = atxmega192a3 +MCU = atxmega192a3u CLOCK = 32000000 TARGET = $(PROJECT).elf @@ -12,8 +12,8 @@ CPP = avr-g++ COMMON = -mmcu=$(MCU) CFLAGS += $(COMMON) -CFLAGS += -gdwarf-2 -std=gnu99 -Wall -Werror -DF_CPU=$(CLOCK)UL -Os -funsigned-char -CFLAGS += -funsigned-bitfields -fpack-struct -fshort-enums +CFLAGS += -gdwarf-2 -std=gnu99 -Wall -Werror -DF_CPU=$(CLOCK)UL -Os +CFLAGS += -funsigned-bitfields -fpack-struct -fshort-enums -funsigned-char CFLAGS += -MD -MP -MT $@ -MF build/dep/$(@F).d # Linker flags diff --git a/src/config.h b/src/config.h index 2d80ff9..078f5a0 100644 --- a/src/config.h +++ b/src/config.h @@ -164,88 +164,72 @@ * largest possible operation - usually the status report. */ -/*********************************************************************************** - **** DEFINITIONS AND SETTINGS ***************************************************** - ***********************************************************************************/ +#include // Sizing and footprints // chose one based on # of elements in cfgArray -//typedef uint8_t index_t; // use this if there are < 256 indexed objects -typedef uint16_t index_t; // use this if there are > 255 indexed objects +//typedef uint8_t index_t; // use this if there are < 256 indexed objects +typedef uint16_t index_t; // use this if there are > 255 indexed objects // defines allocated from stack (not-pre-allocated) -#define NV_FORMAT_LEN 128 // print formatting string max length -#define NV_MESSAGE_LEN 128 // sufficient space to contain end-user messages +#define NV_FORMAT_LEN 128 // print formatting string max length +#define NV_MESSAGE_LEN 128 // sufficient space to contain end-user messages // pre-allocated defines (take RAM permanently) #define NV_SHARED_STRING_LEN 512 // shared string for string values -#define NV_BODY_LEN 30 // body elements - allow for 1 parent + N children +#define NV_BODY_LEN 30 // body elements - allow for 1 parent + N children // (each body element takes about 30 bytes of RAM) // Stuff you probably don't want to change -#define GROUP_LEN 3 // max length of group prefix -#define TOKEN_LEN 5 // mnemonic token string: group prefix + short token -#define NV_FOOTER_LEN 18 // sufficient space to contain a JSON footer array -#define NV_LIST_LEN (NV_BODY_LEN+2) // +2 allows for a header and a footer -#define NV_MAX_OBJECTS (NV_BODY_LEN-1) // maximum number of objects in a body string +#define GROUP_LEN 3 // max length of group prefix +#define TOKEN_LEN 5 // mnemonic token string: group prefix + short token +#define NV_FOOTER_LEN 18 // sufficient space to contain a JSON footer array +#define NV_LIST_LEN (NV_BODY_LEN+2) // +2 allows for a header and a footer +#define NV_MAX_OBJECTS (NV_BODY_LEN-1) // maximum number of objects in a body string #define NO_MATCH (index_t)0xFFFF #define NV_STATUS_REPORT_LEN NV_MAX_OBJECTS // max number of status report elements - see cfgArray // **** must also line up in cfgArray, se00 - seXX **** enum tgCommunicationsMode { - TEXT_MODE = 0, // text command line mode - JSON_MODE, // strict JSON construction + TEXT_MODE = 0, // text command line mode + JSON_MODE, // strict JSON construction JSON_MODE_RELAXED // relaxed JSON construction (future) }; enum flowControl { - FLOW_CONTROL_OFF = 0, // flow control disabled - FLOW_CONTROL_XON, // flow control uses XON/XOFF + FLOW_CONTROL_OFF = 0, // flow control disabled + FLOW_CONTROL_XON, // flow control uses XON/XOFF FLOW_CONTROL_RTS // flow control uses RTS/CTS }; -/* -enum lineTermination { // REMOVED. Too easy to make the board non-responsive (not a total brick, but close) - IGNORE_OFF = 0, // accept either CR or LF as termination on RX text line - IGNORE_CR, // ignore CR on RX - IGNORE_LF // ignore LF on RX -}; -*/ -/* -enum tgCommunicationsSticky { - NOT_STICKY = 0, // communications mode changes automatically - STICKY // communications mode does not change -}; -*/ - enum valueType { // value typing for config and JSON TYPE_EMPTY = -1, // value struct is empty (which is not the same as "0") - TYPE_0 = 0, // value is 'null' (meaning the JSON null value) - TYPE_BOOL, // value is "true" (1) or "false"(0) - TYPE_INTEGER, // value is a uint32_t - TYPE_DATA, // value is blind cast to uint32_t - TYPE_FLOAT, // value is a floating point number + TYPE_0 = 0, // value is 'null' (meaning the JSON null value) + TYPE_BOOL, // value is "true" (1) or "false"(0) + TYPE_INTEGER, // value is a uint32_t + TYPE_DATA, // value is blind cast to uint32_t + TYPE_FLOAT, // value is a floating point number TYPE_STRING, // value is in string field - TYPE_ARRAY, // value is array element count, values are CSV ASCII in string field - TYPE_PARENT // object is a parent to a sub-object + TYPE_ARRAY, // value is array element count, values are CSV ASCII in string field + TYPE_PARENT // object is a parent to a sub-object }; /**** operations flags and shorthand ****/ #define F_INITIALIZE 0x01 // initialize this item (run set during initialization) -#define F_PERSIST 0x02 // persist this item when set is run -#define F_NOSTRIP 0x04 // do not strip the group prefix from the token -#define F_CONVERT 0x08 // set if unit conversion is required - -#define _f0 0x00 -#define _fi (F_INITIALIZE) -#define _fp (F_PERSIST) -#define _fn (F_NOSTRIP) -#define _fc (F_CONVERT) +#define F_PERSIST 0x02 // persist this item when set is run +#define F_NOSTRIP 0x04 // do not strip the group prefix from the token +#define F_CONVERT 0x08 // set if unit conversion is required + +#define _f0 0x00 +#define _fi (F_INITIALIZE) +#define _fp (F_PERSIST) +#define _fn (F_NOSTRIP) +#define _fc (F_CONVERT) #define _fip (F_INITIALIZE | F_PERSIST) -#define _fipc (F_INITIALIZE | F_PERSIST | F_CONVERT) -#define _fipn (F_INITIALIZE | F_PERSIST | F_NOSTRIP) -#define _fipnc (F_INITIALIZE | F_PERSIST | F_NOSTRIP | F_CONVERT) +#define _fipc (F_INITIALIZE | F_PERSIST | F_CONVERT) +#define _fipn (F_INITIALIZE | F_PERSIST | F_NOSTRIP) +#define _fipnc (F_INITIALIZE | F_PERSIST | F_NOSTRIP | F_CONVERT) /**** Structures ****/ diff --git a/src/controller.h b/src/controller.h index 9a85b53..5d5421d 100644 --- a/src/controller.h +++ b/src/controller.h @@ -70,9 +70,9 @@ extern controller_t cs; // controller state structure enum cmControllerState { // manages startup lines CONTROLLER_INITIALIZING = 0, // controller is initializing - not ready for use - CONTROLLER_NOT_CONNECTED, // controller has not yet detected connection to USB (or other comm channel) - CONTROLLER_CONNECTED, // controller has connected to USB (or other comm channel) - CONTROLLER_STARTUP, // controller is running startup messages and lines + CONTROLLER_NOT_CONNECTED, // controller has not yet detected connection to comm channel + CONTROLLER_CONNECTED, // controller has connected to comm channel + CONTROLLER_STARTUP, // controller is running startup messages and lines CONTROLLER_READY // controller is active and ready for use }; diff --git a/src/hardware.h b/src/hardware.h index 0cf848f..9c40629 100644 --- a/src/hardware.h +++ b/src/hardware.h @@ -36,8 +36,8 @@ * HI Dwell timer counter (set in stepper.h) * LO Segment execution SW interrupt (set in stepper.h) * MED GPIO1 switch port (set in gpio.h) - * MED Serial RX for USB & RS-485 (set in usart.c) - * MED Serial TX for USB & RS-485 (set in usart.c) (* see note) + * MED Serial RX (set in usart.c) + * MED Serial TX (set in usart.c) (* see note) * LO Real time clock interrupt (set in xmega_rtc.h) * * (*) The TX cannot run at LO level or exception reports and other prints @@ -49,34 +49,14 @@ #ifndef HARDWARE_H_ONCE #define HARDWARE_H_ONCE -/*--- Hardware platform enumerations ---*/ - enum hwPlatform { HM_PLATFORM_NONE = 0, - HW_PLATFORM_TINYG_XMEGA, // TinyG code base on Xmega boards. - // hwVersion 7 = TinyG v7 and earlier - // hwVersion 8 = TinyG v8 - - HW_PLATFORM_G2_DUE, // G2 code base on native Arduino Due - - HW_PLATFORM_TINYG_V9 // G2 code base on v9 boards - // hwVersion 0 = v9c - // hwVersion 1 = v9d - // hwVersion 2 = v9f - // hwVersion 3 = v9h - // hwVersion 4 = v9i }; -#define HW_VERSION_TINYGV6 6 -#define HW_VERSION_TINYGV7 7 -#define HW_VERSION_TINYGV8 8 - -#define HW_VERSION_TINYGV9C 0 -#define HW_VERSION_TINYGV9D 1 -#define HW_VERSION_TINYGV9F 2 -#define HW_VERSION_TINYGV9H 3 -#define HW_VERSION_TINYGV9I 4 +#define HW_VERSION_TINYGV6 6 +#define HW_VERSION_TINYGV7 7 +#define HW_VERSION_TINYGV8 8 #include "config.h" // needed for the stat_t typedef #include @@ -95,40 +75,40 @@ enum hwPlatform { *** These are not all the same, and must line up in multiple places in gpio.h *** * Sorry if this is confusing - it's a board routing issue */ -#define PORT_MOTOR_1 PORTA // motors mapped to ports +#define PORT_MOTOR_1 PORTA // motors mapped to ports #define PORT_MOTOR_2 PORTF -#define PORT_MOTOR_3 PORTE -#define PORT_MOTOR_4 PORTD +#define PORT_MOTOR_3 PORTE +#define PORT_MOTOR_4 PORTD -#define PORT_SWITCH_X PORTA // Switch axes mapped to ports -#define PORT_SWITCH_Y PORTD -#define PORT_SWITCH_Z PORTE -#define PORT_SWITCH_A PORTF +#define PORT_SWITCH_X PORTA // Switch axes mapped to ports +#define PORT_SWITCH_Y PORTD +#define PORT_SWITCH_Z PORTE +#define PORT_SWITCH_A PORTF #define PORT_OUT_V7_X PORTA // v7 mapping - Output bits mapped to ports -#define PORT_OUT_V7_Y PORTF +#define PORT_OUT_V7_Y PORTF #define PORT_OUT_V7_Z PORTD #define PORT_OUT_V7_A PORTE #define PORT_OUT_V6_X PORTA // v6 and earlier mapping - Output bits mapped to ports -#define PORT_OUT_V6_Y PORTF +#define PORT_OUT_V6_Y PORTF #define PORT_OUT_V6_Z PORTE #define PORT_OUT_V6_A PORTD // These next four must be changed when the PORT_MOTOR_* definitions change! -#define PORTCFG_VP0MAP_PORT_MOTOR_1_gc PORTCFG_VP0MAP_PORTA_gc -#define PORTCFG_VP1MAP_PORT_MOTOR_2_gc PORTCFG_VP1MAP_PORTF_gc -#define PORTCFG_VP2MAP_PORT_MOTOR_3_gc PORTCFG_VP2MAP_PORTE_gc -#define PORTCFG_VP3MAP_PORT_MOTOR_4_gc PORTCFG_VP3MAP_PORTD_gc +#define PORTCFG_VP0MAP_PORT_MOTOR_1_gc PORTCFG_VP02MAP_PORTA_gc +#define PORTCFG_VP1MAP_PORT_MOTOR_2_gc PORTCFG_VP13MAP_PORTF_gc +#define PORTCFG_VP2MAP_PORT_MOTOR_3_gc PORTCFG_VP02MAP_PORTE_gc +#define PORTCFG_VP3MAP_PORT_MOTOR_4_gc PORTCFG_VP13MAP_PORTD_gc -#define PORT_MOTOR_1_VPORT VPORT0 -#define PORT_MOTOR_2_VPORT VPORT1 -#define PORT_MOTOR_3_VPORT VPORT2 -#define PORT_MOTOR_4_VPORT VPORT3 +#define PORT_MOTOR_1_VPORT VPORT0 +#define PORT_MOTOR_2_VPORT VPORT1 +#define PORT_MOTOR_3_VPORT VPORT2 +#define PORT_MOTOR_4_VPORT VPORT3 /* * Port setup - Stepper / Switch Ports: - * b0 (out) step (SET is step, CLR is rest) + * b0 (out) step (SET is step, CLR is rest) * b1 (out) direction (CLR = Clockwise) * b2 (out) motor enable (CLR = Enabled) * b3 (out) microstep 0 @@ -139,33 +119,33 @@ enum hwPlatform { */ #define MOTOR_PORT_DIR_gm 0x3F // dir settings: lower 6 out, upper 2 in -enum cfgPortBits { // motor control port bit positions +enum cfgPortBits { // motor control port bit positions STEP_BIT_bp = 0, // bit 0 - DIRECTION_BIT_bp, // bit 1 + DIRECTION_BIT_bp, // bit 1 MOTOR_ENABLE_BIT_bp, // bit 2 - MICROSTEP_BIT_0_bp, // bit 3 - MICROSTEP_BIT_1_bp, // bit 4 - GPIO1_OUT_BIT_bp, // bit 5 (4 gpio1 output bits; 1 from each axis) - SW_MIN_BIT_bp, // bit 6 (4 input bits for homing/limit switches) - SW_MAX_BIT_bp // bit 7 (4 input bits for homing/limit switches) + MICROSTEP_BIT_0_bp, // bit 3 + MICROSTEP_BIT_1_bp, // bit 4 + GPIO1_OUT_BIT_bp, // bit 5 (4 gpio1 output bits; 1 from each axis) + SW_MIN_BIT_bp, // bit 6 (4 input bits for homing/limit switches) + SW_MAX_BIT_bp // bit 7 (4 input bits for homing/limit switches) }; -#define STEP_BIT_bm (1< #include "xmega/xmega_interrupts.h" @@ -50,6 +51,7 @@ static void init() { usart_init(); // serial port // do these next + tmc2660_init(); // motor drivers stepper_init(); // stepper subsystem encoder_init(); // virtual encoders switch_init(); // switches diff --git a/src/report.c b/src/report.c index 96dc2ff..b5289e5 100644 --- a/src/report.c +++ b/src/report.c @@ -52,16 +52,16 @@ rxSingleton_t rx; */ stat_t rpt_exception(uint8_t status) { - if (status != STAT_OK) { // makes it possible to call exception reports w/o checking status value - if (js.json_syntax == JSON_SYNTAX_RELAXED) { - printf_P(PSTR("{er:{fb:%0.2f,st:%d,msg:\"%s\"}}\n"), - TINYG_FIRMWARE_BUILD, status, get_status_message(status)); - } else { - printf_P(PSTR("{\"er\":{\"fb\":%0.2f,\"st\":%d,\"msg\":\"%s\"}}\n"), - TINYG_FIRMWARE_BUILD, status, get_status_message(status)); - } + if (status != STAT_OK) { // makes it possible to call exception reports w/o checking status value + if (js.json_syntax == JSON_SYNTAX_RELAXED) { + printf_P(PSTR("{er:{fb:%0.2f,st:%d,msg:\"%s\"}}\n"), + TINYG_FIRMWARE_BUILD, status, get_status_message(status)); + } else { + printf_P(PSTR("{\"er\":{\"fb\":%0.2f,\"st\":%d,\"msg\":\"%s\"}}\n"), + TINYG_FIRMWARE_BUILD, status, get_status_message(status)); } - return status; // makes it possible to inline, e.g: return(rpt_exception(status)); + } + return status; // makes it possible to inline, e.g: return(rpt_exception(status)); } /* @@ -69,7 +69,7 @@ stat_t rpt_exception(uint8_t status) */ stat_t rpt_er(nvObj_t *nv) { - return(rpt_exception(STAT_GENERIC_EXCEPTION_REPORT)); // bogus exception report for testing + return(rpt_exception(STAT_GENERIC_EXCEPTION_REPORT)); // bogus exception report for testing } /**** Application Messages ********************************************************* @@ -84,33 +84,33 @@ stat_t rpt_er(nvObj_t *nv) void _startup_helper(stat_t status, const char *msg) { #ifndef __SUPPRESS_STARTUP_MESSAGES - js.json_footer_depth = JSON_FOOTER_DEPTH; //++++ temporary until changeover is complete - nv_reset_nv_list(); - nv_add_object((const char_t *)"fv"); // firmware version - nv_add_object((const char_t *)"fb"); // firmware build - nv_add_object((const char_t *)"hp"); // hardware platform - nv_add_object((const char_t *)"hv"); // hardware version - nv_add_object((const char_t *)"id"); // hardware ID - nv_add_string((const char_t *)"msg", pstr2str(msg)); // startup message - json_print_response(status); + js.json_footer_depth = JSON_FOOTER_DEPTH; //++++ temporary until changeover is complete + nv_reset_nv_list(); + nv_add_object((const char_t *)"fv"); // firmware version + nv_add_object((const char_t *)"fb"); // firmware build + nv_add_object((const char_t *)"hp"); // hardware platform + nv_add_object((const char_t *)"hv"); // hardware version + nv_add_object((const char_t *)"id"); // hardware ID + nv_add_string((const char_t *)"msg", pstr2str(msg)); // startup message + json_print_response(status); #endif } void rpt_print_initializing_message() { - _startup_helper(STAT_INITIALIZING, PSTR(INIT_MESSAGE)); + _startup_helper(STAT_INITIALIZING, PSTR(INIT_MESSAGE)); } void rpt_print_loading_configs_message() { - _startup_helper(STAT_INITIALIZING, PSTR("Loading configs from EEPROM")); + _startup_helper(STAT_INITIALIZING, PSTR("Loading configs from EEPROM")); } void rpt_print_system_ready_message() { - _startup_helper(STAT_OK, PSTR("SYSTEM READY")); - if (cfg.comm_mode == TEXT_MODE) - text_response(STAT_OK, (char_t *)""); // prompt + _startup_helper(STAT_OK, PSTR("SYSTEM READY")); + if (cfg.comm_mode == TEXT_MODE) + text_response(STAT_OK, (char_t *)""); // prompt } /***************************************************************************** @@ -160,11 +160,11 @@ static uint8_t _populate_filtered_status_report(); uint8_t _is_stat(nvObj_t *nv) { - char_t tok[TOKEN_LEN+1]; + char_t tok[TOKEN_LEN+1]; - GET_TOKEN_STRING(nv->value, tok); - if (strcmp(tok, "stat") == 0) { return true;} - return false; + GET_TOKEN_STRING(nv->value, tok); + if (strcmp(tok, "stat") == 0) { return true;} + return false; } /* @@ -175,26 +175,26 @@ uint8_t _is_stat(nvObj_t *nv) */ void sr_init_status_report() { - nvObj_t *nv = nv_reset_nv_list(); // used for status report persistence locations - sr.status_report_requested = false; - char_t sr_defaults[NV_STATUS_REPORT_LEN][TOKEN_LEN+1] = { STATUS_REPORT_DEFAULTS }; // see settings.h - nv->index = nv_get_index((const char_t *)"", (const char_t *)"se00"); // set first SR persistence index - sr.stat_index = 0; - - for (uint8_t i=0; i < NV_STATUS_REPORT_LEN ; i++) { - if (sr_defaults[i][0] == 0) break; // quit on first blank array entry - sr.status_report_value[i] = -1234567; // pre-load values with an unlikely number - nv->value = nv_get_index((const char_t *)"", sr_defaults[i]);// load the index for the SR element - if (nv->value == NO_MATCH) { - rpt_exception(STAT_BAD_STATUS_REPORT_SETTING); // trap mis-configured profile settings - return; - } - if (_is_stat(nv) == true) - sr.stat_index = nv->value; // identify index for 'stat' if status is in the report - nv_set(nv); - nv_persist(nv); // conditionally persist - automatic by nv_persist() - nv->index++; // increment SR NVM index + nvObj_t *nv = nv_reset_nv_list(); // used for status report persistence locations + sr.status_report_requested = false; + char_t sr_defaults[NV_STATUS_REPORT_LEN][TOKEN_LEN+1] = { STATUS_REPORT_DEFAULTS }; // see settings.h + nv->index = nv_get_index((const char_t *)"", (const char_t *)"se00"); // set first SR persistence index + sr.stat_index = 0; + + for (uint8_t i=0; i < NV_STATUS_REPORT_LEN ; i++) { + if (sr_defaults[i][0] == 0) break; // quit on first blank array entry + sr.status_report_value[i] = -1234567; // pre-load values with an unlikely number + nv->value = nv_get_index((const char_t *)"", sr_defaults[i]);// load the index for the SR element + if (nv->value == NO_MATCH) { + rpt_exception(STAT_BAD_STATUS_REPORT_SETTING); // trap mis-configured profile settings + return; } + if (_is_stat(nv) == true) + sr.stat_index = nv->value; // identify index for 'stat' if status is in the report + nv_set(nv); + nv_persist(nv); // conditionally persist - automatic by nv_persist() + nv->index++; // increment SR NVM index + } } /* @@ -206,27 +206,27 @@ void sr_init_status_report() */ stat_t sr_set_status_report(nvObj_t *nv) { - uint8_t elements = 0; - index_t status_report_list[NV_STATUS_REPORT_LEN]; - memset(status_report_list, 0, sizeof(status_report_list)); - index_t sr_start = nv_get_index((const char_t *)"",(const char_t *)"se00");// set first SR persistence index - - for (uint8_t i=0; inx) == 0) || (nv->valuetype == TYPE_EMPTY)) break; - if ((nv->valuetype == TYPE_BOOL) && (fp_TRUE(nv->value))) { - status_report_list[i] = nv->index; - nv->value = nv->index; // persist the index as the value - nv->index = sr_start + i; // index of the SR persistence location - nv_persist(nv); - elements++; - } else { - return STAT_UNRECOGNIZED_NAME; - } + uint8_t elements = 0; + index_t status_report_list[NV_STATUS_REPORT_LEN]; + memset(status_report_list, 0, sizeof(status_report_list)); + index_t sr_start = nv_get_index((const char_t *)"",(const char_t *)"se00");// set first SR persistence index + + for (uint8_t i=0; inx) == 0) || (nv->valuetype == TYPE_EMPTY)) break; + if ((nv->valuetype == TYPE_BOOL) && (fp_TRUE(nv->value))) { + status_report_list[i] = nv->index; + nv->value = nv->index; // persist the index as the value + nv->index = sr_start + i; // index of the SR persistence location + nv_persist(nv); + elements++; + } else { + return STAT_UNRECOGNIZED_NAME; } - if (elements == 0) - return STAT_INVALID_OR_MALFORMED_COMMAND; - memcpy(sr.status_report_list, status_report_list, sizeof(status_report_list)); - return(_populate_unfiltered_status_report()); // return current values + } + if (elements == 0) + return STAT_INVALID_OR_MALFORMED_COMMAND; + memcpy(sr.status_report_list, status_report_list, sizeof(status_report_list)); + return(_populate_unfiltered_status_report()); // return current values } /* @@ -243,42 +243,42 @@ stat_t sr_set_status_report(nvObj_t *nv) */ stat_t sr_request_status_report(uint8_t request_type) { - if (request_type == SR_IMMEDIATE_REQUEST) { - sr.status_report_systick = SysTickTimer_getValue(); - } - if ((request_type == SR_TIMED_REQUEST) && (sr.status_report_requested == false)) { - sr.status_report_systick = SysTickTimer_getValue() + sr.status_report_interval; - } - sr.status_report_requested = true; - return STAT_OK; + if (request_type == SR_IMMEDIATE_REQUEST) { + sr.status_report_systick = SysTickTimer_getValue(); + } + if ((request_type == SR_TIMED_REQUEST) && (sr.status_report_requested == false)) { + sr.status_report_systick = SysTickTimer_getValue() + sr.status_report_interval; + } + sr.status_report_requested = true; + return STAT_OK; } stat_t sr_status_report_callback() // called by controller dispatcher { #ifdef __SUPPRESS_STATUS_REPORTS - return STAT_NOOP; + return STAT_NOOP; #endif - if (sr.status_report_verbosity == SR_OFF) - return STAT_NOOP; + if (sr.status_report_verbosity == SR_OFF) + return STAT_NOOP; - if (sr.status_report_requested == false) - return STAT_NOOP; + if (sr.status_report_requested == false) + return STAT_NOOP; - if (SysTickTimer_getValue() < sr.status_report_systick) - return STAT_NOOP; + if (SysTickTimer_getValue() < sr.status_report_systick) + return STAT_NOOP; - sr.status_report_requested = false; // disable reports until requested again + sr.status_report_requested = false; // disable reports until requested again - if (sr.status_report_verbosity == SR_VERBOSE) { - _populate_unfiltered_status_report(); - } else { - if (_populate_filtered_status_report() == false) { // no new data - return STAT_OK; - } + if (sr.status_report_verbosity == SR_VERBOSE) { + _populate_unfiltered_status_report(); + } else { + if (_populate_filtered_status_report() == false) { // no new data + return STAT_OK; } - nv_print_list(STAT_OK, TEXT_INLINE_PAIRS, JSON_OBJECT_FORMAT); - return STAT_OK; + } + nv_print_list(STAT_OK, TEXT_INLINE_PAIRS, JSON_OBJECT_FORMAT); + return STAT_OK; } /* @@ -286,9 +286,9 @@ stat_t sr_status_report_callback() // called by controller dispatcher */ stat_t sr_run_text_status_report() { - _populate_unfiltered_status_report(); - nv_print_list(STAT_OK, TEXT_MULTILINE_FORMATTED, JSON_RESPONSE_FORMAT); - return STAT_OK; + _populate_unfiltered_status_report(); + nv_print_list(STAT_OK, TEXT_MULTILINE_FORMATTED, JSON_RESPONSE_FORMAT); + return STAT_OK; } /* @@ -298,27 +298,27 @@ stat_t sr_run_text_status_report() */ static stat_t _populate_unfiltered_status_report() { - const char_t sr_str[] = "sr"; - char_t tmp[TOKEN_LEN+1]; - nvObj_t *nv = nv_reset_nv_list(); // sets *nv to the start of the body - - nv->valuetype = TYPE_PARENT; // setup the parent object (no length checking required) - strcpy(nv->token, sr_str); - nv->index = nv_get_index((const char_t *)"", sr_str);// set the index - may be needed by calling function - nv = nv->nx; // no need to check for 0 as list has just been reset - - for (uint8_t i=0; iindex = sr.status_report_list[i]) == 0) { break;} - nv_get_nvObj(nv); - - strcpy(tmp, nv->group); // flatten out groups - WARNING - you cannot use strncpy here... - strcat(tmp, nv->token); - strcpy(nv->token, tmp); //...or here. - - if ((nv = nv->nx) == 0) - return cm_hard_alarm(STAT_BUFFER_FULL_FATAL); // should never be 0 unless SR length exceeds available buffer array - } - return STAT_OK; + const char_t sr_str[] = "sr"; + char_t tmp[TOKEN_LEN+1]; + nvObj_t *nv = nv_reset_nv_list(); // sets *nv to the start of the body + + nv->valuetype = TYPE_PARENT; // setup the parent object (no length checking required) + strcpy(nv->token, sr_str); + nv->index = nv_get_index((const char_t *)"", sr_str);// set the index - may be needed by calling function + nv = nv->nx; // no need to check for 0 as list has just been reset + + for (uint8_t i=0; iindex = sr.status_report_list[i]) == 0) { break;} + nv_get_nvObj(nv); + + strcpy(tmp, nv->group); // flatten out groups - WARNING - you cannot use strncpy here... + strcat(tmp, nv->token); + strcpy(nv->token, tmp); //...or here. + + if ((nv = nv->nx) == 0) + return cm_hard_alarm(STAT_BUFFER_FULL_FATAL); // should never be 0 unless SR length exceeds available buffer array + } + return STAT_OK; } /* @@ -336,40 +336,40 @@ static stat_t _populate_unfiltered_status_report() */ static uint8_t _populate_filtered_status_report() { - const char_t sr_str[] = "sr"; - uint8_t has_data = false; - char_t tmp[TOKEN_LEN+1]; - nvObj_t *nv = nv_reset_nv_list(); // sets nv to the start of the body - - nv->valuetype = TYPE_PARENT; // setup the parent object (no need to length check the copy) - strcpy(nv->token, sr_str); -// nv->index = nv_get_index((const char_t *)"", sr_str);// OMITTED - set the index - may be needed by calling function - nv = nv->nx; // no need to check for 0 as list has just been reset - - for (uint8_t i=0; iindex = sr.status_report_list[i]) == 0) { break;} - - nv_get_nvObj(nv); - // do not report values that have not changed... - // ...except for stat=3 (STOP), which is an exception - if (fp_EQ(nv->value, sr.status_report_value[i])) { -// if (nv->index != sr.stat_index) { -// if (fp_EQ(nv->value, COMBINED_PROGRAM_STOP)) { - nv->valuetype = TYPE_EMPTY; - continue; -// } -// } - // report anything that has changed - } else { - strcpy(tmp, nv->group); // flatten out groups - WARNING - you cannot use strncpy here... - strcat(tmp, nv->token); - strcpy(nv->token, tmp); //...or here. - sr.status_report_value[i] = nv->value; - if ((nv = nv->nx) == 0) return false; // should never be 0 unless SR length exceeds available buffer array - has_data = true; - } + const char_t sr_str[] = "sr"; + uint8_t has_data = false; + char_t tmp[TOKEN_LEN+1]; + nvObj_t *nv = nv_reset_nv_list(); // sets nv to the start of the body + + nv->valuetype = TYPE_PARENT; // setup the parent object (no need to length check the copy) + strcpy(nv->token, sr_str); + // nv->index = nv_get_index((const char_t *)"", sr_str);// OMITTED - set the index - may be needed by calling function + nv = nv->nx; // no need to check for 0 as list has just been reset + + for (uint8_t i=0; iindex = sr.status_report_list[i]) == 0) { break;} + + nv_get_nvObj(nv); + // do not report values that have not changed... + // ...except for stat=3 (STOP), which is an exception + if (fp_EQ(nv->value, sr.status_report_value[i])) { + // if (nv->index != sr.stat_index) { + // if (fp_EQ(nv->value, COMBINED_PROGRAM_STOP)) { + nv->valuetype = TYPE_EMPTY; + continue; + // } + // } + // report anything that has changed + } else { + strcpy(tmp, nv->group); // flatten out groups - WARNING - you cannot use strncpy here... + strcat(tmp, nv->token); + strcpy(nv->token, tmp); //...or here. + sr.status_report_value[i] = nv->value; + if ((nv = nv->nx) == 0) return false; // should never be 0 unless SR length exceeds available buffer array + has_data = true; } - return has_data; + } + return has_data; } /* @@ -384,9 +384,9 @@ stat_t sr_set(nvObj_t *nv) { return sr_set_status_report(nv);} stat_t sr_set_si(nvObj_t *nv) { - if (nv->value < STATUS_REPORT_MIN_MS) { nv->value = STATUS_REPORT_MIN_MS;} - sr.status_report_interval = (uint32_t)nv->value; - return(STAT_OK); + if (nv->value < STATUS_REPORT_MIN_MS) { nv->value = STATUS_REPORT_MIN_MS;} + sr.status_report_interval = (uint32_t)nv->value; + return(STAT_OK); } /********************* @@ -427,10 +427,10 @@ void sr_print_sv(nvObj_t *nv) { text_print_ui8(nv, fmt_sv);} */ void qr_init_queue_report() { - qr.queue_report_requested = false; - qr.buffers_added = 0; - qr.buffers_removed = 0; - qr.init_tick = SysTickTimer_getValue(); + qr.queue_report_requested = false; + qr.buffers_added = 0; + qr.buffers_removed = 0; + qr.init_tick = SysTickTimer_getValue(); } /* @@ -441,28 +441,28 @@ void qr_init_queue_report() */ void qr_request_queue_report(int8_t buffers) { - // get buffer depth and added/removed count - qr.buffers_available = mp_get_planner_buffers_available(); - if (buffers > 0) { - qr.buffers_added += buffers; - } else { - qr.buffers_removed -= buffers; - } - - // time-throttle requests while generating arcs - qr.motion_mode = cm_get_motion_mode(ACTIVE_MODEL); - if ((qr.motion_mode == MOTION_MODE_CW_ARC) || (qr.motion_mode == MOTION_MODE_CCW_ARC)) { - uint32_t tick = SysTickTimer_getValue(); - if (tick - qr.init_tick < MIN_ARC_QR_INTERVAL) { - qr.queue_report_requested = false; - return; - } + // get buffer depth and added/removed count + qr.buffers_available = mp_get_planner_buffers_available(); + if (buffers > 0) { + qr.buffers_added += buffers; + } else { + qr.buffers_removed -= buffers; + } + + // time-throttle requests while generating arcs + qr.motion_mode = cm_get_motion_mode(ACTIVE_MODEL); + if ((qr.motion_mode == MOTION_MODE_CW_ARC) || (qr.motion_mode == MOTION_MODE_CCW_ARC)) { + uint32_t tick = SysTickTimer_getValue(); + if (tick - qr.init_tick < MIN_ARC_QR_INTERVAL) { + qr.queue_report_requested = false; + return; } + } - // either return or request a report - if (qr.queue_report_verbosity != QR_OFF) { - qr.queue_report_requested = true; - } + // either return or request a report + if (qr.queue_report_verbosity != QR_OFF) { + qr.queue_report_requested = true; + } } /* @@ -471,50 +471,50 @@ void qr_request_queue_report(int8_t buffers) stat_t qr_queue_report_callback() // called by controller dispatcher { #ifdef __SUPPRESS_QUEUE_REPORTS - return STAT_NOOP; + return STAT_NOOP; #endif - if (qr.queue_report_verbosity == QR_OFF) - return STAT_NOOP; + if (qr.queue_report_verbosity == QR_OFF) + return STAT_NOOP; - if (qr.queue_report_requested == false) - return STAT_NOOP; + if (qr.queue_report_requested == false) + return STAT_NOOP; - qr.queue_report_requested = false; + qr.queue_report_requested = false; - if (cfg.comm_mode == TEXT_MODE) { - if (qr.queue_report_verbosity == QR_SINGLE) { - fprintf(stderr, "qr:%d\n", qr.buffers_available); - } else { - fprintf(stderr, "qr:%d, qi:%d, qo:%d\n", qr.buffers_available,qr.buffers_added,qr.buffers_removed); - } + if (cfg.comm_mode == TEXT_MODE) { + if (qr.queue_report_verbosity == QR_SINGLE) { + fprintf(stderr, "qr:%d\n", qr.buffers_available); + } else { + fprintf(stderr, "qr:%d, qi:%d, qo:%d\n", qr.buffers_available,qr.buffers_added,qr.buffers_removed); + } - } else if (js.json_syntax == JSON_SYNTAX_RELAXED) { - if (qr.queue_report_verbosity == QR_SINGLE) { - fprintf(stderr, "{qr:%d}\n", qr.buffers_available); - } else { - fprintf(stderr, "{qr:%d,qi:%d,qo:%d}\n", qr.buffers_available, qr.buffers_added,qr.buffers_removed); - } + } else if (js.json_syntax == JSON_SYNTAX_RELAXED) { + if (qr.queue_report_verbosity == QR_SINGLE) { + fprintf(stderr, "{qr:%d}\n", qr.buffers_available); + } else { + fprintf(stderr, "{qr:%d,qi:%d,qo:%d}\n", qr.buffers_available, qr.buffers_added,qr.buffers_removed); + } + } else { + if (qr.queue_report_verbosity == QR_SINGLE) { + fprintf(stderr, "{\"qr\":%d}\n", qr.buffers_available); } else { - if (qr.queue_report_verbosity == QR_SINGLE) { - fprintf(stderr, "{\"qr\":%d}\n", qr.buffers_available); - } else { - fprintf(stderr, "{\"qr\":%d,\"qi\":%d,\"qo\":%d}\n", qr.buffers_available, qr.buffers_added,qr.buffers_removed); - } + fprintf(stderr, "{\"qr\":%d,\"qi\":%d,\"qo\":%d}\n", qr.buffers_available, qr.buffers_added,qr.buffers_removed); } - qr_init_queue_report(); + } + qr_init_queue_report(); - return STAT_OK; + return STAT_OK; } /* - * rx_request_rx_report() - request an update on usb serial buffer space available + * rx_request_rx_report() - request an update on serial buffer space available */ void rx_request_rx_report() { - rx.rx_report_requested = true; - rx.space_available = usart_rx_space(); + rx.rx_report_requested = true; + rx.space_available = usart_rx_space(); } @@ -522,13 +522,13 @@ void rx_request_rx_report() { * rx_report_callback() - send rx report if one has been requested */ stat_t rx_report_callback() { - if (!rx.rx_report_requested) - return STAT_NOOP; + if (!rx.rx_report_requested) + return STAT_NOOP; - rx.rx_report_requested = false; + rx.rx_report_requested = false; - fprintf(stderr, "{\"rx\":%d}\n", rx.space_available); - return STAT_OK; + fprintf(stderr, "{\"rx\":%d}\n", rx.space_available); + return STAT_OK; } @@ -540,25 +540,25 @@ stat_t rx_report_callback() { * qo_get() - run a queue report - buffers out */ stat_t qr_get(nvObj_t *nv) { - nv->value = (float)mp_get_planner_buffers_available(); // ensure that manually requested QR count is always up to date - nv->valuetype = TYPE_INTEGER; - return STAT_OK; + nv->value = (float)mp_get_planner_buffers_available(); // ensure that manually requested QR count is always up to date + nv->valuetype = TYPE_INTEGER; + return STAT_OK; } stat_t qi_get(nvObj_t *nv) { - nv->value = (float)qr.buffers_added; - nv->valuetype = TYPE_INTEGER; - qr.buffers_added = 0; // reset it - return STAT_OK; + nv->value = (float)qr.buffers_added; + nv->valuetype = TYPE_INTEGER; + qr.buffers_added = 0; // reset it + return STAT_OK; } stat_t qo_get(nvObj_t *nv) { - nv->value = (float)qr.buffers_removed; - nv->valuetype = TYPE_INTEGER; - qr.buffers_removed = 0; // reset it - return STAT_OK; + nv->value = (float)qr.buffers_removed; + nv->valuetype = TYPE_INTEGER; + qr.buffers_removed = 0; // reset it + return STAT_OK; } @@ -573,61 +573,61 @@ stat_t qo_get(nvObj_t *nv) { * job_print_job() */ stat_t job_populate_job_report() { - const char_t job_str[] = "job"; - char_t tmp[TOKEN_LEN+1]; - nvObj_t *nv = nv_reset_nv_list(); // sets *nv to the start of the body + const char_t job_str[] = "job"; + char_t tmp[TOKEN_LEN+1]; + nvObj_t *nv = nv_reset_nv_list(); // sets *nv to the start of the body - nv->valuetype = TYPE_PARENT; // setup the parent object - strcpy(nv->token, job_str); + nv->valuetype = TYPE_PARENT; // setup the parent object + strcpy(nv->token, job_str); - //nv->index = nv_get_index((const char_t *)"", job_str);// set the index - may be needed by calling function - nv = nv->nx; // no need to check for 0 as list has just been reset + //nv->index = nv_get_index((const char_t *)"", job_str);// set the index - may be needed by calling function + nv = nv->nx; // no need to check for 0 as list has just been reset - index_t job_start = nv_get_index((const char_t *)"",(const char_t *)"job1");// set first job persistence index - for (uint8_t i=0; i<4; i++) { + index_t job_start = nv_get_index((const char_t *)"",(const char_t *)"job1");// set first job persistence index + for (uint8_t i=0; i<4; i++) { - nv->index = job_start + i; - nv_get_nvObj(nv); + nv->index = job_start + i; + nv_get_nvObj(nv); - strcpy(tmp, nv->group); // concatenate groups and tokens - do NOT use strncpy() - strcat(tmp, nv->token); - strcpy(nv->token, tmp); + strcpy(tmp, nv->group); // concatenate groups and tokens - do NOT use strncpy() + strcat(tmp, nv->token); + strcpy(nv->token, tmp); - if ((nv = nv->nx) == 0) - return STAT_OK; // should never be 0 unless SR length exceeds available buffer array - } - return STAT_OK; + if ((nv = nv->nx) == 0) + return STAT_OK; // should never be 0 unless SR length exceeds available buffer array + } + return STAT_OK; } stat_t job_set_job_report(nvObj_t *nv) { - index_t job_start = nv_get_index((const char_t *)"",(const char_t *)"job1");// set first job persistence index - - for (uint8_t i=0; i<4; i++) { - if (((nv = nv->nx) == 0) || (nv->valuetype == TYPE_EMPTY)) { break;} - if (nv->valuetype == TYPE_INTEGER) { - cs.job_id[i] = nv->value; - nv->index = job_start + i; // index of the SR persistence location - nv_persist(nv); - } else { - return STAT_UNSUPPORTED_TYPE; - } + index_t job_start = nv_get_index((const char_t *)"",(const char_t *)"job1");// set first job persistence index + + for (uint8_t i=0; i<4; i++) { + if (((nv = nv->nx) == 0) || (nv->valuetype == TYPE_EMPTY)) { break;} + if (nv->valuetype == TYPE_INTEGER) { + cs.job_id[i] = nv->value; + nv->index = job_start + i; // index of the SR persistence location + nv_persist(nv); + } else { + return STAT_UNSUPPORTED_TYPE; } - job_populate_job_report(); // return current values - return STAT_OK; + } + job_populate_job_report(); // return current values + return STAT_OK; } uint8_t job_report_callback() { - if (cfg.comm_mode == TEXT_MODE) { - // no-op, job_ids are client app state - } else if (js.json_syntax == JSON_SYNTAX_RELAXED) { - fprintf(stderr, "{job:[%lu,%lu,%lu,%lu]}\n", cs.job_id[0], cs.job_id[1], cs.job_id[2], cs.job_id[3] ); - } else { - fprintf(stderr, "{\"job\":[%lu,%lu,%lu,%lu]}\n", cs.job_id[0], cs.job_id[1], cs.job_id[2], cs.job_id[3] ); - //job_clear_report(); - } - return STAT_OK; + if (cfg.comm_mode == TEXT_MODE) { + // no-op, job_ids are client app state + } else if (js.json_syntax == JSON_SYNTAX_RELAXED) { + fprintf(stderr, "{job:[%lu,%lu,%lu,%lu]}\n", cs.job_id[0], cs.job_id[1], cs.job_id[2], cs.job_id[3] ); + } else { + fprintf(stderr, "{\"job\":[%lu,%lu,%lu,%lu]}\n", cs.job_id[0], cs.job_id[1], cs.job_id[2], cs.job_id[3] ); + //job_clear_report(); + } + return STAT_OK; } stat_t job_get(nvObj_t *nv) { return job_populate_job_report();} diff --git a/src/report.h b/src/report.h index 595717c..da41d0d 100644 --- a/src/report.h +++ b/src/report.h @@ -37,56 +37,56 @@ #define MIN_ARC_QR_INTERVAL 200 // minimum interval between QRs during arc generation (in system ticks) enum srVerbosity { // status report enable and verbosity - SR_OFF = 0, // no reports - SR_FILTERED, // reports only values that have changed from the last report - SR_VERBOSE // reports all values specified + SR_OFF = 0, // no reports + SR_FILTERED, // reports only values that have changed from the last report + SR_VERBOSE // reports all values specified }; enum cmStatusReportRequest { - SR_TIMED_REQUEST = 0, // request a status report at next timer interval - SR_IMMEDIATE_REQUEST // request a status report ASAP + SR_TIMED_REQUEST = 0, // request a status report at next timer interval + SR_IMMEDIATE_REQUEST // request a status report ASAP }; enum qrVerbosity { // planner queue enable and verbosity - QR_OFF = 0, // no response is provided - QR_SINGLE, // queue depth reported - QR_TRIPLE // queue depth reported for buffers, buffers added, buffered removed + QR_OFF = 0, // no response is provided + QR_SINGLE, // queue depth reported + QR_TRIPLE // queue depth reported for buffers, buffers added, buffered removed }; typedef struct srSingleton { - /*** config values (PUBLIC) ***/ - uint8_t status_report_verbosity; - uint32_t status_report_interval; // in milliseconds + /*** config values (PUBLIC) ***/ + uint8_t status_report_verbosity; + uint32_t status_report_interval; // in milliseconds - /*** runtime values (PRIVATE) ***/ - uint8_t status_report_requested; // flag that SR has been requested - uint32_t status_report_systick; // SysTick value for next status report - index_t stat_index; // table index value for stat - determined during initialization - index_t status_report_list[NV_STATUS_REPORT_LEN]; // status report elements to report - float status_report_value[NV_STATUS_REPORT_LEN]; // previous values for filtered reporting + /*** runtime values (PRIVATE) ***/ + uint8_t status_report_requested; // flag that SR has been requested + uint32_t status_report_systick; // SysTick value for next status report + index_t stat_index; // table index value for stat - determined during initialization + index_t status_report_list[NV_STATUS_REPORT_LEN]; // status report elements to report + float status_report_value[NV_STATUS_REPORT_LEN]; // previous values for filtered reporting } srSingleton_t; typedef struct qrSingleton { // data for queue reports - /*** config values (PUBLIC) ***/ - uint8_t queue_report_verbosity; // queue reports enabled and verbosity level + /*** config values (PUBLIC) ***/ + uint8_t queue_report_verbosity; // queue reports enabled and verbosity level - /*** runtime values (PRIVATE) ***/ - uint8_t queue_report_requested; // set to true to request a report - uint8_t buffers_available; // stored buffer depth passed to by callback - uint8_t prev_available; // buffers available at last count - uint16_t buffers_added; // buffers added since last count - uint16_t buffers_removed; // buffers removed since last report - uint8_t motion_mode; // used to detect arc movement - uint32_t init_tick; // time when values were last initialized or cleared + /*** runtime values (PRIVATE) ***/ + uint8_t queue_report_requested; // set to true to request a report + uint8_t buffers_available; // stored buffer depth passed to by callback + uint8_t prev_available; // buffers available at last count + uint16_t buffers_added; // buffers added since last count + uint16_t buffers_removed; // buffers removed since last report + uint8_t motion_mode; // used to detect arc movement + uint32_t init_tick; // time when values were last initialized or cleared } qrSingleton_t; typedef struct rxSingleton { - uint8_t rx_report_requested; - uint16_t space_available; // space available in usb rx buffer at time of request + uint8_t rx_report_requested; + uint16_t space_available; // space available in rx buffer at time of request } rxSingleton_t; /**** Externs - See report.c for allocation ****/ @@ -128,23 +128,23 @@ stat_t qo_get(nvObj_t *nv); #ifdef __TEXT_MODE - void sr_print_sr(nvObj_t *nv); - void sr_print_si(nvObj_t *nv); - void sr_print_sv(nvObj_t *nv); - void qr_print_qv(nvObj_t *nv); - void qr_print_qr(nvObj_t *nv); - void qr_print_qi(nvObj_t *nv); - void qr_print_qo(nvObj_t *nv); +void sr_print_sr(nvObj_t *nv); +void sr_print_si(nvObj_t *nv); +void sr_print_sv(nvObj_t *nv); +void qr_print_qv(nvObj_t *nv); +void qr_print_qr(nvObj_t *nv); +void qr_print_qi(nvObj_t *nv); +void qr_print_qo(nvObj_t *nv); #else - #define sr_print_sr tx_print_stub - #define sr_print_si tx_print_stub - #define sr_print_sv tx_print_stub - #define qr_print_qv tx_print_stub - #define qr_print_qr tx_print_stub - #define qr_print_qi tx_print_stub - #define qr_print_qo tx_print_stub +#define sr_print_sr tx_print_stub +#define sr_print_si tx_print_stub +#define sr_print_sv tx_print_stub +#define qr_print_qv tx_print_stub +#define qr_print_qr tx_print_stub +#define qr_print_qi tx_print_stub +#define qr_print_qo tx_print_stub #endif // __TEXT_MODE diff --git a/src/stepper.c b/src/stepper.c index 9301854..47b8123 100644 --- a/src/stepper.c +++ b/src/stepper.c @@ -25,8 +25,9 @@ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/* This module provides the low-level stepper drivers and some related functions. - * See stepper.h for a detailed explanation of this module. + +/* This module provides the low-level stepper drivers and some related functions. + * See stepper.h for a detailed explanation of this module. */ #include "tinyg.h" @@ -62,6 +63,7 @@ static void _request_load_move(); * - motor polarity is setup during config_init() * - high level interrupts must be enabled in main() once all inits are complete */ + /* NOTE: This is the bare code that the Motate timer calls replace. * NB: requires: #include * @@ -814,7 +816,6 @@ static int8_t _get_motor(const nvObj_t *nv) static void _set_motor_steps_per_unit(nvObj_t *nv) { uint8_t m = _get_motor(nv); -// st_cfg.mot[m].units_per_step = (st_cfg.mot[m].travel_rev * st_cfg.mot[m].step_angle) / (360 * st_cfg.mot[m].microsteps); // unused st_cfg.mot[m].steps_per_unit = (360 * st_cfg.mot[m].microsteps) / (st_cfg.mot[m].travel_rev * st_cfg.mot[m].step_angle); st_reset(); } diff --git a/src/tmc2660.c b/src/tmc2660.c new file mode 100644 index 0000000..c6a8164 --- /dev/null +++ b/src/tmc2660.c @@ -0,0 +1,237 @@ +/******************************************************************************\ + + This file is part of the TinyG firmware. + + Copyright (c) 2016, Buildbotics LLC + All rights reserved. + + The C! library is free software: you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License + as published by the Free Software Foundation, either version 2.1 of + the License, or (at your option) any later version. + + The C! library 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 C! library. If not, see + . + + In addition, BSD licensing may be granted on a case by case basis + by written permission from at least one of the copyright holders. + You may request written permission by emailing the authors. + + For information regarding this software email: + Joseph Coffland + joseph@buildbotics.com + +\******************************************************************************/ + +#include "tmc2660.h" + +#include +#include +#include + + +typedef enum { + TMC2660_STATE_CONFIG, + TMC2660_STATE_MONITOR, + TMC2660_STATE_RESET, +} tmc2660_state_t; + +typedef enum { + SPI_STATE_SELECT, + SPI_STATE_WRITE, + SPI_STATE_READ, +} spi_state_t; + +typedef struct { + uint16_t mstep; + uint8_t status; + uint32_t regs[5]; +} tmc2660_driver_t; + + +static const uint32_t reg_addrs[] = { + TMC2660_DRVCTRL_ADDR, + TMC2660_CHOPCONF_ADDR, + TMC2660_SMARTEN_ADDR, + TMC2660_SGCSCONF_ADDR, + TMC2660_DRVCONF_ADDR +}; + + +static volatile tmc2660_state_t state; +static volatile uint8_t driver; +static volatile uint8_t reg; +static tmc2660_driver_t drivers[TMC2660_NUM_DRIVERS]; + +static volatile spi_state_t spi_state; +static volatile uint8_t spi_byte; +static volatile uint32_t spi_out; +static volatile uint32_t spi_in; + + +static void spi_cs(int driver, int enable) { + if (enable) + switch (driver) { + case 0: TMC2660_SPI_SSX_PORT.OUTCLR = 1 << TMC2660_SPI_SSX_PIN; break; + case 1: TMC2660_SPI_SSY_PORT.OUTCLR = 1 << TMC2660_SPI_SSY_PIN; break; + case 2: TMC2660_SPI_SSZ_PORT.OUTCLR = 1 << TMC2660_SPI_SSZ_PIN; break; + case 3: TMC2660_SPI_SSA_PORT.OUTCLR = 1 << TMC2660_SPI_SSA_PIN; break; + case 4: TMC2660_SPI_SSB_PORT.OUTCLR = 1 << TMC2660_SPI_SSB_PIN; break; + } + else + switch (driver) { + case 0: TMC2660_SPI_SSX_PORT.OUTSET = 1 << TMC2660_SPI_SSX_PIN; break; + case 1: TMC2660_SPI_SSY_PORT.OUTSET = 1 << TMC2660_SPI_SSY_PIN; break; + case 2: TMC2660_SPI_SSZ_PORT.OUTSET = 1 << TMC2660_SPI_SSZ_PIN; break; + case 3: TMC2660_SPI_SSA_PORT.OUTSET = 1 << TMC2660_SPI_SSA_PIN; break; + case 4: TMC2660_SPI_SSB_PORT.OUTSET = 1 << TMC2660_SPI_SSB_PIN; break; + } +} + + + +static void spi_send() { + // Flush any status errors + // TODO check errors + uint8_t x = SPIC.STATUS; + x = x; + + // Read + if (!spi_byte) spi_in = 0; + else spi_in = spi_in << 8 | SPIC.DATA; + + // Write + if (spi_byte < 3) + SPIC.DATA = 0xff & (spi_out >> ((2 - spi_byte++) * 8)); + else spi_byte = 0; +} + + +void spi_next() { + switch (spi_state) { + case SPI_STATE_SELECT: + // Select driver + spi_cs(driver, 1); + + // Next state + TMC2660_TIMER.PER = 4; + spi_state = SPI_STATE_WRITE; + break; + + case SPI_STATE_WRITE: + spi_out = reg_addrs[reg] | drivers[driver].regs[reg]; + spi_send(); + + // Next state + TMC2660_TIMER.PER = 16; + spi_state = SPI_STATE_READ; + break; + + case SPI_STATE_READ: + // Deselect driver + spi_cs(driver, 0); + + // Read response + drivers[driver].mstep = (spi_in >> 14) & 0x3ff; + drivers[driver].status = spi_in >> 4; + + // Next state + spi_state = SPI_STATE_SELECT; + + if (++reg == 5) { + reg = 0; + if (++driver == TMC2660_NUM_DRIVERS) driver = 0; + + TMC2660_TIMER.PER = 10; + + } else TMC2660_TIMER.PER = 2; + break; + } +} + + +ISR(SPIC_INT_vect) { + spi_send(); +} + + +ISR(TCC1_OVF_vect) { + spi_next(); +} + + +void tmc2660_init() { + // Reset state + state = TMC2660_STATE_CONFIG; + spi_state = SPI_STATE_SELECT; + driver = reg = spi_byte = 0; + memset(drivers, 0, sizeof(drivers)); + + // Configure motors + for (int i = 0; i < TMC2660_NUM_DRIVERS; i++) { + drivers[i].regs[TMC2660_DRVCTRL] = 0; + drivers[i].regs[TMC2660_CHOPCONF] = 0x14557; + drivers[i].regs[TMC2660_SMARTEN] = 0x8202; + drivers[i].regs[TMC2660_SGCSCONF] = 0x1001f; + drivers[i].regs[TMC2660_DRVCONF] = 0x10; + } + + // Setup pins + TMC2660_SPI_PORT.OUTSET = 1 << 4; // High + TMC2660_SPI_PORT.DIRSET = 1 << 4; // Output + TMC2660_SPI_PORT.OUTSET = 1 << TMC2660_SPI_SCK_PIN; // High + TMC2660_SPI_PORT.DIRSET = 1 << TMC2660_SPI_SCK_PIN; // Output + TMC2660_SPI_PORT.DIRCLR = 1 << TMC2660_SPI_MISO_PIN; // Input + TMC2660_SPI_PORT.OUTSET = 1 << TMC2660_SPI_MOSI_PIN; // High + TMC2660_SPI_PORT.DIRSET = 1 << TMC2660_SPI_MOSI_PIN; // Output + +#if TMC2660_NUM_DRIVERS > 0 + TMC2660_SPI_SSX_PORT.OUTSET = 1 << TMC2660_SPI_SSX_PIN; // High + TMC2660_SPI_SSX_PORT.DIRSET = 1 << TMC2660_SPI_SSX_PIN; // Output +#endif +#if TMC2660_NUM_DRIVERS > 1 + TMC2660_SPI_SSY_PORT.OUTSET = 1 << TMC2660_SPI_SSY_PIN; // High + TMC2660_SPI_SSY_PORT.DIRSET = 1 << TMC2660_SPI_SSY_PIN; // Output +#endif +#if TMC2660_NUM_DRIVERS > 2 + TMC2660_SPI_SSZ_PORT.OUTSET = 1 << TMC2660_SPI_SSZ_PIN; // High + TMC2660_SPI_SSZ_PORT.DIRSET = 1 << TMC2660_SPI_SSZ_PIN; // Output +#endif +#if TMC2660_NUM_DRIVERS > 3 + TMC2660_SPI_SSA_PORT.OUTSET = 1 << TMC2660_SPI_SSA_PIN; // High + TMC2660_SPI_SSA_PORT.DIRSET = 1 << TMC2660_SPI_SSA_PIN; // Output +#endif +#if TMC2660_NUM_DRIVERS > 4 + TMC2660_SPI_SSB_PORT.OUTSET = 1 << TMC2660_SPI_SSB_PIN; // High + TMC2660_SPI_SSB_PORT.DIRSET = 1 << TMC2660_SPI_SSB_PIN; // Output +#endif + + // Configure SPI + PR.PRPC &= ~PR_SPI_bm; // Disable power reduction + SPIC.CTRL = SPI_ENABLE_bm | SPI_DORD_bm | SPI_MASTER_bm | SPI_MODE_3_gc | + SPI_PRESCALER_DIV128_gc; // enable, big endian, master, mode 3, clock/128 + PORTC.REMAP = PORT_SPI_bm; // Swap SCK and MOSI + SPIC.INTCTRL = SPI_INTLVL_MED_gc; // interupt level + + // Configure timer + PR.PRPC &= ~PR_TC1_bm; // Disable power reduction + TMC2660_TIMER.PER = F_CPU / 1024 / 10; // Set timer period + TMC2660_TIMER.INTCTRLA = TC_OVFINTLVL_LO_gc; // Low priority overflow int + TMC2660_TIMER.CTRLA = TC_CLKSEL_DIV1024_gc; // enable, clock/1024 +} + + +uint8_t tmc2660_status(int driver) { + return drivers[driver].status; +} + + +uint16_t tmc2660_step(int driver) { + return drivers[driver].mstep; +} diff --git a/src/tmc2660.h b/src/tmc2660.h new file mode 100644 index 0000000..8a0ff88 --- /dev/null +++ b/src/tmc2660.h @@ -0,0 +1,151 @@ +/******************************************************************************\ + + This file is part of the TinyG firmware. + + Copyright (c) 2016, Buildbotics LLC + All rights reserved. + + The C! library is free software: you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License + as published by the Free Software Foundation, either version 2.1 of + the License, or (at your option) any later version. + + The C! library 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 C! library. If not, see + . + + In addition, BSD licensing may be granted on a case by case basis + by written permission from at least one of the copyright holders. + You may request written permission by emailing the authors. + + For information regarding this software email: + Joseph Coffland + joseph@buildbotics.com + +\******************************************************************************/ + +#ifndef TMC2660_H +#define TMC2660_H + +#include + +#define TMC2660_SPI_PORT PORTC +#define TMC2660_SPI_SCK_PIN 5 +#define TMC2660_SPI_MISO_PIN 6 +#define TMC2660_SPI_MOSI_PIN 7 + +#define TMC2660_SPI_SSX_PORT PORTA +#define TMC2660_SPI_SSX_PIN 3 +#define TMC2660_SPI_SSY_PORT PORTF +#define TMC2660_SPI_SSY_PIN 3 +#define TMC2660_SPI_SSZ_PORT PORTE +#define TMC2660_SPI_SSZ_PIN 3 +#define TMC2660_SPI_SSA_PORT PORTD +#define TMC2660_SPI_SSA_PIN 3 +#define TMC2660_SPI_SSB_PORT PORTB +#define TMC2660_SPI_SSB_PIN 3 + +#define TMC2660_NUM_DRIVERS 4 + +#define TMC2660_TIMER TCC1 + +void tmc2660_init(); +uint8_t tmc2660_status(int driver); +uint16_t tmc2660_step(int driver); + +#define TMC2660_DRVCTRL 0 +#define TMC2660_DRVCTRL_ADDR (0UL << 18) +#define TMC2660_DRVCTRL_PHA (1UL << 17) +#define TMC2660_DRVCTRL_CA(x) (((int32_t)x & 0xff) << 9) +#define TMC2660_DRVCTRL_PHB (1UL << 8) +#define TMC2660_DRVCTRL_CB(x) (((int32_t)x & 0xff) << 0) +#define TMC2660_DRVCTRL_INTPOL (1UL << 9) +#define TMC2660_DRVCTRL_DEDGE (1UL << 8) +#define TMC2660_DRVCTRL_MRES_256 (0UL << 0) +#define TMC2660_DRVCTRL_MRES_128 (1UL << 0) +#define TMC2660_DRVCTRL_MRES_64 (2UL << 0) +#define TMC2660_DRVCTRL_MRES_32 (3UL << 0) +#define TMC2660_DRVCTRL_MRES_16 (4UL << 0) +#define TMC2660_DRVCTRL_MRES_8 (5UL << 0) +#define TMC2660_DRVCTRL_MRES_4 (6UL << 0) +#define TMC2660_DRVCTRL_MRES_2 (7UL << 0) +#define TMC2660_DRVCTRL_MRES_1 (8UL << 0) + +#define TMC2660_CHOPCONF 1 +#define TMC2660_CHOPCONF_ADDR (4UL << 17) +#define TMC2660_CHOPCONF_TBL_16 (0UL << 15) +#define TMC2660_CHOPCONF_TBL_24 (1UL << 15) +#define TMC2660_CHOPCONF_TBL_36 (2UL << 15) +#define TMC2660_CHOPCONF_TBL_54 (3UL << 15) +#define TMC2660_CHOPCONF_CHM (1UL << 14) +#define TMC2660_CHOPCONF_RNDTF (1UL << 13) +#define TMC2660_CHOPCONF_FDM_COMP (0UL << 12) +#define TMC2660_CHOPCONF_FDM_TIMER (1UL << 12) +#define TMC2660_CHOPCONF_HDEC_16 (0UL << 11) +#define TMC2660_CHOPCONF_HDEC_32 (1UL << 11) +#define TMC2660_CHOPCONF_HDEC_48 (2UL << 11) +#define TMC2660_CHOPCONF_HDEC_64 (3UL << 11) +#define TMC2660_CHOPCONF_HEND(x) ((((int32_t)x + 3) & 0xf) << 7) +#define TMC2660_CHOPCONF_SWO(x) ((((int32_t)x + 3) & 0xf) << 7) +#define TMC2660_CHOPCONF_HSTART(x) ((((int32_t)x - 1) & 7) << 4) +#define TMC2660_CHOPCONF_FASTD(x) ((((int32_t)x & 8) << 11) | (x & 7) << 4)) +#define TMC2660_CHOPCONF_TOFF_TBL (1 << 0) +#define TMC2660_CHOPCONF_TOFF(x) (((int32_t)x & 0xf) << 0) + +#define TMC2660_SMARTEN 2 +#define TMC2660_SMARTEN_ADDR (5UL << 17) +#define TMC2660_SMARTEN_SEIMIN (1UL << 15) +#define TMC2660_SMARTEN_SEDN_32 (0UL << 13) +#define TMC2660_SMARTEN_SEDN_8 (1UL << 13) +#define TMC2660_SMARTEN_SEDN_2 (2UL << 13) +#define TMC2660_SMARTEN_SEDN_1 (3UL << 13) +#define TMC2660_SMARTEN_MAX(x) ((x & 0xf) << 8) +#define TMC2660_SMARTEN_SEUP_1 (0UL << 5) +#define TMC2660_SMARTEN_SEUP_2 (1UL << 5) +#define TMC2660_SMARTEN_SEUP_4 (2UL << 5) +#define TMC2660_SMARTEN_SEUP_8 (3UL << 5) +#define TMC2660_SMARTEN_MIN(x) (((int32_t)x & 0xf) << 0) + +#define TMC2660_SGCSCONF 3 +#define TMC2660_SGCSCONF_ADDR (6UL << 17) +#define TMC2660_SGCSCONF_SFILT (1UL << 17) +#define TMC2660_SGCSCONF_THRESH(x) (((int32_t)x & 0x7f) << 8) +#define TMC2660_SGCSCONF_CS(x) (((int32_t)x & 0x1f) << 0) +#define TMC2660_SGCSCONF_CS_NONE (31UL << 0) + +#define TMC2660_DRVCONF 4 +#define TMC2660_DRVCONF_ADDR (7UL << 17) +#define TMC2660_DRVCONF_TST (1UL << 16) +#define TMC2660_DRVCONF_SLPH_MIN (0UL << 14) +#define TMC2660_DRVCONF_SLPH_MIN_TC (1UL << 14) +#define TMC2660_DRVCONF_SLPH_MED_TC (2UL << 14) +#define TMC2660_DRVCONF_SLPH_MAX (3UL << 14) +#define TMC2660_DRVCONF_SLPL_MIN (0UL << 12) +#define TMC2660_DRVCONF_SLPL_MED (2UL << 12) +#define TMC2660_DRVCONF_SLPL_MAX (3UL << 12) +#define TMC2660_DRVCONF_DISS2G (1UL << 10) +#define TMC2660_DRVCONF_TS2G_3_2 (0UL << 8) +#define TMC2660_DRVCONF_TS2G_1_6 (1UL << 8) +#define TMC2660_DRVCONF_TS2G_1_2 (2UL << 8) +#define TMC2660_DRVCONF_TS2G_0_8 (3UL << 8) +#define TMC2660_DRVCONF_SDOFF (1UL << 7) +#define TMC2660_DRVCONF_VSENSE (1UL << 6) +#define TMC2660_DRVCONF_RDSEL_MSTEP (0UL << 4) +#define TMC2660_DRVCONF_RDSEL_SG (1UL << 4) +#define TMC2660_DRVCONF_RDSEL_SGCS (2UL << 4) + +#define TMC2660_DRVSTATUS_STST (1UL << 7) +#define TMC2660_DRVSTATUS_OLB (1UL << 6) +#define TMC2660_DRVSTATUS_OLA (1UL << 5) +#define TMC2660_DRVSTATUS_S2GB (1UL << 4) +#define TMC2660_DRVSTATUS_S2GA (1UL << 3) +#define TMC2660_DRVSTATUS_OTPW (1UL << 2) +#define TMC2660_DRVSTATUS_OT (1UL << 1) +#define TMC2660_DRVSTATUS_SG (1UL << 0) + +#endif // TMC2660_H diff --git a/src/usart.c b/src/usart.c index cbb6024..502db7b 100644 --- a/src/usart.c +++ b/src/usart.c @@ -2,7 +2,7 @@ This file is part of the TinyG firmware. - Copyright (c) 2015, Buildbotics LLC + Copyright (c) 2015-2016, Buildbotics LLC All rights reserved. The C! library is free software: you can redistribute it and/or @@ -118,7 +118,7 @@ void usart_init(void) { USARTC0.CTRLA = USART_RXCINTLVL_HI_gc; USARTC0.CTRLB = USART_RXEN_bm | USART_TXEN_bm | USART_CLK2X_bm; - PMIC.CTRL |= PMIC_HILVLEN_bm; // Lowlevel interrupt on + PMIC.CTRL |= PMIC_HILVLEN_bm; // Interrupt level on // Connect IO stdout = &_stdout; diff --git a/src/usart.h b/src/usart.h index f4d2b1f..c6b8e6e 100644 --- a/src/usart.h +++ b/src/usart.h @@ -2,7 +2,7 @@ This file is part of the TinyG firmware. - Copyright (c) 2015, Buildbotics LLC + Copyright (c) 2015-2016, Buildbotics LLC All rights reserved. The C! library is free software: you can redistribute it and/or