




Study with the several resources on Docsity
Earn points by helping other students or get them with a premium plan
Prepare for your exams
Study with the several resources on Docsity
Earn points to download
Earn points by helping other students or get them with a premium plan
A lab guide for ece 332l - microprocessors, focusing on lab 7 in spring 2008. Students will learn about the nios ii hal api, including its usage for interrupts, timers, system time, file descriptor, uart, and lcd via standard library routines. The lab covers both hal api calls and c standard library function calls.
Typology: Lab Reports
1 / 8
This page cannot be seen from the preview
Don't miss anything!





lightweight runtime environment that provides a simple device driver interface for programs to communicate with the underlying hardware.
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();
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 tps2; } 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.
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)
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.
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,…);
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> // FILE #include <string.h> // 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; }
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> // FILE, fprintf, fputs, fclose #include <unistd.h> // for usleep #define ENTER_TO_CONTINUE() printf("Press Enter to continue\n");getchar();getchar() #define LCD_clear() fputs("\x1b[2J", fp) #define LCD_clearEOL() fputs("\x1b[K", fp) #define LCD_top() fputs("\x1b[1;1H", fp) #define LCD_setPOS(row,col) 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.
Nios II Software Developer’s Handbook
Chapter 4. Overview of the Hardware Abstraction Layer
Chapter 5. Developing Programs using the HAL
Chapter 11: HAL API Reference
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