A TextDisplay driver that supports graphical displays using on of the SED133x conrtrolers. Allows stdout and stderr output to be redirected to the display.

Sed133xLCD.cpp

Committer:
llagendijk
Date:
2011-01-29
Revision:
7:d79600310cfe
Parent:
6:2f8aed3d2be4

File content as of revision 7:d79600310cfe:

// mbed sed1330LCD Library Base Class
// Based on TextLCD (Copyright (c) 2007-2009 sford)
// Released under the MIT License: http://mbed.org/license/mit
// Author: louis Lagendijk
//
// Supports SED1330 (and probably the SED1335 and SED1336).
// Based on datasheet 268-0.4
//
// This code drives the display using the 8080 interface:
//      SEL1 = 0
//      SEL2 = 0
// These things require a lot of pins:
// 8 bits for the databus +
// *Reset (1)
// *Read
// *Write
// *ChipSelect
// A0
//
// Note(1): Reset is a Schmitt trigger input that can normally not be driven from
// an MBED output pin. We just pull it high with  a 5k resistor feeding a 10uF elco
// and the reset pin. This will reset the display once. Right now we do not use
// the reset pin.
//
// Character sizes can be set as desired (default 6*8). The SED seems to use a
// 5*7 font internally other font sizes use additional white space around the
// characters.
// Font widths of more than 8 pixels are not supported.
// The actual size in characters is caluclated from the horizontal/ vertical
// resolution and the specified font size.
// Recommended fontsize = 6*9 or 6*10
//
#include "mbed.h"
#include "Sed133xLCD.h"

//
//memory layout, datasheet shows 64kBit memory, 8 kByte * 8
// text screen, reserve 2k
//
#define TEXT_SCREEN_START (int) 0
// reserve one line of text extra as parts of it may be shown
#define TEXT_SCREEN_SIZE (int) (_columns * (_rows + 1))
#define TEXT_SCREEN_RESERVED (int) (2 * TEXT_SCREEN_SIZE)

// Graphical screen, reserve 4kB, not used

#define GRAPHICAL_SCREEN_START (int) (TEXT_SCREEN_START + TEXT_SCREEN_RESERVED)
#define GRAPHICAL_SCREEN_SIZE  (int) (_hor_dots * _vert_dots / 8)
#define GRAPHICAL_SCREEN_RESERVED (int) 0x1000

// char. gen. RAM, take whatever is left, not used

#define CG_RAM_START (int) (GRAPHICAL_SCREEN_START + GRAPHICAL_SCREEN_RESERVED)
// reserve room for 32 chars * 8 lines of 8 dots, only 32 can be squeeed in
#define CG_RAM_SIZE (int) (32 * 8 * 8)
#define CG_RAM_RESERVED (int)(0x8000 - CG_RAM_START)


commandName_t commandNameTab[] = {
    { SYSTEM_SET, "System set" },
    { SET_MEM, "Set memory" },
    { GET_MEM, "Get memory" },
    { SCROLL_SET, "Scroll set" },
    { SET_CURSOR, "Set cursor" },
    { GET_CURSOR, "Get cursor" },
    { CURSOR_DIR_RIGHT, "Cursor right" },
    { CURSOR_DIR_LEFT, "Cursor left" },
    { CURSOR_DIR_UP, "Cursor up" },
    { CURSOR_DIR_DOWN, "Cursor down" },
    { SLEEP_IN, "Sleep in" },
    { DISPLAY_OFF, "Display off" },
    { DISPLAY_ON, "Display on" },
    { HORIZONTAL_SCROLL_POSITION, "Horizontal scroll pos" },
    { OVERLAY_FORMAT, "Display format" },
    { CHAR_GEN_RAM_ADDR, "Char gen. ram address" },
    { CURSOR_FORM, "Cursor form" },
    { NO_COMMAND, ""}
};

char * Sed133xLCD::commandName(command_t command_val) {
    int i;
    for (i=0; commandNameTab[i].value != NO_COMMAND; i++) {
        if (commandNameTab[i].value == command_val) {
            return commandNameTab[i].text;
        }
    }
    return NULL;
}

/* low level interface functions
*/

void Sed133xLCD::busWait() {
    wait_us(0);
}

void Sed133xLCD::resetSed(void) {

    /* send reset */
    _reset = 1;
    wait_ms(50);
    _reset = 0;
    /* initialize databus */

    _dataBus.mode(PullNone);

    /* initialize control pins */
     _reset = 0;
    _nRead = _nWrite  = 1;

    /* wait for reset to complete */
    wait_ms(50);
}

void Sed133xLCD::sendByte(dataType_t type, uint8_t data) {

    /* sends one byte to the SED133X. A0 is set depending to the type of data
       to be sent (data or command)
     */
    _addr0 = type;
    _dataBus.output();
    _dataBus = data;
    Sed133xLCD::busWait();
    _nSelect = 0;
    _nWrite = 0;
    Sed133xLCD::busWait();
    _nWrite = 1;
    _nSelect = 1;
    Sed133xLCD::busWait();
}

void  Sed133xLCD::sendCommand(uint8_t data) {
    sendByte(t_command, data);
}

void  Sed133xLCD::sendData(uint8_t data) {
    sendByte(t_data, data);
}

uint8_t Sed133xLCD::getByte(dataType_t type) {

    /* reads one byte from the SED133X. A0 is set according to the type of data
       to be retrieved (data or command)
      */

    uint8_t data;

    _addr0 = type;
    _dataBus.input();
    busWait();
    _nRead = 0;
    Sed133xLCD::busWait();
    data = _dataBus;
    _nRead = 1;
    Sed133xLCD::busWait();
    return data;
}


/* Send SED133x commands
*/

void Sed133xLCD::systemSet(void) {

    sendCommand(SYSTEM_SET);

    // p1
    uint8_t M0 = 0;    // Internal char. generator
    uint8_t M1 = 0;    // CGRAM1, 32 characters
    uint8_t M2 = 0;    // 8 pixel character height
    uint8_t WS = 0;    // single panel drive
    uint8_t IV = 1;    // no top-line correction
    uint8_t TL = 0;    // LCD mode
    uint8_t DR = 0;    // normal operation (single panel)
    sendData((DR << 7) | (TL << 6) | (IV  << 5) | (1 << 4) | (WS << 3) | (M2 << 2) | (M1 << 1) | M0);

    // p2
    uint8_t WF = 1;    // usually 1, 16 line AC drive
    uint8_t FX = _char_width;
    sendData((WF << 7) | (FX - 1));

    // p3  FY: Char height
    sendData(_char_height - 1);

    // p4 CR: Bytes (not chars!) per line!
    uint8_t CR = ((_columns -1) * (_char_width > 8 ? 2 : 1) );
    sendData(CR);

    // p5 TCR: length of line incl hor. blanking
    sendData(CR + 4);

    // LF, lines per frame
    sendData(_vert_dots - 1);

    // AP graphical display: size of a scan line
    int AP =  ((_char_width > 8 ? 2 : 1) * (_columns));
    sendData(AP & 0xff);
    sendData(AP >> 8);
}

void Sed133xLCD::scrollSet(void) {

    /* allocate Screen 1 at 0 */
    int SA1 = TEXT_SCREEN_START;

    /* Start of graphical screen  */
    int SA2 = GRAPHICAL_SCREEN_START;

    sendCommand(SCROLL_SET);
    /* SAD 1 Low */
    sendData(SA1 & 255);
    /* SAD 1 high */
    sendData(SA1 >> 8);
    /* SL 1 */
    sendData(_vert_dots -1);
    /* SAD 2 low */
    sendData( SA2 & 255);
    /* SAD 2 high */
    sendData( SA2 >> 8);
    /* SL 2 */
    sendData( _vert_dots -1);
}

void Sed133xLCD::horizontalScrollPosition(void) {

    sendCommand(HORIZONTAL_SCROLL_POSITION);
    sendData( 0x0);      /* no offset */
}

void Sed133xLCD::overlayFormat(void) {

    sendCommand(OVERLAY_FORMAT);

    int MX = 0;     /* 0 = logical OR between layers, 1 is exclusive OR */
    int DM1 = 0;    /* Screen block 1: text mode */
    int DM2 = 0;    /* screen block 3: text mode */
    int OV = 0;     /* 2 layer compositioon */

    sendData( (OV << 4) | (DM2 << 3) | (DM1 << 2) |MX);
}

void Sed133xLCD::cursorDirection(void) {
    sendCommand(CURSOR_DIR_RIGHT);
}

void Sed133xLCD::cursorForm(void) {

    sendCommand(CURSOR_FORM);

    /* cursor width is uint8_twidth - 3 pixels */
    sendData(_char_width - 3 - 1);

    /* set block cursor as we are in graphical mode */
    int CM = 1;

    /* cursor vertical size 7 pixels */
    int CRY = 7 - 1;

    sendData( (CM << 7) | CRY);
}

void Sed133xLCD::displayOn(void) {

    sendCommand(DISPLAY_ON);

    /* flash cursor? */
    uint8_t FC = 0; /* cursor off */

    uint8_t layer1 = 1; /* on, no flashing */
    uint8_t layer2 = 0; /* off */
    uint8_t layer3 = 0; /* off */


    sendData((layer3 << 6) | (layer2 << 4) | (layer1 << 2) | FC);
}

void Sed133xLCD::displayOff(void) {

    sendCommand(DISPLAY_OFF);
}

void Sed133xLCD::charGenRamAddr(void) {
    sendCommand(CHAR_GEN_RAM_ADDR);
    sendData(CG_RAM_START & 255);
    sendData(CG_RAM_START >> 8);
}

void Sed133xLCD::clsText(void) {
    /*
     * Clear text screen
     */
     
    int i;
    setCursor(TEXT_SCREEN_START);
    sendCommand(SET_MEM);
    for (i=0; i < TEXT_SCREEN_RESERVED; i++) {
        sendData(' ');
    }
    setCursor(TEXT_SCREEN_START);
}

void Sed133xLCD::clsGraphics(void) {
    /*
     * clear graphics screen
     */

    int i;
    setCursor(GRAPHICAL_SCREEN_START);
    sendCommand(SET_MEM);
    for (i=0; i < GRAPHICAL_SCREEN_RESERVED; i++) {
        sendData(0);
    }
    setCursor(GRAPHICAL_SCREEN_START);
}

void Sed133xLCD::clearCharacterGeneratorRam(void) {
    /*
     * Clear character generator RAM
     */
     
    int i;
    setCursor(CG_RAM_START);
    sendCommand(SET_MEM);
    for (i=0; i < CG_RAM_SIZE; i++) {
        sendData(0);
    }
    setCursor(TEXT_SCREEN_START);
}

void Sed133xLCD::printText(uint8_t *text) {
    /* 
     * write text to screen
     */
    int len = strlen((char*)text);
    sendCommand(SET_MEM);
    while (len > 0) {
        sendData(text[len--]);
    }
}

void Sed133xLCD::printData(int len, uint8_t*data) {
    /* 
     * write (binary) data to screen
     */
    sendCommand(SET_MEM);
    while (len > 0) {
        sendData(data[len--]);
    }
}

void Sed133xLCD::setCursor(uint8_t column, uint8_t row) {
    /*
      * set cursor on text screen 
      */
    int pos = row * _columns + column;
    sendCommand(SET_CURSOR);
    sendData( pos & 255);
    sendData( pos >> 8);
}

void Sed133xLCD::setCursor(int pos) {
    /*
     * set cursor on graphical screen 
     */
    sendCommand(SET_CURSOR);
    sendData( pos & 255);
    sendData( pos >> 8);
}

/*
 * Public functions 
 */
 
 Sed133xLCD::Sed133xLCD(PinName reset, PinName nRead, PinName nWrite, PinName nSelect, PinName addr0,
                       PinName d0, PinName d1, PinName d2, PinName d3,
                       PinName d4, PinName d5, PinName d6, PinName d7,
                       uint16_t hor_dots, uint16_t vert_dots,
                       uint8_t char_width, uint8_t char_height,
                       const char *name) :
        TextDisplay(name),
        _reset(reset), _nRead(nRead), _nWrite(nWrite), _nSelect(nSelect), _addr0(addr0),
        _dataBus(d0, d1, d2, d3, d4, d5, d6, d7),
        _hor_dots(hor_dots), _vert_dots(vert_dots),
        _char_width(char_width), _char_height(char_height) {

    // if we have at least 8 dots left we can squeeze in one more row
    _rows = _vert_dots /_char_height + (((_vert_dots % _char_height) > 7) ? 1: 0);
    _columns = _hor_dots / char_width;
    initializeSed();
}



void Sed133xLCD::initializeSed(void) {
    resetSed();
    systemSet();
    scrollSet();
    horizontalScrollPosition();
    overlayFormat();
    cursorDirection();
    clsText();
    clsGraphics();
    clearCharacterGeneratorRam();
    cursorForm();
    displayOn();
    charGenRamAddr();
}

void Sed133xLCD::character(uint16_t column, uint16_t row, int c) {
    /*
     * Write character at specified position on screen
     */
     
    // check for illegal input
    if ( (column >= _columns) || (row >= _rows) )
        return;
    setCursor((char) column, (char)row);
    sendCommand(SET_MEM);
    sendData(c);
}

void Sed133xLCD::cls(void) {
    clsText();
}