diff --git a/Makefile b/Makefile index f28534d..a68da2f 100644 --- a/Makefile +++ b/Makefile @@ -31,7 +31,7 @@ PROGRAM = mendel -SOURCES = $(PROGRAM).c serial.c dda.c gcode_parse.c gcode_process.c clock.c timer.c temp.c sermsg.c dda_queue.c watchdog.c debug.c sersendf.c heater.c analog.c delay.c +SOURCES = $(PROGRAM).c serial.c dda.c gcode_parse.c gcode_process.c timer.c temp.c sermsg.c dda_queue.c watchdog.c debug.c sersendf.c heater.c analog.c delay.c ############################################################################## # # diff --git a/clock.c b/clock.c deleted file mode 100644 index 9056814..0000000 --- a/clock.c +++ /dev/null @@ -1,74 +0,0 @@ -/* - clock.c - - a system clock with 1ms ticks -*/ - -#include "clock.h" - -#include -#include - -#include "config.h" - -// global clock -#ifdef GLOBAL_CLOCK -volatile uint32_t clock = 0; -#endif - -// 1/4 second tick -uint8_t clock_counter_250ms = 0; -uint8_t clock_counter_1s = 0; -volatile uint8_t clock_flag = 0; - -void clock_setup() { - // use system clock - ASSR = 0; - - // no compare match, CTC mode - TCCR2A = MASK(WGM21); - // TODO: Timer 2 has higher priority than Timer 1 used for the stepper - // interrupts, which is bad. See AVR Reference Manual p. 9: - // "The interrupts have priority in accordance - // with their Interrupt Vector position. The - // lower the Interrupt Vector address, the higher - // the priority." - // in conjunction with p. 63 (interrupt vector table). - - // 128 prescaler (16MHz / 128 = 125KHz) - TCCR2B = MASK(CS22) | MASK(CS20); - - // 125KHz / 125 = 1KHz for a 1ms tick rate - OCR2A = 125; - - // interrupt on overflow, when counter reaches OCR2A - TIMSK2 |= MASK(OCIE2A); -} - -ISR(TIMER2_COMPA_vect) { - // global clock -#ifdef GLOBAL_CLOCK - clock++; -#endif - // 1/4 second tick - if (++clock_counter_250ms == 250) { - clock_flag |= CLOCK_FLAG_250MS; - clock_counter_250ms = 0; - if (++clock_counter_1s == 4) { - clock_flag |= CLOCK_FLAG_1S; - clock_counter_1s = 0; - } - } -} - -#ifdef GLOBAL_CLOCK -uint32_t clock_read() { - uint32_t c; - - cli(); // set atomic - c = clock; // copy clock value - sei(); // release atomic - - return c; -} -#endif diff --git a/clock.h b/clock.h deleted file mode 100644 index b8eabf0..0000000 --- a/clock.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef _CLOCK_H -#define _CLOCK_H - -#include - -void clock_setup(void) __attribute__ ((cold)); - -#ifdef GLOBAL_CLOCK -uint32_t clock_read(void); -#endif - -extern volatile uint8_t clock_flag; - -#define CLOCK_FLAG_250MS 1 -#define CLOCK_FLAG_1S 2 - -/* - ifclock() {} - - so we can do stuff like: - ifclock(CLOCK_FLAG_250MS) { - report(); - } - - or: - ifclock(CLOCK_FLAG_1S) - power_off(); -*/ - -#define ifclock(F) for (;clock_flag & (F);clock_flag &= ~(F)) - -#endif /* _CLOCK_H */ diff --git a/dda.c b/dda.c index d079df4..44c2c1e 100644 --- a/dda.c +++ b/dda.c @@ -399,7 +399,6 @@ void dda_start(DDA *dda) { // set timeout for first step setTimer(dda->c >> 8); - enableTimerInterrupt(); } } diff --git a/dda_queue.c b/dda_queue.c index fb3edb2..d295c14 100644 --- a/dda_queue.c +++ b/dda_queue.c @@ -9,6 +9,7 @@ #include "sermsg.h" #include "temp.h" #include "delay.h" +#include "sersendf.h" uint8_t mb_head = 0; uint8_t mb_tail = 0; @@ -78,7 +79,7 @@ void enqueue(TARGET *t) { mb_head = h; // fire up in case we're not running yet - if (timerInterruptIsEnabled() == 0) + if (movebuffer[mb_tail].live == 0) next_move(); } @@ -92,19 +93,11 @@ void next_move() { mb_tail = t; } else - disableTimerInterrupt(); + setTimer(0); } void print_queue() { - serial_writechar('Q'); - serwrite_uint8(mb_tail); - serial_writechar('/'); - serwrite_uint8(mb_head); - if (queue_full()) - serial_writechar('F'); - if (queue_empty()) - serial_writechar('E'); - serial_writechar('\n'); + sersendf_P(PSTR("Q%d/%d%c\n"), mb_tail, mb_head, (queue_full()?'F':(queue_empty()?'E':' '))); } void queue_flush() { diff --git a/delay.h b/delay.h index 16abe03..83aaf36 100644 --- a/delay.h +++ b/delay.h @@ -3,6 +3,8 @@ #include +#define WAITING_DELAY 10 MS + void delay(uint32_t delay); void delay_ms(uint32_t delay); diff --git a/gcode_process.c b/gcode_process.c index 9a31d4c..542d064 100644 --- a/gcode_process.c +++ b/gcode_process.c @@ -248,7 +248,7 @@ void process_gcode_command() { #endif // M112- immediate stop case 112: - disableTimerInterrupt(); + timer_stop(); queue_flush(); power_off(); break; diff --git a/mendel.c b/mendel.c index ee9aeda..08fb037 100644 --- a/mendel.c +++ b/mendel.c @@ -9,7 +9,6 @@ #include "dda.h" #include "gcode_parse.h" #include "timer.h" -#include "clock.h" #include "temp.h" #include "sermsg.h" #include "watchdog.h" @@ -93,10 +92,7 @@ void init(void) { io_init(); // set up timers - setupTimerInterrupt(); - - // set up clock - clock_setup(); + timer_init(); // read PID settings from EEPROM heater_init(); @@ -142,8 +138,8 @@ void clock_250ms(void) { print_queue(); } // temperature - if (temp_get_target()) - temp_print(); +/* if (temp_get_target()) + temp_print();*/ } } diff --git a/timer.c b/timer.c index 90a6118..2f4586f 100644 --- a/timer.c +++ b/timer.c @@ -3,102 +3,112 @@ #include #include "dda_queue.h" -#include "watchdog.h" + +volatile uint32_t next_step_time; + +uint8_t clock_counter_250ms = 0; +uint8_t clock_counter_1s = 0; +volatile uint8_t clock_flag = 0; + +// how often we overflow and update our clock; with F_CPU=16MHz, max is < 4.096ms (TICK_TIME = 65535) +#define TICK_TIME 2 MS + +// timer overflow, happens every TICK_TIME +ISR(TIMER1_CAPT_vect) { + /* + check if next step time will occur before next overflow + */ + if (next_step_time > TICK_TIME) + next_step_time -= TICK_TIME; + else { + if (next_step_time > 0) { + OCR1A = next_step_time & 0xFFFF; + TIMSK1 |= MASK(OCIE1A); + } + } + + /* + clock stuff + */ + clock_counter_250ms += (TICK_TIME / (F_CPU / 1000)); + if (clock_counter_250ms >= 250) { + clock_counter_250ms -= 250; + clock_flag |= CLOCK_FLAG_250MS; + clock_counter_1s += 1; + if (clock_counter_1s >= 4) { + clock_counter_1s -= 4; + clock_flag |= CLOCK_FLAG_1S; + } + } +} ISR(TIMER1_COMPA_vect) { + // led on WRITE(SCK, 1); - + + // disable this interrupt. if we set a new timeout, it will be re-enabled when appropriate + TIMSK1 &= ~MASK(OCIE1A); + + // ensure we don't interrupt again unless timer is reset + next_step_time = 0; + + /* + stepper tick + */ queue_step(); - + + // led off WRITE(SCK, 0); } -void setupTimerInterrupt() +void timer_init() { // no outputs TCCR1A = 0; - // CTC mode - TCCR1B = MASK(WGM12); - // no interrupts yet - TIMSK1 = 0; + // CTC mode- use ICR for top + TCCR1B = MASK(WGM13) | MASK(WGM12) | MASK(CS10); + // set timeout- first timeout is indeterminate, probably doesn't matter + ICR1 = TICK_TIME; + // overflow interrupt (uses input capture interrupt in CTC:ICR mode) + TIMSK1 = MASK(ICIE1); } -// the following are all from reprap project 5D firmware with some modification to reduce redundancy - -uint8_t getTimerResolution(const uint32_t delay) -{ - // these also represent frequency: 1000000 / delay / 2 = frequency in hz. - - // our slowest speed at our highest resolution ( (2^16-1) * 0.0625 usecs = 4095 usecs (4 millisecond max)) - // range: 8Mhz max - 122hz min - if (delay <= 65535L) - return 1; - // our slowest speed at our next highest resolution ( (2^16-1) * 0.5 usecs = 32767 usecs (32 millisecond max)) - // range:1Mhz max - 15.26hz min - else if (delay <= 524280L) - return 2; - // our slowest speed at our medium resolution ( (2^16-1) * 4 usecs = 262140 usecs (0.26 seconds max)) - // range: 125Khz max - 1.9hz min - else if (delay <= 4194240L) - return 3; - // our slowest speed at our medium-low resolution ( (2^16-1) * 16 usecs = 1048560 usecs (1.04 seconds max)) - // range: 31.25Khz max - 0.475hz min - else if (delay <= 16776960L) - return 4; - // our slowest speed at our lowest resolution ((2^16-1) * 64 usecs = 4194240 usecs (4.19 seconds max)) - // range: 7.812Khz max - 0.119hz min - //its really slow... hopefully we can just get by with super slow. - return 5; -} - -void setTimerResolution(uint8_t r) -{ - // assuming CS10,CS11,CS12 are adjacent bits in platform endian order, - TCCR1B = (TCCR1B & ~(MASK(CS12) | MASK(CS11) | MASK(CS10))) | (r << CS10); -} - -uint16_t getTimerCeiling(const uint32_t delay) -{ - // our slowest speed at our highest resolution ( (2^16-1) * 0.0625 usecs = 4095 usecs) - if (delay <= 65535L) - return (delay & 0xffff); - // our slowest speed at our next highest resolution ( (2^16-1) * 0.5 usecs = 32767 usecs) - else if (delay <= 524280L) - return ((delay >> 3) & 0xffff); - // our slowest speed at our medium resolution ( (2^16-1) * 4 usecs = 262140 usecs) - else if (delay <= 4194240L) - return ((delay >> 6) & 0xffff); - // our slowest speed at our medium-low resolution ( (2^16-1) * 16 usecs = 1048560 usecs) - else if (delay <= 16776960L) - return ((delay >> 8) & 0xffff); - // our slowest speed at our lowest resolution ((2^16-1) * 64 usecs = 4194240 usecs) - else if (delay <= 67107840L) - return ((delay >> 10) & 0xffff); - //its really slow... hopefully we can just get by with super slow. - else - return 65535; -} - - -// Depending on how much work the interrupt function has to do, this is -// pretty accurate between 10 us and 0.1 s. At fast speeds, the time -// taken in the interrupt function becomes significant, of course. - -// Note - it is up to the user to call enableTimerInterrupt() after a call -// to this function. - void setTimer(uint32_t delay) { - // delay is the delay between steps in IOclk ticks. - // - // we break it into 5 different resolutions based on the delay. - // then we set the resolution based on the size of the delay. - // we also then calculate the timer ceiling required. (ie what the counter counts to) - // the result is the timer counts up to the appropriate time and then fires an interrupt. + // save interrupt flag + uint8_t sreg = SREG; + // disable interrupts + cli(); - setTimerResolution(0); // stop timer - GTCCR = MASK(PSRSYNC); // reset prescaler - affects timer 0 too but since it's doing PWM, it's not using the prescaler - - setTimerCeiling(getTimerCeiling(delay)); // set timeout - setTimerResolution(getTimerResolution(delay)); // restart timer with proper prescaler + // re-enable clock interrupt in case we're recovering from emergency stop + TIMSK1 |= MASK(ICIE1); + + if (delay > 0) { + // mangle timer variables + next_step_time = delay + TCNT1; + if (delay <= 16) { + // force interrupt + // TODO: datasheet says force only doesn't work in CTC:COMPA mode, test if CTC:ICR mode allows force + TIMSK1 |= MASK(OCIE1A); + TCCR1C |= MASK(FOC1A); + next_step_time = 0; + } + else if (delay <= TICK_TIME) { + OCR1A = next_step_time & 0xFFFF; + TIMSK1 |= MASK(OCIE1A); + } + } + else { + next_step_time = 0; + } + + // restore interrupt flag + SREG = sreg; +} + +void timer_stop() { + // disable all interrupts + TIMSK1 = 0; + // reset timeout + next_step_time = 0; } diff --git a/timer.h b/timer.h index afb51f8..2626860 100644 --- a/timer.h +++ b/timer.h @@ -8,21 +8,22 @@ #define US * (F_CPU / 1000000) #define MS * (F_CPU / 1000) -// #define DEFAULT_TICK (100 US) -#define WAITING_DELAY (10 MS) +/* +clock stuff +*/ +extern volatile uint8_t clock_flag; -void setupTimerInterrupt(void) __attribute__ ((cold)); +#define CLOCK_FLAG_250MS 1 +#define CLOCK_FLAG_1S 2 +#define ifclock(F) for (;clock_flag & (F);clock_flag &= ~(F)) -uint8_t getTimerResolution(const uint32_t delay); -void setTimerResolution(uint8_t r); - -uint16_t getTimerCeiling(const uint32_t delay); -#define setTimerCeiling(c) OCR1A = c +/* +timer stuff +*/ +void timer_init(void) __attribute__ ((cold)); void setTimer(uint32_t delay); -#define enableTimerInterrupt() do { TIMSK1 |= (1<