Instrukcja 3.
Zależności czasowe i przerwania
Do projektu w Qsys należy dołączyć dwa moduły IntervalTimer (Łączenie z szyną Avalon rozkazów i danych). Służą one do odmierzania czasu. Obydwa należy ustawić jako klasyczne liczniki (full featured). Dostępne są jeszcze wersje generatora przerwania i watchdog (resetuje procesor co pewien czas zapobiegając zawieszeniu układu).
Po skompilowaniu układu należy w Nios II IDE w bibliotece BSP wybrać z menu kontekstowego Nios II | Generate BSP. Po odświeżeniu bibliotek należy uruchomić konfigurator biblioteki BSP poleceniem Nios II | BSP Editor z menu kontekstowego. Należy odnaleźć wartości sys_clk_timer i timestamp_timer i powiązać z nimi dodane do projektu układy czasowe. Całość zatwierdzamy poleceniem Generate.
Biblioteka:
<sys/alt_timestamp.h>
int alt_timestamp_start (void) - uruchamia licznik znacznika czasu. Zwraca 0 w razie powodzenia. W przeciwnym przypadku zwraca wartość różną od zera.
alt_u32 alt_timestamp_freq (void) - Funkcja pozwalająca określić częstotliwość pracy licznika znacznika czasu. Zwraca liczbę sygnałów przypadających na sekundę.
alt_u32 alt_timestamp (void) – zwraca wartość licznika znacznika czasu.
"alt_types.h"
Typ Opis
alt_8 Signed 8-bit integer.
alt_u8 Unsigned 8-bit integer.
alt_16 Signed 16-bit integer.
alt_u16 Unsigned 16-bit integer.
alt_32 Signed 32-bit integer.
alt_u32 Unsigned 32-bit integer.
alt_64 Signed 64-bit integer.
alt_u64 Unsigned 64-bit integer.
Przykład pomiaru czasu:
#include <stdio.h>
#include "sys/alt_timestamp.h"
#include "alt_types.h"
intmain (void)
{
alt_u32 time1;
alt_u32 time2;
if(alt_timestamp_start() < 0)
{
printf("Brak timera w systemie\n");
}
else
{
time1 = alt_timestamp();
func1(); /* funkcja, której czas wykoonania zostanie zmierzony */
time2 = alt_timestamp();
func2();
printf("czas wykonywania func1 = %u cykli\n", (unsigned int) (time2 - time1));
printf("Częstotliwość timera = %u\n",(unsigned int)alt_timestamp_freq());
}
return0;
}
- zarejestrowanie funkcji wywoływanej przez zegar:
intalt_alarm_start (alt_alarm* alarm, alt_u32 nticks, alt_u32 (*callback) (void* context),void* context);
gdzie: alarm – adres zmiennej statycznej lub globalnej typu alt_alarm,
nticks– liczba cykli zegara po jakiej ponownie zostanie wywołana funkcja, 0 - zatrzymuje alarm,
callback – adres funkcji wywołanej po czasie nticks, funkcja zwraca liczbę cykli po jakiej będzie ponownie wywołana,
context– parametr funkcji (nieużywany).
Funkcja zwraca 0, gdy OK, <0 gdy brak zegara systemowego.
- zatrzymanie alarmu: voidalt_alarm_stop (alt_alarm* alarm)
Przykład: wywoływanie alarmu co 1s.
#include <stddef.h>
#include <stdio.h>
#include "sys/alt_alarm.h"
#include "alt_types.h"
/*
* The callback function.
*/
alt_u32 my_alarm_callback (void* context)
{
/* This function is called once per second */
returnalt_ticks_per_second();
}
...
/* The alt_alarm must persist for the duration of the alarm. */
staticalt_alarm alarm;
...
if(alt_alarm_start (&alarm, alt_ticks_per_second(), my_alarm_callback, NULL) < 0)
{
printf("No system clock available\n");
}
5. Obsługa przerwań.
Procedura obsługi przerwań musi być zdefiniowana jako:
void interrupt_handler(void* context, alt_u32 id)
{
… // Nie należy używać funkcji wykorzystujących przerwania (np. printf).
// Należy pamiętać o wyzerowaniu źródła przerwania np. clear_edge_capture
}
gdzie id – numer przerwania, context – parametry procedury.
- plik nagłówkowy:: #include <sys/alt_irq.h>
- rejestracja procedury obsługi przerwania:
intalt_irq_register (alt_u32 irq, void* isr_context, alt_isr_func isr)
gdzie: irq – numer przerwania,
isr – adres procedury obsługi przerwania,
isr_context – adres obszaru z parametrami przekazywanymi do procedury obsługi przerwania.
- zablokowanie przerwania: intalt_irq_disable (alt_u32 irq)
- odblokowanie przerwania: intalt_irq_enable (alt_u32 irq)
Moduły Parallel Port do obsługi przerwań wykorzystują:
- ustawienie maski przerwań:
void alt_up_parallel_port_set_interrupt_mask(alt_up_parallel_port_dev *parallel_port,unsigned mask)
maska określa które wejścia portu (wartość 1) generują przerwania przy zmianie stanu, po inicjalizacji wszystkie porty są zablokowane (maska =0).
- zerowanie rejestru zmian wejść:
unsignedint alt_up_parallel_port_clear_edge_capture( alt_up_parallel_port_dev *parallel_port)
Przykład:
keys = alt_up_parallel_port_open_dev(KEYS_NAME);
alt_irq_register(KEYS_IRQ, (void*) &edge_capture, hex_inc_irq);
alt_irq_enable(KEYS_IRQ);
alt_up_parallel_port_set_interrupt_mask(keys, 0100);
Zadania:
-
Używając znacznika czasu zmierz czas wykonywania się dowolnej operacji.
-
Używając przerwań, oprogramuj przycisk 3 tak, aby wyświetlał wartość inkrementowaną na wyświetlaczu LCD lub siedmiosegmentowy.
-
Zademonstruj działanie alarmu za pomocą zegara i alarmu systemowego.
English Version
Introduction
Time dependences and interrupts
To the Qsys project add two modules of IntervalTimer (connect it to Avalon Instruction and Data buses). We use them to count the time. Both of them should be set as classic counter (full featured). There are also available: an interrupt generator and watchdog (this module cyclic resets whole device to protect it against its frozen).
Compil the project. Next, in Nios II IDE in BSP project call function Nios II | Generate BSP from context menu. After the library refresh, run configuration of BSP library calling Nios II | BSP Editor from context menu. Find parameters: sys_clk_timer and timestamp_timer and associate them with IntervalTimer modules added to the Qsys project. Click Generate button to apply all changes.
Library:
<sys/alt_timestamp.h>
int alt_timestamp_start (void) - runs the counter. return 0 if successful. Otherwise returns value different than 0.
alt_u32 alt_timestamp_freq (void) - This function returns count of signals per second. Thus allow to define the timestamp frequency.
alt_u32 alt_timestamp (void) – returns the timestamp counter value.
"alt_types.h"
Type description
alt_8 Signed 8-bit integer.
alt_u8 Unsigned 8-bit integer.
alt_16 Signed 16-bit integer.
alt_u16 Unsigned 16-bit integer.
alt_32 Signed 32-bit integer.
alt_u32 Unsigned 32-bit integer.
alt_64 Signed 64-bit integer.
alt_u64 Unsigned 64-bit integer.
Example of time measuring:
#include <stdio.h>
#include "sys/alt_timestamp.h"
#include "alt_types.h"
intmain (void)
{
alt_u32 time1;
alt_u32 time2;
if(alt_timestamp_start() < 0)
{
printf("Brak timera w systemie\n");
}
else
{
time1 = alt_timestamp();
func1(); /* funkcja, której czas wykoonania zostanie zmierzony */
time2 = alt_timestamp();
func2();
printf("czas wykonywania func1 = %u cykli\n", (unsigned int) (time2 - time1));
printf("Częstotliwość timera = %u\n",(unsigned int)alt_timestamp_freq());
}
return0;
}
- registering of function which is periodically called by clock:
intalt_alarm_start (alt_alarm* alarm, alt_u32 nticks, alt_u32 (*callback) (void* context),void* context);
where: alarm – address of global or static variable of type alt_alarm,
nticks– count of clock cycles after which the function is called. 0 - stops the alarm,
callback – The address of function, which is called after nticks. The function returns a count of cycle after which is called again,
context– function parameter (unused).
The function returns 0 if success, <0 otherwise.
- alarm stop: voidalt_alarm_stop (alt_alarm* alarm)
Example: calling alarm function every second.
#include <stddef.h>
#include <stdio.h>
#include "sys/alt_alarm.h"
#include "alt_types.h"
/*
* The callback function.
*/
alt_u32 my_alarm_callback (void* context)
{
/* This function is called once per second */
returnalt_ticks_per_second();
}
...
/* The alt_alarm must persist for the duration of the alarm. */
staticalt_alarm alarm;
...
if(alt_alarm_start (&alarm, alt_ticks_per_second(), my_alarm_callback, NULL) < 0)
{
printf("No system clock available\n");
}
5. An interrupt service.
A function of an interrupt service must be defined as::
void interrupt_handler(void* context, alt_u32 id)
{
… // Using a function, which use an interrupt is prohibited (eg. printf).
// the interrupt source should be cleared, eg. clear_edge_capture
}
where: id – number of interrupt, context – the procedure parameter.
- header file:: #include <sys/alt_irq.h>
- registration of interrupt service function:
intalt_irq_register (alt_u32 irq, void* isr_context, alt_isr_func isr)
where: irq – number of interrupt,
isr – address of interrupt service function,
isr_context – address of memory space, where parameters for running function could be kept.
- Interrupt suspension: intalt_irq_disable (alt_u32 irq)
- unlock an interrupt: intalt_irq_enable (alt_u32 irq)
Modules "Parallel Port" use for interrupt service:
- interrupt mask setting:
void alt_up_parallel_port_set_interrupt_mask(alt_up_parallel_port_dev *parallel_port,unsigned mask)
the mask defines, which port inputs (value 1) generate an interrupt in case of its state changing. After initialisation, all ports are locked (mask = 0).
- change register clearing:
unsignedint alt_up_parallel_port_clear_edge_capture( alt_up_parallel_port_dev *parallel_port)
Example:
keys = alt_up_parallel_port_open_dev(KEYS_NAME);
alt_irq_register(KEYS_IRQ, (void*) &edge_capture, hex_inc_irq);
alt_irq_enable(KEYS_IRQ);
alt_up_parallel_port_set_interrupt_mask(keys, 0100);
Tasks:
-
Using timestamp, check the time of execution of any function.
-
Using interrupts, program the third button in such way, to obtain incremented value on LCD display or 7 segment.
-
Show, how an alarm works. Use to do it a clock and a system alarm.