Forum Discussion

Altera_Forum's avatar
Altera_Forum
Icon for Honored Contributor rankHonored Contributor
13 years ago

NIOS II timer problem

Hi, I've got a problem with my program running on DE2 board from altera (Nios II processor)

Our task was to construct a model of a washing machine, and allow user to choose the speed of spin. In addition, program has to use interrupts. We did it on Sw slider switches, and a hex display - for displaying the chosen value. Below is our code(based on hello world template).

But now we have to make a latency after someone turns on the switch and before the value appears on the display, for example 3 sec. We need to use alt_nticks() function.

My idea of how it should work was - in the first instruction of the interrupt handler function store the value of current time and then in the if statement if(swstate & SW1) add an additional condition like this if(swstate & SW1 && currenttime - alt_nticks() < 3*alt_ntics_per_second())

but when we tried to read a time in the interrupt handler something bad was going with the program, value of time was always zero or the program didnt respond.

I am not sure how exactly alt_nticks() funkction is working... or maybe this was a completely wrong way?

My question is how to make such a latency I describe? I would appreciate any hints.

Thanks for help :)

/*
 * "Hello World" example.
 *
 * This example prints 'Hello from Nios II' to the STDOUT stream. It runs on
 * the Nios II 'standard', 'full_featured', 'fast', and 'low_cost' example
 * designs. It runs with or without the MicroC/OS-II RTOS and requires a STDOUT
 * device in your system's hardware.
 * The memory footprint of this hosted application is ~69 kbytes by default
 * using the standard reference design.
 *
 * For a reduced footprint version of this template, and an explanation of how
 * to reduce the memory footprint for a given application, see the
 * "small_hello_world" template.
 *
 */
# define  SW0 0x00000001
# define  SW1 0x00000002
# define  SW2 0x00000004
# define  SW3 0x00000008
# define  SW4 0x00000010
# define  SW5 0x00000020
# define  SW6 0x00000040
# define  SW7 0x00000080
# define  SW8 0x00000100
# define  SW9 0x00000200
# define  SW10 0x00000400
# define  SW11 0x00000800
# define  SW12 0x00001000
# define  SW13 0x00002000
# define  SW14 0x00004000
# define  SW15 0x00008000
# define  SW16 0x00010000
# define  SW17 0x00020000
# define  KEY1 0x00000002
# define  KEY2 0x00000004
# define  KEY3 0x00000008
# define  LED0 0x00000001
# define  LED1 0x00000002
# define  LED2 0x00000004
# define  LED3 0x00000008
# define  LED4 0x00000010
# define  LED5 0x00000020
# define  LED6 0x00000040
# define  LED7 0x00000080
# define  LED8 0x00000100
# define  LED9 0x00000200
# define  LED10 0x00000400
# define  LED11 0x00000800
# define  LED12 0x00001000
# define  LED13 0x00002000
# define  LED14 0x00004000
# define  LED15 0x00008000
# define  LED16 0x00010000
# define  LED17 0x00020000
# define  SEGA 0x01
# define  SEGB 0x02
# define  SEGC 0x03
# define  SEGD 0x04
# define  SEGE 0x08
# define  SEGF 0x10
# define  SEGG 0x20
# include <stdio.h>
# include <io.h>
# include <system.h>
# include "altera_up_avalon_parallel_port.h"
# include "sys/alt_irq.h"
# include <sys/alt_timestamp.h>
# include "sys/alt_alarm.h"
# include "alt_types.h"
  int swstate = 0;
  int state = 0;
  int wybrano = 0;
  struct alt_up_dev{
	  alt_up_parallel_port_dev* uchwytSW;
	  alt_up_parallel_port_dev* uchwytLEDR;
	  alt_up_parallel_port_dev* uchwytHEX;
  };
  struct alt_up_dev up_dev;
void wyswietl(int raz, int dwa, int czy, int cztery){
	//IOWR(PARALLEL_PORT_3_BASE,0, (raz << 24) | (dwa <<16) | (czy <<8) |cztery);
	alt_up_parallel_port_write_data(up_dev.uchwytHEX,  (raz << 24) | (dwa <<16) | (czy <<8) |cztery);
}
int czaspoczatkowy = 0;
int czaslokalny = 0;
int tik = 0;
int flag = 0;
void interrupt_hanlder(struct alt_up_dev* up_dev, alt_u32 id){
	 swstate = alt_up_parallel_port_read_data(up_dev->uchwytSW);
	 czaspoczatkowy = alt_nticks();
	 	 if(flag==0){
	 		 flag = 1;
	 	 }
		  wyswietl(0,0, 0, 0);
		  switch(state){
		  case 0: //sw0
			  czaslokalny = alt_nticks();
			  if((swstate & SW0)){
				  czaspoczatkowy = alt_nticks();
				  wybrano= wybrano + 1;
				  wyswietl(0,127, 63, 63);
				  //printf("Wybrano 0!\n");
			  }//koniec if
				  state = 1;
			  break;
		  case 1:
			  if(swstate & SW1){
			  			  wybrano= wybrano + 1;
			  			  wyswietl(0,111, 63, 63);
			  			//printf("Wybrano 1!\n");
			  }//koniec if
			  			  state = 2;
			  		  break;
		  case 2:
		 		  if(swstate & SW2){
		 		  			  wybrano= wybrano + 1;
		 		  			  wyswietl(6,63, 63, 63);
		 		  		//	printf("Wybrano 2!\n");
		 		 }//koniec if
		 		  			  state = 3;
		 		  		  break;// koniec case 2
		  case 3:
		  	 		  if(swstate & SW3){
		  	 		  			  wybrano= wybrano + 1;
		  	 		  			  wyswietl(6,6, 63, 63);
		  	 		  //			printf("Wybrano 3!\n");
		  	 		}//koniec if
		  	 		  			  state = 4;
		  	 		  		  break;// koniec case 3
		  case 4:
		  	 		  if(swstate & SW4){
		  	 		  			  wybrano= wybrano + 1;
		  	 		  			  wyswietl(6,91, 63, 63);
		  	 		//  			printf("Wybrano 4!\n");
		  	 		 }//koniec if
		  	 		  			  state = 5;
		  	 		  		  break;// koniec case 4
		  case 5:
			  if(wybrano > 1){
				  state = 6;
				 // printf("%d",wybrano);
				 // printf("Wybrano 5!\n");
			  }//koniec if
			  else{
				  wybrano = 0;
				  state = 0;
			  }
		  	  	 	break;// koniec case 3
		  case 6:
			  //IOWR(PARALLEL_PORT_2_BASE, 0, 1);
			  alt_up_parallel_port_write_data(up_dev->uchwytLEDR, 1);
			  wyswietl(0,121, 80, 80);
			  if(swstate == 0){
				  wybrano = 0;
				  state = 5;
				  //IOWR(PARALLEL_PORT_2_BASE, 0, 0);
				  alt_up_parallel_port_write_data(up_dev->uchwytLEDR, 0);
			  }
		  	  	  	 		  		  break;// koniec case 3
		  }//koniec switcha
		 // clear_edge_capture();
}
int main()
{
  printf("Hello from Nios II!\n");
  
  tik = 3* alt_ticks_per_second();
  while(1){
	  alt_up_parallel_port_dev *uchwytSW = alt_up_parallel_port_open_dev("/dev/parallel_port_0");
	  alt_up_parallel_port_dev *uchwytRED = alt_up_parallel_port_open_dev("/dev/parallel_port_2");
	  alt_up_parallel_port_dev *uchwytHEX = alt_up_parallel_port_open_dev("/dev/parallel_port_3");
	  if(uchwytSW != NULL){
		  up_dev.uchwytSW = uchwytSW;
	  }
	  if(uchwytRED != NULL){
		  up_dev.uchwytLEDR = uchwytRED;
	  }
	  if(uchwytHEX != NULL){
	  		  up_dev.uchwytHEX = uchwytHEX;
	  	  }
	  alt_irq_register(1,(void*) &up_dev,(void*) interrupt_hanlder);
	  alt_up_parallel_port_set_interrupt_mask(uchwytSW,0xff);
	 
	 
  }//koniec while
  return 0;
}

4 Replies

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    If I were you, I'd write your own Avalon slave with a 32bit up-counter that counts at (say) 1kHz). You can then use simple modulo arithmetic for timeouts (up to 40-something days).

    A similar counter, counting at sys_clk can easily be used for performance mearurements.

    IIRC the Altera timer is a 16bit slave that requires multiple accesses to read - so can't be used from program code and ISR unless you disable interrupts.

    It is also over-complicated for what it is.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    We must use this function... is it possible to use it along with interrupts?

    We're quite new in nios programming, started using it last week.

    If you could explain it in easier way... :) Thanks
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    I just wrote a small test program, and using alt_nticks works perfectly in this program:

    #include "sys/alt_alarm.h"
    # include "sys/alt_timestamp.h"
    static alt_alarm my_alarm;
    static alt_u32 ticks_per_250ms;
    static volatile unsigned char callback_called;
    alt_u32 alarm_callback(void* context){
    	callback_called = 1;
    	return ticks_per_250ms;
    }
    int main(void){
    	ticks_per_250ms = alt_ticks_per_second() / 4;
    	callback_called = 0;
    alt_alarm_start(&my_alarm, ticks_per_250ms, alarm_callback, NULL);
    int current_ticks = 0;
    while(1){
    	current_ticks = alt_nticks();
    }
    }
    

    So it seems, that it can run with interrupts enabled and in normal program code.

    But I have another, bigger project, which also uses the lwIP stack and FreeRTOS, and in this project, alt_nticks() returns zero all the time. This drives me crazy... the BSP is exactly the same for both projects and I did not call any FreeRTOS or lwip specific code before making the call to alt_nticks() (btw: in my freeRTOS project, the alt_alarm doesn't work either for some kind of reason... maybe this is related to the alt_nticks problem?)

    regards

    *edit*:

    btw, I was using a hardware design provided by my board manufacturer (DE2-115 board and the rgmii-enet0 webserver hardware config)
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    That fact that the functions sometimes (or even usually) work when called from both interrupt and normal code doesn't mean that they will always work.

    I'm 99.9% sure the Altera timers are based on 16bit IO devices (possibly because they've only been ported from the 16bit niosI), and as such require multiple bus cycles to access any of the 32bit registers.

    This means that in an interrupt routine interrupts the main line code part way through one on those sequences than incorrect data is obtained.

    It also makes the accesses slow! if you are trying to time short instruction sequences they are hopeless.