Search:

Return to previous page

Contents of file 'dogm16x.c':



    1   /*=============================================================================
    2    * File:        dogm16x.c
    3    * Created:     September 12, 2010 [v.1.0]
    4    * Last change: September 3, 2011 [v.1.4]
    5    * Author:      Fredrik Jonsson <http://jonsson.eu/>
    6    *
    7    * Copyright (C) 2011, Fredrik Jonsson <http://jonsson.eu/>
    8    * Non-commercial copying welcome.
    9    *
   10    * Summary
   11    *
   12    * The set of routines in dogm16x.c provides a driver for the Electronic
   13    * Assembly DOG-M family of LCD displays [1,2] for the Microchip PIC32
   14    * microcontroller, employing the Parallel Master Port (PMP), with data
   15    * on pins PMD0-PMD7 and PMP control signals on pins PMWR, PMRD and PMA0.
   16    *
   17    * Hardware connections
   18    *
   19    * The connections between the Parallel Master Port (PMP, data on pins
   20    * PMD0-PMD7; PMP control signals on pins PMWR, PMRD, and PMA0) of the
   21    * PIC32MX processor and the Electronic Assembly DOGM display are as
   22    * follows:
   23    *
   24    *     PIC32 pin      OLIMEX PCB     LCD pin
   25    * --------------------------------------------------------------------------
   26    *     PMD7    ---    RE7     ---    28 (D7)         Display data, MSB
   27    *     PMD6    ---    RE6     ---    29 (D6)         Display data
   28    *     PMD5    ---    RE5     ---    30 (D5)         Display data
   29    *     PMD4    ---    RE4     ---    31 (D4)         Display data
   30    *     PMD3    ---    RE3     ---    32 (D3)         Display data
   31    *     PMD2    ---    RE2     ---    33 (D2)         Display data
   32    *     PMD1    ---    RE1     ---    34 (D1)         Display data
   33    *     PMD0    ---    RE0     ---    35 (D0)         Display data, LSB
   34    *     PMWR    ---    RD4     ---    36 (E)          Enable, falling edge
   35    *     PMRD    ---    RD5     ---    37 (R/W)        Low=Write, High=Read
   36    *     PMA0    ---    RB15    ---    39 (RS)         Low=Control, High=Data
   37    *
   38    * In addition, the following connections to the LCD provide power supply and
   39    * proper ground:
   40    *     PIC32 pin     OLIMEX PCB    LCD pin
   41    *                   GROUND --- 38 (CSB)        Chip select
   42    *                   GROUND --- 27 (VSS)        Power supply, 0V
   43    *                   +3.3V  --- 26 (VDD)        Power supply, +3.3V
   44    *                   +3.3V  --- 25 (VIN)
   45    *                   +3.3V  --- 23 (PSB)
   46    *                   +3.3V  --- 40 (RESET)
   47    *                   +3.3V  --- X ohm resistor --- 20   Power supply 3.3V, illumination
   48    *                   +3.3V  --- X ohm resistor --- 1    Power supply 3.3V, illumination
   49    *                   GROUND --- 2 (VSS)         Power supply 0V, illumination
   50    *                   GROUND --- 19 (VSS)         Power supply 0V, illumination
   51    *                 |------------   21 (CAP1N)
   52    *                === 2.2 uF Capacitor
   53    *                 |------------   22 (CAP1P)
   54    *                 |------------  24 (VOUT)
   55    *                === 2.2 uF
   56    *    +3.3V -------|
   57    *
   58    * Installing the driver as a shared library
   59    *
   60    * See enclosed file README.txt.
   61    *
   62    * Examples of usage
   63    *
   64    * Example 1. High-level usage of the library, writing entire strings of data:
   65    *
   66    *   char buf[128];
   67    *   float x=0.4711;
   68    *   write_string_to_display("Hello World!\n");
   69    *   sprintf(buf,"sin(%f)=%f\n",x,sin(x));
   70    *   write_string_to_display(buf);
   71    *
   72    * Example 2. Low-level usage of the library, writing individual characters
   73    * and positioning the cursor by direct access to the LCD registers:
   74    *
   75    *   write_to_display_register(LCDCMD,0x80|0x00);  // Set position to 1st row, 1st col
   76    *   write_to_display_register(LCDDATA,'A');       // Write 'A' at 1st row, 1st col
   77    *   write_to_display_register(LCDCMD,0x80|0x00);  // Reposition to 1st row, 1st col
   78    *   write_to_display_register(LCDDATA,'B');       // Overwrites the previous 'A'
   79    *   write_to_display_register(LCDDATA,'C');       // Writes a 'C' next after the 'B'
   80    *   write_to_display_register(LCDCMD,0x80|0x05);  // Reposition to 1st row, 6th col
   81    *   write_to_display_register(LCDDATA,'D');       // Writes a 'C' at 1st row, 5th col
   82    *   write_to_display_register(LCDDATA,'E');       // Writes a 'E' next after the 'D'
   83    *   write_to_display_register(LCDCMD,0x80|0x10);  // Set position to 2nd row, 1st col
   84    *   write_to_display_register(LCDDATA,'G');       // Write 'G' at 1st row, 1st col
   85    *   sprintf(buf,"%d",read_display_register(0x02)&0x7f);
   86    *   write_string_to_display(buf);
   87    *
   88    *
   89    * [1] See the Electronic Assembly web site on their display-on-glass (DOG)
   90    *     series at http://www.lcd-module.com/products/dog.html
   91    * [2] For suppliers of the Electronic Assembly DOG-M series and corresponding
   92    *     backlights, see https://www.elfa.se/elfa3~se_en/elfa/init.do?query=DC-76206&in=fam
   93    *     (display) and https://www.elfa.se/elfa3~se_en/elfa/init.do?query=DC-76207&in=fam
   94    *     (backlight modules).
   95    *===========================================================================*/
   96   #include <p32xxxx.h>  /* Microchip PIC32-family specifics/generics */
   97   #include <plib.h>     /* To access the PIC32 Peripheral Library    */
   98   #include "dogm16x.h"
   99   
  100   /*
  101    * Directly from the PIC32 Family Reference Manual [1]: The Parallel Master
  102    * Port (PMP) is a parallel 8-bit/16-bit I/O module specifically designed to
  103    * communicate with a wide variety of parallel devices such as communications
  104    * peripherals, LCDs, external memory devices and microcontrollers. Because
  105    * the interfaces to parallel peripherals vary significantly, the PMP module
  106    * is highly configurable.
  107    *
  108    * The driver makes use of the Parallell Master Port (PMP) in Master mode (mode
  109    * set by PMP_MASTER_1), in which the following Special Function Registers
  110    * (SFRs) apply:
  111    *
  112    * PMCON: Parallel Port Control Register
  113    * This register (Register 13-1) contains the bits that control much of the
  114    * module?s basic functionality. A key bit is the ON control bit, which is
  115    * used to Reset, enable or disable the module. When the module is disabled,
  116    * all of the associated I/O pins revert to their designated I/O function.
  117    * In addition, any read or write operations active or pending are stopped,
  118    * and the BUSY bit is cleared. The data within the module registers is
  119    * retained, including the data in PMSTAT register. Therefore, the module
  120    * could be disabled after a reception, and the last received data and status
  121    * would still be available for processing. When the module is enabled, all
  122    * buffer control logic is reset, along with PMSTAT. All other bits in PMCON
  123    * control address multiplexing, enable various port control signals, and
  124    * select control signal polarity. For futher details, see PIC32 Family
  125    * Reference Manual [1] Chapter 13.3.1 ?Parallel Master Port Configuration
  126    * Options?.
  127    *
  128    * PMMODE: Parallel Port Mode Register
  129    * This register (Register 13-2) contains bits that control the operational
  130    * modes of the module. Master/Slave mode selection, as well as configuration
  131    * options for both modes, are set by this register. It also contains the
  132    * universal status flag BUSY, used in Master modes to indicate that an
  133    * operation by the module in progress. For futher details, see PIC32 Family
  134    * Reference Manual [1], Chapters 13.4 ?Slave Modes of Operation? and 13.3
  135    * ?Master Modes of Operation?.
  136    *
  137    * PMADDR: Parallel Port Address Register
  138    * This register (Register 13-3) functions as PMADDR in master modes. It
  139    * contains the address to which outgoing data is to be written, as well
  140    * as the Chip Select control bits for addressing parallel slave devices.
  141    * The PMADDR register is not used in any of the Slave modes.
  142    *
  143    * PMAEN: Parallel Port Pin Enable Register
  144    * This register (Register 13-6) controls the operation of address and Chip
  145    * Select pins associated to this module. Setting these bits allocates the
  146    * corresponding microcontroller pins to the PMP module; clearing the bits
  147    * allocates the pins to port I/O or other peripheral modules associated
  148    * with the pin.
  149    */
  150   
  151   /*
  152    * In order to avoid any conflicts with these settings (via pragmas),
  153    * ensure that the MPLAB IDE settings are Configure -> Configuration
  154    * Bits -> Configuration Bits set in code.
  155    *
  156    * For details on these config settings for the oscillator frequency
  157    * dividers of the PIC32MX, see Di Lucio page 151.
  158    */
  159   #pragma config POSCMOD=XT, FNOSC=PRIPLL
  160   #pragma config FPLLIDIV=DIV_2, FPLLMUL=MUL_18, FPLLODIV=DIV_1
  161   #pragma config FPBDIV=DIV_2, FWDTEN=OFF, CP=OFF, BWP=OFF
  162   
  163   #undef FPB
  164   #define FPB (36000000L)
  165   void delayms(unsigned t)
  166   {
  167      int fpbthresh=FPB/1000;
  168      T1CON = 0x8000;     /* Enable TMR1, Tpb, 1:1 */
  169      while (t--) {       /* t x 1ms loop */
  170         TMR1 = 0;
  171         while (TMR1 < fpbthresh);
  172      }
  173   }
  174   #undef FPB
  175   
  176   int row, col;
  177   
  178   /*
  179    * The initialize_display() routine performs the initialization of the Parallel Master
  180    * Port (PMP) key parameters of the Microchip PIC32MX (here PIC32MX340F512)
  181    * using the mPMPOpen() macro as defined in pmp.h [1].
  182    *
  183    * The significance of the bits of the PMCON (Parallel Port Control Register)
  184    * are as follows:
  185    *
  186    * bit 31-16 Reserved: Write ?0?; ignore read
  187    *
  188    * bit 15 ON: Parallel Master Port Enable bit
  189    * 1 = PMP enabled
  190    * 0 = PMP disabled, no off-chip access performed
  191    * Note: When using 1:1 PBCLK divisor, the user?s software should not read/write
  192    * the peripheral?s SFRs in the SYSCLK cycle immediately following the instruction
  193    * that clears the module?s ON control bit.
  194    *
  195    * bit 14 FRZ: Freeze in Debug Exception Mode bit
  196    * 1 = Freeze operation when CPU is in Debug Exception mode
  197    * 0 = Continue operation even when CPU is in Debug Exception mode
  198    * Note: FRZ is writable in Debug Exception mode only, it is forced to ?0? in normal mode.
  199    *
  200    * bit 13 SIDL: Stop in Idle Mode bit
  201    * 1 = Discontinue module operation when device enters Idle mode
  202    * 0 = Continue module operation in Idle mode
  203    *
  204    * bit 12-11 ADRMUX<1:0>: Address/Data Multiplexing Selection bits
  205    * 11 = All 16 bits of address are multiplexed on PMD<15:0> pins
  206    * 10 = All 16 bits of address are multiplexed on PMD<7:0> pins
  207    * 01 = Lower 8 bits of address are multiplexed on PMD<7:0> pins,
  208    *      upper 8 bits are on PMA<15:8>
  209    * 00 = Address and data appear on separate pins
  210    *
  211    * bit 10 PMPTTL: PMP Module TTL Input Buffer Select bit
  212    * 1 = PMP module uses TTL input buffers
  213    * 0 = PMP module uses Schmitt Trigger input buffer
  214    *
  215    * bit 9 PTWREN: Write Enable Strobe Port Enable bit
  216    * 1 = PMWR/PMENB port enabled
  217    * 0 = PMWR/PMENB port disabled
  218    *
  219    * bit 8 PTRDEN: Read/Write Strobe Port Enable bit
  220    * 1 = PMRD/PMWR port enabled
  221    * 0 = PMRD/PMWR port disabled
  222    *
  223    * bit 7-6 CSF<1:0>: Chip Select Function bits(4)
  224    * 11 = Reserved
  225    * 10 = PMCS2 and PMCS1 function as Chip Select
  226    * 01 = PMCS2 functions as Chip Select, PMCS1 functions as address bit 14
  227    * 00 = PMCS2 and PMCS1 function as address bits 15 and 14
  228    *
  229    * bit 5 ALP: Address Latch Polarity bit(4)
  230    * 1 = Active-high (PMALL and PMALH)
  231    * 0 = Active-low (PMALL and PMALH)
  232    *
  233    * bit 4 CS2P: Chip Select 1 Polarity bit(4)
  234    * 1 = Active-high (PMCS2)
  235    * 0 = Active-low (PMCS2)
  236    *
  237    * bit 3 CS1P: Chip Select 0 Polarity bit(4)
  238    * 1 = Active-high (PMCS1)
  239    * 0 = Active-low (PMCS1)
  240    *
  241    * bit 2 Reserved: Write ?0?; ignore read
  242    *
  243    * bit 1 WRSP: Write Strobe Polarity bit
  244    * For Slave Modes and Master mode 2 (PMMODE<9:8> = 00,01,10):
  245    * 1 = Write strobe active-high (PMWR)
  246    * 0 = Write strobe active-low (PMWR)
  247    * For Master mode 1 (PMMODE<9:8> = 11):
  248    * 1 = Enable strobe active-high (PMENB)
  249    * 0 = Enable strobe active-low (PMENB)
  250    *
  251    * bit 0 RDSP: Read Strobe Polarity bit
  252    * For Slave modes and Master mode 2 (PMMODE<9:8> = 00,01,10):
  253    * 1 = Read Strobe active-high (PMRD)
  254    * 0 = Read Strobe active-low (PMRD)
  255    * For Master mode 1 (PMMODE<9:8> = 11):
  256    * 1 = Read/write strobe active-high (PMRD/PMWR)
  257    * 0 = Read/write strobe active-low (PMRD/PMWR)
  258    *
  259    * [1] The pmp.h header file is located in the peripheral include directory
  260    *     /Microchip/MPLAB\ C32\ Suite/pic32mx/include/peripheral/pmp.h).
  261    */
  262   void initialize_display(void)
  263   {
  264      unsigned int control, mode, port, interrupt;
  265   
  266      /*
  267       * PMCON - Initialization pattern for the PMP control register
  268       *
  269       * The definitions of the positions PMCON_*_POSITION are for the
  270       * PIC32MX340F512 made in
  271       * /Microchip/MPLAB\ C32\ Suite/pic32mx/include/proc/p32mx340f512h.h
  272       * To get a listing, simply run
  273       *   $ grep -R PMCON_ /cygdrive/c/Microchip/MPLAB\ C32\ Suite/pic32mx/include/proc/p32mx340f512h.h
  274       *
  275       * The initialization pattern for the PMP control register is composed from
  276       * the following terms:
  277       *     1000000000000000   (=1<<15 = 0x8000), from PMP_ON
  278       *   | 0000001100000000   (=3<<8 = 0x0300), from PMP_READ_WRITE_EN
  279       *   | 0000000000100000   (=1<<5 = 0x0020), from PMP_LATCH_POL_HI
  280       *   | 0000000000000010   (=1<<1 = 0x0002), from PMP_WRITE_POL_HI
  281       *   | 0000000000000001   (=1<<0 = 0x0001), from PMP_READ_POL_HI
  282       *  --------------------
  283       *   = 1000001100100011   (= 0x8323), resulting control pattern
  284       *
  285       * Note: The control setting recommended by Di Lucio [1] is 0x83FB; however,
  286       * this implies that the reserved control bit 2 of the PMCON register is
  287       * set to '1', in contrary to the recommended value of '0' as written in
  288       * the PIC32MX Family Reference Manual, Chapter 13 (DS61128E, page 13-6).
  289       *
  290       * [1] Jasio Di Lucio, "Programming 32-bit microcontrollers in C" (Newnes,
  291       *     Amsterdam, 2008).
  292       */
  293      control = PMP_ON             /* 0x8000: (1 << _PMCON_ON_POSITION), with  _PMCON_ON_POSITION=0x0000000F=15: Configure PMP enabled */
  294              | PMP_IDLE_CON       /* 0x0000: Operate during IDLE (default) */
  295              | PMP_MUX_OFF        /* 0x0000: No 16-bit multilplexing (default) */
  296              | PMP_ST             /* 0x0000: PMP Input buffer type as Schmidt Trigger inputs (default) */
  297              | PMP_READ_WRITE_EN  /* 0x0300: (3 << _PMCON_PTRDEN_POSITION), with _PMCON_PTRDEN_POSITION=0x00000008=8: Configure RD, RD/WR strobe = ON; WR, WR/ENB strobe = ON */
  298              | PMP_LATCH_POL_HI   /* 0x0020: (1 << _PMCON_ALP_POSITION), with _PMCON_ALP_POSITION = 0x00000005 */
  299              | PMP_WRITE_POL_HI   /* 0x0002: (1 << _PMCON_WRSP_POSITION), with _PMCON_WRSP_POSITION = 0x00000001 */
  300              | PMP_READ_POL_HI;   /* 0x0001: (1 << _PMCON_RDSP_POSITION), with _PMCON_RDSP_POSITION = 0x00000000 */
  301                                   /* 0x8323: Result after bitwise OR on the above patterns  */
  302   
  303      /*
  304       * PMMODE - Initialization pattern for the PMP mode
  305       *
  306       * The initialization pattern for the PMP mode register is composed from
  307       * the following terms:
  308       *     0000000000000000   (0x0000), from PMP_IRQ_OFF (default)
  309       *   | 0000000000000000   (0x0000), from PMP_AUTO_ADDR_OFF (default)
  310       *   | 0000000000000000   (0x0000), from PMP_DATA_BUS_8 (default)
  311       *   | 0000001100000000   (=3<<8 = 0x0300), from PMP_MODE_MASTER1
  312       *   | 0000000011000000   (=3<<6 = 0x00c0), from PMP_WAIT_BEG_4
  313       *   | 0000000000111100   (=15<<2 = 0x003c), from PMP_WAIT_MID_15
  314       *   | 0000000000000011   (=3<<0 = 0x0003), from PMP_WAIT_END_4
  315       *  --------------------
  316       *   = 0000001111111111   (=0x03FF), resulting mode pattern
  317       */
  318      mode    = PMP_IRQ_OFF        /* 0x0000: PMP interrupt mode OFF */
  319              | PMP_AUTO_ADDR_OFF  /* 0x0000: Auto Increment/Decrement OFF */
  320              | PMP_DATA_BUS_8     /* 0x0000: Configure 8-bit data mode (default) */
  321              | PMP_MODE_MASTER1   /* 0x0300: (3 << _PMMODE_MODE_POSITION), with _PMMODE_MODE_POSITION = 0x00000008; Configure MASTER mode 1 */
  322              | PMP_WAIT_BEG_4     /* 0x00c0: (3 << _PMMODE_WAITB_POSITION), with _PMMODE_WAITB_POSITION = 0x00000006; Beginning phase wait state as "4 Tpb WAIT" */
  323              | PMP_WAIT_MID_15    /* 0x003c: (15 << _PMMODE_WAITM_POSITION), with _PMMODE_WAITM_POSITION = 0x00000002; Middle phase wait state as "3 Tpb WAIT" */
  324              | PMP_WAIT_END_4;    /* 0x0003: (3 << _PMMODE_WAITE_POSITION), with _PMMODE_WAITE_POSITION = 0x00000000; End phase wait state as "4 Tpb WAIT" */
  325                                   /* 0x03FF: Result after bitwise OR on the above patterns  */
  326   
  327      port    =  PMP_PEN_0;        /* 0x0001: PMA0 enabled as the address line for register selection */
  328   
  329      interrupt=PMP_INT_OFF;       /* 0x0000: No interrupts used here */
  330   
  331      /*
  332       * Employ the mPMPOpen(control, mode, port, interrupt) macro for the actual
  333       * assignment of the control, mode and port patterns to the PMCON (control),
  334       * PMMODE (mode) and PMAEN (port) registers. Also configure any interrupts
  335       * (which, however, are not used here).
  336       * The mPMPOpen(control, mode, port, interrupt) macro is simply defined as
  337       *    #define mPMPOpen(control, mode, port, interrupt)\
  338       *    (\
  339       *        PMCON = (control),\
  340       *        PMMODE = (mode),\
  341       *        PMAEN = (port),\
  342       *        mPMPClearIntFlag(),\
  343       *        mPMPSetIntPriority(((interrupt) & 7)),\
  344       *        mPMPSetIntSubPriority((((interrupt)>> 4) & 3)),\
  345       *        mPMPIntEnable(((interrupt) >> 15))\
  346       *    )
  347       */
  348      mPMPOpen(control, mode, port, interrupt);
  349      delayms(32); /* wait for >30ms */
  350   
  351      /*
  352       * Initiate the DOGM163 display with 8-bit initialization sequence. For details,
  353       * see the Electronic Assembly DOG-M data sheet "DOG Series 3.3V", Issue 1.2010,
  354       * page 7, "Examples for initialisation", available at
  355       * http://www.lcd-module.de/eng/pdf/doma/dog-me.pdf.
  356       *
  357       * Notice that the PMPSetAddress(unsigned int addrs) function (defined as an
  358       * inline function directly in the pmp.h header file) simply consists of the
  359       * two lines
  360       *
  361       *     while(mIsPMPBusy());
  362       *     PMADDR = addrs;
  363       *
  364       * while PMPMasterWrite(unsigned short value) consists of
  365       *
  366       *     while(mIsPMPBusy());
  367       *     PMDIN = value;
  368       */
  369      PMPSetAddress(LCDCMD);/* Select command register */
  370      PMPMasterWrite(DOGM_FUNCTION_SET   /* Function Set:   00100000 (= 0x20) */
  371            |DOGM_EIGHT_BIT_INTERFACE    /* 8 bit data:    |00010000 (= 0x10) */
  372            |DOGM_NUM_LINE_IS_TWO        /* 2 lines:       |00001000 (= 0x08) */
  373            |DOGM_SINGLE_HEIGHT_FONT     /* Single height: |00000000 (= 0x00) */
  374            |DOGM_INSTRUCTION_TABLE_ONE);/* Select Table 1:|00000001 (= 0x01) */
  375      delayms(32); /* >30 us */          /* Result pattern: 00111001 (= 0x39) */
  376   
  377      PMPMasterWrite(DOGM_BIAS_SET       /* Bias set:       00010100 (= 0x14) */
  378         |DOGM_ONE_FIFTH_BIAS            /* 1/5:th bias:   |00000000 (= 0x00) */
  379         |DOGM_THREELINE_BIAS);          /* 3 lines:       |00000001 (= 0x01) */
  380      delayms(32); /* >30 us */          /* Result pattern: 00010101 (= 0x15) */
  381   
  382      PMPMasterWrite(0x55); /* Power Control Set: Booster on, contrast C5, set C4 */
  383      delayms(32);                /* > 30 us */
  384   
  385      PMPMasterWrite(0x6e); /* Follower Control Set: Set voltage follower and gain */
  386      delayms(32);                /* > 30 us */
  387   
  388      PMPMasterWrite(0x72); /* Contrast Set: Set contrast C3, C2, C1 */
  389      delayms(32);                /* > 30 us */
  390   
  391      PMPMasterWrite(0x38); /* Function Set: Switch back to instruction table 0 */
  392      delayms(32);                /* > 30 us */
  393   
  394      PMPMasterWrite(DOGM_DISPLAY_ON  /* Display Settings:    */
  395         |DOGM_ENTIRE_DISPLAY_ON      /* Set display ON, ...  */
  396         |DOGM_CURSOR_OFF             /* ... cursor ON, ...   */
  397         |DOGM_CURSOR_POSITION_OFF);  /* ... cursor blink ON. */
  398      delayms(32);                /* > 30 us */
  399   
  400      PMPMasterWrite(DOGM_CLEAR__DISPLAY); /* Clear display, cursor to home */
  401      delayms(32);                /* > 30 us */
  402      PMPMasterWrite(DOGM_ENTRY_MODE_SET
  403         |DOGM_CURSOR_MOVE_DIR_FORWARD
  404         |DOGM_CURSOR_SHIFT_DIR_DOWN);
  405      delayms(32);                /* > 30 us */
  406   
  407      return;
  408   }
  409   
  410   /*
  411    * The delay: Needed or not?
  412    */
  413   #define READ_DISPLAY_REGISTER_DELAY (7)
  414   char read_display_register(int addr)
  415   {
  416      PMPSetAddress(addr);        /* Select register */
  417   /*   delayms(READ_DISPLAY_REGISTER_DELAY); */
  418      mPMPMasterReadByte();       /* Initiate read sequence */
  419   /*   delayms(READ_DISPLAY_REGISTER_DELAY); */
  420      return(mPMPMasterReadByte()); /* Read actual data */
  421   }
  422   #undef READ_DISPLAY_REGISTER_DELAY
  423   
  424   /*
  425    * Read the address counter of the LCD using R/W=1(high), RS=0(low), implying
  426    * a 0x02 address mask. The address counter is returned in the 7 lowest bits
  427    * of the ACx register, hence the masking by 0x7f=01111111.
  428    */
  429   int read_current_address_counter(void)
  430   {
  431      return(read_display_register(0x02)&0x3F);
  432   }
  433   
  434   /*
  435    * The display_is_busy() routine obtains the status of the display and returns
  436    * 0 if the display is ready to receive commands; otherwise a non-zero value is
  437    * returned. Essentially, the routine reads the LCDCMD register via the PMP and
  438    * masks out the BF bit using R/W=1(high), RS=0(low); see "Read Busy Flag and
  439    * Address" in DOGM data sheet, available at
  440    * http://www.lcd-module.com/eng/pdf/doma/dog-me.pdf
  441    */
  442   char display_is_busy(void)
  443   {
  444      return (read_display_register(LCDCMD)&0x80);
  445   }
  446   
  447   void write_to_display_register(int addr, char c)
  448   {
  449      while (display_is_busy());
  450      while (PMMODEbits.BUSY);
  451      PMPSetAddress(addr);
  452      PMPMasterWrite(c);
  453      return;
  454   }
  455   
  456   void write_character_to_display(char c)
  457   {
  458      write_to_display_register(LCDDATA,c);
  459      col++;
  460      if (col>DOGM163_NUM_COLS) {
  461         col=1;
  462         row++;
  463         if (row>DOGM163_NUM_ROWS) row=1;
  464      }
  465      return;
  466   }
  467   
  468   void send_command_to_display(char c) /*cmdLCD*/
  469   {
  470      write_to_display_register(LCDCMD,c);
  471      return;
  472   }
  473   
  474   void setLCDG(char a)
  475   {
  476      send_command_to_display((a&0x3F)|0x40);
  477      return;
  478   }
  479   
  480   void setLCDC(char a) {
  481      send_command_to_display((a&0x7F)|0x80);
  482      return;
  483   }
  484   
  485   void clear_display(void)
  486   {
  487      send_command_to_display(DOGM_CLEAR__DISPLAY);
  488      row=1;
  489      col=1;
  490      delayms(1);
  491      return;
  492   }
  493   
  494   void move_to_position_on_display(int rowpos, int colpos)
  495   {
  496      int k;
  497   
  498      row=rowpos;
  499      col=colpos;
  500      if (row>DOGM163_NUM_ROWS) row=1;
  501      if (col>DOGM163_NUM_COLS) col=1;
  502      if (row==1) {
  503         k=col-1; /* Avoid multiplication if possible */
  504      } else {
  505         k=col-1+(row-1)*DOGM163_NUM_COLS;
  506      }
  507      send_command_to_display(0x80|k); /* Set address counter to identified position */
  508      return;
  509   }
  510   
  511   /*
  512    * Move to upper left corner of display, but do not wipe out any characters
  513    * already written to the display (in contrary to the clear_display() routine).
  514    */
  515   void move_to_beginning_of_display(void)
  516   {
  517      send_command_to_display(DOGM_RETURN_HOME);
  518      row=1;
  519      col=1;
  520      return;
  521   }
  522   
  523   /*
  524    * Move cursor to the beginning of the current line.
  525    */
  526   void move_to_beginning_of_line(void)
  527   {
  528      move_to_position_on_display(row, 1); /* Same row, first column */
  529      return;
  530   }
  531   
  532   /*
  533    * Move cursor to the beginning of the next line.
  534    */
  535   void advance_to_next_line(void)
  536   {
  537      move_to_position_on_display(row+1, 1); /* Next row, first column */
  538      return;
  539   }
  540   
  541   void write_string_to_display(char *s)
  542   {
  543      char k;
  544   
  545      while(*s!='\0') { /* Until termination character of string */
  546         switch (*s) {
  547   
  548            case '\t': /* Print out DOGM_TAB_LENGTH tab characters */
  549               for (k=0;k<DOGM_TAB_LENGTH;k++)
  550                  write_character_to_display(' ');
  551               break;
  552   
  553            case '\r': /* Carriage return */
  554               move_to_beginning_of_line();
  555               break;
  556   
  557            case '\n': /* Newline; also wipe out rest of line */
  558               for (;col<DOGM163_NUM_COLS;col++) write_character_to_display(' ');
  559               advance_to_next_line();
  560               break;
  561   
  562            default: /* Simply print the character pointed out by *s */
  563               write_character_to_display(*s);
  564               break;
  565         }
  566         s++;
  567      }
  568   }
  569   

Return to previous page

Generated by ::viewsrc::

Last modified Wednesday 15 Feb 2023