Optimize buffer layout

This commit puts the framebuffer management in specific framebuffer files.
The framebuffer is now written to in a way optimised for sending it.
It also adds support for bit-banding if macro CONFIG_BIT_BANDING is defined.
Framebuffer is also not passed as an argument to display functions anymore.
pull/264/head
Morgan Diepart 2024-04-19 18:55:18 +02:00
rodzic 7c30a3d8e9
commit 693d4d1b7d
18 zmienionych plików z 441 dodań i 248 usunięć

Wyświetl plik

@ -43,6 +43,7 @@ openrtx_src = ['openrtx/src/core/state.c',
'openrtx/src/core/chan.c',
'openrtx/src/core/gps.c',
'openrtx/src/core/dsp.cpp',
'openrtx/src/core/framebuffer.c',
'openrtx/src/core/cps.c',
'openrtx/src/core/crc.c',
'openrtx/src/core/datetime.c',

Wyświetl plik

@ -0,0 +1,171 @@
/***************************************************************************
* Copyright (C) 2020 - 2024 by Federico Amedeo Izzo IU2NUO, *
* Niccolò Izzo IU2KIN, *
* Silvano Seva IU2KWO, *
* Morgan Diepart ON4MOD *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, see <http://www.gnu.org/licenses/> *
***************************************************************************/
#ifndef FRAMEBUFFER_H
#define FRAMEBUFFER_H
/**
* This source file provides an implementation for the graphics framebuffer.
* It is suitable for both color, grayscale and B/W display.
* It assumes that the screen is rendered more often than it is written to.
* Thus it stores the framebuffer in an order optimised to send it. This order
* may not be linear.
*
* Mode 0: this mode is the default framebuffer behavior, that is, the buffer
* is stored linearly, line-by-line.
*
* Mode 1: this mode is optimized for SSD1309-like screens.
* The following indices are the indices of the position in the storage
* (for a screen of 16 lines and 4 columns)
* --------------------> columns
* | 0 8 16 24
* | 1 9 17 25
* | 2 10 18 26
* | 3 11 19 27
* | 4 12 20 28
* | 5 13 21 29
* | 6 14 22 30
* | 7 15 23 31
* | 32 40 48 56
* | 33 41 49 57
* | 34 42 50 58
* | 35 43 51 59
* | 36 44 52 60
* | 37 45 53 61
* | 38 46 54 62
* | 39 47 55 63
* V
* lines
*/
#include <hwconfig.h>
#include <stdlib.h>
#include <graphics.h>
#include <string.h>
#ifdef __cplusplus
extern "C" {
#endif
#ifdef CONFIG_PIX_FMT_RGB565
/* This specialization is meant for an RGB565 little endian pixel format.
* Thus, to accomodate for the endianness, the fields in struct rgb565_t have to
* be written in reversed order.
*
* For more details about endianness and bitfield structs see the following web
* page: http://mjfrazer.org/mjfrazer/bitfields/
*/
#define PIXEL_T rgb565_t
#define FB_SIZE (CONFIG_SCREEN_HEIGHT * CONFIG_SCREEN_WIDTH)
typedef struct
{
uint16_t b : 5;
uint16_t g : 6;
uint16_t r : 5;
}
rgb565_t;
static rgb565_t _true2highColor(color_t true_color)
{
rgb565_t high_color;
high_color.r = true_color.r >> 3;
high_color.g = true_color.g >> 2;
high_color.b = true_color.b >> 3;
return high_color;
}
#elif defined CONFIG_PIX_FMT_BW
/**
* This specialization is meant for black and white pixel format.
* It is suitable for monochromatic displays with 1 bit per pixel,
* it will have RGB and grayscale counterparts
*/
#define PIXEL_T uint8_t
#define FB_SIZE (((CONFIG_SCREEN_HEIGHT * CONFIG_SCREEN_WIDTH) / 8 ) + 1)
typedef enum
{
COLOR_WHITE = 0,
COLOR_BLACK = 1,
}
bw_t;
static bw_t _color2bw(color_t true_color)
{
if(true_color.r == 0 &&
true_color.g == 0 &&
true_color.b == 0)
return COLOR_WHITE;
else
return COLOR_BLACK;
}
#else
#error Please define a pixel format type into hwconfig.h or meson.build
#endif
/**
* Initializes the framebuffer in the specified mode
* @param store_mode: mode in which the data is stored in the framebuffer
*/
void framebuffer_init(uint8_t store_mode);
/**
* Change the color of a single pixel.
* @param pos: x,y coordinates of the pixel.
* @param color: desired pixel color, in color_t format.
*/
void framebuffer_setPixel(point_t pos, color_t color);
/**
* Returns the color of the pixel at specified position
* @param pos: position of the pixel to read
* @return color of the pixel located at pos.
*/
PIXEL_T framebuffer_readPixel(point_t pos);
/**
* Returns a pointer to the framebuffer storage.
* @return pointer to the underlying framebuffer array
*/
PIXEL_T *framebuffer_getPointer();
/**
* Clears the framebuffer
*/
void framebuffer_clear();
/**
* Terminates the framebuffer
*/
void framebuffer_terminate();
#ifdef __cplusplus
}
#endif
#endif /* FRAMEBUFFER_H */

Wyświetl plik

@ -156,13 +156,6 @@ void gfx_clearScreen();
*/
void gfx_fillScreen(color_t color);
/**
* Change the color of a single pixel.
* @param pos: x,y coordinates of the pixel.
* @param color: desired pixel color, in color_t format.
*/
void gfx_setPixel(point_t pos, color_t color);
/**
* Draw a line from start to end coordinates, ends included.
* @param start: line start point, in pixel coordinates.

Wyświetl plik

@ -21,6 +21,7 @@
#include <stdint.h>
#include <stdbool.h>
#include <framebuffer.h>
#ifdef __cplusplus
extern "C" {
@ -49,18 +50,12 @@ extern "C" {
*/
/**
* This function initialises the display and allocates framebuffer on the heap.
*
* NOTE: framebuffer allocation is the first operation performed, if fails an
* error message is printed on the virtual COM port and this function returns
* prematurely, without configuring the display.
* Thus, a dark screen can be symptom of failed allocation.
* This function initialises the display and the framebuffer.
*/
void display_init();
/**
* When called, this function terminates the display driver
* and deallocates the framebuffer.
* When called, this function terminates the display driver and the framebuffer.
*/
void display_terminate();
@ -72,7 +67,7 @@ void display_terminate();
* @param endRow: last row of the framebuffer section to be copied
* @param fb: pointer to frameBuffer.
*/
void display_renderRows(uint8_t startRow, uint8_t endRow, void *fb);
void display_renderRows(uint8_t startRow, uint8_t endRow);
/**
* Copy framebuffer content to the display internal buffer, to be called
@ -81,7 +76,7 @@ void display_renderRows(uint8_t startRow, uint8_t endRow, void *fb);
*
* @param fb: pointer to framebuffer.
*/
void display_render(void *fb);
void display_render();
/**
* Set display contrast.

Wyświetl plik

@ -0,0 +1,119 @@
/***************************************************************************
* Copyright (C) 2020 - 2024 by Federico Amedeo Izzo IU2NUO, *
* Niccolò Izzo IU2KIN, *
* Silvano Seva IU2KWO, *
* Morgan Diepart ON4MOD *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, see <http://www.gnu.org/licenses/> *
***************************************************************************/
#include "framebuffer.h"
#include <stdlib.h>
#include <graphics.h>
#include <hwconfig.h>
#include <stddef.h>
#include <stdint.h>
static PIXEL_T __attribute__((section(".bss.fb"))) framebuffer[FB_SIZE];
static uint8_t mode = 0;
#ifdef CONFIG_BIT_BANDING
static uint8_t *bit_banded_framebuffer;
#endif
void framebuffer_init(uint8_t store_mode)
{
mode = store_mode;
#ifdef CONFIG_BIT_BANDING
bit_banded_framebuffer = (uint8_t *)(0x22000000UL + 32UL*((uint32_t)framebuffer - 0x20000000UL));
#endif
}
static inline size_t framebuffer_index(point_t pos){
switch(mode){
case 0:
default:
/* Linear adressing */
return (pos.x + pos.y*CONFIG_SCREEN_WIDTH);
case 1:
/* Adressing per page */
return (pos.x*8 + pos.y%8 + (pos.y/8)*(CONFIG_SCREEN_WIDTH*8));
}
}
void framebuffer_setPixel(point_t pos, color_t color)
{
if (pos.x >= CONFIG_SCREEN_WIDTH || pos.y >= CONFIG_SCREEN_HEIGHT ||
pos.x < 0 || pos.y < 0)
return; // off the screen
// Computes the position in the buffer according to the mode selected
size_t linear_index = framebuffer_index(pos);
#ifdef CONFIG_PIX_FMT_RGB565
// Blend old pixel value and new one
rgb565_t pixel = _true2highColor(color);
if (color.alpha < 255)
{
rgb565_t old_pixel = framebuffer[linear_index];
pixel.r = ((255-color.alpha)*old_pixel.r+color.alpha*pixel.r)/255;
pixel.g = ((255-color.alpha)*old_pixel.g+color.alpha*pixel.g)/255;
pixel.b = ((255-color.alpha)*old_pixel.b+color.alpha*pixel.b)/255;
}
framebuffer[linear_index] = pixel;
#elif defined CONFIG_PIX_FMT_BW
// Ignore more than half transparent pixels
if (color.alpha >= 128)
{
#ifdef CONFIG_BIT_BANDING
bit_banded_framebuffer[linear_index*4] = _color2bw(color);
#else
uint_fast16_t cell = linear_index / 8;
uint_fast16_t elem = linear_index % 8;
framebuffer[cell] &= ~(1 << elem);
framebuffer[cell] |= (_color2bw(color) << elem);
#endif // CONFIG_BIT_BANDING
}
#endif // CONFIG_PIXEL_FMT
}
PIXEL_T framebuffer_readPixel(point_t pos)
{
size_t linear_index = framebuffer_index(pos);
#ifdef CONFIG_PIX_FMT_RGB565
return framebuffer[linear_index];
#elif defined CONFIG_PIX_FMT_BW
#ifdef CONFIG_BIT_BANDING
return bit_banded_framebuffer[linear_index*4];
#else
uint_fast16_t cell = linear_index / 8;
uint_fast16_t elem = linear_index % 8;
return (framebuffer[cell] >> elem) & 0x01;
#endif // CONFIG_BIT_BANDING
#endif // CONFIG_PIXEL_FMT
}
PIXEL_T *framebuffer_getPointer()
{
return framebuffer;
}
void framebuffer_clear()
{
// Set the whole framebuffer to 0x00 = make the screen black
memset(framebuffer, 0x00, FB_SIZE * sizeof(PIXEL_T));
}
void framebuffer_terminate(){}

Wyświetl plik

@ -18,8 +18,8 @@
***************************************************************************/
/**
* This source file provides an implementation for the graphics.h interface
* It is suitable for both color, grayscale and B/W display
* This source file provides an implementation for the graphics.h interface
* It is suitable for both color, grayscale and B/W display.
*/
#include <interfaces/display.h>
@ -31,6 +31,7 @@
#include <limits.h>
#include <stdio.h>
#include <math.h>
#include <framebuffer.h>
#include <gfxfont.h>
#include <TomThumb.h>
@ -86,73 +87,8 @@ static const GFXfont fonts[] = { TomThumb, // 5pt
Symbols8pt7b // 8pt
};
#ifdef CONFIG_PIX_FMT_RGB565
/* This specialization is meant for an RGB565 little endian pixel format.
* Thus, to accomodate for the endianness, the fields in struct rgb565_t have to
* be written in reversed order.
*
* For more details about endianness and bitfield structs see the following web
* page: http://mjfrazer.org/mjfrazer/bitfields/
*/
#define PIXEL_T rgb565_t
#define FB_SIZE (CONFIG_SCREEN_HEIGHT * CONFIG_SCREEN_WIDTH)
typedef struct
{
uint16_t b : 5;
uint16_t g : 6;
uint16_t r : 5;
}
rgb565_t;
static rgb565_t _true2highColor(color_t true_color)
{
rgb565_t high_color;
high_color.r = true_color.r >> 3;
high_color.g = true_color.g >> 2;
high_color.b = true_color.b >> 3;
return high_color;
}
#elif defined CONFIG_PIX_FMT_BW
/**
* This specialization is meant for black and white pixel format.
* It is suitable for monochromatic displays with 1 bit per pixel,
* it will have RGB and grayscale counterparts
*/
#define PIXEL_T uint8_t
#define FB_SIZE (((CONFIG_SCREEN_HEIGHT * CONFIG_SCREEN_WIDTH) / 8 ) + 1)
typedef enum
{
WHITE = 0,
BLACK = 1,
}
bw_t;
static bw_t _color2bw(color_t true_color)
{
if(true_color.r == 0 &&
true_color.g == 0 &&
true_color.b == 0)
return WHITE;
else
return BLACK;
}
#else
#error Please define a pixel format type into hwconfig.h or meson.build
#endif
static PIXEL_T __attribute__((section(".bss.fb"))) framebuffer[FB_SIZE];
static char text[32];
void gfx_init()
{
display_init();
@ -164,33 +100,17 @@ void gfx_init()
void gfx_terminate()
{
display_terminate();
}
void gfx_renderRows(uint8_t startRow, uint8_t endRow)
{
display_renderRows(startRow, endRow, framebuffer);
framebuffer_terminate();
}
void gfx_render()
{
display_render(framebuffer);
}
void gfx_clearRows(uint8_t startRow, uint8_t endRow)
{
if(endRow < startRow)
return;
uint16_t start = startRow * CONFIG_SCREEN_WIDTH * sizeof(PIXEL_T);
uint16_t height = endRow - startRow * CONFIG_SCREEN_WIDTH * sizeof(PIXEL_T);
// Set the specified rows to 0x00 = make the screen black
memset(framebuffer + start, 0x00, height);
display_render();
}
void gfx_clearScreen()
{
// Set the whole framebuffer to 0x00 = make the screen black
memset(framebuffer, 0x00, FB_SIZE * sizeof(PIXEL_T));
framebuffer_clear();
}
void gfx_fillScreen(color_t color)
@ -200,46 +120,11 @@ void gfx_fillScreen(color_t color)
for(int16_t x = 0; x < CONFIG_SCREEN_WIDTH; x++)
{
point_t pos = {x, y};
gfx_setPixel(pos, color);
framebuffer_setPixel(pos, color);
}
}
}
inline void gfx_setPixel(point_t pos, color_t color)
{
if (pos.x >= CONFIG_SCREEN_WIDTH || pos.y >= CONFIG_SCREEN_HEIGHT ||
pos.x < 0 || pos.y < 0)
return; // off the screen
#ifdef CONFIG_PIX_FMT_RGB565
// Blend old pixel value and new one
if (color.alpha < 255)
{
uint8_t alpha = color.alpha;
rgb565_t new_pixel = _true2highColor(color);
rgb565_t old_pixel = framebuffer[pos.x + pos.y*CONFIG_SCREEN_WIDTH];
rgb565_t pixel;
pixel.r = ((255-alpha)*old_pixel.r+alpha*new_pixel.r)/255;
pixel.g = ((255-alpha)*old_pixel.g+alpha*new_pixel.g)/255;
pixel.b = ((255-alpha)*old_pixel.b+alpha*new_pixel.b)/255;
framebuffer[pos.x + pos.y*CONFIG_SCREEN_WIDTH] = pixel;
}
else
{
framebuffer[pos.x + pos.y*CONFIG_SCREEN_WIDTH] = _true2highColor(color);
}
#elif defined CONFIG_PIX_FMT_BW
// Ignore more than half transparent pixels
if (color.alpha >= 128)
{
uint16_t cell = (pos.x + pos.y*CONFIG_SCREEN_WIDTH) / 8;
uint16_t elem = (pos.x + pos.y*CONFIG_SCREEN_WIDTH) % 8;
framebuffer[cell] &= ~(1 << elem);
framebuffer[cell] |= (_color2bw(color) << elem);
}
#endif
}
void gfx_drawLine(point_t start, point_t end, color_t color)
{
int16_t steep = abs(end.y - start.y) > abs(end.x - start.x);
@ -286,9 +171,9 @@ void gfx_drawLine(point_t start, point_t end, color_t color)
{
point_t pos = {start.y, start.x};
if (steep)
gfx_setPixel(pos, color);
framebuffer_setPixel(pos, color);
else
gfx_setPixel(start, color);
framebuffer_setPixel(start, color);
err -= dy;
if (err < 0)
@ -318,7 +203,7 @@ void gfx_drawRect(point_t start, uint16_t width, uint16_t height, color_t color,
if(fill || perimeter)
{
point_t pos = {x, y};
gfx_setPixel(pos, color);
framebuffer_setPixel(pos, color);
}
}
}
@ -334,14 +219,14 @@ void gfx_drawCircle(point_t start, uint16_t r, color_t color)
point_t pos = start;
pos.y += r;
gfx_setPixel(pos, color);
framebuffer_setPixel(pos, color);
pos.y -= 2 * r;
gfx_setPixel(pos, color);
framebuffer_setPixel(pos, color);
pos.y += r;
pos.x += r;
gfx_setPixel(pos, color);
framebuffer_setPixel(pos, color);
pos.x -= 2 * r;
gfx_setPixel(pos, color);
framebuffer_setPixel(pos, color);
while (x < y)
{
@ -358,28 +243,28 @@ void gfx_drawCircle(point_t start, uint16_t r, color_t color)
pos.x = start.x + x;
pos.y = start.y + y;
gfx_setPixel(pos, color);
framebuffer_setPixel(pos, color);
pos.x = start.x - x;
pos.y = start.y + y;
gfx_setPixel(pos, color);
framebuffer_setPixel(pos, color);
pos.x = start.x + x;
pos.y = start.y - y;
gfx_setPixel(pos, color);
framebuffer_setPixel(pos, color);
pos.x = start.x - x;
pos.y = start.y - y;
gfx_setPixel(pos, color);
framebuffer_setPixel(pos, color);
pos.x = start.x + y;
pos.y = start.y + x;
gfx_setPixel(pos, color);
framebuffer_setPixel(pos, color);
pos.x = start.x - y;
pos.y = start.y + x;
gfx_setPixel(pos, color);
framebuffer_setPixel(pos, color);
pos.x = start.x + y;
pos.y = start.y - x;
gfx_setPixel(pos, color);
framebuffer_setPixel(pos, color);
pos.x = start.x - y;
pos.y = start.y - x;
gfx_setPixel(pos, color);
framebuffer_setPixel(pos, color);
}
}
@ -523,7 +408,7 @@ point_t gfx_printBuffer(point_t start, fontSize_t size, textAlign_t alignment,
point_t pos;
pos.x = start.x + xo + xx;
pos.y = start.y + yo + yy;
gfx_setPixel(pos, color);
framebuffer_setPixel(pos, color);
}
}
@ -684,10 +569,10 @@ void gfx_drawBattery(point_t start, uint16_t width, uint16_t height,
bottom_right.x += width - 1;
bottom_right.y += height - 1;
gfx_setPixel(top_left, black);
gfx_setPixel(top_right, black);
gfx_setPixel(bottom_left, black);
gfx_setPixel(bottom_right, black);
framebuffer_setPixel(top_left, black);
framebuffer_setPixel(top_right, black);
framebuffer_setPixel(bottom_left, black);
framebuffer_setPixel(bottom_right, black);
// Draw the button
point_t button_start;
@ -741,7 +626,7 @@ void gfx_drawSmeter(point_t start, uint16_t width, uint16_t height, rssi_t rssi,
color = (i > 9) ? red : color;
point_t pixel_pos = start;
pixel_pos.x += i * (width - 1) / 11;
gfx_setPixel(pixel_pos, color);
framebuffer_setPixel(pixel_pos, color);
pixel_pos.y += height;
if (i == 10) {
pixel_pos.x -= 8;
@ -834,9 +719,9 @@ void gfx_drawSmeterLevel(point_t start, uint16_t width, uint16_t height, rssi_t
{
point_t pixel_pos = {start.x, (uint8_t) (start.y + volume_height)};
pixel_pos.x += i * (width - 1) / 4;
gfx_setPixel(pixel_pos, white);
framebuffer_setPixel(pixel_pos, white);
pixel_pos.y += ((bar_height / bar_height_divider * 3) + 3);
gfx_setPixel(pixel_pos, white);
framebuffer_setPixel(pixel_pos, white);
}
// Level bar
uint16_t level_height = bar_height * 3 / bar_height_divider;

Wyświetl plik

@ -25,6 +25,7 @@
#include <string.h>
#include <miosix.h>
#include <kernel/scheduler/scheduler.h>
#include <framebuffer.h>
/**
* LCD command set, basic and extended
@ -90,6 +91,7 @@
using namespace miosix;
static Thread *lcdWaiting = 0;
static PIXEL_T *framebuffer;
void __attribute__((used)) DmaImpl()
{
@ -122,6 +124,9 @@ static inline __attribute__((__always_inline__)) void writeData(uint8_t val)
void display_init()
{
framebuffer_init(0);
framebuffer = framebuffer_getPointer();
/* Initialise backlight driver */
backlight_init();
@ -431,9 +436,10 @@ void display_terminate()
/* Shut off FSMC and deallocate framebuffer */
RCC->AHB3ENR &= ~RCC_AHB3ENR_FSMCEN;
__DSB();
framebuffer_terminate();
}
void display_renderRows(uint8_t startRow, uint8_t endRow, void *fb)
void display_renderRows(uint8_t startRow, uint8_t endRow)
{
/*
* Put screen data lines back to alternate function mode, since they are in
@ -456,7 +462,7 @@ void display_renderRows(uint8_t startRow, uint8_t endRow, void *fb)
* the CS pin low, in this way user code calling the renderingInProgress
* function gets true as return value and does not stomp our work.
*/
uint16_t *frameBuffer = (uint16_t *) fb;
uint16_t *frameBuffer = (uint16_t *) framebuffer;
for(uint8_t y = startRow; y < endRow; y++)
{
for(uint8_t x = 0; x < CONFIG_SCREEN_WIDTH; x++)
@ -511,9 +517,9 @@ void display_renderRows(uint8_t startRow, uint8_t endRow, void *fb)
}
}
void display_render(void *fb)
void display_render()
{
display_renderRows(0, CONFIG_SCREEN_HEIGHT, fb);
display_renderRows(0, CONFIG_SCREEN_HEIGHT);
}
void display_setContrast(uint8_t contrast)

Wyświetl plik

@ -22,9 +22,7 @@
#include <zephyr/device.h>
#include <hwconfig.h>
#include <string.h>
// Display is monochromatic, one bit per pixel
#define FB_SIZE ((CONFIG_SCREEN_HEIGHT * CONFIG_SCREEN_WIDTH) / 8 + 1)
#include <framebuffer.h>
static const struct device *displayDev;
static const struct display_buffer_descriptor displayBufDesc =
@ -36,29 +34,33 @@ static const struct display_buffer_descriptor displayBufDesc =
};
static uint8_t shadowBuffer[FB_SIZE];
static PIXEL_T *framebuffer;
void display_init()
{
framebuffer_init(0);
framebuffer = framebuffer_getPointer();
// Get display handle
displayDev = DEVICE_DT_GET(DT_CHOSEN(zephyr_display));
}
void display_terminate()
{
framebuffer_terminate();
}
void display_renderRows(uint8_t startRow, uint8_t endRow, void *fb)
void display_renderRows(uint8_t startRow, uint8_t endRow)
{
(void) startRow;
(void) endRow;
// Only complete rendering is supported
display_render(fb);
display_render();
}
void display_render(void *fb)
void display_render()
{
uint8_t *frameBuffer = (uint8_t *) fb;
memset(shadowBuffer, 0x00, FB_SIZE);
for(uint8_t y = 0; y < CONFIG_SCREEN_HEIGHT; y++)
@ -66,7 +68,7 @@ void display_render(void *fb)
for(uint8_t x = 0; x < CONFIG_SCREEN_WIDTH; x++)
{
size_t cell = x / 8 + y * (CONFIG_SCREEN_WIDTH / 8);
bool pixel = frameBuffer[cell] & (1 << (x % 8));
bool pixel = framebuffer[cell] & (1 << (x % 8));
if (pixel)
shadowBuffer[x + y / 8 * CONFIG_SCREEN_WIDTH] |= 1 << (y % 8);
}

Wyświetl plik

@ -28,9 +28,15 @@
#include <hwconfig.h>
#include <SPI2.h>
#include "SH110x_Mod17.h"
#include <framebuffer.h>
static PIXEL_T *framebuffer;
void SH110x_init()
{
framebuffer_init(0);
framebuffer = framebuffer_getPointer();
gpio_setPin(LCD_CS);
gpio_clearPin(LCD_DC);
@ -64,40 +70,43 @@ void SH110x_init()
spi2_sendRecv(0xA4); /* SH110X_DISPLAYALLON_RESUME */
spi2_sendRecv(0xA6); /* SH110X_NORMALDISPLAY */
spi2_sendRecv(0xAF); /* SH110x_DISPLAYON */
spi2_sendRecv(0x21);
gpio_setPin(LCD_CS);
}
void SH110x_terminate()
{
spi2_sendRecv(0xAE);
framebuffer_terminate();
}
void SH110x_renderRows(uint8_t startRow, uint8_t endRow, void *fb)
void SH110x_renderRows(uint8_t startRow, uint8_t endRow)
{
gpio_clearPin(LCD_CS);
gpio_clearPin(LCD_DC); /* RS low -> command mode */
(void) spi2_sendRecv(0xB0); /* Set X position */
gpio_setPin(LCD_DC); /* RS high -> data mode */
size_t index = 0;
uint8_t *frameBuffer = (uint8_t *) fb;
for(uint8_t y = startRow; y < endRow; y++)
{
gpio_clearPin(LCD_DC); /* RS low -> command mode */
(void) spi2_sendRecv(y & 0x0F); /* Set Y position */
(void) spi2_sendRecv(0x10 | ((y >> 4) & 0x07));
gpio_setPin(LCD_DC); /* RS high -> data mode */
for(uint8_t x = 0; x < CONFIG_SCREEN_WIDTH/8; x++)
{
gpio_clearPin(LCD_DC); /* RS low -> command mode */
(void) spi2_sendRecv(y & 0x0F); /* Set Y position */
(void) spi2_sendRecv(0x10 | ((y >> 4) & 0x07));
(void) spi2_sendRecv(0xB0 | x); /* Set X position */
gpio_setPin(LCD_DC); /* RS high -> data mode */
size_t pos = x + y * (CONFIG_SCREEN_WIDTH/8);
spi2_sendRecv(frameBuffer[pos]);
spi2_sendRecv(framebuffer[index++]);
}
}
gpio_setPin(LCD_CS);
}
void SH110x_render(void *fb)
void SH110x_render()
{
SH110x_renderRows(0, CONFIG_SCREEN_HEIGHT, fb);
SH110x_renderRows(0, CONFIG_SCREEN_HEIGHT);
}
void SH110x_setContrast(uint8_t contrast)

Wyświetl plik

@ -12,9 +12,9 @@ void SH110x_init();
void SH110x_terminate();
void SH110x_renderRows(uint8_t startRow, uint8_t endRow, void *fb);
void SH110x_renderRows(uint8_t startRow, uint8_t endRow);
void SH110x_render(void *fb);
void SH110x_render();
void SH110x_setContrast(uint8_t contrast);

Wyświetl plik

@ -28,7 +28,9 @@
#include <interfaces/delays.h>
#include <hwconfig.h>
#include <SPI2.h>
#include <framebuffer.h>
static PIXEL_T *framebuffer;
/**
* \internal
@ -38,12 +40,12 @@
*
* @param row: pixel row to be be sent.
*/
void SSD1306_renderRow(uint8_t row, uint8_t *frameBuffer)
void SSD1306_renderRow(uint8_t row)
{
for(uint16_t i = 0; i < 64; i++)
{
uint8_t out = 0;
uint8_t tmp = frameBuffer[(i * 16) + (15 - row)];
uint8_t tmp = framebuffer[(i * 16) + (15 - row)];
for(uint8_t j = 0; j < 8; j++)
{
@ -57,6 +59,9 @@ void SSD1306_renderRow(uint8_t row, uint8_t *frameBuffer)
void SSD1306_init()
{
framebuffer_init(0);
framebuffer = framebuffer_getPointer();
gpio_setPin(LCD_CS);
gpio_clearPin(LCD_RS);
@ -96,9 +101,10 @@ void SSD1306_init()
void SSD1306_terminate()
{
spi2_terminate();
framebuffer_terminate();
}
void SSD1306_renderRows(uint8_t startRow, uint8_t endRow, void *fb)
void SSD1306_renderRows(uint8_t startRow, uint8_t endRow)
{
gpio_clearPin(LCD_CS);
@ -109,15 +115,15 @@ void SSD1306_renderRows(uint8_t startRow, uint8_t endRow, void *fb)
(void) spi2_sendRecv(0x00); /* Set X position */
(void) spi2_sendRecv(0x10);
gpio_setPin(LCD_RS); /* RS high -> data mode */
SSD1306_renderRow(row, (uint8_t *) fb);
SSD1306_renderRow(row, framebuffer);
}
gpio_setPin(LCD_CS);
}
void SSD1306_render(void *fb)
void SSD1306_render()
{
SSD1306_renderRows(0, (CONFIG_SCREEN_WIDTH / 8) - 1, fb);
SSD1306_renderRows(0, (CONFIG_SCREEN_WIDTH / 8) - 1, framebuffer);
}
void SSD1306_setContrast(uint8_t contrast)

Wyświetl plik

@ -28,9 +28,15 @@
#include <hwconfig.h>
#include <SPI2.h>
#include "SSD1309_Mod17.h"
#include <framebuffer.h>
static PIXEL_T *framebuffer;
void SSD1309_init()
{
framebuffer_init(1);
framebuffer = framebuffer_getPointer();
gpio_setPin(LCD_CS);
gpio_clearPin(LCD_DC);
@ -61,9 +67,10 @@ void SSD1309_init()
void SSD1309_terminate()
{
spi2_sendRecv(0xAE);
framebuffer_terminate();
}
void SSD1309_renderRows(uint8_t startRow, uint8_t endRow, void *fb)
void SSD1309_renderRows(uint8_t startRow, uint8_t endRow)
{
gpio_clearPin(LCD_CS);
@ -72,11 +79,9 @@ void SSD1309_renderRows(uint8_t startRow, uint8_t endRow, void *fb)
uint8_t endPage = endRow / 8;
gpio_clearPin(LCD_DC);
spi2_sendRecv(0x20); // Set page addressing mode
spi2_sendRecv(0x20); // Set page addressing mode to horizontal
spi2_sendRecv(0x02);
uint8_t *framebuffer = (uint8_t *)fb;
for(uint8_t page = startPage; page < endPage; page++)
{
gpio_clearPin(LCD_DC);
@ -86,7 +91,6 @@ void SSD1309_renderRows(uint8_t startRow, uint8_t endRow, void *fb)
gpio_setPin(LCD_DC); // DC high -> data mode
uint8_t topRow = page*8;
for(uint8_t col = 0; col < CONFIG_SCREEN_WIDTH; col++)
{
uint8_t data = 0;
@ -105,10 +109,9 @@ void SSD1309_renderRows(uint8_t startRow, uint8_t endRow, void *fb)
gpio_setPin(LCD_CS);
}
void SSD1309_render(void *fb)
void SSD1309_render()
{
gpio_clearPin(LCD_CS);
gpio_clearPin(LCD_DC);
spi2_sendRecv(0xB0);
spi2_sendRecv(0x20); // Set horizontal addressing mode
@ -117,24 +120,8 @@ void SSD1309_render(void *fb)
spi2_sendRecv(0x10);
gpio_setPin(LCD_DC); // DC high -> data mode
uint8_t *framebuffer = (uint8_t *)fb;
// Refresh the whole screen 8 rows by 8 rows
for(uint8_t topRow = 0; topRow <= 56; topRow += 8)
{
for(uint8_t col = 0; col < CONFIG_SCREEN_WIDTH; col++)
{
uint8_t data = 0;
uint8_t bit_offset = col%8; // Bit offset in the fb for the column we are refreshing
// Gather the 8 rows of data
for(uint8_t subRow = 0; subRow < 8; subRow++)
{
uint8_t cell = framebuffer[((topRow+subRow)*CONFIG_SCREEN_WIDTH+col)/8];
data |= ((cell>>bit_offset)&0x01) << subRow;
}
spi2_sendRecv(data);
}
for(size_t i = 0; i < FB_SIZE; i++){
spi2_sendRecv(framebuffer[i]);
}
gpio_setPin(LCD_CS);

Wyświetl plik

@ -34,9 +34,9 @@ void SSD1309_init();
void SSD1309_terminate();
void SSD1309_renderRows(uint8_t startRow, uint8_t endRow, void *fb);
void SSD1309_renderRows(uint8_t startRow, uint8_t endRow);
void SSD1309_render(void *fb);
void SSD1309_render();
void SSD1309_setContrast(uint8_t contrast);

Wyświetl plik

@ -27,7 +27,9 @@
#include <interfaces/delays.h>
#include "hwconfig.h"
#include <SPI2.h>
#include <framebuffer.h>
static PIXEL_T *framebuffer;
/**
* \internal
@ -67,6 +69,9 @@ static void display_renderRow(uint8_t row, uint8_t *frameBuffer)
void display_init()
{
framebuffer_init(0);
framebuffer = framebuffer_getPointer();
gpio_setMode(LCD_CS, OUTPUT);
gpio_setMode(LCD_RST, OUTPUT);
gpio_setMode(LCD_RS, OUTPUT);
@ -98,10 +103,10 @@ void display_init()
void display_terminate()
{
framebuffer_terminate();
}
void display_renderRows(uint8_t startRow, uint8_t endRow, void *fb)
void display_renderRows(uint8_t startRow, uint8_t endRow)
{
spi2_lockDeviceBlocking();
gpio_clearPin(LCD_CS);
@ -113,16 +118,16 @@ void display_renderRows(uint8_t startRow, uint8_t endRow, void *fb)
(void) spi2_sendRecv(0x10); /* Set X position */
(void) spi2_sendRecv(0x04);
gpio_setPin(LCD_RS); /* RS high -> data mode */
display_renderRow(row, (uint8_t *) fb);
display_renderRow(row, framebuffer);
}
gpio_setPin(LCD_CS);
spi2_releaseDevice();
}
void display_render(void *fb)
void display_render()
{
display_renderRows(0, CONFIG_SCREEN_HEIGHT / 8, fb);
display_renderRows(0, CONFIG_SCREEN_HEIGHT / 8);
}
void display_setContrast(uint8_t contrast)

Wyświetl plik

@ -27,6 +27,9 @@
#include <interfaces/display.h>
#include <interfaces/delays.h>
#include <hwconfig.h>
#include <framebuffer.h>
static PIXEL_T *framebuffer;
/**
* \internal
@ -62,10 +65,10 @@ static void sendByteToController(uint8_t value)
*
* @param row: pixel row to be be sent.
*/
static void display_renderRow(uint8_t row, uint8_t *frameBuffer)
static void display_renderRow(uint8_t row)
{
/* magic stuff */
uint8_t *buf = (frameBuffer + 128 * row);
uint8_t *buf = (framebuffer + 128 * row);
for (uint8_t i = 0; i<16; i++)
{
uint8_t tmp[8] = {0};
@ -92,6 +95,9 @@ static void display_renderRow(uint8_t row, uint8_t *frameBuffer)
void display_init()
{
framebuffer_init(0);
framebuffer = framebuffer_getPointer();
backlight_init(); /* Initialise backlight driver */
gpio_setMode(LCD_CS, OUTPUT);
@ -132,9 +138,10 @@ void display_terminate()
gpio_setMode(LCD_RS, INPUT);
gpio_setMode(LCD_CLK, INPUT);
gpio_setMode(LCD_DAT, INPUT);
framebuffer_terminate();
}
void display_renderRows(uint8_t startRow, uint8_t endRow, void *fb)
void display_renderRows(uint8_t startRow, uint8_t endRow)
{
for(uint8_t row = startRow; row < endRow; row++)
{
@ -143,14 +150,14 @@ void display_renderRows(uint8_t startRow, uint8_t endRow, void *fb)
sendByteToController(0x10); /* Set X position */
sendByteToController(0x04);
gpio_setPin(LCD_RS); /* RS high -> data mode */
display_renderRow(row, (uint8_t *) fb);
display_renderRow(row);
}
}
void display_render(void *fb)
void display_render()
{
display_renderRows(0, CONFIG_SCREEN_HEIGHT / 8, fb);
display_renderRows(0, CONFIG_SCREEN_HEIGHT / 8);
}
void display_setContrast(uint8_t contrast)

Wyświetl plik

@ -25,6 +25,7 @@
#include "SH110x_Mod17.h"
#include "SSD1309_Mod17.h"
#include <SPI2.h>
#include <framebuffer.h>
const hwInfo_t *hwInfo = NULL;
Mod17_HwInfo_t *mod17HwInfo = NULL;
@ -32,8 +33,8 @@ Mod17_HwInfo_t *mod17HwInfo = NULL;
typedef struct {
void (*init)(void);
void (*terminate)(void);
void (*renderRows)(uint8_t , uint8_t, void *);
void (*render)(void *);
void (*renderRows)(uint8_t , uint8_t);
void (*render)();
void (*setContrast)(uint8_t);
void (*setBacklightLevel)(uint8_t);
} display_fcts_t;
@ -97,14 +98,14 @@ void display_terminate()
spi2_terminate();
}
void display_renderRows(uint8_t startRow, uint8_t endRow, void *fb)
void display_renderRows(uint8_t startRow, uint8_t endRow)
{
disp_fcts.renderRows(startRow, endRow, fb);
disp_fcts.renderRows(startRow, endRow);
}
void display_render(void *fb)
void display_render()
{
disp_fcts.render(fb);
disp_fcts.render();
}
void display_setContrast(uint8_t contrast)

Wyświetl plik

@ -31,8 +31,10 @@
#include <stdio.h>
#include <string.h>
#include <SDL2/SDL.h>
#include <framebuffer.h>
static bool inProgress; /* Flag to signal when rendering is in progress */
static PIXEL_T *framebuffer;
/*
* SDL main loop syncronization
@ -49,11 +51,10 @@ extern Uint32 SDL_Backlight_Event;
* Internal helper function which fetches pixel at position (x, y) from framebuffer
* and returns it in SDL-compatible format, which is ARGB8888.
*/
static uint32_t fetchPixelFromFb(unsigned int x, unsigned int y, void *fb)
static uint32_t fetchPixelFromFb(unsigned int x, unsigned int y)
{
(void) x;
(void) y;
(void) fb;
uint32_t pixel = 0;
#ifdef CONFIG_PIX_FMT_BW
@ -61,10 +62,9 @@ static uint32_t fetchPixelFromFb(unsigned int x, unsigned int y, void *fb)
* Black and white 1bpp format: framebuffer is an array of uint8_t, where
* each cell contains the values of eight pixels, one per bit.
*/
uint8_t *buf = (uint8_t *)(fb);
unsigned int cell = (x + y*CONFIG_SCREEN_WIDTH) / 8;
unsigned int elem = (x + y*CONFIG_SCREEN_WIDTH) % 8;
if(buf[cell] & (1 << elem)) pixel = 0xFFFFFFFF;
if(framebuffer[cell] & (1 << elem)) pixel = 0xFFFFFFFF;
#endif
#ifdef PIX_FMT_GRAYSC
@ -72,7 +72,7 @@ static uint32_t fetchPixelFromFb(unsigned int x, unsigned int y, void *fb)
* Convert from 8bpp grayscale to ARGB8888, we have to do nothing more that
* replicating the pixel value for the three components
*/
uint8_t *buf = (uint8_t *)(fb);
uint8_t *buf = (uint8_t *)(framebuffer);
uint8_t px = buf[x + y*CONFIG_SCREEN_WIDTH];
pixel = 0xFF000000 | (px << 16) | (px << 8) | px;
@ -85,6 +85,8 @@ static uint32_t fetchPixelFromFb(unsigned int x, unsigned int y, void *fb)
void display_init()
{
inProgress = false;
framebuffer_init(0);
framebuffer = framebuffer_getPointer();
}
void display_terminate()
@ -92,9 +94,10 @@ void display_terminate()
while (inProgress){ } /* Wait until current render finishes */
chan_close(&fb_sync);
chan_terminate(&fb_sync);
framebuffer_terminate();
}
void display_renderRows(uint8_t startRow, uint8_t endRow, void *fb)
void display_renderRows(uint8_t startRow, uint8_t endRow)
{
(void) startRow;
(void) endRow;
@ -110,14 +113,14 @@ void display_renderRows(uint8_t startRow, uint8_t endRow, void *fb)
void *pixelMap;
chan_recv(&fb_sync, &pixelMap);
#ifdef CONFIG_PIX_FMT_RGB565
memcpy(pixelMap, fb, sizeof(PIXEL_SIZE) * CONFIG_SCREEN_HEIGHT * CONFIG_SCREEN_WIDTH);
memcpy(pixelMap, framebuffer, sizeof(PIXEL_SIZE) * CONFIG_SCREEN_HEIGHT * CONFIG_SCREEN_WIDTH);
#else
uint32_t *pixels = (uint32_t *) pixelMap;
for (unsigned int x = 0; x < CONFIG_SCREEN_WIDTH; x++)
{
for (unsigned int y = startRow; y < endRow; y++)
{
pixels[x + y * CONFIG_SCREEN_WIDTH] = fetchPixelFromFb(x, y, fb);
pixels[x + y * CONFIG_SCREEN_WIDTH] = fetchPixelFromFb(x, y);
}
}
#endif
@ -129,9 +132,9 @@ void display_renderRows(uint8_t startRow, uint8_t endRow, void *fb)
inProgress = false;
}
void display_render(void *fb)
void display_render()
{
display_renderRows(0, CONFIG_SCREEN_HEIGHT, fb);
display_renderRows(0, CONFIG_SCREEN_HEIGHT);
}
void display_setContrast(uint8_t contrast)

Wyświetl plik

@ -34,6 +34,9 @@
/* Screen pixel format */
#define CONFIG_PIX_FMT_BW
/* Device supports bit banding */
#define CONFIG_BIT_BANDING
/* Device has no battery */
#define CONFIG_BAT_NONE