/************************************************************************* * Copyright © 2004 Altera Corporation, San Jose, California, USA. * * All rights reserved. All use of this software and documentation is * * subject to the License Agreement located at the end of this file below.* *************************************************************************/ /****************************************************************************** * * Description * ************* * A simple program which, using an 8 bit variable, counts from 0 to ff, * repeatedly. Output of this variable is displayed on the LEDs, the Seven * Segment Display, and the LCD. The four "buttons" (SW0-SW3) are used * to control output to these devices in the following manner: * Button1 (SW0) => LED is "counting" * Button2 (SW1) => Seven Segment is "counting" * Button3 (SW2) => LCD is "counting" * Button4 (SW3) => All of the peripherals are "counting". * * Upon completion of "counting", there is a short waiting period during * which button/switch presses will be identified on STDOUT. * NOTE: These buttons have not been de-bounced, so one button press may * cause multiple notifications to STDOUT. * * Requirements * ************** * To be useful, this program requires the following devices to be configured: * an LED PIO named 'led_pio', * a Seven Segment Display PIO named 'seven_seg_pio', * an LCD Display named 'lcd_display', * a Button PIO named 'button_pio', * a UART (JTAG or standard serial) * * * Peripherals Exercised by SW * ***************************** * LEDs * Seven Segment Display * LCD * Buttons (SW0-SW3) * UART (JTAG or serial) * Software Files * **************** * count_binary.c ==> This file. * main() is contained here, as is the lion's share of the * functionality. * count_binary.h ==> Contains some very simple VT100 ESC sequence defines * for formatting text to the LCD Display. * * * Useful Functions * ***************** * count_binary.c (this file) has the following useful functions. * static void sevenseg_set_hex( int hex ) * - Defines a hexadecimal display map for the seven segment display. * static void handle_button_interrupts( void* context, alt_u32 id) * static void init_button_pio() * - These are useful functions because they demonstrate how to write * and register an interrupt handler with the system library. * * count_binary.h * The file defines some useful VT100 escape sequences for use on the LCD * Display. */ #include "count_binary.h" // A "loop counter" variable. static alt_u8 count; // A variable to hold the value of the button pio edge capture register. static alt_u32 edge_capture; /* Button pio functions */ /* Some simple functions to: 1. Define an interrupt handler function. 2. Register this handler in the system. */ /******************************************************************* * static void handle_button_interrupts( void* context, alt_u32 id)* * * * Handle interrupts from the buttons. * * This interrupt event is triggered by a button/switch press. * * This handler sets *context to the value read from the button * * edge capture register. The button edge capture register * * is then cleared and normal program execution resumes. * * The value stored in *context is used to control program flow * * in the rest of this program's routines. * ******************************************************************/ static void handle_button_interrupts(void* context, alt_u32 id) { int* edge_capture_ptr = (int*) context; // Store the value in the Button's edge capture register in *context. *edge_capture_ptr = IORD_ALTERA_AVALON_PIO_EDGE_CAP(BUTTON_PIO_BASE); // Reset the Button's edge capture register. IOWR_ALTERA_AVALON_PIO_EDGE_CAP(BUTTON_PIO_BASE, 0); } /* Initialize the button_pio. */ static void init_button_pio() { // Enable all 4 button interrupts. IOWR_ALTERA_AVALON_PIO_IRQ_MASK(BUTTON_PIO_BASE, 0xf); // Reset the edge capture register. IOWR_ALTERA_AVALON_PIO_EDGE_CAP(BUTTON_PIO_BASE, 0x0); // Register the interrupt handler. alt_irq_register( BUTTON_PIO_IRQ, &edge_capture, handle_button_interrupts ); } /* Seven Segment Display PIO Functions * sevenseg_set_hex() -- implements a hex digit map. */ static void sevenseg_set_hex(int hex) { static alt_u8 segments[16] = { 0x81, 0xCF, 0x92, 0x86, 0xCC, 0xA4, 0xA0, 0x8F, 0x80, 0x84, // 0-9 0x88, 0xE0, 0xF2, 0xC2, 0xB0, 0xB8 }; // a-f unsigned int data = segments[hex & 15] | (segments[(hex >> 4) & 15] << 8); IOWR_ALTERA_AVALON_PIO_DATA(SEVEN_SEG_PIO_BASE, data); } /* Functions used in main loop * lcd_init() -- Writes a simple message to the top line of the LCD. * initial_message() -- Writes a message to stdout (usually JTAG_UART). * count_() -- Implements the counting on the respective device. * handle_button_press() -- Determines what to do when one of the buttons is pressed. */ static void lcd_init(FILE * lcd) { /* If the LCD Display exists, write a simple message on the first line. */ #ifdef LCD_DISPLAY_NAME fprintf(lcd, "%c%s Counting will be displayed below...", ESC, ESC_TOP_LEFT); #endif } static void initial_message() { printf("\n***************************\n"); printf("*Hello from Nios II! *\n"); printf("*Counting from 1 to ff *\n"); printf("***************************\n"); } /******************************************************** * The following functions write the value of the global* * variable 'count' to 3 peripherals, if they exist on * * the system. Specifically: * * The LEDs will illuminate, the Seven Segment Display * * will count from 00-ff, and the LCD will display the * * hex value as the program loops. * * *****************************************************/ /* static void count_led() * * Illuminate LEDs with the value of 'count', if they * exist on the system */ static void count_led() { #ifdef LED_PIO_BASE IOWR_ALTERA_AVALON_PIO_DATA(LED_PIO_BASE, count); #endif } /* static void count_sevenseg() * * Display value of 'count' on the Seven Segment Display */ static void count_sevenseg() { #ifdef SEVEN_SEG_PIO_BASE sevenseg_set_hex(count); #endif } /* static void count_lcd(FILE * lcd) * * Display the value of 'count' on the LCD Display, if it * exists in the system. * * NOTE: A HAL character device driver is used, so the LCD * is treated as an I/O device (i.e.: using fprintf). You * can read more about HAL drivers . */ static void count_lcd(FILE * lcd) { #ifdef LCD_DISPLAY_NAME fprintf(lcd, "%c%s 0x%x\n", ESC, ESC_COL2_INDENT5, count); #endif } /* count_all merely combines all three peripherals counting */ static void count_all(FILE * lcd) { count_led(); count_sevenseg(); count_lcd(lcd); } static void handle_button_press(alt_u8 type, FILE * lcd) { //Button press actions while counting. if (type == 'c') { switch (edge_capture) { // Button 1: Output counting to LED only. case 0x1: count_led(); break; // Button 2: Output counting to SEVEN SEG only. case 0x2: count_sevenseg(); break; // Button 3: Output counting to D only. case 0x4: count_lcd(lcd); break; // Button 4: Output counting to LED, SEVEN_SEG, and D. case 0x8: count_all(lcd); break; // If value ends up being something different (shouldn't) do same as 8. default: count_all(lcd); break; } } /* If 'type' is anything else, assume we're "waiting"...*/ else { switch (edge_capture) { case 0x1: printf( "Button 1\n"); edge_capture = 0; break; case 0x2: printf( "Button 2\n"); edge_capture = 0; break; case 0x4: printf( "Button 3\n"); edge_capture = 0; break; case 0x8: printf( "Button 4\n"); edge_capture = 0; break; printf( "Button press UNKNOWN!!\n"); } } } /******************************************************************************* * int main() * * * * Implements a continuous loop counting from 00 to FF. 'count' is the loop * * counter. * * The value of 'count' will be display on one or more of the following 3 * * devices, based upon hardware availability: LEDs, Seven Segment Display, * * and the LCD Display. * * * * During the counting loop, a switch press of SW0-SW3 will affect the * * behavior of the counting in the following way: * * * * SW0 - Only the LED will be "counting". * * SW1 - Only the Seven Segment Display will be "counting". * * SW2 - Only the LCD Display will be "counting". * * SW3 - All devices "counting". * * * * There is also a 10 second "wait", following the count loop, * * during which button presses are still * * detected. * * * * The result of the button press is displayed on STDOUT. * * * * NOTE: These buttons are not de-bounced, so you may get multiple * * messages for what you thought was a single button press! * * * * NOTE: References to Buttons 1-4 correspond to SW0-SW3 on the Development * * Kits. * ******************************************************************************/ int main(void) { // Initialize the global count variable. count = 0; // Initialize the button pio. #ifdef BUTTON_PIO_BASE init_button_pio(); #endif // Open the LCD Display, if it exists, for writing. #ifdef LCD_DISPLAY_NAME FILE * lcd = fopen("/dev/lcd_display", "w"); lcd_init(lcd); #endif // Initial message to output. initial_message(); // Continue 0-ff counting loop. while( 1 ) { usleep(100000); ++count; if (edge_capture != 0) { // Handle button presses while counting... handle_button_press('c',lcd); } // If no button presses, try to output counting to all. else { count_all(lcd); } /* * If done counting, wait about 10 seconds... * detect button presses while waiting. */ if( count == 255 ) { #ifdef LCD_DISPLAY_NAME fprintf(lcd, "%c%s %c%s %c%s Waiting...\n", ESC, ESC_TOP_LEFT, ESC, ESC_CLEAR, ESC, ESC_COL1_INDENT5); #endif printf("\nWaiting..."); edge_capture = 0; // Reset to 0 during wait/pause period. //Clear the 2nd. line of the LCD screen. #ifdef LCD_DISPLAY_NAME fprintf(lcd, "%c%s, %c%s", ESC, ESC_COL2_INDENT5, ESC, ESC_CLEAR); #endif int i; int wait_time =0; for (i = 0; i<100; ++i) { printf("."); #ifdef LCD_DISPLAY_NAME wait_time = i/10; fprintf(lcd, "%c%s %ds\n", ESC, ESC_COL2_INDENT5, wait_time); #endif if (edge_capture != 0) { printf( "\nYou pushed: " ); handle_button_press('w',lcd); } usleep(100000); // Sleep for 0.1s. } /* Output the "loop start" messages before looping, again. */ initial_message(); #ifdef LCD_DISPLAY_NAME lcd_init(lcd); #endif } } fclose(lcd); return(0); } /****************************************************************************** * * * License Agreement * * * * Copyright (c) 2004 Altera Corporation, San Jose, California, USA. * * All rights reserved. * * * * Permission is hereby granted, free of charge, to any person obtaining a * * copy of this software and associated documentation files (the "Software"), * * to deal in the Software without restriction, including without limitation * * the rights to use, copy, modify, merge, publish, distribute, sublicense, * * and/or sell copies of the Software, and to permit persons to whom the * * Software is furnished to do so, subject to the following conditions: * * * * The above copyright notice and this permission notice shall be included in * * all copies or substantial portions of the Software. * * * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * * DEALINGS IN THE SOFTWARE. * * * * This agreement shall be governed in all respects by the laws of the State * * of California and by the laws of the United States of America. * * Altera does not recommend, suggest or require that this reference design * * file be used in conjunction or combination with any other product. * ******************************************************************************/