diff --git a/drivers/gdisp/AlteraFramereader/board_alteraframereader_template.h b/drivers/gdisp/AlteraFramereader/board_alteraframereader_template.h new file mode 100644 index 00000000..4fc7d071 --- /dev/null +++ b/drivers/gdisp/AlteraFramereader/board_alteraframereader_template.h @@ -0,0 +1,30 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +#define SCREEN_WIDTH 800 +#define SCREEN_HEIGHT 480 +#define FRAMEREADER_BASE ALT_VIP_VFR_0_BASE + +#if GDISP_NEED_CONTROL + static void board_backlight(GDisplay* g, uint8_t percent) + { + (void)g; + (void)percent; + } + + static void board_contrast(GDisplay* g, uint8_t percent) + { + (void)g; + (void)percent; + } + + static void board_power(GDisplay* g, powermode_t pwr) + { + (void)g; + (void)pwr; + } +#endif diff --git a/drivers/gdisp/AlteraFramereader/driver.mk b/drivers/gdisp/AlteraFramereader/driver.mk new file mode 100644 index 00000000..374cda11 --- /dev/null +++ b/drivers/gdisp/AlteraFramereader/driver.mk @@ -0,0 +1,2 @@ +GFXINC += $(GFXLIB)/drivers/gdisp/AlteraFramereader +GFXSRC += $(GFXLIB)/drivers/gdisp/AlteraFramereader/gdisp_lld_alteraframereader.c diff --git a/drivers/gdisp/AlteraFramereader/gdisp_lld_alteraframereader.c b/drivers/gdisp/AlteraFramereader/gdisp_lld_alteraframereader.c new file mode 100644 index 00000000..5b27f944 --- /dev/null +++ b/drivers/gdisp/AlteraFramereader/gdisp_lld_alteraframereader.c @@ -0,0 +1,280 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +#include +#include +#include +#include "gfx.h" + +#if GFX_USE_GDISP + +#define GDISP_DRIVER_VMT GDISPVMT_alteraframereader +#include "gdisp_lld_config.h" +#include "../../../src/gdisp/gdisp_driver.h" +#include "board_alteraframereader.h" + +#ifndef FRAMEREADER_BASE + #error "Framereader IP base address (FRAMEREADER_BASE) not set in board file." +#endif +#ifndef SCREEN_WIDTH + #error "Screen width (SCREEN_WIDTH) not set in board file." +#endif +#ifndef SCREEN_HEIGHT + #error "Screen height (SCREEN_HEIGHT) not set in board file." +#endif + +// ToDo: Merge this into fbPriv +typedef struct fbInfo { + void* pixels; // The pixel buffer + coord_t linelen; // The number of bytes per display line +} fbInfo; + +typedef struct fbPriv { + fbInfo fbi; // Display information + void* frame0; + void* frame1; +} fbPriv; + +/*===========================================================================*/ +/* Driver local routines . */ +/*===========================================================================*/ + +#define PIXIL_POS(g, x, y) ((y) * ((fbPriv *)(g)->priv)->fbi.linelen + (x) * sizeof(LLDCOLOR_TYPE)) +#define PIXEL_ADDR(g, pos) ((LLDCOLOR_TYPE *)(((char *)((fbPriv *)(g)->priv)->fbi.pixels)+pos)) +#define PRIV(g) ((fbPriv *)g->priv) + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +LLDSPEC bool_t gdisp_lld_init(GDisplay* g) +{ + // Allocate the frame buffers + PRIV(g)->frame0 = gfxAlloc(SCREEN_WIDTH * SCREEN_HEIGHT * sizeof(LLDCOLOR_TYPE)); + PRIV(g)->frame1 = gfxAlloc(SCREEN_WIDTH * SCREEN_HEIGHT * sizeof(LLDCOLOR_TYPE)); + if (!PRIV(g)->frame0 || !PRIV(g)->frame1) { + gfxHalt("Couldn't allocate memory for framebuffer\r\n"); + } + + // Initialize the private structure + g->g.Width = SCREEN_WIDTH; + g->g.Height = SCREEN_HEIGHT; + g->g.Backlight = 100; + g->g.Contrast = 50; + g->g.Orientation = GDISP_ROTATE_0; + g->g.Powermode = powerOn; + g->board = 0; + PRIV(g)->fbi.linelen = g->g.Width * sizeof(LLDCOLOR_TYPE); // bytes per line + PRIV(g)->fbi.pixels = PRIV(g)->frame0; + + // Make sure the MSB is set so we bypass the data cache of the NIOS-II soft core + PRIV(g)->fbi.pixels = (void*)((char*)PRIV(g)->fbi.pixels + 0x80000000); + + // Stop the framereader to allow for configuration + IOWR(ALT_VIP_VFR_0_BASE, 0x00, 0x00); // stop for config + + // Frame 0 + IOWR(ALT_VIP_VFR_0_BASE, 0x04, (uint32_t)PRIV(g)->frame0); + IOWR(ALT_VIP_VFR_0_BASE, 0x05, SCREEN_WIDTH*SCREEN_HEIGHT/2); + IOWR(ALT_VIP_VFR_0_BASE, 0x06, SCREEN_WIDTH*SCREEN_HEIGHT); + IOWR(ALT_VIP_VFR_0_BASE, 0x08, SCREEN_WIDTH); + IOWR(ALT_VIP_VFR_0_BASE, 0x09, SCREEN_HEIGHT); + IOWR(ALT_VIP_VFR_0_BASE, 0x0a, 0x00); + + // Frame 1 + IOWR(ALT_VIP_VFR_0_BASE, 0x0b, (uint32_t)PRIV(g)->frame1); + IOWR(ALT_VIP_VFR_0_BASE, 0x0c, SCREEN_WIDTH*SCREEN_HEIGHT/2); + IOWR(ALT_VIP_VFR_0_BASE, 0x0d, SCREEN_WIDTH*SCREEN_HEIGHT); + IOWR(ALT_VIP_VFR_0_BASE, 0x0f, SCREEN_WIDTH); + IOWR(ALT_VIP_VFR_0_BASE, 0x10, SCREEN_HEIGHT); + IOWR(ALT_VIP_VFR_0_BASE, 0x11, 0x00); + + // Select frame0 (user draws to frame0 -> double buffering disabled by default) + IOWR(ALT_VIP_VFR_0_BASE, 0x03, 0x00); + + // Start the framebuffer reader + IOWR(ALT_VIP_VFR_0_BASE, 0x00, 0x01); + + return TRUE; +} + +LLDSPEC void gdisp_lld_draw_pixel(GDisplay* g) +{ + unsigned pos; + + #if GDISP_NEED_CONTROL + switch(g->g.Orientation) { + case GDISP_ROTATE_0: + default: + pos = PIXIL_POS(g, g->p.x, g->p.y); + break; + case GDISP_ROTATE_90: + pos = PIXIL_POS(g, g->p.y, g->g.Width-g->p.x-1); + break; + case GDISP_ROTATE_180: + pos = PIXIL_POS(g, g->g.Width-g->p.x-1, g->g.Height-g->p.y-1); + break; + case GDISP_ROTATE_270: + pos = PIXIL_POS(g, g->g.Height-g->p.y-1, g->p.x); + break; + } + #else + pos = PIXIL_POS(g, g->p.x, g->p.y); + #endif + + PIXEL_ADDR(g, pos)[0] = gdispColor2Native(g->p.color); +} + +LLDSPEC color_t gdisp_lld_get_pixel_color(GDisplay* g) +{ + unsigned pos; + LLDCOLOR_TYPE color; + + #if GDISP_NEED_CONTROL + switch(g->g.Orientation) { + case GDISP_ROTATE_0: + default: + pos = PIXIL_POS(g, g->p.x, g->p.y); + break; + case GDISP_ROTATE_90: + pos = PIXIL_POS(g, g->p.y, g->g.Width-g->p.x-1); + break; + case GDISP_ROTATE_180: + pos = PIXIL_POS(g, g->g.Width-g->p.x-1, g->g.Height-g->p.y-1); + break; + case GDISP_ROTATE_270: + pos = PIXIL_POS(g, g->g.Height-g->p.y-1, g->p.x); + break; + } + #else + pos = PIXIL_POS(g, g->p.x, g->p.y); + #endif + + color = PIXEL_ADDR(g, pos)[0]; + return gdispNative2Color(color); +} + +#if GDISP_NEED_CONTROL + LLDSPEC void gdisp_lld_control(GDisplay* g) + { + switch(g->p.x) { + case GDISP_CONTROL_POWER: + if (g->g.Powermode == (powermode_t)g->p.ptr) + return; + switch((powermode_t)g->p.ptr) { + case powerOff: case powerOn: case powerSleep: case powerDeepSleep: + board_power(g, (powermode_t)g->p.ptr); + break; + default: + return; + } + g->g.Powermode = (powermode_t)g->p.ptr; + return; + + case GDISP_CONTROL_ORIENTATION: + if (g->g.Orientation == (orientation_t)g->p.ptr) + return; + switch((orientation_t)g->p.ptr) { + case GDISP_ROTATE_0: + case GDISP_ROTATE_180: + if (g->g.Orientation == GDISP_ROTATE_90 || g->g.Orientation == GDISP_ROTATE_270) { + coord_t tmp; + + tmp = g->g.Width; + g->g.Width = g->g.Height; + g->g.Height = tmp; + } + break; + case GDISP_ROTATE_90: + case GDISP_ROTATE_270: + if (g->g.Orientation == GDISP_ROTATE_0 || g->g.Orientation == GDISP_ROTATE_180) { + coord_t tmp; + + tmp = g->g.Width; + g->g.Width = g->g.Height; + g->g.Height = tmp; + } + break; + default: + return; + } + g->g.Orientation = (orientation_t)g->p.ptr; + return; + + case GDISP_CONTROL_BACKLIGHT: + if ((unsigned)g->p.ptr > 100) g->p.ptr = (void *)100; + board_backlight(g, (unsigned)g->p.ptr); + g->g.Backlight = (unsigned)g->p.ptr; + return; + + case GDISP_CONTROL_CONTRAST: + if ((unsigned)g->p.ptr > 100) g->p.ptr = (void *)100; + board_contrast(g, (unsigned)g->p.ptr); + g->g.Contrast = (unsigned)g->p.ptr; + return; + + case GDISP_CONTROL_BUFFERS_SWAP: + if (PRIV(g)->fbi.pixels == PRIV(g)->frame0) { + PRIV(g)->fbi.pixels = PRIV(g)->frame1; + IOWR(ALT_VIP_VFR_0_BASE, 0x03, 0x00); + } else { + PRIV(g)->fbi.pixels = PRIV(g)->frame0; + IOWR(ALT_VIP_VFR_0_BASE, 0x03, 0x01); + } + return; + + case GDISP_CONTROL_BUFFERS_ENABLE: + // Display frame0, draw to frame1 + PRIV(g)->fbi.pixels = PRIV(g)->frame1; + IOWR(ALT_VIP_VFR_0_BASE, 0x03, 0x00); + return; + + case GDISP_CONTROL_BUFFERS_DISABLE: + // Display frame0, draw to frame0 + PRIV(g)->fbi.pixels = PRIV(g)->frame0; + IOWR(ALT_VIP_VFR_0_BASE, 0x03, 0x00); + return; + } + } +#endif + +#if GDISP_HARDWARE_FILLS + LLDSPEC void gdisp_lld_fill_area(GDisplay* g) + { + int i; + unsigned int addr; + int bytes_per_line; + int bytes_per_pixel; + uint8_t* line; + + // Calculate some values required for further calculations + bytes_per_pixel = ((fbPriv*)g->priv)->fbi.linelen/g->g.Width; // must be 4 + bytes_per_line = ((fbPriv*)g->priv)->fbi.linelen; + + // Allocate line buffer + line = gfxAlloc(bytes_per_pixel * g->p.cx); + + // Fill the line buffer with the solid color + for (i = 0; i < bytes_per_pixel * g->p.cx; i += 4) { + *((color_t*)(line + i)) = g->p.color; + } + + // Calculate the address of the first pixel of the rectangle (top left corner) + addr = (int)((char *)((fbPriv *)g->priv)->fbi.pixels + (g->p.y * bytes_per_line) + (g->p.x * bytes_per_pixel)); + + // Copy filled line buffer to create rectangle + for (i = 0; i < g->p.cy; i++) { + memcpy((void*)addr, line, bytes_per_pixel * g->p.cx); + addr += bytes_per_line; + } + + // Free the line buffer + gfxFree(line); + } +#endif // GDISP_HARDWARE_FILLS + +#endif /* GFX_USE_GDISP */ diff --git a/drivers/gdisp/AlteraFramereader/gdisp_lld_config.h b/drivers/gdisp/AlteraFramereader/gdisp_lld_config.h new file mode 100644 index 00000000..637f4f4e --- /dev/null +++ b/drivers/gdisp/AlteraFramereader/gdisp_lld_config.h @@ -0,0 +1,27 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +#ifndef _GDISP_LLD_CONFIG_H +#define _GDISP_LLD_CONFIG_H + +#if GFX_USE_GDISP + +#define GDISP_HARDWARE_DRAWPIXEL TRUE +#define GDISP_HARDWARE_PIXELREAD TRUE +#define GDISP_HARDWARE_CONTROL TRUE +#define GDISP_HARDWARE_FILLS TRUE + +#define GDISP_LLD_PIXELFORMAT GDISP_PIXELFORMAT_RGB888 + +// gdispControl() options +#define GDISP_CONTROL_BUFFERS_SWAP (GDISP_CONTROL_LLD+0) // Swap framebuffers (double buffering). Parameter is ignored. +#define GDISP_CONTROL_BUFFERS_ENABLE (GDISP_CONTROL_LLD+1) // Enable double buffering. Parameter is ignored. +#define GDISP_CONTROL_BUFFERS_DISABLE (GDISP_CONTROL_LLD+2) // Disable double buffering. Parameter is ignored. + +#endif /* GFX_USE_GDISP */ + +#endif /* _GDISP_LLD_CONFIG_H */ diff --git a/drivers/gdisp/AlteraFramereader/readme.txt b/drivers/gdisp/AlteraFramereader/readme.txt new file mode 100644 index 00000000..87777be4 --- /dev/null +++ b/drivers/gdisp/AlteraFramereader/readme.txt @@ -0,0 +1,27 @@ +This driver can be used for the "Frame Reader IP Core" that comes with the "Video and Image Processing Suite" package +from Altera/Intel/Quartus. + +This driver takes advantage of the double buffering feature offered by the "Frame Reader IP Core". The following commands +can be used through the gdispControl() API to manage the two frame buffers: + + gdispControl(GDISP_CONTROL_BUFFERS_ENABLE, 0); // Enabel the two framebuffers (Disabled by default) + gdispControl(GDISP_CONTROL_BUFFERS_DISABLE, 0); // Disable the two framebuffers (Disabled by default) + gdispControl(GDISP_CONTROL_BUFFERS_SWAP, 0); // Swap the framebuffers (if enabled) + +The double buffering is taken care of completely by the driver. It sets the framebuffer pointers correctly so that it's +transparent to the application. There's no need to handle the two framebuffers manually through the multiple displays +support offered by uGFX. Using GDISP_CONTROL_BUFFERS_SWAP will swap the framebuffers on the actual hardware as well +as swap the framebuffer pointers for the default GDisplay to draw to the other framebuffer. + + +To use this driver: + +1. Add in your gfxconf.h: + a) #define GFX_USE_GDISP TRUE + +2. To your makefile add the following lines: + include $(GFXLIB)/gfx.mk + include $(GFXLIB)/drivers/gdisp/AlteraFramereader/driver.mk + +3. Add a board_alteraframereader.h to you project directory (or board directory) + base on one of the templates found in this drivers directory.