185 lines
3.9 KiB
C
185 lines
3.9 KiB
C
#include "main.h"
|
|
#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);
|
|
|
|
// clear display
|
|
display_write_instruction_byte(0x01);
|
|
|
|
// enable display
|
|
display_write_instruction_byte(0x0C);
|
|
|
|
// move cursor to first line
|
|
display_write_instruction_byte(0x80);
|
|
}
|
|
|
|
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;
|
|
|
|
if (GPIOE->MODER != 0x00504000)
|
|
PANIC(0x4000);
|
|
|
|
uint8_t status = 0;
|
|
|
|
GPIOE->ODR = 0x0;
|
|
GPIOE->BSRR = DISPLAY_RW;
|
|
|
|
GPIOE->BSRR = DISPLAY_ENA;
|
|
status |= (GPIOE->IDR & 0xF000) >> 8;
|
|
GPIOE->BSRR = (DISPLAY_ENA << 16);
|
|
|
|
GPIOE->BSRR = DISPLAY_ENA;
|
|
status |= (GPIOE->IDR & 0xF000) >> 12;
|
|
GPIOE->BSRR = (DISPLAY_ENA << 16);
|
|
|
|
GPIOE->ODR = 0x0;
|
|
|
|
return status;
|
|
}
|
|
|
|
static void display_write_instruction_byte_direct(uint8_t code)
|
|
{
|
|
DISPLAY_POLL_UNTIL_READY;
|
|
|
|
// make sure GPIOE is in correct mode
|
|
GPIOE->MODER = 0x55504000;
|
|
|
|
if (GPIOE->MODER != 0x55504000)
|
|
PANIC(0x4000);
|
|
|
|
GPIOE->ODR = (code & 0xF0) << 8;
|
|
GPIOE->BSRR = DISPLAY_ENA;
|
|
GPIOE->BSRR = (DISPLAY_ENA << 16);
|
|
|
|
GPIOE->ODR = (code & 0x0F) << 12;
|
|
GPIOE->BSRR = DISPLAY_ENA;
|
|
GPIOE->BSRR = (DISPLAY_ENA << 16);
|
|
}
|
|
|
|
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;
|
|
|
|
// make sure GPIOE is in correct mode
|
|
GPIOE->MODER = 0x55504000;
|
|
|
|
if (GPIOE->MODER != 0x55504000)
|
|
PANIC(0x4000);
|
|
|
|
GPIOE->ODR = ((code & 0xF0) << 8) | (DISPLAY_RS);
|
|
GPIOE->BSRR = DISPLAY_ENA;
|
|
GPIOE->BSRR = DISPLAY_ENA << 16;
|
|
|
|
GPIOE->ODR = ((code & 0x0F) << 12) | (DISPLAY_RS);
|
|
GPIOE->BSRR = DISPLAY_ENA;
|
|
GPIOE->BSRR = DISPLAY_ENA << 16;
|
|
}
|
|
|
|
static void display_write_data_byte_framebuffer(uint8_t code)
|
|
{
|
|
if (display_current_frame >= DISPLAY_FRAMES_AVAILABLE)
|
|
return;
|
|
|
|
if (((int) des.cursor_offset >= 32) || ((int) des.cursor_offset < 0))
|
|
return;
|
|
|
|
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])
|
|
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]);
|
|
}
|
|
}
|