diff --git a/lambda-test/Makefile b/lambda-test/Makefile index a981d1c..061a775 100644 --- a/lambda-test/Makefile +++ b/lambda-test/Makefile @@ -14,8 +14,8 @@ ## If you've split your program into multiple .c / .h files, ## include the additional source (in same directory) here -LOCAL_SOURCE = avrjunit.c adc-test.c alert-test.c command-test.c \ -display-test.c integers-test.c interrupts-test.c release-test.c \ +LOCAL_SOURCE = avrjunit.c utils.c adc-test.c airgate-test.c alert-test.c \ +command-test.c display-test.c integers-test.c interrupts-test.c release-test.c \ rules-test.c scheduler-test.c sensors-test.c strings-test.c usart-test.c ## Here you can link to one more directory (and multiple .c files) diff --git a/lambda-test/adc-test.c b/lambda-test/adc-test.c index 140085c..36133a8 100644 --- a/lambda-test/adc-test.c +++ b/lambda-test/adc-test.c @@ -9,7 +9,6 @@ */ #include "avrjunit.h" -#include "integers.h" #include "interrupts.h" #include "adc.h" #include "pins.h" diff --git a/lambda-test/airgate-test.c b/lambda-test/airgate-test.c new file mode 100644 index 0000000..fafe36a --- /dev/null +++ b/lambda-test/airgate-test.c @@ -0,0 +1,129 @@ +/* + * airgate-test.c + * + * Created on: 28.03.2016 + * Author: dode@luniks.net + */ + +#include +#include +#include "avrjunit.h" +#include "pins.h" +#include "airgate.h" +#include "integers.h" +#include "utils.h" + +/* Module airgate */ + +static bool testSetAirgate(void) { + + resetAirgate(0); + setAirgate(100); + + assertTrue(isAirgateBusy()); + // full motor current is set + assertTrue(bit_is_clear(PORT, PIN_CURRENT)); + // direction 0 + assertTrue(bit_is_clear(PORT, PIN_DIR)); + // min speed is set + assertTrue(MIN_SPEED == OCR2A); + // timer2 is running (prescaler is set) + assertTrue(0 != TCCR2B); + + stepUntilDone(); + + assertFalse(isAirgateBusy()); + // reduced motor current is set + assertFalse(bit_is_clear(PORT, PIN_CURRENT)); + // timer2 is stopped + assertTrue(0 == TCCR2B); + // requested position reached + assertTrue(100 == getAirgate()); + + return true; +} + +static bool testMakeSteps(void) { + + const uint16_t SPEED_PROD = (uint16_t)MIN_SPEED * MAX_SPEED; + const uint16_t ramp = MIN(abs(MAX_SPEED - MIN_SPEED), (100 << STEPPING_MODE) >> 1); + uint8_t speed = MIN_SPEED; + + resetAirgate(0); + setAirgate(100); + + // full motor current is set + assertTrue(bit_is_clear(PORT, PIN_CURRENT)); + // step pin is low + assertTrue(bit_is_clear(PORT, PIN_STEP)); + assertTrue(MIN_SPEED == OCR2A); + + makeSteps(); + + // step pin is toggled high + assertTrue(bit_is_set(PORT, PIN_STEP)); + // accelerated by 1 + assertTrue((SPEED_PROD / ++speed) == OCR2A); + + makeSteps(); + + // step pin is toggled low + assertTrue(bit_is_clear(PORT, PIN_STEP)); + // no acceleration + assertTrue((SPEED_PROD / speed) == OCR2A); + + // step until end of acceleration ramp + for (uint16_t i = 1; i < ramp; i++) { + makeSteps(); + makeSteps(); + } + + // should have accelerated to MAX_SPEED + speed = MAX_SPEED; + assertTrue((SPEED_PROD / speed) == OCR2A); + + // make remaining steps + stepUntilDone(); + + // step pin is toggled low + assertTrue(bit_is_clear(PORT, PIN_STEP)); + // decelerated to MIN_SPEED + speed = MIN_SPEED; + assertTrue((SPEED_PROD / speed) == OCR2A); + // reached requested position + assertTrue(100 == getAirgate()); + // reduced motor current is set + assertTrue(bit_is_set(PORT, PIN_CURRENT)); + + return true; +} + +static bool testSetSleepMode(void) { + + setSleepMode(false); + + assertTrue(bit_is_set(PORT, PIN_SLEEP)); + + setSleepMode(true); + + assertTrue(bit_is_clear(PORT, PIN_SLEEP)); + + return true; +} + +/* Test "class" */ +static const char class[] PROGMEM = "airgate"; + +/* Test names */ +static const char testSetAirgate_P[] PROGMEM = "testSetAirgate"; +static const char testMakeSteps_P[] PROGMEM = "testMakeSteps"; +static const char testSetSleepMode_P[] PROGMEM = "testSetSleepMode"; + +/* Tests */ +static TestCase const tests[] = { + {class, testSetAirgate_P, testSetAirgate}, + {class, testMakeSteps_P, testMakeSteps}, + {class, testSetSleepMode_P, testSetSleepMode} +}; + +TestClass airgateClass = {tests, ARRAY_LENGTH(tests)}; diff --git a/lambda-test/alert-test.c b/lambda-test/alert-test.c index 99bf76b..d2d9291 100644 --- a/lambda-test/alert-test.c +++ b/lambda-test/alert-test.c @@ -9,7 +9,6 @@ */ #include "avrjunit.h" -#include "integers.h" #include "interrupts.h" #include "alert.h" diff --git a/lambda-test/avrjunit.h b/lambda-test/avrjunit.h index 1d0fef3..18206df 100644 --- a/lambda-test/avrjunit.h +++ b/lambda-test/avrjunit.h @@ -35,6 +35,11 @@ #define assertNotNull(exp) if ((exp) == NULL) return false /** + * Computes the length of the given array. + */ +#define ARRAY_LENGTH(array) (sizeof(array) / sizeof(array[0])) + +/** * Function pointer for test functions taking no parameters and returning * true on success and false on failure. */ diff --git a/lambda-test/command-test.c b/lambda-test/command-test.c index 26b550f..1de23c2 100644 --- a/lambda-test/command-test.c +++ b/lambda-test/command-test.c @@ -12,9 +12,10 @@ #include "alert.h" #include "command.h" #include "display.h" -#include "integers.h" #include "interrupts.h" #include "sensors.h" +#include "airgate.h" +#include "utils.h" /* Module command */ @@ -70,6 +71,18 @@ return true; } +static bool testSetAirgate(void) { + + resetAirgate(0); + + runCommand("sa 100"); + stepUntilDone(); + + assertTrue(100 == getAirgate()); + + return true; +} + /* Test "class" */ static const char class[] PROGMEM = "command"; @@ -78,13 +91,15 @@ static const char testIsLogging_P[] PROGMEM = "testIsLogging"; static const char testHeater_P[] PROGMEM = "testHeater"; static const char testCycleDisplay_P[] PROGMEM = "testCycleDisplay"; +static const char testSetAirgate_P[] PROGMEM = "testSetAirgate"; /* Tests */ static TestCase const tests[] = { {class, testIsSimulation_P, testIsSimulation}, {class, testIsLogging_P, testIsLogging}, {class, testHeater_P, testHeater}, - {class, testCycleDisplay_P, testCycleDisplay} + {class, testCycleDisplay_P, testCycleDisplay}, + {class, testSetAirgate_P, testSetAirgate} }; TestClass commandClass = {tests, ARRAY_LENGTH(tests)}; diff --git a/lambda-test/display-test.c b/lambda-test/display-test.c index 6057024..4d4b8e8 100644 --- a/lambda-test/display-test.c +++ b/lambda-test/display-test.c @@ -11,7 +11,6 @@ #include #include "avrjunit.h" #include "display.h" -#include "integers.h" #include "sensors.h" #include "alert.h" diff --git a/lambda-test/interrupts-test.c b/lambda-test/interrupts-test.c index e71db71..0202471 100644 --- a/lambda-test/interrupts-test.c +++ b/lambda-test/interrupts-test.c @@ -11,7 +11,6 @@ #include #include #include "avrjunit.h" -#include "integers.h" #include "interrupts.h" /* Module interrupts */ diff --git a/lambda-test/lambda-test.c b/lambda-test/lambda-test.c index 57f7dd0..a11d66f 100644 --- a/lambda-test/lambda-test.c +++ b/lambda-test/lambda-test.c @@ -25,6 +25,7 @@ extern TestClass releaseClass; extern TestClass adcClass; + extern TestClass airgateClass; extern TestClass alertClass; extern TestClass commandClass; extern TestClass displayClass; @@ -41,6 +42,7 @@ // run these before interrupts are initialized to avoid interference runClass(rulesClass); runClass(adcClass); + runClass(airgateClass); runClass(alertClass); runClass(commandClass); runClass(displayClass); diff --git a/lambda-test/release-test.c b/lambda-test/release-test.c index e481238..b53600e 100644 --- a/lambda-test/release-test.c +++ b/lambda-test/release-test.c @@ -9,7 +9,6 @@ */ #include "avrjunit.h" -#include "integers.h" #include "interrupts.h" #include "messages.h" #include "pins.h" diff --git a/lambda-test/rules-test.c b/lambda-test/rules-test.c index 33dcfc4..fab9aa8 100644 --- a/lambda-test/rules-test.c +++ b/lambda-test/rules-test.c @@ -12,9 +12,9 @@ #include "avrjunit.h" #include "rules.h" #include "alert.h" -#include "integers.h" #include "interrupts.h" #include "airgate.h" +#include "utils.h" /* Module rules */ @@ -22,13 +22,6 @@ extern int8_t state; extern Rule rules[]; -static void stepUntilDone(void) { - while (isAirgateBusy()) { - makeSteps(); - } - makeSteps(); -} - static bool testAirgate50(void) { Measurement meas = {0, 0, 0, 0}; @@ -455,7 +448,7 @@ return true; } -static bool testHeaterTimeout0(void) { +static bool testHeaterTimeout(void) { resetRules(true); resetTime(); @@ -477,28 +470,6 @@ return true; } -static bool testHeaterTimeout1(void) { - - resetRules(true); - resetTime(); - Measurement meas = {0, 0, 0, 0}; - - setHeaterState(heaterStateOn); - - // equal or more than 3 hours below TEMP_AIRGATE_0 - addTime(10800UL); - - meas.tempI = TEMP_AIRGATE_0 - 1; - meas.lambda = LAMBDA_MAX; - meas.current = milliAmpsReady; - reason(meas); - assertTrue(heaterStateOff == getHeaterState()); - - cancelAlert(); - - return true; -} - /* Test "class" */ static const char class[] PROGMEM = "rules"; @@ -514,8 +485,7 @@ static const char testHeaterFaultNoconn_P[] PROGMEM = "testHeaterFaultNoconn"; static const char testHeaterFaultShort_P[] PROGMEM = "testHeaterFaultShort"; static const char testHeaterFaultNoheat_P[] PROGMEM = "testHeaterFaultNoheat"; -static const char testHeaterTimeout0_P[] PROGMEM = "testHeaterTimeout0"; -static const char testHeaterTimeout1_P[] PROGMEM = "testHeaterTimeout1"; +static const char testHeaterTimeout_P[] PROGMEM = "testHeaterTimeout"; /* Tests */ static TestCase const tests[] = { @@ -530,8 +500,7 @@ {class, testHeaterFaultNoconn_P, testHeaterFaultNoconn}, {class, testHeaterFaultShort_P, testHeaterFaultShort}, {class, testHeaterFaultNoheat_P, testHeaterFaultNoheat}, - {class, testHeaterTimeout0_P, testHeaterTimeout0}, - {class, testHeaterTimeout1_P, testHeaterTimeout1} + {class, testHeaterTimeout_P, testHeaterTimeout} }; TestClass rulesClass = {tests, ARRAY_LENGTH(tests)}; diff --git a/lambda-test/scheduler-test.c b/lambda-test/scheduler-test.c index 06ef9b2..bfe7b0b 100644 --- a/lambda-test/scheduler-test.c +++ b/lambda-test/scheduler-test.c @@ -6,7 +6,6 @@ */ #include "avrjunit.h" -#include "integers.h" #include "interrupts.h" #include "scheduler.h" diff --git a/lambda-test/sensors-test.c b/lambda-test/sensors-test.c index f690e14..7d1f0e3 100644 --- a/lambda-test/sensors-test.c +++ b/lambda-test/sensors-test.c @@ -11,7 +11,6 @@ #include #include #include "avrjunit.h" -#include "integers.h" #include "interrupts.h" #include "adc.h" #include "sensors.h" diff --git a/lambda-test/strings-test.c b/lambda-test/strings-test.c index 0a9b727..83229ac 100644 --- a/lambda-test/strings-test.c +++ b/lambda-test/strings-test.c @@ -10,7 +10,6 @@ #include #include "avrjunit.h" -#include "integers.h" #include "strings.h" /* Module strings */ diff --git a/lambda-test/usart-test.c b/lambda-test/usart-test.c index 98f3611..63c074f 100644 --- a/lambda-test/usart-test.c +++ b/lambda-test/usart-test.c @@ -11,7 +11,6 @@ #include "usart.h" #include #include "avrjunit.h" -#include "integers.h" /* Module usart */ diff --git a/lambda-test/utils.c b/lambda-test/utils.c new file mode 100644 index 0000000..fab2de0 --- /dev/null +++ b/lambda-test/utils.c @@ -0,0 +1,16 @@ +/* + * utils.c + * + * Created on: 28.03.2016 + * Author: dode@luniks.net + */ + +#include "utils.h" +#include "airgate.h" + +void stepUntilDone(void) { + while (isAirgateBusy()) { + makeSteps(); + } + makeSteps(); +} diff --git a/lambda-test/utils.h b/lambda-test/utils.h new file mode 100644 index 0000000..31d2e22 --- /dev/null +++ b/lambda-test/utils.h @@ -0,0 +1,19 @@ +/* + * utils.h + * + * Created on: 28.03.2016 + * Author: dode@luniks.net + * + * Some utility functions used by many tests. + */ + +#ifndef UTILS_H_ +#define UTILS_H_ + +/** + * Trigger steps as done by the timer ISR until the requested motor position + * is reached. + */ +void stepUntilDone(void); + +#endif /* UTILS_H_ */ diff --git a/lambda/TODO b/lambda/TODO index c615f43..712fa87 100644 --- a/lambda/TODO +++ b/lambda/TODO @@ -3,6 +3,7 @@ * AVR * Functionality +- Evaluate driver fault pin value (rule) * Circuit - AVCC should be connected to VCC via an LC network diff --git a/lambda/airgate.c b/lambda/airgate.c index 9ee2957..c84b745 100644 --- a/lambda/airgate.c +++ b/lambda/airgate.c @@ -6,11 +6,10 @@ * * Simple stepper motor control with a linear acceleration profile using the * DRV8825. An absolute position from 0 to 255 can be set where 200 units - * correspond to 360° rotation. + * correspond to 360° rotation (with 1.8 ° step angle). */ #include -#include #include #include #include "airgate.h" @@ -18,6 +17,8 @@ #include "interrupts.h" #include "pins.h" +static const uint16_t SPEED_PROD = (uint16_t)MIN_SPEED * MAX_SPEED; + /* Direction */ static volatile int8_t dir = 0; /* Current position */ @@ -49,6 +50,7 @@ // setup time _delay_us(3); // set start speed + speed = MIN_SPEED; OCR2A = MIN_SPEED; // start timer2 TCCR2B |= TIMER2_PRESCALE; @@ -66,18 +68,21 @@ void makeSteps(void) { if (steps > 0) { PORT ^= (1 << PIN_STEP); - done++; - steps--; - if (done < ramp && speed < MAX_SPEED) { - // accelerate within ramp - speed++; - } else if (steps < ramp && speed > MIN_SPEED) { - // decelerate within ramp - speed--; + if (bit_is_set(PORT, PIN_STEP)) { + done++; + steps--; + if (done < ramp && speed < MAX_SPEED) { + // accelerate within ramp + speed++; + } else if (steps < ramp && speed > MIN_SPEED) { + // decelerate within ramp + speed--; + } + // linearize an unfavourably increasing acceleration curve + OCR2A = SPEED_PROD / speed; } - // linearize an unfavourably increasing acceleration curve - OCR2A = ((uint16_t)MIN_SPEED * MAX_SPEED) / speed; } else { + PORT &= ~(1 << PIN_STEP); stop(); pos += (done * dir); done = 0; @@ -93,7 +98,7 @@ if (bit_is_clear(PORT, PIN_SLEEP)) { setSleepMode(false); } - int16_t diff = (((int16_t)target) << SCALE) - pos; + int16_t diff = (((int16_t)target) << STEPPING_MODE) - pos; if (diff != 0) { dir = (diff > 0) - (diff < 0); steps = abs(diff); @@ -103,15 +108,7 @@ } uint8_t getAirgate(void) { - return pos >> SCALE; -} - -uint8_t getAirgateInPercent(void) { - if (getAirgate() == 0) { - return 0; - } - - return 100000 / ((AIRGATE_OPEN * 1000UL) / getAirgate()); + return pos >> STEPPING_MODE; } bool isAirgateBusy(void) { @@ -135,7 +132,7 @@ void resetAirgate(uint16_t const position) { dir = 0; - pos = position << SCALE; + pos = position << STEPPING_MODE; steps = 0; done = 0; ramp = 0; diff --git a/lambda/airgate.h b/lambda/airgate.h index 0dfa80b..bc6693c 100644 --- a/lambda/airgate.h +++ b/lambda/airgate.h @@ -5,6 +5,9 @@ * Author: dode@luniks.net */ +#include +#include + #ifndef AIRGATE_H_ #define AIRGATE_H_ @@ -19,10 +22,9 @@ #define AIRGATE_OPEN 60 /** - * 1 = full step, 2 = half step, 3 = 1/4 step, 4 = 8 microsteps, ... - * for 180°. + * 0 = full step, 1 = half step, 2 = 1/4 step, 3 = 8 microsteps, ... */ -#define SCALE 3 +#define STEPPING_MODE 2 /** * Called from the timer interrupt ISR and makes a half step or stops the @@ -32,7 +34,7 @@ /** * Sets the airgate position 0 - 255, where 200 units correspond to 360° - * rotation. + * rotation (with 1.8 ° step angle). */ void setAirgate(uint8_t const position); @@ -43,11 +45,6 @@ uint8_t getAirgate(void); /** - * Returns the current airgate position translated to percent. - */ -uint8_t getAirgateInPercent(void); - -/** * Returns true if the motor is currently busy setting an airgate position, * false otherwise. */ diff --git a/lambda/display.c b/lambda/display.c index 44eb9df..dae8e04 100644 --- a/lambda/display.c +++ b/lambda/display.c @@ -83,8 +83,12 @@ * Displays the airgate position in %. */ static void displayAirgate(uint8_t const airgate) { + uint16_t airgateInPercent = 0; + if (airgate > 0) { + airgateInPercent = 100000UL / ((AIRGATE_OPEN * 1000UL) / airgate); + } char line1[17]; - snprintf(line1, sizeof(line1), "%d%%", airgate); + snprintf(line1, sizeof(line1), "%d%%", airgateInPercent); setText(MSG_AIRGATE, line1); } @@ -137,7 +141,7 @@ if (position == displayPosMax) { displayMeas(measMax, " ^"); } else if (position == displayPosAirgate) { - displayAirgate(getAirgateInPercent()); + displayAirgate(getAirgate()); } else if (position == displayPosHeater) { displayCurrent(measLatest.current); } else if (position == displayPosLastText) {