Wim Huiskamp / PT6311

Dependents:   mbed_PT6311

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers PT6311.cpp Source File

PT6311.cpp

00001 /* mbed PT6311 Library, for Princeton PT6311 VFD controller
00002  * Copyright (c) 2016, v01: WH, Initial version, for VFDEM2 code
00003  *
00004  * Permission is hereby granted, free of charge, to any person obtaining a copy
00005  * of this software and associated documentation files (the "Software"), to deal
00006  * in the Software without restriction, including without limitation the rights
00007  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
00008  * copies of the Software, and to permit persons to whom the Software is
00009  * furnished to do so, subject to the following conditions:
00010  *
00011  * The above copyright notice and this permission notice shall be included in
00012  * all copies or substantial portions of the Software.
00013  *
00014  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00015  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00016  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
00017  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00018  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
00019  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
00020  * THE SOFTWARE.
00021  */
00022 #include "mbed.h" 
00023 #include "PT6311.h"
00024 
00025 /** Constructor for class for driving Princeton PT6311 VFD controller
00026  *
00027  *  @brief Supports 8 Grids of 20 Segments upto 16 Grids of 12 Segments. Also supports a scanned keyboard of upto 48 keys, 4 switches and 5 LEDs.
00028  *         SPI bus interface device. 
00029  *   
00030  *  @param PinName mosi, miso, sclk, cs SPI bus pins
00031  *  @param Mode selects either number of Digits and Segments
00032 */
00033 PT6311::PT6311(PinName mosi, PinName miso, PinName sclk, PinName cs, Mode mode) : _spi(mosi,miso,sclk), _cs(cs), _mode(mode) {
00034 
00035   _init();
00036 }
00037 
00038 /** Init the SPI interface and the controller
00039   * @param  none
00040   * @return none
00041   */ 
00042 void PT6311::_init(){
00043   
00044 //init SPI
00045   _cs=1;
00046   _spi.format(8,3); //PT6311 uses mode 3 (Clock High on Idle, Data latched on second (=rising) edge)
00047 //  _spi.frequency(100000);   
00048   _spi.frequency(500000);     
00049 
00050 //init controller  
00051   _writeCmd(PT6311_MODE_SET_CMD, _mode);                                               // Mode set command
00052 
00053   _display = PT6311_DSP_ON;
00054   _bright  = PT6311_BRT_DEF; 
00055   _writeCmd(PT6311_DSP_CTRL_CMD, _display | _bright );                                 // Display control cmd, display on/off, brightness   
00056   
00057   _writeCmd(PT6311_DATA_SET_CMD, PT6311_DATA_WR | PT6311_ADDR_INC | PT6311_MODE_NORM); // Data set cmd, normal mode, auto incr, write data  
00058 }   
00059 
00060 
00061 /** Clear the screen and locate to 0
00062  */  
00063 void PT6311::cls() {
00064   
00065   _cs=0;
00066   wait_us(1);    
00067   _spi.write(_flip(PT6311_ADDR_SET_CMD | 0x00)); // Address set cmd, 0
00068       
00069   for (int cnt=0; cnt<PT6311_DISPLAY_MEM; cnt++) {
00070     _spi.write(0x00); // data 
00071   }
00072   
00073   wait_us(1);
00074   _cs=1;      
00075   
00076 }  
00077 
00078 /** Set Brightness
00079   *
00080   * @param  char brightness (3 significant bits, valid range 0..7 (1/16 .. 14/14 dutycycle)  
00081   * @return none
00082   */
00083 void PT6311::setBrightness(char brightness){
00084 
00085   _bright = brightness & PT6311_BRT_MSK; // mask invalid bits
00086   
00087   _writeCmd(PT6311_DSP_CTRL_CMD, _display | _bright );  // Display control cmd, display on/off, brightness  
00088 
00089 }
00090 
00091 /** Set the Display mode On/off
00092   *
00093   * @param bool display mode
00094   */
00095 void PT6311::setDisplay(bool on) {
00096   
00097   if (on) {
00098     _display = PT6311_DSP_ON;
00099   }
00100   else {
00101    _display = PT6311_DSP_OFF;
00102   }
00103   
00104   _writeCmd(PT6311_DSP_CTRL_CMD, _display | _bright );  // Display control cmd, display on/off, brightness   
00105 }
00106 
00107 /** Write databyte to PT6311
00108   *  @param  int address display memory location to write byte
00109   *  @param  char data byte written at given address
00110   *  @return none
00111   */ 
00112 void PT6311::writeData(int address, char data) {
00113   _cs=0;
00114   wait_us(1);    
00115   _spi.write(_flip(PT6311_ADDR_SET_CMD | (address & PT6311_ADDR_MSK))); // Set Address cmd
00116       
00117   _spi.write(_flip(data)); // data 
00118   
00119   wait_us(1);
00120   _cs=1;         
00121     
00122 }
00123 
00124 /** Write Display datablock to PT6311
00125   *  @param  DisplayData_t data Array of PT6311_DISPLAY_MEM (=48) bytes for displaydata (starting at address 0)
00126   *  @param  length number bytes to write (valid range 0..PT6311_DISPLAY_MEM (=48), starting at address 0)   
00127   *  @return none
00128   */    
00129 void PT6311::writeData(DisplayData_t data, int length) {
00130   _cs=0;
00131   wait_us(1);    
00132   _spi.write(_flip(PT6311_ADDR_SET_CMD | 0x00)); // Set Address at 0
00133       
00134 // sanity check
00135   if (length < 0) {length = 0;}
00136   if (length > PT6311_DISPLAY_MEM) {length = PT6311_DISPLAY_MEM;}
00137 
00138 //  for (int idx=0; idx<PT6311_DISPLAY_MEM; idx++) {  
00139   for (int idx=0; idx<length; idx++) {    
00140     _spi.write(_flip(data[idx])); // data 
00141   }
00142   
00143   wait_us(1);
00144   _cs=1;         
00145     
00146 }
00147 
00148 /** Read keydata block from PT6311
00149   *  @param  *keydata Ptr to Array of PT6311_KEY_MEM (=6) bytes for keydata
00150   *  @return bool keypress True when at least one key was pressed
00151   *
00152   * Note: Due to the hardware configuration the PT6311 key matrix scanner will detect multiple keys pressed at same time,
00153   *       but this may also result in some spurious keys being set in keypress data array.
00154   *       It may be best to ignore all keys in those situations. That option is implemented in this method depending on #define setting.  
00155   */ 
00156 bool PT6311::getKeys(KeyData_t *keydata) {
00157   int keypress = 0;
00158   char data;
00159 
00160   // Read keys
00161   _cs=0;
00162   wait_us(1);    
00163   
00164   // Enable Key Read mode
00165   _spi.write(_flip(PT6311_DATA_SET_CMD | PT6311_KEY_RD | PT6311_ADDR_INC | PT6311_MODE_NORM)); // Data set cmd, normal mode, auto incr, read data
00166 
00167   for (int idx=0; idx < PT6311_KEY_MEM; idx++) {
00168     data = _flip(_spi.write(0xFF));    // read keys and correct bitorder
00169     
00170     data = data & PT6311_KEY_MSK; // Mask valid bits
00171     if (data != 0) {  // Check for any pressed key
00172       for (int bit=0; bit < 8; bit++) {
00173         if (data & (1 << bit)) {keypress++;} // Test all significant bits
00174       }
00175     }  
00176 
00177     (*keydata)[idx] = data;            // Store keydata after correcting bitorder
00178   }
00179 
00180   wait_us(1);
00181   _cs=1;    
00182 
00183   // Restore Data Write mode
00184   _writeCmd(PT6311_DATA_SET_CMD, PT6311_DATA_WR | PT6311_ADDR_INC | PT6311_MODE_NORM); // Data set cmd, normal mode, auto incr, write data  
00185       
00186 #if(1)
00187 // Dismiss multiple keypresses at same time
00188   return (keypress == 1);    
00189 #else
00190 // Allow multiple keypress and accept possible spurious keys
00191   return (keypress > 0);
00192 #endif  
00193 }
00194 
00195 
00196 /** Read switches from PT6311
00197   *
00198   *  @param  none
00199   *  @return char for switch data (4 least significant bits) 
00200   *
00201   */   
00202 char PT6311::getSwitches() {
00203   char data;
00204 
00205   // Read switches
00206   _cs=0;
00207   wait_us(1);    
00208   
00209   // Enable Switch Read mode
00210   _spi.write(_flip(PT6311_DATA_SET_CMD | PT6311_SW_RD | PT6311_ADDR_INC | PT6311_MODE_NORM)); // Data set cmd, normal mode, auto incr, read data
00211 
00212   data = _flip(_spi.write(0xFF)) & PT6311_SW_MSK;   // read switches and correct bitorder
00213 
00214   wait_us(1);
00215   _cs=1;    
00216 
00217   // Restore Data Write mode
00218   _writeCmd(PT6311_DATA_SET_CMD, PT6311_DATA_WR | PT6311_ADDR_INC | PT6311_MODE_NORM); // Data set cmd, normal mode, auto incr, write data  
00219       
00220   return data;       
00221 }
00222    
00223 
00224 /** Set LEDs
00225   *
00226   * @param  char leds (5 least significant bits)  
00227   * @return none
00228   */
00229 void  PT6311::setLED (char leds) {
00230 
00231   // Set LEDs
00232   _cs=0;
00233   wait_us(1);    
00234   
00235   // Enable LED Write mode
00236   _spi.write(_flip(PT6311_DATA_SET_CMD | PT6311_LED_WR | PT6311_ADDR_INC | PT6311_MODE_NORM)); // Data set cmd, normal mode, auto incr, write data
00237 
00238   _spi.write(_flip(leds & PT6311_LED_MSK));    // write LEDs in correct bitorder
00239 
00240   wait_us(1);
00241   _cs=1;    
00242 
00243   // Restore Data Write mode
00244   _writeCmd(PT6311_DATA_SET_CMD, PT6311_DATA_WR | PT6311_ADDR_INC | PT6311_MODE_NORM); // Data set cmd, normal mode, auto incr, write data  
00245 }
00246 
00247 
00248 
00249 /** Helper to reverse all command or databits. The PT6311 expects LSB first, whereas SPI is MSB first
00250   *  @param  char data
00251   *  @return bitreversed data
00252   */ 
00253 char PT6311::_flip(char data) {
00254  char value=0;
00255   
00256  if (data & 0x01) {value |= 0x80;} ;  
00257  if (data & 0x02) {value |= 0x40;} ;
00258  if (data & 0x04) {value |= 0x20;} ;
00259  if (data & 0x08) {value |= 0x10;} ;
00260  if (data & 0x10) {value |= 0x08;} ;
00261  if (data & 0x20) {value |= 0x04;} ;
00262  if (data & 0x40) {value |= 0x02;} ;
00263  if (data & 0x80) {value |= 0x01;} ;
00264  return value;       
00265 }
00266 
00267 
00268 /** Write command and parameter to PT6311
00269   *  @param  int cmd Command byte
00270   *  &Param  int data Parameters for command
00271   *  @return none
00272   */  
00273 void PT6311::_writeCmd(int cmd, int data){
00274     
00275   _cs=0;
00276   wait_us(1);    
00277  
00278   _spi.write(_flip( (cmd & PT6311_CMD_MSK) | (data & ~PT6311_CMD_MSK)));   
00279  
00280   wait_us(1);
00281   _cs=1;      
00282     
00283 };  
00284 
00285 
00286 
00287 
00288 #if (VFDEM2_TEST == 1)
00289 /** Constructor for class for driving Princeton PT6311 VFD controller as used in VFDEM2
00290   *
00291   *  @brief Supports 12 Grids of 16 Segments and Icons (10 digits of 14 Segments plus some icons and another 2 Icon grids).  
00292   *         Also supports a scanned keyboard of 7 keys and 1 LED.
00293   *  
00294   *  @param  PinName mosi, miso, sclk, cs SPI bus pins
00295   */  
00296 PT6311_VFDEM2::PT6311_VFDEM2(PinName mosi, PinName miso, PinName sclk, PinName cs) : PT6311(mosi, miso, sclk, cs, Grid12_Seg16) {
00297   _column  = 0;
00298   _columns = VFDEM2_NR_DIGITS;    
00299 }  
00300 
00301 #if(0)
00302 #if DOXYGEN_ONLY
00303     /** Write a character to the LCD
00304      *
00305      * @param c The character to write to the display
00306      */
00307     int putc(int c);
00308 
00309     /** Write a formatted string to the LCD
00310      *
00311      * @param format A printf-style format string, followed by the
00312      *               variables to use in formatting the string.
00313      */
00314     int printf(const char* format, ...);   
00315 #endif
00316 #endif
00317 
00318 /** Locate cursor to a screen column
00319   *
00320   * @param column  The horizontal position from the left, indexed from 0
00321   */
00322 void PT6311_VFDEM2::locate(int column) {
00323   //sanity check
00324   if (column < 0) {column = 0;}
00325   if (column > (_columns - 1)) {column = _columns - 1;}  
00326   
00327   _column = column;       
00328 }
00329 
00330 
00331 /** Number of screen columns
00332   *
00333   * @param none
00334   * @return columns
00335   */
00336 int PT6311_VFDEM2::columns() {
00337     return _columns;
00338 }
00339 
00340     
00341 /** Clear the screen and locate to 0
00342   * @param bool clrAll Clear Icons also (default = false)
00343   */ 
00344 void PT6311_VFDEM2::cls(bool clrAll) {  
00345   int idx;
00346   
00347   if (clrAll) {
00348     //clear local buffer (including Icons)
00349     for (idx=0; idx < (VFDEM2_NR_GRIDS * PT6311_BYTES_PER_GRID); idx++) {
00350       _displaybuffer[idx] = 0x00;  
00351     }
00352   }  
00353   else {
00354     //clear local buffer (preserving Icons)
00355     for (int grd=0; grd < VFDEM2_NR_GRIDS; grd++) {
00356       idx = grd * PT6311_BYTES_PER_GRID; // 3 bytes for every Grid
00357       _displaybuffer[idx    ] = _displaybuffer[idx    ] & MASK_ICON_GRID[grd][0];  
00358       _displaybuffer[idx + 1] = _displaybuffer[idx + 1] & MASK_ICON_GRID[grd][1];
00359       _displaybuffer[idx + 2] = _displaybuffer[idx + 2] & MASK_ICON_GRID[grd][2];      
00360     }  
00361   }
00362 
00363   writeData(_displaybuffer, (VFDEM2_NR_GRIDS * PT6311_BYTES_PER_GRID));
00364 
00365   _column = 0;   
00366 }    
00367 
00368 /** Set Icon
00369   *
00370   * @param Icon icon Enums Icon has Grid position encoded in 8 MSBs, Icon pattern encoded in 16 LSBs
00371   * @return none
00372   */
00373 void PT6311_VFDEM2::setIcon(Icon icon) {
00374   int addr, icn;
00375 
00376    icn =        icon  & 0xFFFF;
00377   addr = (icon >> 24) & 0xFF; 
00378   addr = (addr - 1) * PT6311_BYTES_PER_GRID;  // 3 Bytes for every Grid
00379     
00380   //Save char...and set bits for icon to write
00381   _displaybuffer[addr    ] = _displaybuffer[addr    ] | LO(icn);      
00382   _displaybuffer[addr + 1] = _displaybuffer[addr + 1] | MD(icn);      
00383   _displaybuffer[addr + 2] = _displaybuffer[addr + 2] | HI(icn);        
00384   writeData(_displaybuffer, (VFDEM2_NR_GRIDS * PT6311_BYTES_PER_GRID));
00385 }
00386 
00387 /** Clr Icon
00388   *
00389   * @param Icon icon Enums Icon has Grid position encoded in 8 MSBs, Icon pattern encoded in 16 LSBs
00390   * @return none
00391   */
00392 void PT6311_VFDEM2::clrIcon(Icon icon) {
00393   int addr, icn;
00394 
00395    icn =        icon  & 0xFFFF;
00396   addr = (icon >> 24) & 0xFF; 
00397   addr = (addr -1 ) * PT6311_BYTES_PER_GRID;   // 3 Bytes for every Grid
00398     
00399   //Save char...and clr bits for icon to write
00400   _displaybuffer[addr    ] = _displaybuffer[addr    ] & ~LO(icn);      
00401   _displaybuffer[addr + 1] = _displaybuffer[addr + 1] & ~MD(icn);      
00402   _displaybuffer[addr + 2] = _displaybuffer[addr + 2] & ~HI(icn);        
00403   writeData(_displaybuffer, (VFDEM2_NR_GRIDS * PT6311_BYTES_PER_GRID));
00404 }
00405 
00406 
00407 /** Set User Defined Characters (UDC)
00408   *
00409   * @param unsigned char udc_idx  The Index of the UDC (0..7)
00410   * @param int udc_data           The bitpattern for the UDC (16 bits)       
00411   */
00412 void PT6311_VFDEM2::setUDC(unsigned char udc_idx, int udc_data) {
00413 
00414   //Sanity check
00415   if (udc_idx > (VFDEM2_NR_UDC-1)) {
00416     return;
00417   }
00418 
00419   // Mask out Icon bits?
00420   _UDC_16S[udc_idx] = udc_data & 0xFFFF;
00421 }
00422 
00423 /** Write a single character (Stream implementation)
00424   */
00425 int PT6311_VFDEM2::_putc(int value) {
00426     bool validChar = false;
00427     short pattern  = 0x0000;
00428     int addr;
00429     
00430     if ((value == '\n') || (value == '\r')) {
00431       //No character to write
00432       validChar = false;
00433       
00434       //Update Cursor      
00435       _column = 0;
00436     }
00437     else if ((value >= 0) && (value < VFDEM2_NR_UDC)) {
00438       //Character to write
00439       validChar = true;
00440       pattern = _UDC_16S[value];
00441     }  
00442 #if (SHOW_ASCII == 1)
00443     //display all ASCII characters
00444     else if ((value >= FONT_16S_START) && (value <= FONT_16S_END)) {   
00445       //Character to write
00446       validChar = true;
00447       pattern = FONT_16S[value - FONT_16S_START];
00448     } // else
00449 #else
00450     //display only digits and hex characters
00451     else if (value == '-') {
00452       //Character to write
00453       validChar = true;
00454       pattern = C16_MIN;         
00455     }
00456     else if ((value >= (int)'0') && (value <= (int) '9')) {   
00457       //Character to write
00458       validChar = true;
00459       pattern = FONT_16S[value - (int) '0'];
00460     }
00461     else if ((value >= (int) 'A') && (value <= (int) 'F')) {   
00462       //Character to write
00463       validChar = true;
00464       pattern = FONT_16S[10 + value - (int) 'A'];
00465     }
00466     else if ((value >= (int) 'a') && (value <= (int) 'f')) {   
00467       //Character to write
00468       validChar = true;
00469       pattern = FONT_16S[10 + value - (int) 'a'];
00470     } //else
00471 #endif
00472     if (validChar) {
00473       //Character to write
00474  
00475       //Translate between _column and displaybuffer entries
00476       //Note that the VFDEM2 has ten 14 Segment digits/grids. 
00477       //Some of these Grids also have icons that need to be preserved
00478       //_column ==  0 => Grid11 => addr = 30
00479       //_column ==  1 => Grid10 => addr = 27
00480       // ....
00481       //_column ==  9 => Grid2  => addr = 3            
00482       addr = (10 - _column) * PT6311_BYTES_PER_GRID; // 3 Bytes for every Grid;
00483       
00484       //Save icons...and set bits for character to write
00485       _displaybuffer[addr]   = (_displaybuffer[addr]   & MASK_ICON_GRID[10 - _column][0]) | LO(pattern);
00486       _displaybuffer[addr+1] = (_displaybuffer[addr+1] & MASK_ICON_GRID[10 - _column][1]) | MD(pattern);
00487 //      _displaybuffer[addr+2] = (_displaybuffer[addr+2] & MASK_ICON_GRID[10 - _column][2]) | HI(pattern);
00488 
00489       writeData(_displaybuffer, (VFDEM2_NR_GRIDS * PT6311_BYTES_PER_GRID));
00490                                 
00491       //Update Cursor
00492       _column++;
00493       if (_column > (VFDEM2_NR_DIGITS - 1)) {
00494         _column = 0;
00495       }
00496 
00497     } // if validChar           
00498 
00499     return value;
00500 }
00501 
00502 // get a single character (Stream implementation)
00503 int PT6311_VFDEM2::_getc() {
00504     return -1;
00505 }
00506 #endif