speed limit hit at 250ms per refresh now try pio
This commit is contained in:
37
src/main.c
37
src/main.c
@@ -1,17 +1,42 @@
|
||||
#include "main.h"
|
||||
#include "hardware/gpio.h"
|
||||
#include "pico/stdlib.h"
|
||||
#include "pico/time.h"
|
||||
#include "tft.h"
|
||||
|
||||
// lcd configuration
|
||||
const struct tft_config lcd_config = {
|
||||
.spi = PICO_DEFAULT_SPI_INSTANCE,
|
||||
.gpio_din = PICO_DEFAULT_SPI_TX_PIN,
|
||||
.gpio_clk = PICO_DEFAULT_SPI_SCK_PIN,
|
||||
.gpio_cs = PICO_DEFAULT_SPI_CSN_PIN,
|
||||
.gpio_dc = 26,
|
||||
.gpio_rst = 22,
|
||||
.gpio_bl = 20,
|
||||
.width = 320,
|
||||
.height = 480,
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
gpio_init(DLED_PIN);
|
||||
gpio_set_dir(DLED_PIN, GPIO_OUT);
|
||||
stdio_init_all();
|
||||
|
||||
// gpio_init(DLED_PIN);
|
||||
// gpio_set_dir(DLED_PIN, GPIO_OUT);
|
||||
|
||||
tft_init(&lcd_config);
|
||||
|
||||
while (true) {
|
||||
gpio_put(DLED_PIN, 0);
|
||||
sleep_ms(250);
|
||||
gpio_put(DLED_PIN, 1);
|
||||
sleep_ms(1000);
|
||||
// gpio_put(DLED_PIN, 0);
|
||||
// sleep_ms(250);
|
||||
// gpio_put(DLED_PIN, 1);
|
||||
// sleep_ms(1000);
|
||||
absolute_time_t start = get_absolute_time();
|
||||
tft_fill(0b0000000000000000);
|
||||
tft_fill(0b1111111111111111);
|
||||
absolute_time_t end = get_absolute_time();
|
||||
volatile int64_t diff = absolute_time_diff_us(start, end);
|
||||
printf("test");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,4 @@
|
||||
#include "pico/stdlib.h"
|
||||
#include "tft.h"
|
||||
|
||||
#define DLED_PIN 25
|
||||
|
||||
// void* malloc(size_t size);
|
||||
// size_t strlen(const char* str);
|
||||
#define DLED_PIN 25
|
||||
266
src/tft.c
266
src/tft.c
@@ -1,145 +1,173 @@
|
||||
#include "tft.h"
|
||||
void cmd(uint8_t cmd)
|
||||
|
||||
static struct tft_config tft_cfg;
|
||||
static bool tft_data_mode = false;
|
||||
|
||||
void tft_cmd(uint8_t cmd, const uint8_t* data, size_t len)
|
||||
{
|
||||
CS_L;
|
||||
RS_C;
|
||||
spi_write_blocking(spi_default, &cmd, 1);
|
||||
CS_H;
|
||||
spi_set_format(tft_cfg.spi, 8, SPI_CPOL_0, SPI_CPHA_0, SPI_MSB_FIRST);
|
||||
tft_data_mode = false;
|
||||
|
||||
gpio_put(tft_cfg.gpio_cs, 0);
|
||||
gpio_put(tft_cfg.gpio_dc, 0);
|
||||
|
||||
spi_write_blocking(tft_cfg.spi, &cmd, sizeof(cmd));
|
||||
|
||||
if (len) {
|
||||
gpio_put(tft_cfg.gpio_dc, 1);
|
||||
spi_write_blocking(tft_cfg.spi, data, len);
|
||||
}
|
||||
gpio_put(tft_cfg.gpio_cs, 1);
|
||||
gpio_put(tft_cfg.gpio_dc, 1);
|
||||
}
|
||||
void data(uint8_t data)
|
||||
void tft_caset(uint16_t xs, uint16_t xe)
|
||||
{
|
||||
CS_L;
|
||||
RS_D;
|
||||
spi_write_blocking(spi_default, &data, 1);
|
||||
CS_H;
|
||||
}
|
||||
void reset()
|
||||
{
|
||||
sleep_ms(120);
|
||||
gpio_put(RESET_PIN, 1);
|
||||
sleep_ms(120);
|
||||
gpio_put(RESET_PIN, 0);
|
||||
sleep_ms(120);
|
||||
gpio_put(RESET_PIN, 1);
|
||||
sleep_ms(120);
|
||||
uint8_t data[] = {
|
||||
xs >> 8,
|
||||
xs & 0xff,
|
||||
xe >> 8,
|
||||
xe & 0xff,
|
||||
};
|
||||
|
||||
// CASET (2Ah): Column Address Set
|
||||
tft_cmd(0x2a, data, sizeof(data));
|
||||
}
|
||||
|
||||
void init_pins()
|
||||
void tft_raset(uint16_t ys, uint16_t ye)
|
||||
{
|
||||
gpio_init(LED_PIN);
|
||||
gpio_set_dir(LED_PIN, GPIO_OUT);
|
||||
gpio_put(LED_PIN, 1);
|
||||
gpio_init(RESET_PIN);
|
||||
gpio_set_dir(RESET_PIN, GPIO_OUT);
|
||||
gpio_init(RS_PIN);
|
||||
gpio_set_dir(RS_PIN, GPIO_OUT);
|
||||
gpio_init(CS_PIN);
|
||||
gpio_set_dir(CS_PIN, GPIO_OUT);
|
||||
CS_H;
|
||||
spi_init(spi_default, SPI_CLK);
|
||||
gpio_set_function(RX_PIN, GPIO_FUNC_SPI);
|
||||
gpio_set_function(SCK_PIN, GPIO_FUNC_SPI);
|
||||
gpio_set_function(TX_PIN, GPIO_FUNC_SPI);
|
||||
uint8_t data[] = {
|
||||
ys >> 8,
|
||||
ys & 0xff,
|
||||
ye >> 8,
|
||||
ye & 0xff,
|
||||
};
|
||||
|
||||
// RASET (2Bh): Row Address Set
|
||||
tft_cmd(0x2b, data, sizeof(data));
|
||||
}
|
||||
void init()
|
||||
void tft_init(const struct tft_config* config)
|
||||
{
|
||||
init_pins();
|
||||
memcpy(&tft_cfg, config, sizeof(tft_cfg));
|
||||
|
||||
write_command(0x01); // Software reset
|
||||
sleep_ms(120);
|
||||
set_sys_clock_khz(250 * 1000, true);
|
||||
|
||||
write_command(0x11); // Sleep exit
|
||||
sleep_ms(120);
|
||||
volatile uint ach = spi_init(tft_cfg.spi, 67 * 1000 * 1000); // original 125 * 1000 * 1000
|
||||
spi_set_format(tft_cfg.spi, 8, SPI_CPOL_0, SPI_CPHA_0, SPI_MSB_FIRST);
|
||||
|
||||
write_command(0xF0); // Command Set control
|
||||
write_data(0xC3); // Enable extension command 2 partI
|
||||
gpio_set_function(tft_cfg.gpio_din, GPIO_FUNC_SPI);
|
||||
gpio_set_function(tft_cfg.gpio_clk, GPIO_FUNC_SPI);
|
||||
|
||||
write_command(0xF0); // Command Set control
|
||||
write_data(0x96); // Enable extension command 2 partII
|
||||
gpio_init(tft_cfg.gpio_cs);
|
||||
gpio_init(tft_cfg.gpio_dc);
|
||||
gpio_init(tft_cfg.gpio_rst);
|
||||
gpio_init(tft_cfg.gpio_bl);
|
||||
|
||||
write_command(0x36); // Memory Data Access Control MX, MY, RGB mode
|
||||
write_data(0x48); // X-Mirror, Top-Left to right-Buttom, RGB
|
||||
gpio_set_dir(tft_cfg.gpio_cs, GPIO_OUT);
|
||||
gpio_set_dir(tft_cfg.gpio_dc, GPIO_OUT);
|
||||
gpio_set_dir(tft_cfg.gpio_rst, GPIO_OUT);
|
||||
gpio_set_dir(tft_cfg.gpio_bl, GPIO_OUT);
|
||||
|
||||
write_command(0x3A); // Interface Pixel Format
|
||||
write_data(0x55); // Control interface color format set to 16
|
||||
gpio_put(tft_cfg.gpio_cs, 1);
|
||||
gpio_put(tft_cfg.gpio_dc, 1);
|
||||
gpio_put(tft_cfg.gpio_rst, 1);
|
||||
sleep_ms(100);
|
||||
|
||||
write_command(0xB4); // Column inversion
|
||||
write_data(0x01); // 1-dot inversion
|
||||
// SWRESET (01h): Software Reset
|
||||
tft_cmd(0x01, NULL, 0);
|
||||
sleep_ms(150);
|
||||
|
||||
write_command(0xB6); // Display Function Control
|
||||
write_data(0x80); // Bypass
|
||||
write_data(0x02); // Source Output Scan from S1 to S960, Gate Output scan from G1 to G480, scan cycle=2
|
||||
write_data(0x3B); // LCD Drive Line=8*(59+1)
|
||||
// SLPOUT (11h): Sleep Out
|
||||
tft_cmd(0x11, NULL, 0);
|
||||
sleep_ms(50);
|
||||
|
||||
write_command(0xE8); // Display Output Ctrl Adjust
|
||||
write_data(0x40);
|
||||
write_data(0x8A);
|
||||
write_data(0x00);
|
||||
write_data(0x00);
|
||||
write_data(0x29); // Source eqaulizing period time= 22.5 us
|
||||
write_data(0x19); // Timing for "Gate start"=25 (Tclk)
|
||||
write_data(0xA5); // Timing for "Gate End"=37 (Tclk), Gate driver EQ function ON
|
||||
write_data(0x33);
|
||||
// COLMOD (3Ah): Interface Pixel Format
|
||||
// - RGB interface color format = 65K of RGB interface
|
||||
// - Control interface color format = 16bit/pixel
|
||||
tft_cmd(0x3a, (uint8_t[]) { 0x55 }, 1);
|
||||
sleep_ms(10);
|
||||
|
||||
write_command(0xC1); // Power control2
|
||||
write_data(0x06); // VAP(GVDD)=3.85+( vcom+vcom offset), VAN(GVCL)=-3.85+( vcom+vcom offset)
|
||||
// MADCTL (36h): Memory Data Access Control
|
||||
// - Page Address Order = Top to Bottom
|
||||
// - Column Address Order = Left to Right
|
||||
// - Page/Column Order = Normal Mode
|
||||
// - Line Address Order = LCD Refresh Top to Bottom
|
||||
// - RGB/BGR Order = RGB
|
||||
// - Display Data Latch Data Order = LCD Refresh Left to Right
|
||||
tft_cmd(0x36, (uint8_t[]) { 0x00 }, 1);
|
||||
|
||||
write_command(0xC2); // Power control 3
|
||||
write_data(0xA7); // Source driving current level=low, Gamma driving current level=High
|
||||
tft_caset(0, tft_cfg.width);
|
||||
tft_raset(0, tft_cfg.height);
|
||||
|
||||
write_command(0xC5); // VCOM Control
|
||||
write_data(0x18); // VCOM=0.9
|
||||
// INVON (21h): Display Inversion On
|
||||
// tft_cmd(0x21, NULL, 0);
|
||||
// sleep_ms(10);
|
||||
|
||||
sleep_ms(120);
|
||||
// NORON (13h): Normal Display Mode On
|
||||
tft_cmd(0x13, NULL, 0);
|
||||
sleep_ms(10);
|
||||
|
||||
// ST7796 Gamma Sequence
|
||||
write_command(0xE0); // Gamma"+"
|
||||
write_data(0xF0);
|
||||
write_data(0x09);
|
||||
write_data(0x0b);
|
||||
write_data(0x06);
|
||||
write_data(0x04);
|
||||
write_data(0x15);
|
||||
write_data(0x2F);
|
||||
write_data(0x54);
|
||||
write_data(0x42);
|
||||
write_data(0x3C);
|
||||
write_data(0x17);
|
||||
write_data(0x14);
|
||||
write_data(0x18);
|
||||
write_data(0x1B);
|
||||
|
||||
write_command(0xE1); // Gamma"-"
|
||||
write_data(0xE0);
|
||||
write_data(0x09);
|
||||
write_data(0x0B);
|
||||
write_data(0x06);
|
||||
write_data(0x04);
|
||||
write_data(0x03);
|
||||
write_data(0x2B);
|
||||
write_data(0x43);
|
||||
write_data(0x42);
|
||||
write_data(0x3B);
|
||||
write_data(0x16);
|
||||
write_data(0x14);
|
||||
write_data(0x17);
|
||||
write_data(0x1B);
|
||||
|
||||
sleep_ms(120);
|
||||
|
||||
write_command(0xF0); // Command Set control
|
||||
write_data(0x3C); // Disable extension command 2 partI
|
||||
|
||||
write_command(0xF0); // Command Set control
|
||||
write_data(0x69); // Disable extension command 2 partII
|
||||
|
||||
CS_H;
|
||||
sleep_ms(120);
|
||||
CS_L;
|
||||
|
||||
write_command(0x29); // Display on
|
||||
// DISPON (29h): Display On
|
||||
tft_cmd(0x29, NULL, 0);
|
||||
sleep_ms(10);
|
||||
|
||||
gpio_put(tft_cfg.gpio_bl, 1);
|
||||
}
|
||||
void set_pixel_red()
|
||||
void tft_ramwr()
|
||||
{
|
||||
write_data(0b111111000100000000);
|
||||
gpio_put(tft_cfg.gpio_cs, 0);
|
||||
gpio_put(tft_cfg.gpio_dc, 0);
|
||||
|
||||
// RAMWR (2Ch): Memory Write
|
||||
uint8_t cmd = 0x2c;
|
||||
spi_write_blocking(tft_cfg.spi, &cmd, sizeof(cmd));
|
||||
|
||||
gpio_put(tft_cfg.gpio_cs, 0);
|
||||
gpio_put(tft_cfg.gpio_dc, 1);
|
||||
}
|
||||
void tft_write(const void* data, size_t len)
|
||||
{
|
||||
spi_write16_blocking(tft_cfg.spi, data, len / 2);
|
||||
}
|
||||
|
||||
void tft_put(uint16_t pixel)
|
||||
{
|
||||
tft_write(&pixel, sizeof(pixel));
|
||||
}
|
||||
|
||||
void tft_fill(uint16_t pixel)
|
||||
{
|
||||
int num_pixels = tft_cfg.width * tft_cfg.height;
|
||||
|
||||
tft_set_cursor(0, 0);
|
||||
if (!tft_data_mode) {
|
||||
tft_ramwr();
|
||||
|
||||
spi_set_format(tft_cfg.spi, 16, SPI_CPOL_0, SPI_CPHA_0, SPI_MSB_FIRST);
|
||||
|
||||
tft_data_mode = true;
|
||||
}
|
||||
|
||||
printf("test");
|
||||
for (int i = 0; i < num_pixels; i++) {
|
||||
|
||||
tft_put(pixel);
|
||||
}
|
||||
printf("test");
|
||||
}
|
||||
|
||||
void tft_set_cursor(uint16_t x, uint16_t y)
|
||||
{
|
||||
tft_caset(x, tft_cfg.width);
|
||||
tft_raset(y, tft_cfg.height);
|
||||
}
|
||||
|
||||
void tft_vertical_scroll(uint16_t row)
|
||||
{
|
||||
uint8_t data[] = {
|
||||
(row >> 8) & 0xff,
|
||||
row & 0x00ff
|
||||
};
|
||||
|
||||
// VSCSAD (37h): Vertical Scroll Start Address of RAM
|
||||
tft_cmd(0x37, data, sizeof(data));
|
||||
}
|
||||
43
src/tft.h
43
src/tft.h
@@ -3,26 +3,31 @@
|
||||
|
||||
#include "hardware/gpio.h"
|
||||
#include "hardware/spi.h"
|
||||
#include "hardware/divider.h"
|
||||
#include "pico/stdlib.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#define LED_PIN 20
|
||||
#define RESET_PIN 22
|
||||
#define RS_PIN 26
|
||||
#define RX_PIN PICO_DEFAULT_SPI_RX_PIN
|
||||
#define CS_PIN PICO_DEFAULT_SPI_CSN_PIN
|
||||
#define SCK_PIN PICO_DEFAULT_SPI_SCK_PIN
|
||||
#define TX_PIN PICO_DEFAULT_SPI_TX_PIN
|
||||
#define SPI_CLK 66666666
|
||||
#define CS_L gpio_put(CS_PIN, 0)
|
||||
#define CS_H gpio_put(CS_PIN, 1)
|
||||
#define RS_C gpio_put(RS_PIN, 0)
|
||||
#define RS_D gpio_put(RS_PIN, 1)
|
||||
struct tft_config {
|
||||
spi_inst_t* spi;
|
||||
uint gpio_din;
|
||||
uint gpio_clk;
|
||||
int gpio_cs;
|
||||
uint gpio_dc;
|
||||
uint gpio_rst;
|
||||
uint gpio_bl;
|
||||
uint16_t width;
|
||||
uint16_t height;
|
||||
};
|
||||
|
||||
void write_command(uint8_t cmd);
|
||||
void write_data(uint8_t data);
|
||||
void reset();
|
||||
void init_pins();
|
||||
void init();
|
||||
void set_pixel_red();
|
||||
void tft_cmd(uint8_t cmd, const uint8_t* data, size_t len);
|
||||
void tft_caset(uint16_t xs, uint16_t xe);
|
||||
void tft_raset(uint16_t ys, uint16_t ye);
|
||||
void tft_init(const struct tft_config* config);
|
||||
void tft_ramwr();
|
||||
void tft_write(const void* data, size_t len);
|
||||
void tft_put(uint16_t pixel);
|
||||
void tft_fill(uint16_t pixel);
|
||||
void tft_set_cursor(uint16_t x, uint16_t y);
|
||||
void tft_vertical_scroll(uint16_t row);
|
||||
|
||||
#endif // TFT_H
|
||||
#endif // TFT_H
|
||||
57
src/tft.pio
Normal file
57
src/tft.pio
Normal file
@@ -0,0 +1,57 @@
|
||||
;
|
||||
; Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
|
||||
;
|
||||
; SPDX-License-Identifier: BSD-3-Clause
|
||||
;
|
||||
|
||||
.program tft
|
||||
.side_set 1
|
||||
|
||||
; This is just a simple clocked serial TX. At 125 MHz system clock we can
|
||||
; sustain up to 62.5 Mbps.
|
||||
; Data on OUT pin 0
|
||||
; Clock on side-set pin 0
|
||||
|
||||
.wrap_target
|
||||
out pins, 1 side 0 ; stall here if no data (clock low)
|
||||
nop side 1
|
||||
.wrap
|
||||
|
||||
% c-sdk {
|
||||
// For optimal use of DMA bandwidth we would use an autopull threshold of 32,
|
||||
// but we are using a threshold of 8 here (consume 1 byte from each FIFO entry
|
||||
// and discard the remainder) to make things easier for software on the other side
|
||||
|
||||
static inline void tft_program_init(PIO pio, uint sm, uint offset, uint data_pin, uint clk_pin, float clk_div) {
|
||||
pio_gpio_init(pio, data_pin);
|
||||
pio_gpio_init(pio, clk_pin);
|
||||
pio_sm_set_consecutive_pindirs(pio, sm, data_pin, 1, true);
|
||||
pio_sm_set_consecutive_pindirs(pio, sm, clk_pin, 1, true);
|
||||
pio_sm_config c = st7789_lcd_program_get_default_config(offset);
|
||||
sm_config_set_sideset_pins(&c, clk_pin);
|
||||
sm_config_set_out_pins(&c, data_pin, 1);
|
||||
sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX);
|
||||
sm_config_set_clkdiv(&c, clk_div);
|
||||
sm_config_set_out_shift(&c, false, true, 8);
|
||||
pio_sm_init(pio, sm, offset, &c);
|
||||
pio_sm_set_enabled(pio, sm, true);
|
||||
}
|
||||
|
||||
// Making use of the narrow store replication behaviour on RP2040 to get the
|
||||
// data left-justified (as we are using shift-to-left to get MSB-first serial)
|
||||
|
||||
static inline void tft_put(PIO pio, uint sm, uint8_t x) {
|
||||
while (pio_sm_is_tx_fifo_full(pio, sm))
|
||||
;
|
||||
*(volatile uint8_t*)&pio->txf[sm] = x;
|
||||
}
|
||||
|
||||
// SM is done when it stalls on an empty FIFO
|
||||
|
||||
static inline void tft_wait_idle(PIO pio, uint sm) {
|
||||
uint32_t sm_stall_mask = 1u << (sm + PIO_FDEBUG_TXSTALL_LSB);
|
||||
pio->fdebug = sm_stall_mask;
|
||||
while (!(pio->fdebug & sm_stall_mask))
|
||||
;
|
||||
}
|
||||
%}
|
||||
Reference in New Issue
Block a user