mirror of
https://github.com/stasenso/rp_pico_display_engine.git
synced 2026-06-27 05:42:41 +03:00
display: move ST7789 window setup and DMA start into hw_start_dma
This commit is contained in:
+186
-22
@@ -2,6 +2,10 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include "pico/stdlib.h"
|
||||
#include "hardware/spi.h"
|
||||
#include "hardware/dma.h"
|
||||
#include "hardware/irq.h"
|
||||
|
||||
|
||||
#ifndef DISPLAY_MAX_BUFFERS
|
||||
@@ -31,48 +35,208 @@ typedef struct
|
||||
|
||||
|
||||
static display_context_t ctx;
|
||||
static int dma_chan = -1;
|
||||
|
||||
#ifndef SPI_PORT
|
||||
#define SPI_PORT spi0
|
||||
#endif
|
||||
|
||||
#ifndef PIN_MOSI
|
||||
#define PIN_MOSI 19
|
||||
#endif
|
||||
|
||||
#ifndef PIN_SCK
|
||||
#define PIN_SCK 18
|
||||
#endif
|
||||
|
||||
#ifndef PIN_CS
|
||||
#define PIN_CS 17
|
||||
#endif
|
||||
|
||||
#ifndef PIN_DC
|
||||
#define PIN_DC 22
|
||||
#endif
|
||||
|
||||
#ifndef PIN_RST
|
||||
#define PIN_RST 13
|
||||
#endif
|
||||
|
||||
#ifndef PIN_BL
|
||||
#define PIN_BL 12
|
||||
#endif
|
||||
|
||||
static inline void st7789_send_command(uint8_t cmd)
|
||||
{
|
||||
/* DC=0: передаём байт команды контроллеру дисплея */
|
||||
gpio_put(PIN_DC, 0);
|
||||
gpio_put(PIN_CS, 0);
|
||||
spi_write_blocking(SPI_PORT, &cmd, 1);
|
||||
gpio_put(PIN_CS, 1);
|
||||
}
|
||||
|
||||
static inline void st7789_send_data_bytes(const uint8_t* data, size_t len)
|
||||
{
|
||||
/* DC=1: передаём полезные данные команды */
|
||||
gpio_put(PIN_DC, 1);
|
||||
gpio_put(PIN_CS, 0);
|
||||
spi_write_blocking(SPI_PORT, data, len);
|
||||
gpio_put(PIN_CS, 1);
|
||||
}
|
||||
|
||||
static inline void st7789_send_data_u8(uint8_t data)
|
||||
{
|
||||
st7789_send_data_bytes(&data, 1);
|
||||
}
|
||||
|
||||
static void display_dma_irq_trampoline(void)
|
||||
{
|
||||
display_dma_irq_handler();
|
||||
}
|
||||
|
||||
|
||||
/* ============================================================
|
||||
=== Hardware abstraction (to be implemented later)
|
||||
=== Абстракция оборудования (реализовать позже)
|
||||
============================================================ */
|
||||
|
||||
static void hw_init(uint16_t width, uint16_t height)
|
||||
{
|
||||
/* TODO:
|
||||
- init SPI
|
||||
- init DMA
|
||||
- init Core1 if needed
|
||||
- register DMA IRQ
|
||||
*/
|
||||
/* Максимально быстрый SPI для вывода кадров на ST7789 */
|
||||
spi_init(SPI_PORT, 1000 * 100 * 625); /* 62.5 MHz */
|
||||
spi_set_format(
|
||||
SPI_PORT,
|
||||
8,
|
||||
SPI_CPOL_0,
|
||||
SPI_CPHA_0,
|
||||
SPI_MSB_FIRST
|
||||
);
|
||||
|
||||
/* Линии данных SPI */
|
||||
gpio_set_function(PIN_MOSI, GPIO_FUNC_SPI);
|
||||
gpio_set_function(PIN_SCK, GPIO_FUNC_SPI);
|
||||
|
||||
/* Управляющие пины дисплея */
|
||||
gpio_init(PIN_CS);
|
||||
gpio_init(PIN_DC);
|
||||
gpio_init(PIN_RST);
|
||||
gpio_init(PIN_BL);
|
||||
gpio_set_dir(PIN_CS, GPIO_OUT);
|
||||
gpio_set_dir(PIN_DC, GPIO_OUT);
|
||||
gpio_set_dir(PIN_RST, GPIO_OUT);
|
||||
gpio_set_dir(PIN_BL, GPIO_OUT);
|
||||
|
||||
gpio_put(PIN_CS, 1);
|
||||
gpio_put(PIN_DC, 1);
|
||||
gpio_put(PIN_BL, 0);
|
||||
|
||||
/* Аппаратный reset дисплея */
|
||||
gpio_put(PIN_RST, 0);
|
||||
sleep_ms(50);
|
||||
gpio_put(PIN_RST, 1);
|
||||
sleep_ms(50);
|
||||
|
||||
st7789_send_command(0x01); /* SWRESET: программный сброс */
|
||||
sleep_ms(150);
|
||||
st7789_send_command(0x11); /* SLPOUT: выход из sleep mode */
|
||||
sleep_ms(150);
|
||||
|
||||
st7789_send_command(0x36); /* MADCTL: ориентация/порядок осей и RGB/BGR */
|
||||
st7789_send_data_u8(0b10100000); /* Параметр из рабочей версии Thread.c */
|
||||
|
||||
st7789_send_command(0x3A); /* COLMOD: формат пикселя */
|
||||
st7789_send_data_u8(0x55); /* 16 бит на пиксель (RGB565) */
|
||||
|
||||
{
|
||||
uint16_t x_end = (width > 0) ? (uint16_t)(width - 1u) : 0u;
|
||||
uint16_t y_end = (height > 0) ? (uint16_t)(height - 1u) : 0u;
|
||||
uint8_t window[4];
|
||||
|
||||
/* Окно вывода по X: [0 .. width-1] */
|
||||
st7789_send_command(0x2A); /* CASET: Column Address Set */
|
||||
window[0] = 0x00;
|
||||
window[1] = 0x00;
|
||||
window[2] = (uint8_t)(x_end >> 8);
|
||||
window[3] = (uint8_t)x_end;
|
||||
st7789_send_data_bytes(window, sizeof(window));
|
||||
|
||||
/* Окно вывода по Y: [0 .. height-1] */
|
||||
st7789_send_command(0x2B); /* RASET: Row Address Set */
|
||||
window[2] = (uint8_t)(y_end >> 8);
|
||||
window[3] = (uint8_t)y_end;
|
||||
st7789_send_data_bytes(window, sizeof(window));
|
||||
}
|
||||
|
||||
/* DMA -> SPI TX, чтобы выгружать кадр без участия CPU */
|
||||
dma_chan = dma_claim_unused_channel(true);
|
||||
dma_channel_config c = dma_channel_get_default_config((uint)dma_chan);
|
||||
channel_config_set_transfer_data_size(&c, DMA_SIZE_8); /* SPI в режиме 8 бит */
|
||||
channel_config_set_read_increment(&c, true); /* читать массив буфера */
|
||||
channel_config_set_write_increment(&c, false); /* писать в один регистр SPI DR */
|
||||
channel_config_set_dreq(&c, spi_get_dreq(SPI_PORT, true)); /* Тактирование от готовности SPI TX */
|
||||
|
||||
dma_channel_configure(
|
||||
(uint)dma_chan,
|
||||
&c,
|
||||
&spi_get_hw(SPI_PORT)->dr, /* куда пишем: SPI data register */
|
||||
NULL,
|
||||
0,
|
||||
false
|
||||
);
|
||||
|
||||
/* Прерывание по окончанию DMA-передачи кадра */
|
||||
dma_channel_set_irq0_enabled((uint)dma_chan, true);
|
||||
irq_set_exclusive_handler(DMA_IRQ_0, display_dma_irq_trampoline);
|
||||
irq_set_enabled(DMA_IRQ_0, true);
|
||||
|
||||
st7789_send_command(0x21); /* INVON: включить инверсию (как в старом коде) */
|
||||
st7789_send_command(0x29); /* DISPON: включить дисплей */
|
||||
gpio_put(PIN_BL, 1);
|
||||
}
|
||||
|
||||
static void hw_start_dma(uint16_t* buffer, size_t pixel_count)
|
||||
{
|
||||
/* TODO:
|
||||
- assert dma not active at HW level
|
||||
- assert CS low
|
||||
- configure DMA transfer
|
||||
- start transfer
|
||||
*/
|
||||
uint16_t x_end = (ctx.width > 0) ? (uint16_t)(ctx.width - 1u) : 0u;
|
||||
uint16_t y_end = (ctx.height > 0) ? (uint16_t)(ctx.height - 1u) : 0u;
|
||||
uint8_t window[4];
|
||||
|
||||
(void)buffer;
|
||||
(void)pixel_count;
|
||||
st7789_send_command(0x2A); /* CASET: Column Address Set */
|
||||
window[0] = 0x00;
|
||||
window[1] = 0x00;
|
||||
window[2] = (uint8_t)(x_end >> 8);
|
||||
window[3] = (uint8_t)x_end;
|
||||
st7789_send_data_bytes(window, sizeof(window));
|
||||
|
||||
st7789_send_command(0x2B); /* RASET: Row Address Set */
|
||||
window[2] = (uint8_t)(y_end >> 8);
|
||||
window[3] = (uint8_t)y_end;
|
||||
st7789_send_data_bytes(window, sizeof(window));
|
||||
|
||||
st7789_send_command(0x2C); /* RAMWR: Memory Write */
|
||||
|
||||
/* DC=1 и CS=0 перед непрерывной DMA-передачей буфера */
|
||||
gpio_put(PIN_DC, 1);
|
||||
gpio_put(PIN_CS, 0);
|
||||
|
||||
dma_channel_set_read_addr((uint)dma_chan, buffer, false);
|
||||
dma_channel_set_trans_count((uint)dma_chan, pixel_count * sizeof(uint16_t), true);
|
||||
}
|
||||
|
||||
static void hw_raise_cs(void)
|
||||
{
|
||||
/* TODO: raise chip select */
|
||||
gpio_put(PIN_CS, 1);
|
||||
}
|
||||
|
||||
|
||||
/* ============================================================
|
||||
=== DMA IRQ handler (must be wired to real IRQ later)
|
||||
=== Обработчик DMA IRQ (позже подключить к реальному IRQ)
|
||||
============================================================ */
|
||||
|
||||
void display_dma_irq_handler(void)
|
||||
{
|
||||
/* TODO: clear DMA interrupt flag */
|
||||
if (dma_chan >= 0)
|
||||
{
|
||||
/* Сбрасываем флаг IRQ у текущего DMA-канала */
|
||||
dma_hw->ints0 = 1u << (uint)dma_chan;
|
||||
}
|
||||
|
||||
hw_raise_cs();
|
||||
|
||||
@@ -82,7 +246,7 @@ void display_dma_irq_handler(void)
|
||||
|
||||
|
||||
/* ============================================================
|
||||
=== Public API
|
||||
=== Публичный API
|
||||
============================================================ */
|
||||
|
||||
void display_init(const display_config_t* cfg)
|
||||
@@ -129,7 +293,7 @@ uint16_t* display_get_draw_buffer(void)
|
||||
{
|
||||
while (ctx.dma_busy)
|
||||
{
|
||||
/* busy wait */
|
||||
/* активное ожидание */
|
||||
}
|
||||
}
|
||||
|
||||
@@ -208,7 +372,7 @@ void display_wait(void)
|
||||
{
|
||||
while (ctx.dma_busy)
|
||||
{
|
||||
/* busy wait */
|
||||
/* активное ожидание */
|
||||
}
|
||||
}
|
||||
|
||||
@@ -226,4 +390,4 @@ void display_poll(void)
|
||||
ctx.frame_done_cb();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user