Wim Huiskamp / PT6964

Dependents:   mbed_PT6964

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers PT6964.cpp Source File

PT6964.cpp

00001 /* mbed PT6964 Library, for PT6964 LED controller
00002  * Copyright (c) 2015, v01: WH, Initial version
00003  *               2015, v02: WH, rename Digit/Grid 
00004  *               2016, v03: WH, updated Icon handling, UDCs and _putc() 
00005  *               2016, v04: WH, Refactored display and keyboard defines    
00006  *
00007  * Permission is hereby granted, free of charge, to any person obtaining a copy
00008  * of this software and associated documentation files (the "Software"), to deal
00009  * in the Software without restriction, including without limitation the rights
00010  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
00011  * copies of the Software, and to permit persons to whom the Software is
00012  * furnished to do so, subject to the following conditions:
00013  *
00014  * The above copyright notice and this permission notice shall be included in
00015  * all copies or substantial portions of the Software.
00016  *
00017  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00018  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00019  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
00020  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00021  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
00022  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
00023  * THE SOFTWARE.
00024  */
00025 #include "mbed.h" 
00026 #include "PT6964.h"
00027 #include "Font_7Seg.h"
00028 
00029 /** Constructor for class for driving PT6964 LED controller with SPI bus interface device. 
00030  *  Note: the PT6964 is also available from other chipvendors eg AIP1628, HT1628, CM1628, SM1628
00031  *  @brief Supports 4 digits @ 13 segments or 5 digits @ 12 segments or 6 Digits @ 11 Segments or 7 Digits @ 10 Segments. 
00032  *         Also supports a scanned keyboard of upto 20 keys.
00033  *   
00034  *  @param  PinName mosi, miso, sclk, cs SPI bus pins
00035  *  @param  Mode selects either 6 Digits of 12 Segments or 7 Digits of 10 Segments (default) 
00036 */
00037 PT6964::PT6964(PinName mosi, PinName miso, PinName sclk, PinName cs, Mode mode) : _spi(mosi,miso,sclk), _cs(cs), _mode(mode) {
00038 
00039   _init();
00040 }
00041 
00042 /** Init the SPI interface and the controller
00043   * @param  none
00044   * @return none
00045   */ 
00046 void PT6964::_init(){
00047   
00048 //init SPI
00049   _cs=1;
00050   _spi.format(8,3); //PT6964 uses mode 3 (Clock High on Idle, Data latched on second (=rising) edge)
00051   _spi.frequency(500000);   
00052 
00053 //init controller  
00054   _writeCmd(PT6964_MODE_SET_CMD, _mode);                                               // Mode set command 
00055 
00056   _display = PT6964_DSP_ON;
00057   _bright  = PT6964_BRT_DEF; 
00058   _writeCmd(PT6964_DSP_CTRL_CMD, _display | _bright );                                 // Display control cmd, display on/off, brightness   
00059   
00060   _writeCmd(PT6964_DATA_SET_CMD, PT6964_DATA_WR | PT6964_ADDR_INC | PT6964_MODE_NORM); // Data set cmd, normal mode, auto incr, write data  
00061 }   
00062 
00063 
00064 /** Clear the screen and locate to 0
00065  */  
00066 void PT6964::cls() {
00067   
00068   _cs=0;
00069   wait_us(1);    
00070   _spi.write(_flip(PT6964_ADDR_SET_CMD | 0x00)); // Address set cmd, 0
00071       
00072   for (int cnt=0; cnt<PT6964_DISPLAY_MEM; cnt++) {
00073     _spi.write(0x00); // data 
00074   }
00075   
00076   wait_us(1);
00077   _cs=1;      
00078 }  
00079 
00080 /** Set Brightness
00081   *
00082   * @param  char brightness (3 significant bits, valid range 0..7 (1/16 .. 14/14 dutycycle)  
00083   * @return none
00084   */
00085 void PT6964::setBrightness(char brightness){
00086 
00087   _bright = brightness & PT6964_BRT_MSK; // mask invalid bits
00088   
00089   _writeCmd(PT6964_DSP_CTRL_CMD, _display | _bright );  // Display control cmd, display on/off, brightness  
00090 }
00091 
00092 /** Set the Display mode On/off
00093   *
00094   * @param bool display mode
00095   */
00096 void PT6964::setDisplay(bool on) {
00097   
00098   if (on) {
00099     _display = PT6964_DSP_ON;
00100   }
00101   else {
00102    _display = PT6964_DSP_OFF;
00103   }
00104   
00105   _writeCmd(PT6964_DSP_CTRL_CMD, _display | _bright );  // Display control cmd, display on/off, brightness   
00106 }
00107 
00108 /** Write databyte to PT6964
00109   *  @param  int address display memory location to write byte
00110   *  @param  char data byte written at given address
00111   *  @return none
00112   */ 
00113 void PT6964::writeData(int address, char data) {
00114   _cs=0;
00115   wait_us(1);    
00116   _spi.write(_flip(PT6964_ADDR_SET_CMD | (address & PT6964_ADDR_MSK))); // Set Address cmd
00117       
00118   _spi.write(_flip(data)); // data 
00119   
00120   wait_us(1);
00121   _cs=1;             
00122 }
00123 
00124 /** Write Display datablock to PT6964
00125   *  @param  DisplayData_t data Array of PT6964_DISPLAY_MEM (=14) bytes for displaydata (starting at address 0)
00126   *  @param  length number bytes to write (valide range 0..PT6964_DISPLAY_MEM (=14), starting at address 0)     
00127   *  @return none
00128   */ 
00129 void PT6964::writeData(DisplayData_t data, int length) {
00130   _cs=0;
00131   wait_us(1);    
00132   _spi.write(_flip(PT6964_ADDR_SET_CMD | 0x00)); // Set Address at 0
00133       
00134 // sanity check
00135   if (length < 0) {length = 0;}
00136   if (length > PT6964_DISPLAY_MEM) {length = PT6964_DISPLAY_MEM;}
00137 
00138 //  for (int idx=0; idx<PT6964_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 PT6964
00149   *  @param  *keydata Ptr to Array of PT6964_KEY_MEM (=5) bytes for keydata
00150   *  @return bool keypress True when at least one key was pressed
00151   *
00152   * Note: Due to the hardware configuration the PT6964 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 PT6964::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(PT6964_DATA_SET_CMD | PT6964_KEY_RD | PT6964_ADDR_INC | PT6964_MODE_NORM)); // Data set cmd, normal mode, auto incr, read data
00166 
00167   for (int idx=0; idx < PT6964_KEY_MEM; idx++) {
00168     data = _flip(_spi.write(0xFF));    // read keys and correct bitorder
00169 
00170     data = data & PT6964_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(PT6964_DATA_SET_CMD, PT6964_DATA_WR | PT6964_ADDR_INC | PT6964_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 /** Helper to reverse all command or databits. The PT6964 expects LSB first, whereas SPI is MSB first
00197   *  @param  char data
00198   *  @return bitreversed data
00199   */ 
00200 char PT6964::_flip(char data) {
00201  char value=0;
00202   
00203  if (data & 0x01) {value |= 0x80;} ;  
00204  if (data & 0x02) {value |= 0x40;} ;
00205  if (data & 0x04) {value |= 0x20;} ;
00206  if (data & 0x08) {value |= 0x10;} ;
00207  if (data & 0x10) {value |= 0x08;} ;
00208  if (data & 0x20) {value |= 0x04;} ;
00209  if (data & 0x40) {value |= 0x02;} ;
00210  if (data & 0x80) {value |= 0x01;} ;
00211  return value;       
00212 }
00213 
00214 
00215 /** Write command and parameter to PT6964
00216   *  @param  int cmd Command byte
00217   *  &Param  int data Parameters for command
00218   *  @return none
00219   */  
00220 void PT6964::_writeCmd(int cmd, int data){
00221     
00222   _cs=0;
00223   wait_us(1);    
00224 //  _spi.write(_flip( (cmd & 0xF0) | (data & 0x0F)));  
00225   _spi.write(_flip( (cmd & PT6964_CMD_MSK) | (data & ~PT6964_CMD_MSK)));   
00226  
00227   wait_us(1);
00228   _cs=1;          
00229 }  
00230 
00231 
00232 
00233 
00234 /** Constructor for class for driving Princeton PT6964 controller as used in DVD538A
00235   *
00236   *  @brief Supports 4 Digits of 7 Segments, 1 Grid of 9 Icons. Also supports a scanned keyboard of 4.
00237   *   
00238   *  @param  PinName mosi, miso, sclk, cs SPI bus pins
00239   */
00240 PT6964_DVD538A::PT6964_DVD538A(PinName mosi, PinName miso, PinName sclk, PinName cs) : PT6964(mosi, miso, sclk, cs, Grid7_Seg10) {
00241   _column  = 0;
00242   _columns = DVD538A_NR_DIGITS;    
00243 }  
00244 
00245 #if(0)
00246 #if DOXYGEN_ONLY
00247     /** Write a character to the Display
00248      *
00249      * @param c The character to write to the display
00250      */
00251     int putc(int c);
00252 
00253     /** Write a formatted string to the Display
00254      *
00255      * @param format A printf-style format string, followed by the
00256      *               variables to use in formatting the string.
00257      */
00258     int printf(const char* format, ...);   
00259 #endif
00260 #endif
00261 
00262 /** Locate cursor to a screen column
00263   *
00264   * @param column  The horizontal position from the left, indexed from 0
00265   */
00266 void PT6964_DVD538A::locate(int column) {
00267   //sanity check
00268   if (column < 0) {column = 0;}
00269   if (column > (_columns - 1)) {column = _columns - 1;}  
00270   
00271   _column = column;       
00272 }
00273 
00274 
00275 /** Number of screen columns
00276   *
00277   * @param none
00278   * @return columns
00279   */
00280 int PT6964_DVD538A::columns() {
00281     return _columns;
00282 }
00283 
00284 
00285 /** Clear the screen and locate to 0
00286   * @param bool clrAll Clear Icons also (default = false)
00287   */ 
00288 void PT6964_DVD538A::cls(bool clrAll) {  
00289 
00290   if (clrAll) {
00291     //clear local buffer (including Icons)
00292     for (int idx=0; idx < (DVD538A_NR_GRIDS << 1); idx++) {  // * PT6964_BYTES_PER_GRID
00293       _displaybuffer[idx] = 0x00;  
00294     }
00295   }  
00296   else {
00297     //clear local buffer (preserving Icons)
00298     for (int idx=0; idx < DVD538A_NR_GRIDS; idx++) {
00299       _displaybuffer[(idx<<1)]     = _displaybuffer[(idx<<1)]     & MASK_ICON_GRID[idx][0];  
00300       _displaybuffer[(idx<<1) + 1] = _displaybuffer[(idx<<1) + 1] & MASK_ICON_GRID[idx][1];
00301     }  
00302   }
00303 
00304   writeData(_displaybuffer, (DVD538A_NR_GRIDS * PT6964_BYTES_PER_GRID));
00305 
00306   _column = 0;   
00307 }     
00308 
00309 
00310 /** Set Icon
00311   *
00312   * @param Icon icon Enums Icon has Grid position encoded in 8 MSBs, Icon pattern encoded in 16 LSBs
00313   * @return none
00314   */
00315 void PT6964_DVD538A::setIcon(Icon icon) {
00316   int addr, icn;
00317 
00318    icn =        icon  & 0xFFFF;
00319   addr = (icon >> 24) & 0xFF; 
00320   addr = (addr - 1) << 1;     // * PT6964_BYTES_PER_GRID
00321     
00322   //Save char...and set bits for icon to write
00323   _displaybuffer[addr]   = _displaybuffer[addr]   | LO(icn);      
00324   _displaybuffer[addr+1] = _displaybuffer[addr+1] | HI(icn);      
00325   writeData(_displaybuffer, (DVD538A_NR_GRIDS * PT6964_BYTES_PER_GRID));
00326 }
00327 
00328 /** Clr Icon
00329   *
00330   * @param Icon icon Enums Icon has Grid position encoded in 8 MSBs, Icon pattern encoded in 16 LSBs
00331   * @return none
00332   */
00333 void PT6964_DVD538A::clrIcon(Icon icon) {
00334   int addr, icn;
00335 
00336   icn =        icon  & 0xFFFF;
00337   addr = (icon >> 24) & 0xFF; 
00338   addr = (addr - 1) << 1;     // * PT6964_BYTES_PER_GRID
00339 
00340   //Save char...and clr bits for icon to write
00341   _displaybuffer[addr]   = _displaybuffer[addr]   & ~LO(icn);      
00342   _displaybuffer[addr+1] = _displaybuffer[addr+1] & ~HI(icn);      
00343   writeData(_displaybuffer, (DVD538A_NR_GRIDS * PT6964_BYTES_PER_GRID));
00344 }
00345 
00346 
00347 /** Set User Defined Characters (UDC)
00348   *
00349   * @param unsigned char udc_idx  The Index of the UDC (0..7)
00350   * @param int udc_data           The bitpattern for the UDC (16 bits)       
00351   */
00352 void PT6964_DVD538A::setUDC(unsigned char udc_idx, int udc_data) {
00353 
00354   //Sanity check
00355   if (udc_idx > (DVD538A_NR_UDC-1)) {
00356     return;
00357   }
00358   // Mask out Icon bits?
00359 
00360   _UDC_7S[udc_idx] = udc_data;
00361 }
00362 
00363 
00364 /** Write a single character (Stream implementation)
00365   */
00366 int PT6964_DVD538A::_putc(int value) {
00367     int addr;
00368     bool validChar = false;
00369     short pattern  = 0x0000;
00370     
00371     if ((value == '\n') || (value == '\r')) {
00372       //No character to write
00373       validChar = false;
00374       
00375       //Update Cursor      
00376       _column = 0;
00377     } 
00378     else if (value == '-') {
00379       //No character to write
00380       validChar = true;
00381       pattern = C7_MIN;         
00382     }
00383     else if ((value >= 0) && (value < DVD538A_NR_UDC)) {
00384       //Character to write
00385       validChar = true;
00386       pattern = _UDC_7S[value];
00387     }  
00388     else if ((value >= (int)'0') && (value <= (int) '9')) {   
00389       //Character to write
00390       validChar = true;
00391       pattern = FONT_7S[value - (int) '0'];
00392     }
00393     else if ((value >= (int) 'A') && (value <= (int) 'F')) {   
00394       //Character to write
00395       validChar = true;
00396       pattern = FONT_7S[10 + value - (int) 'A'];
00397     }
00398     else if ((value >= (int) 'a') && (value <= (int) 'f')) {   
00399       //Character to write
00400       validChar = true;
00401       pattern = FONT_7S[10 + value - (int) 'a'];
00402     } //else
00403 
00404     if (validChar) {
00405       //Character to write
00406  
00407       //Translate between _column and displaybuffer entries
00408       //_column == 0 => Grid5 => addr = 8
00409       //_column == 1 => Grid4 => addr = 6
00410       //_column == 2 => Grid3 => addr = 4
00411       //_column == 3 => Grid4 => addr = 2            
00412       addr = (4 - _column) << 1;  // * PT6964_BYTES_PER_GRID
00413 
00414       //Save icons...and set bits for character to write
00415       _displaybuffer[addr]   = (_displaybuffer[addr]   & MASK_ICON_GRID[4 - _column][0]) | LO(pattern);
00416       _displaybuffer[addr+1] = (_displaybuffer[addr+1] & MASK_ICON_GRID[4 - _column][1]) | HI(pattern);
00417 
00418       writeData(_displaybuffer, (DVD538A_NR_GRIDS * PT6964_BYTES_PER_GRID));
00419                                 
00420       //Update Cursor
00421       _column++;
00422       if (_column > (DVD538A_NR_DIGITS - 1)) {
00423         _column = 0;
00424       }
00425 
00426     } // if validChar           
00427 
00428     return value;
00429 }
00430 
00431 // get a single character (Stream implementation)
00432 int PT6964_DVD538A::_getc() {
00433     return -1;
00434 }