2017-02-15 58 views
0

我试图在SimAVR运行下面的AVR程序:时钟频率设置不会改变仿真速度

#include <avr/io.h> 
#include <util/delay.h> 

int main() 
{ 
    DDRB |= _BV(DDB5); 

    for (;;) 
    { 
     PORTB ^= _BV(PB5); 
     _delay_ms(2000); 
    } 
} 

我和F_CPU=16000000编译它。该SimAVR亚军如下:

#include <stdlib.h> 
#include <stdio.h> 
#include <pthread.h> 

#include "sim_avr.h" 
#include "avr_ioport.h" 
#include "sim_elf.h" 

avr_t * avr = NULL; 

static void* avr_run_thread(void * ignore) 
{ 
    for (;;) { 
     avr_run(avr); 
    } 
    return NULL; 
} 

void led_changed_hook(struct avr_irq_t* irq, uint32_t value, void* param) 
{ 
    printf("led_changed_hook %d %d\n", irq->irq, value); 
} 

int main(int argc, char *argv[]) 
{ 
    elf_firmware_t f; 
    elf_read_firmware("image.elf", &f); 
    f.frequency = 16e6; 

    const char *mmcu = "atmega328p"; 
    avr = avr_make_mcu_by_name(mmcu); 
    if (!avr) { 
     fprintf(stderr, "%s: AVR '%s' not known\n", argv[0], mmcu); 
     exit(1); 
    } 
    avr_init(avr); 
    avr_load_firmware(avr, &f); 

    avr_irq_register_notify(
     avr_io_getirq(avr, AVR_IOCTL_IOPORT_GETIRQ('B'), 5), 
     led_changed_hook, 
     NULL); 

    pthread_t run; 
    pthread_create(&run, NULL, avr_run_thread, NULL); 

    for (;;) {} 
} 

的问题是,我从led_changed_hook输出,它运行在〜4倍的速度看。而且,改变f.frequency似乎对模拟速度没有任何影响。

如何确保SimAVR以正确的实时速度运行模拟?

+0

为什么要在CPU频率上升时,以毫秒为单位的延迟主要由更快的速度运行? – tofro

+0

我以为'_delay_ms'宏扩展为忙等待?例如,如果我用'F_CPU = 800000'对其进行编译,然后将其上载并运行在运行频率为16MHz的真实芯片上,我确实发现闪烁速度是两倍。 – Cactus

+0

@tofro:[此文档页面](http://www.nongnu.org/avr-libc/user-manual/group__util__delay.html)非常明确指出'_delay_ms'&c。正在使用忙等待编译时计算的循环数。 – Cactus

回答

0

It turns out SimAVR doesn't support timing-accurate simulation of opcodes因此运行的_delay_ms完成的忙等待的仿真时间是完全无关的

  • 它需要多长时间的实际MCU
  • 模拟MCU的时钟频率

正确的解决方案是使用定时器中断,然后在MCU上休眠。模拟器将正确模拟计时器计数器,并且睡眠将暂停模拟,直到计时器触发。

#include <avr/interrupt.h> 
#include <avr/power.h> 
#include <avr/sleep.h> 

int main() 
{ 
    DDRB |= _BV(DDB5); 

    TCCR1A = 0; 
    TCCR1B = 0; 
    TCNT1 = 0; 
    TIMSK1 |= (1 << OCIE1A); 

    sei(); 

    /* Set TIMER1 to 0.5 Hz */ 
    TCCR1B |= (1 << WGM12); 
    OCR1A = 31248; 
    TCCR1B |= ((1 << CS12) | (1 << CS10)); 

    set_sleep_mode(SLEEP_MODE_IDLE); 
    sleep_enable(); 
    for (;;) 
    { 
     sleep_mode(); 
    } 
} 

ISR(TIMER1_COMPA_vect){ 
    PORTB ^= _BV(PB5); 
}