Device Name

Small amount of text describing what the device is

DeviceDevice name
ConfigurationDevice paramaters/details (eg. width)
Input/OutputWhether device is for inputting to processor, outputing from the processing, or both
Address BaseStart of address range for the device. This is where the device is memory-mapped to.
Address Map
AddressR/WDescription
base+offsetR/WDescription of what lies in the address space. The "base" refers to the Address Base given directly above.
InitializationIn words, how to initialize the device
Interrupts
TriggeredWhat event actually triggers the interrupt
IRQ LineThe IRQ line it's configured to use
EnableHow to enable interrupts on the device (does not include how to enable processor to accept the interrupts)
AcknowledgeHow to de-assert the interrupt
Hardware SetupHow to plug the device into the DE2 or make other necessary hardware changes such as turning the device on.
Reference Links to other documentation, datasheets, etc.

Notes

Any notes go here, or elaborations on how things work.

Example: Short descriptive title of what code does

  code goes here
7-segment Display on DE2

7-segment Display

The 7-segment displays are configured as a single 32-bit register whose value is shown in hexadecimal on the 8 digits of the 7-segment displays.

Device7-segment Display
ConfigurationOne 32-bit register
Input/OutputOutput only
Address Base0xff1100
Address Mapbase - maps directly to the register

Assembly Example: Write 0xdeadbeef to the 7-segment displays

  .equ ADDR_7SEGS, 0xff1100

  movia r2,ADDR_7SEGS
  movia r3,0xdeadbeef
  stw   r3,0(r2)        /* Write to 7-seg display */

C Example: Write 0xdeadbeef to the 7-segment displays

#define ADDR_7SEGS (long *) 0xff1100
int main()
{
   *ADDR_7SEGS = 0xdeadbeef;
}




Audio Core on DE2



Audio Core

The Audio Core is a circuit which simplifies communication between the Nios II processor and the Audio CODEC responsible for converting sound into digital values (enCOding) and vice versa (DECoding). It is essentially 2 pairs of FIFOs (so 4 in total) each 256 entries deep with each pair responsible for sending/receiving samples to/from the LINEOUT/MIC. They are pairs because there are two different channels, left and right, allowing for stereo sound (stereo sound means the left and right speakers can play different sounds, while mono sound means they both play the same). See the image below for a diagram of the Audio Core and its FIFOs.

DeviceAudio Core
Configuration16-bit samples, dual-channel, 48KHz sampling rate, 256 sample FIFO
Input/OutputBoth
Address Base0xff1160
Address Map
AddressR/WDescription
baseR/WControl Register for clearing FIFOs and interrupt control/status. See Note 1
base+4R/WFifospace Register tells you how much space is in each of the 4 FIFOs. See Note 2.
base+8R/WLeft Data, reads read from the MIC FIFO, writes write to the LINEOUT FIFO.
base+12R/WRight Data, reads read from the MIC FIFO, writes write to the LINEOUT FIFO.
InitializationNone
Interrupts
TriggeredRead Interrupts - when either left/right FIFO is 75% or more filled.
Write Interrupts - when either left/right FIFO is 75% or more empty
IRQ Line12
EnableIn Control Register set bits 1 (WE) and 0 (RE) for write and read interrupts respectively.
AcknowledgeNo Acknowledge - interrupts will keep re-occurring till FIFOs are below/above the 75% mark. See Note 3
Hardware SetupPlug the microphone into the "MIC" port, and the speakers into the "LINEOUT" audio port.
Reference Audio Core Datasheet
WM8731 Audio CODEC Datasheet

Notes

  1. The Control Register uses only the least significant 6 bits as follows:
    BitNameDescription
    0RERead Interrupt enable
    1WERead Interrupt enable
    2CRClear both left and right read FIFOs
    3CWClear both left and right write FIFOs
    4RIIndicates that a read interrupt is pending
    5WIIndicates that a write interrupt is pending

  2. The Fifospace Register stores how much space is in each of the 4 FIFOs. The register is 32-bits wide and since each FIFO has only 256 entries, the Fifospace register can all 4 of the 8-bit values.
    BitsNameDescription
    7:0RA RCRead data Available in Right Channel
    15:8RA LCRead data Available in Left Channel
    23:16WS RCWrite Space in Right Channel
    31:24RA LCRead Space in Left Channel

  3. There is no Interrupt Acknowledge, you simply need to make sure that for every interrupt you appropriately pop/push something to/from the violating FIFO. As long as your Interrupt Service Routine is faster than the 48KHz of the CODEC, the processor will equilibriate with the CODEC and interrupt only once with every new sample. The Nios Processor runs about 2000 times faster than the CODEC's sampling rate, so avoid executing more than 2000 instructions in your ISR.

IMPORTANT: You must always write to both left and right FIFOs. If either FIFO is empty, nothing is sent to the Audio CODEC.

Assembly Example: Echo program - connects mic to speakers, polling

.equ ADDR_AUDIODACFIFO, 0xff1160
_start:
  movia r2,ADDR_AUDIODACFIFO
  ldw   r3,4(r2)      /* Read fifospace register */
  andi  r3,r3,0xff    /* Extract # of samples in Input Right Channel FIFO */
  beq   r3,r0,_start  /* If no samples in FIFO, go back to start */
  ldw   r3,8(r2)
  stw   r3,8(r2)      /* Echo to left channel */
  ldw   r3,12(r2)
  stw   r3,12(r2)     /* Echo to right channel */
  br _start

C Example: Echo program - connects mic to speakers, polling

#include "alt_up_audio.h"

// assumes input only from right channel
int main()
{
   unsigned sample_count;
   long audiobuf[256];

    alt_up_audio_reset_audio_core(); //get the audio started
   while (1)
   {
       sample_count = alt_up_audio_read_right_channel(audiobuf,256);
       if(sample_count)
       { //must write both output channels
           alt_up_audio_write_left_channel(audiobuf,sample_count);
           alt_up_audio_write_right_channel(audiobuf,sample_count);
       }
    }
}

/* For this program to work, alt_up_audio.c has to be included in the list of
 * programs to be compiled (In Nios II Configure Program menu). This file can
 * be found in the folder where the University Program libraries are installed.
 * If this is not done, the linker will fail.*/
Digital Protoboard on DE2

Digital Protoboard

The Digital Protoboard is the the set of 8 switches and 8 LEDs sitting beside the breadboard. This board can be connected to the 40-pin expansion header (either JP1 or JP2) so that the Nios II processor can access these switches and LEDs.

DeviceDigital Protoboard
Input/Outputeither
Address BaseJP1: switches=0xff1110, LEDs=0xff1120;
JP2: switches=0xff1130, LEDs=0xff1140
Address Map
AddressR/WDescription
baseR/WData Register for reading/writing from/to the pins
base+4R/WDirection Register configures each pin for input (0) or output (1)
base+8R/WInterrupt Mask Register enables interrupts for each pin (the corresponding pin should be configured as input)
base+12R/WEdge Capture Register, a bit is high if corresponding pin changed its value. Writing here clears all bits.
InitializationSet Direction Register bits of switches for input, and LEDs for output
Interrupts
TriggeredOn either edge (when any interrupt-enabled input switch is toggled)
IRQ LineJP1=7, JP2=9
EnableSet bits in Interrupt Mask Register that correspond to input pin you want to interrupt on
AcknowledgeWrite to Edge Capture Register (which clears it)
Hardware SetupConnect the 40-pin ribbon from the hexkeypad to either port JP1/2 on the DE2
Reference GPIO Ports

Notes

The 8 switches on the Digital Protoboard are connected to Port A on the expansion header, while the 8 LEDs are connected to Port B. The 8-bits of each Port A and B directly control each switch/LED.

Assembly Example: Using JP1, Read switches into r3

.equ ADDR_JP1PORTA, 0xff1110

  movia r2,ADDR_JP1PORTA
  stw   r0,4(r2)  /* Set directions to input */

  ldw   r3,0(r2)  /* Read port A data */

Assembly Example: Turn on every other LED

.equ ADDR_JP1PORTB, 0xff1120

  movia r2,ADDR_JP1PORTB
  movi  r3,0xff
  stw   r3,4(r2)  /* Set directions to input */

  movi  r3,0xaa
  stw   r3,0(r2)  /* Drive LEDs */

C Example: Using JP1, Read switches to set LEDs

#define ProtoSwitches (volatile char *) 0xff1110
#define ProtoLEDs (volatile char *) 0xff1120
int main()
{ 
   // init protoboard interface directions
   *(ProtoSwitches+4) = 0; //set switch bit directions to input
   *(ProtoLEDs+4) = 0xff; //set LED bit directions to output
    
   while (1)
   {
      *ProtoLEDs = *ProtoSwitches;
   }
}
DMA Controller on DE2

DMA Controller

There is a DMA (Direct Memory Access) Controller which can perform block transfers between the SRAM, SDRAM, Audio FIFOs, and VGA Adapter. It can only transfer blocks less than 65536 bytes.

DeviceDMA Controller
ConfigurationMaximum 65536 byte blocks, connects SRAM, SDRAM, Audio FIFOs, and VGA Adapter
Input/Outputboth
Address Base0xff1180
Address Map
AddressR/WDescription
baseR/WStatus Register contains status bits see Note 1
base+4R/WReadAddress Register stores memory location to read from
base+8R/WWriteAddress Register stores memory location to write to
base+12R/WLength Register stores number of bytes to transfer
base+16R/WNot used
base+20R/WNot used
base+24R/WControl Register - See Note 2
InitializationNone
Interrupts
TriggeredWhen DONE bit is high (ie. A DMA transaction has completed)
IRQ Line13
EnableSet I_EN bit in Control register high
AcknowledgeWrite zero to Status register
Hardware SetupNone
Reference Altera PIO Datasheet

Notes

  1. The Status Register uses only the least significant 5 bits, the pinout is as follows:
    BitNameDescription
    0DONEIndicates the transaction finished, write zero here to clear it
    1BUSYA transaction is in progress
    2REOPRead side end-of-packet (unused)
    3WEOPWrite side end-of-packet (unused)
    4LENLength register was decremented to 0

  2. The Control Register uses only the least significant 7 bits, the pinout is as follows:
    BitNameDescription
    0BYTESpecifies byte at-a-time transfer
    1HWORDSpecifies half-word (16-bit) at-a-time transfer
    2WORDSpecifies word (32-bit) at-a-time transfer
    3GOEnables DMA transactions
    4I_ENEnable interrupts - occur when DONE is high
    5REENEnd on read-side end-of-packet (unused)
    6WEENEnd on write-side end-of-packet (unused)
    7LEENEnd transaction after Length register reaches zero.

Assembly Example: Copy a string on the SDRAM to the SRAM

.equ ADDR_SRAM, 0x800000
.equ ADDR_SDRAM, 0x1000000
.equ ADDR_DMA, 0xff1180

  movia r2,ADDR_DMA

  movia r3,STRING
  stw   r3,4(r2)      /* Set DMA Read Address */

  movia r3,ADDR_SRAM
  stw   r3,8(r2)      /* Set DMA Write Address */

  movia r3,STRINGLENGTH
  stw   r3,12(r2)     /* Set DMA length */

  movi  r3,0b10001001 /* Set control bits:  bit0 - byte at a time */
                                      /*    bit3 - GO */
                                      /*    bit7 - Till length goes to 0 */
  stw   r3,24(r2)     /* Set DMA control */

WAIT:
  ldw   r3,0(r2)
  andi  r3,r3,1
  beq   r3,r0,WAIT    /* Spin until DONE bit goes high */

  stw   r0,(r2)       /* Clear status register - zero DONE flag */
  stw   r0,24(r2)     /* Clear control register - zeros GO bit */

STOP: br STOP

.equ STRINGLENGTH, 80
STRING:
.asciz "Hello World! I should be transferred from SDRAM to SRAM using the DMA controller"
Hexkeypad on DE2

Hexkeypad

The Hexkeypad can be plugged into either the JP1 or JP2 40-pin expansion headers, once plugged in it is automatically connected to Port A of that header and ignores port B. All 8-bits of Port A are connected directly the 4 row pins and 4 column pins (so 8 pins in total) as shown further below.

DeviceHexkeypad
Input/Outputeither
Address BaseJP1=0xff1110, JP2=0xff1130
Address Map
AddressR/WDescription
baseR/WData Register for reading/writing from/to the pins
base+4R/WDirection Register configures each pin for input (0) or output (1)
base+8R/WInterrupt Mask Register enables interrupts for each pin (the corresponding pin should be configured as input)
base+12R/WEdge Capture Register, a bit is high if corresponding pin changed its value. Writing here clears all bits.
InitializationSet direction register bits so that either rows are inputs and columns are output, or vice versa.
Interrupts
TriggeredOn either edge (when any interrupt-enabled input pin changes its value)
IRQ LineJP1=7, JP2=9
EnableSet bits in Interrupt Mask Register that correspond to input pin you want to interrupt on
AcknowledgeWrite to Edge Capture Register (which clears it)
Hardware SetupConnect the 40-pin ribbon from the hexkeypad to either port JP1/2 on the DE2
Reference Hexkeypad Tutorial

Notes

The hexkeypad is arranged as a 4x4 matrix of wires, and note that they are ONLY wires, no circuitry or logic other than pull-up exist. When you press a button the two wires touch, so to figure out when a key is pressed you need to configure, for example, the rows as outputs and the columns as inputs. You can then drive the rows low and see if any column pin turns low (since the hexkeypad is active-low as explained below). For example, if you press number 5 on the hexkeypad, that connects pin R1 to C1 so if you set R1 as a low output you would see it low on C1 if it was an input, and if you set C1 as a low output you would see low on R1 if it was an input. See the referenced Documentation above.

Active-low - The pins of the hexkeypad are set to be "pulled-up" to logical 1 (or high) by default, so if nothing is being pressed you should read 1's. You should hence drive the output pins low and observe which input pin is low.

Acknowledging interrupts - Interrupts are triggered when any bit in the Edge Capture Register is high. For the hexkeypad this means an interrupt gets generated when you first press a button AND when you let go of the button. So make sure you clear it before you enable interrupts and before you exit your interrupt handler.

Pinouts

The image below shows how the Port A pins connect to the 4 row and 4 column pins of the hexkeypad.

Port BitHexpad Pin
0R0
1R1
2R2
3R3
4C0
5C1
6C2
7C3

Assembly Example: In JP1, Drive columns low and read rows into r3

.equ ADDR_7SEG, 0xff1100
.equ ADDR_JP1PORTA, 0xff1110

  movia r2,ADDR_JP1PORTA
  movia r3,0xf0
  stw   r3,4(r2)  /* Set directions - rows to input, columns to output */

  stw   r0,(r2)   /* Drive all output pins low */

  ldw   r3,0(r2)  /* Read port A data */
  andi  r3,r3,0xf /* Mask out all but last 4 bits */

Assembly Example: Using JP1, Append 1,2,4,8 to the 7-segment displays depending on row pressed

.equ ADDR_7SEG, 0xff1100
.equ ADDR_JP2PORTA, 0xff1130
.equ ADDR_JP2PORTA_DIR, 0xff1134

.global _start
_start:

  movia r2,ADDR_7SEG
  mov   r5,zero   /* Start display at 00000000 */
  stw   r5,0(r2)  /* Write to 7-segment displays */

  movia r2,ADDR_JP2PORTA_DIR
  movia r3,0xf0
  stw   r3,0(r2)  /* Set rows to input, columns to output */

  movia r2,ADDR_JP2PORTA
  stw   r0,(r2)   /* Drive all output pins low */

LOOP:
  movia r2,ADDR_JP2PORTA
  ldw   r3,0(r2)  /* Read port A data */
  movi  r4,0xf
  and   r3,r3,r4  /* Mask out all but last 4 bits */

  beq   r4,r3,LOOP

  xor   r3,r3,r4  /* Invert bits */
  slli  r5,r5,4   /* Shift display left */
  or    r5,r5,r3  /* Tack on newest digit */

  movia r2,ADDR_7SEG
  stw   r5,0(r2)  /* Write to 7-segment displays */

                  /* Debounce loop */
  movia r9,10000000
DELAY:
  subi r9,r9,1
  bne r9,r0, DELAY

C Example: In JP1, Display the value of a pressed key

/*****
 * Gets a NON-DEBOUNCED key from the keypad. For notes on debouncing, see the
 * section on "pushbuttons". Note that this also shows the use of procedures
 * and functions in 'C'.
 *
 * This program had prints a key pressed on the hexkeypad to the terminal (by
 * default goes to the Terminal window of the Altera Debug Client, through JTAG
 * UART). The correct program is this:
 *****/

#define ADDR_JP1PORTA (volatile unsigned char *) 0xff1110
#define HEXPAD ADDR_JP1PORTA
#define ADDR_7SEGS (long *) 0xff1100
unsigned char colstims[]={0xe0,0xd0,0xb0,0x70}; //to run the hexpad


// start the hex keypad
// note that since this uses the GPIO interface you must set the
// directions of the individual bits. See the section on GPIO for
// more information.
void HexkeypadInit()
{
   *(HEXPAD+4) = 0xf0; // set directions – rows in, cols out
   *HEXPAD = 0xff; //set all rows to high
}

// return key found pressed, -1 if no key pressed
// note: if multiple keys pressed, returns the first key
// does not debounce key!
char HexkeypadIn()
{

   unsigned char row,col,keyresp;
   char keycount;

   keycount = 0;
   for(row=0x01;row<0x10;row=row<<1) //go through all rows
   {
      for(col=0;col<4;col++) //do all cols for this row
      {
      *HEXPAD = colstims[col]; //stim one column
      keyresp = *HEXPAD & 0x0f; //get response and mask it
          if((keyresp & row) == 0x00) //this key is pressed
            return(keycount); //return val of this key
          keycount++; //to the next numbered key
      *HEXPAD = 0xf0; //return this col to high (inactive) state
      }
   }
   return(-1); //no key pressed
}  


int main()
{ 
   char inputkey;

   HexkeypadInit(); //this is a procedure to start the keypad

   while (1)
   {
      inputkey = HexkeypadIn(); //function, returns key pressed
      if (inputkey != -1) {
         *ADDR_7SEGS = inputkey;
      }
   }
}
JTAG UART on DE2

JTAG UART

A UART (Universally Asynchronous Receiver-Transmitter) core, to allow for communication between a Nios 2 Terminal and the DE2 Board.

DeviceJTAG UART
Input/OutputBoth
Address Base0xff10f0
Address Map
AddressR/WDescription
baseR/WData Register
31:16 - Number of characters available to read (after this read - see Notes)
15 - read data is valid
7:0 - the data itself
base+4R/WControl Register
31:16 - Spaces available for writing
9 - Write interrupt is pending
8 - Read interrupt is pending
1 - Enable write interrupts
0 - Enable read interrupts
InitializationNone
Interrupts
TriggeredOn data-received or able to send (see below)
IRQ Line1
EnableSet bit 1 and/or 0 in the Control Register for write and read interrupts respectively.
AcknowledgeRead (write) interrupts acknowledged by reading (writing) to the Data Register
Software SetupOpen a new Nios II Command shell and type "nios2-terminal", or "make terminal" if you're using the software development package. This window will then function as your terminal (it will display the output from the JTAG UART and you can type in it to send characters to the UART).
Reference Altera JTAG Core Datasheet

Notes

The Data Register is used for both sending and receiving through the JTAG - the type of instruction executed (stw or ldw) determines whether you send or receive. Every time you read from this register a character is ejected from the receive FIFO, and everytime you write to it you insert a character to the send FIFO. Note that you can not read the "Number of Characters available" in bits 31:16 of this register without reading the data in bits 7:0, and hence ejecting another character. The "Number of Characters available" does not include the character you just ejected - but make sure you extract this character from the 32-bit result (if it is valid).

If you try to send a character when the write FIFO is full, the character will not be sent, and will be lossed.

Assembly Example: Sending the character '0' through the JTAG

movui r2, 0x30 /* ASCII code for 0 */
movia r7, 0xff10f0 /* r7 now contains the base address */
stw   r2, 0(r7) /* Write the character to the JTAG */

Assembly Example: Polling the JTAG until valid data has been received

POLL:
  movia r7, 0xff10f0 /* r7 now contains the base address */
  ldw   r2, 0(r7) /* Load from the JTAG */
  andi  r3, r2, 0x8000 /* Mask other bits */
  beq   r3, r0, POLL /* If this is 0 (branch true), data is not valid */

C Example: Sending "Hello World" through the UART

#define JTAG_UART_DATA (volatile int*) 0xff10f0
#define JTAG_UART_CONTROL (volatile int*) (0xff10f0+4)

int main()
{
    unsigned char hwld[] = {'H','e','l','l','o',' ','W','o','r','l','d'};
    unsigned char *pOutput;

    pOutput = hwld;
    while(*pOutput) //strings in C are zero terminated
    {
         //if room in output buffer
         if((*JTAG_UART_CONTROL)&0xffff0000  ) 
         {
            //then write the next character
            *JTAG_UART_DATA = (*pOutput++); 
         }
     }
}
LCD Controller for the DE2 Board

LCD Controller

The LCD Controller allows you to control the LCD screen on the DE2 board. It will recognize ASCII characters, and accepts various control signals to modify the way it functions and the position of the cursor.

DeviceLCD Controller
ConfigurationTwo 32-bit mapped registers
Input/OutputEither
Address Base0xff1060
Address Map
AddressR/WDescription
baseR/WInstruction
base+4R/WData
ReferencesAltera's Documentation of LCD Core
Detailed Documentation of LCD Controller (See page 14 for full list of instructions available)

Notes

The LCD screen must first be initialized with a series of control signals before you can write ASCII characters to it. The series of commands to initialize the controller for basic functionality (printing ASCII characters as they are sent to the controller) is:

0x38, 0x0c, 0x01, 0x06, 0x80

The LCD controller requires a control signal to change lines or the position of the cursor other than advancing with each character, rather than the ASCII codes. See the example below for details.

Assembly Example: Writing the letter "A", then moving the cursor to the second line

	movia r7, 0xff1060 /* r7 contains base address for LCD controller */
	movui r3, 0x65 /* ASCII code for A */
	stw   r3, 4(r7) /* Write the letter A */

	movui r3, 0xc0 /* Command for moving to the first bit of the second line */
	stw   r3, 0(r7) /* Send the command */

C Example: Write "Hello World" to the LCD Display

#include "alt_up_character_lcd.h"

int main()
{
    alt_up_character_lcd_init(); //init LCD
    alt_up_character_lcd_write("HELLO WORLD",11); //write LCD
}

/* For this program to work, alt_up_character_lcd.c has to be included in the
 * list of programs to be compiled (In Nios II Configure Program menu). This
 * file can be found in the folder where the University Program libraries are
 * installed. If this is not done, the linker will fail.  */
LEDs on DE2

LEDs

There are 18 red LEDs which can be set by writing directly to the 18 least significant bits of the red LED register at 0xff1070, and similarly there are 9 green LEDs at 0xff1080. Both of those locations are in fact 32-bits wide, the upper unused bits are don't cares.

Device7-segment Display
ConfigurationTwo 32-bit registers, one for red and one for green
Input/OutputOutput only
Address Basered LEDs: 0xff1070
green LEDs: 0xff1080
Address Mapbase - each map directly to the register

Notes

Each register is 32-bits wide but only the bottom 18/9 are used for the red/green LEDs. The upper bits are don't cares.

Assembly Example: Turn on all green LEDs

.equ ADDR_GREENLEDS, 0xff1080

  movia r2,ADDR_GREENLEDS
  movi  r3,0xff
  stw   r3,0(r2)        /* Write to LEDs */

Assembly Example: Turn on every other red LED

.equ ADDR_REDLEDS, 0xff1070

  movia r2,ADDR_REDLEDS
  movia r3,0xaaaaa
  stw   r3,0(r2)        /* Write to LEDs */

C Example: Turn on all green LEDs

#define GLEDs (long *) 0xff1080
int main()
{
     *GLEDs = 0x0ff;
}

C Example: Turn on every other red LED

#define RLEDs (long *) 0xff1070
int main()
{
     *RLEDs = 0xaaaaa;
}
Lego Controller on DE2

Lego Controller

The Lego Controller can be plugged into either the JP1 or JP2 40-pin expansion headers, and allows the user to control up to 4 motors (turning them ON/OFF and changing their direction), and read the values of up to 4 light sensors. For a detailed explanation of the bit-mapping, please refer to the Notes section.

DeviceLego Controller
Input/Outputeither
Address BaseJP1: motors=0xff1110, sensors=0xff1120; JP2: motors=0xff1130, sensors: 0xff1140
Address Map Motors:
AddressR/WDescription
baseR/WData Register for controlling the motors (see Notes for more details)
base+4R/WDirection Register, must be set to 0xff

Sensors:
AddressR/WDescription
baseR/WData Register for reading the light sensors (see Notes for more details)
base+4R/WDirection Register, must have its lowest 4 bits set to 0
base+8R/WInterrupt Mask Register enables interrupts for each of the 4 sensors (lowest 4 bits only)
base+12R/WEdge Capture Register, a bit is high if corresponding sensor changed its value (lowest 4 bits only). Writing here clears all bits.
InitializationSet the direction register of the motors to 0xff (all outputs). Set the lowest 4 bits of the direction register of the sensors to 0 (inputs). The highest 4 bits are not used; hence, it is possible to simply write 0x00 into this direction register.
Interrupts
TriggeredOn either edge (when any interrupt-enabled input pin changes its value)
IRQ LineJP1=7, JP2=9
EnableSet bits in Interrupt Mask Register that correspond to the sensor you want to interrupt on
AcknowledgeWrite to Edge Capture Register (which clears it)
Hardware SetupConnect the 40-pin ribbon from the Lego Controller to either port JP1/2 on the DE2
Reference Lego Manual

Notes

The Lego Controller is used to provide an easy interface to the motors and light sensors in the Lego kit. It has two override switches that can turn motors off (one switch for motors 1 and 2, and a second switch for motors 3 and 4). Each of the 4 sensor ports has a potentiometer ("pot"), which can be used to adjust its sensitivity. Make sure that these pots are set correctly for your needs. Lastly, there are two power connectors, providing 5V and 9V. The 5V connector can be used to connect to a motor, and the 9V connector connects to a special Lego piece, and can be used to power a light. Both power connectors can be switched off using a switch located close to them.

Controlling the motors - The motors are controlled by writing to the Data Register designated for them (see table above). The controlling bits come in pairs, and lower bits correspond to lower-numbered motors. In each bit pair, the lower bit is used to turn the motor ON and OFF (0 = OFF, 1 = ON), and the higher bit is used to choose one of two possible directions of rotation. The actual directions depend on the polarity of the connections to the motors. Refer to the diagram below for more information.

Figure 1: The motors Data Register bit mapping

Reading the sensors - Reading the light sensors is done by reading the value of the Data Register designated for them (see table above). Only the lowest 4 bits of the byte are used, and lower bits correspond to lower-numbered sensors. For example, bit 0 corresponds to sensor #1, bit 1 corresponds to sensor #2, etc. The values of the sensors are active-high (i.e., a light shining on a particular light sensor would cause the corresponding bit to be 1).

Interrupts - Interrupts are triggered when any bit in the Edge Capture Register is high. For the Lego Controller this means an interrupt gets generated whenever light is shining on a connected sensor.

Relationship to the parallel interface - As described above, the communication with the Lego Controller is done using either one of the two parallel interfaces (JP1 or JP2). Using an alternate terminology, it can be said that for a particular parallel connector, motors are controlled through port A of the parallel interface, and sensors are read through port B.

Pinouts

The table below shows how the pins of ports A and B of the parallel interface connect to the motors and sensors of the Lego Controller.

Port A BitMotor
0Motor 1 (on/off)
1Motor 1 (direction)
2Motor 2 (on/off)
3Motor 2 (direction)
4Motor 3 (on/off)
5Motor 3 (direction)
6Motor 4 (on/off)
7Motor 4 (direction)
       
Port B BitSensor
0Sensor 1
1Sensor 2
2Sensor 3
3Sensor 4
4Not Used
5Not Used
6Not Used
7Not Used

Assembly Example: Using JP1, Turn motor #1 ON

.equ ADDR_PORT1A, 0xff1110	 /* port A: used to control the motors */
.equ ADDR_DIR1A, 0xff1114            /* port A: I/O direction */

  movia  r2, ADDR_DIR1A              /* set PORTA (motors) for output */
  movi   r3, 0xff
  stb    r3, 0(r2)

  movia  r2, ADDR_PORT1A             /* r2 points to port A (motors) */
  movi   r3, 1
  stb    r3, 0(r2)                   /* Set ON bit for motor #1, rest low */

Assembly Example: Using JP1, read sensors into r3

.equ ADDR_PORT1B, 0xff1120	 /* port A: used to control the motors */
.equ ADDR_DIR1B, 0xff1124            /* port A: I/O direction */

  movia  r2, ADDR_DIR1B              /* set PORTB (sensors) for input */
  stb    r0, 0(r2)

  movia  r2, ADDR_PORT1B             /* r2 points to port B (sensors) */
  ldb    r3, 0(r2)                   /* Read sensor data port into r3 */

Assembly Example: Using JP1, Turn motor #1 ON/OFF and change its direction depending on the values of two sensors

.equ ADDR_PORT1A, 0xff1110	 /* port A: used to control the motors */
.equ ADDR_DIR1A, 0xff1114            /* port A: I/O direction */
.equ ADDR_PORT1B, 0xff1120           /* port B: used to read the light sensors */
.equ ADDR_DIR1B, 0xff1124            /* port B: I/O direction */

.global main
main:

  movia  r2, ADDR_DIR1A              /* set PORTA for output */
  movi   r3, 0xff
  stb    r3, 0(r2)

  movia  r2, ADDR_DIR1B              /* set PORTB for input */
  stb    r0, 0(r2)

  movia  r2, ADDR_PORT1A             /* r2 points to port A (motors) */
  movia  r3, ADDR_PORT1B             /* r3 points to port B (sensors) */

  stb    r0, 0(r2)                   /* turn off all motors */

CHECK_SENSOR1:
  ldb    r4, 0(r3)                   /* read light sensors into r4 */

  andi   r5, r4, 0x01                /* check sensor #1 */
  beq    r5, r0, MOTOR_OFF           /* if no light, turn motor off */

MOTOR_ON:
  ldb    r5, 0(r2)                   /* read current state of motors Data Register */
  ori    r5, r5, 0x01                /* turn motor #1 ON by setting bit 0 to 1 */                    
  stb    r5, 0(r2)
  br     CHECK_SENSOR2

MOTOR_OFF:
  ldb    r5, 0(r2)                   /* read current state of motors Data Register */
  andi   r5, r5, 0xfe                /* turn motor #1 OFF by setting bit 0 to 0 */
  stb    r5, 0(r2)

CHECK_SENSOR2:
  andi   r5, r4, 0x02                /* check sensor #2 */
  beq    r5, r0, DIRECTION2          /* if no light, set to direction 2 */

DIRECTION1:
  ldb    r5, 0(r2)                   /* read current state of motors Data Register */
  ori    r5, r5, 0x02                /* set to direction 1 by setting bit #1 */
  stb    r5, 0(r2)
  br     FINISH

DIRECTION2:
  ldb    r5, 0(r2)                   /* read current state of motors Data Register */
  andi   r5, r5, 0xfd                /* set to direction 2 by unsetting bit #1 */
  stb    r5, 0(r2)

FINISH:
  br     CHECK_SENSOR1               /* repeat the program */

C Example: Using JP1, Turn motor #1 ON

#define ADDR_PORT1A 0xff1110
#define LegoMotors (volatile char *) ADDR_PORT1A

int main()
{ 
   // init lego motor interface directions
   *(LegoMotors+4) = 0xff; //set all bit directions to output
    
   *LegoMotors = 0x01; //set motor 1 on

}
GPIO Ports on DE2

GPIO Port 1A, 1B, 2A, 2B

There are a total of four General Purpose I/O (GPIO) Ports, each made of 8 bidirectional pins on the JP1 and JP2 40-pin expansion headers (hence the ports are each 8-bits wide). These ports are designed to be used with some of the lab's peripherals such as the hexkeypad, Lego controller, and digital protoboard.

DeviceGPIO Port A & B on JP1 & JP2 (can be used with hexkeypad, Lego, or digital protoboard)
Configuration8-bit wide bidirectional port
Input/Outputeither
Address Base1A=0xff1110, 1B=0xff1120, 2A=0xff1130, 2B=0xff1140
Address Map
AddressR/WDescription
baseR/WData Register for reading/writing from/to the pins
base+4R/WDirection Register configures each pin for input (0) or output (1)
base+8R/WInterrupt Mask Register enables interrupts for each pin (the corresponding pin should be configured as input)
base+12R/WEdge Capture Register, a bit is high if corresponding pin changed its value. Writing here clears all bits.
InitializationSet direction register bits to input/output
Interrupts
TriggeredOn either edge (when any interrupt-enabled input pin changes its value)
IRQ Line1A=7, 1B=8, 2A=9, 2B=10
EnableSet bits in Interrupt Mask Register that correspond to input pin you want to interrupt on
AcknowledgeWrite to Edge Capture Register (which clears it)
Hardware SetupConnect the 40-pin ribbon from the hexkeypad/lego controller/protoboard to either port JP1/2 on the DE2
Reference Digital Protoboard
Hexkeypad
Lego Controller
Altera PIO Datasheet

Notes

Choosing a port - You can connect to either one of the 40-pin headers JP1 or JP2, they are both identical. However choosing between port A and port B will be partly determined by the peripheral. For example, if you're using the hexkeypad you should know that it only uses Port A. So when you plug it into JP1 you're automatically using port 1A, and if you plug the ribbon into JP2 you get get port 2A. You then should use the corresponding address base and IRQ line.

Acknowledging interrupts - Interrupts are triggered when any bit in the Edge Capture Register is high. So make sure you clear it before you enable interrupts and before you exit your interrupt handler.

Pinouts

The image below shows where on the 40-pin expansion ports you can find the 8 pins for port A (A0..A7) and port B (B0..B7).


Assembly Example: Write 0xab to GPIO Port 1A

.equ ADDR_JP1PORTA, 0xff1110
.equ ADDR_JP1PORTA_DIR, 0xff1114

  movia r2,ADDR_JP1PORTA_DIR
  movi  r3,0xff
  stw   r3,0(r2)  /* Set direction of all 8-bits to output */

  movia r2,ADDR_JP1PORTA
  movi  r3,0xab
  stw   r3,(r2)   /* Write value to output pins */

Assembly Example: Read pins on GPIO Port 1B into register r3

.equ ADDR_JP1PORTB, 0xff1120
.equ ADDR_JP1PORTB_DIR, 0x681124

  movia r2,ADDR_JP1PORTB_DIR
  stw   r0,0(r2)  /* Set direction of all 8-bits to input */

  movia r2,ADDR_JP1PORTB
  ldw   r3,(r2)   /* Read value from pins */

Assembly Example: Enable interrupts on bits 0-3 of port 1A

.equ ADDR_JP1PORTA, 0xff1110
.equ ADDR_JP1PORTA_DIR, 0xff1114
.equ ADDR_JP1PORTA_IE, 0xff1118
.equ ADDR_JP1PORTA_EDGE, 0xff111c
.equ IRQ_JP1PA, 0x80

  movia r2,ADDR_JP1PORTA_DIR
  stw   r0,0(r2)  /* Set all 8-bits to inputs */

  movia r2,ADDR_JP1PORTA_IE
  movi  r3,0xf
  stw   r3,0(r2)  /* Enable interrupts on 4 LSB pins */

  movia r2,IRQ_JP1PA
  wrctl ctl3,r2   /* Enable bit 7 - button interrupts on Nios2 */

  movia r2,1
  wrctl ctl0,r2   /* Enable global Interrupts on Nios2 */

Assembly Example: Interrupt Handler

.org 0x20
IHANDLER:                 /* All interrupts go to 0x20 */
  rdctl et, ctl4          /* Check if an external interrupt has occurred */
  beq et, r0, SKIP_EA_DEC 

  movia r7,IRQ_JP1PA        /* test for bit 7 interrupt */
  and   r7,et,r7
  beq   r7,r0,EXIT_IHANDLER /* if not, exit handler */

  movia r2,ADDR_JP1PORTA
  ldw   r3,0(r2)  /* Read port A data */

  /*** Do whatever you want with the data from the pins ***/

  movia r7,ADDR_JP1PORTA_EDGE
  stw   r0,0(r7) /* De-assert interrupt - write to edgecapture regs*/

EXIT_IHANDLER:
  subi ea,ea,4    /* Replay interrupted instruction for hw interrupts */
SKIP_EA_DEC:
  eret

C Example: Write value from GPIO Port 1B to GPIO Port 1A

#define ADDR_JP1PORTA (volatile char *) 0xff1110
#define ADDR_JP1PORTB (volatile char *) 0xff1120
int main()
{ 
   // init interface directions
   *(ADDR_JP1PORTB+4) = 0; //set every port1B bit direction to input
   *(ADDR_JP1PORTA+4) = 0xff; //set every port1A bit dir to output
    
   while (1)
   {
      *ADDR_JP1PORTA = *ADDR_JP1PORTB;
   }
}

PS/2 Controller on DE2

PS/2 Controller

The PS/2 Controller is a peripheral that allows for communication between the DE2 Board and a PS/2 Device (Mouse or keyboard).

DevicePS/2 Controller
Configuration2 32-bit mapped registers
Input/OutputEither
Address Base0xff1150
Address Map
AddressR/W/CDescription
baseR/W31:16 Number of characters left to be read (including this read)
7:0 Data
base+4R/CControl/status bits:
10 - indicates an error has occured
8 - read interrupt pending
0 - read interrupt enable
InitializationNone, but mouse or keyboard may require initialization (see references)
Interrupts
TriggeredOn data received
IRQ Line11
EnableBit 0 of control register
AcknowledgeRead data to acknowledge the interrupt
Hardware SetupPlug a PS/2 Device into the PS/2 port on the DE2 Board.
ReferenceFull Documentation of controller from Altera
PS2 Mouse Protocol
PS2 Keyboard Protocol
PS/2 Non-device-specific Documentation (hardware)

Notes

The PS/2 Controller only provides a method for communication between the board and the device. In this way, it functions somewhat similar to a PIT. The style of communication that will take place depends on the device in question.

For specific information on interacting with a PS/2 Mouse or Keyboard, see the references for details.

Assembly Example: A subroutine to send a command to the mouse

/** Sends the command stored in R2, then waits for the response values stored in r3 and/or r4 (if there are any – values greater than 0xff in those registers mean to not expect a response.) */
EXECUTE_COMMAND:
   movia r7, 0xff1150
   rdctl r17, ctl3 /* Disable interrupts during command execution */
   wrctl ctl3, r0

   movui r5, 0xff
   movia r7, PS2
   stw   r2, 0(r7) /* Send command in r2 */

   bgt r3, r5, return_from_execute /* If r3 is > 0xff, finished */

Exec_Loop_1:
   ldw   r6, 0(r7) /* Since r3 < 0xff, wait for the response */
   andi r6, r6, 0xff
   bne r3, r6, Exec_Loop_1

   bgt r4, r5, return_from_execute /* If r4 is > 0xff, finished */

Exec_Loop_2:
   ldw   r6, 0(r7) /* Since r4 < 0xff, wait for the response */
   andi r6, r6, 0xff
   bne r4, r6, Exec_Loop_2

return_from_execute:
   wrctl ctl3, r17 /* Restore previous interrupts */
   ret /* Return */
Push Buttons on DE2

Push Buttons

There are 4 push buttons labelled KEY[0] through KEY[3] on the board which can be simultaneously read as the lowest 4 bits of a memory-mapped register. They are active low, so when you are not pressing them their value is 1, and while you hold them down their value is 0. The push buttons are relatively clean but still require debouncing (see Notes).

DevicePush Button Keys
Configuration32-bit wide register (only least significant 4-bits used)
Input/OutputInput
Address Base0xff1090
Address Map
AddressR/WDescription
baseR/WData Register for reading values from the buttons
base+4R/WNot used
base+8R/WInterrupt Mask Register enables interrupts for each button
base+12R/WEdge Capture Register, a bit is high if corresponding button changed its value. Writing here clears this register.
InitializationNone
Interrupts
TriggeredOn either edge (when any interrupt-enabled button changes its value)
IRQ Line5
EnableSet bits in Interrupt Mask Register that correspond to button you want to interrupt on
AcknowledgeWrite to Edge Capture Register (which clears it)
Hardware SetupNone
Reference Altera PIO Datasheet

Notes

Acknowledging interrupts - Interrupts are triggered when any bit in the Edge Capture Register is high. So make sure you clear it before you enable interrupts and before you exit your interrupt handler.

Debouncing - Debouncing: When you press a key a mechanical contact is made, but it takes a while (10-15 msec typically) to actually settle into place. Before it settles, the contacts "bounce", closing then opening then closing then opening. Digital hardware, or a processor, operates so quickly that it can mistakenly see this as multiple actuations of the pushbutton unless it allows for the debounce time. You will have to use software to make allowances for this phenomenon. (Compensation could have been done in hardware.)

Assembly Example: Read in buttons into r3

.equ ADDR_PUSHBUTTONS, 0xff1090

  movia r2,ADDR_PUSHBUTTONS
  ldw   r3,(r2)   /* Read in buttons - active low */

Assembly Example: Enable Interrupts

.equ ADDR_PUSHBUTTONS, 0xff1090
.equ IRQ_PUSHBUTTONS, 0x20

  movia r2,ADDR_PUSHBUTTON
  movia r3,0xe
  stw   r3,8(r2)  /* Enable interrupts on push buttons 1,2, and 3 */

  movia r2,IRQ_PUSHBUTTON
  wrctl ctl3,r2   /* Enable bit 5 - button interrupt on Processor */

  movia r2,1
  wrctl ctl0,r2   /* Enable global Interrupts on Processor */

C Example: Reading the Pushbuttons

#define Pushbuttons (volatile long *) 0xff1090
#define GLEDs (long *) 0xff1080
int main()
{ 
   long PBval;

   while (1)
   {
      PBval = *Pushbuttons;
      // Display the state of the buttons on green LEDs
      *GLEDs = PBval;

   }
}

C Example: Checking for changes in the Pushbuttons

#define PushbuttonChanges (volatile long *) 0xff109C
#define GLEDs (long *) 0xff1080
int main()
{ 
   long PBchanges;
   int i;

 *PushbuttonChanges = 0; //clear out any changes so far 
 while (1)
   {
      PBchanges = *PushbuttonChanges;
      // Display the state of the change register on green LEDs
      *GLEDs = PBchanges;
      if(PBchanges)
      {
         // Delay, so that we can observe the change on the LEDs
         for (i=0; i<10000000;i++);
         *PushbuttonChanges = 0; //reset the changes for next round
      }
   }
}
Random Number Generator on DE2

Random Number Generator

The random number generator outputs a new 32-bit random number on every clock cycle.

DeviceRandom Number Generator
Configuration32-bit
Input/OutputBoth
Address Base0xff11a0
Address Map
AddressR/WDescription
baseR/WReads read a new random number; Writes write a new seed value into the generator, see Notes

Notes

Pseudo Randomness

For the most part, you likely won't ever need to worry about the fact that the generator does not give truly random output, but in the odd case that you do, the concept of seeding the pseudo random number generator is discussed here.

The Random Number Generator generates random numbers between 0x00000000 and 0xFFFFFFFF every clock cycle. However, from the moment you configure the FPGA, the same sequence of random numbers are generated everytime, making the generator a psuedo random number generator instead of a truly random number generator. To get truly random numbers you have to "seed" the generator once with a single number that was truly randomly generated.

Because the amount of time you spend to typing in the terminal to download your program to the board is random (somewhat close to truly random), a simple way to do this is to seed it with the output from the Random Number Generator itself at the start of your program.

Assembly Example: Read a random number into r3

.equ ADDR_RNG, 0xff11a0

  movia r2,ADDR_RNG
  ldw   r3,(r2)

Assembly Example: Setting the seed to the current random number

.equ ADDR_RNG, 0xff11a0

  movia r2,ADDR_RNG
  ldw   r3,(r2)
  stw   r3,(r2)

C Example: Read a random number

#define RandomNum (volatile long *) 0xff11a0
#define ADDR_7SEGS (long *) 0xff1100
long rando;
int main()
{ 
   int i;

   while (1)
   {
      rando = *RandomNum;
      *ADDR_7SEGS = rando;
      // Create a delay, so that we can observe the number on 7-segment displays
      for (i=0; i<100000000;i++);
   }
}
RS-232 UART on DE2

RS-232 UART

The RS-232 UART (Universally Asynchronous Receiver-Transmitter) is a serial protocol UART, allowing for a connection between a terminal and the DE2 Board.

DeviceRS-232 UART
Configuration6 16-bit mapped registers which each occupy 32 bits (other 16 bits reserved)
Input/OutputEither
Address Base0xff1000
Address Map
AddressR/WDescription
baseR6:0 Receive Data
base+4W6:0 Transmit Data
base+8R/WStatus register bits:
7 - Receive ready (data available)
6 - Transmit ready (can send data to the transmit shift
register)
5 - Transmit empty (transmit shift register is empty)
base+12R/WControl Register (see Notes below)
base+16R/WBaud rate divisor - if configured in your system, allows changing of the baud rate divisor.
(Disabled in default system, register does not exist)
base+20R/W6:0 End-of-packet value - value that indicates the end of packet - default value is 0 (ASCII \0)
InitializationNone
Interrupts
TriggeredAny bit of status register becoming 1 if corresponding control bit is 1
IRQ Line2
EnableConfigured in control register
AcknowledgeRead or write to acknowledge the corresponding interrupt
Hardware SetupPlug the serial cable into the serial outlet on the DE2 Board (also see Notes)
ReferenceFull documentation from Altera.

Notes

To communicate through the RS-232, you must set up a terminal to send and receive characters. Open the Conport program under Courseware, ensure that the Baud Rate is set to 115200 (for the default system, or whatever your baud rate is in a custom system), and ensure that it is communicating through CON1.

Each bit in the control register (offset 12) corresponds to a bit in the status register (offset 8) – if the corresponding bit in the control register is 1, an interrupt will be triggered when the bit in the status register becomes 1.

To check if the device is able to send a new character, read the transmit ready bit in the status register. The transmit empty bit can be read to determine if the last transmition has been completed (and received at the other end of the serial link).

Assembly Example: Receiving a character through the RS-232 UART

  movia r7, 0xff1000                   /* r7 contains base address of the RS-232 UART */

POLL:
  ldw   r3, 8(r7)                          /* Poll for when a character is available to receive */
  andi r3, r3, 0x80
  beq r3, r0, POLL

  ldw   r2, 0(r7)                          /* Receive the character in the RS-232 */

C Example: Sending "Hello World" through the UART

#define RS232_UART_RX (volatile char*)  0xff1000 
#define RS232_UART_TX (volatile char*)  (0xff1000+4) 
#define RS232_UART_STATUS (volatile char*)  (0xff1000+8) 

int main()
{
    unsigned char hwld[] = {'H','e','l','l','o',' ','W','o','r','l','d'};
    unsigned char *pOutput;

    pOutput = hwld;
    while(*pOutput) //strings in C are zero terminated
    {
         //if room in output buffer
         if((*RS232_UART_STATUS )&0x40  ) 
         {
            //then write the next character
            *RS232_UART_TX = (*pOutput++); 
         }
     }
}
Slide Switches on DE2

Slide Switches

The 18 Slide Switches are mapped to a single 32-bit register whose bits correspond directly to each switch. For example, bit 0 gives the value for switch 0. Bits 31:17 are not used.

Device7-segment Display
ConfigurationOne 32-bit register
Input/OutputInput only
Address Base0xff10a0
Address Mapbase - maps directly to the register

Assembly Example: Read switches into r3

  .equ ADDR_SLIDESWITCHES, 0xff10a0

  movia r2,ADDR_SLIDESWITCHES
  ldw   r3,0(r2)                /* Read switches */

C Example: Set red LEDs with switches, invert switch #4

#define Switches (volatile long *) 0xff10a0
#define RLEDs (long *) 0xff1070
int main()
{ 
   long Swval;
   unsigned long Sw3val;
   while (1)
   {
      Swval = *Switches;
      Sw3val = Swval & 0x10;
      if (Sw3val)
         Swval = Swval & 0xfffef;
      else
         Swval = Swval | 0x010;
      *RLEDs = Swval;
   }
}
Legend for describing devices on DE2

Device Name

Small amount of text describing what the device is

DeviceDevice name
ConfigurationDevice paramaters/details (eg. width)
Input/OutputWhether device is for inputting to processor, outputing from the processing, or both
Address BaseStart of address range for the device. This is where the device is memory-mapped to.
Address Map
AddressR/WDescription
base+offsetR/WDescription of what lies in the address space. The "base" refers to the Address Base given directly above.
InitializationIn words, how to initialize the device
Interrupts
TriggeredWhat event actually triggers the interrupt
IRQ LineThe IRQ line it's configured to use
EnableHow to enable interrupts on the device (does not include how to enable processor to accept the interrupts)
AcknowledgeHow to de-assert the interrupt
Hardware SetupHow to plug the device into the DE2 or make other necessary hardware changes such as turning the device on.
Reference Links to other documentation, datasheets, etc.

Notes

Any notes go here, or elaborations on how things work.

Example: Short descriptive title of what code does

  code goes here
Timer on DE2

Timer

The timer is a peripheral that allows the user to measure real-time as a number of clock cycles. A user loads the timer with the number of clock cycles they’d like to wait, and then polls the “Timeout” bit or optionally enables an interrupt to indicate to the processor that the period has elapsed. There are two timers in the system, Timer0 and Timer1, both are identical so you can use either one just by changing the address base.

DeviceTimer
Configuration6 32-bit mapped registers (only lower 16 bits used)
Input/OutputBoth
Address BaseTimer0: 0xff1020
Timer1: 0xff1040
Address Map
AddressR/WDescription
baseR/WStatus Register bits:
1 - Run (1 if timer is running)
0 - Timeout (1 if timer has timed out - write 0 to this address to clear)
base+4R/WControl Register bits:
3 - stop (write 1 to stop timer)
2 - start (write 1 to start timer)
1 - cont (if this bit is 1, timer will restart and continue when it times out,
otherwise it will just reload the timeout period, but not start)
0 - interrupt enable for timeouts
base+8R/WPeriodl - lower 16 bits of Timeout period
base+12R/WPeriodh - upper 16 bits of Timeout period
base+16R/WCounter Snapshot (lower 16 bits)
base+20R/WCounter Snapshot (upper 16 bits)
InitializationNone (though a period must be written before running the timer, or it will immediately timeout)
Interrupts
TriggeredOn timeout
IRQ LineTimer0: 3
Timer1: 4
EnableBit 0 of Control Register
AcknowledgeWrite 0 to status register to clear timeout bit (see address map above)
Hardware SetupNone
ReferenceFull documentation from Altera

Notes

The timer runs on a 100MHz clock, and runs in terms of clock cycles (a period of 100000000 will cause the timer to timeout in 1 second).

The full 32-bit period of the timer is given by the combination of “Periodh” and “Periodl”. Both those registers are only 16-bits, even though they take up 32-bits of the address space.

When a timeout occurs, the Timeout bit in the Control Register will stay as 1 until the user writes 0 to the status register.

When a timeout occurs, the timer's counter is reset to the period, regardless of the "continue" bit. The continue bit determines whether the timer will then wait until 1 is written to the start bit again, or continue running immediately.

Reading the time remaining in the timer can not be done by reading the Periodh/l registers. Instead, the Counter Snapshot is used to copy the current time remaining, which can then be safely read by the user. By writing to either one of the snapshot registers (the written value is ignored), the current value of Periodh and Periodl, will be copied into the corresponding snapshot registers, which can then be read as in example 2 below.

WARNING: Do not try to read the Periodh/l registers directly.

Assembly Example 1: Setting the timer to run for 1000 clock cycles, and stop when it times out

   movia r7, 0xff1020                   /* r7 contains the base address for the timer */
   movui r2, 1000
   stw   r2, 8(r7)                          /* Set the period to be 1000 clock cycles */
   stw   r0, 12(r7)

   movui r2, 4
   stw   r2, 4(r7)                          /* Start the timer without continuing or interrupts */

Assembly Example 2: Reading the current value of the timer into R4

   movia r7, 0xff1020           /* r7 contains the base address for the timer */
   stw   r0,16(r7)              /* Tell Timer to take a snapshot of the timer */
   ldw   r3,16(r7)              /* Read snapshot bits 0..15 */
   ldw   r4,20(r7)              /* Read snapshot bits 16...31 */
   slli  r4,r4,16		/* Shift left logically */
   or    r4,r4,r3               /* Combine bits 0..15 and 16...31 into one register */

C Example: Reading the Timer value

#define Timer0 0xff1020
#define Timer0Status (volatile short*) (Timer0)
#define Timer0Control (volatile short*) (Timer0+4)
#define Timer0TimeoutL (volatile short*) (Timer0+8)
#define Timer0TimeoutH (volatile short*) (Timer0+12)
#define Timer0SnapshotL (volatile short*) (Timer0+16)
#define Timer0SnapshotH (volatile short*) (Timer0+20)

#define ADDR_7SEGS (long *) 0xff1100

long numclks,numchigh,numclow;
int main()
{ 
   int i;
   
   // Configure the timeout period to maximum
   *(Timer0TimeoutL)=0xffff;
   *(Timer0TimeoutH)=0xffff;
   // Configure timer to start counting and to always continue
   *(Timer0Control)=6;

   while (1)
   {
      *(Timer0SnapshotL)=0; //write to timer to get snapshot
      numclow = *(Timer0SnapshotL); //get low part
      numchigh = *(Timer0SnapshotL ); //get high part
      numclks = numclow +(numchigh << 16); //assemble full number
      *ADDR_7SEGS = numclks;

      // Create a delay, so that we can observe the count on 7-segment displays
      for (i=0; i<10000000;i++);
   }
}
VGA Adapter on DE2

VGA Adapter

The VGA Adapter is used to draw pixels on your computer monitor. It connects the Nios2 processor to the DE2 Video DAC chip which then outputs to your monitor. The interface to the adapter is identical to that of a memory, the address corresponds to the pixel you want to write, and the data you write to that address is the colour you want to draw.

DeviceVGA Adapter
Configuration160x120 resolution, 3-bit colour
Input/OutputOutput only
Address Base0xa00000
Address Mapbase+{y[6:0],x[7:0],2'b0} corresponds to pixel (x,y); write access only
InitializationNone needed
InterruptsNone
Hardware SetupConnect the VGA plug of your monitor to the VGA port of the DE2
Reference VGA Adapter website
ADV7123 Video DAC datasheet

Notes

Colour - Each pixel has 32-bits allocated for it in the address space, but only the least significant 3 bits are used to designate the colour. The colours are red, green, blue from MSB to LSB. And of course mixtures are possible as well, see the table below for the full colour map.

Colour Table (3-bits)
ValueColour
000
001
010
011
100
101
110
111

Pixel Address - Since each pixel has 32-bits allocated, the least significant 2-bits of the address are not used and the address is broken down as shown below to extract the x and y coordinate of the desired pixel. Note that the upper bits of the address should take on the necessary value for the Address Base of the VGA Adapter 0xa00000.

Drawing shapes/text - The controller draws only pixels at a time, to draw lines, shapes, or text you need to manually draw each pixel.

Address
Bits16:109:21:0
Functiony[6:0]x[7:0]Unused

Assembly Example: Draw white dot at pixel (4,1)

  .equ ADDR_VGA, 0xa00000

  movia r2,ADDR_VGA
  movi  r3,7
  stw   r3,1040(r2) /* pixel (4,1) is at 4*(4+256*1) = 1040 */

C Example: Program to write two lines on the screen

/* set a single pixel on the screen at x,y
 * x in [0,159], y in [0,119], and colour in [0,7] 
 */ 
void write_pixel(int x, int y, int colour) {
  int *vga_addr=(int*)(0xa00000 + (y<<10) + (x<<2));
  *vga_addr=colour;
}

int main () {

   int x;

   for (x=0;x<160;x++)
   {
      // Draw a straight line in red across the screen centre
      write_pixel(x, 59, 4);
      // Draw a "diagonal" line in green
      if (x<120)
         write_pixel(x, x, 2);
   }
   return 0;
}