diff --git a/lambda-test/Makefile b/lambda-test/Makefile index 8c8a4da..27663ba 100644 --- a/lambda-test/Makefile +++ b/lambda-test/Makefile @@ -21,7 +21,7 @@ ## Here you can link to one more directory (and multiple .c files) EXTRA_SOURCE_DIR = ../lambda/ EXTRA_SOURCE_FILES = interrupts.c adc.c sensors.c integers.c \ -lcdroutines.c display.c alert.c command.c strings.c usart.c rules.c +lcdroutines.c display.c alert.c command.c strings.c usart.c rules.c airgate.c ##########------------------------------------------------------########## ########## Programmer Defaults ########## diff --git a/lambda-test/rules-test.c b/lambda-test/rules-test.c index e1a8fb4..66a26b5 100644 --- a/lambda-test/rules-test.c +++ b/lambda-test/rules-test.c @@ -13,12 +13,12 @@ #include "rules.h" #include "alert.h" #include "interrupts.h" +#include "airgate.h" /* Module rules */ extern uint8_t measCount; extern int8_t state; -extern uint8_t airgate; extern Rule rules[]; static bool testAirgate50(void) { @@ -57,14 +57,14 @@ state = firing_up; reason(meas); assertTrue(rules[0].fired); - assertTrue(50 == airgate); + assertTrue(50 == getAirgate()); // should not fire if airgate == 50 resetRules(false); state = firing_up; reason(meas); assertFalse(rules[0].fired); - assertTrue(50 == airgate); + assertTrue(50 == getAirgate()); cancelAlert(); @@ -107,7 +107,7 @@ state = burning_down; reason(meas); assertTrue(rules[1].fired); - assertTrue(25 == airgate); + assertTrue(25 == getAirgate()); cancelAlert(); @@ -150,7 +150,7 @@ state = burning_down; reason(meas); assertTrue(rules[2].fired); - assertTrue(0 == airgate); + assertTrue(0 == getAirgate()); cancelAlert(); @@ -184,18 +184,18 @@ meas.tempI = TEMP_FIRE_OUT + 1; meas.lambda = LAMBDA_TOO_RICH - 1; resetRules(true); - airgate = 50; + setAirgate(50); reason(meas); assertFalse(rules[3].fired); - assertTrue(50 == airgate); + assertTrue(50 == getAirgate()); meas.tempI = TEMP_FIRE_OUT + 1; meas.lambda = LAMBDA_TOO_RICH - 1; resetRules(true); - airgate = 25; + setAirgate(25); reason(meas); assertTrue(rules[3].fired); - assertTrue(50 == airgate); + assertTrue(50 == getAirgate()); cancelAlert(); @@ -223,18 +223,18 @@ meas.tempI = TEMP_AIRGATE_50 + 1; meas.lambda = LAMBDA_TOO_LEAN + 1; resetRules(true); - airgate = 50; + setAirgate(50); reason(meas); assertFalse(rules[4].fired); - assertTrue(50 == airgate); + assertTrue(50 == getAirgate()); meas.tempI = TEMP_AIRGATE_50 + 1; meas.lambda = LAMBDA_TOO_LEAN + 1; resetRules(true); - airgate = 100; + setAirgate(100); reason(meas); assertTrue(rules[4].fired); - assertTrue(50 == airgate); + assertTrue(50 == getAirgate()); cancelAlert(); @@ -286,9 +286,9 @@ resetRules(true); rules[6].fired = false; - airgate = 50; + setAirgate(50); reason(meas); - assertTrue(50 == airgate); + assertTrue(50 == getAirgate()); assertTrue(heaterStateOff == getHeaterState()); assertFalse(rules[6].fired); @@ -296,7 +296,7 @@ rules[6].fired = false; state = firing_up; reason(meas); - assertTrue(100 == airgate); + assertTrue(100 == getAirgate()); assertTrue(heaterStateOn == getHeaterState()); assertTrue(rules[6].fired); diff --git a/lambda/Makefile b/lambda/Makefile index 4dd53cb..5e8337d 100644 --- a/lambda/Makefile +++ b/lambda/Makefile @@ -3,7 +3,7 @@ MCU = atmega328p # Currently supported are 1 MHz and 8 MHz -F_CPU = 1000000 +F_CPU = 8000000 # Also try BAUD = 19200 or 38400 if you're feeling lucky. BAUD = 9600 @@ -14,7 +14,7 @@ LANG = 0 LOCAL_SOURCE = usart.c interrupts.c adc.c sensors.c integers.c lcdroutines.c \ -display.c alert.c command.c strings.c rules.c +display.c alert.c command.c strings.c rules.c airgate.c EXTRA_SOURCE_DIR = EXTRA_SOURCE_FILES = diff --git a/lambda/airgate.c b/lambda/airgate.c new file mode 100644 index 0000000..d1f8dff --- /dev/null +++ b/lambda/airgate.c @@ -0,0 +1,92 @@ +/* + * airgate.c + * + * Created on: 19.02.2016 + * Author: dode@luniks.net + */ + +#include +#include +#include +#include +#include +#include "airgate.h" +#include "integers.h" + +#include "usart.h" + +// TODO pins + +volatile static int8_t dir = 0; +volatile static uint16_t pos = 100 << 2; +volatile static uint16_t steps = 0; +volatile static uint16_t stepsDone = 0; +static uint8_t speed = 255; + +static void start(void) { + if (bit_is_clear(PORTC, PC5)) { + // wake up driver + PORTC |= (1 << PC5); + // wakeup time + _delay_ms(2); + } + // set dir + if (dir == 1) { + PORTB &= ~(1 << PB6); + } else { + PORTB |= (1 << PB6); + } + // setup time + _delay_us(1); + // set speed + OCR2A = speed; + // start timer2 + TCCR2B |= (1 << CS22) | (1 << CS21); +} + +static void stop(void) { + // stop timer2 + TCCR2B = 0; + // GTCCR |= (1 << PSRASY); + // step pin low + // PORTB &= ~(1 << PB7); +} + +void makeSteps(void) { + if (steps > 0) { + PORTB ^= (1 << PB7); + pos += dir; + steps--; + stepsDone++; + } else { + stop(); + // driver sleep mode + PORTC &= ~(1 << PC5); + + char buf[64]; + snprintf(buf, sizeof(buf), "stopp: pos: %d, steps: %d, done: %d\n", pos, steps, stepsDone); + printString(buf); + + stepsDone = 0; + } +} + +void setAirgate(uint8_t const position) { + stop(); + + int16_t diff = (((int16_t)position) << 2) - pos; + if (diff != 0) { + dir = MAX(-1, MIN(diff, 1)); + steps = abs(diff); + + char buf[96]; + snprintf(buf, sizeof(buf), "start: pos: %d, steps: %d\n", pos, steps); + printString(buf); + + start(); + } +} + +uint8_t getAirgate(void) { + return pos >> 2; +} diff --git a/lambda/airgate.h b/lambda/airgate.h new file mode 100644 index 0000000..8757c34 --- /dev/null +++ b/lambda/airgate.h @@ -0,0 +1,17 @@ +/* + * airgate.h + * + * Created on: 19.02.2016 + * Author: dode@luniks.net + */ + +#ifndef MOTOR_H_ +#define MOTOR_H_ + +void makeSteps(void); + +uint8_t getAirgate(void); + +void setAirgate(uint8_t const position); + +#endif /* MOTOR_H_ */ diff --git a/lambda/command.c b/lambda/command.c index db53711..0bdd930 100644 --- a/lambda/command.c +++ b/lambda/command.c @@ -21,6 +21,7 @@ #include "command.h" #include "strings.h" #include "rules.h" +#include "airgate.h" static bool simulation = false; static bool logging = false; @@ -87,15 +88,24 @@ else if (strcmp_P(fields[0], PSTR("tb")) == 0) { // test beep uint8_t length = 2; + uint16_t tone = 31; if (fields[1] != '\0') { length = atoi(fields[1]); } - uint16_t tone = 31; if (fields[2] != '\0') { tone = atoi(fields[2]); } beep(1, length, tone); } + else if (strcmp_P(fields[0], PSTR("sa")) == 0) { + // set airgate + uint8_t position = 100; + if (fields[1] != '\0') { + position = atoi(fields[1]); + } + setAirgate(position); + } + // else if (simulation) { // add one second per measurement to the time, // assuming one measurement was logged per second diff --git a/lambda/interrupts.c b/lambda/interrupts.c index 95ce891..ae5c439 100644 --- a/lambda/interrupts.c +++ b/lambda/interrupts.c @@ -19,6 +19,7 @@ #include "display.h" #include "alert.h" #include "pins.h" +#include "airgate.h" static volatile bool buttonPressed = false; static volatile uint32_t ints = 0; @@ -39,6 +40,10 @@ } } +ISR(TIMER2_COMPA_vect) { + makeSteps(); +} + uint32_t getTime(void) { uint32_t time; ATOMIC_BLOCK(ATOMIC_FORCEON) { @@ -79,6 +84,13 @@ // enable oxygen sensor heater control output pin DDR |= (1 << PIN_HEATER); + + // enable dir and step pin for stepper motor driver + // TODO pins + DDR |= (1 << PB6); + DDR |= (1 << PB7); + // DDR |= (1 << PB3); // (OC2A) + DDRC |= (1 << PC5); } void setupSleepMode(void) { @@ -93,6 +105,9 @@ // enable timer0 compare match A interrupt TIMSK0 |= (1 << OCIE0A); + // enable timer2 compare match A interrupt + TIMSK2 |= (1 << OCIE2A); + // enable USART RX complete interrupt 0 UCSR0B |= (1 << RXCIE0); @@ -101,13 +116,20 @@ } void initTimers(void) { + // timer0 is for time: about 32 ints per second // timer0 clear timer on compare match mode, TOP OCR0A TCCR0A |= (1 << WGM01); TCCR0B |= TIMER0_PRESCALE; OCR0A = TIMER0_COMP_MATCH; + // timer1 is for the beeper square wave // timer1 clear timer on compare match mode, TOP OCR1A TCCR1B |= (1 << WGM12); TCCR1B |= TIMER1_PRESCALE; OCR1A = TIMER1_COMP_MATCH; + + // timer2 is for the step of the stepper motor using the DRV8825 + // timer2 clear timer on compare match mode, TOP OCR2A + TCCR2A |= (1 << WGM21); + TCCR2B = 0; } diff --git a/lambda/lambda.c b/lambda/lambda.c index c5daf8d..84487ea 100644 --- a/lambda/lambda.c +++ b/lambda/lambda.c @@ -34,6 +34,7 @@ #include "command.h" #include "rules.h" #include "messages.h" +#include "airgate.h" /** * Does initialization, measures, displays and logs the measurements and @@ -57,6 +58,8 @@ alert_P(1, 1, 31, PSTR(MSG_WELCOME), PSTR(""), false); // spend some time on being polite while (getTime() < 3) {} + // TODO remember position before reset? + // setAirgate(100); setHeaterState(heaterStateOn); uint32_t time = 0; diff --git a/lambda/rules.c b/lambda/rules.c index d70db32..976f293 100644 --- a/lambda/rules.c +++ b/lambda/rules.c @@ -12,12 +12,13 @@ #include "interrupts.h" #include "rules.h" #include "messages.h" +#include "airgate.h" #include "usart.h" uint8_t measCount = MEAS_INT; FireState state = undefined; -uint8_t airgate = 100; +// uint8_t airgate = 100; static int32_t deltaAvg = 0; static int16_t tempIMax = TEMP_INIT; @@ -55,8 +56,8 @@ if ((state == firing_up) && meas.tempI >= TEMP_AIRGATE_50 && meas.lambda >= LAMBDA_TOO_LEAN && - airgate != 50) { - airgate = 50; + getAirgate() != 50) { + setAirgate(50); alert_P(BEEPS, LENGTH, TONE, PSTR(MSG_AIRGATE_50_0), PSTR(""), false); *fired = true; } @@ -69,8 +70,8 @@ static void airgate25(bool* const fired, Measurement const meas) { if (state == burning_down && meas.tempI < TEMP_AIRGATE_25 && - meas.lambda >= LAMBDA_TOO_LEAN && airgate > 25) { - airgate = 25; + meas.lambda >= LAMBDA_TOO_LEAN && getAirgate() > 25) { + setAirgate(25); alert_P(BEEPS, LENGTH, TONE, PSTR(MSG_AIRGATE_25_0), PSTR(""), false); *fired = true; } @@ -82,9 +83,9 @@ */ static void airgateClose(bool* const fired, Measurement const meas) { if (state == burning_down && meas.tempI < TEMP_AIRGATE_0 && - meas.lambda >= LAMBDA_MAX && airgate > 0) { + meas.lambda >= LAMBDA_MAX && getAirgate() > 0) { setHeaterState(heaterStateOff); - airgate = 0; + setAirgate(0); alert_P(BEEPS, LENGTH, TONE, PSTR(MSG_AIRGATE_CLOSE_0), PSTR(""), false); *fired = true; @@ -101,8 +102,8 @@ */ static void tooRich(bool* const fired, Measurement const meas) { if (meas.tempI > TEMP_FIRE_OUT && meas.lambda < LAMBDA_TOO_RICH && - getHeaterState() == heaterStateReady && airgate < 50) { - airgate = 50; + getHeaterState() == heaterStateReady && getAirgate() < 50) { + setAirgate(50); alert_P(BEEPS, LENGTH, TONE, PSTR(MSG_AIRGATE_50_0), PSTR(""), false); *fired = true; } @@ -114,8 +115,8 @@ */ static void tooLean(bool* const fired, Measurement const meas) { if (meas.tempI > TEMP_AIRGATE_50 && meas.lambda > LAMBDA_TOO_LEAN && - getHeaterState() == heaterStateReady && airgate > 50) { - airgate = 50; + getHeaterState() == heaterStateReady && getAirgate() > 50) { + setAirgate(50); alert_P(BEEPS, LENGTH, TONE, PSTR(MSG_AIRGATE_50_0), PSTR(""), false); *fired = true; } @@ -145,7 +146,7 @@ if (! *fired && state == firing_up && meas.tempI > TEMP_FIRE_OUT && tempIMax >= TEMP_AIRGATE_50) { resetRules(false); - airgate = 100; + setAirgate(100); tempIMax = meas.tempI; if (getHeaterState() != heaterStateFault) { setHeaterState(heaterStateOn); @@ -208,7 +209,7 @@ if (heaterUptime >= 10800 && meas.tempI < TEMP_AIRGATE_0 && meas.lambda >= LAMBDA_MAX) { setHeaterState(heaterStateOff); - if (airgate > 0) { + if (getAirgate() > 0) { alert_P(BEEPS, LENGTH, TONE, PSTR(MSG_AIRGATE_CLOSE_0), PSTR(""), false); } else { @@ -293,7 +294,7 @@ initQueue(TEMP_INIT); measCount = MEAS_INT; state = undefined; - airgate = 100; + setAirgate(100); } size_t rulesSize = sizeof(rules) / sizeof(rules[0]);