Move LCD bus comms to lcdbus.c; LCD bus write-only w/ simpler HW and more PIO; WIP work on lcd_ui

This commit is contained in:
2023-06-11 13:45:08 +02:00
parent b512372b19
commit 3f7c727440
10 changed files with 454 additions and 1438 deletions

View File

@@ -51,7 +51,7 @@ button_height = 8;
button_small_width = 8;
button_small_height = 8;
render_text = false;
render_text = true;
render_button = true;
row_length = 4;

View File

@@ -206,7 +206,7 @@ module side(rightside = false) {
}
}
render_panel = false;
render_panel = true;
render_case = true;
mount_screw_diam = 4+wiggle_room;

View File

@@ -43,7 +43,7 @@ target_link_libraries(ledtest pico_stdlib hardware_pio)
pico_add_extra_outputs(ledtest)
add_executable(lcdtest
src/lcdtest.c
src/lcdtest.c src/lcdbus.c src/lcd_ui.c
)
pico_generate_pio_header(lcdtest ${CMAKE_CURRENT_LIST_DIR}/src/lcdbus.pio)

File diff suppressed because it is too large Load Diff

133
src/lcd_ui.c Normal file
View File

@@ -0,0 +1,133 @@
#include "fonts.h"
#include "lcdbus.h"
#include <pico/stdlib.h>
#include <stdio.h>
#include <string.h>
enum static_type {
none,
box_full,
box_border,
text,
text_vert,
};
struct static_element {
unsigned upper, left, lower, right;
enum static_type type;
bool visible;
const char *data;
};
struct static_element static_elements[] = {
{ .upper = 0, .left = 119, .right = 121, .lower = 319,
.type = box_full,
.visible = true,
},
{ .upper = 10, .left = 10, .right = 17, .lower = 57,
.type = text_vert,
.visible = true,
.data = "VHF1",
},
{ .upper = 10, .left = 20, .right = 30, .lower = 69,
.type = box_border,
.visible = true,
},
{ .upper = 10, .left = 40, .right = 106, .lower = 22,
.type = text,
.visible = true,
.data = "118.000",
},
{ .upper = 57, .left = 40, .right = 106, .lower = 69,
.type = text,
.visible = true,
.data = "122.800",
},
{ .upper = 79, .left = 0, .right = 239, .lower = 81,
.type = box_full,
.visible = true,
},
{ .upper = 159, .left = 0, .right = 239, .lower = 161,
.type = box_full,
.visible = true,
},
{ .upper = 239, .left = 0, .right = 239, .lower = 241,
.type = box_full,
.visible = true,
},
};
enum ise_ret {
ise_blank = 0,
ise_pixel = 1,
ise_abort,
};
static enum ise_ret in_static_element(unsigned row, unsigned col, struct static_element const * const se)
{
// if (row <= se->lower) return ise_abort;
if (!se->visible) return ise_blank;
if (!((row >= se->upper) && (row <= se->lower) && (col >= se->left) && (col <= se->right))) return ise_blank;
switch(se->type) {
case box_full:
return ise_pixel;
case box_border:
return (row == se->upper) || (row == se->lower) ||(col == se->left) || (col == se->right);
case text:
{
// which character to display
const int char_c = (col - se->left) / 8;
// position inside char
const int pos_r = (row - se->upper) % 12;
const int pos_c = (col - se->left) % 8;
if (char_c >= strlen(se->data)) return false;
const char data = Font8x12[(se->data[char_c]-0x20)*12 + pos_r];
return (data & (1u << (7-pos_c))) != 0;
}
case text_vert:
{
// which character to display
const int char_r = (row - se->upper) / 12;
// position inside char
const int pos_r = (row - se->upper) % 12;
const int pos_c = (col - se->left) % 8;
if (char_r >= strlen(se->data)) return false;
const char data = Font8x12[(se->data[char_r]-0x20)*12 + pos_r];
return (data & (1u << (7-pos_c))) != 0;
}
}
}
static uint16_t get_pixel(unsigned row, unsigned col)
{
for (int se = 0;se < sizeof(static_elements)/sizeof(static_elements[0]);++se) {
switch(in_static_element(row, col, static_elements+se)) {
case ise_pixel:
return 0xffff;
case ise_blank:
continue;
case ise_abort:
return 0x0000;
}
}
return 0x0000;
}
static unsigned cur_row = 0, cur_col = 0;
#define LCD_WIDTH 240
#define LCD_HEIGHT 320
bool lcd_ui_process(void)
{
while (!lcd_fifo_full()) {
lcd_data_write(get_pixel(cur_row, cur_col));
cur_col = (cur_col >= LCD_WIDTH - 1) ? 0 : cur_col + 1;
if (cur_col == 0) {
cur_row = (cur_row >= LCD_HEIGHT - 1) ? 0 : cur_row + 1;
if (cur_row == 0) return true;
}
}
return false;
}

5
src/lcd_ui.h Normal file
View File

@@ -0,0 +1,5 @@
#pragma once
#include <stdbool.h>
bool lcd_ui_process(void);

140
src/lcdbus.c Normal file
View File

@@ -0,0 +1,140 @@
#include <hardware/pio.h>
#include <pico/stdlib.h>
#include <stdio.h>
#include "lcdbus.pio.h"
extern PIO pio;
static uint sm;
#define LCD_RS_PIN 20
#define LCD_SDO_PIN 19
#define LCD_FCK_PIN 18
#define LCD_SCK_PIN 17
#define LCD_WRS_PIN 16
#define LCD_RESET_PIN 15
static bool rs_pin_state = false;
static void lcd_bus_transact(bool dc, uint16_t out)
{
if (dc != rs_pin_state) {
while (!pio_sm_is_tx_fifo_empty(pio, sm));
gpio_put(LCD_RS_PIN, dc);
rs_pin_state = dc;
}
pio_sm_put_blocking(pio, sm, (((uint32_t)out) << 16));
}
void lcd_data_write(uint16_t val)
{
lcd_bus_transact(true, val);
}
void lcd_control_write(uint16_t val)
{
lcd_bus_transact(false, val);
}
uint16_t lcd_reg_write(uint8_t reg, uint16_t val)
{
lcd_control_write(reg);
lcd_data_write(val);
}
void lcd_init(void)
{
gpio_init(LCD_RESET_PIN);
gpio_set_dir(LCD_RESET_PIN, true);
gpio_put(LCD_RESET_PIN, true);
gpio_init(LCD_RS_PIN);
gpio_set_dir(LCD_RS_PIN, true);
gpio_put(LCD_RS_PIN, rs_pin_state);
uint offset = pio_add_program(pio, &lcdbus_program);
sm = pio_claim_unused_sm(pio, true);
pio_sm_config c = lcdbus_program_get_default_config(offset);
sm_config_set_out_pins(&c, LCD_SDO_PIN, 1);
sm_config_set_sideset_pins(&c, LCD_WRS_PIN);
sm_config_set_out_shift(&c, false, false, 16);
sm_config_set_clkdiv(&c, 3.f);
pio_sm_set_pindirs_with_mask(pio, sm,
(1u << LCD_SDO_PIN) | (1u << LCD_SCK_PIN) | (1u << LCD_FCK_PIN) | (1u << LCD_WRS_PIN),
(1u << LCD_SDO_PIN) | (1u << LCD_SCK_PIN) | (1u << LCD_FCK_PIN) | (1u << LCD_WRS_PIN));
pio_gpio_init(pio, LCD_SDO_PIN);
pio_gpio_init(pio, LCD_WRS_PIN);
pio_gpio_init(pio, LCD_SCK_PIN);
pio_gpio_init(pio, LCD_FCK_PIN);
pio_sm_init(pio, sm, offset, &c);
pio_sm_set_enabled(pio, sm, true);
}
void lcd_write_init(void)
{
/* lcd_reg_write(0x07, 0x0021); */
/* lcd_reg_write(0x00, 0x0001); */
/* lcd_reg_write(0x07, 0x0023); */
/* lcd_reg_write(0x10, 0x0000); */
/* sleep_ms(30); */
/* lcd_reg_write(0x07, 0x0033); */
/* lcd_reg_write(0x03, 0xA8A4); */
// Initialization sequence taken from UTFT for SSD1289
// I don't know what it does, but it doesn't flicker...
lcd_reg_write(0x00,0x0001);
lcd_reg_write(0x03,0xA8A4);
lcd_reg_write(0x0C,0x0000);
lcd_reg_write(0x0D,0x080C);
lcd_reg_write(0x0E,0x2B00);
lcd_reg_write(0x1E,0x00B7);
lcd_reg_write(0x01,0x2B3F);
lcd_reg_write(0x02,0x0600);
lcd_reg_write(0x10,0x0000);
lcd_reg_write(0x11,0x6070);
lcd_reg_write(0x05,0x0000);
lcd_reg_write(0x06,0x0000);
lcd_reg_write(0x16,0xEF1C);
lcd_reg_write(0x17,0x0003);
lcd_reg_write(0x07,0x0233);
lcd_reg_write(0x0B,0x0000);
lcd_reg_write(0x0F,0x0000);
lcd_reg_write(0x41,0x0000);
lcd_reg_write(0x42,0x0000);
lcd_reg_write(0x48,0x0000);
lcd_reg_write(0x49,0x013F);
lcd_reg_write(0x4A,0x0000);
lcd_reg_write(0x4B,0x0000);
lcd_reg_write(0x44,0xEF00);
lcd_reg_write(0x45,0x0000);
lcd_reg_write(0x46,0x013F);
lcd_reg_write(0x30,0x0707);
lcd_reg_write(0x31,0x0204);
lcd_reg_write(0x32,0x0204);
lcd_reg_write(0x33,0x0502);
lcd_reg_write(0x34,0x0507);
lcd_reg_write(0x35,0x0204);
lcd_reg_write(0x36,0x0204);
lcd_reg_write(0x37,0x0502);
lcd_reg_write(0x3A,0x0302);
lcd_reg_write(0x3B,0x0302);
lcd_reg_write(0x23,0x0000);
lcd_reg_write(0x24,0x0000);
lcd_reg_write(0x25,0x8000);
}
void lcd_clear(uint16_t val)
{
lcd_reg_write(0x4f,0x0000);
lcd_reg_write(0x4e,0x0000);
lcd_control_write(0x22);
for (int i = 0;i < 320*240;++i) {
lcd_data_write(val);
}
}
bool lcd_fifo_full(void)
{
return pio_sm_is_tx_fifo_full(pio, sm);
}

12
src/lcdbus.h Normal file
View File

@@ -0,0 +1,12 @@
#pragma once
#include <stdint.h>
#include <stdbool.h>
void lcd_data_write(uint16_t val);
void lcd_control_write(uint16_t val);
uint16_t lcd_reg_write(uint8_t reg, uint16_t val);
void lcd_init(void);
void lcd_write_init(void);
void lcd_clear(uint16_t val);
bool lcd_fifo_full(void);

View File

@@ -1,9 +1,11 @@
.program lcdbus
.side_set 2
.side_set 3
pull side 2
nop side 5
.wrap_target
pull side 5
loop:
out pins, 1 side 0
in pins, 1 side 0
jmp !OSRE loop side 1
push side 2
jmp !OSRE loop side 2
nop side 4
nop side 5 [1]

View File

@@ -1,215 +1,81 @@
#include "fonts.h"
//#include "fonts.h"
#include <hardware/pio.h>
#include "lcdbus.h"
#include "lcd_ui.h"
#include <pico/stdlib.h>
#include <stdio.h>
#include "lcdbus.pio.h"
PIO pio = pio0;
static uint sm;
#define LCD_SDI_PIN 20
#define LCD_SDO_PIN 19
#define LCD_FCK_PIN 18
#define LCD_SCK_PIN 17
#define LCD_OE_PIN 16
#define LCD_RS_PIN 15
#define LCD_WR_PIN 14
#define LCD_RD_PIN 13
#define LCD_CS_PIN 12
#define LCD_RESET_PIN 11
static uint16_t lcd_bus_transact(uint16_t out)
{
pio_sm_put(pio, sm, ((uint32_t)out)<<16);
return pio_sm_get_blocking(pio, sm);
}
static void lcd_write(bool dc, uint16_t val)
{
gpio_put_masked((1u << LCD_CS_PIN) | (1u << LCD_WR_PIN) | (1u << LCD_RS_PIN), (dc << LCD_RS_PIN));
gpio_put(LCD_OE_PIN, false);
lcd_bus_transact(val);
gpio_put_masked((1u << LCD_CS_PIN) | (1u << LCD_WR_PIN) | (1u << LCD_RS_PIN),
(1u << LCD_CS_PIN) | (1u << LCD_WR_PIN) | (1u << LCD_RS_PIN));
gpio_put(LCD_OE_PIN, true);
// busy_wait_us(1);
}
static uint16_t lcd_read(bool dc)
{
gpio_put_masked((1u << LCD_CS_PIN) | (1u << LCD_RD_PIN) | (1u << LCD_RS_PIN), (dc << LCD_RS_PIN));
// wait 250 ns
asm volatile ("nop\n");
asm volatile ("nop\n");
asm volatile ("nop\n");
asm volatile ("nop\n");
asm volatile ("nop\n");
asm volatile ("nop\n");
asm volatile ("nop\n");
asm volatile ("nop\n");
asm volatile ("nop\n");
asm volatile ("nop\n");
asm volatile ("nop\n");
asm volatile ("nop\n");
asm volatile ("nop\n");
asm volatile ("nop\n");
asm volatile ("nop\n");
asm volatile ("nop\n");
asm volatile ("nop\n");
asm volatile ("nop\n");
asm volatile ("nop\n");
asm volatile ("nop\n");
asm volatile ("nop\n");
asm volatile ("nop\n");
asm volatile ("nop\n");
asm volatile ("nop\n");
asm volatile ("nop\n");
asm volatile ("nop\n");
asm volatile ("nop\n");
asm volatile ("nop\n");
asm volatile ("nop\n");
asm volatile ("nop\n");
asm volatile ("nop\n");
asm volatile ("nop\n");
const uint16_t ret = lcd_bus_transact(0);
gpio_put_masked((1u << LCD_CS_PIN) | (1u << LCD_RD_PIN) | (1u << LCD_RS_PIN),
(1u << LCD_CS_PIN) | (1u << LCD_RD_PIN) | (1u << LCD_RS_PIN));
return ret;
}
static uint16_t lcd_reg_read(uint8_t reg)
{
lcd_write(false, reg);
return lcd_read(true);
}
static uint16_t lcd_reg_write(uint8_t reg, uint16_t val)
{
lcd_write(false, reg);
lcd_write(true, val);
}
#define FRAME_LED 22
int main(void)
{
setup_default_uart();
printf("lcdtest.c\n");
gpio_init_mask(0x3f << 11);
gpio_set_dir_out_masked(0x3f << 11);
// gpio_init(LCD_OE_PIN);
// gpio_set_dir(LCD_OE_PIN, true);
gpio_put_masked(0x3f << 11, 0x3f << 11);
gpio_put(LCD_OE_PIN, true);
lcd_init();
lcd_write_init();
lcd_clear(0);
/* int color = 0; */
/* while(true) { */
/* const char* const greeting = "Hello, world!"; */
/* const int greeting_len = strlen(greeting); */
/* for (int row = 0;row < 320;++row) { */
/* for (int col = 0; col < 240;++col) { */
/* // which character to display */
/* const int char_r = row / 12; */
/* const int char_c = col / 8; */
/* // position inside char */
/* const int pos_r = row % 12; */
/* const int pos_c = col % 8; */
/* const int index = char_r*30+char_c; */
/* char data = 0; */
/* if (index < greeting_len) { */
/* data = Font8x12[(greeting[index]-0x20)*12 + pos_r]; */
/* } */
/* const bool pixel = (data & (1u << (7-pos_c))) != 0; */
/* if (pixel) { */
/* if (color == 4) { */
/* lcd_data_write(0x0000); */
/* } else { */
/* lcd_data_write(0xffff); */
/* } */
/* } else { */
/* switch(color) { */
/* case 0: */
/* lcd_data_write(0x0000); */
/* break; */
/* case 1: */
/* lcd_data_write(0x001f); */
/* break; */
/* case 2: */
/* lcd_data_write(0x07e0); */
/* break; */
/* case 3: */
/* lcd_data_write(0xf800); */
/* break; */
/* case 4: */
/* lcd_data_write(0xffff); */
/* break; */
/* } */
/* } */
/* } */
/* } */
/* color = (color == 4) ? 0 : color + 1; */
/* sleep_ms(1000); */
/* } */
uint offset = pio_add_program(pio, &lcdbus_program);
sm = pio_claim_unused_sm(pio, true);
pio_sm_config c = lcdbus_program_get_default_config(offset);
sm_config_set_out_pins(&c, LCD_SDO_PIN, 1);
sm_config_set_in_pins(&c, LCD_SDI_PIN);
sm_config_set_sideset_pins(&c, LCD_SCK_PIN);
sm_config_set_out_shift(&c, false, false, 16);
sm_config_set_in_shift(&c, false, false, 16);
sm_config_set_clkdiv(&c, 4);
pio_sm_set_pindirs_with_mask(pio, sm,
(1u << LCD_SDO_PIN) | (1u << LCD_SCK_PIN) | (1u << LCD_FCK_PIN),
(1u << LCD_SDO_PIN) | (1u << LCD_SCK_PIN) | (1u << LCD_FCK_PIN) | (1u << LCD_SDI_PIN));
pio_gpio_init(pio, LCD_SDO_PIN);
pio_gpio_init(pio, LCD_SDI_PIN);
pio_gpio_init(pio, LCD_SCK_PIN);
pio_gpio_init(pio, LCD_FCK_PIN);
pio_sm_init(pio, sm, offset, &c);
pio_sm_set_enabled(pio, sm, true);
//gpio_put(LCD_OE_PIN, false);
sleep_ms(100);
//lcd_write(true, 0x0000);
uint16_t r1 = lcd_read(false);
if (r1 != 0x8989) {
printf("Display chip id not OK (%04hx)\n", r1);
return 0;
}
/* lcd_reg_write(0x07, 0x0021); */
/* lcd_reg_write(0x00, 0x0001); */
/* lcd_reg_write(0x07, 0x0023); */
/* lcd_reg_write(0x10, 0x0000); */
/* sleep_ms(30); */
/* lcd_reg_write(0x07, 0x0033); */
/* lcd_reg_write(0x03, 0xA8A4); */
// Initialization sequence taken from UTFT for SSD1289
// I don't know what it does, but it doesn't flicker...
lcd_reg_write(0x00,0x0001);
lcd_reg_write(0x03,0xA8A4);
lcd_reg_write(0x0C,0x0000);
lcd_reg_write(0x0D,0x080C);
lcd_reg_write(0x0E,0x2B00);
lcd_reg_write(0x1E,0x00B7);
lcd_reg_write(0x01,0x2B3F);
lcd_reg_write(0x02,0x0600);
lcd_reg_write(0x10,0x0000);
lcd_reg_write(0x11,0x6070);
lcd_reg_write(0x05,0x0000);
lcd_reg_write(0x06,0x0000);
lcd_reg_write(0x16,0xEF1C);
lcd_reg_write(0x17,0x0003);
lcd_reg_write(0x07,0x0233);
lcd_reg_write(0x0B,0x0000);
lcd_reg_write(0x0F,0x0000);
lcd_reg_write(0x41,0x0000);
lcd_reg_write(0x42,0x0000);
lcd_reg_write(0x48,0x0000);
lcd_reg_write(0x49,0x013F);
lcd_reg_write(0x4A,0x0000);
lcd_reg_write(0x4B,0x0000);
lcd_reg_write(0x44,0xEF00);
lcd_reg_write(0x45,0x0000);
lcd_reg_write(0x46,0x013F);
lcd_reg_write(0x30,0x0707);
lcd_reg_write(0x31,0x0204);
lcd_reg_write(0x32,0x0204);
lcd_reg_write(0x33,0x0502);
lcd_reg_write(0x34,0x0507);
lcd_reg_write(0x35,0x0204);
lcd_reg_write(0x36,0x0204);
lcd_reg_write(0x37,0x0502);
lcd_reg_write(0x3A,0x0302);
lcd_reg_write(0x3B,0x0302);
lcd_reg_write(0x23,0x0000);
lcd_reg_write(0x24,0x0000);
lcd_reg_write(0x25,0x8000);
lcd_reg_write(0x4f,0x0000);
lcd_reg_write(0x4e,0x0000);
lcd_write(false, 0x22);
for (int i = 0;i < 320*240;++i) {
lcd_write(true, 0x0000);
}
const char* const greeting = "Hello, world!";
const int greeting_len = strlen(greeting);
for (int row = 0;row < 320;++row) {
for (int col = 0; col < 240;++col) {
// which character to display
const int char_r = row / 12;
const int char_c = col / 8;
// position inside char
const int pos_r = row % 12;
const int pos_c = col % 8;
const int index = char_r*30+char_c;
char data = 0;
if (index < greeting_len) {
data = Font8x12[(greeting[index]-0x20)*12 + pos_r];
}
const bool pixel = (data & (1u << (7-pos_c))) != 0;
if (pixel) {
lcd_write(true, 0xffff);
} else {
lcd_write(true, 0x0000);
}
gpio_init(FRAME_LED);
gpio_set_dir(FRAME_LED, true);
bool frame_led = false;
while(true) {
if (lcd_ui_process()) {
gpio_put(FRAME_LED, frame_led);
frame_led = !frame_led;
}
}
}
}