Sanyo LC75711 VFD controller/driver for upto 16 Dot Matrix Characters

Dependents:   mbed_LC75711

The component page is here.

LC75711.cpp

Committer:
wim
Date:
2017-09-15
Revision:
2:cb6f2b7930c8
Parent:
1:bcf010fcacae

File content as of revision 2:cb6f2b7930c8:

/* mbed LC75710 Library, for Sanyo LC7571X VFD controller
 * Note: The LC75710, LC75711 and LC75712 differ only in the built-in character ROM
 *
 * Copyright (c) 2017, v01: WH, Initial version
 *               2017, v02: WH, Cleaned up docs  
 *               2017, v03: WH, Modified setBlink  
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

#include "mbed.h" 
#include "LC75711.h"
#include "LC75711_UDC.inc"


 /** Constructor for class for driving Sanyo LC75711 VFD controller
  *
  *  @brief Supports upto 16 Grids of 35 matrix segments. Also supports 3-8 additional segments (depending on number of grids).
  *         SPI bus interface device. 
  *  @param  PinName mosi, sclk, cs SPI bus pins
  *  @param  Mode selects number of Grids and Segments (default 11 Grids, 35 matrix segments, 8 additional segments)
  */
LC75711::LC75711(PinName mosi, PinName sclk, PinName cs, Mode mode) : _spi(mosi,NC,sclk), _cs(cs), _mode(mode) {

  _init();
}

/** Init the LC75711 interface and the controller
  *
  * @param  none
  * @return none
  */ 
void LC75711::_init(){
  
//init SPI
  _cs=0;
  _spi.format(8,0); //LC75711 uses mode 0 (Clock Low on Idle, Data latched on first (=rising) edge)
//  _spi.frequency(100000);   
  _spi.frequency(250000);     

//init controller  

  // Set number of Grids
  _writeCmd((LC75711_GRID_REG | _mode),      // B16..B23, Command register & value
             0x00,                           // B8..B15, Dummy
             0x00,                           // B0..B7, Dummy
             LC75711_GRID_DLY);              // Command Delay    

  _setAddress(0, 0); // No shift

  setBlink(false);   // No Blink
  setBrightness(LC75711_BRT_DEF); // Default Brightness

  // Clear the DCRAM (undefined at Reset)
  cls(); 

  // Clear the UDC RAM (undefined at Reset)
  const char udc_none[] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00}; 
  for (int idx=0; idx < LC75711_NR_UDC; idx++) {
    setUDC(idx, (char *)udc_none);
  }
       
  setDisplay(true);  // Display On
}   


/** Clear the screen and locate to 0
  *
  * @param none
  * @return none  
  */  
void LC75711::cls() {

  for (int cnt=0; cnt<LC75711_DISPLAY_MEM; cnt++) {
    writeData(char (' '), cnt); // data 
//    writeData(0x00, cnt);       // data     
  }

  for (int cnt=0; cnt<LC75711_ADD_MEM; cnt++) {
    writeData(0x00, cnt);       // adata 
  }  
}  

/** Set the Blink mode
  *
  * @param int  grids selected grids for Blinking enable (default = all)
  * @return none  
  */
void LC75711::setBlink(int grids) {
  
  // Sanity check and update of local shadow
  _blink = _blink | (grids & LC75711_GR_MSK);    // Set grid bits

  _writeCmd((LC75711_BLNK_REG | LC75711_BLNK_ON),  // B16..B23, Command register & value
             ((_blink >> 8) & 0xFF),               // B8..B15, GR8..GR16  
             ( _blink       & 0xFF),               // B0..B7, GR1..GR7            
             LC75711_BLNK_DLY);                    // Command Delay    
}

/** Clr the Blink mode
  *
  * @param int  grids selected grids for Blinking disable (default = all)
  * @return none  
  */
void LC75711::clrBlink(int grids) {
  
  // Sanity check and update of local shadow
  _blink = _blink & ~(grids & LC75711_GR_MSK);   // Clr grid bits   

  _writeCmd((LC75711_BLNK_REG | LC75711_BLNK_ON),  // B16..B23, Command register & value
             ((_blink >> 8) & 0xFF),               // B8..B15, GR8..GR16  
             ( _blink       & 0xFF),               // B0..B7, GR1..GR7            
             LC75711_BLNK_DLY);                    // Command Delay    
}

/** Set Brightness
  *
  * @param  char brightness (8 significant bits, valid range 0..239 (dutycycle linked to number of grids)  
  * @return none
  */
void LC75711::setBrightness(char brightness){
  
//Sanity check
  brightness = brightness & LC75711_BRT_MSK; // mask invalid bits
  if (brightness > 239) {brightness = 239;} 
 
  _writeCmd((LC75711_BRT_REG),               // B16..B23, Command register
             brightness,                     // B8..B15, Brightness
             0x00,                           // B0..B7, Dummy
             LC75711_BRT_DLY);               // Command Delay      
}

/** Set the Display mode On/off
  *
  * @param bool display mode
  * @return none  
  */
void LC75711::setDisplay(bool on) {
  char display;
     
  if (on) {
    display = LC75711_DSPL_ON;
  }
  else {
    display = LC75711_DSPL_OFF;
  }

  _writeCmd((LC75711_DSPL_REG | display),    // B16..B23, Command register & value
             0xFF,                           // B8..B15, GR8..GR16  
             0xFF,                           // B0..B7, GR1..GR7
             LC75711_DSPL_DLY);              // Command Delay    
}


/** Set User Defined Characters (UDC)
  *
  * @param unsigned char udc_idx   The Index of the UDC (0..7)
  * @param UDCData_t udc_data      The bitpattern for the UDC (7 bytes)
  * @return none  
  */
void LC75711::setUDC(unsigned char udc_idx, UDCData_t udc_data) {
  char data;
  
//Sanity check
  udc_idx = udc_idx & LC75711_UDC_MSK; // mask invalid bits

  _cs=0; // Prepare to send Address
  wait_us(1);    

  _spi.write(_flip(LC75711_ADDRESS)); // Address 

  _cs=1; // Latch Address, Prepare to send Command & Params 
  wait_us(1);
  
  data = ((udc_data[1] & 0x07) << 5) | ((udc_data[0] & 0x1F) << 0); 
  _spi.write(_flip(data));            // B0..B7, AM1-AM8

  data = ((udc_data[3] & 0x01) << 7) | ((udc_data[2] & 0x1F) << 2) | ((udc_data[1] & 0x18) >> 3);
  _spi.write(_flip(data));            // B8..B15, AM9-AM16  
    
  data = ((udc_data[4] & 0x0F) << 4) | ((udc_data[3] & 0x1E) >> 1);
  _spi.write(_flip(data));            // B16..B23, AM17-AM24  

  data = ((udc_data[6] & 0x03) << 6) | ((udc_data[5] & 0x1F) << 1) | ((udc_data[4] & 0x10) >> 4);
  _spi.write(_flip(data));            // B24..B31, AM25-AM32  

  data = ((udc_data[6] & 0x1C) >> 2);
  _spi.write(_flip(data));            // B32..B39, AM32-AM35  

  _spi.write(_flip(udc_idx));         // B40..B47, CA0-CA7  
  
  _spi.write(_flip(LC75711_UDC_REG)); // B48..B55, Command register

  wait_us(1);
  _cs=0; // Latch Command & Params

  wait_us(LC75711_UDC_DLY);           // Command Delay  
}


/** Write Data to LC75711
  *
  *  @param char data Character code
  *  @param char address Parameter for data
  *  @return none
  */  
void LC75711::writeData(char data, char address){

//Sanity check
  address = address & LC75711_DADR_MSK; // mask invalid bits

  _writeCmd((LC75711_DATA_REG),         // B16..B23, Command register
             address,                   // B8..B15, DCRAM address
             data,                      // B0..B7, Character code
             LC75711_DATA_DLY);         // Command Delay    
}  

/** Write Additional Data to LC75711
  *
  *  @param char adata Additional code (annunciator)
  *  @param char address Parameter for data
  *  @return none
  */  
void LC75711::writeAData(char adata, char address){

//Sanity check
  address = address & LC75711_AADR_MSK; // mask invalid bits
 
  _writeCmd((LC75711_ADAT_REG | address), // B16..B23, Command register & ADRAM address
             adata,                       // B8..B15, ADATA
             0x00,                        // B0..B7, Dummy
             LC75711_ADAT_DLY);           // Command Delay
}  


/** Set Address
  *
  *  @param char RAM address for data displayed at Grid1 (0..63)
  *  @param char RAM address for adata displayed at Grid1 (0..15) 
  *  @return none
  *
  *  Note that a Shift (L/R) command will change the Address of data displayed at Grid1
  */  
void LC75711::_setAddress(char data_addr, char adata_addr){

//Sanity check
  data_addr  =  data_addr & LC75711_DADR_MSK; // mask invalid bits
  adata_addr = adata_addr & LC75711_AADR_MSK; // mask invalid bits

  _writeCmd((LC75711_AC_REG | adata_addr),   // B16..B23, Command register & ADRAM address
             data_addr,                      // B8..B15, DCRAM address
             0x00,                           // B0..B7, Dummy
             LC75711_AC_DLY);                // Command Delay    
}  


/** Write command and parameters to LC75711
  *
  *  @param char cmd Command byte
  *  @param char data1 Parameters for command
  *  @param char data0 Parameters for command  
  *  @param char delay Delay for command execution
  *  @return none
  */  
void LC75711::_writeCmd(char cmd, char data1, char data0, char delay){

  _cs=0; // Prepare to send Address
  wait_us(1);    

  _spi.write(_flip(LC75711_ADDRESS)); // Address 

  _cs=1; // Latch Address, Prepare to send Command & Params 
  wait_us(1);

  _spi.write(_flip(data0));        // B0..B7

  _spi.write(_flip(data1));        // B8..B15  
    
  _spi.write(_flip(cmd));          // B16..B23, Command register & value

  wait_us(1);
  _cs=0; // Latch Command & Params

  wait_us(delay);                  // Command Delay        
}  


/** Helper to reverse all command or databits. The LC75711 expects LSB first, whereas SPI is MSB first
  *
  *  @param  char data
  *  @return bitreversed data
  */ 
char LC75711::_flip(char data) {
 char value=0;
  
 if (data & 0x01) {value |= 0x80;} ;  
 if (data & 0x02) {value |= 0x40;} ;
 if (data & 0x04) {value |= 0x20;} ;
 if (data & 0x08) {value |= 0x10;} ;
 if (data & 0x10) {value |= 0x08;} ;
 if (data & 0x20) {value |= 0x04;} ;
 if (data & 0x40) {value |= 0x02;} ;
 if (data & 0x80) {value |= 0x01;} ;
 return value;       
}




#if (ASTON_TEST == 1) 

/** Constructor for class for Sanyo LC75711 VFD controller as used in ASTON
  *
  *  @brief Supports 10 Grids of 35 Segments without additional Segments and uses Grid 11 for Icon segments.
  *  
  *  @param  PinName mosi, miso, sclk, cs SPI bus pins
  */
LC75711_ASTON::LC75711_ASTON(PinName mosi, PinName sclk, PinName cs) : LC75711(mosi, sclk, cs, Grid11_Add8) {
  _column   = 0;
  _columns  = ASTON_NR_DIGITS;
  
  // Clear the _udc_icon (should be cleared at Reset)
//  for (int idx=0; idx < 7; idx++) {
//    _udc_icon = 0x00;
//  }
}

/** Locate cursor to a screen column
  *
  * @param column  The horizontal position from the left, indexed from 0
  * @return none  
  */
void LC75711_ASTON::locate(int column) {
  //sanity check
  if (column < 0) {column = 0;}
  if (column > (_columns - 1)) {column = _columns - 1;}  
  
  _column = column;       
}


/** Number of screen columns
  *
  * @param none
  * @return columns
  */
int LC75711_ASTON::columns() {
    return _columns;
}


/** Clear the screen and locate to 0
  *
  * @param bool clrAll Clear Icons also (default = false)
  * @return none  
  */ 
void LC75711_ASTON::cls(bool clrAll) {  

  for (int cnt=0; cnt<ASTON_NR_DIGITS; cnt++) {
    writeData(char (' '), cnt); // data 
  }

  if (clrAll) {
    for (int cnt=0; cnt<ASTON_NR_DIGITS; cnt++) {
      writeAData(0x00, cnt);      // adata 
    }
    
    //Clear Icons
    //
  }  

  _column = 0;   
}    


/** Set Icon
  *
  * @param Icon Enums Icon Encodes UDC_0 byte index in 8 MSBs and encodes Icon bit/segment in 8 LSBs
  * @return none
  */
void LC75711_ASTON::setIcon(Icon icon){
  int byte_idx, bits;
  
  byte_idx = (icon >> 8) & 0x07;          // Decode byte index and sanity mask
  bits     = (1 << (icon & 0x07)) & 0x1F; // Decode bits and sanity mask  
    
  //Set the segment bit for the Icon
  _udc_icon[byte_idx] |= bits;
  
  //Update UDC_0 used to display the Icons at Grid 11
  setUDC(0, _udc_icon);
}

/** Clr Icon
  *
  * @param Icon Enums Icon Encodes UDC_0 byte index in 8 MSBs and encodes Icon bit/segment in 8 LSBs     
  * @return none
  */
void LC75711_ASTON::clrIcon(Icon icon) {
  int byte_idx, bits;
  
  byte_idx = (icon >> 8) & 0x07;          // Decode byte index and sanity mask
  bits     = (1 << (icon & 0x07)) & 0x1F; // Decode bits and sanity mask
    
  //Clear the segment bit for the Icon
  _udc_icon[byte_idx] &= ~bits;
  
  //Update UDC_0 used to display the Icons at Grid 11
  setUDC(0, _udc_icon);
}

/** Write a single character (Stream implementation)
  * 
  * @param value char to print
  * @return value;
  */
int LC75711_ASTON::_putc(int value) {
    int addr;
    
    if ((value == '\n') || (value == '\r')) {
      //No character to write
     
      //Update Cursor      
      _column = 0;
    }
    else if ((value >= 0) && (value < 192)) {
      //Character to write

      //Translate between _column and displaybuffer entries
      //Note that the ASTON has 1 digit/grids. 
      //_column ==  0 => Grid10 => addr = 9
      //_column ==  1 => Grid9  => addr = 8
      // ....
      //_column ==  9 => Grid1  => addr = 0            
      addr = (9 - _column); // 1 Byte for every Grid;
      
      writeData(value, addr);
                                
      //Update Cursor
      _column++;
      if (_column > (ASTON_NR_DIGITS - 1)) {        
        _column = 0;
      }

    } // if validChar           

    return value;
}

/** Get a single character (Stream implementation)
  *
  * @param none  
  * @return -1
  */
int LC75711_ASTON::_getc() {
    return -1;
}
#endif