Showing results for 
Search instead for 
Did you mean: 
Honored Contributor I

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; }
0 Kudos
4 Replies
Honored Contributor I

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.
Honored Contributor I

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
Honored Contributor I

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







btw, I was using a hardware design provided by my board manufacturer (DE2-115 board and the rgmii-enet0 webserver hardware config)
Honored Contributor I

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.