1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/Makefile Fri Nov 22 22:13:07 2013 +0000
1.3 @@ -0,0 +1,41 @@
1.4 +# Makefile - Build the PCF8833 display software
1.5 +#
1.6 +# Copyright (C) 2013 Paul Boddie
1.7 +#
1.8 +# This program is free software; you can redistribute it and/or modify
1.9 +# it under the terms of the GNU General Public License as published by
1.10 +# the Free Software Foundation; either version 2 of the License, or
1.11 +# (at your option) any later version.
1.12 +
1.13 +LIBUBB = ../ben-blinkenlights/libubb
1.14 +SYSROOT = ../openwrt-xburst/staging_dir/target-mipsel_eglibc-2.15
1.15 +TOOLBIN = ../openwrt-xburst/staging_dir/toolchain-mipsel_gcc-4.6-linaro_eglibc-2.15/bin
1.16 +
1.17 +ARCH = mipsel-openwrt-linux
1.18 +CC = $(TOOLBIN)/$(ARCH)-gcc
1.19 +
1.20 +CFLAGS = -g -Wall -fPIC -march=mips32 -I$(LIBUBB)/include # -DDEBUG=1
1.21 +LDFLAGS = -lm -lubb -L$(LIBUBB)
1.22 +
1.23 +TARGETS = spin
1.24 +
1.25 +BASICSRC = pcf8833.c
1.26 +
1.27 +SOURCES = $(BASICSRC) spin.c
1.28 +OBJECTS = $(SOURCES:.c=.o)
1.29 +
1.30 +.PHONY: all clean distclean
1.31 +
1.32 +all: $(TARGETS)
1.33 +
1.34 +clean:
1.35 + rm -f $(OBJECTS) $(TARGETS)
1.36 +
1.37 +distclean: clean
1.38 + echo "Nothing else to clean."
1.39 +
1.40 +$(TARGETS): $(OBJECTS)
1.41 + $(CC) $(LDFLAGS) $(OBJECTS) -o $@
1.42 +
1.43 +.c.o:
1.44 + $(CC) -c $(CFLAGS) $< -o $@
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2.2 +++ b/pcf8833.c Fri Nov 22 22:13:07 2013 +0000
2.3 @@ -0,0 +1,247 @@
2.4 +/*
2.5 + * Ben NanoNote communication with the Nu Electronics "Color LCD &
2.6 + * Joystick Shield" featuring a Nokia 6110 and the PCF8833 display
2.7 + * controller.
2.8 + *
2.9 + * http://shieldlist.org/nuelectronics/colorlcd-joystick
2.10 + *
2.11 + * Copyright (C) 2013 Paul Boddie
2.12 + *
2.13 + * This program is free software; you can redistribute it and/or modify
2.14 + * it under the terms of the GNU General Public License as published by
2.15 + * the Free Software Foundation; either version 2 of the License, or
2.16 + * (at your option) any later version.
2.17 + */
2.18 +
2.19 +#include "pcf8833.h"
2.20 +#include <stdio.h>
2.21 +#include <unistd.h>
2.22 +
2.23 +void LCD_send(lcd_sendmode mode, uint8_t data)
2.24 +{
2.25 + spi_begin();
2.26 + spi_send(data, mode);
2.27 + spi_end();
2.28 +}
2.29 +
2.30 +void LCD_send_more_data(uint8_t data)
2.31 +{
2.32 + spi_begin();
2.33 + spi_send(data, LCD_DATA);
2.34 + spi_end();
2.35 +}
2.36 +
2.37 +void spi_init()
2.38 +{
2.39 + OUT(LCD_CS);
2.40 + OUT(LCD_RESET);
2.41 + OUT(LCD_CLK);
2.42 + OUT(LCD_SEND);
2.43 + OUT(LCD_BACKLIGHT);
2.44 +}
2.45 +
2.46 +void spi_begin()
2.47 +{
2.48 + CLR(LCD_CS);
2.49 +}
2.50 +
2.51 +void spi_end()
2.52 +{
2.53 + SET(LCD_CS);
2.54 +}
2.55 +
2.56 +/**
2.57 + * Send the given value via MOSI/SEND.
2.58 + */
2.59 +void spi_send(uint8_t v, lcd_sendmode mode)
2.60 +{
2.61 + uint8_t mask;
2.62 +
2.63 + if (mode == LCD_DATA)
2.64 + {
2.65 + #ifdef DEBUG
2.66 + printf("D");
2.67 + #endif
2.68 + SET(LCD_SEND);
2.69 + }
2.70 + else
2.71 + {
2.72 + #ifdef DEBUG
2.73 + printf("C");
2.74 + #endif
2.75 + CLR(LCD_SEND);
2.76 + }
2.77 +
2.78 + SET(LCD_CLK);
2.79 + CLR(LCD_CLK);
2.80 +
2.81 + for (mask = 0x80; mask; mask >>= 1)
2.82 + {
2.83 + if (v & mask)
2.84 + {
2.85 + #ifdef DEBUG
2.86 + printf("1");
2.87 + #endif
2.88 + SET(LCD_SEND);
2.89 + }
2.90 + else
2.91 + {
2.92 + #ifdef DEBUG
2.93 + printf("0");
2.94 + #endif
2.95 + CLR(LCD_SEND);
2.96 + }
2.97 +
2.98 + SET(LCD_CLK);
2.99 + CLR(LCD_CLK);
2.100 + }
2.101 +
2.102 + #ifdef DEBUG
2.103 + printf("\n");
2.104 + #endif
2.105 +}
2.106 +
2.107 +void LCD_init(void)
2.108 +{
2.109 + /* Perform a hardware reset on the LCD. */
2.110 + /* CS=1, CLK=0, D/C=0 apparently superfluous */
2.111 +
2.112 + SET(LCD_RESET);
2.113 + usleep(50000);
2.114 + CLR(LCD_RESET);
2.115 + usleep(50000);
2.116 + SET(LCD_RESET);
2.117 + usleep(50000);
2.118 +
2.119 + /* CS=1, CLK=1, D/C=1, 10ms, SWRESET, 10ms apparently superfluous */
2.120 +
2.121 + LCD_send(LCD_COMMAND, LCD_SLEEPOUT);
2.122 +
2.123 + /* Configure display memory access. */
2.124 +
2.125 + LCD_send(LCD_COMMAND, LCD_MADCTL);
2.126 + LCD_send(LCD_DATA, LCD_MADCTL_MY_MX);
2.127 +
2.128 + /* Contrast setting (suggested value 0x40), 10ms apparently superfluous */
2.129 +
2.130 + /* Switch the display on. */
2.131 +
2.132 + LCD_send(LCD_COMMAND, LCD_DISPON);
2.133 +
2.134 + /* Configure the display mode/format. */
2.135 + /* 5 == 16bpp */
2.136 +
2.137 + LCD_send(LCD_COMMAND, LCD_COLMOD);
2.138 + LCD_send(LCD_DATA, 0x05);
2.139 +
2.140 + LCD_send(LCD_COMMAND, LCD_NOP);
2.141 +
2.142 + /* Switch the backlight on. */
2.143 +
2.144 + SET(LCD_BACKLIGHT);
2.145 +}
2.146 +
2.147 +void LCD_window(uint8_t xmin, uint8_t ymin, uint8_t xmax, uint8_t ymax)
2.148 +{
2.149 + LCD_send(LCD_COMMAND, LCD_CASET);
2.150 + LCD_send(LCD_DATA, xmin);
2.151 + LCD_send(LCD_DATA, xmax);
2.152 + LCD_send(LCD_COMMAND, LCD_PASET);
2.153 + LCD_send(LCD_DATA, ymin);
2.154 + LCD_send(LCD_DATA, ymax);
2.155 +}
2.156 +
2.157 +void LCD_blit_int(uint16_t colour)
2.158 +{
2.159 + LCD_send_more_data((colour >> 8) & 0xff); /* RGGB -> RG */
2.160 + LCD_send_more_data(colour & 0xff); /* RGGB -> GB */
2.161 +}
2.162 +
2.163 +void LCD_area(uint8_t xmin, uint8_t ymin, uint8_t xmax, uint8_t ymax, uint16_t colour)
2.164 +{
2.165 + uint16_t i, limit = ((xmax - xmin + 1) * (ymax - ymin + 1)) + 1;
2.166 +
2.167 + LCD_window(xmin, ymin, xmax, ymax);
2.168 + LCD_send(LCD_COMMAND, LCD_RAMWR);
2.169 +
2.170 + for (i = 0; i < limit; i++)
2.171 + {
2.172 + LCD_blit_int(colour);
2.173 + }
2.174 +
2.175 + LCD_send(LCD_COMMAND, LCD_NOP);
2.176 +}
2.177 +
2.178 +void LCD_image(int x, int y, uint16_t image[], uint8_t width, uint8_t height)
2.179 +{
2.180 + LCD_image_region(x, y, image, width, height, 0, width, 0, height);
2.181 +}
2.182 +
2.183 +void LCD_image_region(int x, int y, uint16_t image[], uint8_t width, uint8_t height, uint8_t from_x, uint8_t span_x, uint8_t from_y, uint8_t span_y)
2.184 +{
2.185 + uint8_t xmin, ymin, xcmax, ycmax, xcmin, xc, yc;
2.186 + uint16_t xmax, ymax, colour;
2.187 +
2.188 + /* Find the screen ranges for blitting. */
2.189 +
2.190 + xmin = (x < 0) ? 0 : x;
2.191 + ymin = (y < 0) ? 0 : y;
2.192 + xmax = (x + span_x > SCREEN_X_MAX) ? SCREEN_X_MAX : x + span_x - 1;
2.193 + ymax = (y + span_y > SCREEN_Y_MAX) ? SCREEN_Y_MAX : y + span_y - 1;
2.194 +
2.195 + if ((xmin > SCREEN_X_MAX) || (ymin > SCREEN_Y_MAX) || (xmax < 0) || (ymax < 0))
2.196 + {
2.197 + return;
2.198 + }
2.199 +
2.200 + /* Find the image ranges for reading data. */
2.201 +
2.202 + xcmin = (x < 0) ? -x + from_x : from_x;
2.203 + yc = (y < 0) ? -y + from_y : from_y;
2.204 + xcmax = from_x + ((x + span_x > SCREEN_WIDTH) ? SCREEN_WIDTH - x : span_x);
2.205 + ycmax = from_y + ((y + span_y > SCREEN_HEIGHT) ? SCREEN_HEIGHT - y : span_y);
2.206 +
2.207 + LCD_window(xmin, ymin, xmax, ymax);
2.208 + LCD_send(LCD_COMMAND, LCD_RAMWR);
2.209 +
2.210 + /* Reading from the appropriate image ranges, blit to the appropriate
2.211 + screen ranges. */
2.212 +
2.213 + xc = xcmin;
2.214 + while (yc < ycmax)
2.215 + {
2.216 + colour = image[yc * width + xc];
2.217 + LCD_blit_int(colour);
2.218 +
2.219 + xc++;
2.220 + if (xc == xcmax)
2.221 + {
2.222 + xc = xcmin;
2.223 + yc++;
2.224 + }
2.225 + }
2.226 +
2.227 + LCD_send(LCD_COMMAND, LCD_NOP);
2.228 +}
2.229 +
2.230 +void LCD_normal(void)
2.231 +{
2.232 + LCD_send(LCD_COMMAND, LCD_NORON);
2.233 +}
2.234 +
2.235 +void LCD_scroll_area(uint8_t top_fixed, uint8_t scrolling, uint8_t bottom_fixed)
2.236 +{
2.237 + LCD_send(LCD_COMMAND, LCD_VSCRDEF);
2.238 + LCD_send(LCD_DATA, top_fixed);
2.239 + LCD_send(LCD_DATA, scrolling);
2.240 + LCD_send(LCD_DATA, bottom_fixed);
2.241 +}
2.242 +
2.243 +void LCD_scroll_start(uint8_t address)
2.244 +{
2.245 + LCD_send(LCD_COMMAND, LCD_SEP);
2.246 + LCD_send(LCD_DATA, address);
2.247 +}
2.248 +
2.249 +/* vim: tabstop=4 expandtab shiftwidth=4
2.250 + */
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
3.2 +++ b/pcf8833.h Fri Nov 22 22:13:07 2013 +0000
3.3 @@ -0,0 +1,100 @@
3.4 +/*
3.5 + * Ben NanoNote communication with the Nu Electronics "Color LCD &
3.6 + * Joystick Shield" featuring a Nokia 6110 and the PCF8833 display
3.7 + * controller.
3.8 + *
3.9 + * http://shieldlist.org/nuelectronics/colorlcd-joystick
3.10 + *
3.11 + * Copyright (C) 2013 Paul Boddie
3.12 + *
3.13 + * This program is free software; you can redistribute it and/or modify
3.14 + * it under the terms of the GNU General Public License as published by
3.15 + * the Free Software Foundation; either version 2 of the License, or
3.16 + * (at your option) any later version.
3.17 + */
3.18 +
3.19 +#ifndef __PCF8833_H__
3.20 +#define __PCF8833_H__
3.21 +
3.22 +#include <ubb/ubb.h>
3.23 +
3.24 +/* Pin assignments:
3.25 + *
3.26 + * Sniffer UBB Shifters Shield
3.27 + * ------- ---- ---------- ------
3.28 + * DAT2 DAT2
3.29 + * CD DAT3 A2 (#1) B2 10 (SS/CS)
3.30 + * CMD CMD A1 (#1) B1 9 (RESET)
3.31 + * VCC VDD LV HV VIN
3.32 + * CLK CLK A4 (#1) B4 13 (SCLK/CLK)
3.33 + * GND GND GND GND GND
3.34 + * DAT0 DAT0 A3 (#1) B3 11 (MOSI/SEND)
3.35 + * DAT1 DAT1 A1 (#2) B1 8 (BACKLIGHT)
3.36 + */
3.37 +
3.38 +#define LCD_CS UBB_DAT3
3.39 +#define LCD_RESET UBB_CMD
3.40 +#define LCD_CLK UBB_CLK
3.41 +#define LCD_SEND UBB_DAT0
3.42 +#define LCD_BACKLIGHT UBB_DAT1
3.43 +
3.44 +typedef enum {
3.45 + LCD_COMMAND = 0,
3.46 + LCD_DATA = 1
3.47 +} lcd_sendmode;
3.48 +
3.49 +/* Screen constants. */
3.50 +
3.51 +#define SCREEN_WIDTH 132
3.52 +#define SCREEN_X_MAX 131
3.53 +#define SCREEN_HEIGHT 132
3.54 +#define SCREEN_Y_MAX 131
3.55 +
3.56 +/* Commands. */
3.57 +
3.58 +#define LCD_NOP 0x00
3.59 +#define LCD_SWRESET 0x01
3.60 +#define LCD_SLEEPOUT 0x11
3.61 +#define LCD_NORON 0x13
3.62 +#define LCD_SETCON 0x25
3.63 +#define LCD_DISPOFF 0x28
3.64 +#define LCD_DISPON 0x29
3.65 +#define LCD_CASET 0x2a
3.66 +#define LCD_PASET 0x2b
3.67 +#define LCD_RAMWR 0x2c
3.68 +#define LCD_VSCRDEF 0x33
3.69 +#define LCD_SEP 0x37
3.70 +#define LCD_MADCTL 0x36
3.71 +#define LCD_COLMOD 0x3a
3.72 +
3.73 +/* Command-specific constants. */
3.74 +
3.75 +#define LCD_MADCTL_MY_MX 0xc0
3.76 +#define LCD_MADCTL_MY_V 0xa0
3.77 +#define LCD_MADCTL_MY_MX_V 0xe0
3.78 +#define LCD_MADCTL_MX_V 0x60
3.79 +
3.80 +/* Functions. */
3.81 +
3.82 +void spi_init();
3.83 +void spi_begin();
3.84 +void spi_end();
3.85 +void spi_send(uint8_t v, lcd_sendmode mode);
3.86 +
3.87 +void LCD_send(lcd_sendmode mode, uint8_t data);
3.88 +void LCD_send_more_data(uint8_t data);
3.89 +void LCD_send_raw(uint8_t data);
3.90 +void LCD_init(void);
3.91 +void LCD_window(uint8_t xmin, uint8_t ymin, uint8_t xmax, uint8_t ymax);
3.92 +void LCD_blit_int(uint16_t colour);
3.93 +void LCD_area(uint8_t xmin, uint8_t ymin, uint8_t xmax, uint8_t ymax, uint16_t colour);
3.94 +void LCD_image(int x, int y, uint16_t image[], uint8_t width, uint8_t height);
3.95 +void LCD_image_region(int x, int y, uint16_t image[], uint8_t width, uint8_t height, uint8_t from_x, uint8_t span_x, uint8_t from_y, uint8_t span_y);
3.96 +void LCD_normal(void);
3.97 +void LCD_scroll_area(uint8_t top_fixed, uint8_t scrolling, uint8_t bottom_fixed);
3.98 +void LCD_scroll_start(uint8_t address);
3.99 +
3.100 +#endif /* __PCF8833_H__ */
3.101 +
3.102 +/* vim: tabstop=4 expandtab shiftwidth=4
3.103 + */
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
4.2 +++ b/spin.c Fri Nov 22 22:13:07 2013 +0000
4.3 @@ -0,0 +1,84 @@
4.4 +/*
4.5 + * A demonstration of area filling using different orientations.
4.6 + *
4.7 + * Copyright (C) 2013 Paul Boddie
4.8 + *
4.9 + * This program is free software; you can redistribute it and/or modify
4.10 + * it under the terms of the GNU General Public License as published by
4.11 + * the Free Software Foundation; either version 2 of the License, or
4.12 + * (at your option) any later version.
4.13 + */
4.14 +
4.15 +#include "pcf8833.h"
4.16 +#include <stdio.h>
4.17 +#include <unistd.h>
4.18 +#include <signal.h>
4.19 +#include <stdlib.h>
4.20 +
4.21 +/**
4.22 + * Handle termination of the process.
4.23 + */
4.24 +void shutdown(int signum)
4.25 +{
4.26 + printf("Closing...\n");
4.27 + ubb_close(0);
4.28 + exit(1);
4.29 +}
4.30 +
4.31 +/**
4.32 + * Show a pattern on the screen.
4.33 + */
4.34 +void pattern()
4.35 +{
4.36 + LCD_area(0, 0, 131, 131, 0x000);
4.37 + LCD_area(21, 21, 35, 65, 0xf800); LCD_area(21, 66, 35, 110, 0xfbe0);
4.38 + LCD_area(36, 21, 50, 65, 0xffe0); LCD_area(36, 66, 50, 110, 0x7fe0);
4.39 + LCD_area(51, 21, 65, 65, 0x07e0); LCD_area(51, 66, 65, 110, 0x07ef);
4.40 + LCD_area(66, 21, 80, 65, 0x07ff); LCD_area(66, 66, 80, 110, 0x0bff);
4.41 + LCD_area(81, 21, 95, 65, 0x001f); LCD_area(81, 66, 95, 110, 0x781f);
4.42 + LCD_area(96, 21, 110, 65, 0xf81f); LCD_area(96, 66, 110, 110, 0xf80f);
4.43 +}
4.44 +
4.45 +uint8_t states[] = {LCD_MADCTL_MY_MX, LCD_MADCTL_MY_V, 0, LCD_MADCTL_MX_V};
4.46 +
4.47 +int main(int argc, char *argv[])
4.48 +{
4.49 + uint8_t state = 1, times = 10;
4.50 +
4.51 + signal(SIGINT, shutdown);
4.52 +
4.53 + /* Access the 8:10 port. */
4.54 +
4.55 + if (ubb_open(0) < 0) {
4.56 + perror("ubb_open");
4.57 + return 1;
4.58 + }
4.59 +
4.60 + ubb_power(1);
4.61 + printf("Power on.\n");
4.62 +
4.63 + spi_init();
4.64 + LCD_init();
4.65 +
4.66 + printf("Updating...\n");
4.67 + pattern();
4.68 +
4.69 + while (times--)
4.70 + {
4.71 + sleep(1);
4.72 + printf("Updating...\n");
4.73 +
4.74 + LCD_send(LCD_COMMAND, LCD_MADCTL);
4.75 + LCD_send(LCD_DATA, states[state]);
4.76 + pattern();
4.77 +
4.78 + state = (state + 1) % 4;
4.79 + }
4.80 +
4.81 + printf("Closing...\n");
4.82 + ubb_close(0);
4.83 + return 0;
4.84 +}
4.85 +
4.86 +/* vim: tabstop=4 expandtab shiftwidth=4
4.87 + */