mirror of
https://github.com/justinian/edmfd_firmware.git
synced 2025-12-09 16:24:31 -08:00
Initial WIP for TFT (not working yet)
This commit is contained in:
@@ -53,6 +53,8 @@ target_sources(edmfd PUBLIC
|
|||||||
src/edmfd/main.cc
|
src/edmfd/main.cc
|
||||||
src/edmfd/mcp23017.cc
|
src/edmfd/mcp23017.cc
|
||||||
src/edmfd/screen.cc
|
src/edmfd/screen.cc
|
||||||
|
src/edmfd/spi.cc
|
||||||
|
src/edmfd/tft.cc
|
||||||
src/edmfd/usb_descriptors.cc
|
src/edmfd/usb_descriptors.cc
|
||||||
src/edmfd/vendor.cc
|
src/edmfd/vendor.cc
|
||||||
)
|
)
|
||||||
@@ -66,6 +68,7 @@ target_link_libraries(edmfd PUBLIC
|
|||||||
pico_stdio_uart
|
pico_stdio_uart
|
||||||
pico_unique_id
|
pico_unique_id
|
||||||
hardware_i2c
|
hardware_i2c
|
||||||
|
hardware_spi
|
||||||
tinyusb_device
|
tinyusb_device
|
||||||
tinyusb_board
|
tinyusb_board
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -14,6 +14,8 @@
|
|||||||
#include "hid.hh"
|
#include "hid.hh"
|
||||||
#include "i2c.hh"
|
#include "i2c.hh"
|
||||||
#include "mcp23017.hh"
|
#include "mcp23017.hh"
|
||||||
|
#include "spi.hh"
|
||||||
|
#include "tft.hh"
|
||||||
|
|
||||||
using mcp23017::reg;
|
using mcp23017::reg;
|
||||||
|
|
||||||
@@ -27,11 +29,13 @@ extern "C" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static constexpr unsigned i2c_baud = 400 * 1000;
|
static constexpr unsigned i2c_baud = 400 * 1000;
|
||||||
|
static constexpr unsigned spi_baud = 24 * 1000 * 1000;
|
||||||
|
|
||||||
static constexpr unsigned hid_update_ms = 1000/20; // 20Hz
|
static constexpr unsigned hid_update_ms = 1000/20; // 20Hz
|
||||||
|
|
||||||
static constexpr unsigned bank_leds = 0;
|
static constexpr unsigned bank_leds = 0;
|
||||||
static constexpr unsigned bank_buttons = 1;
|
static constexpr unsigned bank_buttons = 1;
|
||||||
|
|
||||||
static constexpr unsigned buttons_per_group = 5;
|
static constexpr unsigned buttons_per_group = 5;
|
||||||
static constexpr unsigned button_group_count = 2;
|
static constexpr unsigned button_group_count = 2;
|
||||||
static const unsigned button_group_irqs[] = {4, 7};
|
static const unsigned button_group_irqs[] = {4, 7};
|
||||||
@@ -102,6 +106,10 @@ int main(void)
|
|||||||
log::info("board initialized");
|
log::info("board initialized");
|
||||||
|
|
||||||
i2c::init(i2c_baud);
|
i2c::init(i2c_baud);
|
||||||
|
spi::init(spi_baud);
|
||||||
|
|
||||||
|
tft disp {9, 10};
|
||||||
|
disp.init();
|
||||||
|
|
||||||
// set up interrupt handlers
|
// set up interrupt handlers
|
||||||
for (int pin : button_group_irqs) {
|
for (int pin : button_group_irqs) {
|
||||||
|
|||||||
47
src/edmfd/spi.cc
Normal file
47
src/edmfd/spi.cc
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
#include "hardware/spi.h"
|
||||||
|
#include "pico/stdlib.h"
|
||||||
|
#include "pico/binary_info.h"
|
||||||
|
|
||||||
|
#include "logging/log.hh"
|
||||||
|
|
||||||
|
#include "spi.hh"
|
||||||
|
|
||||||
|
namespace spi {
|
||||||
|
|
||||||
|
cs::cs(unsigned pin) :
|
||||||
|
pin {pin}
|
||||||
|
{
|
||||||
|
asm volatile("nop \n nop \n nop");
|
||||||
|
gpio_put(pin, 0); // Active low
|
||||||
|
asm volatile("nop \n nop \n nop");
|
||||||
|
}
|
||||||
|
|
||||||
|
cs::~cs()
|
||||||
|
{
|
||||||
|
asm volatile("nop \n nop \n nop");
|
||||||
|
gpio_put(pin, 1);
|
||||||
|
asm volatile("nop \n nop \n nop");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void init(unsigned baud)
|
||||||
|
{
|
||||||
|
baud = spi_init(spi_default, baud);
|
||||||
|
gpio_set_function(PICO_DEFAULT_SPI_SCK_PIN, GPIO_FUNC_SPI);
|
||||||
|
gpio_set_function(PICO_DEFAULT_SPI_TX_PIN, GPIO_FUNC_SPI);
|
||||||
|
gpio_set_function(PICO_DEFAULT_SPI_RX_PIN, GPIO_FUNC_SPI);
|
||||||
|
|
||||||
|
// Make the SPI pins available to picotool
|
||||||
|
bi_decl(bi_3pins_with_func(PICO_DEFAULT_SPI_RX_PIN, PICO_DEFAULT_SPI_TX_PIN, PICO_DEFAULT_SPI_SCK_PIN, GPIO_FUNC_SPI));
|
||||||
|
|
||||||
|
//spi_set_format(spi_default, 8, SPI_CPOL_0, SPI_CPHA_0, SPI_MSB_FIRST);
|
||||||
|
|
||||||
|
log::info("waiting for spi...");
|
||||||
|
|
||||||
|
while(!spi_is_writable(spi_default));
|
||||||
|
|
||||||
|
log::info("spi initialized at %.1fMHz, SCK=%d TX=%d RX=%d", baud/1000000.f,
|
||||||
|
PICO_DEFAULT_SPI_RX_PIN, PICO_DEFAULT_SPI_TX_PIN, PICO_DEFAULT_SPI_SCK_PIN);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace spi
|
||||||
17
src/edmfd/spi.hh
Normal file
17
src/edmfd/spi.hh
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace spi {
|
||||||
|
|
||||||
|
void init(unsigned baud);
|
||||||
|
|
||||||
|
// RAII chip select
|
||||||
|
class cs
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
cs(unsigned pin);
|
||||||
|
~cs();
|
||||||
|
private:
|
||||||
|
unsigned pin;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace spi
|
||||||
1204
src/edmfd/startup_banner.hh
Normal file
1204
src/edmfd/startup_banner.hh
Normal file
File diff suppressed because it is too large
Load Diff
185
src/edmfd/tft.cc
Normal file
185
src/edmfd/tft.cc
Normal file
@@ -0,0 +1,185 @@
|
|||||||
|
#include "hardware/spi.h"
|
||||||
|
#include "pico/stdlib.h"
|
||||||
|
|
||||||
|
#include "logging/log.hh"
|
||||||
|
#include "spi.hh"
|
||||||
|
#include "tft.hh"
|
||||||
|
|
||||||
|
#include "startup_banner.hh"
|
||||||
|
|
||||||
|
enum class cmd : uint8_t {
|
||||||
|
// Organized by datasheet table page
|
||||||
|
// Page 105
|
||||||
|
nop = 0x00, // p.114, NOP
|
||||||
|
swreset = 0x01, // p.115, Software reset
|
||||||
|
slpin = 0x10, // p.131, Sleep in
|
||||||
|
slpout = 0x11, // p.133, Sleep out
|
||||||
|
|
||||||
|
// Page 106
|
||||||
|
invoff = 0x20, // p.137, Display inversion off
|
||||||
|
invon = 0x21, // p.138, Display inversion on
|
||||||
|
dispoff = 0x28, // p.142, Display off
|
||||||
|
dispon = 0x29, // p.143, Display on
|
||||||
|
caset = 0x2a, // p.144, Column address set
|
||||||
|
paset = 0x2b, // p.146, Page address set
|
||||||
|
ramwr = 0x2c, // p.148, Write VRAM
|
||||||
|
|
||||||
|
// Page 107
|
||||||
|
teoff = 0x34, // p.155, Tear effect line off
|
||||||
|
teon = 0x35, // p.156, Tear effect line on
|
||||||
|
madctl = 0x36, // p.157, Memory access control
|
||||||
|
colmod = 0x3a, // p.164, Color mode
|
||||||
|
tesl = 0x44, // p.167, Set tear scanline
|
||||||
|
|
||||||
|
// Page 110
|
||||||
|
setosc = 0xb0, // p.200, Set internal oscillator
|
||||||
|
setpower = 0xb1, // p.201, Set power control
|
||||||
|
setdisplay = 0xb2, // p.205, Set display control
|
||||||
|
setrgb = 0xb3, // p.207, Set RGB I/F
|
||||||
|
setcyc = 0xb4, // p.210, Set display cycle
|
||||||
|
setvcom = 0xb6, // p.214, Set VCOM voltage
|
||||||
|
setextc = 0xb9, // p.217, Enter extension command
|
||||||
|
|
||||||
|
// Page 111
|
||||||
|
setstba = 0xc0, // p.218, Set source option
|
||||||
|
setpanel = 0xcc, // p.224, Set panel characteristics
|
||||||
|
|
||||||
|
// Page 112
|
||||||
|
setgamma = 0xe0, // p.225, Set gamma
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
const uint8_t init_cmds[] = {
|
||||||
|
// SWRESET Soft reset, then delay 10 ms
|
||||||
|
uint8_t(cmd::swreset), 0x80 + 100 / 5,
|
||||||
|
|
||||||
|
// SETEXTC? Set extension command
|
||||||
|
uint8_t(cmd::setextc), 3, 0xFF, 0x83, 0x57,
|
||||||
|
|
||||||
|
// No command, just delay 300 ms (This was 0xff)
|
||||||
|
uint8_t(cmd::nop), 0x80 + 500 / 5,
|
||||||
|
|
||||||
|
// SETRGB -- ?? 0x80 enables SDO pin (0x00 disables)
|
||||||
|
uint8_t(cmd::setrgb), 4, 0x80, 0x00, 0x06, 0x06,
|
||||||
|
|
||||||
|
// SETVCOM -1.52V
|
||||||
|
uint8_t(cmd::setvcom), 1, 0x25,
|
||||||
|
|
||||||
|
// SETOSC Normal mode 70Hz, Idle mode 55 Hz
|
||||||
|
uint8_t(cmd::setosc), 1, 0x68,
|
||||||
|
|
||||||
|
// SETPANEL BGR, Gate direction swapped
|
||||||
|
uint8_t(cmd::setpanel), 1, 0x05,
|
||||||
|
|
||||||
|
// SETPOWER Not deep standby, BT, VSPR, VSNR, AP, FS
|
||||||
|
uint8_t(cmd::setpower), 6, 0x00, 0x15, 0x1C, 0x1C, 0x83, 0xAA,
|
||||||
|
|
||||||
|
// SETSTBA OPON normal, OPON idle, STBA, STBA, STBA, GEN
|
||||||
|
uint8_t(cmd::setstba), 6, 0x50, 0x50, 0x01, 0x3C, 0x1E, 0x08,
|
||||||
|
|
||||||
|
// SETCYC NW 2, RTN, DIV, DUM, DUM, GDON, GDOFF
|
||||||
|
uint8_t(cmd::setcyc), 7, 0x02, 0x40, 0x00, 0x2A, 0x2A, 0x0D, 0x78,
|
||||||
|
|
||||||
|
// SETGAMMA
|
||||||
|
uint8_t(cmd::setgamma), 34, 0x02, 0x0A, 0x11, 0x1d, 0x23, 0x35, 0x41, 0x4b, 0x4b, 0x42,
|
||||||
|
0x3A, 0x27, 0x1B, 0x08, 0x09, 0x03, 0x02, 0x0A, 0x11, 0x1d,
|
||||||
|
0x23, 0x35, 0x41, 0x4b, 0x4b, 0x42, 0x3A, 0x27, 0x1B, 0x08,
|
||||||
|
0x09, 0x03, 0x00, 0x01,
|
||||||
|
|
||||||
|
// COLMOD 16 bit color
|
||||||
|
uint8_t(cmd::colmod), 1, 0x55,
|
||||||
|
|
||||||
|
// MADCTL
|
||||||
|
uint8_t(cmd::madctl), 1, 0x00, //0xC0,
|
||||||
|
|
||||||
|
// TEON TW off
|
||||||
|
uint8_t(cmd::teon), 1, 0x00,
|
||||||
|
|
||||||
|
// TESL (TEARLINE?)
|
||||||
|
uint8_t(cmd::tesl), 2, 0x00, 0x02,
|
||||||
|
|
||||||
|
// SLPOUT Exit Sleep, then delay 150 ms
|
||||||
|
uint8_t(cmd::slpout), 0x80 + 150 / 5,
|
||||||
|
|
||||||
|
// DISPON Main screen turn on, delay 50 ms
|
||||||
|
uint8_t(cmd::dispon), 0x80 + 50 / 5,
|
||||||
|
|
||||||
|
// End of commands
|
||||||
|
0, 0
|
||||||
|
};
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
void tft::init()
|
||||||
|
{
|
||||||
|
gpio_init(m_cs);
|
||||||
|
gpio_set_dir(m_cs, GPIO_OUT);
|
||||||
|
gpio_put(m_cs, 1); // Initialize to 1 (unselected)
|
||||||
|
|
||||||
|
gpio_init(m_dc);
|
||||||
|
gpio_set_dir(m_dc, GPIO_OUT);
|
||||||
|
gpio_put(m_dc, 1); // Initialize to 1 (data mode)
|
||||||
|
|
||||||
|
|
||||||
|
{
|
||||||
|
spi::cs {m_cs};
|
||||||
|
uint8_t buf[64];
|
||||||
|
uint8_t const *commands = init_cmds;
|
||||||
|
const uint8_t *end = init_cmds + sizeof(init_cmds);
|
||||||
|
while (commands < end) {
|
||||||
|
cmd command = static_cast<cmd>(*commands++);
|
||||||
|
uint8_t nargs = *commands++;
|
||||||
|
if (command == cmd::nop && !nargs) break;
|
||||||
|
|
||||||
|
// If high bit is set, this is a delay
|
||||||
|
unsigned delay = (nargs & 0x80) ? (unsigned(nargs & 0x7f) * 5) : 0;
|
||||||
|
nargs = (nargs & 0x80) ? 0 : (nargs & 0x7f);
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < nargs; ++i)
|
||||||
|
buf[i] = *commands++;
|
||||||
|
|
||||||
|
if (command != cmd::nop)
|
||||||
|
write_command(command, buf, nargs);
|
||||||
|
|
||||||
|
if (delay) {
|
||||||
|
log::trace("Delay %dms", delay);
|
||||||
|
sleep_ms(delay);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
spi::cs {m_cs};
|
||||||
|
uint16_t w = 480/3;
|
||||||
|
uint16_t h = 320/3;
|
||||||
|
unsigned n = w*h;
|
||||||
|
uint16_t color = __builtin_bswap16(startup_color);
|
||||||
|
//color = 0xffff;
|
||||||
|
color = 0xf800;
|
||||||
|
log::info("Drawing %dx%d square, color %04x", w, h, color);
|
||||||
|
set_draw_rect(0, 0, w, h);
|
||||||
|
for (unsigned i = 0; i < n; ++i)
|
||||||
|
spi_write_blocking(spi_default, reinterpret_cast<uint8_t*>(&color), sizeof(color));
|
||||||
|
log::trace("Wrote SPI %d data bytes", n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void tft::write_command(cmd command, uint8_t *args, unsigned args_len)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
spi::cs {m_dc}; // Command Mode
|
||||||
|
spi_write_blocking(spi_default, reinterpret_cast<uint8_t*>(&command), sizeof(command));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args_len)
|
||||||
|
spi_write_blocking(spi_default, args, args_len);
|
||||||
|
log::trace("Wrote SPI command %02x, %d data bytes", command, args_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
void tft::set_draw_rect(uint16_t x, uint16_t y, uint16_t w, uint16_t h)
|
||||||
|
{
|
||||||
|
uint16_t xargs[2] = { __builtin_bswap16(x), __builtin_bswap16(x + w - 1) };
|
||||||
|
uint16_t yargs[2] = { __builtin_bswap16(y), __builtin_bswap16(y + h - 1) };
|
||||||
|
write_command(cmd::caset, reinterpret_cast<uint8_t*>(&xargs), sizeof(xargs));
|
||||||
|
write_command(cmd::paset, reinterpret_cast<uint8_t*>(&yargs), sizeof(yargs));
|
||||||
|
write_command(cmd::ramwr);
|
||||||
|
}
|
||||||
18
src/edmfd/tft.hh
Normal file
18
src/edmfd/tft.hh
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
enum class cmd : uint8_t;
|
||||||
|
|
||||||
|
class tft
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
tft(unsigned cs, unsigned dc) :
|
||||||
|
m_cs {cs}, m_dc {dc} {}
|
||||||
|
|
||||||
|
void init();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void write_command(cmd command, uint8_t *args = nullptr, unsigned args_len = 0);
|
||||||
|
void set_draw_rect(uint16_t x, uint16_t y, uint16_t w, uint16_t h);
|
||||||
|
|
||||||
|
unsigned m_cs, m_dc;
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user