Adding Altera Frame Reader IP Core display driver

This commit is contained in:
Joel Bodenmann 2017-02-18 16:32:57 +01:00
parent 8411fd1f03
commit d3e9955496
5 changed files with 366 additions and 0 deletions

View File

@ -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

View File

@ -0,0 +1,2 @@
GFXINC += $(GFXLIB)/drivers/gdisp/AlteraFramereader
GFXSRC += $(GFXLIB)/drivers/gdisp/AlteraFramereader/gdisp_lld_alteraframereader.c

View File

@ -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 <system.h>
#include <io.h>
#include <string.h>
#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 */

View File

@ -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 */

View File

@ -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.