merging unified_timer stuff
This commit is contained in:
parent
d93dcff378
commit
c7ac215c59
2
Makefile
2
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
|
||||
|
||||
##############################################################################
|
||||
# #
|
||||
|
|
|
|||
74
clock.c
74
clock.c
|
|
@ -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
32
clock.h
|
|
@ -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
1
dda.c
|
|
@ -399,7 +399,6 @@ void dda_start(DDA *dda) {
|
|||
|
||||
// set timeout for first step
|
||||
setTimer(dda->c >> 8);
|
||||
enableTimerInterrupt();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
15
dda_queue.c
15
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() {
|
||||
|
|
|
|||
2
delay.h
2
delay.h
|
|
@ -3,6 +3,8 @@
|
|||
|
||||
#include <stdint.h>
|
||||
|
||||
#define WAITING_DELAY 10 MS
|
||||
|
||||
void delay(uint32_t delay);
|
||||
|
||||
void delay_ms(uint32_t delay);
|
||||
|
|
|
|||
|
|
@ -248,7 +248,7 @@ void process_gcode_command() {
|
|||
#endif
|
||||
// M112- immediate stop
|
||||
case 112:
|
||||
disableTimerInterrupt();
|
||||
timer_stop();
|
||||
queue_flush();
|
||||
power_off();
|
||||
break;
|
||||
|
|
|
|||
10
mendel.c
10
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();*/
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
176
timer.c
176
timer.c
|
|
@ -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
23
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<<OCIE1A); } while (0)
|
||||
#define disableTimerInterrupt() do { TIMSK1 &= ~(1<<OCIE1A); } while (0)
|
||||
#define timerInterruptIsEnabled() (TIMSK1 & (1 << OCIE1A))
|
||||
void timer_stop(void);
|
||||
|
||||
#endif /* _TIMER_H */
|
||||
|
|
|
|||
Loading…
Reference in New Issue