/*** vfd.c ***/ /* code to drive a Noritake GU128x64-311 VFD module and to determine the tach reading from a '92 Toyota Corolla engine */ /* copyright (c) Andrew Huang 1998 */ #include "cmon.h" #include "vfd.h" #define IS == #define AINT != #define AND && #define OR || void vfd_draw_num( unsigned char bitmap[8][128], int x, int y, int data, int mode ); void vfd_copychar( unsigned char bitmap[8][128], int x, int y, int charcode, int mode ); static unsigned char vfd_wp = 1; static unsigned char vfd_dp = 0; void tach_init_itu() { /* tach_init_itu */ /* locals */ /* body */ /* using TIOCA3/B3, TCLKA */ TIOR3 = 0x5D; /* 0101 1101 */ /* grb, gra capture falling edge */ TCR3 = 0x2C; /* 0010 1100 */ /* ext clock A, falling edge, clear on capt */ TFCR = 0x4F; /* 0100 1111 */ /* normal mode with buffering on GRA/B */ TMDR = 0x00; /* 0000 0000 */ TSNC = 0x60; /* timers operate asynchronously */ TSTR = 0x68; /* start unit 3 counting */ } /* tach_init_itu */ void vfd_draw_num( unsigned char bitmap[8][128], int x, int y, int data, int mode ) { /* vfd_draw_num */ /* locals */ unsigned char bcd_num[30]; int i; /* body */ /* handle minus sign */ if( data < 0 ) { vfd_copychar( bitmap, x, y, V_HYPHEN, mode ); x += 8; data = -data; } /* if */ i = 0; while( data ) { bcd_num[i] = data % 10; data /= 10; i++; } /* while */ i = i - 1; for( ; i >= 0; i-- ) { vfd_copychar( bitmap, x, y, bcd_num[i] + V_0, mode ); x += 8; } /* for */ } /* vfd_draw_num */ void vfd_draw_rect( unsigned char start[8][128], int x1, int y1, int x2, int y2 ) { /* vfd_draw_rect */ /* locals */ int i; int temp; int yindex, ybitplace, ybit; /* body */ if( x1 > x2 ) { temp = x1; x1 = x2; x2 = temp; } /* if */ if( y1 > y2 ) { temp = y1; y1 = y2; y2 = temp; } /* if */ x1 &= 0x7F; x2 &= 0x7F; y1 &= 0x3F; y2 &= 0x3F; /* x-dir bottom (along y1) */ yindex = y1 >> 3; ybitplace = y1 & 0x7; ybitplace = ~ybitplace & 0x7; ybit = 0x1 << ybitplace; for( i = x1; i < x2; i++ ) { start[yindex][i] |= ybit; } /* for */ /* x-dir top (along y2) */ yindex = y2 >> 3; ybitplace = y2 & 0x7; ybitplace = ~ybitplace & 0x7; ybit = 0x1 << ybitplace; for( i = x1; i < x2; i++ ) { start[yindex][i] |= ybit; } /* for */ /* y-dir parallels */ for( i = y1; i <= y2; i++ ) { start[ (i >> 3) ][ x1 ] |= (0x1 << (~(i & 0x7) & 0x7)); start[ (i >> 3) ][ x2 ] |= (0x1 << (~(i & 0x7) & 0x7)); } /* for */ } /* vfd_draw_rect */ void vfd_draw_filled_rect( unsigned char start[8][128], int x1, int y1, int x2, int y2 ) { /* vfd_draw_filled_rect */ /* locals */ int i, j; int temp; int yindex, ybitplace, ybit; /* body */ if( x1 > x2 ) { temp = x1; x1 = x2; x2 = temp; } /* if */ if( y1 > y2 ) { temp = y1; y1 = y2; y2 = temp; } /* if */ x1 &= 0x7F; x2 &= 0x7F; y1 &= 0x3F; y2 &= 0x3F; /* y-dir parallels */ for( i = y1; i < y2; i++ ) { yindex = i >> 3; ybit = (0x1 << (~(i & 0x7) & 0x7)); for( j = x1; j < x2; j++ ) { start[ yindex ][ j ] |= ybit; } /* for */ } /* for */ } /* vfd_draw_filled_rect */ #define TCLKA_FREQ (19531) /* in hertz */ #define RPM_MAX 6000 #define NUMAVE 20 void vfd_test_bars() { /* vfd_test_bars */ /* locals */ int x1, x2, y1, y2, xtext, ytext, rpmbar; int i, j, x; unsigned char bitmap[8][128]; unsigned short pbd; unsigned short ticks; unsigned int rpm; int samples, rpmsample; /* body */ /* set intensity to 100% */ pbd = 0xFFF3; PBDR = pbd; pbd = 0xFFF2; PBDR = pbd; pbd = 0xFFF0; PBDR = pbd; pbd = 0xFFF0; PBDR = pbd; pbd = 0xFFF2; PBDR = pbd; pbd = 0xFFF3; PBDR = pbd; pbd = 0x3FF3; PBDR = pbd; x1 = 10; x2 = 118; y1 = 20; y2 = 36; xtext = 16; ytext = 24; for( i = x1; i < x2; i += 10 ) { for( x = 0; x < 8; x++ ) { for( j = 0; j < 128; j++ ) { bitmap[x][j] = 0; } /* for */ } /* for */ vfd_draw_rect( bitmap, x1, y1, x2, y2 ); vfd_draw_filled_rect( bitmap, x1, y1, i, y2 ); vfd_draw_num( bitmap, xtext, ytext, (i-x1) * (RPM_MAX / (x2-x1)), BLT_XOR ); vfd_display_bitmap( bitmap ); } for( i = x2; i > x1; i -= 10 ) { for( x = 0; x < 8; x++ ) { for( j = 0; j < 128; j++ ) { bitmap[x][j] = 0; } /* for */ } /* for */ vfd_draw_rect( bitmap, x1, y1, x2, y2 ); vfd_draw_filled_rect( bitmap, x1, y1, i, y2 ); vfd_draw_num( bitmap, xtext, ytext, (i-x1) * (RPM_MAX / (x2-x1)), BLT_XOR ); vfd_display_bitmap( bitmap ); } while(1) { for( x = 0; x < 8; x++ ) { for( j = 0; j < 128; j++ ) { bitmap[x][j] = 0; } /* for */ } /* for */ /* calculate rpm */ ticks = BRA3; rpm = (15 * TCLKA_FREQ) / ticks; rpm = rpm * 2; /* double RPMs because both edges are ignition */ rpmsample += rpm; if( rpm < 6 ) rpm = 0; /* handle 0 case */ /* rpm actually only goes down to like 4 */ /* figure out graphic position */ rpmbar = ((rpm * (x2 - x1)) / RPM_MAX) + x1; vfd_draw_rect( bitmap, x1, y1, x2, y2 ); vfd_draw_filled_rect( bitmap, x1, y1, rpmbar, y2 ); vfd_draw_num( bitmap, xtext, ytext, rpm, BLT_XOR ); vfd_display_bitmap( bitmap ); } /* while */ } /* vfd_test_bars */ void vfd_write_byte( int x, int y, unsigned char data ) { /* locals */ register unsigned short pad, pbd, address; /* body */ pad = 0x0000; pbd = 0x0003; /* BRAD | WRITE_N */ address = ((x << 3) & 0x3F8) | (y & 0x7); pad |= (address << (A1_BIT - 1)); if( address & 0x1 ) { pad |= A0; } /* if */ if( address & 0x40 ) { /* 0100 0000 */ pad |= A6; } /* if */ pad |= CLEAR_N; PADR = pad; pbd |= ((data & 0xC0) << (D6_BIT - 6)); pbd |= ((data & 0x3F) << D0_BIT); if( vfd_dp IS 1 ) { pbd |= DP0; } if( vfd_wp IS 1 ) { pbd |= WP0; } PBDR = pbd; pbd &= ~WRITE_N; /* flip write_n low */ PBDR = pbd; pbd |= WRITE_N; /* flip write_n high again */ PBDR = pbd; } /* vfd_write_byte */ void vfd_display_bitmap( unsigned char start[8][128] ) { /* vfd_display_bitmap */ /* locals */ int i, j; unsigned short pbd; /* body */ for( i = 127; i >= 0; i-- ) { for( j = 0; j < 8; j++ ) { vfd_write_byte( i, j, (unsigned char) start[j][i] ); } /* for */ } /* for */ if( vfd_wp IS 0 ) { vfd_wp = 1; vfd_dp = 0; } else { vfd_wp = 0; vfd_dp = 1; } vfd_write_byte( i, j, (unsigned char) start[j][i] ); } /* vfd_display_bitmap */ void vfd_clear() { /* vfd_clear */ /* locals */ unsigned short pbd; unsigned short pad; /* body */ vfd_init(); tach_init_itu(); pad = 0x0001; pbd = 0x0003; /* blank the first page */ pad = 0x0000; PBDR = pbd; PADR = pad; pad = 0x0001; PADR = pad; /* blank the second page */ pbd = 0xC003; pad = 0x0000; PBDR = pbd; PADR = pad; pad = 0x0001; PADR = pad; /* set intensity to 100% */ pbd = 0x3FF3; PBDR = pbd; pbd = 0x3FF2; PBDR = pbd; pbd = 0x3FF0; PBDR = pbd; pbd = 0x3FF0; PBDR = pbd; pbd = 0x3FF2; PBDR = pbd; pbd = 0x3FF3; PBDR = pbd; } /* vfd_clear */ void vfd_init() { /* vfd_init */ /* locals */ /* body */ /* 0000 0010 0000 0000 */ PACR1 = 0x0200; /* port 8 high bits all I/O */ /* 1011 1111 1000 0000 */ PACR2 = 0xBF80; /* output if 1, input if 0 */ /* 1111 1111 1000 0111 */ PAIOR = 0xFF87; /* 0000 0000 1010 0000 */ PBCR1 = 0x00A0; /* 0000 0000 1010 0000 */ PBCR2 = 0x00A0; /* 1111 0011 1111 0011 */ PBIOR = 0xF3F3; /* 0000 0000 0000 0011 */ PADR = 0x0001; PBDR = 0x0003; } /* vfd_init */ void vfd_copychar( unsigned char bitmap[8][128], int x, int y, int charcode, int mode ) { /* vfd_copychar */ /* locals */ int i; /* the VFD charmap itself (8x8 font) */ unsigned char chargen[ 128 ][ 8 ] = { { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, /* 000 0111 */ { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0x08, 0x08, 0x08, 0x08, 0x08 }, /* '-' */ { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, /* 000 1111 */ { 0, 0, 0, 0x3E, 0x51, 0x49, 0x45, 0x3E }, /* '0' */ { 0, 0, 0, 0, 0x42, 0x7F, 0x40, 0 }, /* '1' */ { 0, 0, 0, 0x42, 0x61, 0x51, 0x49, 0x46 }, /* '2' */ { 0, 0, 0, 0x21, 0x41, 0x45, 0x4B, 0x31 }, /* '3' */ { 0, 0, 0, 0x18, 0x14, 0x12, 0x7F, 0x10 }, /* '4' */ { 0, 0, 0, 0x27, 0x45, 0x45, 0x45, 0x39 }, /* '5' */ { 0, 0, 0, 0x3C, 0x4A, 0x49, 0x49, 0x30 }, /* '6' */ { 0, 0, 0, 0x01, 0x01, 0x79, 0x05, 0x03 }, /* '7' */ /* 001 0111 */ { 0, 0, 0, 0x36, 0x49, 0x49, 0x49, 0x36 }, /* '8' */ { 0, 0, 0, 0x06, 0x49, 0x49, 0x29, 0x1E }, /* '9' */ { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, /* 001 1111 */ { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, /* 010 0111 */ { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, /* 010 1111 */ { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, /* 011 0111 */ { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, /* 011 1111 */ { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, /* 100 0111 */ { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, /* 100 1111 */ { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, /* 101 0111 */ { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, /* 101 1111 */ { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, /* 110 0111 */ { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, /* 110 1111 */ { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, /* 111 0111 */ { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, /* 111 1111 */ }; /* body */ /* catch overflows */ if( (x > 127) OR (x < 0) ) return; if( (y > (63 - 8)) OR (y < 0) ) return; for( i = 0; i < 8; i++ ) { if( ( x + i ) > 127 ) { continue; } /* if */ switch( mode ) { case BLT_AND: bitmap[ y >> 3 ][ x + i ] &= chargen[ charcode ][ i ]; break; case BLT_OR: bitmap[ y >> 3 ][ x + i ] |= chargen[ charcode ][ i ]; break; case BLT_XOR: bitmap[ y >> 3 ][ x + i ] ^= chargen[ charcode ][ i ]; break; case BLT_EQUALS: default: bitmap[ y >> 3 ][ x + i ] = chargen[ charcode ][ i ]; break; } } } /* vfd_copychar */