Files
retrobsd/sys/pic32/glcd.c
2015-09-14 20:28:31 -07:00

687 lines
15 KiB
C

/*
* Graphical GLCD driver for PIC32.
*
* Copyright (C) 2012 Majenko Technologies <matt@majenko.co.uk>
*
* Permission to use, copy, modify, and distribute this software
* and its documentation for any purpose and without fee is hereby
* granted, provided that the above copyright notice appear in all
* copies and that both that the copyright notice and this
* permission notice and warranty disclaimer appear in supporting
* documentation, and that the name of the author not be used in
* advertising or publicity pertaining to distribution of the
* software without specific, written prior permission.
*
* The author disclaim all warranties with regard to this
* software, including all implied warranties of merchantability
* and fitness. In no event shall the author be liable for any
* special, indirect or consequential damages or any damages
* whatsoever resulting from loss of use, data or profits, whether
* in an action of contract, negligence or other tortious action,
* arising out of or in connection with the use or performance of
* this software.
*/
#include <sys/param.h>
#include <sys/conf.h>
#include <sys/user.h>
#include <sys/ioctl.h>
#include <sys/systm.h>
#include <sys/uio.h>
#include <sys/glcd.h>
#include <sys/debug.h>
#include <sys/kconfig.h>
const struct devspec glcddevs[] = {
{ 0, "glcd0" },
{ 0, 0 }
};
#define _BC(R,B) (R &= ~(1<<B))
#define _BS(R,B) (R |= (1<<B))
unsigned char screen[9][128];
unsigned char mode;
unsigned char screen_x = 0;
unsigned char screen_y = 0;
#define MODE_TEXT 0
#define MODE_LOAD 1
const unsigned char font[] = {
0x00, 0x00, 0x00, 0x00, 0x00,// (space)
0x00, 0x00, 0x5F, 0x00, 0x00,// !
0x00, 0x07, 0x00, 0x07, 0x00,// "
0x14, 0x7F, 0x14, 0x7F, 0x14,// #
0x24, 0x2A, 0x7F, 0x2A, 0x12,// $
0x23, 0x13, 0x08, 0x64, 0x62,// %
0x36, 0x49, 0x55, 0x22, 0x50,// &
0x00, 0x05, 0x03, 0x00, 0x00,// '
0x00, 0x1C, 0x22, 0x41, 0x00,// (
0x00, 0x41, 0x22, 0x1C, 0x00,// )
0x08, 0x2A, 0x1C, 0x2A, 0x08,// *
0x08, 0x08, 0x3E, 0x08, 0x08,// +
0x00, 0x50, 0x30, 0x00, 0x00,// ,
0x08, 0x08, 0x08, 0x08, 0x08,// -
0x00, 0x60, 0x60, 0x00, 0x00,// .
0x20, 0x10, 0x08, 0x04, 0x02,// /
0x3E, 0x51, 0x49, 0x45, 0x3E,// 0
0x00, 0x42, 0x7F, 0x40, 0x00,// 1
0x42, 0x61, 0x51, 0x49, 0x46,// 2
0x21, 0x41, 0x45, 0x4B, 0x31,// 3
0x18, 0x14, 0x12, 0x7F, 0x10,// 4
0x27, 0x45, 0x45, 0x45, 0x39,// 5
0x3C, 0x4A, 0x49, 0x49, 0x30,// 6
0x01, 0x71, 0x09, 0x05, 0x03,// 7
0x36, 0x49, 0x49, 0x49, 0x36,// 8
0x06, 0x49, 0x49, 0x29, 0x1E,// 9
0x00, 0x36, 0x36, 0x00, 0x00,// :
0x00, 0x56, 0x36, 0x00, 0x00,// ;
0x00, 0x08, 0x14, 0x22, 0x41,// <
0x14, 0x14, 0x14, 0x14, 0x14,// =
0x41, 0x22, 0x14, 0x08, 0x00,// >
0x02, 0x01, 0x51, 0x09, 0x06,// ?
0x32, 0x49, 0x79, 0x41, 0x3E,// @
0x7E, 0x11, 0x11, 0x11, 0x7E,// A
0x7F, 0x49, 0x49, 0x49, 0x36,// B
0x3E, 0x41, 0x41, 0x41, 0x22,// C
0x7F, 0x41, 0x41, 0x22, 0x1C,// D
0x7F, 0x49, 0x49, 0x49, 0x41,// E
0x7F, 0x09, 0x09, 0x01, 0x01,// F
0x3E, 0x41, 0x41, 0x51, 0x32,// G
0x7F, 0x08, 0x08, 0x08, 0x7F,// H
0x00, 0x41, 0x7F, 0x41, 0x00,// I
0x20, 0x40, 0x41, 0x3F, 0x01,// J
0x7F, 0x08, 0x14, 0x22, 0x41,// K
0x7F, 0x40, 0x40, 0x40, 0x40,// L
0x7F, 0x02, 0x04, 0x02, 0x7F,// M
0x7F, 0x04, 0x08, 0x10, 0x7F,// N
0x3E, 0x41, 0x41, 0x41, 0x3E,// O
0x7F, 0x09, 0x09, 0x09, 0x06,// P
0x3E, 0x41, 0x51, 0x21, 0x5E,// Q
0x7F, 0x09, 0x19, 0x29, 0x46,// R
0x46, 0x49, 0x49, 0x49, 0x31,// S
0x01, 0x01, 0x7F, 0x01, 0x01,// T
0x3F, 0x40, 0x40, 0x40, 0x3F,// U
0x1F, 0x20, 0x40, 0x20, 0x1F,// V
0x7F, 0x20, 0x18, 0x20, 0x7F,// W
0x63, 0x14, 0x08, 0x14, 0x63,// X
0x03, 0x04, 0x78, 0x04, 0x03,// Y
0x61, 0x51, 0x49, 0x45, 0x43,// Z
0x00, 0x00, 0x7F, 0x41, 0x41,// [
0x02, 0x04, 0x08, 0x10, 0x20,// "\"
0x41, 0x41, 0x7F, 0x00, 0x00,// ]
0x04, 0x02, 0x01, 0x02, 0x04,// ^
0x40, 0x40, 0x40, 0x40, 0x40,// _
0x00, 0x01, 0x02, 0x04, 0x00,// `
0x20, 0x54, 0x54, 0x54, 0x78,// a
0x7F, 0x48, 0x44, 0x44, 0x38,// b
0x38, 0x44, 0x44, 0x44, 0x20,// c
0x38, 0x44, 0x44, 0x48, 0x7F,// d
0x38, 0x54, 0x54, 0x54, 0x18,// e
0x08, 0x7E, 0x09, 0x01, 0x02,// f
0x08, 0x14, 0x54, 0x54, 0x3C,// g
0x7F, 0x08, 0x04, 0x04, 0x78,// h
0x00, 0x44, 0x7D, 0x40, 0x00,// i
0x20, 0x40, 0x44, 0x3D, 0x00,// j
0x00, 0x7F, 0x10, 0x28, 0x44,// k
0x00, 0x41, 0x7F, 0x40, 0x00,// l
0x7C, 0x04, 0x18, 0x04, 0x78,// m
0x7C, 0x08, 0x04, 0x04, 0x78,// n
0x38, 0x44, 0x44, 0x44, 0x38,// o
0x7C, 0x14, 0x14, 0x14, 0x08,// p
0x08, 0x14, 0x14, 0x18, 0x7C,// q
0x7C, 0x08, 0x04, 0x04, 0x08,// r
0x48, 0x54, 0x54, 0x54, 0x20,// s
0x04, 0x3F, 0x44, 0x40, 0x20,// t
0x3C, 0x40, 0x40, 0x20, 0x7C,// u
0x1C, 0x20, 0x40, 0x20, 0x1C,// v
0x3C, 0x40, 0x30, 0x40, 0x3C,// w
0x44, 0x28, 0x10, 0x28, 0x44,// x
0x0C, 0x50, 0x50, 0x50, 0x3C,// y
0x44, 0x64, 0x54, 0x4C, 0x44,// z
0x00, 0x08, 0x36, 0x41, 0x00,// {
0x00, 0x00, 0x7F, 0x00, 0x00,// |
0x00, 0x41, 0x36, 0x08, 0x00,// }
0x08, 0x08, 0x2A, 0x1C, 0x08,// ->
0x08, 0x1C, 0x2A, 0x08, 0x08 // <-
};
/*
* Devices:
* /dev/glcd
*
* Write to the device outputs to GLCD memory as data. Use ioctl() to send
* comands:
*
* ioctl(fd, GLCD_RESET, 0) - reset the GLCD
* ioctl(fd, GLCD_SET_PAGE, page) - set the page address
* ioctl(fd, GLCD_SET_Y, y) - set the page offset
*
*/
int abs(int x)
{
if(x>0)
return x;
return 0-x;
}
void glcd_delay()
{
unsigned long c;
for(c=0; c<200; c++)
asm("nop");
}
void glcd_write_value(int chip, unsigned char data)
{
_BC(LAT_RW, PIN_RW);
_BC(TRIS_DB0, PIN_DB0);
_BC(TRIS_DB1, PIN_DB1);
_BC(TRIS_DB2, PIN_DB2);
_BC(TRIS_DB3, PIN_DB3);
_BC(TRIS_DB4, PIN_DB4);
_BC(TRIS_DB5, PIN_DB5);
_BC(TRIS_DB6, PIN_DB6);
_BC(TRIS_DB7, PIN_DB7);
if(chip==0)
_BS(LAT_CS1, PIN_CS1);
if(chip==1)
_BS(LAT_CS2, PIN_CS2);
if(data & 0b00000001)
_BS(LAT_DB0, PIN_DB0);
else
_BC(LAT_DB0, PIN_DB0);
if(data & 0b00000010)
_BS(LAT_DB1, PIN_DB1);
else
_BC(LAT_DB1, PIN_DB1);
if(data & 0b00000100)
_BS(LAT_DB2, PIN_DB2);
else
_BC(LAT_DB2, PIN_DB2);
if(data & 0b00001000)
_BS(LAT_DB3, PIN_DB3);
else
_BC(LAT_DB3, PIN_DB3);
if(data & 0b00010000)
_BS(LAT_DB4, PIN_DB4);
else
_BC(LAT_DB4, PIN_DB4);
if(data & 0b00100000)
_BS(LAT_DB5, PIN_DB5);
else
_BC(LAT_DB5, PIN_DB5);
if(data & 0b01000000)
_BS(LAT_DB6, PIN_DB6);
else
_BC(LAT_DB6, PIN_DB6);
if(data & 0b10000000)
_BS(LAT_DB7, PIN_DB7);
else
_BC(LAT_DB7, PIN_DB7);
_BS(LAT_E, PIN_E);
glcd_delay();
_BC(LAT_E, PIN_E);
glcd_delay();
if(chip==0)
_BC(LAT_CS1, PIN_CS1);
if(chip==1)
_BC(LAT_CS2, PIN_CS2);
}
void glcd_write_data(int chip, unsigned char value)
{
_BS(LAT_DI, PIN_DI);
glcd_write_value(chip,value);
}
void glcd_write_command(int chip, unsigned char value)
{
_BC(LAT_DI, PIN_DI);
glcd_write_value(chip,value);
}
void glcd_init()
{
_BC(TRIS_DI, PIN_DI);
_BC(TRIS_RW, PIN_RW);
_BC(TRIS_E, PIN_E);
_BC(TRIS_DB0, PIN_DB0);
_BC(TRIS_DB1, PIN_DB1);
_BC(TRIS_DB2, PIN_DB2);
_BC(TRIS_DB3, PIN_DB3);
_BC(TRIS_DB4, PIN_DB4);
_BC(TRIS_DB5, PIN_DB5);
_BC(TRIS_DB6, PIN_DB6);
_BC(TRIS_DB7, PIN_DB7);
_BC(TRIS_CS1, PIN_CS1);
_BC(TRIS_CS2, PIN_CS2);
_BC(TRIS_RES, PIN_RES);
_BC(LAT_E, PIN_E);
_BC(LAT_CS1, PIN_CS1);
_BC(LAT_CS2, PIN_CS2);
_BS(LAT_RES, PIN_RES);
glcd_write_command(0,GLCD_CMD_ON);
glcd_write_command(1,GLCD_CMD_ON);
glcd_write_command(0,GLCD_CMD_START);
glcd_write_command(1,GLCD_CMD_START);
}
void glcd_reset()
{
_BC(LAT_RES, PIN_RES);
glcd_delay();
_BS(LAT_RES, PIN_RES);
glcd_init();
}
void glcd_set_page(int chip, int page)
{
glcd_write_command(chip, GLCD_CMD_SET_PAGE | (page & 0x07));
}
void glcd_set_y(int chip, int y)
{
glcd_write_command(chip, GLCD_CMD_SET_Y | (y & 0x63));
}
void glcd_update()
{
unsigned char x,y;
for(y=0; y<8; y++)
{
glcd_set_page(0,y);
glcd_set_page(1,y);
glcd_set_y(0,0);
glcd_set_y(1,0);
for(x=0; x<64; x++)
{
glcd_write_data(0,screen[y][x]);
glcd_write_data(1,screen[y][x+64]);
}
}
}
void glcd_cls()
{
unsigned char x,y;
for(y=0; y<8; y++)
{
for(x=0; x<128; x++)
{
screen[y][x] = 0;
}
}
screen_x = 0;
screen_y = 0;
}
void glcd_load_page()
{
screen_x = 0;
screen_y = 0;
mode = MODE_LOAD;
}
int
glcd_open (dev, flag, mode)
dev_t dev;
{
int unit = minor(dev);
if (unit >= 2)
return ENXIO;
if (u.u_uid != 0)
return EPERM;
glcd_init();
mode = MODE_TEXT;
DEBUG("glcd%d: Openend\n",unit);
//screen_x = 0;
//screen_y = 0;
return 0;
}
int glcd_close (dev_t dev, int flag, int mode)
{
return 0;
}
int glcd_read (dev_t dev, struct uio *uio, int flag)
{
// TODO
return ENODEV;
}
void glcd_scrollUp(void)
{
unsigned char x, y;
for (y=0; y<9; y++) {
for (x=0; x<128; x++) {
screen[y][x] = screen[y][x]>>1;
if (y < 8)
screen[y][x] |= (screen[y+1][x]<<7);
}
}
}
void glcd_putc(char c)
{
unsigned int cpos;
if (c=='\r') {
screen_x = 0;
return;
}
if (c=='\n') {
screen_y++;
screen_x = 0;
if (screen_y>7) {
screen_y--;
for (cpos=0; cpos<8; cpos++)
glcd_scrollUp();
}
return;
}
if (c == 0x08) {
if (screen_x > 0) {
screen_x -= 6;
} else {
if (screen_y > 0) {
screen_x = 127-7;
screen_y--;
}
}
return;
}
if (c == 0x07) {
return;
}
if (c == 0x0C) {
glcd_cls();
glcd_update();
return;
}
if (screen_x > 127-6) {
screen_x = 0;
screen_y++;
if (screen_y > 7) {
screen_y--;
for (cpos=0; cpos<8; cpos++)
glcd_scrollUp();
}
}
cpos = (c - ' ') * 5;
screen[screen_y][screen_x++] = font[cpos++];
screen[screen_y][screen_x++] = font[cpos++];
screen[screen_y][screen_x++] = font[cpos++];
screen[screen_y][screen_x++] = font[cpos++];
screen[screen_y][screen_x++] = font[cpos++];
screen[screen_y][screen_x++] = 0;
}
void glcd_setPixel(int x, int y)
{
unsigned char row;
unsigned char pixel;
unsigned char mask;
if (x > 127)
return;
if (y > 63)
return;
if (x < 0)
return;
if (y < 0)
return;
row = y>>3;
pixel = y & 0x07;
mask = 1 << pixel;
screen[row][x] |= mask;
}
void glcd_clearPixel(int x, int y)
{
unsigned char row;
unsigned char pixel;
unsigned char mask;
if (x > 127)
return;
if (y > 63)
return;
if (x < 0)
return;
if (y < 0)
return;
row = y>>3;
pixel = y & 0x07;
mask = 1 << pixel;
screen[row][x] &= ~mask;
}
void glcd_drawLine(int x, int y, int x2, int y2, unsigned char ink)
{
int w, h;
int dx1=0, dy1=0, dx2=0, dy2=0;
int longest, shortest;
int numerator;
int i;
w = x2 - x;
h = y2 - y;
if (w < 0) {
dx1 = -1;
dx2 = -1;
} else if (w > 0) {
dx1 = 1;
dx2 = 1;
}
if (h < 0)
dy1 = -1;
else if (h > 0)
dy1 = 1;
longest = abs(w);
shortest = abs(h);
if (! (longest>shortest)) {
longest = abs(h);
shortest = abs(w);
if (h < 0)
dy2 = -1;
else if (h > 0)
dy2 = 1;
dx2 = 0;
}
numerator = longest >> 1;
for (i=0; i<=longest; i++) {
if (ink == 1)
glcd_setPixel(x, y);
else
glcd_clearPixel(x, y);
numerator += shortest;
if (! (numerator < longest)) {
numerator -= longest;
x += dx1;
y += dy1;
} else {
x += dx2;
y += dy2;
}
}
}
void glcd_set_pixel(struct glcd_command *c)
{
glcd_setPixel(c->x1, c->y1);
}
void glcd_clear_pixel(struct glcd_command *c)
{
glcd_clearPixel(c->x1, c->y1);
}
void glcd_draw_line(struct glcd_command *c)
{
glcd_drawLine(c->x1, c->y1, c->x2, c->y2, c->ink);
}
void glcd_draw_box(struct glcd_command *c)
{
glcd_drawLine(c->x1, c->y1, c->x1, c->y2, c->ink);
glcd_drawLine(c->x1, c->y1, c->x2, c->y1, c->ink);
glcd_drawLine(c->x2, c->y2, c->x1, c->y2, c->ink);
glcd_drawLine(c->x2, c->y2, c->x2, c->y1, c->ink);
}
void glcd_draw_filled_box(struct glcd_command *c)
{
unsigned char y;
int y1, y2;
if (c->y1 > c->y2) {
y1 = c->y2;
y2 = c->y1;
} else {
y1 = c->y1;
y2 = c->y2;
}
for (y=y1; y<=y2; y++) {
glcd_drawLine(c->x1, y, c->x2, y, c->ink);
}
}
void glcd_goto_xy(struct glcd_command *c)
{
screen_x = c->x1;
screen_y = c->y1;
}
int glcd_write (dev_t dev, struct uio *uio, int flag)
{
struct iovec *iov;
int i;
iov = uio->uio_iov;
switch (mode) {
case MODE_LOAD:
for (i=0; i<iov->iov_len; i++) {
screen[screen_y][screen_x] = *(iov->iov_base+i);
screen_x++;
if (screen_x == 128) {
screen_y++;
if (screen_y == 8) {
mode = MODE_TEXT;
glcd_update();
}
}
}
break;
case MODE_TEXT:
for (i=0; i<iov->iov_len; i++) {
glcd_putc(*(iov->iov_base+i));
}
glcd_update();
break;
}
return 0;
}
int glcd_ioctl (dev_t dev, register u_int cmd, caddr_t addr, int flag)
{
switch (cmd) {
case GLCD_RESET:
glcd_reset();
break;
case GLCD_UPDATE:
glcd_update();
break;
case GLCD_CLS:
glcd_cls();
break;
case GLCD_LOAD_PAGE:
glcd_load_page();
break;
case GLCD_SET_PIXEL:
glcd_set_pixel((struct glcd_command *)addr);
break;
case GLCD_CLEAR_PIXEL:
glcd_clear_pixel((struct glcd_command *)addr);
break;
case GLCD_LINE:
glcd_draw_line((struct glcd_command *)addr);
break;
case GLCD_BOX:
glcd_draw_box((struct glcd_command *)addr);
break;
case GLCD_FILLED_BOX:
glcd_draw_filled_box((struct glcd_command *)addr);
break;
case GLCD_GOTO_XY:
glcd_goto_xy((struct glcd_command *)addr);
break;
}
return 0;
}
/*
* Test to see if device is present.
* Return true if found and initialized ok.
*/
static int
glcdprobe(config)
struct conf_device *config;
{
int flags = config->dev_flags;
printf("glcd0: flags %#x\n", flags);
return 1;
}
struct driver glcddriver = {
"glcd", glcdprobe,
};