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
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
setTimer(dda->c >> 8);
enableTimerInterrupt();
}
}

View File

@ -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() {

View File

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

View File

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

View File

@ -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();*/
}
}

176
timer.c
View File

@ -3,102 +3,112 @@
#include <avr/interrupt.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) {
// 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;
}

23
timer.h
View File

@ -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<<OCIE1A); } while (0)
#define disableTimerInterrupt() do { TIMSK1 &= ~(1<<OCIE1A); } while (0)
#define timerInterruptIsEnabled() (TIMSK1 & (1 << OCIE1A))
void timer_stop(void);
#endif /* _TIMER_H */