ECE 332L
Spring 2008
Microprocessors Lab
Nios II HAL API
Lab 7
Objective: This lab introduces the hardware abstraction layer (HAL) for the Nios II processor. HAL is a
lightweight runtime environment that provides a simple device driver interface for programs to communicate with
the underlying hardware.
Part 1: Introduction
In previous labs we have been focused on working with devices at the lowest levels. Last week we utilized a
portion of the HAL functionality provided by Altera that allowed us easy access to the hardware interrupts on the
NIOS II system.
HAL provides the glue between the low level devices and the standard libraries found on most systems that
provide C compilers. As can seen in Figure 1, devices can be accessed through the Standard C Libraries, directly
through the HAL API or as we have been doing previously through direct access. Not all devices need to access
through HAL but where possible it improves the portability of the code developed.
Figure 1. The layers of HAL base system
For some devices Altera’s Nios II IDE automatically provides the device drivers and HAL API functionality that
allow the devices to be accessed via the C Standard Library interfaces. Last week we saw how to disable these
drivers and interfaces provided by Altera for the JTAG UART, and Timer devices. However the interrupt
handling routines that we utilized were part of the HAL functionality provided by Altera. This week we will
further explore accessing HAL API calls directly and through C Standard Library function calls.
So, again for review last week we saw the usage of the HAL API calls for interrupts.
alt_irq_enable();
alt_irq_disable();
alt_irq_register();
Page 1 of 8
Microprocessors Lab
Nios II HAL API
ECE 332L
Spring 2008
Lab 7
Part 2. Timer utilization
For this part we will utilize an abstraction of the timer device. This abstraction is in the form of an alarm or call
back on a periodic basis. Code 1 demonstrates the operation of this device.
Note: timer_0 is the default system clock. This setting can be changed in your project System Library Property.
Select System Library on the left, there is a System Clock Timer pull-down menu.
Code 1: HAL timer/alarm usage
/* file: alarm.c */
#include <stdio.h>
#include <sys/alt_alarm.h>
unsigned int tps;
alt_u32 alarm_1_callback (void* context)
{
static unsigned int count = 0;
printf("alarm 1: %d\n",++count);
// REMOVE
return tps*2;
}
alt_u32 alarm_2_callback (void* context)
{
static unsigned int count = 0;
printf("alarm 2: %d\n",++count);
// REMOVE
return tps*3;
}
int main(void)
{
alt_alarm alarm_1;
alt_alarm alarm_2;
printf("starting alarms\n");
tps = alt_ticks_per_second();
alt_alarm_start ( &alarm_1, tps, alarm_1_callback, NULL );
alt_alarm_start ( &alarm_2, tps, alarm_2_callback, NULL );
while(1);
}
Alarm callback functions execute in an interrupt context. In other words they are just like code that is written for
interrupt service routines and should limit the usage of input and output. So, the printf statements should be
considered valid only for demonstration purposes and be removed from final code. Notice the value that is
returned from each callback and compare it to the value used for the start. Consider the scope needed for the two
alarms. Do they need to be static? Should they be global? Why does this code work as coded?
Using the alarm facility create code that will turn on LEDR17 for 10 msec out of every 5 seconds. The values
for required on time and period should be variables. Consider making this routine an object that would allow
multiple LEDs to cycle on and off for different amounts of time per period.
Page 2 of 8
Microprocessors Lab
Nios II HAL API
ECE 332L
Spring 2008
Lab 7
Part 3: System Time
Many systems implement the gettimeofday() and settimeofday() functions in addition to several other
structures and functions to deal with time. Code 2 illustrates the usage of these two functions. Again, note the
improper usage of I/O in the example code.
Code 2: HAL system time usage
/* file: time.c */
#include <stdio.h>
#include <sys/alt_alarm.h>
#include <sys/time.h>
unsigned int tps;
alt_u32 alarm_callback (void* context)
{
struct timeval now;
int rc;
rc = gettimeofday (&now, NULL);
printf("Seconds: %u\n", (unsigned int)now.tv_sec);
// REMOVE
return tps;
}
int main(void)
{
static alt_alarm alarm;
struct timeval now;
int rc;
tps = alt_ticks_per_second ();
now.tv_sec = (4*86400)+(23*3600)+(58*60)+50;
now.tv_usec = 0;
// 4:23:58:50
rc = settimeofday (&now, NULL);
alt_alarm_start ( &alarm, tps, alarm_callback, NULL );
while(1);
}
Review the Standard C Library documentation to find the names of at least two functions and two structures
dealing with time.
Now add a routine to your program in Part 2 that displays the HHMMSSXX on the seven-segment display device,
where HH is Hours, MM is minutes, SS is seconds, and XX is hundreds of seconds.
Page 3 of 8
ECE 332L
Spring 2008
Microprocessors Lab
Nios II HAL API
Lab 7
Part 4: File Descriptor, File Pointer, UART and Serial Terminal
For low-level I/O on the Altera system, open(), read(), write(), and close() functions are used (there
are more but these are the more important ones). These functions are implemented by Altera as a part of the HAL
library. The functions originated from the UNIX operating system and you can find information about them in the
C Programming Language book (see last page for reference list). These functions are characterized by the usage
of an integer file descriptor fd. In general, a program associates a file descriptor to a device’s name, and then
writes and reads characters to or from the file using the ANSI C file operations. fd is associated with HAL
open(), read(), write(), and close() functions. In the HAL (file descriptor) layer, the open function
call returns a file description (which is an integer).
On top of the HAL layer (open(), read(), write(), and close() functions), there is another layer of
abstraction (see following figure), this is the streams layer. In the streams layer, the fopen function call returns
a file pointer.
Streams introduce the concept of standard input (stdin), standard output (stdout), and standard error
(stderr), allowing programs to work with these devices without first opening them. Functions like scanf()
and printf() implicitly work with stdin and stdout. The streams functions are defined in the stdio.h
header. (Nios II Software Developer’s Handbook)
streams (using file pointer)
fopen(), fread(), fwrite(), fclose(),
fprintf(), etc.
HAL (using file descriptor)
open(), read(), write(), close(), etc.
Example:
FILE *fp;
fp=fopen(…);
fread(…,fp);
Example:
int fd;
fd = fopen(…);
read(fd,…);
Figure 2: HAL System I/O layer with streams layer above
In short, streams are a collection of programs that sit on top of the HAL library and utilize the open(), read(),
write(), and close() functions. Streams are a higher level of I/O and provide what is sometimes called text
mode since they perform formatting of data. This is fine for interactions with terminal devices (high-level) but is
not suitable for communications between low-level devices. Communication between devices should be done in
what is called raw mode (binary mode). Care should be taken when choosing options for these function calls.
Examples of the usage both the HAL and streams I/O functionality are provided as a starting point for further
exploration.
Up to this point our programs have been using file pointers stdin (you may not realize this, but it is there! stdin
is where you give inputs to your program) and stdout (where messages/results being displayed/output) that are
associated with the JTAG UART device. Through system library property configuration settings for the system
library project in the NIOS II IDE the stdin and stdout can be associated with other devices. Two such
devices are the standard UART and the LCD. The devices can also be accessed by opening them directly (open
or fopen) and then utilizing the appropriate functions to achieve the desired results.
Page 4 of 8
Microprocessors Lab
Nios II HAL API
ECE 332L
Spring 2008
Lab 7
To work with the standard UART you need to utilize a properly configured terminal program on another system.
For the Windows system this could be Hyperterminal (Programs→Accessories→Communications→
Hyperterminal). The UART for this lab is provided with the following parameters (you can find these parameters
in system.h too!):
Baudrate:
115200
Data bits: 8
Parity: None
Stop bits: 1
Flow control:
None
Code 3 show a usage of stream. The fopen function calls pass a file pointer for further stream manipulation.
Code 3: stream usage
/* file: UART_fp.c */
#include <stdio.h>
#include <string.h>
// FILE
// strlen
int main()
{
FILE* fp;
char buff[10];
char msg[] = "\n\rEnter keystrokes here";
printf("\n\rStarting UART_fp.c v2\n\r");
fp = fopen("/dev/uart", "r+");
fwrite(msg, 1, strlen(msg), fp);
while (fread(buff, 1, 1, fp))
{
if (buff[0] == 0x1b) break;
printf("[%02x]-", buff[0]);
}
fprintf(fp, "\n\rall done");
fclose(fp);
printf("\nall done\n");
return 0;
}
Page 5 of 8
Microprocessors Lab
Nios II HAL API
ECE 332L
Spring 2008
Lab 7
Code 4 is another example of opening a device for manipulation. In this case, the device is open with
nonblocking option. Do you know what the difference blocking and nonblocking calls?
Code 4: Nonblocking using HAL – file descriptor
/* file: UART_fd.c */
#include
#include
#include
#include
#include
<stdio.h>
<unistd.h>
<fcntl.h>
<string.h>
<ctype.h>
//
//
//
//
//
printf
read, write, close
open, O_RDWR | O_NONBLOCK
strcpy
isprint
int main ( void )
{
char buff[80];
int fd;
int count = 0;
printf("\n\rStarting UART_fd.c\n\r");
fd = open ("/dev/uart", O_RDWR | O_NONBLOCK);
printf("fd=%08x\n", fd);
strcpy(buff, "\n\rhello UART. talk to me.\n\r");
write(fd, buff, strlen(buff));
while (1)
{
int nbr;
char ch;
if ( (nbr = read(fd, buff, 1)) > 0)
{
ch = buff[0];
printf("%c[%02x]", isprint(buff[0])?buff[0]:'_', buff[0]);
write(fd, buff, nbr);
if (ch == 0x1b) break;
}
count++; if (count > 100000) { count=0; putchar('.');}
}
strcpy(buff, "\n\rgood bye\n\r");
write(fd, buff, strlen(buff));
close(fd);
printf("\nall done\n");
return 0;
}
Page 6 of 8
Microprocessors Lab
Nios II HAL API
ECE 332L
Spring 2008
Lab 7
Part 5: LCD via Standard Library routines
Figure 4 demonstrates access to the LCD device via standard C library routines. Documentation for the escape
sequences is documented in your manuals [which manual???].
Code 5: Access LCD via standard C library routines
/* file: LCD.c */
#include <stdio.h>
#include <unistd.h>
// FILE, fprintf, fputs, fclose
// for usleep
#define ENTER_TO_CONTINUE() printf("Press Enter to
continue\n");getchar();getchar()
#define
#define
#define
#define
LCD_clear()
LCD_clearEOL()
LCD_top()
LCD_setPOS(row,col)
fputs("\x1b[2J", fp)
fputs("\x1b[K", fp)
fputs("\x1b[1;1H", fp)
fprintf(fp, "\x1b[%d;%dH", row, col)
int main (void)
{
int i;
FILE* fp;
printf("\n\rStarting LCD.c v2\n\r");
fp = fopen ("/dev/lcd", "w");
if (fp == NULL) {
fprintf(stderr, "open failed\n"); return 0;
}
fprintf(fp, "Starting Tests\nThis is line two");
ENTER_TO_CONTINUE();
LCD_clear();
fprintf(fp, "0123456789abcdef\nxxxxxxxxxxxxxxxx");
ENTER_TO_CONTINUE();
LCD_setPOS(2,3); fputs("+", fp); usleep(2000000);
LCD_setPOS(1,5); fputs("+", fp);
ENTER_TO_CONTINUE();
LCD_clear();
fprintf(fp, "Test Message x"); usleep(500000);
for (i=0; i<10; i++) { fprintf(fp, "\b%d", i); usleep(500000); }
fprintf(fp, "\nAll done\n"); printf("All done\n");
fclose (fp);
return 0;
}
Add a routine to the code developed in Parts 2 and 3 that will periodically update the LCD display with text
chosen from a list of at least 6 messages. Each message should stay on the display for at least 5 seconds.
Page 7 of 8
ECE 332L
Spring 2008
Microprocessors Lab
Nios II HAL API
Lab 7
References/Reading List:
Nios II Software Developer’s Handbook
Chapter 4. Overview of the Hardware Abstraction Layer
Chapter 5. Developing Programs using the HAL
• Using File Subsystems
• Using Timer Devices
Chapter 11: HAL API Reference
• alt_alarm_start ()
• alt_alarm_stop ()
• alt_ticks_per_second ()
• close ()
• fstat ()
• lseek ()
• open ()
• write ()
• gettimeofday ()
• settimeofday ()
The C Programming Language
Sections 8.1 (File Descriptors) and 8.2 (Low Level I/O – Read and Write)
Appendix B.1: Input and Output: <stdio.h>
Appendix B.10: Date and Time Functions: <time.h>
GCC Compiler – Newlib ANSI C Standard Library Documentation
Programs → Altera → Nios II EDS 7.1 → Nios II 7.1 Documentation, Click on “Literature on the left”.
Scroll down to Software Development, you should see “Newlib ANSI C standard library documentation”.
Quartus II Version 7.1 Handbook Volume 5: Embedded Peripherals
Chapter 10. Optrex 16207 LCD Controller Core
• Software Programming Model
• HAL System Library Support
Page 8 of 8
© Copyright 2026 Paperzz