HDSP253X Smart Alphanumeric LED matrix display

Dependents:   mbed_bus

HDSP253X.cpp

Committer:
wim
Date:
2015-01-25
Revision:
0:b3430a613781

File content as of revision 0:b3430a613781:

/* HDSP253X_Display - Intelligent 8 digit 5x7 LED matrix display
 *
 * Copyright (c) 2011 Wim Huiskamp
 * Modified software based on sourcecode by RAC 06/08/2008
 *
 * Released under the MIT License: http://mbed.org/license/mit
 *
 * version 0.2 Initial Release
*/
#include "mbed.h"
//#include "Utils.h"
#include "PCF8574_DataBus.h"
#include "PCF8574_AddressBus.h"
#include "PCF8574_EnableBus.h"
#include "MBED_ControlBus.h"
#include "HDSP253X.h"

/** Create an HDSP253X_Display object connected to the proper busses
 *
 * @param  PCF8574_DataBus data databus to connect to 
 * @param  PCF8574_AddressBus address addressbus to connect to 
 * @param  PCF8574_EnableBus enable enablebus to connect to 
 * @param  MBED_ControlBus control controlbus to connect to 
*/
HDSP253X_Display::HDSP253X_Display (PCF8574_DataBus &databus, PCF8574_AddressBus &addressbus, PCF8574_EnableBus &enablebus, MBED_ControlBus &controlbus) : 
                                     _databus(databus), _addressbus(addressbus), _enablebus(enablebus), _controlbus(controlbus) {

   _init();
}    

/** Init HDSP253X_Display
 * @param
 * @returns 
 */
void HDSP253X_Display::_init(void)
{
    // Apply reset
    reset();  // Note that this also resets the LED status display. 
 
    // Note: Brightness is 100% after reset
    set_brightness(HDSP253X_DEF_DISPLAY_BRIGHT);
 
    // Reset cursor 
    locate(0);
}


/*****************************************************************************/
/*******************  LOW LEVEL HDSP253X SUPPORT FUNCTIONS  ******************/
/*****************************************************************************/

/*---------------------------------------------------------------------------*\
 |
 |  Function:       HDSP253X_reset
 |
 |  Description:    Reset routine for HDSP253X display, applying reset, 
 |                  removing reset, then waiting for preset delay.
 |                  With the internal clock, the delay should be around 1
 |                  millisecond, but slower clocks will require longer delays.
 |                  After reset the Char RAM and Flash RAM is cleared, the CTRL word is
 |                  cleared (Blink Off, Flash Off, Brightness 100%). UDC RAM and address
 |                  are unaffected.
 |
 |  Parameters:     None
 |
 |  Returns:        Nothing.
 |
\*---------------------------------------------------------------------------*/
void HDSP253X_Display::reset(void)
{
//NOTE: On LF28A the Reset* pin is connected to the display and to the latches.
//      That implies they are all reset when the Reset* pin is used !
// 
// Alternative for the Display may be SW reset instruction

    // Apply the reset condition and then remove after short delay
    _enablebus.chipselect(CS_DISP, HIGH);  
    wait_ms(HDSP253X_1TCY_WAIT_MS);
    
    _enablebus.reset(LOW);   
    wait_ms(HDSP253X_1TCY_WAIT_MS);    
    wait_ms(HDSP253X_1TCY_WAIT_MS);        
    _enablebus.reset(HIGH);             
    
    // Wait for the preset delay to allow operation to complete
    wait_ms(HDSP253X_RST_CLR_DELAY_MS);
    
    // Reset cursor 
    locate(0);
}


/*---------------------------------------------------------------------------*\
 |
 |  Function:       HDSP253X_write
 |
 |  Description:    Low level data write routine for HDSP253X. Takes in data
 |                  and address (including Flash as top bit) and writes
 |                  it to the display. For simplicity, entire address byte
 |                  is written, even though top two bits are unused inputs.
 |                  After performing the operation, address lines are set
 |                  all high, in order to eliminate current drain through
 |                  pullup resistors (0.5mA per pin with 10K pullups)
 |
 |  Parameters:     address - full address in bits 0-5 (bit 5 is flash)
 |                  data - data byte to write out
 |
 |  Returns:        Nothing.
 |
\*---------------------------------------------------------------------------*/

void HDSP253X_Display::_write(uint8_t address, uint8_t data)
{
//    // Switch databus buffer to outputs
//    _controlbus.busdir(WRITE);        
//    // Switch databus to outputs
//    _databus.busdir(WRITE);   

    
    // Write out the address on to the addressbus and wait
    _addressbus.write(address);
//    wait_ms(HDSP253X_1TCY_WAIT_MS);

    // Set CE low and wait
    _enablebus.chipselect(CS_DISP, LOW);  
//    wait_ms(HDSP253X_1TCY_WAIT_MS);

    // Write data to the databus
    _databus.write(data);        
//    wait_ms(HDSP253X_1TCY_WAIT_MS);
     
    // Set WR low, wait, then set high and wait
    _controlbus.WR(LOW);
//    wait_ms(HDSP253X_1TCY_WAIT_MS);
    _controlbus.WR(HIGH);
//    wait_ms(HDSP253X_1TCY_WAIT_MS);

    // Set CE high and wait
    _enablebus.chipselect(CS_DISP, HIGH);  
//    wait_ms(HDSP253X_1TCY_WAIT_MS);
    
//    // Switch databus back to inputs
//    _databus.busdir(READ);        
//    // Switch databus buffer back to inputs
//    _controlbus.busdir(READ);  

//    // Set address lines all high to minimise power through pullups
//    _addressbus.write(HDSP253X_ADDR_LOW_POWER);
}

/*---------------------------------------------------------------------------*\
 |
 |  Function:       HDSP253X_read
 |
 |  Description:    Low level data read routine for HDSP253X. Takes in 
 |                  address (including Flash as top bit) and reads data
 |                  from the display. For simplicity, entire address byte
 |                  is written, even though top two bits are unused inputs.
 |                  After performing the operation, address lines are set
 |                  all high, in order to eliminate current drain through
 |                  pullup resistors (0.5mA per pin with 10K pullups)
 |
 |  Parameters:     address - full address in bits 0-5 (bit 5 is flash)
 |
 |  Returns:        data - data byte read in (Note that D7 is masked out)
 |
\*---------------------------------------------------------------------------*/

uint8_t HDSP253X_Display::_read(uint8_t address)
{
    uint8_t data = 0;

    // Switch databus to inputs
    _databus.busdir(READ);        
    // Switch databus buffer to inputs
    _controlbus.busdir(READ);      
       
    // Write out the address on to the addressbus and wait
    _addressbus.write(address);
//    wait_ms(HDSP253X_1TCY_WAIT_MS);

    // Set CE low and wait
    _enablebus.chipselect(CS_DISP, LOW);
//    wait_ms(HDSP253X_1TCY_WAIT_MS);

    // Set RD low and wait
    _controlbus.RD(LOW);
//    wait_ms(HDSP253X_1TCY_WAIT_MS);
    
    // Read the data byte from databus
    // Mask out the not-readable D7 bit, this mask is needed for my specific targetboard !
    // Reading the unconnected D7 bit results in 'H' level. A RMW cycle on the Ctrl register
    // would then always result in a Clearscreen !
    data = _databus.read() & HDSP253X_CTRL_MASK;

    // set RD high and wait
    _controlbus.RD(HIGH);
//    wait_ms(HDSP253X_1TCY_WAIT_MS);

    // Set CE high and wait
    _enablebus.chipselect(CS_DISP, HIGH);
//    wait_ms(HDSP253X_1TCY_WAIT_MS);

//    // Set address lines all high to minimise power through pullups
//    _addressbus.write(HDSP253X_ADDR_LOW_POWER);

    // Switch databus buffer back to outputs
    _controlbus.busdir(WRITE);        
    // Switch databus to outputs
    _databus.busdir(WRITE);   
    
    // Return read data to caller
    return data;
}


/*****************************************************************************/
/**************  HIGH LEVEL HDSP253X CHARACTER DISPLAY FUNCTIONS  ************/
/*****************************************************************************/


/*---------------------------------------------------------------------------*\
 |
 |  Function:       HDSP253X_putudc
 |
 |  Description:    Displays specified UDC character on the display at current
 |                  position. Used defined characters use codes from 128-142.
 |                  Note that the normal putc write routines can also be used
 |                  to show UDCs, using ASCII values 128 to 143 inclusive.
 |
 |  Parameters:     udc_char_num - UDC character, 16 possible UDC values from 0-15
 |
 |  Returns:        Nothing
 |
\*---------------------------------------------------------------------------*/

void HDSP253X_Display::putudc (char udc_char_num)
{
  putc(HDSP253X_ASCII_UDC_CHARS + udc_char_num);
}

/*---------------------------------------------------------------------------*\
 |
 |  Function:       HDSP253X_printf
 |
 |  Description:    Displays specified string on the display at current
 |                  cursor position. Increments cursor.
 |
 |  Parameters:     format - format string
 |                  args   - data
 |
 |  Returns:        Nothing
 |
\*---------------------------------------------------------------------------*/

void HDSP253X_Display::printf (char * format, ...) {
   char display_string[64];
//   int rv;   
   int string_len, i;   
   va_list args;
   va_start (args, format);

//   rv=vsprintf (display_string, format, args);
   vsprintf (display_string, format, args);   
   va_end (args);   
// printf("printing:'%s'\n", display_string);
//   writeString (buffer);

   // loop round, writing characters
   string_len = strlen(display_string);   // obtain length of string
   for (i = 0; i < string_len; i++) {
     putc(display_string[i]);
   };

   // return rv;
}



/*---------------------------------------------------------------------------*\
 |
 |  Function:       HDSP253X_putc
 |
 |  Description:    Displays specified character on the display at current
 |                  cursor position. Increments cursor.
 |                  Position on the display (0 to 7, Leftmost = 0)
 |
 |  Parameters:     disp_char - single character to display
 |                    - ASCII characters, 128 values between 0-127
 |                    - UDC character, 15 possible UDC values from 128-142
 |
 |  Returns:        Nothing
 |
\*---------------------------------------------------------------------------*/
void HDSP253X_Display::putc(char disp_char) {

    // Write selected character to display at current position
   
    if ((disp_char & HDSP253X_UDC_SEL) == HDSP253X_UDC_SEL) {      
        // Write UDC character to display, code between 128-143
        disp_char &= HDSP253X_UDC_MASK;        // mask off unused bits
        disp_char |= HDSP253X_UDC_SEL;         // add in top bit to specify UDC        
        _write(HDSP253X_ADDR_CHAR_BASE + _column, disp_char);
    }
    else {
        // Write ASCII character, code between 0-127
        disp_char &= HDSP253X_CHAR_MASK;        // mask off unused bits
        _write(HDSP253X_ADDR_CHAR_BASE + _column, disp_char);        
    }
    
    // Incr and wrap around cursorposition
    _column++; 
    _column = _column % HDSP253X_NUM_CHARS;    
}



#if(0)
char HDSP253X_Display::getc() {
  return -1;
}
#endif

/*---------------------------------------------------------------------------*\
 |
 |  Function:       HDSP253X_locate
 |
 |  Description:    Set the cursor address where the next character will be written. 
 |
 |  Parameters:     Cursor Column address
 |
 |  Returns:        Nothing
 |
\*---------------------------------------------------------------------------*/

void HDSP253X_Display::locate(uint8_t column) {

//    _row = row % HDSP253X_NUM_ROWS;
    _column = column % HDSP253X_NUM_CHARS;
}


/*---------------------------------------------------------------------------*\
 |
 |  Function:       HDSP253X_cls
 |
 |  Description:    Clears the displayed data and flash RAM, but not the user
 |                  defined characters. Waits for the preset delay to ensure the 
 |                  display is ready for operation; with an internal clock,
 |                  this delay needs to be around 1 millisecond. 
 |
 |  Parameters:     None
 |
 |  Returns:        Nothing
 |
\*---------------------------------------------------------------------------*/

void HDSP253X_Display::cls(void) {

    uint8_t disp_data;

    // Read in control word, modify and write back out
    disp_data = _read(HDSP253X_ADDR_CTRL_WORD);
    disp_data |= HDSP253X_CTRL_CLEAR_MASK;
    _write(HDSP253X_ADDR_CTRL_WORD, disp_data);

    // Wait for the preset delay to allow operation to complete
    wait_ms(HDSP253X_RST_CLR_DELAY_MS);

    // Reset cursor 
    locate(0);
}


/*---------------------------------------------------------------------------*\
 |
 |  Function:       HDSP253X_set_brightness
 |
 |  Description:    Sets the brightness of the HDSP253X display, by performing
 |                  a read-modify-write on the control register.
 |
 |  Parameters:     brightness - 3 bit brightness value
 |
 |  Returns:        Nothing
 |
\*---------------------------------------------------------------------------*/

void HDSP253X_Display::set_brightness(uint8_t brightness) {

    uint8_t ctrl_data;

    // Read in control word, modify and write back out
    ctrl_data = _read(HDSP253X_ADDR_CTRL_WORD);
    ctrl_data &= ~HDSP253X_CTRL_BRIGHT_MASK;
    ctrl_data |= (brightness & HDSP253X_CTRL_BRIGHT_MASK);
    _write(HDSP253X_ADDR_CTRL_WORD, ctrl_data);
}

/*---------------------------------------------------------------------------*\
 |
 |  Function:       HDSP253X_start_self_test
 |
 |  Description:    Starts the HDSP253X self test, setting the relevant 
 |                  control word bit. The caller should then wait for 
 |                  the required number of seconds before checking the result.
 |                  With the internal display clock, the self test takes 
 |                  around 5 seconds, so waiting for 6 seconds should
 |                  be OK. Slower clocks will require longer delays.
 |
 |                  Note that some displays such as the Siemens HDSP2111
 |                  appear to take longer than the official 4.5 seconds
 |                  so it is advisable to wait for longer (say 6 seconds)
 |                  before checking the result. Attempting to access the
 |                  display before it is ready may result in the self test
 |                  status failing to clear down.
 |
 |                  Also note that some display datasheets suggest that
 |                  the display must be reset BEFORE running the self
 |                  test routine, so this routine does this.
 |
 |  Parameters:     None
 |
 |  Returns:        Nothing
 |
\*---------------------------------------------------------------------------*/

void HDSP253X_Display::start_self_test(void) {

    // Reset the display to ensure it is ready for the self test
    reset();

    // Directly write the self test request, as control word is wiped at end
    _write(HDSP253X_ADDR_CTRL_WORD, HDSP253X_CTRL_SELFTEST_MASK);
}

/*---------------------------------------------------------------------------*\
 |
 |  Function:       HDSP253X_finish_self_test
 |
 |  Description:    Reads the control register to determine the self test
 |                  result. Then issues a display reset to ensure 
 |                  that it is ready for operation afterwards. While such
 |                  a reset should not be necessary if an adequate delay
 |                  occurs between starting the self test and checking the 
 |                  result, issuing a reset guarantees that the display will 
 |                  be ready for operation. This also means that this function
 |                  can be called early to prematurely terminate a self test.
 |
 |  Parameters:     None
 |
 |  Returns:        True if passed, False if failed
 |
\*---------------------------------------------------------------------------*/

bool HDSP253X_Display::finish_self_test(void) {
    uint8_t ctrl_data;
    bool result;
    
    // Read back control word and obtain self test result
    ctrl_data = _read(HDSP253X_ADDR_CTRL_WORD);
    result = ((ctrl_data & HDSP253X_CTRL_STRESULT_MASK) != 0);

    // Reset the display to ensure it is ready for normal operation
    reset();

    // Indicate the self test result
    return result;
}


/*---------------------------------------------------------------------------*\
 |
 |  Function:       HDSP253X_set_blink_mode
 |
 |  Description:    Enables or disables the blinking function on the display.
 |                  When enabled, blinking will flash the whole display 
 |                  irrespective of the flash RAM. With the internal clock,
 |                  the blink rate is 2Hz. Note that blink mode overrides 
 |                  the normal flashing mode.
 |
 |  Parameters:     enable - true to enable, false to disable
 |
 |  Returns:        Nothing
 |
\*---------------------------------------------------------------------------*/

void HDSP253X_Display::set_blink_mode(bool enable) {
    uint8_t ctrl_data;

    // read in control word, modify and write back out
    ctrl_data = _read(HDSP253X_ADDR_CTRL_WORD);
    if (enable) {
      ctrl_data |= HDSP253X_CTRL_BLINK_MASK;
    }
    else {
      ctrl_data &= ~HDSP253X_CTRL_BLINK_MASK;
    }
    _write(HDSP253X_ADDR_CTRL_WORD, ctrl_data);
}

/*---------------------------------------------------------------------------*\
 |
 |  Function:       HDSP253X_set_flash_mode
 |
 |  Description:    Enables or disables the flashing function on the display.
 |                  When enabled, characters with the flashing bit set in the 
 |                  RAM will flash. With the internal clock, the flash rate is 2Hz.
 |
 |  Parameters:     enable - true to enable, false to disable
 |
 |  Returns:        Nothing
 |
\*---------------------------------------------------------------------------*/

void HDSP253X_Display::set_flash_mode(bool enable) {
    uint8_t ctrl_data;

    // read in control word, modify and write back out
    ctrl_data = _read(HDSP253X_ADDR_CTRL_WORD);
    if (enable) {
      ctrl_data |= HDSP253X_CTRL_FLASH_MASK;
    }
    else {
      ctrl_data &= ~HDSP253X_CTRL_FLASH_MASK;
    }
    _write(HDSP253X_ADDR_CTRL_WORD, ctrl_data);
}

/*---------------------------------------------------------------------------*\
 |
 |  Function:       HDSP253X_set_all_flash_states
 |
 |  Description:    Sets flashing states of all characters in flash RAM, using 
 |                  supplied bit mask. Each bit corresponds to a character
 |                  (bit 7 on left, bit 0 on right), and is set to flash and
 |                  clear for steady operation. NOTE: The overall flashing 
 |                  enable/disable state is set by the separate set flash 
 |                  mode function.
 |
 |  Parameters:     flash_bits - bitmask containing flash states
 |
 |  Returns:        Nothing
 |
\*---------------------------------------------------------------------------*/

void HDSP253X_Display::set_all_flash_states(uint8_t flash_bits)
{
    int i;
    uint8_t char_pos;

    // loop round all character positions, extracting each bit in turn
    for (i = 1; i <= HDSP253X_NUM_CHARS; i++)
    {
      // Get state of bottom bit from mask and use to adjust flash state
      // Note that character address is reversed as we start from right
      char_pos = HDSP253X_NUM_CHARS - i;
      _write(HDSP253X_ADDR_FLASH_BASE + char_pos, flash_bits & 0x01);

      // Shift the mask to the right, ready for the next go
      flash_bits >>= 1;
    }
}

/*---------------------------------------------------------------------------*\
 |
 |  Function:       HDSP253X_set_char_flash_state
 |
 |  Description:    Sets flashing state of one character in flash RAM, using 
 |                  supplied character position and enable state. NOTE: The 
 |                  overall flashing enable/disable state is set by the 
 |                  separate set flash mode function.
 |
 |  Parameters:     flash_state - TRUE to flash, FALSE for steady operation
 |                  char_pos - position on the display (0 to 7)
 |
 |  Returns:        Nothing
 |
\*---------------------------------------------------------------------------*/

void HDSP253X_Display::set_char_flash_state(bool flash_state, uint8_t char_pos) {
    // Write out the new flash state to the flash RAM
    _write(HDSP253X_ADDR_FLASH_BASE + char_pos, flash_state);
}

/*---------------------------------------------------------------------------*\
 |
 |  Function:       HDSP253X_define_user_char
 |
 |  Description:    Full definition of UDC, firstly setting the UDC address
 |                  to specified character, and then loading all 7 data rows.
 |                  Note that for each row, only the bottom 5 bits are used.
 |  
 |  Parameters:     udc_char_num - number of UDC character, from 0 to 15
 |                  row_data_1 - top row data
 |                  row_data_2 - second row data
 |                  row_data_3 - third row data
 |                  row_data_4 - fourth row data
 |                  row_data_5 - fifth row data
 |                  row_data_6 - sixth row data
 |                  row_data_7 - bottomp row data
 |  
 |  Returns:        Nothing
 |
\*---------------------------------------------------------------------------*/

void HDSP253X_Display::define_user_char(uint8_t udc_char_num, uint8_t row_data_1, uint8_t row_data_2,
                                        uint8_t row_data_3, uint8_t row_data_4, uint8_t row_data_5, 
                                        uint8_t row_data_6, uint8_t row_data_7)
{
    // firstly set the UDC character address, by writing to the UDC addr reg
    _write(HDSP253X_ADDR_UDC_ADDRESS, udc_char_num);

    // now write out the 7 rows to the UDC RAM
    _write(HDSP253X_ADDR_UDC_ROW_BASE+0, row_data_1);
    _write(HDSP253X_ADDR_UDC_ROW_BASE+1, row_data_2);
    _write(HDSP253X_ADDR_UDC_ROW_BASE+2, row_data_3);
    _write(HDSP253X_ADDR_UDC_ROW_BASE+3, row_data_4);
    _write(HDSP253X_ADDR_UDC_ROW_BASE+4, row_data_5);
    _write(HDSP253X_ADDR_UDC_ROW_BASE+5, row_data_6);
    _write(HDSP253X_ADDR_UDC_ROW_BASE+6, row_data_7);
}


/*****************************************************************************/
/******************************  END OF FILE  ********************************/
/*****************************************************************************/