[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
This commit is contained in:
parent
9370ddbadd
commit
3ccc0ca0f3
|
@ -7,6 +7,8 @@
|
||||||
#define DISPLAY_RW ((uint16_t) (0x1U << 10))
|
#define DISPLAY_RW ((uint16_t) (0x1U << 10))
|
||||||
#define DISPLAY_ENA ((uint16_t) (0x1U << 11))
|
#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_POLL_UNTIL_READY do { while (display_read_status() & 0x80) {} } while (0)
|
||||||
|
|
||||||
#define DISPLAY_SET_INCREMENT do { display_write_instruction_byte(0x06); } 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)
|
#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);
|
void display_init(void);
|
||||||
uint8_t display_read_status(void);
|
|
||||||
void display_write_instruction_byte(uint8_t code);
|
void display_write_instruction_byte(uint8_t code);
|
||||||
void display_write_data_byte(uint8_t code);
|
void display_write_data_byte(uint8_t code);
|
||||||
void display_write_data_seq(char *codes);
|
void display_write_data_seq(char *codes);
|
||||||
|
void display_to_framebuffer(void);
|
||||||
|
void display_to_direct(void);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -32,6 +32,8 @@ extern "C" {
|
||||||
/* Private includes ----------------------------------------------------------*/
|
/* Private includes ----------------------------------------------------------*/
|
||||||
/* USER CODE BEGIN Includes */
|
/* USER CODE BEGIN Includes */
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
/* USER CODE END Includes */
|
/* USER CODE END Includes */
|
||||||
|
|
||||||
/* Exported types ------------------------------------------------------------*/
|
/* Exported types ------------------------------------------------------------*/
|
||||||
|
|
|
@ -2,8 +2,21 @@
|
||||||
#include "lcd.h"
|
#include "lcd.h"
|
||||||
#include "generic_macros.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)
|
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
|
// switch to 4-bit 2-line mode
|
||||||
display_write_instruction_byte(0x28);
|
display_write_instruction_byte(0x28);
|
||||||
|
|
||||||
|
@ -17,7 +30,17 @@ void display_init(void)
|
||||||
display_write_instruction_byte(0x80);
|
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
|
// make sure GPIOE is in correct mode
|
||||||
GPIOE->MODER = 0x00504000;
|
GPIOE->MODER = 0x00504000;
|
||||||
|
@ -43,7 +66,7 @@ uint8_t display_read_status(void)
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
void display_write_instruction_byte(uint8_t code)
|
static void display_write_instruction_byte_direct(uint8_t code)
|
||||||
{
|
{
|
||||||
DISPLAY_POLL_UNTIL_READY;
|
DISPLAY_POLL_UNTIL_READY;
|
||||||
|
|
||||||
|
@ -62,7 +85,37 @@ void display_write_instruction_byte(uint8_t code)
|
||||||
GPIOE->BSRR = (DISPLAY_ENA << 16);
|
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;
|
DISPLAY_POLL_UNTIL_READY;
|
||||||
|
|
||||||
|
@ -81,12 +134,45 @@ void display_write_data_byte(uint8_t code)
|
||||||
GPIOE->BSRR = DISPLAY_ENA << 16;
|
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)
|
void display_write_data_seq(char *codes)
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < 16; i++) {
|
for (size_t i = 0; i < 16; i++) {
|
||||||
if (codes[i] != 0)
|
if (codes[i])
|
||||||
display_write_data_byte(codes[i]);
|
display_write_data_byte(codes[i]);
|
||||||
else
|
else
|
||||||
break;
|
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]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -30,7 +30,6 @@
|
||||||
#include "CS43L22.h"
|
#include "CS43L22.h"
|
||||||
#include "SST25VF016B.h"
|
#include "SST25VF016B.h"
|
||||||
#include "LIS302DL.h"
|
#include "LIS302DL.h"
|
||||||
#include "DHT11.h"
|
|
||||||
#include "MP45DT02.h"
|
#include "MP45DT02.h"
|
||||||
#include "LSM9DS1.h"
|
#include "LSM9DS1.h"
|
||||||
|
|
||||||
|
@ -65,6 +64,8 @@ SPI_HandleTypeDef hspi1;
|
||||||
|
|
||||||
TIM_HandleTypeDef htim2;
|
TIM_HandleTypeDef htim2;
|
||||||
|
|
||||||
|
extern size_t display_current_frame;
|
||||||
|
|
||||||
/* USER CODE BEGIN PV */
|
/* USER CODE BEGIN PV */
|
||||||
|
|
||||||
void ((*executors[])(void)) = {
|
void ((*executors[])(void)) = {
|
||||||
|
@ -305,10 +306,30 @@ int main(void)
|
||||||
GPIOD->ODR = 0xF000;
|
GPIOD->ODR = 0xF000;
|
||||||
button_init_and_test();
|
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 */
|
/* USER CODE END 2 */
|
||||||
|
|
||||||
/* Infinite loop */
|
/* Infinite loop */
|
||||||
/* USER CODE BEGIN WHILE */
|
/* USER CODE BEGIN WHILE */
|
||||||
|
|
||||||
|
/*
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
if (delay_between_runs[current_executor_id] == -1 && buttons_interrupt_enabled)
|
if (delay_between_runs[current_executor_id] == -1 && buttons_interrupt_enabled)
|
||||||
|
@ -334,10 +355,11 @@ int main(void)
|
||||||
} else {
|
} else {
|
||||||
HAL_Delay(delay_between_runs[current_executor_id]);
|
HAL_Delay(delay_between_runs[current_executor_id]);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
/* USER CODE END WHILE */
|
/* USER CODE END WHILE */
|
||||||
|
|
||||||
/* USER CODE BEGIN 3 */
|
/* USER CODE BEGIN 3 */
|
||||||
}
|
//}
|
||||||
/* USER CODE END 3 */
|
/* USER CODE END 3 */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,6 @@
|
||||||
C_SRCS += \
|
C_SRCS += \
|
||||||
../Core/Src/24AA02E48.c \
|
../Core/Src/24AA02E48.c \
|
||||||
../Core/Src/CS43L22.c \
|
../Core/Src/CS43L22.c \
|
||||||
../Core/Src/DHT11.c \
|
|
||||||
../Core/Src/DNI.c \
|
../Core/Src/DNI.c \
|
||||||
../Core/Src/LIS302DL.c \
|
../Core/Src/LIS302DL.c \
|
||||||
../Core/Src/LSM9DS1.c \
|
../Core/Src/LSM9DS1.c \
|
||||||
|
@ -25,7 +24,6 @@ C_SRCS += \
|
||||||
OBJS += \
|
OBJS += \
|
||||||
./Core/Src/24AA02E48.o \
|
./Core/Src/24AA02E48.o \
|
||||||
./Core/Src/CS43L22.o \
|
./Core/Src/CS43L22.o \
|
||||||
./Core/Src/DHT11.o \
|
|
||||||
./Core/Src/DNI.o \
|
./Core/Src/DNI.o \
|
||||||
./Core/Src/LIS302DL.o \
|
./Core/Src/LIS302DL.o \
|
||||||
./Core/Src/LSM9DS1.o \
|
./Core/Src/LSM9DS1.o \
|
||||||
|
@ -43,7 +41,6 @@ OBJS += \
|
||||||
C_DEPS += \
|
C_DEPS += \
|
||||||
./Core/Src/24AA02E48.d \
|
./Core/Src/24AA02E48.d \
|
||||||
./Core/Src/CS43L22.d \
|
./Core/Src/CS43L22.d \
|
||||||
./Core/Src/DHT11.d \
|
|
||||||
./Core/Src/DNI.d \
|
./Core/Src/DNI.d \
|
||||||
./Core/Src/LIS302DL.d \
|
./Core/Src/LIS302DL.d \
|
||||||
./Core/Src/LSM9DS1.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: clean-Core-2f-Src
|
||||||
|
|
||||||
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
|
.PHONY: clean-Core-2f-Src
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
"./Core/Src/24AA02E48.o"
|
"./Core/Src/24AA02E48.o"
|
||||||
"./Core/Src/CS43L22.o"
|
"./Core/Src/CS43L22.o"
|
||||||
"./Core/Src/DHT11.o"
|
|
||||||
"./Core/Src/DNI.o"
|
"./Core/Src/DNI.o"
|
||||||
"./Core/Src/LIS302DL.o"
|
"./Core/Src/LIS302DL.o"
|
||||||
"./Core/Src/LSM9DS1.o"
|
"./Core/Src/LSM9DS1.o"
|
||||||
|
|
Loading…
Reference in New Issue