Skip to content

USART as SPI-master: incorrect timing / not properly simulated? #477

@kittennbfive

Description

@kittennbfive

Hi,

the following code for mega1284P configures the USART1 as SPI-master and sends out the same byte again and again (stop the simulation with Ctrl+C!) at maximum speed=f_osc/2. It also sets a pin to measure the time needed for the transmission.

On real hardware with a 18,432MHz crystal this time is about 1,74µs (measured with a scope), but in the VCD-file produced by simavr the time is about 7,7µs! This is way too much.

Is an USART as a SPI-master actually properly simulated by simavr?

#include <avr/io.h>
#include <stdint.h>

uint8_t spi_send_receive(const uint8_t v)
{
	PORTB|=(1<<PB0);
	while(!(UCSR1A&(1<<UDRE1)));
	UDR1=v;
	while(!(UCSR1A&(1<<RXC1)));
	PORTB&=~(1<<PB0);
	return UDR1;
}

int main(void)
{
	DDRB|=(1<<PB0);
	
	//USART1 as SPI, max speed
	UBRR1=0;
	DDRD|=(1<<PD3)|(1<<PD4);
	UCSR1C=(1<<UMSEL11)|(1<<UMSEL10);
	UCSR1B=(1<<RXEN1)|(1<<TXEN1);
	UBRR1=0;
	
	while(1)
		spi_send_receive(0xaa);
	
	return 0;
}
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include <err.h>
#include <signal.h>

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

volatile bool run=true;

static void sigint_handler(int sig)
{
	(void)sig;
	run=false;
}

int main(void)
{
	signal(SIGINT, &sigint_handler);
		
	avr_t *avr1;
	elf_firmware_t firmware1;

	if(elf_read_firmware("avr.elf", &firmware1))
	{
		printf("elf_read_firmware failed\n");
		return 1;
	}
	avr1 = avr_make_mcu_by_name("atmega1284p");
	if (!avr1) {
		printf("avr_make_mcu_by_name failed\n");
		return 1;
	}
	
	avr_init(avr1);
	avr1->frequency=18432000;
	avr_load_firmware(avr1, &firmware1);
	
	avr_vcd_t vcd1;
	avr_vcd_init(avr1, "test.vcd", &vcd1, 100);
	avr_vcd_add_signal(&vcd1, avr_io_getirq(avr1, AVR_IOCTL_IOPORT_GETIRQ('B'), 0), 1, "PB0");
	avr_vcd_start(&vcd1);
	
	//the simulator will block if nothing is "received", so just add a virtual connection
	avr_connect_irq(avr_io_getirq(avr1, AVR_IOCTL_UART_GETIRQ('1'), UART_IRQ_OUTPUT), avr_io_getirq(avr1, AVR_IOCTL_UART_GETIRQ('1'), UART_IRQ_INPUT));
	
	int state1;
	do
	{
		state1=avr_run(avr1);
		
	} while(state1!=cpu_Done && state1!=cpu_Crashed && run);

	avr_vcd_close(&vcd1);
	avr_terminate(avr1);

	return 0;
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions