Bug fixes for timers, added some wdt support for limit debounce.

- Typo in timer def,
- Handle 8 bit timers correctly,
- Don't skip TOP count in CTC mode
- added SREG for atomic bit operations
This commit is contained in:
ashelly
2014-07-10 13:01:03 -04:00
parent 23ed7b6d4b
commit 9b37637ae6
7 changed files with 198 additions and 138 deletions

View File

@@ -22,12 +22,14 @@
#include "interrupt.h"
#include "io.h"
#include "wdt.h"
//pseudo-Interrupt vector table
//pseudo-Interrupt vector table
isr_fp compa_vect[6]={0};
isr_fp compb_vect[6]={0};
isr_fp ovf_vect[6]={0};
isr_fp wdt_vect = 0;
isr_fp pc_vect = 0;
void sei() {io.sreg|=SEI;}
void cli() {io.sreg&=~SEI;}
@@ -45,91 +47,108 @@ enum sim_wgm_mode {
wgm_RESERVED
};
enum sim_wgm_mode sim_wgm0[4] = {wgm_NORMAL,wgm_PHASE_PWM,wgm_CTC,wgm_FAST_PWM};
enum sim_wgm_mode sim_wgmN[8] = {wgm_NORMAL,wgm_PHASE_PWM,wgm_PHASE_PWM,wgm_PH_F_PWM,
wgm_CTC, wgm_FAST_PWM, wgm_FAST_PWM, wgm_FAST_PWM};
//3-bit wgm table for 8-bit timers
enum sim_wgm_mode sim_wgm_3[] = {wgm_NORMAL,wgm_PHASE_PWM,wgm_CTC,wgm_FAST_PWM,
wgm_RESERVED,wgm_PHASE_PWM, wgm_RESERVED, wgm_FAST_PWM};
//4-bit wgm modes for 16-bit timers
enum sim_wgm_mode sim_wgm_4[16] = {wgm_NORMAL,wgm_PHASE_PWM,wgm_PHASE_PWM,wgm_PHASE_PWM,
wgm_CTC, wgm_FAST_PWM, wgm_FAST_PWM, wgm_FAST_PWM,
wgm_PH_F_PWM, wgm_PH_F_PWM, wgm_PHASE_PWM, wgm_PHASE_PWM,
wgm_CTC, wgm_RESERVED, wgm_FAST_PWM, wgm_FAST_PWM};
static const uint16_t timer_bitdepth[SIM_N_TIMERS] = {
0xFF,0xFFFF,0xFF,
//0xFFFF,0xFFFF,0xFFFF 3 more for mega
};
void timer_interrupts() {
int i;
uint8_t ien = io.sreg&SEI; //interrupts enabled?
io.prescaler++;
//all clocks
for (i=0;i<2;i++){
for (i=0;i<SIM_N_TIMERS;i++){
uint8_t cs = io.tccrb[i]&7; //clock select bits
int16_t increment = sim_scaling[cs];
uint16_t bitmask = timer_bitdepth[i];
uint8_t cs = io.tccrb[i]&7; //clock select bits
int16_t increment = sim_scaling[cs];
//check scaling to see if timer fires
if (increment && (io.prescaler&(increment-1))==0) {
//check scaling to see if timer fires
if (increment && (io.prescaler&(increment-1))==0) {
//select waveform generation mode
enum sim_wgm_mode mode;
if (i==0 || i==2) { //(T0 and T2 are different from rest)
uint8_t wgm = io.tccra[i]&3; //look at low 2 bits
mode = sim_wgm0[wgm];
}
else {
uint8_t wgm = ((io.tccrb[i]&8)>>1) | (io.tccra[i]&3); //only using 3 bits for now
mode = sim_wgmN[wgm];
}
//tick
io.tcnt[i]++;
//comparators
if ((io.timsk[i]&(1<<SIM_OCA)) && io.tcnt[i]==io.ocra[i]) io.tifr[i]|=(1<<SIM_OCA);
if ((io.timsk[i]&(1<<SIM_OCB)) && io.tcnt[i]==io.ocrb[i]) io.tifr[i]|=(1<<SIM_OCB);
if ((io.timsk[i]&(1<<SIM_OCC)) && io.tcnt[i]==io.ocrc[i]) io.tifr[i]|=(1<<SIM_OCC);
//select waveform generation mode
enum sim_wgm_mode mode;
if (i==0 || i==2) { //(T0 and T2 use only 3 wgm bits)
uint8_t wgm = ((io.tccrb[i]&0x08)>>1) | (io.tccra[i]&3);
mode = sim_wgm_3[wgm];
}
else {
uint8_t wgm = ((io.tccrb[i]&0x18)>>1) | (io.tccra[i]&3); //4 wgm bits
mode = sim_wgm_4[wgm];
}
switch (mode) {
case wgm_NORMAL: //Normal mode
if (i==0) io.tcnt[i]&=0xFF; //timer0 is 8 bit;
if (i==2) io.tcnt[i]&=0xFF; //timer2 is 8 bit;
if (io.tcnt[i]==0) io.tifr[i]|=(1<<SIM_TOV);
break;
//tick
if (io.tifr[i]&(1<<SIM_ROLL)) { //handle CTC mode rollover
io.tcnt[i]=0;
io.tifr[i]&=~(1<<SIM_ROLL);
}
else {
io.tcnt[i]++;
}
io.tcnt[i]&=bitmask; //limit the 8 bit timers
case wgm_CTC: //CTC mode
if (io.tcnt[i]==io.ocra[i]) io.tcnt[i]=0;
break;
default: //unsupported
break;
}
//call any triggered interupts
if (ien && io.tifr[i]) {
if (compa_vect[i] && (io.tifr[i]&(1<<SIM_OCA))) {
compa_vect[i]();
io.tifr[i]&=~(1<<SIM_OCA);
//TODO: insert port_monitor call here
}
if (compb_vect[i] && (io.tifr[i]&(1<<SIM_OCB))) {
compb_vect[i]();
io.tifr[i]&=~(1<<SIM_OCB);
}
if (ovf_vect[i] && (io.tifr[i]&(1<<SIM_TOV))) {
ovf_vect[i]();
io.tifr[i]&=~(1<<SIM_TOV);
}
}
}
switch (mode) {
case wgm_NORMAL: //Normal mode, ovf on rollover
if (io.tcnt[i]==0) io.tifr[i]|=(1<<SIM_TOV); //overflow
break;
case wgm_CTC: //CTC mode, ovf at TOP, 0 next tick
if (io.tcnt[i]==(io.ocra[i]&bitmask)) {
io.tifr[i]|=(1<<SIM_TOV)|(1<<SIM_ROLL); //overflow
}
break;
default: //unsupported
break;
}
//comparators
if ((io.timsk[i]&(1<<SIM_OCA)) && io.tcnt[i]==(io.ocra[i]&bitmask)) io.tifr[i]|=(1<<SIM_OCA);
if ((io.timsk[i]&(1<<SIM_OCB)) && io.tcnt[i]==(io.ocrb[i]&bitmask)) io.tifr[i]|=(1<<SIM_OCB);
if ((io.timsk[i]&(1<<SIM_OCC)) && io.tcnt[i]==(io.ocrc[i]&bitmask)) io.tifr[i]|=(1<<SIM_OCC);
//call any triggered interupts
if (ien && io.tifr[i]) {
if (compa_vect[i] && (io.tifr[i]&(1<<SIM_OCA))) {
compa_vect[i]();
io.tifr[i]&=~(1<<SIM_OCA);
//TODO: insert port_monitor call here
}
if (compb_vect[i] && (io.tifr[i]&(1<<SIM_OCB))) {
compb_vect[i]();
io.tifr[i]&=~(1<<SIM_OCB);
}
if (ovf_vect[i] && (io.tifr[i]&(1<<SIM_TOV))) {
ovf_vect[i]();
io.tifr[i]&=~(1<<SIM_TOV);
}
}
}
}
//// TODO for more complete timer sim.
// pwm modes. (only used for variable spindle, I think).
//// TODO for more complete timer sim.
// pwm modes. (only used for variable spindle, I think).
// -- would require fixing wgm mode for Timers1..5
// -- phase correct modes need updown counter.
// output pins (also only for variable spindle, I think).
//// Other chip features not needed yet for grbl:
// writes to TCNT0 prevent compare match (need write detector.)
// writes to TCNT0 prevent compare match (need write detector.)
// force output compare (unused)
// input capture (unused and how would we signal it?)
// define the other output compare registers.
// usercode can clear unhandled interrupt flags by writing 1.
// usercode can clear unhandled interrupt flags by writing 1.
// --(this may be impossible, since bit was 1 before the write.)
// prescaler reset.
// maybe need to cli on interrupt entry
}