merging unified_timer stuff

This commit is contained in:
Michael Moon 2010-10-25 23:14:31 +11:00
parent d93dcff378
commit c7ac215c59
10 changed files with 116 additions and 221 deletions

View File

@ -31,7 +31,7 @@
PROGRAM = mendel 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
############################################################################## ##############################################################################
# # # #

74
clock.c
View File

@ -1,74 +0,0 @@
/*
clock.c
a system clock with 1ms ticks
*/
#include "clock.h"
#include <avr/io.h>
#include <avr/interrupt.h>
#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

32
clock.h
View File

@ -1,32 +0,0 @@
#ifndef _CLOCK_H
#define _CLOCK_H
#include <stdint.h>
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 */

1
dda.c
View File

@ -399,7 +399,6 @@ void dda_start(DDA *dda) {
// set timeout for first step // set timeout for first step
setTimer(dda->c >> 8); setTimer(dda->c >> 8);
enableTimerInterrupt();
} }
} }

View File

@ -9,6 +9,7 @@
#include "sermsg.h" #include "sermsg.h"
#include "temp.h" #include "temp.h"
#include "delay.h" #include "delay.h"
#include "sersendf.h"
uint8_t mb_head = 0; uint8_t mb_head = 0;
uint8_t mb_tail = 0; uint8_t mb_tail = 0;
@ -78,7 +79,7 @@ void enqueue(TARGET *t) {
mb_head = h; mb_head = h;
// fire up in case we're not running yet // fire up in case we're not running yet
if (timerInterruptIsEnabled() == 0) if (movebuffer[mb_tail].live == 0)
next_move(); next_move();
} }
@ -92,19 +93,11 @@ void next_move() {
mb_tail = t; mb_tail = t;
} }
else else
disableTimerInterrupt(); setTimer(0);
} }
void print_queue() { void print_queue() {
serial_writechar('Q'); sersendf_P(PSTR("Q%d/%d%c\n"), mb_tail, mb_head, (queue_full()?'F':(queue_empty()?'E':' ')));
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');
} }
void queue_flush() { void queue_flush() {

View File

@ -3,6 +3,8 @@
#include <stdint.h> #include <stdint.h>
#define WAITING_DELAY 10 MS
void delay(uint32_t delay); void delay(uint32_t delay);
void delay_ms(uint32_t delay); void delay_ms(uint32_t delay);

View File

@ -248,7 +248,7 @@ void process_gcode_command() {
#endif #endif
// M112- immediate stop // M112- immediate stop
case 112: case 112:
disableTimerInterrupt(); timer_stop();
queue_flush(); queue_flush();
power_off(); power_off();
break; break;

View File

@ -9,7 +9,6 @@
#include "dda.h" #include "dda.h"
#include "gcode_parse.h" #include "gcode_parse.h"
#include "timer.h" #include "timer.h"
#include "clock.h"
#include "temp.h" #include "temp.h"
#include "sermsg.h" #include "sermsg.h"
#include "watchdog.h" #include "watchdog.h"
@ -93,10 +92,7 @@ void init(void) {
io_init(); io_init();
// set up timers // set up timers
setupTimerInterrupt(); timer_init();
// set up clock
clock_setup();
// read PID settings from EEPROM // read PID settings from EEPROM
heater_init(); heater_init();
@ -142,8 +138,8 @@ void clock_250ms(void) {
print_queue(); print_queue();
} }
// temperature // temperature
if (temp_get_target()) /* if (temp_get_target())
temp_print(); temp_print();*/
} }
} }

176
timer.c
View File

@ -3,102 +3,112 @@
#include <avr/interrupt.h> #include <avr/interrupt.h>
#include "dda_queue.h" #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) { ISR(TIMER1_COMPA_vect) {
// led on
WRITE(SCK, 1); 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(); queue_step();
// led off
WRITE(SCK, 0); WRITE(SCK, 0);
} }
void setupTimerInterrupt() void timer_init()
{ {
// no outputs // no outputs
TCCR1A = 0; TCCR1A = 0;
// CTC mode // CTC mode- use ICR for top
TCCR1B = MASK(WGM12); TCCR1B = MASK(WGM13) | MASK(WGM12) | MASK(CS10);
// no interrupts yet // set timeout- first timeout is indeterminate, probably doesn't matter
TIMSK1 = 0; 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) void setTimer(uint32_t delay)
{ {
// delay is the delay between steps in IOclk ticks. // save interrupt flag
// uint8_t sreg = SREG;
// we break it into 5 different resolutions based on the delay. // disable interrupts
// then we set the resolution based on the size of the delay. cli();
// 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.
setTimerResolution(0); // stop timer // re-enable clock interrupt in case we're recovering from emergency stop
GTCCR = MASK(PSRSYNC); // reset prescaler - affects timer 0 too but since it's doing PWM, it's not using the prescaler TIMSK1 |= MASK(ICIE1);
setTimerCeiling(getTimerCeiling(delay)); // set timeout if (delay > 0) {
setTimerResolution(getTimerResolution(delay)); // restart timer with proper prescaler // 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;
} }

23
timer.h
View File

@ -8,21 +8,22 @@
#define US * (F_CPU / 1000000) #define US * (F_CPU / 1000000)
#define MS * (F_CPU / 1000) #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); timer stuff
*/
uint16_t getTimerCeiling(const uint32_t delay); void timer_init(void) __attribute__ ((cold));
#define setTimerCeiling(c) OCR1A = c
void setTimer(uint32_t delay); void setTimer(uint32_t delay);
#define enableTimerInterrupt() do { TIMSK1 |= (1<<OCIE1A); } while (0) void timer_stop(void);
#define disableTimerInterrupt() do { TIMSK1 &= ~(1<<OCIE1A); } while (0)
#define timerInterruptIsEnabled() (TIMSK1 & (1 << OCIE1A))
#endif /* _TIMER_H */ #endif /* _TIMER_H */