Ejemplo n.º 1
0
void LcdLogic::wireHook(avr_t *avr)
{
    this->avr = avr;

    hd44780_init(avr, &hd44780, WIDTH, HEIGHT, this, LcdLogic::displayChanged);

    /* Connect data lines to Port C, 4-7 (bidirectional). */
    for (int i = 0; i < 4; i++) {
        avr_irq_t * iavr = avr_io_getirq(avr, AVR_IOCTL_IOPORT_GETIRQ('C'), 4 + i);
        avr_irq_t * ilcd = hd44780.irq + IRQ_HD44780_D4 + i;
        // AVR -> LCD
        avr_connect_irq(iavr, ilcd);
        // LCD -> AVR
        avr_connect_irq(ilcd, iavr);
    }

    avr_connect_irq(avr_io_getirq(avr, AVR_IOCTL_IOPORT_GETIRQ('C'), 2),
                    hd44780.irq + IRQ_HD44780_RS);
    avr_connect_irq(avr_io_getirq(avr, AVR_IOCTL_IOPORT_GETIRQ('C'), 3),
                    hd44780.irq + IRQ_HD44780_E);
    /* RW is set to GND. */

    avr_vcd_init(avr, "lcd.vcd", &vcdFile, 100000);
    avr_vcd_add_signal(&vcdFile,
            avr_io_getirq(avr, AVR_IOCTL_IOPORT_GETIRQ('C'), IOPORT_IRQ_PIN_ALL),
            4 /* bits */, "D4-D7");
    avr_vcd_add_signal(&vcdFile,
            avr_io_getirq(avr, AVR_IOCTL_IOPORT_GETIRQ('C'), 2),
            1 /* bits */, "RS");
    avr_vcd_add_signal(&vcdFile,
            avr_io_getirq(avr, AVR_IOCTL_IOPORT_GETIRQ('C'), 3),
            1 /* bits */, "E");
}
Ejemplo n.º 2
0
void LedButtonsLogic::wireHook(avr_t *avr)
{
    this->avr = avr;

    /* Every port has 8 pins. */
    const int count = strlen(ports) * 8;

    /* Construct the port names. */
    int nameLength = sizeof("PORTA0");
    const char *names[count];
    char _names[count * nameLength];
    char *s = _names;
    for (int i = 0; i < count; i++) {
        int port = i / 8;
        int pin = i % 8;

        snprintf(s, nameLength, "PORT%c%d", ports[port], pin);
        names[i] = s;
        s += nameLength;
    }

    irq = avr_alloc_irq(&avr->irq_pool, 0, count, names);

    for (int i = 0; i < count; i++) {
        int port = i / 8;
        int pin = i % 8;

        avr_connect_irq(irq + i, avr_io_getirq(avr, AVR_IOCTL_IOPORT_GETIRQ(ports[port]), pin));

        /* We need this helper struct to keep track of 1) which port the IRQ came from,
         * and 2) which class instance to notify. */
        CallbackData *d = new CallbackData;
        d->instance = this;
        d->port = 'A' + port;
        callbackData.append(d);

        avr_irq_register_notify(avr_io_getirq(avr, AVR_IOCTL_IOPORT_GETIRQ(ports[port]), pin),
                                LedButtonsLogic::pinChanged, d);
    }

    avr_vcd_init(avr, "ledbuttons.vcd", &vcdFile, 100000);
    for (int i = 0; i < 8; i++) {
        char name[6];
        snprintf(name, 6, "PORT%c", ports[i]);
        avr_vcd_add_signal(&vcdFile,
                avr_io_getirq(avr, AVR_IOCTL_IOPORT_GETIRQ(ports[i]), IOPORT_IRQ_PIN_ALL),
                           8 /* bits */, name);
    }
}
Ejemplo n.º 3
0
int main(int argc, char *argv[])
{
	elf_firmware_t		f;
	const char			*fname="../src/binw2.elf";
	const char			*mmcu="attiny13";

	elf_read_firmware(fname, &f);

	snprintf(f.mmcu, sizeof(f.mmcu) - 1, "%s", mmcu);
	f.frequency = 4800000;
	printf("firmware %s f=%d mmcu=%s\n", fname, (int)f.frequency, f.mmcu);

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

	// initialize our 'peripheral'
	button_init(avr, &button, "button");

	// "connect" the output irq of the button to the port pin of the AVR
	avr_connect_irq(
		button.irq + IRQ_BUTTON_OUT,
		avr_io_getirq(avr, AVR_IOCTL_IOPORT_GETIRQ('B'), IOPORT_IRQ_PIN4));

	avr_irq_register_notify(
		avr_io_getirq(avr, AVR_IOCTL_IOPORT_GETIRQ('B'), IOPORT_IRQ_DIRECTION_ALL),
		ddr_hook,
		NULL);

	avr_irq_register_notify(
		avr_io_getirq(avr, AVR_IOCTL_IOPORT_GETIRQ('B'), IOPORT_IRQ_PIN_ALL),
		pin_changed_hook, 
		"portb");

	// even if not setup at startup, activate gdb if crashing
	avr->gdb_port = 1234;
	//if (0) {
	//	//avr->state = cpu_Stopped;
	//	avr_gdb_init(avr);
	//}

	/*
	 *	VCD file initialization
	 *	
	 *	This will allow you to create a "wave" file and display it in gtkwave
	 *	Pressing "r" and "s" during the demo will start and stop recording
	 *	the pin changes
	 */
	avr_vcd_init(avr, "gtkwave_output.vcd", &vcd_file, 100000 /* usec */);
	avr_vcd_add_signal(&vcd_file, 
		avr_io_getirq(avr, AVR_IOCTL_IOPORT_GETIRQ('B'), IOPORT_IRQ_PIN_ALL), 8 /* bits */ ,
		"portb" );
	avr_vcd_add_signal(&vcd_file, 
		button.irq + IRQ_BUTTON_OUT, 1 /* bits */ ,
		"button" );

	// 'raise' it, it's a "pullup"
	avr_raise_irq(button.irq + IRQ_BUTTON_OUT, 0);

	printf( "Launching binw2 simulation\n"
			"   Press 'space' to press virtual button attached to pin %d\n"
			"   Press 'q' to quit\n"
			"   Press 'r' to start recording a 'wave' file\n"
			"   Press 's' to stop recording\n",
			IOPORT_IRQ_PIN4);

	/*
	 * OpenGL init, can be ignored
	 */
	glutInit(&argc, argv);		/* initialize GLUT system */

	glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
	glutInitWindowSize(5 * SZ_PIXSIZE, 7 * SZ_PIXSIZE);
	window = glutCreateWindow("Glut");	/* create window */

	// Set up projection matrix
	glMatrixMode(GL_PROJECTION); // Select projection matrix
	glLoadIdentity(); // Start with an identity matrix
	glOrtho(0, 5 * SZ_PIXSIZE, 0, 7 * SZ_PIXSIZE, 0, 10);
	//glScalef(1, -1, 1);
	//glTranslatef(0, -7 * SZ_PIXSIZE, 0);

	glutDisplayFunc(displayCB);		/* set window's display callback */
	glutKeyboardFunc(keyCB);		/* set window's key callback */
	glutTimerFunc(1000 / 24, timerCB, 0);

	// the AVR run on it's own thread. it even allows for debugging!
	pthread_t run;
	pthread_create(&run, NULL, avr_run_thread, NULL);

	glutMainLoop();
}
Ejemplo n.º 4
0
int main(int argc, char *argv[])
{
	elf_firmware_t f;
	//const char * fname =  "atmega48_ledramp.axf";
	const char * fname =  argv[1];
	char path[256];

//	sprintf(path, "%s/%s", dirname(argv[0]), fname);
//	printf("Firmware pathname is %s\n", path);
	elf_read_firmware(fname, &f);

	printf("firmware %s f=%d mmcu=%s\n", fname, (int)f.frequency, f.mmcu);

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

	// initialize our 'peripheral'
	button_init(avr, &button, "button");
	// "connect" the output irw of the button to the port pin of the AVR
	avr_connect_irq(
		button.irq + IRQ_BUTTON_OUT,
		avr_io_getirq(avr, AVR_IOCTL_IOPORT_GETIRQ('C'), 0));

	// connect all the pins on port B to our callback
	for (int i = 0; i < 8; i++)
		avr_irq_register_notify(
			avr_io_getirq(avr, AVR_IOCTL_IOPORT_GETIRQ('B'), i),
			pin_changed_hook, 
			NULL);

	// even if not setup at startup, activate gdb if crashing
	avr->gdb_port = 1234;
	if (0) {
		//avr->state = cpu_Stopped;
		avr_gdb_init(avr);
	}

	/*
	 *	VCD file initialization
	 *	
	 *	This will allow you to create a "wave" file and display it in gtkwave
	 *	Pressing "r" and "s" during the demo will start and stop recording
	 *	the pin changes
	 */
	avr_vcd_init(avr, "gtkwave_output.vcd", &vcd_file, 100000 /* usec */);
	avr_vcd_add_signal(&vcd_file, 
		avr_io_getirq(avr, AVR_IOCTL_IOPORT_GETIRQ('B'), IOPORT_IRQ_PIN_ALL), 8 /* bits */ ,
		"portb" );
	avr_vcd_add_signal(&vcd_file, avr_io_getirq(avr, AVR_IOCTL_IOPORT_GETIRQ('C'), IOPORT_IRQ_PIN0), 1, "portc");
	avr_vcd_add_signal(&vcd_file, 
		button.irq + IRQ_BUTTON_OUT, 1 /* bits */ ,
		"button" );

	// 'raise' it, it's a "pullup"
	avr_raise_irq(button.irq + IRQ_BUTTON_OUT, 1);

	printf( "Demo launching: 'LED' bar is PORTB, updated every 1/64s by the AVR\n"
			"   firmware using a timer. If you press 'space' this presses a virtual\n"
			"   'button' that is hooked to the virtual PORTC pin 0 and will\n"
			"   trigger a 'pin change interrupt' in the AVR core, and will 'invert'\n"
			"   the display.\n"
			"   Press 'q' to quit\n\n"
			"   Press 'r' to start recording a 'wave' file\n"
			"   Press 's' to stop recording\n"
			);

	/*
	 * OpenGL init, can be ignored
	 */
	glutInit(&argc, argv);		/* initialize GLUT system */

	glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
	glutInitWindowSize(8 * pixsize, 1 * pixsize);		/* width=400pixels height=500pixels */
	window = glutCreateWindow("Glut");	/* create window */

	// Set up projection matrix
	glMatrixMode(GL_PROJECTION); // Select projection matrix
	glLoadIdentity(); // Start with an identity matrix
	glOrtho(0, 8 * pixsize, 0, 1 * pixsize, 0, 10);
	glScalef(1,-1,1);
	glTranslatef(0, -1 * pixsize, 0);

	glutDisplayFunc(displayCB);		/* set window's display callback */
	glutKeyboardFunc(keyCB);		/* set window's key callback */
	glutTimerFunc(1000 / 24, timerCB, 0);

	// the AVR run on it's own thread. it even allows for debugging!
	pthread_t run;
	pthread_create(&run, NULL, avr_run_thread, NULL);

	glutMainLoop();
}
Ejemplo n.º 5
0
int main(int argc, char *argv[])
{
	elf_firmware_t f;
	const char * fname =  "wordClock-erl";
	char path[256];

//	sprintf(path, "%s/%s", dirname(argv[0]), fname);
//	printf("Firmware pathname is %s\n", path);
	elf_read_firmware(fname, &f);

	strcpy( f.mmcu, "atmega168" ); // hack
	f.frequency = 16000000;
	printf("firmware %s f=%d mmcu=%s\n", fname, (int)f.frequency, f.mmcu);
	
	avr = avr_make_mcu_by_name(f.mmcu);
	if (!avr) {
		fprintf(stderr, "%s: AVR '%s' now known\n", argv[0], f.mmcu);
		exit(1);
	}
	avr_init(avr);
	avr_load_firmware(avr, &f);

	// initialize our 'peripheral'
	// button_init(avr, &button, "button");
	// "connect" the output irw of the button to the port pin of the AVR
	/*
	avr_connect_irq(
		button.irq + IRQ_BUTTON_OUT,
		avr_io_getirq(avr, AVR_IOCTL_IOPORT_GETIRQ('C'), 0));
	*/
	// connect all the pins on port B to our callback
#if 0
	for (int i = 0; i < 8; i++)
		avr_irq_register_notify(
			avr_io_getirq(avr, AVR_IOCTL_IOPORT_GETIRQ('B'), i),
			pin_changed_hook, 
			NULL);
#endif
	// even if not setup at startup, activate gdb if crashing
	avr->gdb_port = 1234;
	if (0) {
		//avr->state = cpu_Stopped;
		avr_gdb_init(avr);
	}

	/*
	 *	VCD file initialization
	 *	
	 *	This will allow you to create a "wave" file and display it in gtkwave
	 *	Pressing "r" and "s" during the demo will start and stop recording
	 *	the pin changes
	 *     
	 *      Initially set to 100 000 usec = 100 ms. I think it is how often
	 *      to flush its' log.
	 */
	avr_vcd_init(avr, "gtkwave_output.vcd", &vcd_file, 100 /* usec */);

	/* want MOSI, SCLK, XLAT, BLANK */
	avr_vcd_add_signal( &vcd_file, 
			    avr_io_getirq(avr, AVR_IOCTL_SPI_GETIRQ(0), 
					  SPI_IRQ_OUTPUT), 
			    8, "MOSI" );

	avr_vcd_add_signal(&vcd_file, 
			   avr_io_getirq(avr, AVR_IOCTL_IOPORT_GETIRQ('B'), 1 ),
			   1, "XLAT" );
	avr_vcd_add_signal(&vcd_file, 
			   avr_io_getirq(avr, AVR_IOCTL_IOPORT_GETIRQ('B'), 2 ),
			   1, "BLANK" );
	avr_vcd_add_signal(&vcd_file, 
			   avr_io_getirq(avr, AVR_IOCTL_IOPORT_GETIRQ('B'), 5 ),
			   1, "SCLK" );
#if 0
	avr_vcd_add_signal(&vcd_file, 
		button.irq + IRQ_BUTTON_OUT, 1 /* bits */ ,
		"button" );

	// 'raise' it, it's a "pullup"
	avr_raise_irq(button.irq + IRQ_BUTTON_OUT, 1);
#endif
	avr_vcd_start( &vcd_file );
							       
	printf( "Demo launching. " );
#if 0
	/*
	 * OpenGL init, can be ignored
	 */
	glutInit(&argc, argv);		/* initialize GLUT system */

	glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
	glutInitWindowSize(8 * pixsize, 1 * pixsize);		/* width=400pixels height=500pixels */
	window = glutCreateWindow("Glut");	/* create window */

	// Set up projection matrix
	glMatrixMode(GL_PROJECTION); // Select projection matrix
	glLoadIdentity(); // Start with an identity matrix
	glOrtho(0, 8 * pixsize, 0, 1 * pixsize, 0, 10);
	glScalef(1,-1,1);
	glTranslatef(0, -1 * pixsize, 0);

	glutDisplayFunc(displayCB);		/* set window's display callback */
	glutKeyboardFunc(keyCB);		/* set window's key callback */
	glutTimerFunc(1000 / 24, timerCB, 0);
#endif
	// the AVR run on it's own thread. it even allows for debugging!
	pthread_t run;
	pthread_create(&run, NULL, avr_run_thread, NULL);

	sleep( 60 ); // wait 5 seconds, then exit.

	avr_vcd_stop(&vcd_file);

	/*	glutMainLoop(); */
}
Ejemplo n.º 6
0
int main(int argc, char *argv[])
{
	int state;
	elf_firmware_t f;
	const char *fname = "../BasicMotorControl.elf";
	const char *mmcu = "atmega328p";

	if (elf_read_firmware(fname, &f) != 0)
	{
		exit(1);
	}

	f.frequency = 16000000;

	printf("firmware %s f=%d mmcu=%s\n", fname, (int)f.frequency, mmcu);

	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);

#if 0
	/* even if not setup at startup, activate gdb if crashing */
	avr->gdb_port = 1234;
	avr->state = cpu_Stopped;
	avr_gdb_init(avr);
#endif

	/* VCD file initialization */
	avr_vcd_init(avr, "wave.vcd", &vcd_file, 10000 /* usec */);
	avr_vcd_add_signal(&vcd_file, avr_io_getirq(avr, AVR_IOCTL_IOPORT_GETIRQ('B'), 0), 1, "B0" ); 
	avr_vcd_add_signal(&vcd_file, avr_io_getirq(avr, AVR_IOCTL_IOPORT_GETIRQ('B'), 1), 1, "B1" ); 
	avr_vcd_add_signal(&vcd_file, avr_io_getirq(avr, AVR_IOCTL_IOPORT_GETIRQ('B'), 2), 1, "B2" ); 
	avr_vcd_add_signal(&vcd_file, avr_io_getirq(avr, AVR_IOCTL_IOPORT_GETIRQ('B'), 3), 1, "B3" ); 
	avr_vcd_start(&vcd_file);

	/* IRQ callback hooks */
	avr_irq_register_notify( avr_io_getirq(avr, AVR_IOCTL_IOPORT_GETIRQ('B'), 0), pin_changed_hook, NULL); 
	avr_irq_register_notify( avr_io_getirq(avr, AVR_IOCTL_IOPORT_GETIRQ('B'), 1), pin_changed_hook, NULL); 
	avr_irq_register_notify( avr_io_getirq(avr, AVR_IOCTL_IOPORT_GETIRQ('B'), 2), pin_changed_hook, NULL); 
	avr_irq_register_notify( avr_io_getirq(avr, AVR_IOCTL_IOPORT_GETIRQ('B'), 3), pin_changed_hook, NULL); 

	/* show some info */
	show_ports(avr);

	/* install signal handlers */
	signal(SIGINT, sig_int);
	signal(SIGTERM, sig_int);

	/* main loop */
	printf("*** Entering main loop ***\n");
	while (1) 
	{
		state = avr_run(avr);
		if (state == cpu_Done || state == cpu_Crashed)
		{
			printf("CPU State %d\n", state);
			break;
		}
	}

	avr_vcd_stop(&vcd_file);
	avr_terminate(avr);

	return 0;
}
Ejemplo n.º 7
0
int
main (int argc, char *argv[])
{
  elf_firmware_t firmware;
  const char *firmware_path = "../../../firmwares/blink-led.elf";
  int rc = elf_read_firmware (firmware_path, &firmware);
  if (rc == -1)
    exit (1);
  printf ("firmware %s f=%d mmcu=%s\n", firmware_path, (int) firmware.frequency, firmware.mmcu);

  firmware.frequency = 16e6;
  avr = avr_make_mcu_by_name ("atmega2560"); // firmware.mmcu
  if (!avr)
    {
      fprintf (stderr, "%s: AVR '%s' not known\n", argv[0], firmware.mmcu);
      exit (1);
    }
  avr_init (avr);
  avr_load_firmware (avr, &firmware);

  avr->log = LOG_TRACE;
  avr->trace = 1;

  // connect all the pins on port B to our callback
  for (int i = 0; i < 8; i++)
    avr_irq_register_notify (avr_io_getirq (avr, AVR_IOCTL_IOPORT_GETIRQ ('B'), i),
                             pin_changed_hook, NULL);

  /*
   * VCD file initialization
   * 
   * This will allow you to create a "wave" file and display it in gtkwave Pressing "r" and "s"
   * during the demo will start and stop recording the pin changes
   */
  avr_vcd_init (avr, "gtkwave_output.vcd", &vcd_file, 100000); // us
  avr_vcd_add_signal (&vcd_file,
                      avr_io_getirq (avr, AVR_IOCTL_IOPORT_GETIRQ ('B'), IOPORT_IRQ_PIN_ALL),
                      8, // bits
                      "porth");

  printf ("   Press 'q' to quit\n\n"
          "   Press 'r' to start recording a 'wave' file\n"
	  "   Press 's' to stop recording\n");

  // the AVR run on it's own thread. it even allows for debugging!
  pthread_t run;
  pthread_create (&run, NULL, avr_run_thread, NULL);

  while (1)
    {
      switch (getchar())
	{
	case 'q':
	  exit(0);
	  break;
	case 'r':
	  printf ("Starting VCD trace\n");
	  avr_vcd_start (&vcd_file);
	  break;
	case 's':
	  printf ("Stopping VCD trace\n");
	  avr_vcd_stop (&vcd_file);
	  break;
	}
      fflush(stdin);
      fflush(stdout);
      // sleep (10); // s
    }
}
Ejemplo n.º 8
0
int main(int argc, char *argv[])
{
	elf_firmware_t f;
	const char * fname =  "atmega168_timer_64led.axf";
	//char path[256];

//	sprintf(path, "%s/%s", dirname(argv[0]), fname);
	//printf("Firmware pathname is %s\n", path);
	elf_read_firmware(fname, &f);

	printf("firmware %s f=%d mmcu=%s\n", fname, (int)f.frequency, f.mmcu);

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

	//
	// initialize our 'peripherals'
	//
	hc595_init(avr, &shifter);
	
	button_init(avr, &button[B_START], "button.start");
	avr_connect_irq(
		button[B_START].irq + IRQ_BUTTON_OUT,
		avr_io_getirq(avr, AVR_IOCTL_IOPORT_GETIRQ('C'), 0));
	button_init(avr, &button[B_STOP], "button.stop");
	avr_connect_irq(
		button[B_STOP].irq + IRQ_BUTTON_OUT,
		avr_io_getirq(avr, AVR_IOCTL_IOPORT_GETIRQ('B'), 1));
	button_init(avr, &button[B_RESET], "button.reset");
	avr_connect_irq(
		button[B_RESET].irq + IRQ_BUTTON_OUT,
		avr_io_getirq(avr, AVR_IOCTL_IOPORT_GETIRQ('B'), 0));

	// connects the fake 74HC595 array to the pins
	avr_irq_t * i_mosi = avr_io_getirq(avr, AVR_IOCTL_SPI_GETIRQ(0), SPI_IRQ_OUTPUT),
			* i_reset = avr_io_getirq(avr, AVR_IOCTL_IOPORT_GETIRQ('D'), 4),
			* i_latch = avr_io_getirq(avr, AVR_IOCTL_IOPORT_GETIRQ('D'), 7);
	avr_connect_irq(i_mosi, shifter.irq + IRQ_HC595_SPI_BYTE_IN);
	avr_connect_irq(i_reset, shifter.irq + IRQ_HC595_IN_RESET);
	avr_connect_irq(i_latch, shifter.irq + IRQ_HC595_IN_LATCH);

	avr_irq_t * i_pwm = avr_io_getirq(avr, AVR_IOCTL_TIMER_GETIRQ('0'), TIMER_IRQ_OUT_PWM0);
	avr_irq_register_notify(
		i_pwm,
		pwm_changed_hook, 
		NULL);	
	avr_irq_register_notify(
		shifter.irq + IRQ_HC595_OUT,
		hc595_changed_hook, 
		NULL);

	// even if not setup at startup, activate gdb if crashing
	avr->gdb_port = 1234;
	if (0) {
		//avr->state = cpu_Stopped;
		avr_gdb_init(avr);
	}

	/*
	 *	VCD file initialization
	 *	
	 *	This will allow you to create a "wave" file and display it in gtkwave
	 *	Pressing "r" and "s" during the demo will start and stop recording
	 *	the pin changes
	 */
	avr_vcd_init(avr, "gtkwave_output.vcd", &vcd_file, 10000 /* usec */);

	avr_vcd_add_signal(&vcd_file, 
		avr_get_interrupt_irq(avr, 7), 1 /* bit */ ,
		"TIMER2_COMPA" );
	avr_vcd_add_signal(&vcd_file, 
		avr_get_interrupt_irq(avr, 17), 1 /* bit */ ,
		"SPI_INT" );
	avr_vcd_add_signal(&vcd_file, 
		i_mosi, 8 /* bits */ ,
		"MOSI" );

	avr_vcd_add_signal(&vcd_file, 
		i_reset, 1 /* bit */ ,
		"595_RESET" );
	avr_vcd_add_signal(&vcd_file, 
		i_latch, 1 /* bit */ ,
		"595_LATCH" );
	avr_vcd_add_signal(&vcd_file, 
		button[B_START].irq + IRQ_BUTTON_OUT, 1 /* bits */ ,
		"start" );
	avr_vcd_add_signal(&vcd_file, 
		button[B_STOP].irq + IRQ_BUTTON_OUT, 1 /* bits */ ,
		"stop" );
	avr_vcd_add_signal(&vcd_file, 
		button[B_RESET].irq + IRQ_BUTTON_OUT, 1 /* bits */ ,
		"reset" );

	avr_vcd_add_signal(&vcd_file, 
		shifter.irq + IRQ_HC595_OUT, 32 /* bits */ ,
		"HC595" );
	avr_vcd_add_signal(&vcd_file, 
		i_pwm, 8 /* bits */ ,
		"PWM" );

	// 'raise' it, it's a "pullup"
	avr_raise_irq(button[B_START].irq + IRQ_BUTTON_OUT, 1);
	avr_raise_irq(button[B_STOP].irq + IRQ_BUTTON_OUT, 1);
	avr_raise_irq(button[B_RESET].irq + IRQ_BUTTON_OUT, 1);

	printf( "Demo : This is a real world firmware, a 'stopwatch'\n"
			"   timer that can count up to 99 days. It features a PWM control of the\n"
			"   brightness, blinks the dots, displays the number of days spent and so on.\n\n"
			"   Press '0' to press the 'start' button\n"
			"   Press '1' to press the 'stop' button\n"
			"   Press '2' to press the 'reset' button\n"
			"   Press 'q' to quit\n\n"
			"   Press 'r' to start recording a 'wave' file - with a LOT of data\n"
			"   Press 's' to stop recording\n"
			"  + Make sure to watch the brightness dim once you stop the timer\n\n"
			);

	/*
	 * OpenGL init, can be ignored
	 */
	glutInit(&argc, argv);		/* initialize GLUT system */


	int w = 22, h = 8;
	
	glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
	glutInitWindowSize(w * pixsize, h * pixsize);		/* width=400pixels height=500pixels */
	window = glutCreateWindow("Press 0, 1, 2 or q");	/* create window */

	// Set up projection matrix
	glMatrixMode(GL_PROJECTION); // Select projection matrix
	glLoadIdentity(); // Start with an identity matrix
	glOrtho(0, w * pixsize, 0, h * pixsize, 0, 10);
	glScalef(1,-1,1);
	glTranslatef(0, -1 * h * pixsize, 0);

	glutDisplayFunc(displayCB);		/* set window's display callback */
	glutKeyboardFunc(keyCB);		/* set window's key callback */
	glutTimerFunc(1000 / 24, timerCB, 0);

	// the AVR run on it's own thread. it even allows for debugging!
	pthread_t run;
	pthread_create(&run, NULL, avr_run_thread, NULL);

	glutMainLoop();
}