/* * Copyright (C) 2004 by Ole Reinhardt , * Kernelconcepts http://www.kernelconcepts.de * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * For additional information see http://www.ethernut.de/ * */ /*! * \file arch/avr/dev/hd44780_bus.c * \brief Terminal device definitions for memory mapped lcd. * * * This is a terminal device driver for a memory mapped hd44780 compatible * lcd. It is connected to the databus / adressbus. A Chipselect is generated * from /rd, /wr, and the address decoder. It is connected to the lcds enable * signal. A0 is connected to the register select pin and A1 to the read/write * signal. Therefore you'll read from an address with an offset of two * * Have a look to our m-can board if you have questions. * * \verbatim * $Id: hd44780_bus.c 5472 2013-12-06 00:16:28Z olereinhardt $ * \endverbatim */ /* Not ported. */ #ifdef __GNUC__ #include #include #include #include #include #include #include static uint16_t lcd_base = 0x0000; #ifndef LCD_4x20 #ifndef LCD_4x16 #ifndef LCD_2x40 #ifndef LCD_2x20 #ifndef LCD_2x16 #ifndef LCD_2x8 #ifndef LCD_1x20 #ifndef LCD_1x16 #ifndef LCD_1x8 #ifndef KS0073_CONTROLLER #define LCD_2x16 #endif #endif #endif #endif #endif #endif #endif #endif #endif #endif #define LCD_DELAY asm volatile ("nop"); asm volatile ("nop") /*! * \addtogroup xgDisplay */ /*@{*/ /*! * \brief Waits until Busy bit is reset or timeout */ static inline void LcdBusyWait(void) { #if !defined(MMNET02) && !defined(MMNET03) && !defined(MMNET04) && \ !defined(MMNET102) && !defined(MMNET103) && !defined(MMNET104) // wait until LCD busy bit goes to zero // do a read from control register while (*(volatile uint8_t *) (LCD_CTRL_ADDR + LCD_READ_OFFSET) & 1 << LCD_BUSY) LCD_DELAY; LCD_DELAY; LCD_DELAY; LCD_DELAY; LCD_DELAY; LCD_DELAY; LCD_DELAY; LCD_DELAY; LCD_DELAY; LCD_DELAY; LCD_DELAY; LCD_DELAY; LCD_DELAY; #else /* MMnet02 can not read the control register */ NutDelay(5); #endif } /*! * \brief Write databyte to LCD controller over data bus * * \param ch Byte to send. */ static void LcdWriteData(uint8_t data) { LcdBusyWait(); // wait until LCD not busy *(volatile uint8_t *) (LCD_DATA_ADDR) = data; } /*! * \brief Write command byte to LCD controller. */ static void LcdWriteCmd(uint8_t cmd, uint8_t delay) { LcdBusyWait(); // wait until LCD not busy *(volatile uint8_t *) (LCD_CTRL_ADDR) = cmd; } static void LcdSetCursor(uint8_t pos) { uint8_t x = 0; uint8_t y = 0; #ifdef KS0073_CONTROLLER uint8_t offset[4] = {0x00, 0x20, 0x40, 0x60}; y = pos / 20; x = pos % 20; if (y > 3) y = 3; #endif #if defined(LCD_2x40) uint8_t offset [2] = {0x00, 0x40}; y = pos / 40; x = pos % 40; if (y > 1) y = 1; #endif #if defined(LCD_4x20) || defined(LCD_2x20) uint8_t offset [4] = {0x00, 0x40, 0x14, 0x54}; y = pos / 20; x = pos % 20; if (y>3) y=3; #endif #if defined(LCD_4x16) || defined(LCD_2x16) uint8_t offset [4] = {0x00, 0x40, 0x10, 0x50}; y = pos / 16; x = pos % 16; if (y>3) y=3; #endif #if defined(LCD_2x8) uint8_t offset [2] = {0x00, 0x40}; y = pos / 8; x = pos % 8; if (y>1) y=1; #endif #if defined(LCD_1x8) || defined(LCD_1x16) || defined(LCD_1x20) uint8_t offset [1] = { 0x00 }; y = 0; x = pos; #endif pos = x + offset[y]; LcdWriteCmd(1 << LCD_DDRAM | pos, 0); } static void LcdCursorHome(void) { LcdWriteCmd(1 << LCD_HOME, 0); } static void LcdCursorLeft(void) { LcdWriteCmd(1 << LCD_MOVE, 0); } static void LcdCursorRight(void) { LcdWriteCmd(1 << LCD_MOVE | 1 << LCD_MOVE_RIGHT, 0); } static void LcdClear(void) { LcdWriteCmd(1 << LCD_CLR, 0); } static void LcdCursorMode(uint8_t on) { LcdWriteCmd(1 << LCD_ON_CTRL | on ? 1 << LCD_ON_CURSOR : 0x00, 0); } /*! * \brief Initialization of the LCD controller */ static int LcdInit(NUTDEVICE * dev) { lcd_base = dev->dev_base; #ifdef KS0073_CONTROLLER // LCD function set with extended Register Set. LcdWriteCmd((1 << LCD_FUNCTION) | 1 << LCD_FUNCTION_8BIT | (1 << LCD_FUNCTION_RE), 0); NutDelay(50); LcdWriteCmd((1 << LCD_FUNCTION) | 1 << LCD_FUNCTION_8BIT | (1 << LCD_FUNCTION_RE), 0); NutDelay(50); LcdWriteCmd((1 << LCD_FUNCTION) | 1 << LCD_FUNCTION_8BIT | (1 << LCD_FUNCTION_RE), 0); NutDelay(50); LcdWriteCmd((1 << LCD_EXT) | ((((TERMDCB *) dev->dev_dcb)->dcb_nrows > 2) ? (1 << LCD_EXT_4LINES) : 0), 0); LcdWriteCmd((1 << LCD_FUNCTION) | 1 << LCD_FUNCTION_8BIT, 0); #else // LCD function set LcdWriteCmd((1 << LCD_FUNCTION) | 1 << LCD_FUNCTION_8BIT | (1 << LCD_FUNCTION_2LINES), 0); NutDelay(50); LcdWriteCmd((1 << LCD_FUNCTION) | 1 << LCD_FUNCTION_8BIT | (1 << LCD_FUNCTION_2LINES), 0); NutDelay(50); LcdWriteCmd((1 << LCD_FUNCTION) | 1 << LCD_FUNCTION_8BIT | (1 << LCD_FUNCTION_2LINES), 0); NutDelay(50); #endif // clear LCD LcdWriteCmd(1 << LCD_CLR, 0); // set entry mode LcdWriteCmd(1 << LCD_ENTRY_MODE | 1 << LCD_ENTRY_INC, 0); // set display to on LcdWriteCmd(1 << LCD_ON_CTRL | 1 << LCD_ON_DISPLAY, 0); // move cursor to home LcdWriteCmd(1 << LCD_HOME, 0); // set data address to 0 LcdWriteCmd(1 << LCD_DDRAM | 0x00, 0); return 0; } /*! * \brief Terminal device control block structure. */ TERMDCB dcb_term = { LcdInit, /*!< \brief Initialize display subsystem, dss_init. */ LcdWriteData, /*!< \brief Write display character, dss_write. */ LcdWriteCmd, /*!< \brief Write display command, dss_command. */ LcdClear, /*!< \brief Clear display, dss_clear. */ LcdSetCursor, /*!< \brief Set display cursor, dss_set_cursor. */ LcdCursorHome, /*!< \brief Set display cursor home, dss_cursor_home. */ LcdCursorLeft, /*!< \brief Move display cursor left, dss_cursor_left. */ LcdCursorRight, /*!< \brief Move display cursor right, dss_cursor_right. */ LcdCursorMode, /*!< \brief Switch cursor on/off, dss_cursor_mode. */ 0, /*!< \brief Mode flags. */ 0, /*!< \brief Status flags. */ #ifdef KS0073_CONTROLLER 4, /*!< \brief Number of rows. */ 20, /*!< \brief Number of columns per row. */ 20, /*!< \brief Number of visible columns. */ #endif #ifdef LCD_4x20 4, /*!< \brief Number of rows. */ 20, /*!< \brief Number of columns per row. */ 20, /*!< \brief Number of visible columns. */ #endif #ifdef LCD_4x16 4, /*!< \brief Number of rows. */ 16, /*!< \brief Number of columns per row. */ 16, /*!< \brief Number of visible columns. */ #endif #ifdef LCD_2x40 2, /*!< \brief Number of rows. */ 40, /*!< \brief Number of columns per row. */ 40, /*!< \brief Number of visible columns. */ #endif #ifdef LCD_2x20 2, /*!< \brief Number of rows. */ 20, /*!< \brief Number of columns per row. */ 20, /*!< \brief Number of visible columns. */ #endif #ifdef LCD_2x16 2, /*!< \brief Number of rows. */ 16, /*!< \brief Number of columns per row. */ 16, /*!< \brief Number of visible columns. */ #endif #ifdef LCD_2x8 2, /*!< \brief Number of rows. */ 8, /*!< \brief Number of columns per row. */ 8, /*!< \brief Number of visible columns. */ #endif #ifdef LCD_1x20 1, /*!< \brief Number of rows. */ 20, /*!< \brief Number of columns per row. */ 20, /*!< \brief Number of visible columns. */ #endif #ifdef LCD_1x16 1, /*!< \brief Number of rows. */ 16, /*!< \brief Number of columns per row. */ 16, /*!< \brief Number of visible columns. */ #endif #ifdef LCD_1x8 1, /*!< \brief Number of rows. */ 8, /*!< \brief Number of columns per row. */ 8, /*!< \brief Number of visible columns. */ #endif 0, /*!< \brief Cursor row. */ 0, /*!< \brief Cursor column. */ 0 /*!< \brief Display shadow memory. */ }; /*! * \brief LCD device information structure. */ NUTDEVICE devLcdBus = { 0, /*!< Pointer to next device. */ {'l', 'c', 'd', 'b', 'u', 's', 0, 0, 0}, /*!< Unique device name. */ IFTYP_STREAM, /*!< Type of device. */ 0, /*!< Base address. */ 0, /*!< First interrupt number. */ 0, /*!< Interface control block. */ &dcb_term, /*!< Driver control block. */ TermInit, /*!< Driver initialization routine. */ TermIOCtl, /*!< Driver specific control function. */ 0, TermWrite, TermWrite_P, TermOpen, TermClose, 0, 0, /*!< Select function, optional, not yet implemented */ }; #else void keep_icc_happy(void) { } #endif /*@}*/