Skip to content

Commit

Permalink
Merge pull request #430 from gin66/master
Browse files Browse the repository at this point in the history
fix timer foc behavior
  • Loading branch information
buserror committed Jun 3, 2021
2 parents 3021456 + 8d660ce commit a56b550
Show file tree
Hide file tree
Showing 5 changed files with 70 additions and 19 deletions.
28 changes: 20 additions & 8 deletions simavr/cores/sim_mega2560.h
Expand Up @@ -316,6 +316,7 @@ const struct mcu_t {
.r_ocrh = OCR1AH, // 16 bits timers have two bytes of it
.com = AVR_IO_REGBITS(TCCR1A, COM1A0, 0x3),
.com_pin = AVR_IO_REGBIT(PORTB, PB5),
.foc = AVR_IO_REGBIT(TCCR1C, FOC1A),
.interrupt = {
.enable = AVR_IO_REGBIT(TIMSK1, OCIE1A),
.raised = AVR_IO_REGBIT(TIFR1, OCF1A),
Expand All @@ -327,6 +328,7 @@ const struct mcu_t {
.r_ocrh = OCR1BH,
.com = AVR_IO_REGBITS(TCCR1A, COM1B0, 0x3),
.com_pin = AVR_IO_REGBIT(PORTB, PB6),
.foc = AVR_IO_REGBIT(TCCR1C, FOC1B),
.interrupt = {
.enable = AVR_IO_REGBIT(TIMSK1, OCIE1B),
.raised = AVR_IO_REGBIT(TIFR1, OCF1B),
Expand All @@ -338,6 +340,7 @@ const struct mcu_t {
.r_ocrh = OCR1CH,
.com = AVR_IO_REGBITS(TCCR1A, COM1C0, 0x3),
.com_pin = AVR_IO_REGBIT(PORTB, PB7), // same as timer0A
.foc = AVR_IO_REGBIT(TCCR1C, FOC1C),
.interrupt = {
.enable = AVR_IO_REGBIT(TIMSK1, OCIE1C),
.raised = AVR_IO_REGBIT(TIFR1, OCF1C),
Expand Down Expand Up @@ -382,14 +385,14 @@ const struct mcu_t {
},
// TIMER2_COMPB is only appeared in 2560
[AVR_TIMER_COMPB] = {
.r_ocr = OCR2B,
.com = AVR_IO_REGBITS(TCCR2A, COM2B0, 0x3),
.com_pin = AVR_IO_REGBIT(PORTH, PH6),
.interrupt = {
.enable = AVR_IO_REGBIT(TIMSK2, OCIE2B),
.raised = AVR_IO_REGBIT(TIFR2, OCF2B),
.vector = TIMER2_COMPB_vect,
},
.r_ocr = OCR2B,
.com = AVR_IO_REGBITS(TCCR2A, COM2B0, 0x3),
.com_pin = AVR_IO_REGBIT(PORTH, PH6),
.interrupt = {
.enable = AVR_IO_REGBIT(TIMSK2, OCIE2B),
.raised = AVR_IO_REGBIT(TIFR2, OCF2B),
.vector = TIMER2_COMPB_vect,
},
},
},
},
Expand Down Expand Up @@ -437,6 +440,7 @@ const struct mcu_t {
.r_ocrh = OCR3AH, // 16 bits timers have two bytes of it
.com = AVR_IO_REGBITS(TCCR3A, COM3A0, 0x3),
.com_pin = AVR_IO_REGBIT(PORTE, PE3),
.foc = AVR_IO_REGBIT(TCCR3C, FOC3A),
.interrupt = {
.enable = AVR_IO_REGBIT(TIMSK3, OCIE3A),
.raised = AVR_IO_REGBIT(TIFR3, OCF3A),
Expand All @@ -448,6 +452,7 @@ const struct mcu_t {
.r_ocrh = OCR3BH,
.com = AVR_IO_REGBITS(TCCR3A, COM3B0, 0x3),
.com_pin = AVR_IO_REGBIT(PORTE, PE4),
.foc = AVR_IO_REGBIT(TCCR3C, FOC3B),
.interrupt = {
.enable = AVR_IO_REGBIT(TIMSK3, OCIE3B),
.raised = AVR_IO_REGBIT(TIFR3, OCF3B),
Expand All @@ -459,6 +464,7 @@ const struct mcu_t {
.r_ocrh = OCR3CH,
.com = AVR_IO_REGBITS(TCCR3A, COM3C0, 0x3),
.com_pin = AVR_IO_REGBIT(PORTE, PE5),
.foc = AVR_IO_REGBIT(TCCR3C, FOC3C),
.interrupt = {
.enable = AVR_IO_REGBIT(TIMSK3, OCIE3C),
.raised = AVR_IO_REGBIT(TIFR3, OCF3C),
Expand Down Expand Up @@ -519,6 +525,7 @@ const struct mcu_t {
.r_ocrh = OCR4AH, // 16 bits timers have two bytes of it
.com = AVR_IO_REGBITS(TCCR4A, COM4A0, 0x3),
.com_pin = AVR_IO_REGBIT(PORTH, PH3),
.foc = AVR_IO_REGBIT(TCCR4C, FOC4A),
.interrupt = {
.enable = AVR_IO_REGBIT(TIMSK4, OCIE4A),
.raised = AVR_IO_REGBIT(TIFR4, OCF4A),
Expand All @@ -530,6 +537,7 @@ const struct mcu_t {
.r_ocrh = OCR4BH,
.com = AVR_IO_REGBITS(TCCR4A, COM4B0, 0x3),
.com_pin = AVR_IO_REGBIT(PORTH, PH4),
.foc = AVR_IO_REGBIT(TCCR4C, FOC4B),
.interrupt = {
.enable = AVR_IO_REGBIT(TIMSK4, OCIE4B),
.raised = AVR_IO_REGBIT(TIFR4, OCF4B),
Expand All @@ -541,6 +549,7 @@ const struct mcu_t {
.r_ocrh = OCR4CH,
.com = AVR_IO_REGBITS(TCCR4A, COM4C0, 0x3),
.com_pin = AVR_IO_REGBIT(PORTH, PH5),
.foc = AVR_IO_REGBIT(TCCR4C, FOC4C),
.interrupt = {
.enable = AVR_IO_REGBIT(TIMSK4, OCIE4C),
.raised = AVR_IO_REGBIT(TIFR4, OCF4C),
Expand Down Expand Up @@ -597,6 +606,7 @@ const struct mcu_t {
.r_ocrh = OCR5AH, // 16 bits timers have two bytes of it
.com = AVR_IO_REGBITS(TCCR5A, COM5A0, 0x3),
.com_pin = AVR_IO_REGBIT(PORTL, PL3),
.foc = AVR_IO_REGBIT(TCCR5C, FOC5A),
.interrupt = {
.enable = AVR_IO_REGBIT(TIMSK5, OCIE5A),
.raised = AVR_IO_REGBIT(TIFR5, OCF5A),
Expand All @@ -608,6 +618,7 @@ const struct mcu_t {
.r_ocrh = OCR5BH,
.com = AVR_IO_REGBITS(TCCR5A, COM5B0, 0x3),
.com_pin = AVR_IO_REGBIT(PORTL, PL4),
.foc = AVR_IO_REGBIT(TCCR5C, FOC5B),
.interrupt = {
.enable = AVR_IO_REGBIT(TIMSK5, OCIE5B),
.raised = AVR_IO_REGBIT(TIFR5, OCF5B),
Expand All @@ -619,6 +630,7 @@ const struct mcu_t {
.r_ocrh = OCR5CH,
.com = AVR_IO_REGBITS(TCCR5A, COM5C0, 0x3),
.com_pin = AVR_IO_REGBIT(PORTL, PL5),
.foc = AVR_IO_REGBIT(TCCR5C, FOC5C),
.interrupt = {
.enable = AVR_IO_REGBIT(TIMSK5, OCIE5C),
.raised = AVR_IO_REGBIT(TIFR5, OCF5C),
Expand Down
2 changes: 2 additions & 0 deletions simavr/cores/sim_mega32u4.c
Expand Up @@ -331,6 +331,7 @@ const struct mcu_t {
.r_ocrh = OCR1AH, // 16 bits timers have two bytes of it
.com = AVR_IO_REGBITS(TCCR1A, COM1A0, 0x3),
.com_pin = AVR_IO_REGBIT(PORTB, 5),
.foc = AVR_IO_REGBIT(TCCR1C, FOC1A),
.interrupt = {
.enable = AVR_IO_REGBIT(TIMSK1, OCIE1A),
.raised = AVR_IO_REGBIT(TIFR1, OCF1A),
Expand All @@ -342,6 +343,7 @@ const struct mcu_t {
.r_ocrh = OCR1BH,
.com = AVR_IO_REGBITS(TCCR1A, COM1B0, 0x3),
.com_pin = AVR_IO_REGBIT(PORTB, 6),
.foc = AVR_IO_REGBIT(TCCR1C, FOC1B),
.interrupt = {
.enable = AVR_IO_REGBIT(TIMSK1, OCIE1B),
.raised = AVR_IO_REGBIT(TIFR1, OCF1B),
Expand Down
2 changes: 2 additions & 0 deletions simavr/cores/sim_megax8.h
Expand Up @@ -279,6 +279,7 @@ const struct mcu_t SIM_CORENAME = {
.r_ocrh = OCR1AH, // 16 bits timers have two bytes of it
.com = AVR_IO_REGBITS(TCCR1A, COM1A0, 0x3),
.com_pin = AVR_IO_REGBIT(PORTB, 1),
.foc = AVR_IO_REGBIT(TCCR1C, FOC1A),
.interrupt = {
.enable = AVR_IO_REGBIT(TIMSK1, OCIE1A),
.raised = AVR_IO_REGBIT(TIFR1, OCF1A),
Expand All @@ -290,6 +291,7 @@ const struct mcu_t SIM_CORENAME = {
.r_ocrh = OCR1BH,
.com = AVR_IO_REGBITS(TCCR1A, COM1B0, 0x3),
.com_pin = AVR_IO_REGBIT(PORTB, 2),
.foc = AVR_IO_REGBIT(TCCR1C, FOC1B),
.interrupt = {
.enable = AVR_IO_REGBIT(TIMSK1, OCIE1B),
.raised = AVR_IO_REGBIT(TIFR1, OCF1B),
Expand Down
56 changes: 45 additions & 11 deletions simavr/sim/avr_timer.c
Expand Up @@ -74,32 +74,39 @@ static avr_cycle_count_t
avr_timer_comp(
avr_timer_t *p,
avr_cycle_count_t when,
uint8_t comp)
uint8_t comp,
uint8_t raise_interrupt)
{
avr_t * avr = p->io.avr;
avr_raise_interrupt(avr, &p->comp[comp].interrupt);
if (raise_interrupt) {
avr_raise_interrupt(avr, &p->comp[comp].interrupt);
}

// check output compare mode and set/clear pins
uint8_t mode = avr_regbit_get(avr, p->comp[comp].com);
avr_irq_t * irq = &p->io.irq[TIMER_IRQ_OUT_COMP + comp];

uint32_t flags = 0;
if (p->comp[comp].com_pin.reg) // we got a physical pin
flags |= AVR_IOPORT_OUTPUT;
AVR_LOG(avr, LOG_TRACE, "Timer comp: irq %p, mode %d @%d\n", irq, mode, when);
switch (mode) {
case avr_timer_com_normal: // Normal mode OCnA disconnected
break;
case avr_timer_com_toggle: // Toggle OCnA on compare match
if (p->comp[comp].com_pin.reg) // we got a physical pin
avr_raise_irq(irq,
AVR_IOPORT_OUTPUT |
flags |
(avr_regbit_get(avr, p->comp[comp].com_pin) ? 0 : 1));
else // no pin, toggle the IRQ anyway
avr_raise_irq(irq,
p->io.irq[TIMER_IRQ_OUT_COMP + comp].value ? 0 : 1);
break;
case avr_timer_com_clear:
avr_raise_irq(irq, 0);
avr_raise_irq(irq, flags | 0);
break;
case avr_timer_com_set:
avr_raise_irq(irq, 1);
avr_raise_irq(irq, flags | 1);
break;
}

Expand All @@ -120,6 +127,11 @@ avr_timer_comp_on_tov(
uint8_t mode = avr_regbit_get(avr, p->comp[comp].com);
avr_irq_t * irq = &p->io.irq[TIMER_IRQ_OUT_COMP + comp];

// only PWM modes have special behaviour on overflow
if((p->wgm_op_mode_kind != avr_timer_wgm_pwm) &&
(p->wgm_op_mode_kind != avr_timer_wgm_fast_pwm))
return;

switch (mode) {
case avr_timer_com_normal: // Normal mode
break;
Expand All @@ -140,7 +152,7 @@ avr_timer_compa(
avr_cycle_count_t when,
void * param)
{
return avr_timer_comp((avr_timer_t*)param, when, AVR_TIMER_COMPA);
return avr_timer_comp((avr_timer_t*)param, when, AVR_TIMER_COMPA, 1);
}

static avr_cycle_count_t
Expand All @@ -149,7 +161,7 @@ avr_timer_compb(
avr_cycle_count_t when,
void * param)
{
return avr_timer_comp((avr_timer_t*)param, when, AVR_TIMER_COMPB);
return avr_timer_comp((avr_timer_t*)param, when, AVR_TIMER_COMPB, 1);
}

static avr_cycle_count_t
Expand All @@ -158,7 +170,7 @@ avr_timer_compc(
avr_cycle_count_t when,
void * param)
{
return avr_timer_comp((avr_timer_t*)param, when, AVR_TIMER_COMPC);
return avr_timer_comp((avr_timer_t*)param, when, AVR_TIMER_COMPC, 1);
}

static void
Expand Down Expand Up @@ -704,6 +716,23 @@ avr_timer_write(
}
}

/*
* write to the "force output compare" bits
*/
static void avr_timer_write_foc(struct avr_t * avr, avr_io_addr_t addr, uint8_t v, void * param)
{
avr_timer_t * p = (avr_timer_t *)param;

/* These are strobe writes, so just decode them, don't store them */

for (int compi = 0; compi < AVR_TIMER_COMP_COUNT; compi++) {
if ((addr == p->comp[compi].foc.reg) &&
(v & (1 << p->comp[compi].foc.bit))) {
avr_timer_comp(p, avr->cycle, compi, 0);
}
}
}

/*
* write to the TIFR register. Watch for code that writes "1" to clear
* pending interrupts.
Expand All @@ -728,11 +757,14 @@ avr_timer_write_pending(
// avr_core_watch_write(avr, addr, v); // This raises flags instead of clearing it.

// clear any interrupts & flags
avr_clear_interrupt_if(avr, &p->overflow, ov);
avr_clear_interrupt_if(avr, &p->icr, ic);
if (avr_regbit_from_value(avr, p->overflow.raised, v))
avr_clear_interrupt_if(avr, &p->overflow, ov);
if (avr_regbit_from_value(avr, p->icr.raised, v))
avr_clear_interrupt_if(avr, &p->icr, ic);

for (int compi = 0; compi < AVR_TIMER_COMP_COUNT; compi++)
avr_clear_interrupt_if(avr, &p->comp[compi].interrupt, cp[compi]);
if (avr_regbit_from_value(avr, p->comp[compi].interrupt.raised, v))
avr_clear_interrupt_if(avr, &p->comp[compi].interrupt, cp[compi]);
}

static void
Expand Down Expand Up @@ -938,6 +970,8 @@ avr_timer_init(

if (p->comp[compi].r_ocr) // not all timers have all comparators
avr_register_io_write(avr, p->comp[compi].r_ocr, avr_timer_write_ocr, &p->comp[compi]);
if (p->comp[compi].foc.reg)
avr_register_io_write(avr, p->comp[compi].foc.reg, avr_timer_write_foc, p);
}
avr_register_io_write(avr, p->r_tcnt, avr_timer_tcnt_write, p);
avr_register_io_read(avr, p->r_tcnt, avr_timer_tcnt_read, p);
Expand Down
1 change: 1 addition & 0 deletions simavr/sim/avr_timer.h
Expand Up @@ -115,6 +115,7 @@ typedef struct avr_timer_comp_t {
avr_regbit_t com; // comparator output mode registers
avr_regbit_t com_pin; // where comparator output is connected
uint64_t comp_cycles;
avr_regbit_t foc; // "force compare match" strobe
} avr_timer_comp_t, *avr_timer_comp_p;

enum {
Expand Down

0 comments on commit a56b550

Please sign in to comment.