speed limit hit at 250ms per refresh now try pio

This commit is contained in:
matthias wagner
2023-05-13 13:57:56 +02:00
parent e5ad290ac4
commit af5a1611d5
22 changed files with 11580 additions and 10097 deletions

View File

@@ -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;
}

View File

@@ -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
View File

@@ -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));
}

View File

@@ -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
View 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))
;
}
%}