From 3778fb3dde4e5f58a37af928f4bfcdfdd0309b29 Mon Sep 17 00:00:00 2001 From: Hauke Petersen Date: Tue, 28 Apr 2015 15:56:46 +0200 Subject: [PATCH] drivers: added driver for PCD8544 LCD display --- drivers/Makefile.include | 3 + drivers/include/pcd8544.h | 202 ++++++++++++ drivers/pcd8544/Makefile | 1 + drivers/pcd8544/include/pcd8544_internal.h | 76 +++++ drivers/pcd8544/pcd8544.c | 363 +++++++++++++++++++++ 5 files changed, 645 insertions(+) create mode 100644 drivers/include/pcd8544.h create mode 100644 drivers/pcd8544/Makefile create mode 100644 drivers/pcd8544/include/pcd8544_internal.h create mode 100644 drivers/pcd8544/pcd8544.c diff --git a/drivers/Makefile.include b/drivers/Makefile.include index 08f9fccf56..25a18bd2c7 100644 --- a/drivers/Makefile.include +++ b/drivers/Makefile.include @@ -46,3 +46,6 @@ endif ifneq (,$(filter ina220,$(USEMODULE))) USEMODULE_INCLUDES += $(RIOTBASE)/drivers/ina220/include endif +ifneq (,$(filter pcd8544,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/pcd8544/include +endif diff --git a/drivers/include/pcd8544.h b/drivers/include/pcd8544.h new file mode 100644 index 0000000000..bda2cbc621 --- /dev/null +++ b/drivers/include/pcd8544.h @@ -0,0 +1,202 @@ +/* + * Copyright (C) 2015 Freie Universität Berlin + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @defgroup driver_pcd8544 PCD8544 LCD driver + * @ingroup drivers + * @brief Driver for PCD8544 LCD displays + * + * @{ + * + * @file + * @brief Interface definition for the PCD8544 LCD driver + * + * @author Hauke Petersen + */ + +#ifndef __PDC8544_H +#define __PDC8544_H + +#include + +#include "periph/gpio.h" +#include "periph/spi.h" + +#ifdef __cplusplus + extern "C" { +#endif + +/** + * @brief Definition of display dimensions + * @{ + */ +#define PCD8544_RES_X (84U) /**< pixels per row */ +#define PCD8544_RES_Y (48U) /**< pixels per column */ +#define PCD8544_COLS (14U) /**< characters per row */ +#define PCD8544_ROWS (6U) /**< characters per column */ +/** @} */ + +/** + * @brief Default values for temperature compensation and contrast + * @{ + */ +#define PCD8544_DEFAULT_CONTRAST (45U) +#define PCD8544_DEFAULT_BIAS (3U) +#define PCD8544_DEFAULT_TEMPCOEF (0U) +/** @} */ + +/** + * @brief PCD8544 device descriptor + */ +typedef struct { + spi_t spi; /**< SPI bus the display is connected to */ + gpio_t cs; /**< chip-select pin, low: active */ + gpio_t reset; /**< reset pin, low: active */ + gpio_t mode; /**< mode pin: low: cmd mode, high: data mode */ + uint8_t inverted; /**< internal flag to keep track of inversion state */ +} pcd8544_t; + +/** + * @brief Initialize the given display + * + * @param[in] dev device descriptor of display to use + * @param[in] spi SPI bus the display is connected to + * @param[in] cs GPIO pin that is connected to the CS pin + * @param[in] reset GPIO pin that is connected to the RESET pin + * @param[in] mode GPIO pin that is connected to the MODE pin + * + * @return 0 on success + * @return <0 on error + */ +int pcd8544_init(pcd8544_t *dev, spi_t spi, gpio_t cs, + gpio_t reset, gpio_t mode); + +/** + * @brief Set the contrast for the given display + * + * @note A contrast value of 45 yields good results for 3V3 + * + * @param[in] dev display device descriptor + * @param[in] contrast targeted contrast value [0 - 127] + */ +void pcd8544_set_contrast(pcd8544_t *dev, uint8_t contrast); + +/** + * @brief Set the temperature coefficient for the given display + * + * @note Look at the datasheet for more information + * + * @param[in] dev device descriptor of display to use + * @param[in] coef temperature coefficient to use [0 - 3] + */ +void pcd8544_set_tempcoef(pcd8544_t *dev, uint8_t coef); + +/** + * @brief Set the internal BIAS for the given display + * + * @note Look at the datasheet for more information + * + * @param[in] dev device descriptor of display to use + * @param[in] bias the BIAS to use [0 - 7] + * + */ +void pcd8544_set_bias(pcd8544_t *dev, uint8_t bias); + +/** + * @brief Write an image to memory of the given display + * + * The image must be given as a char array with 504 elements. Each bit in the + * array represents one pixel on the display. Each byte in the array contains + * 8 stacked pixels, from top to bottom. So byte[0] contains the pixels from + * (0,0) to (0,7), byte[1] (1,0) to (1,7) and byte[503] the pixels from + * (83,40) to (83,47) -> see the 'horizontal addressing' section in the + * datasheet. + * + * @param[in] dev device descriptor of display to use + * @param[in] img char array with image data (must be of size := 504) + */ +void pcd8544_write_img(pcd8544_t *dev, const char img[]); + +/** + * @brief Write a single ASCII character to the display + * + * The position of the character is specified in columns (x) and rows (y) + * + * @param[in] dev device descriptor of display to use + * @param[in] x column to put the character [0 - 13] + * @param[in] y row to put the character [0 - 5] + * @param[in] c ASCII code for the character to write + */ +void pcd8544_write_c(pcd8544_t *dev, uint8_t x, uint8_t y, const char c); + +/** + * @brief Write a string to a given position on the display + * + * This function prints a given string to the given position on the display. The + * position is given in terms of columns (x) and rows (y). If a string does not + * fit completely in the given position (it overflows its row), the overflowing + * part of the string is cut off. + * + * @param[in] dev device descriptor of display to use + * @param[in] x starting column of the string [0 - 13] + * @param[in] y row to write the string to [0 - 5] + * @param[in] str string to write to the display + */ +void pcd8544_write_s(pcd8544_t *dev, uint8_t x, uint8_t y, const char* str); + +/** + * @brief Clear the current display (clear the display memory) + * + * @param[in] dev device descriptor of display to use + */ +void pcd8544_clear(pcd8544_t *dev); + +/** + * @brief Invert the display (toggles dark and bright pixels) + * + * @param[in] dev device descriptor of display to use + */ +void pcd8544_invert(pcd8544_t *dev); + +/** + * @brief Get the current inversion status of the display + * + * @param[in] dev device descriptor of display to use + * + * @return 0 -> display is not inverted + * @return 1 -> display is inverted + */ +int pcd8544_is_inverted(pcd8544_t *dev); + +/** + * @brief Power on the display + * + * @param[in] dev device descriptor of display to use + */ +void pcd8544_poweron(pcd8544_t *dev); + +/** + * @brief Poser off the display + * + * @param[in] dev device descriptor of display to use + */ +void pcd8544_poweroff(pcd8544_t *dev); + +/** + * @brief I wonder what this does -> find out! + * + * @param[in] dev device descriptor of display to use + */ +void pcd8544_riot(pcd8544_t *dev); + +#ifdef __cplusplus +} +#endif + +#endif /* __PDC8544_H */ +/** @} */ diff --git a/drivers/pcd8544/Makefile b/drivers/pcd8544/Makefile new file mode 100644 index 0000000000..48422e909a --- /dev/null +++ b/drivers/pcd8544/Makefile @@ -0,0 +1 @@ +include $(RIOTBASE)/Makefile.base diff --git a/drivers/pcd8544/include/pcd8544_internal.h b/drivers/pcd8544/include/pcd8544_internal.h new file mode 100644 index 0000000000..719639e511 --- /dev/null +++ b/drivers/pcd8544/include/pcd8544_internal.h @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2015 Freie Universität Berlin + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup driver_pcd8544 + * + * @{ + * + * @file + * @brief Internal definitions for PCD8544 displays + * + * @author Hauke Petersen + */ + +#ifndef PDC8544_INTERNAL_H +#define PDC8544_INTERNAL_H + +#ifdef __cplusplus + extern "C" { +#endif + +/** + * @brief Delay for resetting the device + */ +#define RESET_DELAY (5000) /* keep reset low for 5ms */ + +/** + * @brief Communication modes: command or data + * @{ + */ +#define MODE_CMD (0) /**< we are sending a command */ +#define MODE_DTA (1) /**< we are sending some data */ +/** @} */ + +/** + * @brief Maximum parameter values + * @{ + */ +#define CONTRAST_MAX (127U) /**< maximum possible contrast value */ +#define TEMP_MAX (3U) /**< maximum possible temp coefficient */ +#define BIAS_MAX (7U) /**< maximum possible bias value */ +/** @} */ + +/** + * @brief Display commands + * @{ + */ +#define CMD_DISABLE (0x24) /**< set LCD into power down mode */ +#define CMD_ENABLE_H (0x20) /**< ON using horizontal addressing */ +#define CMD_ENABLE_V (0x22) /**< ON using vertical addressing */ +#define CMD_EXTENDED (0x21) /**< enter extended instruction set mode */ + +#define CMD_MODE_BLANK (0x08) /**< display nothing */ +#define CMD_MODE_NORMAL (0x0c) /**< display memory content */ +#define CMD_MODE_ALLON (0x09) /**< display 'black' screen */ +#define CMD_MODE_INVERSE (0x0d) /**< display inverted memory content */ + +#define CMD_SET_Y (0x40) /**< set 3-bit y address, OR with Y value */ +#define CMD_SET_X (0x80) /**< set 7-bit x address, OR with X value */ + +#define CMD_EXT_TEMP (0x04) /**< select temperature coefficient */ +#define CMD_EXT_BIAS (0x10) /**< select BIAS value */ +#define CMD_EXT_CONTRAST (0x80) /**< set contrast, OR with [0 - 127] */ +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* PDC8544_INTERNAL_H */ +/** @} */ diff --git a/drivers/pcd8544/pcd8544.c b/drivers/pcd8544/pcd8544.c new file mode 100644 index 0000000000..fbe7c06128 --- /dev/null +++ b/drivers/pcd8544/pcd8544.c @@ -0,0 +1,363 @@ +/* + * Copyright (C) 2015 Freie Universität Berlin + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup drivers_pcd8544 + * @{ + * @file + * @brief Implementation of the SPI driver for the PDC8544 graphics display + * + * @author Hauke Petersen + * @} + */ + +#include +#include + +#include "hwtimer.h" +#include "periph/spi.h" +#include "periph/gpio.h" +#include "pcd8544.h" +#include "pcd8544_internal.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" + +#define ASCII_MIN 0x20 /**< start of ASCII table */ +#define ASCII_MAX 0x7e /**< end of ASCII table */ +#define CHAR_WIDTH (6U) /**< pixel width of a single character */ + +static const uint8_t _ascii[][5] = { + {0x00, 0x00, 0x00, 0x00, 0x00},/* 20 SPACE*/ + {0x00, 0x00, 0x5f, 0x00, 0x00},/* 21 ! */ + {0x00, 0x07, 0x00, 0x07, 0x00},/* 22 " */ + {0x14, 0x7f, 0x14, 0x7f, 0x14},/* 23 # */ + {0x24, 0x2a, 0x7f, 0x2a, 0x12},/* 24 $ */ + {0x23, 0x13, 0x08, 0x64, 0x62},/* 25 % */ + {0x36, 0x49, 0x55, 0x22, 0x50},/* 26 & */ + {0x00, 0x05, 0x03, 0x00, 0x00},/* 27 ' */ + {0x00, 0x1c, 0x22, 0x41, 0x00},/* 28 ( */ + {0x00, 0x41, 0x22, 0x1c, 0x00},/* 29 ) */ + {0x14, 0x08, 0x3e, 0x08, 0x14},/* 2a * */ + {0x08, 0x08, 0x3e, 0x08, 0x08},/* 2b + */ + {0x00, 0x50, 0x30, 0x00, 0x00},/* 2c , */ + {0x08, 0x08, 0x08, 0x08, 0x08},/* 2d - */ + {0x00, 0x60, 0x60, 0x00, 0x00},/* 2e . */ + {0x20, 0x10, 0x08, 0x04, 0x02},/* 2f / */ + {0x3e, 0x51, 0x49, 0x45, 0x3e},/* 30 0 */ + {0x00, 0x42, 0x7f, 0x40, 0x00},/* 31 1 */ + {0x42, 0x61, 0x51, 0x49, 0x46},/* 32 2 */ + {0x21, 0x41, 0x45, 0x4b, 0x31},/* 33 3 */ + {0x18, 0x14, 0x12, 0x7f, 0x10},/* 34 4 */ + {0x27, 0x45, 0x45, 0x45, 0x39},/* 35 5 */ + {0x3c, 0x4a, 0x49, 0x49, 0x30},/* 36 6 */ + {0x01, 0x71, 0x09, 0x05, 0x03},/* 37 7 */ + {0x36, 0x49, 0x49, 0x49, 0x36},/* 38 8 */ + {0x06, 0x49, 0x49, 0x29, 0x1e},/* 39 9 */ + {0x00, 0x36, 0x36, 0x00, 0x00},/* 3a : */ + {0x00, 0x56, 0x36, 0x00, 0x00},/* 3b ; */ + {0x08, 0x14, 0x22, 0x41, 0x00},/* 3c < */ + {0x14, 0x14, 0x14, 0x14, 0x14},/* 3d = */ + {0x00, 0x41, 0x22, 0x14, 0x08},/* 3e > */ + {0x02, 0x01, 0x51, 0x09, 0x06},/* 3f ? */ + {0x32, 0x49, 0x79, 0x41, 0x3e},/* 40 @ */ + {0x7e, 0x11, 0x11, 0x11, 0x7e},/* 41 A */ + {0x7f, 0x49, 0x49, 0x49, 0x36},/* 42 B */ + {0x3e, 0x41, 0x41, 0x41, 0x22},/* 43 C */ + {0x7f, 0x41, 0x41, 0x22, 0x1c},/* 44 D */ + {0x7f, 0x49, 0x49, 0x49, 0x41},/* 45 E */ + {0x7f, 0x09, 0x09, 0x09, 0x01},/* 46 F */ + {0x3e, 0x41, 0x49, 0x49, 0x7a},/* 47 G */ + {0x7f, 0x08, 0x08, 0x08, 0x7f},/* 48 H */ + {0x00, 0x41, 0x7f, 0x41, 0x00},/* 49 I */ + {0x20, 0x40, 0x41, 0x3f, 0x01},/* 4a J */ + {0x7f, 0x08, 0x14, 0x22, 0x41},/* 4b K */ + {0x7f, 0x40, 0x40, 0x40, 0x40},/* 4c L */ + {0x7f, 0x02, 0x0c, 0x02, 0x7f},/* 4d M */ + {0x7f, 0x04, 0x08, 0x10, 0x7f},/* 4e N */ + {0x3e, 0x41, 0x41, 0x41, 0x3e},/* 4f O */ + {0x7f, 0x09, 0x09, 0x09, 0x06},/* 50 P */ + {0x3e, 0x41, 0x51, 0x21, 0x5e},/* 51 Q */ + {0x7f, 0x09, 0x19, 0x29, 0x46},/* 52 R */ + {0x46, 0x49, 0x49, 0x49, 0x31},/* 53 S */ + {0x01, 0x01, 0x7f, 0x01, 0x01},/* 54 T */ + {0x3f, 0x40, 0x40, 0x40, 0x3f},/* 55 U */ + {0x1f, 0x20, 0x40, 0x20, 0x1f},/* 56 V */ + {0x3f, 0x40, 0x38, 0x40, 0x3f},/* 57 W */ + {0x63, 0x14, 0x08, 0x14, 0x63},/* 58 X */ + {0x07, 0x08, 0x70, 0x08, 0x07},/* 59 Y */ + {0x61, 0x51, 0x49, 0x45, 0x43},/* 5a Z */ + {0x00, 0x7f, 0x41, 0x41, 0x00},/* 5b [ */ + {0x02, 0x04, 0x08, 0x10, 0x20},/* 5c \ */ + {0x00, 0x41, 0x41, 0x7f, 0x00},/* 5d ] */ + {0x04, 0x02, 0x01, 0x02, 0x04},/* 5e ^ */ + {0x40, 0x40, 0x40, 0x40, 0x40},/* 5f _ */ + {0x00, 0x01, 0x02, 0x04, 0x00},/* 60 ` */ + {0x20, 0x54, 0x54, 0x54, 0x78},/* 61 a */ + {0x7f, 0x48, 0x44, 0x44, 0x38},/* 62 b */ + {0x38, 0x44, 0x44, 0x44, 0x20},/* 63 c */ + {0x38, 0x44, 0x44, 0x48, 0x7f},/* 64 d */ + {0x38, 0x54, 0x54, 0x54, 0x18},/* 65 e */ + {0x08, 0x7e, 0x09, 0x01, 0x02},/* 66 f */ + {0x0c, 0x52, 0x52, 0x52, 0x3e},/* 67 g */ + {0x7f, 0x08, 0x04, 0x04, 0x78},/* 68 h */ + {0x00, 0x44, 0x7d, 0x40, 0x00},/* 69 i */ + {0x20, 0x40, 0x44, 0x3d, 0x00},/* 6a j */ + {0x7f, 0x10, 0x28, 0x44, 0x00},/* 6b k */ + {0x00, 0x41, 0x7f, 0x40, 0x00},/* 6c l */ + {0x7c, 0x04, 0x18, 0x04, 0x78},/* 6d m */ + {0x7c, 0x08, 0x04, 0x04, 0x78},/* 6e n */ + {0x38, 0x44, 0x44, 0x44, 0x38},/* 6f o */ + {0x7c, 0x14, 0x14, 0x14, 0x08},/* 70 p */ + {0x08, 0x14, 0x14, 0x18, 0x7c},/* 71 q */ + {0x7c, 0x08, 0x04, 0x04, 0x08},/* 72 r */ + {0x48, 0x54, 0x54, 0x54, 0x20},/* 73 s */ + {0x04, 0x3f, 0x44, 0x40, 0x20},/* 74 t */ + {0x3c, 0x40, 0x40, 0x20, 0x7c},/* 75 u */ + {0x1c, 0x20, 0x40, 0x20, 0x1c},/* 76 v */ + {0x3c, 0x40, 0x30, 0x40, 0x3c},/* 77 w */ + {0x44, 0x28, 0x10, 0x28, 0x44},/* 78 x */ + {0x0c, 0x50, 0x50, 0x50, 0x3c},/* 79 y */ + {0x44, 0x64, 0x54, 0x4c, 0x44},/* 7a z */ + {0x00, 0x08, 0x36, 0x41, 0x00},/* 7b { */ + {0x00, 0x00, 0x7f, 0x00, 0x00},/* 7c | */ + {0x00, 0x41, 0x36, 0x08, 0x00},/* 7d } */ + {0x10, 0x08, 0x08, 0x10, 0x08},/* 7e ~ */ +}; + +static const char _riot[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfc, 0x7e, + 0x3e, 0x3e, 0x1f, 0x1f, 0x1f, 0x1f, 0x3f, 0x3e, + 0x7e, 0xfe, 0xfc, 0xf8, 0xf0, 0xe0, 0x80, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, 0xff, + 0x07, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, + 0xc0, 0xc0, 0xc0, 0x80, 0x00, 0x00, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0xe0, 0xe0, 0xf0, 0xf0, 0xf8, 0xfc, 0xfc, + 0x7e, 0x7f, 0x3f, 0x1f, 0x0f, 0x07, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc0, 0xf0, 0xf8, 0xfc, 0xfe, 0x3f, + 0x1f, 0x0f, 0x0f, 0x07, 0x07, 0x07, 0x03, 0x03, + 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, + 0xfe, 0x00, 0x00, 0x00, 0x01, 0x03, 0x03, 0x83, + 0x81, 0x81, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x03, 0x0f, 0x3f, 0xff, 0xff, + 0xfc, 0xf0, 0xe0, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x03, 0x0f, 0x1f, 0x3f, 0x3f, 0x7e, + 0x7c, 0x78, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0x78, + 0x7c, 0x7e, 0x3f, 0x3f, 0x1f, 0x0f, 0x07, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x03, 0x0f, 0x1f, 0x3f, 0x3f, + 0x1f, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + + +static void _write(pcd8544_t *dev, uint8_t is_data, char data) +{ + /* set command or data mode */ + gpio_write(dev->mode, is_data); + /* write byte to LCD */ + spi_acquire(dev->spi); + gpio_clear(dev->cs); + spi_transfer_byte(dev->spi, data, 0); + gpio_set(dev->cs); + spi_release(dev->spi); +} + +static inline void _set_x(pcd8544_t *dev, uint8_t x) +{ + _write(dev, MODE_CMD, CMD_SET_X | x); +} + +static inline void _set_y(pcd8544_t *dev, uint8_t y) +{ + _write(dev, MODE_CMD, CMD_SET_Y | y); +} + +int pcd8544_init(pcd8544_t *dev, spi_t spi, gpio_t cs, gpio_t reset, gpio_t mode) +{ + /* save pin mapping */ + dev->spi = spi; + dev->cs = cs; + dev->reset = reset; + dev->mode = mode; + dev->inverted = 0; + + DEBUG("done setting dev members\n"); + + /* initialze pins */ + gpio_init_out(cs, GPIO_NOPULL); + gpio_init_out(reset, GPIO_NOPULL); + gpio_init_out(mode, GPIO_NOPULL); + DEBUG("done with gpios\n"); + /* clear CS line */ + gpio_set(cs); + DEBUG("done clearing CS line\n"); + /* initialize SPI */ + spi_init_master(spi, SPI_CONF_FIRST_RISING, SPI_SPEED_1MHZ); + DEBUG("done initializing SPI master\n"); + /* reset display */ + gpio_clear(reset); + hwtimer_wait(RESET_DELAY); + gpio_set(reset); + + /* clear display memory */ + pcd8544_clear(dev); + /* write initialization sequence to display */ + pcd8544_set_contrast(dev, PCD8544_DEFAULT_CONTRAST); + pcd8544_set_bias(dev, PCD8544_DEFAULT_BIAS); + pcd8544_set_tempcoef(dev, PCD8544_DEFAULT_TEMPCOEF); + /* enable display */ + _write(dev, MODE_CMD, CMD_ENABLE_H); + _write(dev, MODE_CMD, CMD_MODE_NORMAL); + return 0; +} + +void pcd8544_set_contrast(pcd8544_t *dev, uint8_t contrast) +{ + if (contrast > CONTRAST_MAX) { + contrast = CONTRAST_MAX; + } + _write(dev, MODE_CMD, CMD_EXTENDED); + _write(dev, MODE_CMD, (CMD_EXT_CONTRAST | contrast)); + _write(dev, MODE_CMD, CMD_ENABLE_H); +} + +void pcd8544_set_tempcoef(pcd8544_t *dev, uint8_t coef) +{ + if (coef > TEMP_MAX) { + coef = TEMP_MAX; + } + _write(dev, MODE_CMD, CMD_EXTENDED); + _write(dev, MODE_CMD, (CMD_EXT_TEMP | coef)); + _write(dev, MODE_CMD, CMD_ENABLE_H); +} + +void pcd8544_set_bias(pcd8544_t *dev, uint8_t bias) +{ + if (bias > BIAS_MAX) { + bias = BIAS_MAX; + } + _write(dev, MODE_CMD, CMD_EXTENDED); + _write(dev, MODE_CMD, (CMD_EXT_BIAS | bias)); + _write(dev, MODE_CMD, CMD_ENABLE_H); +} + +void pcd8544_riot(pcd8544_t *dev) +{ + pcd8544_write_img(dev, _riot); +} + +void pcd8544_write_img(pcd8544_t *dev, const char img[]) +{ + /* set initial position */ + _set_x(dev, 0); + _set_y(dev, 0); + /* write image data to display */ + for (int i = 0; i < (PCD8544_RES_X * PCD8544_RES_Y / 8); i++) { + _write(dev, MODE_DTA, img[i]); + } +} + +void pcd8544_write_c(pcd8544_t *dev, uint8_t x, uint8_t y, char c) +{ + /* check position */ + if (x >= PCD8544_COLS || y >= PCD8544_ROWS) { + return ; + } + /* set position */ + _set_x(dev, x * CHAR_WIDTH); + _set_y(dev, y); + /* write char */ + for (int i = 0; i < CHAR_WIDTH - 1; i++) { + _write(dev, MODE_DTA, _ascii[c - ASCII_MIN][i]); + } + _write(dev, MODE_DTA, 0x00); +} + +void pcd8544_write_s(pcd8544_t *dev, uint8_t x, uint8_t y, const char *s) +{ + for (; (*s != '\0') && x < PCD8544_COLS; x++, s++) { + pcd8544_write_c(dev, x, y, *s); + } +} + +void pcd8544_clear(pcd8544_t *dev) +{ + _set_x(dev, 0); + _set_y(dev, 0); + for (int i = 0; i < PCD8544_RES_X * PCD8544_ROWS; i++) { + _write(dev, MODE_DTA, 0x00); + } +} + +void pcd8544_invert(pcd8544_t *dev) +{ + if (dev->inverted) { + _write(dev, MODE_CMD, CMD_MODE_NORMAL); + } + else { + _write(dev, MODE_CMD, CMD_MODE_INVERSE); + } + dev->inverted ^= 0x01; +} + +int pcd8544_is_inverted(pcd8544_t *dev) +{ + return dev->inverted; +} + +void pcd8544_poweron(pcd8544_t *dev) +{ + _write(dev, MODE_CMD, CMD_ENABLE_H); +} + +void pcd8544_poweroff(pcd8544_t *dev) +{ + _write(dev, MODE_CMD, CMD_DISABLE); +}