Tuesday 10 September 2013

How to implement interrupt handling for Nios 2?

How to implement interrupt handling for Nios 2?

I've succeeded writing polling for Nios 2 and the Altera DE2 and now I'm
instructed to do something similar but using interrupts instead for the
interaction:
Use interrupts from the keys instead of polling. This means that you must
write an interrupt service routine for the button interrupt (name the
function key InterruptHandler), and that you must initialize the system so
that interrupts from the button PIO will cause the key InterruptHandler
function to be executed. You must also enable interrupts from the button
PIO by writing appropriate value(s) to the appropriate register(s) in the
button PIO using the appropriate macro(s). The behavior caused by the
buttons shall be changed compared to the previous exercise: KEY0 The
button KEY0 shall toggle between start and stop counting the time. KEY1
Each time you push the button KEY1 the time value shall be incremented by
one. KEY2 Each time you push the button KEY2 the the time value shall be
set to 00:00. KEY3 Each time you push the button KEY3 the the time value
shall be set to 2.8 completed 59:57.
Now I don't really know which part to write in assembly and which part to
write in C, I have a few functions in assembly and C that I've written but
I'm not sure how to put the pieces together or if I'm missing something.
you must write an interrupt service routine for the button interrupt (name
the function key InterruptHandler), and that you must initialize the
system so that interrupts from the button PIO will cause the key
InterruptHandler function to be executed.
#include "alt_irq.h"
/* Define the null pointer */
#define NULL_POINTER ( (void *) 0)
void tick ( volatile int * ); /* in file tick.c */
/* Define addresses etc for de2_pio_keys4 */
volatile int * const de2_pio_keys4_base = (volatile int *) 0x840;
volatile int * const de2_pio_keys4_intmask = (volatile int *) 0x848;
volatile int * const de2_pio_keys4_edgecap = (volatile int *) 0x84c;
const int de2_pio_keys4_intindex = 2;
const int de2_pio_keys4_irqbit = 1 << 2;
/*
* Interrupt handler for de2_pio_keys4.
* The parameters are ignored here, but are
* required for correct compilation.
* The type alt_u32 is an Altera-defined
* unsigned integer type.
*
* To help debugging interruptible interrupt-handlers,
* this handler delays a long while when a key is pressed.
* However, there is no delay when the key is released.
*
* We keep a software copy of the LED value, since
* the parallel output ports are not program-readable.
*
* Example: we send out the value 1 on de2_pio_keys4,
* by executing *DE2_PIO_KEYS4_BASE = 1;
* Then we try to read the port by executing
* int test_val = *DE2_PIO_KEYS4_BASE; // WRONG
* The value of test_val is now undefined.
* The port returns some bits which are not related
* to the value we have written.
*
* The software copy of the LED value
* for this interrupt handler
* is the global variable myleds, defined above.
*/
void irq_handler_keys( void * context, alt_u32 irqnum )
{
alt_u32 save_value;
save_value = alt_irq_interruptible( de2_pio_keys4_intindex );
/* Read edge capture register of the de2_pio_keys4 device. */
int edges = *de2_pio_keys4_edgecap;
/* Clear edge capture register - writing
* any value clears all bits. */
*de2_pio_keys4_edgecap = 0;
/* If action on KEY0 */
if( edges & 1 )
{
/* If KEY0 is pressed now */
if( (*de2_pio_keys4_base & 1) == 0 )
{
/* Turn on green LED LEDG0
* in software copy of LED bits. */
myleds = myleds | 1;
/* Copy software LED bits to actual LEDs. */
*de2_pio_greenled9 = myleds;
/* Print an upper-case 'D' using out_char_uart_0. */
out_char_uart_0( 'D' );
/* Wait a long while */
bigdelay();
/* Print a lower-case 'd' using out_char_uart_0. */
out_char_uart_0( 'd' );
}
/* If KEY0 is released now */
else if( (*de2_pio_keys4_base & 1) != 0 )
{
/* Turn off green LED LEDG0
* in software copy of LED bits. */
myleds = myleds & 0xffffe;
/* Print an 'U' using out_char_uart_0. */
out_char_uart_0( 'U' );
/* Copy software LED bits to actual LEDs. */
*de2_pio_greenled9 = myleds;
}
alt_irq_non_interruptible( save_value );
}
}
int main()
{
/* Remove unwanted interrupts.
* initfix_int is supplied by KTH.
* A nonzero return value indicates failure. */
if( initfix_int() != 0 ) n2_fatal_error();
/* Initialize de2_pio_keys4 for
* interrupts. */
keysinit_int();
/* Initialize timer_1 for
* continuous timeout interrupts. */
timerinit_int();
/* Loop forever. */
while( 1 )
{
/* do some work */
/* Programmed delay between underscores.
* Defined earlier in this file. */
somedelay();
}
}
I didn't compile the above but it is my attempt at getting started to
solve the exercise.
The file tick.c is
/*
* tick.c - increment time in BCD format
*
* Copyright abandoned. This file is in the public domain.
*/
/*
* tick expects a pointer to a memory location containing
* BCD-coded time, and returns nothing.
*
* Time is stored as: days - hours - minutes - seconds,
* with two BCD digits for each number.
*/
void tick( unsigned int * timep )
{
/* Get current value, store locally */
register unsigned int t = * timep;
t += 1; /* Increment local copy */
/* If result was not a valid BCD-coded time, adjust now */
if( (t & 0x0000000f) == 0x0000000a ) t += 0x00000006;
if( (t & 0x000000f0) == 0x00000060 ) t += 0x000000a0;
/* Seconds are now OK */
if( (t & 0x00000f00) == 0x00000a00 ) t += 0x00000600;
if( (t & 0x0000f000) == 0x00006000 ) t += 0x0000a000;
/* Minutes are now OK */
if( (t & 0x000f0000) == 0x000a0000 ) t += 0x00060000;
if( (t & 0x00ff0000) == 0x00240000 ) t += 0x00dc0000;
/* Hours are now OK */
if( (t & 0x0f000000) == 0x0a000000 ) t += 0x06000000;
if( (t & 0xf0000000) == 0xa0000000 ) t = 0;
/* Days are now OK */
* timep = t; /* Store new value */
}
But do I not need any assembly to complete the task? Can I do it entirely
with C? I thought that when writing an ISR it must be done in assembly?
What more can you tell me to help me complete the task? I build it using
Quartus II and the Nios 2 SBT.

No comments:

Post a Comment