Firmware for single step driver with fast step (up to 340kHz) and simple gcode interpreter.
Dependencies: FastPWM SimpleIOMacros mbed
main.cpp
- Committer:
- daapp
- Date:
- 2013-02-28
- Revision:
- 1:86997189bb6b
- Parent:
- 0:b53649cd217f
- Child:
- 2:33a99f65551d
File content as of revision 1:86997189bb6b:
/* picocom -b 115200 -c --imap lfcrlf --omap crlf /dev/ttyACM0 */ /* todo: attach callback to Serial when no command executed only with STOP command todo: when command complete it should print "ok" todo: when all settings printed print "ok" todo: when value of parameter changed print "ok saved" todo: when value of parameter is invalid print "err invalid value" todo: add G command for set zero here */ #include "mbed.h" #include "FastPWM.h" #include "IOMacros.h" #define VERSION "0.1" #define DEBUG #define FILESYSTEM_ROOT "local" #define SETTINGS_FILE ("/" FILESYSTEM_ROOT "/settings.txt") #define SETTINGS_BACKUP_FILE ("/" FILESYSTEM_ROOT "/settings.bak") LocalFileSystem local(FILESYSTEM_ROOT); /* p30 - P0_4 */ // const uint32_t counterPin = 4; const uint32_t counterIntMask = p30_SET_MASK; volatile int32_t position; FastPWM stepper(p21); // Dir pin is p22 - P2.4 /* G code interpreter state*/ bool absMovementMode = true; double mmPosition = 0.0; // mm double feedRate = 1.0; // mm/sec^2 /* *** Serial port *** */ Serial pc(USBTX, USBRX); #define SERIAL_BUFFER_SIZE 40 char serialBuffer[SERIAL_BUFFER_SIZE+1]; int serialPosition = 0; /* *** Settings *** */ typedef struct { double steps_per_mm; double acceleration; // mm/sec^2 double start_acceleration; // mm/sec^2 } settings_t; settings_t settings; // return true - if parsed succesfully // return false - if error during parsing bool parse_settings(FILE *fp, settings_t *settings) { // todo: write parser return true; } void load_settings(char *filename) { FILE *fp; #ifdef DEBUG pc.printf("debug load settings from file \"%s\"\n", filename); #endif fp = fopen(filename, "r"); if (fp == NULL) { settings.steps_per_mm = 25600.0 / 150.0; // 170.666667; settings.acceleration = 1000.000; settings.start_acceleration = 0.0; } else { parse_settings(fp, &settings); fclose(fp); } } void save_settings(char *filename) { FILE *fp; fp = fopen(SETTINGS_FILE, "w"); if (fp != NULL) { fprintf(fp, "$0=%f\n", settings.steps_per_mm); fprintf(fp, "$1=%f\n", settings.acceleration); fprintf(fp, "$2=%f\n", settings.start_acceleration); fclose(fp); #ifdef DEBUG pc.printf("ok settings saved to %s\n", SETTINGS_FILE); #endif } else { pc.printf("err unable to open %s for writing\n", SETTINGS_FILE); } } void print_settings() { pc.printf("$0=%f (x, steps/mm)\n", settings.steps_per_mm); pc.printf("$1=%f (x accel, mm/sec^2)\n", settings.acceleration); pc.printf("$2=%f (x start acceleration, mm/sec^2)\n", settings.start_acceleration); pc.printf("ok\n"); } // return true if no error // return false if error (invalid parameter or value) bool set_param(char name, char *value) { if (name >= '0' && name <= '2') { char *endP = value; double dblValue; bool error = false; dblValue = strtod(value, &endP); if (value == endP || *endP != '\0') { pc.printf("err invalid value for command $%c: %s\n", name, value); error = true; } else { #ifdef DEBUG pc.printf("debug $%c=%f -> %s\n", name, dblValue, endP); #endif switch (name) { case '0': if (dblValue > 0.0) { settings.steps_per_mm = dblValue; } else { pc.printf("err value should be > 0.0, but %f\n", dblValue); error = true; } break; case '1': if (dblValue > 0.0) { settings.acceleration = dblValue; } else { pc.printf("err value should be > 0.0, but %f\n", dblValue); error = true; } break; case '2': if (dblValue >= 0.0) { settings.start_acceleration = dblValue; } else { pc.printf("err value should be >= 0.0, but %f\n", dblValue); error = true; } break; default: pc.printf("err parameter %c unrecognized\n", name); error = true; break; } } return !error; } else { pc.printf("err invalid parameter %c\n", name); return false; } } void invalidCommand() { pc.printf("err invalid command %s\n", serialBuffer); } void moveModule(double position) { double newmmPosition; newmmPosition = absMovementMode ? position : mmPosition + position; #ifdef DEBUG pc.printf("debug move from %f to %f\n", mmPosition, newmmPosition); pc.printf("debug move from %f to %f\n", mmPosition * settings.steps_per_mm, newmmPosition * settings.steps_per_mm); #endif if (newmmPosition > mmPosition) { p22_CLR; } else { p22_SET; } // todo: remove position = 0; stepper.period(1.0/170000.0); stepper.write(0.50); mmPosition = newmmPosition; } void stopModule() { stepper.write(0); #ifdef DEBUG pc.printf("position = %d steps\n", position); #endif mmPosition = position / settings.steps_per_mm; pc.printf("ok stop position %f mm\n", mmPosition); } void processCommand(void) { #ifdef DEBUG pc.printf("debug serial buffer <%s>\n", serialBuffer); #endif if (serialBuffer[0] == '\0') { // todo: empty command stop the stage stopModule(); } else if (serialBuffer[0] == '$') { // '$' - print or change settings if (serialBuffer[1] == '\0') { print_settings(); } else if (serialBuffer[1] >= '0' and serialBuffer[1] <='9' and serialBuffer[2] == '=') { // todo: save settings to file if (set_param(serialBuffer[1], &serialBuffer[3])) { save_settings(SETTINGS_FILE); } } else { invalidCommand(); } } else if (serialBuffer[0] == '?' && serialBuffer[1] == '\0') { // todo: print in millimeters pc.printf("ok %f\n", mmPosition); } else { // todo: parse G-code here char *p = serialBuffer, *endP = serialBuffer; uint32_t ulValue; double dblValue; bool error = false; bool newAbsMovementMode = absMovementMode; double newmmPosition = mmPosition; double newFeedRate = feedRate; bool move = false; while (*p != '\0') { switch (*p) { case 'G': p++; ulValue = strtoul(p, &endP, 10); if (p == endP) { pc.printf("err invalid value for command G: %s\n", p); error = true; } else { #ifdef DEBUG pc.printf("debug G%u -> %s\n", ulValue, endP); #endif p = endP; switch (ulValue) { case 0: // todo: implement break; case 1: // todo: implement break; case 90: newAbsMovementMode = true; break; case 91: newAbsMovementMode = false; break; default: pc.printf("err invalid value for command G: %u\n", ulValue); error = true; break; } } break; case 'X': p++; dblValue = strtod(p, &endP); if (p == endP) { pc.printf("err invalid value for command X: %s\n", p); error = true; } else { #ifdef DEBUG pc.printf("debug X%f -> %s\n", dblValue, endP); #endif p = endP; newmmPosition = dblValue; move = true; } break; case 'F': p++; dblValue = strtod(p, &endP); if (p == endP || dblValue < 0.0) { pc.printf("err invalid value for command F: %s\n", p); error = true; } else { #ifdef DEBUG pc.printf("debug parse F%f => rest %s\n", dblValue, endP); #endif p = endP; newFeedRate = dblValue; } break; default: pc.printf("err invalid command %s\n", p); error = true; break; } if (error) { break; } } if (!error) { // todo: check all flags and execute commands here absMovementMode = newAbsMovementMode; //mmPosition = newmmPosition; feedRate = newFeedRate; // todo: run line module here pc.printf("absMovementMode = %u\n", absMovementMode); pc.printf("mmPosition = %f\n", mmPosition); pc.printf("feedRate = %f\n", feedRate); if (move) { moveModule(newmmPosition); } } } } void readChar(void) { int ch; #ifdef DEBUG LED4_ON; #endif ch = pc.getc(); if (serialPosition < SERIAL_BUFFER_SIZE) { } else { pc.printf("\nToo long string, should be <= %d characters.\n", SERIAL_BUFFER_SIZE); serialPosition = 0; } if (ch == ' ' || ch == '\t') { // ignore space characters } else { if (ch == '\n') { serialBuffer[serialPosition] = '\0'; processCommand(); serialPosition = 0; serialBuffer[serialPosition] = '\0'; } else { if (ch >= 'a' and ch <= 'z') { ch = 'A' + (ch - 'a'); // convert to upper case } serialBuffer[serialPosition++] = ch; } } #ifdef DEBUG LED4_OFF; #endif } void update_position(); extern "C" void EINT3_IRQHandler (void) __irq { if (LPC_GPIOINT->IntStatus & 0x1) { if (LPC_GPIOINT->IO0IntStatF & counterIntMask) { update_position(); } } LPC_GPIOINT->IO2IntClr = (LPC_GPIOINT->IO2IntStatR | LPC_GPIOINT->IO2IntStatF); LPC_GPIOINT->IO0IntClr = (LPC_GPIOINT->IO0IntStatR | LPC_GPIOINT->IO0IntStatF); } void update_position() { position++; /* if (position > 0) { position--; } else { position = 170000; }*/ } void event_irq_init(void) { p30_AS_INPUT; // Enable p30 is P0_4 for rising edge interrupt generation. LPC_GPIOINT->IO0IntEnF |= counterIntMask; //NVIC_SetPriority(EINT3_IRQn, 1); // Enable the interrupt NVIC_EnableIRQ(EINT3_IRQn); } int main() { LED1_USE; // step movement LED4_USE; // serial port receive p22_AS_OUTPUT; position = 0; pc.baud(115200); pc.attach(readChar); pc.printf("IGNB-SM %s ['$' for help]\n", VERSION); load_settings(SETTINGS_FILE); //stepper.period(1.0/170000.0); //stepper.write(0.50); event_irq_init(); while(1) { //position = 0; //LED1_ON; //stepper.write(0.5); //wait(1); //stepper.write(0.0); //LED1_OFF; //pc.printf("%d\r\n", position); //wait(1); } }