static void lcd_writech(uint8_t ch, uint8_t row, uint8_t column) { uint8_t addr; /* Set the cursor position. Internally, the HD44780U supports a display * size of up to 2x40 addressed as follows: * * Column 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 ... 39 * Row 0 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f ... 27 * Ro1 1 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f ... 67 */ addr = column; if (row > 0) { addr |= HD4478OU_DDRAM_ROW1; } lcd_wrcommand(HD4478OU_DDRAM_AD(addr)); /* And write the character here */ lcd_wrdata(ch); }
int up_lcd1602_initialize(void) { uint32_t regval; int ret = OK; /* Only initialize the driver once. */ if (!g_lcd1602.initialized) { lcdvdbg("Initializing\n"); /* PMP Master mode configuration */ /* Make sure that interrupts are disabled */ putreg32(INT_PMP, PIC32MX_INT_IEC1CLR); /* Stop and reset the PMP module and clear the mode and control registers. */ putreg32(0, PIC32MX_PMP_MODE); putreg32(0, PIC32MX_PMP_AEN); putreg32(0, PIC32MX_PMP_CON); putreg32(0, PIC32MX_PMP_ADDR); /* Set LCD timing values, PMP master mode 3, 8-bit mode, no address * increment, and no interrupts. */ regval = (PMP_MODE_WAITE_RD(0) | PMP_MODE_WAITM(3) | PMP_MODE_WAITB_1TPB | PMP_MODE_MODE_MODE1 | PMP_MODE_MODE8 | PMP_MODE_INCM_NONE | PMP_MODE_IRQM_NONE); putreg32(regval, PIC32MX_PMP_MODE); /* Enable the PMP for reading and writing * PMRD/PMWR is active high (1=RD; 0=WR) * PMENB is active high. * No chip selects * Address latch is active high * Enable PMRD/PMWR, PMENB, and the PMP. */ regval = (PMP_CON_RDSP | PMP_CON_WRSP | PMP_CON_ALP | PMP_CON_CSF_ADDR1415 | PMP_CON_PTRDEN | PMP_CON_PTWREN | PMP_CON_ADRMUX_NONE | PMP_CON_ON); putreg32(regval, PIC32MX_PMP_CON); /* Configure and enable the LCD */ /* Wait > 15 milliseconds afer Vdd > 4.5V */ up_mdelay(100); /* Select the 8-bit interface. BF cannot be checked before this command. * This needs to be done a few times with some magic delays. */ lcd_wrcommand(HD4478OU_FUNC | HD4478OU_FUNC_DL8D | HD4478OU_FUNC_N1); up_mdelay(50); lcd_wrcommand(HD4478OU_FUNC | HD4478OU_FUNC_DL8D | HD4478OU_FUNC_N1); up_udelay(50); lcd_wrcommand(HD4478OU_FUNC | HD4478OU_FUNC_DL8D | HD4478OU_FUNC_N1); lcd_wrcommand(HD4478OU_FUNC | HD4478OU_FUNC_DL8D | HD4478OU_FUNC_N1); /* Configure the display */ lcd_wrcommand(HD4478OU_DISPLAY); /* Display, cursor, and blink off */ lcd_wrcommand(HD4478OU_CLEAR); /* Clear the display */ lcd_wrcommand(HD4478OU_INPUT | HD4478OU_INPUT_INCR); /* Increment mode */ lcd_wrcommand(HD4478OU_DISPLAY | HD4478OU_DISPLAY_ON); /* Display on, cursor and blink off */ lcd_wrcommand(HD4478OU_DDRAM_AD(0)); /* Select DDRAM RAM AD=0 */ /* Register the LCD device driver */ ret = register_driver("/dev/lcd1602", &g_lcdops, 0644, &g_lcd1602); g_lcd1602.initialized = true; } return ret; }
static void lcd_action(enum slcdcode_e code, uint8_t count) { lcdvdbg("Action: %d count: %d\n", code, count); lcd_dumpstate("BEFORE ACTION"); switch (code) { /* Erasure */ case SLCDCODE_BACKDEL: /* Backspace (backward delete) N characters */ { int tmp; /* If we are at the home position or if the count is zero, then ignore the action */ if (g_lcd1602.curcol < 1 || count < 1) { break; } /* Otherwise, BACKDEL is like moving the cursor back N characters then doing a * forward deletion. Decrement the cursor position and fall through. */ tmp = (int)g_lcd1602.curcol - count; if (tmp < 0) { tmp = 0; count = g_lcd1602.curcol; } /* Save the updated cursor positions */ g_lcd1602.curcol = tmp; } case SLCDCODE_FWDDEL: /* DELete (forward delete) N characters moving text */ if (count > 0) { int nchars; int nmove; int i; /* How many characters are to the right of the cursor position * (including the one at the cursor position)? Then get the * number of characters to move. */ nchars = LCD_NCOLUMNS - g_lcd1602.curcol; nmove = MIN(nchars, count) - 1; /* Move all characters after the current cursor position left by 'nmove' characters */ for (i = g_lcd1602.curcol + nmove; i < LCD_NCOLUMNS - 1; i++) { uint8_t ch = lcd_readch(g_lcd1602.currow, i); lcd_writech(ch, g_lcd1602.currow, i - nmove); } /* Erase the last 'nmove' characters on the display */ for (i = LCD_NCOLUMNS - nmove; i < LCD_NCOLUMNS; i++) { lcd_writech(' ', i, 0); } } break; case SLCDCODE_ERASE: /* Erase N characters from the cursor position */ if (count > 0) { int last; int i; /* Get the last position to clear and make sure that the last * position is on the SLCD. */ last = g_lcd1602.curcol + count - 1; if (last >= LCD_NCOLUMNS) { last = LCD_NCOLUMNS - 1; } /* Erase N characters after the current cursor position left by one */ for (i = g_lcd1602.curcol; i < last; i++) { lcd_writech(' ', g_lcd1602.currow, i); } } break; case SLCDCODE_CLEAR: /* Home the cursor and erase the entire display */ { /* Clear the display */ lcd_wrcommand(HD4478OU_CLEAR); /* And home the cursor */ g_lcd1602.currow = 0; g_lcd1602.curcol = 0; } break; case SLCDCODE_ERASEEOL: /* Erase from the cursor position to the end of line */ { int i; /* Erase characters after the current cursor position to the end of the line */ for (i = g_lcd1602.curcol; i < LCD_NCOLUMNS; i++) { lcd_writech(' ', g_lcd1602.currow, i); } } break; /* Cursor movement */ case SLCDCODE_HOME: /* Cursor home */ { g_lcd1602.currow = 0; g_lcd1602.curcol = 0; } break; case SLCDCODE_END: /* Cursor end */ { g_lcd1602.curcol = LCD_NCOLUMNS - 1; } break; case SLCDCODE_LEFT: /* Cursor left by N characters */ { int tmp = (int)g_lcd1602.curcol - count; /* Don't permit movement past the beginning of the SLCD */ if (tmp < 0) { tmp = 0; } /* Save the new cursor position */ g_lcd1602.curcol = (uint8_t)tmp; } break; case SLCDCODE_RIGHT: /* Cursor right by N characters */ { int tmp = (int)g_lcd1602.curcol + count; /* Don't permit movement past the end of the SLCD */ if (tmp >= LCD_NCOLUMNS) { tmp = LCD_NCOLUMNS - 1; } /* Save the new cursor position */ g_lcd1602.curcol = (uint8_t)tmp; } break; case SLCDCODE_UP: /* Cursor up by N lines */ { int tmp = (int)g_lcd1602.currow - count; /* Don't permit movement past the top of the SLCD */ if (tmp < 0) { tmp = 0; } /* Save the new cursor position */ g_lcd1602.currow = (uint8_t)tmp; } break; case SLCDCODE_DOWN: /* Cursor down by N lines */ { int tmp = (int)g_lcd1602.currow + count; /* Don't permit movement past the bottom of the SLCD */ if (tmp >= LCD_NROWS) { tmp = LCD_NROWS - 1; } /* Save the new cursor position */ g_lcd1602.currow = (uint8_t)tmp; } break; case SLCDCODE_PAGEUP: /* Cursor up by N pages */ case SLCDCODE_PAGEDOWN: /* Cursor down by N pages */ break; /* Not supportable on this SLCD */ /* Blinking */ case SLCDCODE_BLINKSTART: /* Start blinking with current cursor position */ case SLCDCODE_BLINKEND: /* End blinking after the current cursor position */ case SLCDCODE_BLINKOFF: /* Turn blinking off */ break; /* Not implemented */ /* These are actually unreportable errors */ default: case SLCDCODE_NORMAL: /* Not a special keycode */ break; } lcd_dumpstate("AFTER ACTION"); }
int up_lcd1602_initialize(void) { int ret = OK; /* Only initialize the driver once. */ if (!g_lcd1602.initialized) { lcdinfo("Initializing\n"); /* Configure GPIO pins */ putreg16(0, PIC32MX_IOPORTE_TRIS); /* Set DB0-15 as outputs */ pic32mx_configgpio(GPIO_LCD_RS); /* RS: Selects commnand or data */ pic32mx_configgpio(GPIO_LCD_RW); /* RW: Selects read or write */ pic32mx_configgpio(GPIO_LCD_E); /* E: Starts transfer */ /* Configure LCD power in the OFF state */ pic32mx_configgpio(GPIO_LCD_LIGHT); /* K */ pic32mx_configgpio(GPIO_LCD_COMP); /* Vo */ pic32mx_configgpio(GPIO_LCD_PWR); /* Vbuson/AN5/RB5 controls +5V USB */ g_lcd1602.brightness = 0; /* Remember tht the light is off */ /* A small delay is necessary between when GPIO_LCD_E was set up as an * output with initial value of 0 and this operation. That delay should * be well covered by the intervening GPIO configurations. */ pic32mx_gpiowrite(GPIO_LCD_E, true); /* Enable transfer */ /* Configure and enable the LCD */ /* Delay for 4.1MS or more */ up_mdelay(5); /* Select the 8-bit interface. BF cannot be checked before this command. * This needs to be done a few times with some magic delays. * * Function set: 5x7 Style | N=2R | DL=8D */ lcd_wrcommand(HD4478OU_FUNC | HD4478OU_FUNC_F5x7 | HD4478OU_FUNC_N1 | HD4478OU_FUNC_DL8D); up_udelay(100); /* Delay more than 100uS */ lcd_wrcommand(HD4478OU_FUNC | HD4478OU_FUNC_F5x7 | HD4478OU_FUNC_N1 | HD4478OU_FUNC_DL8D); up_udelay(40); /* Delay more than 40uS */ lcd_wrcommand(HD4478OU_FUNC | HD4478OU_FUNC_F5x7 | HD4478OU_FUNC_N1 | HD4478OU_FUNC_DL8D); lcd_waitbusy(); lcd_wrcommand(HD4478OU_FUNC | HD4478OU_FUNC_F5x7 | HD4478OU_FUNC_N1 | HD4478OU_FUNC_DL8D); lcd_waitbusy(); /* Display ON, cursor OFF, blink OFF */ lcd_wrcommand(HD4478OU_DISPLAY | HD4478OU_DISPLAY_ON); lcd_waitbusy(); /* Clear the display and home the cursor */ lcd_wrcommand(HD4478OU_CLEAR); /* Clear display */ lcd_waitbusy(); lcd_wrcommand(HD4478OU_RETURN); /* Return home: AC=0 */ lcd_waitbusy(); /* Entry Mode Set: * * - Increment address by one, * - Shift cursor to right (display is not shifted) */ lcd_wrcommand(HD4478OU_INPUT | HD4478OU_INPUT_INCR); /* Register the LCD device driver */ ret = register_driver("/dev/lcd1602", &g_lcdops, 0644, &g_lcd1602); g_lcd1602.initialized = true; } return ret; }