From 3ccc0ca0f39b2aabf8b9e485f3d7c429f87cfc95 Mon Sep 17 00:00:00 2001 From: hasslesstech Date: Mon, 14 Apr 2025 16:53:13 +0300 Subject: [PATCH] [lcd] add support for operating on virtual framebuffers Current implementation contains full support for: - transparent switching between direct and framebuffer rendering modes - writing characters to framebuffers - loading frame from memory to physical display As well as partial support for instruction writes including: - resetting the display (clears memory, sets cursor at 0:0, switches to increment mode) - switching between increment/decrement modes - setting cursor position --- Core/Inc/lcd.h | 9 +++- Core/Inc/main.h | 2 + Core/Src/lcd.c | 108 +++++++++++++++++++++++++++++++++++---- Core/Src/main.c | 26 +++++++++- Debug/Core/Src/subdir.mk | 5 +- Debug/objects.list | 1 - 6 files changed, 132 insertions(+), 19 deletions(-) diff --git a/Core/Inc/lcd.h b/Core/Inc/lcd.h index 05aef0a..c7c0e85 100644 --- a/Core/Inc/lcd.h +++ b/Core/Inc/lcd.h @@ -7,6 +7,8 @@ #define DISPLAY_RW ((uint16_t) (0x1U << 10)) #define DISPLAY_ENA ((uint16_t) (0x1U << 11)) +#define DISPLAY_FRAMES_AVAILABLE 14 + #define DISPLAY_POLL_UNTIL_READY do { while (display_read_status() & 0x80) {} } while (0) #define DISPLAY_SET_INCREMENT do { display_write_instruction_byte(0x06); } while (0) @@ -16,11 +18,16 @@ #define DISPLAY_CLEAR do { display_write_instruction_byte(0x01); } while (0) +struct Display_emu_state { + size_t cursor_offset:5; + size_t next:1; +}; void display_init(void); -uint8_t display_read_status(void); void display_write_instruction_byte(uint8_t code); void display_write_data_byte(uint8_t code); void display_write_data_seq(char *codes); +void display_to_framebuffer(void); +void display_to_direct(void); #endif diff --git a/Core/Inc/main.h b/Core/Inc/main.h index be9a3f3..22c4fda 100644 --- a/Core/Inc/main.h +++ b/Core/Inc/main.h @@ -32,6 +32,8 @@ extern "C" { /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ +#include + /* USER CODE END Includes */ /* Exported types ------------------------------------------------------------*/ diff --git a/Core/Src/lcd.c b/Core/Src/lcd.c index 3aebda7..d1573e3 100644 --- a/Core/Src/lcd.c +++ b/Core/Src/lcd.c @@ -2,22 +2,45 @@ #include "lcd.h" #include "generic_macros.h" +static char display_framebuffer[16*2*DISPLAY_FRAMES_AVAILABLE]; +size_t display_current_frame; +static size_t display_framebuffer_mode; + +static struct Display_emu_state des; + void display_init(void) { + // prepare virtual framebuffer + display_current_frame = 0; + display_framebuffer_mode = 0; + des.cursor_offset = 0; + des.next = 0; + memset(display_framebuffer, 0x20, 16*2*DISPLAY_FRAMES_AVAILABLE); + // switch to 4-bit 2-line mode - display_write_instruction_byte(0x28); + display_write_instruction_byte(0x28); - // clear display - display_write_instruction_byte(0x01); + // clear display + display_write_instruction_byte(0x01); - // enable display - display_write_instruction_byte(0x0C); + // enable display + display_write_instruction_byte(0x0C); - // move cursor to first line - display_write_instruction_byte(0x80); + // move cursor to first line + display_write_instruction_byte(0x80); } -uint8_t display_read_status(void) +void display_to_framebuffer(void) +{ + display_framebuffer_mode = 1; +} + +void display_to_direct(void) +{ + display_framebuffer_mode = 0; +} + +static uint8_t display_read_status(void) { // make sure GPIOE is in correct mode GPIOE->MODER = 0x00504000; @@ -43,7 +66,7 @@ uint8_t display_read_status(void) return status; } -void display_write_instruction_byte(uint8_t code) +static void display_write_instruction_byte_direct(uint8_t code) { DISPLAY_POLL_UNTIL_READY; @@ -62,7 +85,37 @@ void display_write_instruction_byte(uint8_t code) GPIOE->BSRR = (DISPLAY_ENA << 16); } -void display_write_data_byte(uint8_t code) +static void display_write_instruction_byte_framebuffer(uint8_t code) +{ + // emulate physical display behavior on receiving instructions + if (code & 0x80) { + // decode new cursor offset + size_t offset = ((code & 0x40) >> 2) | (code & 0xF); + des.cursor_offset = offset; + } else if (code == 0x01) { + // reset screen + memset(&(display_framebuffer[16*2*display_current_frame]), 0x20, 16*2); + des.cursor_offset = 0; + des.next = 0; + } else if (code == 0x06) { + // set increment mode + des.next = 0; + } else if (code == 0x04) { + // set decrement mode + des.next = 1; + } +} + +void display_write_instruction_byte(uint8_t code) +{ + if (display_framebuffer_mode) { + display_write_instruction_byte_framebuffer(code); + } else { + display_write_instruction_byte_direct(code); + } +} + +static void display_write_data_byte_direct(uint8_t code) { DISPLAY_POLL_UNTIL_READY; @@ -81,12 +134,45 @@ void display_write_data_byte(uint8_t code) GPIOE->BSRR = DISPLAY_ENA << 16; } +static void display_write_data_byte_framebuffer(uint8_t code) +{ + display_framebuffer[16*2*display_current_frame + des.cursor_offset] = (char) code; + des.cursor_offset += des.next ? -1 : 1; +} + +void display_write_data_byte(uint8_t code) +{ + if (display_framebuffer_mode) { + display_write_data_byte_framebuffer(code); + } else { + display_write_data_byte_direct(code); + } +} + void display_write_data_seq(char *codes) { for (size_t i = 0; i < 16; i++) { - if (codes[i] != 0) + if (codes[i]) display_write_data_byte(codes[i]); else break; } } + +void display_load(uint32_t frame_no) +{ + if (display_framebuffer_mode) + return; + + DISPLAY_CLEAR; + + for (uint32_t i = 0; i < 16; i++) { + display_write_data_byte_direct(display_framebuffer[16*2*display_current_frame + i]); + } + + DISPLAY_SET_CURSOR(1, 0); + + for (uint32_t i = 0; i < 16; i++) { + display_write_data_byte_direct(display_framebuffer[16*2*display_current_frame + i + 16]); + } +} diff --git a/Core/Src/main.c b/Core/Src/main.c index 93bdbfa..998cd4e 100644 --- a/Core/Src/main.c +++ b/Core/Src/main.c @@ -30,7 +30,6 @@ #include "CS43L22.h" #include "SST25VF016B.h" #include "LIS302DL.h" -#include "DHT11.h" #include "MP45DT02.h" #include "LSM9DS1.h" @@ -65,6 +64,8 @@ SPI_HandleTypeDef hspi1; TIM_HandleTypeDef htim2; +extern size_t display_current_frame; + /* USER CODE BEGIN PV */ void ((*executors[])(void)) = { @@ -305,10 +306,30 @@ int main(void) GPIOD->ODR = 0xF000; button_init_and_test(); + // perform all tests + display_to_framebuffer(); + + for (display_current_frame = 0; display_current_frame < 11; display_current_frame++) + { + executors[display_current_frame](); + } + + display_to_direct(); + display_current_frame = 0; + + while (1) { + display_load(display_current_frame); + display_current_frame++; + display_current_frame %= 11; + HAL_Delay(1000); + } + /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ + + /* while (1) { if (delay_between_runs[current_executor_id] == -1 && buttons_interrupt_enabled) @@ -334,10 +355,11 @@ int main(void) } else { HAL_Delay(delay_between_runs[current_executor_id]); } + */ /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ - } + //} /* USER CODE END 3 */ } diff --git a/Debug/Core/Src/subdir.mk b/Debug/Core/Src/subdir.mk index 85c5623..4e7014d 100644 --- a/Debug/Core/Src/subdir.mk +++ b/Debug/Core/Src/subdir.mk @@ -7,7 +7,6 @@ C_SRCS += \ ../Core/Src/24AA02E48.c \ ../Core/Src/CS43L22.c \ -../Core/Src/DHT11.c \ ../Core/Src/DNI.c \ ../Core/Src/LIS302DL.c \ ../Core/Src/LSM9DS1.c \ @@ -25,7 +24,6 @@ C_SRCS += \ OBJS += \ ./Core/Src/24AA02E48.o \ ./Core/Src/CS43L22.o \ -./Core/Src/DHT11.o \ ./Core/Src/DNI.o \ ./Core/Src/LIS302DL.o \ ./Core/Src/LSM9DS1.o \ @@ -43,7 +41,6 @@ OBJS += \ C_DEPS += \ ./Core/Src/24AA02E48.d \ ./Core/Src/CS43L22.d \ -./Core/Src/DHT11.d \ ./Core/Src/DNI.d \ ./Core/Src/LIS302DL.d \ ./Core/Src/LSM9DS1.d \ @@ -66,7 +63,7 @@ Core/Src/%.o Core/Src/%.su Core/Src/%.cyclo: ../Core/Src/%.c Core/Src/subdir.mk clean: clean-Core-2f-Src clean-Core-2f-Src: - -$(RM) ./Core/Src/24AA02E48.cyclo ./Core/Src/24AA02E48.d ./Core/Src/24AA02E48.o ./Core/Src/24AA02E48.su ./Core/Src/CS43L22.cyclo ./Core/Src/CS43L22.d ./Core/Src/CS43L22.o ./Core/Src/CS43L22.su ./Core/Src/DHT11.cyclo ./Core/Src/DHT11.d ./Core/Src/DHT11.o ./Core/Src/DHT11.su ./Core/Src/DNI.cyclo ./Core/Src/DNI.d ./Core/Src/DNI.o ./Core/Src/DNI.su ./Core/Src/LIS302DL.cyclo ./Core/Src/LIS302DL.d ./Core/Src/LIS302DL.o ./Core/Src/LIS302DL.su ./Core/Src/LSM9DS1.cyclo ./Core/Src/LSM9DS1.d ./Core/Src/LSM9DS1.o ./Core/Src/LSM9DS1.su ./Core/Src/MP45DT02.cyclo ./Core/Src/MP45DT02.d ./Core/Src/MP45DT02.o ./Core/Src/MP45DT02.su ./Core/Src/PCA9685.cyclo ./Core/Src/PCA9685.d ./Core/Src/PCA9685.o ./Core/Src/PCA9685.su ./Core/Src/SST25VF016B.cyclo ./Core/Src/SST25VF016B.d ./Core/Src/SST25VF016B.o ./Core/Src/SST25VF016B.su ./Core/Src/lcd.cyclo ./Core/Src/lcd.d ./Core/Src/lcd.o ./Core/Src/lcd.su ./Core/Src/main.cyclo ./Core/Src/main.d ./Core/Src/main.o ./Core/Src/main.su ./Core/Src/stm32f4xx_hal_msp.cyclo ./Core/Src/stm32f4xx_hal_msp.d ./Core/Src/stm32f4xx_hal_msp.o ./Core/Src/stm32f4xx_hal_msp.su ./Core/Src/stm32f4xx_it.cyclo ./Core/Src/stm32f4xx_it.d ./Core/Src/stm32f4xx_it.o ./Core/Src/stm32f4xx_it.su ./Core/Src/syscalls.cyclo ./Core/Src/syscalls.d ./Core/Src/syscalls.o ./Core/Src/syscalls.su ./Core/Src/sysmem.cyclo ./Core/Src/sysmem.d ./Core/Src/sysmem.o ./Core/Src/sysmem.su ./Core/Src/system_stm32f4xx.cyclo ./Core/Src/system_stm32f4xx.d ./Core/Src/system_stm32f4xx.o ./Core/Src/system_stm32f4xx.su + -$(RM) ./Core/Src/24AA02E48.cyclo ./Core/Src/24AA02E48.d ./Core/Src/24AA02E48.o ./Core/Src/24AA02E48.su ./Core/Src/CS43L22.cyclo ./Core/Src/CS43L22.d ./Core/Src/CS43L22.o ./Core/Src/CS43L22.su ./Core/Src/DNI.cyclo ./Core/Src/DNI.d ./Core/Src/DNI.o ./Core/Src/DNI.su ./Core/Src/LIS302DL.cyclo ./Core/Src/LIS302DL.d ./Core/Src/LIS302DL.o ./Core/Src/LIS302DL.su ./Core/Src/LSM9DS1.cyclo ./Core/Src/LSM9DS1.d ./Core/Src/LSM9DS1.o ./Core/Src/LSM9DS1.su ./Core/Src/MP45DT02.cyclo ./Core/Src/MP45DT02.d ./Core/Src/MP45DT02.o ./Core/Src/MP45DT02.su ./Core/Src/PCA9685.cyclo ./Core/Src/PCA9685.d ./Core/Src/PCA9685.o ./Core/Src/PCA9685.su ./Core/Src/SST25VF016B.cyclo ./Core/Src/SST25VF016B.d ./Core/Src/SST25VF016B.o ./Core/Src/SST25VF016B.su ./Core/Src/lcd.cyclo ./Core/Src/lcd.d ./Core/Src/lcd.o ./Core/Src/lcd.su ./Core/Src/main.cyclo ./Core/Src/main.d ./Core/Src/main.o ./Core/Src/main.su ./Core/Src/stm32f4xx_hal_msp.cyclo ./Core/Src/stm32f4xx_hal_msp.d ./Core/Src/stm32f4xx_hal_msp.o ./Core/Src/stm32f4xx_hal_msp.su ./Core/Src/stm32f4xx_it.cyclo ./Core/Src/stm32f4xx_it.d ./Core/Src/stm32f4xx_it.o ./Core/Src/stm32f4xx_it.su ./Core/Src/syscalls.cyclo ./Core/Src/syscalls.d ./Core/Src/syscalls.o ./Core/Src/syscalls.su ./Core/Src/sysmem.cyclo ./Core/Src/sysmem.d ./Core/Src/sysmem.o ./Core/Src/sysmem.su ./Core/Src/system_stm32f4xx.cyclo ./Core/Src/system_stm32f4xx.d ./Core/Src/system_stm32f4xx.o ./Core/Src/system_stm32f4xx.su .PHONY: clean-Core-2f-Src diff --git a/Debug/objects.list b/Debug/objects.list index b546871..7a27312 100644 --- a/Debug/objects.list +++ b/Debug/objects.list @@ -1,6 +1,5 @@ "./Core/Src/24AA02E48.o" "./Core/Src/CS43L22.o" -"./Core/Src/DHT11.o" "./Core/Src/DNI.o" "./Core/Src/LIS302DL.o" "./Core/Src/LSM9DS1.o"