From 57349cba802ed327d93d8974e503b0b784cfe689 Mon Sep 17 00:00:00 2001 From: Silvano Seva Date: Wed, 10 Aug 2022 12:26:04 +0200 Subject: [PATCH] Changed allocation of display framebuffers from dynamic to static. Reorganised code in some of the display drivers. --- platform/drivers/display/HX8353_MD3x.cpp | 21 ++-- platform/drivers/display/SH110x_Mod17.c | 33 ++---- platform/drivers/display/SSD1306_Mod17.c | 82 ++++++-------- platform/drivers/display/ST7567_MD9600.c | 89 ++++++++------- platform/drivers/display/UC1701_GDx.c | 101 +++++++++--------- platform/mcu/STM32F4xx/linker_script_MDx.ld | 11 +- platform/mcu/STM32F4xx/linker_script_Mod17.ld | 11 +- 7 files changed, 158 insertions(+), 190 deletions(-) diff --git a/platform/drivers/display/HX8353_MD3x.cpp b/platform/drivers/display/HX8353_MD3x.cpp index 1dda92c5..8fbc6461 100644 --- a/platform/drivers/display/HX8353_MD3x.cpp +++ b/platform/drivers/display/HX8353_MD3x.cpp @@ -87,13 +87,14 @@ #define LCD_FSMC_ADDR_DATA 0x60040000 /* - * LCD framebuffer, dynamically allocated. - * Pixel format is RGB565, 16 bit per pixel + * LCD framebuffer, statically allocated and placed in the "large" RAM block + * 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; -Thread *lcdWaiting = 0; +static Thread *lcdWaiting = 0; void __attribute__((used)) DmaImpl() { @@ -126,14 +127,8 @@ static inline __attribute__((__always_inline__)) void writeData(uint8_t val) void display_init() { - - /* Allocate and clear framebuffer, setting all pixels to 0xFFFF makes the - * 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)); + /* Clear framebuffer, setting all pixels to 0x00 makes the screen white */ + memset(frameBuffer, 0x00, SCREEN_WIDTH * SCREEN_HEIGHT * sizeof(uint16_t)); /* * Turn on DMA2 and configure its interrupt. DMA is used to transfer the @@ -435,8 +430,6 @@ void display_init() void display_terminate() { - free(frameBuffer); - /* Shut off FSMC and deallocate framebuffer */ RCC->AHB3ENR &= ~RCC_AHB3ENR_FSMCEN; __DSB(); diff --git a/platform/drivers/display/SH110x_Mod17.c b/platform/drivers/display/SH110x_Mod17.c index f82f7aa3..17866e16 100644 --- a/platform/drivers/display/SH110x_Mod17.c +++ b/platform/drivers/display/SH110x_Mod17.c @@ -30,32 +30,18 @@ #include /* - * LCD framebuffer, allocated on the heap by display_init(). - * Pixel format is black and white, one bit per pixel + * LCD framebuffer, statically allocated and placed in the "large" RAM block + * 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() { - - /* - * 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 */ - memset(frameBuffer, 0x00, fbSize); + memset(frameBuffer, 0x00, FB_SIZE); /* * Initialise SPI2 for external flash and LCD @@ -114,11 +100,6 @@ void display_init() void display_terminate() { - if(frameBuffer != NULL) - { - free(frameBuffer); - } - spi2_terminate(); } diff --git a/platform/drivers/display/SSD1306_Mod17.c b/platform/drivers/display/SSD1306_Mod17.c index eb22e4bb..55565f31 100644 --- a/platform/drivers/display/SSD1306_Mod17.c +++ b/platform/drivers/display/SSD1306_Mod17.c @@ -29,33 +29,44 @@ #include #include + /* - * LCD framebuffer, allocated on the heap by display_init(). - * Pixel format is black and white, one bit per pixel + * LCD framebuffer, statically allocated and placed in the "large" RAM block + * 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() { - - /* - * 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 */ - memset(frameBuffer, 0x00, fbSize); + memset(frameBuffer, 0x00, FB_SIZE); /* * Initialise SPI2 for external flash and LCD @@ -79,18 +90,17 @@ void display_init() gpio_setPin(LCD_CS); gpio_clearPin(LCD_RS); - gpio_clearPin(LCD_RST); /* Reset controller */ + gpio_clearPin(LCD_RST); // Reset controller delayMs(50); gpio_setPin(LCD_RST); delayMs(50); 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(0xd5); // SH110X_SETDISPLAYCLOCKDIV, 0x51, spi2_sendRecv(0x51); - //spi2_sendRecv(0x20); // SH110X_MEMORYMODE, spi2_sendRecv(0x81); // SH110X_SETCONTRAST, 0x4F, spi2_sendRecv(0x4F); spi2_sendRecv(0xAD); // SH110X_DCDC, 0x8A, @@ -115,31 +125,9 @@ void display_init() void display_terminate() { - if(frameBuffer != NULL) - { - free(frameBuffer); - } - 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)< /* - * LCD framebuffer, allocated on the heap by display_init(). - * Pixel format is black and white, one bit per pixel + * LCD framebuffer, statically allocated and placed in the "large" RAM block + * 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() { - /* 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); + memset(frameBuffer, 0x00, FB_SIZE); gpio_setMode(LCD_CS, OUTPUT); gpio_setMode(LCD_RST, OUTPUT); @@ -83,37 +108,7 @@ void display_init() 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) diff --git a/platform/drivers/display/UC1701_GDx.c b/platform/drivers/display/UC1701_GDx.c index e3fb9ecb..e4c38cff 100644 --- a/platform/drivers/display/UC1701_GDx.c +++ b/platform/drivers/display/UC1701_GDx.c @@ -28,12 +28,19 @@ #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 */ -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++) { @@ -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() { - /* 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_RST, OUTPUT); gpio_setMode(LCD_RS, OUTPUT); @@ -102,37 +129,11 @@ void display_init() 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++) - { - sendByteToController(tmp[s]); - } - } + gpio_setMode(LCD_CS, INPUT); + gpio_setMode(LCD_RST, INPUT); + gpio_setMode(LCD_RS, INPUT); + gpio_setMode(LCD_CLK, INPUT); + gpio_setMode(LCD_DAT, INPUT); } void display_renderRows(uint8_t startRow, uint8_t endRow) diff --git a/platform/mcu/STM32F4xx/linker_script_MDx.ld b/platform/mcu/STM32F4xx/linker_script_MDx.ld index 598d8724..59ba6655 100644 --- a/platform/mcu/STM32F4xx/linker_script_MDx.ld +++ b/platform/mcu/STM32F4xx/linker_script_MDx.ld @@ -50,7 +50,6 @@ _main_stack_top = 0x20000000 + _main_stack_size; ASSERT(_main_stack_size % 8 == 0, "MAIN stack size error"); /* Mapping the heap into the large 128KB RAM */ -_end = _main_stack_top; _heap_end = 0x20020000; /* end of available ram */ /* identify the Entry Point */ @@ -176,6 +175,12 @@ SECTIONS } > smallram _bss_end = .; - /*_end = .;*/ - /*PROVIDE(end = .);*/ + .bss2 : + { + *(.bss2) + . = ALIGN(8); + } > largeram + + _end = .; + PROVIDE(end = .); } diff --git a/platform/mcu/STM32F4xx/linker_script_Mod17.ld b/platform/mcu/STM32F4xx/linker_script_Mod17.ld index 23e7597f..9070a814 100644 --- a/platform/mcu/STM32F4xx/linker_script_Mod17.ld +++ b/platform/mcu/STM32F4xx/linker_script_Mod17.ld @@ -50,7 +50,6 @@ _main_stack_top = 0x10000000 + _main_stack_size; ASSERT(_main_stack_size % 8 == 0, "MAIN stack size error"); /* Mapping the heap into the large 128KB RAM */ -_end = 0x20000000; _heap_end = 0x20020000; /* end of available ram */ /* identify the Entry Point */ @@ -175,6 +174,12 @@ SECTIONS } > smallram _bss_end = .; - /*_end = .;*/ - /*PROVIDE(end = .);*/ + .bss2 : + { + *(.bss2) + . = ALIGN(8); + } > largeram + + _end = .; + PROVIDE(end = .); }