TAMS / Java / Hades / applets: contents | previous | next | ||||
Hades Applets contents visual index introduction std_logic_1164 gatelevel circuits delay models flipflops adders and arithm... counters LFSR and selftest memories programmable logic state-machine editor misc. demos I/O and displays DCF-77 clock relays (switch-le... CMOS circuits (sw... RTLIB logic RTLIB registers Prima processor D*CORE MicroJava Pic16 cosimulation Mips R3000 cosimu... TinyMips int... TinyMips Sieve TinyMips stack TinyMips mul... TinyMips loa... TinyMips mul... TinyMips wit... TinyMips UAR... TinyMips UAR... TinyMips int... TinyMips int... Mips fast Sieve TinyMips wit... Mips - game ... Mips prime n... Intel MCS4 (i4004) image processing ... [Sch04] Codeumsetzer [Sch04] Addierer [Sch04] Flipflops [Sch04] Schaltwerke [Sch04] RALU, Min... [Fer05] State-Mac... [Fer05] PIC16F84/... [Fer05] Miscellan... [Fer05] Femtojava FreeTTS | TinyMips - multiplexed seven-segment display
Circuit Description
This applet demonstrates a multiplexed seven-segment display
controlled via the PIO8255 parallel input/output adapter chip.
Please check the introductory applet for the introduction and description of the TinyMips processor. The hardware structure consists of the processor, some glue logic, a single RAM component that stores both the program and the working set data, and the PIO8255 interface chip. See the PIO 8255 overview page for details about the parallel input/output adapter.
The multiplexed displayThis applet demonstrates the typical way to connect peripheral devices to a microprocessor system via a configurable parallel input/output adapter. While the applet uses a simulation model based on the Intel 8255 chip, similar devices from other vendors could have been used as well. Also, some commercially available microcontrollers already include several programmable input/output lines on chip, but our TinyMips processor does not.The 8255 PIO is based on a bidirectional 8-bit databus. Four memory addresses are reserved in order to access the four internal on-chip registers. To avoid extra complexity with byte-ordering issues during load-byte and store-byte operations, we connect the PIO with the full 32-bit width to the MIPS data-bus. Naturally, only the lower eight bits are actually used during actual transfers to and from the PIO. This also means that we can use word addressing, and the address inputs A1 and A0 of the PIO are therefore connected to bits A3 and A2 of the MIPS address bus. The address-decoder is set up to activate the PIO for the virtual address range a0080000-a00800fc (hex). This is a typical address range for peripheral devices, because it lies in the "unmapped uncached" kernel segment (kuseg1) of the R3000-series processors. The static MMU of a R3000 processor would translate the virtual addresses in the above range to physical addresses in the range 00080000-000800c. However, we have disabled the MMU of the TinyMips processor in this applet, and the virtual addresses are directly used as physical addresses. Therefore, the control and data registers of the 8255 PIO-chip are accessed via the following addresses:
MIPS virtual address physical address PIO register (MMU disabled) ----------------------+-------------------+------------- a008.0000 a008.0000 port A a008.0004 a008.0004 port B a008.0008 a008.0008 port C a008.000c a008.000c control The program (see below for the full sourcecode) defines a few simple utility functions to write data into the control and data registers, and to read the current values of input ports. At program start, we once call pioSetMode() to configure the PIO with ports A and B selected as outputs and port C as input. As you can see in the schematics, port A then drives the segment lines of the seven-segment displays, while bits PB4..PB0 are connected to inverting buffers (amplifiers) to drive the common cathodes of the displays. The main part of the program then consists of an endless loop that increments the count variable, and then calls the displayVariable method to display the counter value. Each iteration of the display loop first disables all digit drivers. It then repeatly calculates the segment-data for to the 4-bit digit value to be displayed, loads this data into port A to drive the segment lines, and then activates one of the digit drivers via port B. Usage Wait until the applet is loaded, then watch the program. You can now open the memory-editor (via popup > edit) The memory editor highlights the last read operation in green color, and the last write operation in cyan color, which allows you to easily watch the program execution. If you want to change the simulation speed, just select 'edit' on the clock-generator component, then edit the value of the clock-generator 'period' property, and select 'apply' (and 'ok' to close the clock-generator config dialog). The default clock rate is slow enough to allow you watching the memory accesses during the main loops of the program. Similarly, open the TinyMips user-interface window (via popup > edit) to watch the current register values. The binary program running on the processor was compiled and linked with the GNU gcc (2.7.2.3) and binutils cross-compiler toolchain on a Linux x86 host, with the final ELF loading and relocation done via the Hades Elf2rom tool. See: The following listing shows the actual C source code of the program:
/* demonstrate a multiplexed display controlled via the PIO8255 */ // base address for the stack. This leaves very little space for // the stack, but means that you can watch program-code, stack, // and heap accesses at the same time in the memory editor. // Remember that byte-address 0x800 is displayed at word-address 0x200 // in the RAM editor. #define STACKBASE 0x00000800 // base address for some debugging output in the RAM. // Note that byte-address 0x880 is displayed at word-address 0x220 // in the RAM editor. #define BASE 0x00000880 // axxx.xxxx is mapped to 0xxx.xxxx by the (static) R-3000 MMU // but remains axxx.xxx in this demo because we disable the MMU. #define PIO_BASE 0xa0080000 #define PIO_REGA (PIO_BASE+0) #define PIO_REGB (PIO_BASE+4) #define PIO_REGC (PIO_BASE+8) #define PIO_XREG (PIO_BASE+12) #define PIO_MODE_CHANGE 0x80 #define PIO_GROUPA_MODE0 0x00 #define PIO_GROUPA_MODE1 0x20 #define PIO_GROUPA_MODE2 0x60 #define PIO_GROUPB_MODE0 0x00 #define PIO_GROUPB_MODE1 0x04 #define PIO_PORTA_INPUT 0x10 #define PIO_PORTA_OUTPUT 0x00 #define PIO_UPPERC_INPUT 0x08 #define PIO_UPPERC_OUTPUT 0x00 #define PIO_PORTB_INPUT 0x02 #define PIO_PORTB_OUTPUT 0x00 #define PIO_LOWERC_INPUT 0x01 #define PIO_LOWERC_OUTPUT 0x00 void pioSetMode( int value ) { int *xreg = (int*) PIO_XREG; int command = PIO_MODE_CHANGE | (value&0x000000ff); *xreg = command; } void pioWritePortA( int value ) { int *reg = (int*) PIO_REGA; int data = value & 0x000000ff; *reg = data; } void pioWritePortB( int value ) { int *reg = (int*) PIO_REGB; int data = value & 0x000000ff; *reg = data; } void pioWritePortC( int value ) { int *reg = (int*) PIO_REGC; int data = value & 0x000000ff; *reg = data; } void pioWriteUpperC( int value ) { int *reg = (int*) PIO_REGC; int data = (*reg & 0x0000000f) | value & 0x000000f0; *reg = data; } void pioWriteLowerC( int value ) { int *reg = (int*) PIO_REGC; int data = (*reg & 0x000000f0) | value & 0x0000000f; *reg = data; } int pioReadPortA() { int *reg = (int*) PIO_REGA; int data = *reg; return data; } int pioReadPortB() { int *reg = (int*) PIO_REGB; int data = *reg; return data; } int pioReadPortC() { int *reg = (int*) PIO_REGC; int data = *reg; return data; } /* +-A-+ F B +-G-+ E C +-D-+ (P) encoding is 0000....00 PGFEDCBA p is not driven by this routine. If necessary, OR the return value with mask 0x80. */ int sevenSegment( int value ) { switch( value ) { case 0: return 0x0000003f; // 00111111 case 1: return 0x00000006; // 00000110 case 2: return 0x0000005b; // 01011011 case 3: return 0x0000004f; // 01001111 case 4: return 0x00000066; // 01100110 case 5: return 0x0000006d; // 01101101 case 6: return 0x0000007d; // 01111101 case 7: return 0x00000007; // 00000111 case 8: return 0x0000007f; // 01111111 case 9: return 0x0000006f; // 01101111 case 0xa: return 0x00000077; // 01110111 case 0xb: return 0x0000007c; // 01111100 case 0xc: return 0x00000039; // 00111001 case 0xd: return 0x0000005e; // 01011110 case 0xe: return 0x00000079; // 01111001 case 0xf: return 0x00000071; // 01110001 default: // three horizontal bars as error indicator return 0x00000049; // 01001001 } } void waitLoop() { int i, limit; int *ptr; ptr = (int*) BASE; limit = 0x0015; for( i=0; i < limit; i++ ) { *ptr = i; } } void displayValue( int value ) { int tmp, mask, hex, segs, i; int ndigits = 5; int *ptr = (int*) BASE; *(ptr-1) = 0xdeadbeef; *(ptr-2) = value; mask = 0xf; for( i=0; i < ndigits; i++ ) { pioWritePortB( 0x00 ); // all digits off hex = value & mask; segs = sevenSegment( hex >> (i << 2) ); pioWritePortA( segs ); pioWritePortB( 1 << i ); // one digit on waitLoop(); mask = mask << 4; } pioWritePortB( 0 ); // disable all digits again } int main( int argc, char** argv ) { int count; pioSetMode( PIO_MODE_CHANGE | PIO_GROUPA_MODE0 | PIO_GROUPB_MODE0 | PIO_PORTA_OUTPUT | PIO_PORTB_OUTPUT | PIO_UPPERC_INPUT | PIO_LOWERC_INPUT ); for( count=0; ; count++ ) { displayValue( count ); } }
| |||
Print version | Run this demo in the Hades editor (via Java WebStart) | ||||
Usage | FAQ | About | License | Feedback | Tutorial (PDF) | Referenzkarte (PDF, in German) | ||||
Impressum | http://tams.informatik.uni-hamburg.de/applets/hades/webdemos/76-mips/16-led/led.html |