ST7781 driver compiled.
This commit is contained in:
@@ -81,6 +81,7 @@ pic32/sdramp.c optional dr
|
||||
pic32/sdram.S optional dr
|
||||
pic32/spirams.c optional sr
|
||||
pic32/sramc.c optional rc
|
||||
pic32/st7781.c optional swtft
|
||||
pic32/skel.c optional skel
|
||||
pic32/spi.c optional spi
|
||||
pic32/spi_bus.c optional spi
|
||||
|
||||
881
sys/pic32/st7781.c
Normal file
881
sys/pic32/st7781.c
Normal file
@@ -0,0 +1,881 @@
|
||||
/*
|
||||
* ST7781 TFT LCD driver for PIC32.
|
||||
*
|
||||
* Based on code provided by Smoke And Wires
|
||||
* https://github.com/Smoke-And-Wires/TFT-Shield-Example-Code
|
||||
*
|
||||
* Copyright (C) 2015 Serge Vakulenko <serge@vak.ru>
|
||||
*
|
||||
* 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/tty.h>
|
||||
#include <sys/kconfig.h>
|
||||
#include <sys/gpanel.h>
|
||||
|
||||
/*
|
||||
* Display size.
|
||||
*/
|
||||
#define WIDTH 240
|
||||
#define HEIGHT 320
|
||||
|
||||
/*
|
||||
* Cursor position for text output.
|
||||
*/
|
||||
static int _col, _row;
|
||||
|
||||
/*
|
||||
* Signal mappings:
|
||||
* /RESET - reset and initialize the chip.
|
||||
* /CS - chip select when low.
|
||||
* /RS - data or command selection.
|
||||
* /RD - read operation enable.
|
||||
* /WR - write operation enable.
|
||||
*/
|
||||
#define RST_IDLE() LAT_SET(LCD_RST_PORT) = 1<<LCD_RST_PIN
|
||||
#define RST_ACTIVE() LAT_CLR(LCD_RST_PORT) = 1<<LCD_RST_PIN
|
||||
|
||||
#define CS_IDLE() LAT_SET(LCD_CS_PORT) = 1<<LCD_CS_PIN
|
||||
#define CS_ACTIVE() LAT_CLR(LCD_CS_PORT) = 1<<LCD_CS_PIN
|
||||
|
||||
#define RS_DATA() LAT_SET(LCD_RS_PORT) = 1<<LCD_CS_PIN
|
||||
#define RS_COMMAND() LAT_CLR(LCD_RS_PORT) = 1<<LCD_CS_PIN
|
||||
|
||||
#define RD_IDLE() LAT_SET(LCD_RD_PORT) = 1<<LCD_RD_PIN
|
||||
#define RD_ACTIVE() LAT_CLR(LCD_RD_PORT) = 1<<LCD_RD_PIN
|
||||
|
||||
#define WR_IDLE() LAT_SET(LCD_WR_PORT) = 1<<LCD_WR_PIN
|
||||
#define WR_ACTIVE() LAT_CLR(LCD_WR_PORT) = 1<<LCD_WR_PIN
|
||||
#define WR_STROBE() { WR_ACTIVE(); WR_IDLE(); }
|
||||
|
||||
/*
|
||||
* Set direction of data bus as output.
|
||||
*/
|
||||
static void setWriteDir()
|
||||
{
|
||||
TRIS_CLR(LCD_D0_PORT) = 1 << LCD_D0_PIN;
|
||||
TRIS_CLR(LCD_D1_PORT) = 1 << LCD_D1_PIN;
|
||||
TRIS_CLR(LCD_D2_PORT) = 1 << LCD_D2_PIN;
|
||||
TRIS_CLR(LCD_D3_PORT) = 1 << LCD_D3_PIN;
|
||||
TRIS_CLR(LCD_D4_PORT) = 1 << LCD_D4_PIN;
|
||||
TRIS_CLR(LCD_D5_PORT) = 1 << LCD_D5_PIN;
|
||||
TRIS_CLR(LCD_D6_PORT) = 1 << LCD_D6_PIN;
|
||||
TRIS_CLR(LCD_D7_PORT) = 1 << LCD_D7_PIN;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set direction of data bus as input.
|
||||
*/
|
||||
static void setReadDir()
|
||||
{
|
||||
TRIS_SET(LCD_D0_PORT) = 1 << LCD_D0_PIN;
|
||||
TRIS_SET(LCD_D1_PORT) = 1 << LCD_D1_PIN;
|
||||
TRIS_SET(LCD_D2_PORT) = 1 << LCD_D2_PIN;
|
||||
TRIS_SET(LCD_D3_PORT) = 1 << LCD_D3_PIN;
|
||||
TRIS_SET(LCD_D4_PORT) = 1 << LCD_D4_PIN;
|
||||
TRIS_SET(LCD_D5_PORT) = 1 << LCD_D5_PIN;
|
||||
TRIS_SET(LCD_D6_PORT) = 1 << LCD_D6_PIN;
|
||||
TRIS_SET(LCD_D7_PORT) = 1 << LCD_D7_PIN;
|
||||
}
|
||||
|
||||
/*
|
||||
* Send a byte to the data bus.
|
||||
*/
|
||||
static void writeByte(unsigned value)
|
||||
{
|
||||
if (value & 1) {
|
||||
LAT_SET(LCD_D0_PORT) = 1 << LCD_D0_PIN;
|
||||
} else {
|
||||
LAT_CLR(LCD_D0_PORT) = 1 << LCD_D0_PIN;
|
||||
}
|
||||
if (value & 2) {
|
||||
LAT_SET(LCD_D1_PORT) = 1 << LCD_D1_PIN;
|
||||
} else {
|
||||
LAT_CLR(LCD_D1_PORT) = 1 << LCD_D1_PIN;
|
||||
}
|
||||
if (value & 4) {
|
||||
LAT_SET(LCD_D2_PORT) = 1 << LCD_D2_PIN;
|
||||
} else {
|
||||
LAT_CLR(LCD_D2_PORT) = 1 << LCD_D2_PIN;
|
||||
}
|
||||
if (value & 8) {
|
||||
LAT_SET(LCD_D3_PORT) = 1 << LCD_D3_PIN;
|
||||
} else {
|
||||
LAT_CLR(LCD_D3_PORT) = 1 << LCD_D3_PIN;
|
||||
}
|
||||
if (value & 0x10) {
|
||||
LAT_SET(LCD_D4_PORT) = 1 << LCD_D4_PIN;
|
||||
} else {
|
||||
LAT_CLR(LCD_D4_PORT) = 1 << LCD_D4_PIN;
|
||||
}
|
||||
if (value & 0x20) {
|
||||
LAT_SET(LCD_D5_PORT) = 1 << LCD_D5_PIN;
|
||||
} else {
|
||||
LAT_CLR(LCD_D5_PORT) = 1 << LCD_D5_PIN;
|
||||
}
|
||||
if (value & 0x40) {
|
||||
LAT_SET(LCD_D6_PORT) = 1 << LCD_D6_PIN;
|
||||
} else {
|
||||
LAT_CLR(LCD_D6_PORT) = 1 << LCD_D6_PIN;
|
||||
}
|
||||
if (value & 0x80) {
|
||||
LAT_SET(LCD_D7_PORT) = 1 << LCD_D7_PIN;
|
||||
} else {
|
||||
LAT_CLR(LCD_D7_PORT) = 1 << LCD_D7_PIN;
|
||||
}
|
||||
WR_STROBE();
|
||||
}
|
||||
|
||||
/*
|
||||
* Delay for a given number of nanoseconds.
|
||||
*/
|
||||
void ndelay(unsigned nsec)
|
||||
{
|
||||
/* Four instructions (cycles) per loop. */
|
||||
unsigned nloops = (nsec * (CPU_KHZ/1000)) / 1000 / 4;
|
||||
|
||||
while (nloops-- > 0)
|
||||
asm volatile ("nop");
|
||||
}
|
||||
|
||||
static unsigned readByte()
|
||||
{
|
||||
unsigned value = 0;
|
||||
|
||||
/* Pixel read operations require a minimum 400 nS delay
|
||||
* from RD_ACTIVE to polling the input pins. */
|
||||
RD_ACTIVE();
|
||||
ndelay(400);
|
||||
if (PORT_VAL(LCD_D0_PORT) & (1 << LCD_D0_PIN)) value |= 1;
|
||||
if (PORT_VAL(LCD_D1_PORT) & (1 << LCD_D1_PIN)) value |= 2;
|
||||
if (PORT_VAL(LCD_D2_PORT) & (1 << LCD_D2_PIN)) value |= 4;
|
||||
if (PORT_VAL(LCD_D3_PORT) & (1 << LCD_D3_PIN)) value |= 8;
|
||||
if (PORT_VAL(LCD_D4_PORT) & (1 << LCD_D4_PIN)) value |= 0x10;
|
||||
if (PORT_VAL(LCD_D5_PORT) & (1 << LCD_D5_PIN)) value |= 0x20;
|
||||
if (PORT_VAL(LCD_D6_PORT) & (1 << LCD_D6_PIN)) value |= 0x40;
|
||||
if (PORT_VAL(LCD_D7_PORT) & (1 << LCD_D7_PIN)) value |= 0x80;
|
||||
RD_IDLE();
|
||||
return value;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write a 16-bit value to the ST7781 register.
|
||||
*/
|
||||
static void writeReg(unsigned reg, unsigned value)
|
||||
{
|
||||
RS_COMMAND();
|
||||
writeByte(reg >> 8);
|
||||
writeByte(reg);
|
||||
RS_DATA();
|
||||
writeByte(value >> 8);
|
||||
writeByte(value);
|
||||
}
|
||||
|
||||
static void initDisplay()
|
||||
{
|
||||
/*
|
||||
* Set all control bits to high (idle).
|
||||
* Signals are active low.
|
||||
*/
|
||||
CS_IDLE();
|
||||
WR_IDLE();
|
||||
RD_IDLE();
|
||||
RST_IDLE();
|
||||
|
||||
/* Enable outputs. */
|
||||
TRIS_CLR(LCD_CS_PORT) = 1 << LCD_CS_PIN;
|
||||
TRIS_CLR(LCD_RS_PORT) = 1 << LCD_RS_PIN;
|
||||
TRIS_CLR(LCD_WR_PORT) = 1 << LCD_WR_PIN;
|
||||
TRIS_CLR(LCD_RD_PORT) = 1 << LCD_RD_PIN;
|
||||
TRIS_CLR(LCD_RST_PORT) = 1 << LCD_RST_PIN;
|
||||
setWriteDir();
|
||||
|
||||
/* Reset the chip. */
|
||||
RST_ACTIVE();
|
||||
udelay(2000);
|
||||
RST_IDLE();
|
||||
|
||||
/* Data transfer sync. */
|
||||
CS_ACTIVE();
|
||||
RS_COMMAND();
|
||||
writeByte(0x00);
|
||||
WR_STROBE(); // Three extra 0x00s
|
||||
WR_STROBE();
|
||||
WR_STROBE();
|
||||
CS_IDLE();
|
||||
|
||||
/* Initialization of LCD controller. */
|
||||
CS_ACTIVE();
|
||||
writeReg(0x01, 0x0100);
|
||||
writeReg(0x02, 0x0700);
|
||||
writeReg(0x03, 0x1030);
|
||||
writeReg(0x08, 0x0302);
|
||||
writeReg(0x09, 0x0000);
|
||||
writeReg(0x0A, 0x0008);
|
||||
|
||||
/* Power control registers. */
|
||||
writeReg(0x10, 0x0790);
|
||||
writeReg(0x11, 0x0005);
|
||||
writeReg(0x12, 0x0000);
|
||||
writeReg(0x13, 0x0000);
|
||||
//udelay(50000);
|
||||
|
||||
/* Power supply startup 1 settings. */
|
||||
writeReg(0x10, 0x12B0);
|
||||
//udelay(50000);
|
||||
writeReg(0x11, 0x0007);
|
||||
//udelay(50000);
|
||||
|
||||
/* Power supply startup 2 settings. */
|
||||
writeReg(0x12, 0x008C);
|
||||
writeReg(0x13, 0x1700);
|
||||
writeReg(0x29, 0x0022);
|
||||
//udelay(50000);
|
||||
|
||||
/* Gamma cluster settings. */
|
||||
writeReg(0x30, 0x0000);
|
||||
writeReg(0x31, 0x0505);
|
||||
writeReg(0x32, 0x0205);
|
||||
writeReg(0x35, 0x0206);
|
||||
writeReg(0x36, 0x0408);
|
||||
writeReg(0x37, 0x0000);
|
||||
writeReg(0x38, 0x0504);
|
||||
writeReg(0x39, 0x0206);
|
||||
writeReg(0x3C, 0x0206);
|
||||
writeReg(0x3D, 0x0408);
|
||||
|
||||
/* Display window 240*320. */
|
||||
writeReg(0x50, 0x0000);
|
||||
writeReg(0x51, 0x00EF);
|
||||
writeReg(0x52, 0x0000);
|
||||
writeReg(0x53, 0x013F);
|
||||
|
||||
/* Frame rate settings. */
|
||||
writeReg(0x60, 0xA700);
|
||||
writeReg(0x61, 0x0001);
|
||||
writeReg(0x90, 0x0033); // RTNI setting
|
||||
|
||||
/* Display on. */
|
||||
writeReg(0x07, 0x0133);
|
||||
#if 0
|
||||
writeReg(0x01, 0x0100);
|
||||
writeReg(0x02, 0x0700);
|
||||
writeReg(0x03, 0x1030);
|
||||
writeReg(0x08, 0x0302);
|
||||
writeReg(0x09, 0x0000);
|
||||
writeReg(0x0A, 0x0008);
|
||||
|
||||
/* Power control registers. */
|
||||
writeReg(0x10, 0x0790);
|
||||
writeReg(0x11, 0x0005);
|
||||
writeReg(0x12, 0x0000);
|
||||
writeReg(0x13, 0x0000);
|
||||
//udelay(50000);
|
||||
|
||||
/* Power supply startup 1 settings. */
|
||||
writeReg(0x10, 0x12B0);
|
||||
//udelay(50000);
|
||||
writeReg(0x11, 0x0007);
|
||||
//udelay(50000);
|
||||
|
||||
/* Power supply startup 2 settings. */
|
||||
writeReg(0x12, 0x008C);
|
||||
writeReg(0x13, 0x1700);
|
||||
writeReg(0x29, 0x0022);
|
||||
//udelay(50000);
|
||||
|
||||
/* Gamma cluster settings. */
|
||||
writeReg(0x30, 0x0000);
|
||||
writeReg(0x31, 0x0505);
|
||||
writeReg(0x32, 0x0205);
|
||||
writeReg(0x35, 0x0206);
|
||||
writeReg(0x36, 0x0408);
|
||||
writeReg(0x37, 0x0000);
|
||||
writeReg(0x38, 0x0504);
|
||||
writeReg(0x39, 0x0206);
|
||||
writeReg(0x3C, 0x0206);
|
||||
writeReg(0x3D, 0x0408);
|
||||
|
||||
/* Display window 240*320. */
|
||||
writeReg(0x50, 0x0000);
|
||||
writeReg(0x51, 0x00EF);
|
||||
writeReg(0x52, 0x0000);
|
||||
writeReg(0x53, 0x013F);
|
||||
|
||||
/* Frame rate settings. */
|
||||
writeReg(0x60, 0xA700);
|
||||
writeReg(0x61, 0x0001);
|
||||
writeReg(0x90, 0x0033); // RTNI setting
|
||||
|
||||
/* Display on. */
|
||||
writeReg(0x07, 0x0133);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void setAddrWindow(int x0, int y0, int x1, int y1)
|
||||
{
|
||||
/* Set address window. */
|
||||
CS_ACTIVE();
|
||||
writeReg(0x50, x0);
|
||||
writeReg(0x51, x1);
|
||||
writeReg(0x52, y0);
|
||||
writeReg(0x53, y1);
|
||||
|
||||
/* Set address counter to top left. */
|
||||
writeReg(0x20, x0);
|
||||
writeReg(0x21, y0);
|
||||
CS_IDLE();
|
||||
}
|
||||
|
||||
/*
|
||||
* Draw a pixel.
|
||||
*/
|
||||
static void setPixel(int x, int y, int color)
|
||||
{
|
||||
if (x < 0 || x >= WIDTH || y < 0 || y >= HEIGHT)
|
||||
return;
|
||||
CS_ACTIVE();
|
||||
writeReg(0x0020, x);
|
||||
writeReg(0x0021, y);
|
||||
writeReg(0x0022, color);
|
||||
CS_IDLE();
|
||||
}
|
||||
|
||||
/*
|
||||
* Fast block fill operation.
|
||||
* Requires setAddrWindow() has previously been called to set
|
||||
* the fill bounds.
|
||||
* 'npixels' is inclusive, MUST be >= 1.
|
||||
*/
|
||||
static void flood(int color, int npixels)
|
||||
{
|
||||
unsigned blocks, i;
|
||||
unsigned hi = color >> 8,
|
||||
lo = color;
|
||||
|
||||
CS_ACTIVE();
|
||||
RS_COMMAND();
|
||||
writeByte(0x00); // High byte of GRAM register...
|
||||
writeByte(0x22); // Write data to GRAM
|
||||
|
||||
/* Write first pixel normally, decrement counter by 1. */
|
||||
RS_DATA();
|
||||
writeByte(hi);
|
||||
writeByte(lo);
|
||||
npixels--;
|
||||
|
||||
/* 64 pixels/block. */
|
||||
blocks = npixels >> 6;
|
||||
if (hi == lo) {
|
||||
// High and low bytes are identical. Leave prior data
|
||||
// on the port(s) and just toggle the write strobe.
|
||||
while (blocks--) {
|
||||
// 64 pixels/block / 4 pixels/pass
|
||||
for (i = 16; i > 0; i--) {
|
||||
// 2 bytes/pixel x 4 pixels
|
||||
WR_STROBE(); WR_STROBE(); WR_STROBE(); WR_STROBE();
|
||||
WR_STROBE(); WR_STROBE(); WR_STROBE(); WR_STROBE();
|
||||
}
|
||||
}
|
||||
// Fill any remaining pixels (1 to 64)
|
||||
for (i = npixels & 63; i > 0; i--) {
|
||||
WR_STROBE();
|
||||
WR_STROBE();
|
||||
}
|
||||
} else {
|
||||
while (blocks--) {
|
||||
// 64 pixels/block / 4 pixels/pass
|
||||
for (i = 16; i > 0; i--) {
|
||||
writeByte(hi); writeByte(lo); writeByte(hi); writeByte(lo);
|
||||
writeByte(hi); writeByte(lo); writeByte(hi); writeByte(lo);
|
||||
}
|
||||
}
|
||||
for (i = npixels & 63; i > 0; i--) {
|
||||
writeByte(hi);
|
||||
writeByte(lo);
|
||||
}
|
||||
}
|
||||
CS_IDLE();
|
||||
}
|
||||
|
||||
/*
|
||||
* Fill a rectangle with specified color.
|
||||
*/
|
||||
static void fillRectangle(int x0, int y0, int x1, int y1, int color)
|
||||
{
|
||||
if (x0 < 0) x0 = 0;
|
||||
if (y0 < 0) x0 = 0;
|
||||
if (x1 < 0) x1 = 0;
|
||||
if (y1 < 0) x1 = 0;
|
||||
if (x0 >= WIDTH) x0 = WIDTH-1;
|
||||
if (x1 >= WIDTH) x1 = WIDTH-1;
|
||||
if (y0 >= HEIGHT) y0 = HEIGHT-1;
|
||||
if (y1 >= HEIGHT) y1 = HEIGHT-1;
|
||||
|
||||
if (x1 < x0) {
|
||||
int t = x0;
|
||||
x0 = x1;
|
||||
x1 = t;
|
||||
}
|
||||
if (y1 < y0) {
|
||||
int t = y0;
|
||||
y0 = y1;
|
||||
y1 = t;
|
||||
}
|
||||
setAddrWindow(x0, y0, x1, y1);
|
||||
flood(color, (x1 - x0 + 1) * (y1 - y0 + 1));
|
||||
setAddrWindow(0, 0, WIDTH-1, HEIGHT-1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Fill a rectangle with user data.
|
||||
*/
|
||||
static void drawImage(int x, int y, int width, int height,
|
||||
const unsigned short *data)
|
||||
{
|
||||
unsigned cnt = width * height;
|
||||
int color;
|
||||
|
||||
setAddrWindow(x, y, x + width - 1, y + height - 1);
|
||||
CS_ACTIVE();
|
||||
RS_COMMAND();
|
||||
writeByte(0x00);
|
||||
writeByte(0x22);
|
||||
RS_DATA();
|
||||
while (cnt--) {
|
||||
color = *data++;
|
||||
writeByte(color >> 8);
|
||||
writeByte(color);
|
||||
}
|
||||
CS_IDLE();
|
||||
}
|
||||
|
||||
/*
|
||||
* Draw a line.
|
||||
*/
|
||||
static void drawLine(int x0, int y0, int x1, int y1, int color)
|
||||
{
|
||||
int dx, dy, stepx, stepy, fraction;
|
||||
|
||||
if (x0 == x1 || y0 == y1) {
|
||||
fillRectangle(x0, y0, x1, y1, color);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Use Bresenham's line algorithm. */
|
||||
dy = y1 - y0;
|
||||
if (dy < 0) {
|
||||
dy = -dy;
|
||||
stepy = -1;
|
||||
} else {
|
||||
stepy = 1;
|
||||
}
|
||||
dx = x1 - x0;
|
||||
if (dx < 0) {
|
||||
dx = -dx;
|
||||
stepx = -1;
|
||||
} else {
|
||||
stepx = 1;
|
||||
}
|
||||
dy <<= 1; /* dy is now 2*dy */
|
||||
dx <<= 1; /* dx is now 2*dx */
|
||||
setPixel(x0, y0, color);
|
||||
if (dx > dy) {
|
||||
fraction = dy - (dx >> 1); /* same as 2*dy - dx */
|
||||
while (x0 != x1) {
|
||||
if (fraction >= 0) {
|
||||
y0 += stepy;
|
||||
fraction -= dx; /* same as fraction -= 2*dx */
|
||||
}
|
||||
x0 += stepx;
|
||||
fraction += dy; /* same as fraction -= 2*dy */
|
||||
setPixel(x0, y0, color);
|
||||
}
|
||||
} else {
|
||||
fraction = dx - (dy >> 1);
|
||||
while (y0 != y1) {
|
||||
if (fraction >= 0) {
|
||||
x0 += stepx;
|
||||
fraction -= dy;
|
||||
}
|
||||
y0 += stepy;
|
||||
fraction += dx;
|
||||
setPixel(x0, y0, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Draw a rectangular frame.
|
||||
*/
|
||||
static void drawFrame(int x0, int y0, int x1, int y1, int color)
|
||||
{
|
||||
fillRectangle(x0, y0, x1, y0, color);
|
||||
fillRectangle(x0, y1, x1, y1, color);
|
||||
fillRectangle(x0, y0, x0, y1, color);
|
||||
fillRectangle(x1, y0, x1, y1, color);
|
||||
}
|
||||
|
||||
/*
|
||||
* Draw a circle.
|
||||
*/
|
||||
static void drawCircle(int x0, int y0, int radius, int color)
|
||||
{
|
||||
int f = 1 - radius;
|
||||
int ddF_x = 0;
|
||||
int ddF_y = -2 * radius;
|
||||
int x = 0;
|
||||
int y = radius;
|
||||
|
||||
setPixel(x0, y0 + radius, color);
|
||||
setPixel(x0, y0 - radius, color);
|
||||
setPixel(x0 + radius, y0, color);
|
||||
setPixel(x0 - radius, y0, color);
|
||||
while (x < y) {
|
||||
if (f >= 0) {
|
||||
y--;
|
||||
ddF_y += 2;
|
||||
f += ddF_y;
|
||||
}
|
||||
x++;
|
||||
ddF_x += 2;
|
||||
f += ddF_x + 1;
|
||||
setPixel(x0 + x, y0 + y, color);
|
||||
setPixel(x0 - x, y0 + y, color);
|
||||
setPixel(x0 + x, y0 - y, color);
|
||||
setPixel(x0 - x, y0 - y, color);
|
||||
setPixel(x0 + y, y0 + x, color);
|
||||
setPixel(x0 - y, y0 + x, color);
|
||||
setPixel(x0 + y, y0 - x, color);
|
||||
setPixel(x0 - y, y0 - x, color);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Start a new line: increase row.
|
||||
*/
|
||||
static void newLine(const struct gpanel_font_t *font)
|
||||
{
|
||||
_col = 0;
|
||||
_row += font->height;
|
||||
if (_row > HEIGHT - font->height)
|
||||
_row = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Draw a glyph of one symbol.
|
||||
*/
|
||||
static void drawGlyph(const struct gpanel_font_t *font,
|
||||
int color, int background, int width, const unsigned short *bits)
|
||||
{
|
||||
int h, w, c;
|
||||
unsigned bitmask = 0;
|
||||
|
||||
if (background >= 0) {
|
||||
/*
|
||||
* Clear background.
|
||||
*/
|
||||
setAddrWindow(_col, _row, _col + width - 1, _row + font->height - 1);
|
||||
CS_ACTIVE();
|
||||
RS_COMMAND();
|
||||
writeByte(0x00);
|
||||
writeByte(0x22);
|
||||
RS_DATA();
|
||||
|
||||
/* Loop on each glyph row. */
|
||||
for (h=0; h<font->height; h++) {
|
||||
/* Loop on every pixel in the row (left to right). */
|
||||
for (w=0; w<width; w++) {
|
||||
if ((w & 15) == 0)
|
||||
bitmask = *bits++;
|
||||
else
|
||||
bitmask <<= 1;
|
||||
|
||||
c = (bitmask & 0x8000) ? color : background;
|
||||
writeByte(c >> 8);
|
||||
writeByte(c);
|
||||
}
|
||||
}
|
||||
CS_IDLE();
|
||||
} else {
|
||||
/*
|
||||
* Transparent background.
|
||||
*/
|
||||
/* Loop on each glyph row. */
|
||||
for (h=0; h<font->height; h++) {
|
||||
/* Loop on every pixel in the row (left to right). */
|
||||
for (w=0; w<width; w++) {
|
||||
if ((w & 15) == 0)
|
||||
bitmask = *bits++;
|
||||
else
|
||||
bitmask <<= 1;
|
||||
|
||||
if (bitmask & 0x8000)
|
||||
setPixel(_col + w, _row + h, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Draw a character from a specified font.
|
||||
*/
|
||||
static void drawChar(const struct gpanel_font_t *font,
|
||||
int color, int background, int sym)
|
||||
{
|
||||
unsigned cindex, width;
|
||||
const unsigned short *bits;
|
||||
|
||||
switch (sym) {
|
||||
case '\n': /* goto next line */
|
||||
newLine(font);
|
||||
return;
|
||||
case '\r': /* carriage return - go to begin of line */
|
||||
_col = 0;
|
||||
return;
|
||||
case '\t': /* tab replaced by space */
|
||||
sym = ' ';
|
||||
break;
|
||||
}
|
||||
|
||||
if (sym < font->firstchar || sym >= font->firstchar + font->size)
|
||||
sym = font->defaultchar;
|
||||
cindex = sym - font->firstchar;
|
||||
|
||||
/* Get font bitmap depending on fixed pitch or not. */
|
||||
if (font->width) {
|
||||
/* Proportional font. */
|
||||
width = font->width[cindex];
|
||||
} else {
|
||||
/* Fixed width font. */
|
||||
width = font->maxwidth;
|
||||
}
|
||||
if (font->offset) {
|
||||
bits = font->bits + font->offset[cindex];
|
||||
} else {
|
||||
bits = font->bits + cindex * font->height;
|
||||
}
|
||||
|
||||
/* Scrolling. */
|
||||
if (_col > WIDTH - width) {
|
||||
newLine(font);
|
||||
}
|
||||
|
||||
/* Draw a character. */
|
||||
drawGlyph(font, color, background, width, bits);
|
||||
_col += width;
|
||||
}
|
||||
|
||||
/*
|
||||
* Draw a string of characters.
|
||||
* TODO: Decode UTF-8.
|
||||
*/
|
||||
static void drawText(const struct gpanel_font_t *font,
|
||||
int color, int background, int x, int y, const char *text)
|
||||
{
|
||||
int sym;
|
||||
|
||||
_col = x;
|
||||
_row = y;
|
||||
for (;;) {
|
||||
sym = *text++;
|
||||
if (! sym)
|
||||
break;
|
||||
|
||||
drawChar(font, color, background, sym);
|
||||
}
|
||||
}
|
||||
|
||||
int gpanel_open(dev_t dev, int flag, int mode)
|
||||
{
|
||||
if (minor(dev) != 0)
|
||||
return ENODEV;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gpanel_close(dev_t dev, int flag, int mode)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gpanel_read(dev_t dev, struct uio *uio, int flag)
|
||||
{
|
||||
return ENODEV;
|
||||
}
|
||||
|
||||
int gpanel_write(dev_t dev, struct uio *uio, int flag)
|
||||
{
|
||||
return ENODEV;
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO: check whether user pointers are valid.
|
||||
*/
|
||||
int gpanel_ioctl(dev_t dev, register u_int cmd, caddr_t addr, int flag)
|
||||
{
|
||||
switch (cmd) {
|
||||
/*
|
||||
* Clear the whole screen with a given color.
|
||||
*/
|
||||
case GPANEL_CLEAR: {
|
||||
struct gpanel_clear_t *param = (struct gpanel_clear_t*) addr;
|
||||
|
||||
CS_ACTIVE();
|
||||
writeReg(0x0020, 0);
|
||||
writeReg(0x0021, 0);
|
||||
flood(param->color, WIDTH * HEIGHT);
|
||||
param->xsize = WIDTH;
|
||||
param->ysize = HEIGHT;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Draw a single pixel.
|
||||
*/
|
||||
case GPANEL_PIXEL: {
|
||||
struct gpanel_pixel_t *param = (struct gpanel_pixel_t*) addr;
|
||||
|
||||
setPixel(param->x, param->y, param->color);
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Draw a line.
|
||||
*/
|
||||
case GPANEL_LINE: {
|
||||
struct gpanel_line_t *param = (struct gpanel_line_t*) addr;
|
||||
|
||||
drawLine(param->x0, param->y0, param->x1, param->y1, param->color);
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Draw a rectangle frame.
|
||||
*/
|
||||
case GPANEL_RECT: {
|
||||
struct gpanel_rect_t *param = (struct gpanel_rect_t*) addr;
|
||||
|
||||
drawFrame(param->x0, param->y0, param->x1, param->y1, param->color);
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Fill a rectangle with color.
|
||||
*/
|
||||
case GPANEL_FILL: {
|
||||
struct gpanel_rect_t *param = (struct gpanel_rect_t*) addr;
|
||||
|
||||
fillRectangle(param->x0, param->y0, param->x1, param->y1, param->color);
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Draw a circle.
|
||||
*/
|
||||
case GPANEL_CIRCLE: {
|
||||
struct gpanel_circle_t *param = (struct gpanel_circle_t*) addr;
|
||||
|
||||
drawCircle(param->x, param->y, param->radius, param->color);
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Fill a rectangular area with the user-supplied data.
|
||||
*/
|
||||
case GPANEL_IMAGE: {
|
||||
struct gpanel_image_t *param = (struct gpanel_image_t*) addr;
|
||||
|
||||
drawImage(param->x, param->y, param->width, param->height,
|
||||
param->image);
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Draw a character.
|
||||
*/
|
||||
case GPANEL_CHAR: {
|
||||
struct gpanel_char_t *param = (struct gpanel_char_t*) addr;
|
||||
|
||||
_col = param->x;
|
||||
_row = param->y;
|
||||
drawChar(param->font, param->color, param->background, param->sym);
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Draw a string of characters.
|
||||
*/
|
||||
case GPANEL_TEXT: {
|
||||
struct gpanel_text_t *param = (struct gpanel_text_t*) addr;
|
||||
|
||||
drawText(param->font, param->color, param->background,
|
||||
param->x, param->y, param->text);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read device ID code.
|
||||
*/
|
||||
static unsigned readDeviceId()
|
||||
{
|
||||
unsigned value;
|
||||
|
||||
CS_ACTIVE();
|
||||
RS_COMMAND();
|
||||
writeByte(0x00);
|
||||
WR_STROBE(); // Repeat prior byte (0x00)
|
||||
setReadDir(); // Switch data bus as input
|
||||
RS_DATA();
|
||||
value = readByte() << 8;
|
||||
value |= readByte();
|
||||
setWriteDir(); // Restore data bus as output
|
||||
CS_IDLE();
|
||||
return value;
|
||||
}
|
||||
|
||||
/*
|
||||
* Test to see if device is present.
|
||||
* Return true if found and initialized ok.
|
||||
*/
|
||||
static int
|
||||
swtftprobe(config)
|
||||
struct conf_device *config;
|
||||
{
|
||||
unsigned id;
|
||||
|
||||
initDisplay();
|
||||
printf("swtft0: display %ux%u\n", HEIGHT, WIDTH);
|
||||
id = readDeviceId();
|
||||
if (id == 0x7783)
|
||||
printf("swtft0: Sitronix ST7781 TFT controller\n");
|
||||
setAddrWindow(0, 0, WIDTH-1, HEIGHT-1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct driver swtftdriver = {
|
||||
"swtft", swtftprobe,
|
||||
};
|
||||
@@ -61,3 +61,19 @@ device adc
|
||||
|
||||
# PWM driver
|
||||
device pwm
|
||||
|
||||
# ST7781 TFT display driver
|
||||
device swtft
|
||||
signal "LCD_RST" pin RB10
|
||||
signal "LCD_CS" pin RB0
|
||||
signal "LCD_RD" pin RB2
|
||||
signal "LCD_RS" pin RB8
|
||||
signal "LCD_WR" pin RB4
|
||||
signal "LCD_D0" pin RA14
|
||||
signal "LCD_D1" pin RD3
|
||||
signal "LCD_D2" pin RE8
|
||||
signal "LCD_D3" pin RD0
|
||||
signal "LCD_D4" pin RF0
|
||||
signal "LCD_D5" pin RD1
|
||||
signal "LCD_D6" pin RD2
|
||||
signal "LCD_D7" pin RE9
|
||||
|
||||
@@ -12,6 +12,20 @@ PARAM += -DGPIO5_ENABLED
|
||||
PARAM += -DGPIO6_ENABLED
|
||||
PARAM += -DADC_ENABLED
|
||||
PARAM += -DPWM_ENABLED
|
||||
PARAM += -DSWTFT_ENABLED
|
||||
PARAM += -DLCD_D7_PORT=TRISE -DLCD_D7_PIN=9
|
||||
PARAM += -DLCD_D6_PORT=TRISD -DLCD_D6_PIN=2
|
||||
PARAM += -DLCD_D5_PORT=TRISD -DLCD_D5_PIN=1
|
||||
PARAM += -DLCD_D4_PORT=TRISF -DLCD_D4_PIN=0
|
||||
PARAM += -DLCD_D3_PORT=TRISD -DLCD_D3_PIN=0
|
||||
PARAM += -DLCD_D2_PORT=TRISE -DLCD_D2_PIN=8
|
||||
PARAM += -DLCD_D1_PORT=TRISD -DLCD_D1_PIN=3
|
||||
PARAM += -DLCD_D0_PORT=TRISA -DLCD_D0_PIN=14
|
||||
PARAM += -DLCD_WR_PORT=TRISB -DLCD_WR_PIN=4
|
||||
PARAM += -DLCD_RS_PORT=TRISB -DLCD_RS_PIN=8
|
||||
PARAM += -DLCD_RD_PORT=TRISB -DLCD_RD_PIN=2
|
||||
PARAM += -DLCD_CS_PORT=TRISB -DLCD_CS_PIN=0
|
||||
PARAM += -DLCD_RST_PORT=TRISB -DLCD_RST_PIN=10
|
||||
PARAM += -DLED_TTY_PORT=TRISA -DLED_TTY_PIN=1
|
||||
PARAM += -DLED_DISK_PORT=TRISF -DLED_DISK_PIN=0
|
||||
PARAM += -DLED_KERNEL_PORT=TRISA -DLED_KERNEL_PIN=0
|
||||
@@ -66,7 +80,7 @@ OBJS = exec_aout.o exec_conf.o exec_elf.o exec_script.o exec_subr.o \
|
||||
ufs_namei.o ufs_subr.o ufs_syscalls.o ufs_syscalls2.o \
|
||||
vfs_vnops.o vm_sched.o vm_swap.o vm_swp.o clock.o cons.o devsw.o \
|
||||
exception.o machdep.o mem.o signal.o swap.o sysctl.o adc.o \
|
||||
gpio.o pwm.o sd.o spi.o spi_bus.o uart.o
|
||||
gpio.o pwm.o sd.o st7781.o spi.o spi_bus.o uart.o
|
||||
|
||||
CFILES = $S/kernel/exec_aout.c $S/kernel/exec_conf.c $S/kernel/exec_elf.c \
|
||||
$S/kernel/exec_script.c $S/kernel/exec_subr.c \
|
||||
@@ -92,8 +106,8 @@ CFILES = $S/kernel/exec_aout.c $S/kernel/exec_conf.c $S/kernel/exec_elf.c \
|
||||
$S/pic32/devsw.c $S/pic32/exception.c $S/pic32/machdep.c \
|
||||
$S/pic32/mem.c $S/pic32/signal.c $S/pic32/swap.c \
|
||||
$S/pic32/sysctl.c $S/pic32/adc.c $S/pic32/gpio.c $S/pic32/pwm.c \
|
||||
$S/pic32/sd.c $S/pic32/spi.c $S/pic32/spi_bus.c $S/pic32/uart.c \
|
||||
swapunix.c
|
||||
$S/pic32/sd.c $S/pic32/st7781.c $S/pic32/spi.c \
|
||||
$S/pic32/spi_bus.c $S/pic32/uart.c swapunix.c
|
||||
|
||||
# load lines for config "xxx" will be emitted as:
|
||||
# xxx: ${SYSTEM_DEP} swapxxx.o
|
||||
@@ -337,6 +351,9 @@ pwm.o: $S/pic32/pwm.c
|
||||
sd.o: $S/pic32/sd.c
|
||||
${COMPILE_C}
|
||||
|
||||
st7781.o: $S/pic32/st7781.c
|
||||
${COMPILE_C}
|
||||
|
||||
spi.o: $S/pic32/spi.c
|
||||
${COMPILE_C}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user