// ### BOILERPLATE ### // Orthographic Cube Firmware // Copyright (C) 2006 Peter Todd // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License along // with this program; if not, write to the Free Software Foundation, Inc., // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. // ### BOILERPLATE ### // LED Display stuff // These functions maintain the low-level led display stuff, the bitmap data and // initialization and scan functions. // The size of the display. #define display_xsize 35 #define display_ysize 35 // Initialize the display. void display_init(); // Does whatever is needed to multiplex the display. This is called from the TMR0 init. void display_do_multiplex(); // Clears the display, sets all pixels off. void display_clear(); // Bitmap data for the display. Each pixel is one bit to make things compact. #define display_xmax display_xsize #define display_ymax ((display_ysize / 8) + 1) uint8_t bitmap0[display_xmax][display_ymax]; uint8_t bitmap1[display_xmax][display_ymax]; // The column that is being currently displayed by the multiplex code. uint8_t current_column; // Which of the two buffers is being displayed for writing and displaying. uint8_t current_buffer; // Switch buffers. #define switch_display_buffers() do { \ current_buffer = ~current_buffer; \ } while (0); // Turns pixel x,y on #define display_pset(x,y) \ do { \ if (current_buffer){ \ bitmap1[(x)][(y) / 8] |= (0x01 << ((y) % 8)); \ } else { \ bitmap0[(x)][(y) / 8] |= (0x01 << ((y) % 8)); \ } \ } while (0); // Turns pixel x,y off #define display_pclear(x,y) \ do { \ if (current_buffer){ \ bitmap1[(x)][(y) / 8] |= ~(0x01 << ((y) % 8)); \ } else { \ bitmap0[(x)][(y) / 8] |= ~(0x01 << ((y) % 8)); \ } \ } while (0); // Macros to set the clock and data lines of the MM5451 #define mm_clk_low() PORTCbits.RC0 = 0; #define mm_clk_high() PORTCbits.RC0 = 1; #define mm_data_low() PORTCbits.RC1 = 0; #define mm_data_high() PORTCbits.RC1 = 1; #define mm_out(x) {PORTCbits.RC1 = x; Nop(); Nop(); mm_clk_high(); Nop(); Nop(); Nop(); Nop(); mm_clk_low(); }; void display_clear(){ uint8_t x,y; for (x = 0; x < display_xmax; x++){ for (y = 0; y < display_ymax; y++){ if (current_buffer){ bitmap1[x][y] = 0x00; } else { bitmap0[x][y] = 0x00; } } } } void display_init(){ current_column = display_xsize; current_buffer = 0; // clear the display, both buffers display_clear(); switch_display_buffers(); display_clear(); // Set tris bits to output for all the FET pins. TRISE = TRISD = TRISB = TRISA = TRISF = TRISG = 0; TRISC = 0; // Set the MM5451 to a default state. mm_clk_low(); mm_data_low(); // Turn brightness on PORTCbits.RC2 = 1; } uint8_t mplex_dout; void display_do_multiplex(){ static uint8_t d,x,i,n,y; // Go to the next column. if (!current_column) current_column = display_xmax; current_column--; // Load the row data into the MM5451 chip. // "Wakeup" the MM by sending it some zero'd out data. mm_data_low(); for (i = 0; i < 5; i++){ mm_out(0); } // Send the start bit. mm_out(1); // We are loading display_ysize bits, backed into i bytes. // Macro to send a single bit. This has been verified to give the proper timings with the MM5451 #define mobit(i) \ _asm \ nop \n \ btfss _mplex_dout,i \n \ bcf _PORTC,1 \n \ btfsc _mplex_dout,i \n \ bsf _PORTC,1 \n \ nop \n \ nop \n \ bsf _PORTC,0 \n \ nop \n \ nop \n \ nop \n \ nop \n \ nop \n \ nop \n \ bcf _PORTC,0 \n \ _endasm; for (y = 0; y < display_ymax; y++){ // The second byte, rows 8-15, has a problem, rows 10 and 11 are flipped, so correct that when we send it. if (y == 1){ if (current_buffer){ mplex_dout = bitmap0[current_column][y]; } else { mplex_dout = bitmap1[current_column][y]; } mobit(0); mobit(1); mobit(3); // swapped mobit(2); // swapped mobit(4); mobit(5); mobit(6); mobit(7); } else { // All other bytes are normal. if (current_buffer){ mplex_dout = bitmap0[current_column][y]; } else { mplex_dout = bitmap1[current_column][y]; } mobit(0); mobit(1); mobit(2); mobit(3); mobit(4); mobit(5); mobit(6); mobit(7); } } // Some notes on the hardware... The FETs are connected directly to // various ports on the pics. The order of the pin connections is as // follows: // PORTE - 0-7 // PORTD - 8-15 // PORTB - 16-19 **4 bits** remaining pins unused // PORTA - 20-23 **4 bits** remaining pins unused // PORTF - 24-31 // PORTG - 32-34 **3 bits** remaining pins unused // The MM5451 will latch the values we have given it to it's outputs on // the next clock pulse, so now is the time to figure out which column // FET to turn on. // Turn off the column FETs. PORTE = PORTD = PORTB = PORTA = PORTF = PORTG = 0; // Figure out which FET to turn on. if (current_column <= 7){ // Column 2 and 3 are swapped. if (current_column == 2){ PORTE = 1 << 3; } else if (current_column == 3){ PORTE = 1 << 2; } else{ PORTE = 1 << current_column; } } else if ((current_column >= 8) && (current_column <= 15)){ PORTD = (1 << (current_column - 8)); } else if ((current_column >= 16) && (current_column <= 19)){ PORTB = 1 << (current_column - 16); } else if ((current_column >= 20) && (current_column <= 23)){ PORTA = 1 << (current_column - 20); } else if ((current_column >= 24) && (current_column <= 31)){ PORTF = 1 << (current_column - 24); } else if ((current_column >= 32) && (current_column <= 34)){ PORTG = 1 << (current_column - 32); } // Pulse clock for an end bit. mm_out(0); mm_out(0); }