Changed allocation of display framebuffers from dynamic to static. Reorganised code in some of the display drivers.

This commit is contained in:
Silvano Seva 2022-08-10 12:26:04 +02:00
parent f1dbfbfe1f
commit 57349cba80
7 changed files with 158 additions and 190 deletions

View File

@ -87,13 +87,14 @@
#define LCD_FSMC_ADDR_DATA 0x60040000 #define LCD_FSMC_ADDR_DATA 0x60040000
/* /*
* LCD framebuffer, dynamically allocated. * LCD framebuffer, statically allocated and placed in the "large" RAM block
* Pixel format is RGB565, 16 bit per pixel * starting at 0x20000000 and accessible by the DMA.
* Pixel format is RGB565, 16 bit per pixel.
*/ */
static uint16_t *frameBuffer; static uint16_t __attribute__((section(".bss2"))) frameBuffer[SCREEN_WIDTH * SCREEN_HEIGHT];
using namespace miosix; using namespace miosix;
Thread *lcdWaiting = 0; static Thread *lcdWaiting = 0;
void __attribute__((used)) DmaImpl() void __attribute__((used)) DmaImpl()
{ {
@ -126,14 +127,8 @@ static inline __attribute__((__always_inline__)) void writeData(uint8_t val)
void display_init() void display_init()
{ {
/* Clear framebuffer, setting all pixels to 0x00 makes the screen white */
/* Allocate and clear framebuffer, setting all pixels to 0xFFFF makes the memset(frameBuffer, 0x00, SCREEN_WIDTH * SCREEN_HEIGHT * sizeof(uint16_t));
* screen white.
*
* TODO: handle the case when memory allocation fails!
*/
frameBuffer = ((uint16_t *) malloc(SCREEN_WIDTH * SCREEN_HEIGHT * sizeof(uint16_t)));
memset(frameBuffer, 0xFF, SCREEN_WIDTH * SCREEN_HEIGHT * sizeof(uint16_t));
/* /*
* Turn on DMA2 and configure its interrupt. DMA is used to transfer the * Turn on DMA2 and configure its interrupt. DMA is used to transfer the
@ -435,8 +430,6 @@ void display_init()
void display_terminate() void display_terminate()
{ {
free(frameBuffer);
/* Shut off FSMC and deallocate framebuffer */ /* Shut off FSMC and deallocate framebuffer */
RCC->AHB3ENR &= ~RCC_AHB3ENR_FSMCEN; RCC->AHB3ENR &= ~RCC_AHB3ENR_FSMCEN;
__DSB(); __DSB();

View File

@ -30,32 +30,18 @@
#include <SPI2.h> #include <SPI2.h>
/* /*
* LCD framebuffer, allocated on the heap by display_init(). * LCD framebuffer, statically allocated and placed in the "large" RAM block
* Pixel format is black and white, one bit per pixel * starting at 0x20000000.
* Pixel format is black and white, one bit per pixel.
*/ */
static uint8_t *frameBuffer; #define FB_SIZE (((SCREEN_HEIGHT * SCREEN_WIDTH) / 8 ) + 1)
static uint8_t __attribute__((section(".bss2"))) frameBuffer[FB_SIZE];
void display_init() void display_init()
{ {
/*
* Framebuffer size, in bytes, with compensating for eventual truncation
* error in division by rounding to the nearest greater integer.
*/
unsigned int fbSize = (SCREEN_HEIGHT * SCREEN_WIDTH)/8;
if((fbSize * 8) < (SCREEN_HEIGHT * SCREEN_WIDTH)) fbSize += 1;
fbSize *= sizeof(uint8_t);
/* Allocate framebuffer */
frameBuffer = (uint8_t *) malloc(fbSize);
if(frameBuffer == NULL)
{
puts("*** LCD ERROR: cannot allocate framebuffer! ***");
return;
}
/* Clear framebuffer, setting all pixels to 0x00 makes the screen white */ /* Clear framebuffer, setting all pixels to 0x00 makes the screen white */
memset(frameBuffer, 0x00, fbSize); memset(frameBuffer, 0x00, FB_SIZE);
/* /*
* Initialise SPI2 for external flash and LCD * Initialise SPI2 for external flash and LCD
@ -114,11 +100,6 @@ void display_init()
void display_terminate() void display_terminate()
{ {
if(frameBuffer != NULL)
{
free(frameBuffer);
}
spi2_terminate(); spi2_terminate();
} }

View File

@ -29,33 +29,44 @@
#include <hwconfig.h> #include <hwconfig.h>
#include <SPI2.h> #include <SPI2.h>
/* /*
* LCD framebuffer, allocated on the heap by display_init(). * LCD framebuffer, statically allocated and placed in the "large" RAM block
* Pixel format is black and white, one bit per pixel * starting at 0x20000000.
* Pixel format is black and white, one bit per pixel.
*/ */
static uint8_t *frameBuffer; #define FB_SIZE (((SCREEN_HEIGHT * SCREEN_WIDTH) / 8 ) + 1)
static uint8_t __attribute__((section(".bss2"))) frameBuffer[FB_SIZE];
/**
* \internal
* Send one row of pixels to the display.
* Pixels in framebuffer are stored "by rows", while display needs data to be
* sent "by columns": this function performs the needed conversion.
*
* @param row: pixel row to be be sent.
*/
void display_renderRow(uint8_t row)
{
for(uint16_t i = 0; i < 64; i++)
{
uint8_t out = 0;
uint8_t tmp = frameBuffer[(i * 16) + (15 - row)];
for(uint8_t j = 0; j < 8; j++)
{
out |= ((tmp >> (7-j)) & 0x01) << j;
}
spi2_sendRecv(out);
}
}
void display_init() void display_init()
{ {
/*
* Framebuffer size, in bytes, with compensating for eventual truncation
* error in division by rounding to the nearest greater integer.
*/
unsigned int fbSize = (SCREEN_HEIGHT * SCREEN_WIDTH)/8;
if((fbSize * 8) < (SCREEN_HEIGHT * SCREEN_WIDTH)) fbSize += 1;
fbSize *= sizeof(uint8_t);
/* Allocate framebuffer */
frameBuffer = (uint8_t *) malloc(fbSize);
if(frameBuffer == NULL)
{
puts("*** LCD ERROR: cannot allocate framebuffer! ***");
return;
}
/* Clear framebuffer, setting all pixels to 0x00 makes the screen white */ /* Clear framebuffer, setting all pixels to 0x00 makes the screen white */
memset(frameBuffer, 0x00, fbSize); memset(frameBuffer, 0x00, FB_SIZE);
/* /*
* Initialise SPI2 for external flash and LCD * Initialise SPI2 for external flash and LCD
@ -79,18 +90,17 @@ void display_init()
gpio_setPin(LCD_CS); gpio_setPin(LCD_CS);
gpio_clearPin(LCD_RS); gpio_clearPin(LCD_RS);
gpio_clearPin(LCD_RST); /* Reset controller */ gpio_clearPin(LCD_RST); // Reset controller
delayMs(50); delayMs(50);
gpio_setPin(LCD_RST); gpio_setPin(LCD_RST);
delayMs(50); delayMs(50);
gpio_clearPin(LCD_CS); gpio_clearPin(LCD_CS);
gpio_clearPin(LCD_RS); /* RS low -> command mode */ gpio_clearPin(LCD_RS);// RS low -> command mode
spi2_sendRecv(0xAE); // SH110X_DISPLAYOFF, spi2_sendRecv(0xAE); // SH110X_DISPLAYOFF,
spi2_sendRecv(0xd5); // SH110X_SETDISPLAYCLOCKDIV, 0x51, spi2_sendRecv(0xd5); // SH110X_SETDISPLAYCLOCKDIV, 0x51,
spi2_sendRecv(0x51); spi2_sendRecv(0x51);
//spi2_sendRecv(0x20); // SH110X_MEMORYMODE,
spi2_sendRecv(0x81); // SH110X_SETCONTRAST, 0x4F, spi2_sendRecv(0x81); // SH110X_SETCONTRAST, 0x4F,
spi2_sendRecv(0x4F); spi2_sendRecv(0x4F);
spi2_sendRecv(0xAD); // SH110X_DCDC, 0x8A, spi2_sendRecv(0xAD); // SH110X_DCDC, 0x8A,
@ -115,31 +125,9 @@ void display_init()
void display_terminate() void display_terminate()
{ {
if(frameBuffer != NULL)
{
free(frameBuffer);
}
spi2_terminate(); spi2_terminate();
} }
void display_renderRow(uint8_t row)
{
uint8_t *buf = (frameBuffer);
for(uint16_t i=0; i<64; i++)
{
uint8_t out=0, tmp=buf[i*16 + 15-row];
for(uint8_t j=0; j<8; j++)
{
out|=((tmp>>(7-j))&1)<<j;
}
spi2_sendRecv(out);
}
}
void display_renderRows(uint8_t startRow, uint8_t endRow) void display_renderRows(uint8_t startRow, uint8_t endRow)
{ {
gpio_clearPin(LCD_CS); gpio_clearPin(LCD_CS);
@ -159,7 +147,7 @@ void display_renderRows(uint8_t startRow, uint8_t endRow)
void display_render() void display_render()
{ {
display_renderRows(0, SCREEN_WIDTH / 8 - 1); display_renderRows(0, (SCREEN_WIDTH / 8) - 1);
} }
bool display_renderingInProgress() bool display_renderingInProgress()

View File

@ -29,28 +29,53 @@
#include <SPI2.h> #include <SPI2.h>
/* /*
* LCD framebuffer, allocated on the heap by display_init(). * LCD framebuffer, statically allocated and placed in the "large" RAM block
* Pixel format is black and white, one bit per pixel * starting at 0x20000000.
* Pixel format is black and white, one bit per pixel.
*/ */
static uint8_t *frameBuffer; #define FB_SIZE (((SCREEN_HEIGHT * SCREEN_WIDTH) / 8 ) + 1)
static uint8_t __attribute__((section(".bss2"))) frameBuffer[FB_SIZE];
/**
* \internal
* Send one row of pixels to the display.
* Pixels in framebuffer are stored "by rows", while display needs data to be
* sent "by columns": this function performs the needed conversion.
*
* @param row: pixel row to be be sent.
*/
static void display_renderRow(uint8_t row)
{
/* magic stuff */
uint8_t *buf = (frameBuffer + 128 * row);
for (uint8_t i = 0; i<16; i++)
{
uint8_t tmp[8] = {0};
for (uint8_t j = 0; j < 8; j++)
{
uint8_t tmp_buf = buf[j*16 + i];
int count = __builtin_popcount(tmp_buf);
while (count > 0)
{
int pos = __builtin_ctz(tmp_buf);
tmp[pos] |= 1UL << j;
tmp_buf &= ~(1 << pos);
count--;
}
}
for (uint8_t s = 0; s < 8; s++)
{
(void) spi2_sendRecv(tmp[s]);
}
}
}
void display_init() void display_init()
{ {
/* Framebuffer size, in bytes */
unsigned int fbSize = (SCREEN_HEIGHT * SCREEN_WIDTH)/8;
if((fbSize * 8) < (SCREEN_HEIGHT * SCREEN_WIDTH)) fbSize += 1; /* Compensate for eventual truncation error in division */
fbSize *= sizeof(uint8_t);
/* Allocate framebuffer */
frameBuffer = (uint8_t *) malloc(fbSize);
if(frameBuffer == NULL)
{
puts("*** LCD ERROR: cannot allocate framebuffer! ***");
return;
}
/* Clear framebuffer, setting all pixels to 0x00 makes the screen white */ /* Clear framebuffer, setting all pixels to 0x00 makes the screen white */
memset(frameBuffer, 0x00, fbSize); memset(frameBuffer, 0x00, FB_SIZE);
gpio_setMode(LCD_CS, OUTPUT); gpio_setMode(LCD_CS, OUTPUT);
gpio_setMode(LCD_RST, OUTPUT); gpio_setMode(LCD_RST, OUTPUT);
@ -83,37 +108,7 @@ void display_init()
void display_terminate() void display_terminate()
{ {
if(frameBuffer != NULL)
{
free(frameBuffer);
}
}
void display_renderRow(uint8_t row)
{
/* magic stuff */
uint8_t *buf = (frameBuffer + 128 * row);
for (uint8_t i = 0; i<16; i++)
{
uint8_t tmp[8] = {0};
for (uint8_t j = 0; j < 8; j++)
{
uint8_t tmp_buf = buf[j*16 + i];
int count = __builtin_popcount(tmp_buf);
while (count > 0)
{
int pos = __builtin_ctz(tmp_buf);
tmp[pos] |= 1UL << j;
tmp_buf &= ~(1 << pos);
count--;
}
}
for (uint8_t s = 0; s < 8; s++)
{
(void) spi2_sendRecv(tmp[s]);
}
}
} }
void display_renderRows(uint8_t startRow, uint8_t endRow) void display_renderRows(uint8_t startRow, uint8_t endRow)

View File

@ -28,12 +28,19 @@
#include "hwconfig.h" #include "hwconfig.h"
/* /*
* LCD framebuffer, allocated on the heap by display_init(). * LCD framebuffer, statically allocated.
* Pixel format is black and white, one bit per pixel * Pixel format is black and white, one bit per pixel
*/ */
static uint8_t *frameBuffer; #define FB_SIZE (((SCREEN_HEIGHT * SCREEN_WIDTH) / 8 ) + 1)
static uint8_t frameBuffer[FB_SIZE];
void sendByteToController(uint8_t value) /**
* \internal
* Send one byte to display controller, via bit banging.
*
* @param value: byte to be sent.
*/
static void sendByteToController(uint8_t value)
{ {
for(uint8_t i = 0; i < 8; i++) for(uint8_t i = 0; i < 8; i++)
{ {
@ -53,24 +60,44 @@ void sendByteToController(uint8_t value)
} }
} }
/**
* \internal
* Send one row of pixels to the display.
* Pixels in framebuffer are stored "by rows", while display needs data to be
* sent "by columns": this function performs the needed conversion.
*
* @param row: pixel row to be be sent.
*/
static void display_renderRow(uint8_t row)
{
/* magic stuff */
uint8_t *buf = (frameBuffer + 128 * row);
for (uint8_t i = 0; i<16; i++)
{
uint8_t tmp[8] = {0};
for (uint8_t j = 0; j < 8; j++)
{
uint8_t tmp_buf = buf[j*16 + i];
int count = __builtin_popcount(tmp_buf);
while (count > 0)
{
int pos = __builtin_ctz(tmp_buf);
tmp[pos] |= 1UL << j;
tmp_buf &= ~(1 << pos);
count--;
}
}
for (uint8_t s = 0; s < 8; s++)
{
sendByteToController(tmp[s]);
}
}
}
void display_init() void display_init()
{ {
/* Framebuffer size, in bytes */
unsigned int fbSize = (SCREEN_HEIGHT * SCREEN_WIDTH)/8;
if((fbSize * 8) < (SCREEN_HEIGHT * SCREEN_WIDTH)) fbSize += 1; /* Compensate for eventual truncation error in division */
fbSize *= sizeof(uint8_t);
/* Allocate framebuffer */
frameBuffer = (uint8_t *) malloc(fbSize);
if(frameBuffer == NULL)
{
puts("*** LCD ERROR: cannot allocate framebuffer! ***");
return;
}
/* Clear framebuffer, setting all pixels to 0x00 makes the screen white */
memset(frameBuffer, 0x00, fbSize);
gpio_setMode(LCD_CS, OUTPUT); gpio_setMode(LCD_CS, OUTPUT);
gpio_setMode(LCD_RST, OUTPUT); gpio_setMode(LCD_RST, OUTPUT);
gpio_setMode(LCD_RS, OUTPUT); gpio_setMode(LCD_RS, OUTPUT);
@ -102,37 +129,11 @@ void display_init()
void display_terminate() void display_terminate()
{ {
if(frameBuffer != NULL) gpio_setMode(LCD_CS, INPUT);
{ gpio_setMode(LCD_RST, INPUT);
free(frameBuffer); gpio_setMode(LCD_RS, INPUT);
} gpio_setMode(LCD_CLK, INPUT);
} gpio_setMode(LCD_DAT, INPUT);
void display_renderRow(uint8_t row)
{
/* magic stuff */
uint8_t *buf = (frameBuffer + 128 * row);
for (uint8_t i = 0; i<16; i++)
{
uint8_t tmp[8] = {0};
for (uint8_t j = 0; j < 8; j++)
{
uint8_t tmp_buf = buf[j*16 + i];
int count = __builtin_popcount(tmp_buf);
while (count > 0)
{
int pos = __builtin_ctz(tmp_buf);
tmp[pos] |= 1UL << j;
tmp_buf &= ~(1 << pos);
count--;
}
}
for (uint8_t s = 0; s < 8; s++)
{
sendByteToController(tmp[s]);
}
}
} }
void display_renderRows(uint8_t startRow, uint8_t endRow) void display_renderRows(uint8_t startRow, uint8_t endRow)

View File

@ -50,7 +50,6 @@ _main_stack_top = 0x20000000 + _main_stack_size;
ASSERT(_main_stack_size % 8 == 0, "MAIN stack size error"); ASSERT(_main_stack_size % 8 == 0, "MAIN stack size error");
/* Mapping the heap into the large 128KB RAM */ /* Mapping the heap into the large 128KB RAM */
_end = _main_stack_top;
_heap_end = 0x20020000; /* end of available ram */ _heap_end = 0x20020000; /* end of available ram */
/* identify the Entry Point */ /* identify the Entry Point */
@ -176,6 +175,12 @@ SECTIONS
} > smallram } > smallram
_bss_end = .; _bss_end = .;
/*_end = .;*/ .bss2 :
/*PROVIDE(end = .);*/ {
*(.bss2)
. = ALIGN(8);
} > largeram
_end = .;
PROVIDE(end = .);
} }

View File

@ -50,7 +50,6 @@ _main_stack_top = 0x10000000 + _main_stack_size;
ASSERT(_main_stack_size % 8 == 0, "MAIN stack size error"); ASSERT(_main_stack_size % 8 == 0, "MAIN stack size error");
/* Mapping the heap into the large 128KB RAM */ /* Mapping the heap into the large 128KB RAM */
_end = 0x20000000;
_heap_end = 0x20020000; /* end of available ram */ _heap_end = 0x20020000; /* end of available ram */
/* identify the Entry Point */ /* identify the Entry Point */
@ -175,6 +174,12 @@ SECTIONS
} > smallram } > smallram
_bss_end = .; _bss_end = .;
/*_end = .;*/ .bss2 :
/*PROVIDE(end = .);*/ {
*(.bss2)
. = ALIGN(8);
} > largeram
_end = .;
PROVIDE(end = .);
} }